Files
evolution/calendar/eventedit.c
Eskil Heyn Olsen eb7c5ae3c5 Committed fixes for the end-on-day recurrence bug where the last
day was skipped.

Also fixed problem with multiple setitimer calls that where especially
pesky in the corba part, where corba calls would cause numerous alarm
dialogs when the events alarm went off.

svn path=/trunk/; revision=1525
1999-12-31 15:58:08 +00:00

1584 lines
44 KiB
C

/*
* EventEditor widget
* Copyright (C) 1998 the Free Software Foundation
*
* Authors: Miguel de Icaza (miguel@kernel.org)
* Federico Mena (quartic@gimp.org)
*/
#include <config.h>
#include <gnome.h>
#include <string.h>
#include "calendar.h"
#include "eventedit.h"
#include "main.h"
#include "timeutil.h"
static void event_editor_class_init (EventEditorClass *class);
static void event_editor_init (EventEditor *ee);
static void event_editor_destroy (GtkObject *object);
GtkWidget* make_spin_button (int val, int low, int high);
void ee_create_ae (GtkTable *table, char *str, CalendarAlarm *alarm, enum AlarmType type,
int y, gboolean control_sens, GtkSignalFunc dirty_func);
void ee_store_alarm (CalendarAlarm *alarm, enum AlarmType type);
/* Note: do not i18n these strings, they are part of the vCalendar protocol */
static char *class_names [] = { "PUBLIC", "PRIVATE", "CONFIDENTIAL" };
static GnomeDialogClass *parent_class;
struct numbered_item {
char *text;
int num;
};
guint
event_editor_get_type (void)
{
static guint event_editor_type = 0;
if(!event_editor_type) {
GtkTypeInfo event_editor_info = {
"EventEditor",
sizeof(EventEditor),
sizeof(EventEditorClass),
(GtkClassInitFunc) event_editor_class_init,
(GtkObjectInitFunc) event_editor_init,
(GtkArgSetFunc) NULL,
(GtkArgGetFunc) NULL,
};
event_editor_type = gtk_type_unique (gnome_dialog_get_type (), &event_editor_info);
}
return event_editor_type;
}
static void
event_editor_class_init (EventEditorClass *class)
{
GtkObjectClass *object_class;
parent_class = gtk_type_class (gnome_dialog_get_type ());
object_class = (GtkObjectClass*) class;
object_class->destroy = event_editor_destroy;
}
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;
}
/*
* Checks if the day range occupies all the day, and if so, check the
* box accordingly
*/
static void
ee_check_all_day (EventEditor *ee)
{
time_t ev_start, ev_end;
ev_start = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->start_time));
ev_end = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->end_time));
if (get_time_t_hour (ev_start) <= day_begin && get_time_t_hour (ev_end) >= day_end)
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ee->general_allday), 1);
else
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ee->general_allday), 0);
}
/*
* Callback: checks that the dates are start < end
*/
static void
check_dates (GnomeDateEdit *gde, EventEditor *ee)
{
time_t start, end;
struct tm tm_start, tm_end;
start = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->start_time));
end = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->end_time));
if (start > end) {
tm_start = *localtime (&start);
tm_end = *localtime (&end);
if (GTK_WIDGET (gde) == ee->start_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;
gnome_date_edit_set_time (GNOME_DATE_EDIT (ee->end_time), mktime (&tm_end));
} else if (GTK_WIDGET (gde) == ee->end_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;
gnome_date_edit_set_time (GNOME_DATE_EDIT (ee->start_time), mktime (&tm_start));
}
}
}
/*
* Callback: checks that start_time < end_time and whether the
* selected hour range spans all of the day
*/
static void
check_times (GnomeDateEdit *gde, EventEditor *ee)
{
time_t start, end;
struct tm tm_start, tm_end;
gdk_pointer_ungrab (GDK_CURRENT_TIME);
gdk_flush ();
start = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->start_time));
end = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->end_time));
if (start >= end) {
tm_start = *localtime (&start);
tm_end = *localtime (&end);
if (GTK_WIDGET (gde) == ee->start_time) {
tm_end.tm_min = tm_start.tm_min;
tm_end.tm_sec = tm_start.tm_sec;
tm_end.tm_hour = tm_start.tm_hour + 1;
if (tm_end.tm_hour >= 24) {
tm_end.tm_hour = 24; /* mktime() will bump the day */
tm_end.tm_min = 0;
tm_end.tm_sec = 0;
}
gnome_date_edit_set_time (GNOME_DATE_EDIT (ee->end_time), mktime (&tm_end));
} else if (GTK_WIDGET (gde) == ee->end_time) {
tm_start.tm_min = tm_end.tm_min;
tm_start.tm_sec = tm_end.tm_sec;
tm_start.tm_hour = tm_end.tm_hour - 1;
if (tm_start.tm_hour < 0) {
tm_start.tm_hour = 0;
tm_start.tm_min = 0;
tm_start.tm_min = 0;
}
gnome_date_edit_set_time (GNOME_DATE_EDIT (ee->start_time), mktime (&tm_start));
}
}
/* Check whether the event spans the whole day */
ee_check_all_day (ee);
}
/*
* Callback: all day event box clicked
*/
static void
set_all_day (GtkToggleButton *toggle, EventEditor *ee)
{
struct tm tm;
time_t start_t;
start_t = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->start_time));
tm = *localtime (&start_t);
tm.tm_hour = day_begin;
tm.tm_min = 0;
tm.tm_sec = 0;
gnome_date_edit_set_time (GNOME_DATE_EDIT (ee->start_time), mktime (&tm));
if (toggle->active)
tm.tm_hour = day_end;
else
tm.tm_hour++;
gnome_date_edit_set_time (GNOME_DATE_EDIT (ee->end_time), mktime (&tm));
}
/* Convenience function to create a properly-configured date editor widget */
GtkWidget *
date_edit_new (time_t the_time, int show_time)
{
return gnome_date_edit_new_flags (the_time,
((show_time ? GNOME_DATE_EDIT_SHOW_TIME : 0)
| (am_pm_flag ? 0 : GNOME_DATE_EDIT_24_HR)
| (week_starts_on_monday
? GNOME_DATE_EDIT_WEEK_STARTS_ON_MONDAY
: 0)));
}
static GtkWidget *
event_editor_setup_time_frame (EventEditor *ee)
{
GtkWidget *frame;
GtkWidget *start_time, *end_time;
GtkTable *t;
frame = gtk_frame_new (_("Time"));
t = GTK_TABLE (ee->general_time_table = gtk_table_new (1, 1, 0));
gtk_container_border_width (GTK_CONTAINER (t), 4);
gtk_table_set_row_spacings (t, 4);
gtk_table_set_col_spacings (t, 4);
gtk_container_add (GTK_CONTAINER (frame), ee->general_time_table);
/* 1. Start time */
if (ee->ical->dtstart == 0){
ee->ical->dtstart = time (NULL);
ee->ical->dtend = time_add_minutes (ee->ical->dtstart, 30);
}
ee->start_time = start_time = date_edit_new (ee->ical->dtstart, TRUE);
gnome_date_edit_set_popup_range ((GnomeDateEdit *) start_time, day_begin, day_end);
gtk_signal_connect (GTK_OBJECT (start_time), "date_changed",
GTK_SIGNAL_FUNC (check_dates), ee);
gtk_signal_connect (GTK_OBJECT (start_time), "time_changed",
GTK_SIGNAL_FUNC (check_times), ee);
gtk_table_attach (t, gtk_label_new (_("Start time:")), 1, 2, 1, 2,
GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
gtk_table_attach (t, start_time, 2, 3, 1, 2,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
/* 2. End time */
ee->end_time = end_time = date_edit_new (ee->ical->dtend, TRUE);
gnome_date_edit_set_popup_range ((GnomeDateEdit *) end_time, day_begin, day_end);
gtk_signal_connect (GTK_OBJECT (end_time), "date_changed",
GTK_SIGNAL_FUNC (check_dates), ee);
gtk_signal_connect (GTK_OBJECT (end_time), "time_changed",
GTK_SIGNAL_FUNC (check_times), ee);
gtk_table_attach (t, gtk_label_new (_("End time:")), 1, 2, 2, 3,
GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
gtk_table_attach (t, end_time, 2, 3, 2, 3,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
/* 3. All day checkbox */
ee->general_allday = gtk_check_button_new_with_label (_("All day event"));
gtk_signal_connect (GTK_OBJECT (ee->general_allday), "toggled",
GTK_SIGNAL_FUNC (set_all_day), ee);
gtk_table_attach (t, ee->general_allday, 3, 4, 1, 2,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
4, 0);
ee_check_all_day (ee);
return frame;
}
static GtkWidget *
timesel_new (void)
{
GtkWidget *menu, *option_menu;
char *items [] = { N_("Minutes"), N_("Hours"), N_("Days") };
int i;
option_menu = gtk_option_menu_new ();
menu = gtk_menu_new ();
for (i = 0; i < 3; i++){
GtkWidget *item;
item = gtk_menu_item_new_with_label (_(items [i]));
gtk_menu_append (GTK_MENU (menu), item);
gtk_widget_show (item);
}
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
return option_menu;
}
/*
* Set the sensitive state depending on whether the alarm enabled flag.
*/
static void
ee_alarm_setting (CalendarAlarm *alarm, int sensitive)
{
gtk_widget_set_sensitive (GTK_WIDGET (alarm->w_count), sensitive);
gtk_widget_set_sensitive (GTK_WIDGET (alarm->w_timesel), sensitive);
if (alarm->type == ALARM_PROGRAM || alarm->type == ALARM_MAIL){
gtk_widget_set_sensitive (GTK_WIDGET (alarm->w_entry), sensitive);
gtk_widget_set_sensitive (GTK_WIDGET (alarm->w_label), sensitive);
}
}
static void
alarm_toggle (GtkToggleButton *toggle, CalendarAlarm *alarm)
{
ee_alarm_setting (alarm, toggle->active);
}
#define FXS (GTK_FILL | GTK_EXPAND | GTK_SHRINK)
#define FS (GTK_FILL | GTK_SHRINK)
void
ee_create_ae (GtkTable *table, char *str, CalendarAlarm *alarm, enum AlarmType type, int y, gboolean control_sens, GtkSignalFunc dirty_func)
{
GtkWidget *entry;
alarm->w_enabled = gtk_check_button_new_with_label (str);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (alarm->w_enabled),
alarm->enabled);
if (control_sens)
gtk_signal_connect (GTK_OBJECT (alarm->w_enabled), "toggled",
GTK_SIGNAL_FUNC (alarm_toggle), alarm);
if (dirty_func)
gtk_signal_connect (GTK_OBJECT (alarm->w_enabled), "toggled",
GTK_SIGNAL_FUNC (dirty_func), NULL);
gtk_table_attach (table, alarm->w_enabled, 0, 1, y, y+1, FS, FS, 0, 0);
alarm->w_count = make_spin_button (alarm->count, 0, 10000);
if (dirty_func)
gtk_signal_connect (GTK_OBJECT (alarm->w_count), "changed",
GTK_SIGNAL_FUNC (dirty_func), NULL);
gtk_table_attach (table, alarm->w_count, 1, 2, y, y+1, FS, FS, 0, 0);
alarm->w_timesel = timesel_new ();
/* is there a "changed" signal which we can connect to? */
gtk_option_menu_set_history (GTK_OPTION_MENU (alarm->w_timesel), alarm->units);
gtk_table_attach (table, alarm->w_timesel, 2, 3, y, y+1, FS, FS, 0, 0);
switch (type){
case ALARM_MAIL:
alarm->w_label = gtk_label_new (_("Mail to:"));
gtk_misc_set_alignment (GTK_MISC (alarm->w_label), 1.0, 0.5);
gtk_table_attach (table, alarm->w_label, 3, 4, y, y+1, FS, FS, 0, 0);
alarm->w_entry = gtk_entry_new ();
gtk_table_attach (table, alarm->w_entry, 4, 5, y, y+1, FXS, FS, 0, 0);
gtk_entry_set_text (GTK_ENTRY (alarm->w_entry), alarm->data ? alarm->data : "");
if (dirty_func)
gtk_signal_connect (GTK_OBJECT (alarm->w_entry),
"changed",
GTK_SIGNAL_FUNC (dirty_func),
NULL);
break;
case ALARM_PROGRAM:
alarm->w_label = gtk_label_new (_("Run program:"));
gtk_misc_set_alignment (GTK_MISC (alarm->w_label), 1.0, 0.5);
gtk_table_attach (table, alarm->w_label, 3, 4, y, y+1, FS, FS, 0, 0);
alarm->w_entry = gnome_file_entry_new ("alarm-program", _("Select program to run at alarm time"));
entry = gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (alarm->w_entry));
gtk_entry_set_text (GTK_ENTRY (entry), alarm->data ? alarm->data : "");
gtk_table_attach (table, alarm->w_entry, 4, 5, y, y+1, FXS, FS, 0, 0);
if (dirty_func)
gtk_signal_connect (GTK_OBJECT (entry),
"changed",
GTK_SIGNAL_FUNC (dirty_func),
NULL);
break;
default:
break;
}
if (control_sens)
ee_alarm_setting (alarm, alarm->enabled);
else
ee_alarm_setting (alarm, TRUE);
}
static GtkWidget *
ee_alarm_widgets (EventEditor *ee)
{
GtkWidget *table, *mailto, *mailte, *l;
l = gtk_frame_new (_("Alarms"));
table = gtk_table_new (1, 1, 0);
gtk_container_border_width (GTK_CONTAINER (table), 4);
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
gtk_container_add (GTK_CONTAINER (l), table);
mailto = gtk_label_new (_("Mail to:"));
mailte = gtk_entry_new ();
ee_create_ae (GTK_TABLE (table), _("Display"), &ee->ical->dalarm, ALARM_DISPLAY, 1, TRUE, NULL);
ee_create_ae (GTK_TABLE (table), _("Audio"), &ee->ical->aalarm, ALARM_AUDIO, 2, TRUE, NULL);
ee_create_ae (GTK_TABLE (table), _("Program"), &ee->ical->palarm, ALARM_PROGRAM, 3, TRUE, NULL);
ee_create_ae (GTK_TABLE (table), _("Mail"), &ee->ical->malarm, ALARM_MAIL, 4, TRUE, NULL);
return l;
}
static GtkWidget *
ee_classification_widgets (EventEditor *ee)
{
GtkWidget *rpub, *rpriv, *rconf;
GtkWidget *frame, *hbox;
frame = gtk_frame_new (_("Classification"));
hbox = gtk_hbox_new (TRUE, 0);
gtk_container_border_width (GTK_CONTAINER (hbox), 4);
gtk_container_add (GTK_CONTAINER (frame), hbox);
rpub = gtk_radio_button_new_with_label (NULL, _("Public"));
rpriv = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (rpub), _("Private"));
rconf = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (rpub), _("Confidential"));
gtk_box_pack_start (GTK_BOX (hbox), rpub, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), rpriv, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), rconf, FALSE, FALSE, 0);
if (strcmp (ee->ical->class, class_names[0]) == 0)
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (rpub), TRUE);
else if (strcmp (ee->ical->class, class_names[1]) == 0)
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (rpriv), TRUE);
else if (strcmp (ee->ical->class, class_names[2]) == 0)
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (rconf), TRUE);
ee->general_radios = rpub;
return frame;
}
/*
* Retrieves the information from the CalendarAlarm widgets and stores them
* on the CalendarAlarm generic values
*/
void
ee_store_alarm (CalendarAlarm *alarm, enum AlarmType type)
{
GtkWidget *item;
GtkMenu *menu;
GList *child;
int idx;
if (alarm->data){
g_free (alarm->data);
alarm->data = 0;
}
alarm->enabled = GTK_TOGGLE_BUTTON (alarm->w_enabled)->active;
if (!alarm->enabled)
return;
if (type == ALARM_PROGRAM)
alarm->data = g_strdup (gtk_entry_get_text (GTK_ENTRY (gnome_file_entry_gtk_entry (alarm->w_entry))));
if (type == ALARM_MAIL)
alarm->data = g_strdup (gtk_entry_get_text (GTK_ENTRY (alarm->w_entry)));
/* Find out the index */
menu = GTK_MENU (GTK_OPTION_MENU (alarm->w_timesel)->menu);
item = gtk_menu_get_active (menu);
for (idx = 0, child = GTK_MENU_SHELL (menu)->children; child->data != item; child = child->next)
idx++;
alarm->units = idx;
alarm->count = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (alarm->w_count));
}
static void
ee_store_general_values_to_ical (EventEditor *ee)
{
GtkRadioButton *radio = GTK_RADIO_BUTTON (ee->general_radios);
iCalObject *ical = ee->ical;
GSList *list = radio->group;
int idx;
time_t now;
now = time (NULL);
ical->dtstart = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->start_time));
ical->dtend = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->end_time));
if (ical->summary)
g_free (ical->summary);
ical->summary = gtk_editable_get_chars (GTK_EDITABLE (ee->general_summary), 0, -1);
ee_store_alarm (&ical->dalarm, ALARM_DISPLAY);
ee_store_alarm (&ical->aalarm, ALARM_AUDIO);
ee_store_alarm (&ical->palarm, ALARM_PROGRAM);
ee_store_alarm (&ical->malarm, ALARM_MAIL);
for (idx = 2; list; list = list->next) {
if (GTK_TOGGLE_BUTTON (list->data)->active)
break;
idx--; /* The group is stored in reverse order of insertion */
}
g_free (ical->class);
ical->class = g_strdup (class_names [idx]);
}
static int
option_menu_active_number (GtkWidget *omenu)
{
GtkWidget *menu;
GtkWidget *item;
struct numbered_item *ni;
menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (omenu));
item = gtk_menu_get_active (GTK_MENU (menu));
ni = gtk_object_get_user_data (GTK_OBJECT (item));
return ni->num;
}
static int
ee_store_recur_rule_to_ical (EventEditor *ee)
{
iCalObject *ical;
int i, j;
GSList *list;
ical = ee->ical;
for (i = 0, list = ee->recur_rr_group; list; i++, list = list->next)
if (GTK_TOGGLE_BUTTON (list->data)->active)
break;
i = g_slist_length (ee->recur_rr_group) - i - 1; /* buttons are stored in reverse order of insertion */
/* None selected, no rule to be stored */
if (i == 0)
return 0;
if (!ical->recur)
ical->recur = g_new0 (Recurrence, 1);
switch (i) {
case 1:
/* Daily */
ical->recur->type = RECUR_DAILY;
ical->recur->interval = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ee->recur_rr_day_period));
break;
case 2:
/* Weekly */
ical->recur->type = RECUR_WEEKLY;
ical->recur->interval = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ee->recur_rr_week_period));
ical->recur->weekday = 0;
for (j = 0; j < 7; j++)
if (GTK_TOGGLE_BUTTON (ee->recur_rr_week_days[j])->active) {
if (j == 6)
ical->recur->weekday |= 1 << 0; /* sunday is at bit 0 */
else
ical->recur->weekday |= 1 << (j + 1);
}
break;
case 3:
/* Monthly */
if (GTK_WIDGET_SENSITIVE (ee->recur_rr_month_date)) {
/* by day */
ical->recur->type = RECUR_MONTHLY_BY_DAY;
ical->recur->u.month_day =
gtk_spin_button_get_value_as_int (
GTK_SPIN_BUTTON (ee->recur_rr_month_date));
ical->recur->interval =
gtk_spin_button_get_value_as_int (
GTK_SPIN_BUTTON (ee->recur_rr_month_period));
} else {
/* by position */
ical->recur->type = RECUR_MONTHLY_BY_POS;
ical->recur->u.month_pos =
option_menu_active_number (ee->recur_rr_month_day);
ical->recur->weekday =
option_menu_active_number (ee->recur_rr_month_weekday);
ical->recur->interval =
gtk_spin_button_get_value_as_int (
GTK_SPIN_BUTTON (ee->recur_rr_month_period));
}
break;
case 4:
/* Yearly */
ical->recur->type = RECUR_YEARLY_BY_DAY;
ical->recur->interval = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ee->recur_rr_year_period));
/* FIXME: need to specify anything else? I am assuming the code will look at the dtstart
* to figure out when to recur. - Federico
*/
break;
default:
g_assert_not_reached ();
}
return 1;
}
static void
ee_store_recur_end_to_ical (EventEditor *ee)
{
iCalObject *ical;
GSList *list;
int i;
/* Ending date of recurrence */
ical = ee->ical;
for (i = 0, list = ee->recur_ed_group; list; i++, list = list->next)
if (GTK_TOGGLE_BUTTON (list->data)->active)
break;
i = g_slist_length (ee->recur_ed_group) - i - 1; /* the list is stored in reverse order of insertion */
switch (i) {
case 0:
/* repeat forever */
ical->recur->_enddate = 0;
ical->recur->enddate = 0;
ical->recur->duration = 0;
break;
case 1:
/* end date */
/* Also here, to ensure that the event is used, we add 86400 secs to get
get next day, in accordance to the RFC */
ical->recur->_enddate = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->recur_ed_end_on)) + 86400;
ical->recur->enddate = ical->recur->_enddate;
ical->recur->duration = 0;
break;
case 2:
/* end after n occurrences */
ical->recur->duration = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (ee->recur_ed_end_after));
ical_object_compute_end (ical);
break;
default:
g_assert_not_reached ();
break;
}
}
static void
free_exdate (iCalObject *ical)
{
GList *list;
if (!ical->exdate)
return;
for (list = ical->exdate; list; list = list->next)
g_free (list->data);
g_list_free (ical->exdate);
ical->exdate = NULL;
}
static void
ee_store_recur_exceptions_to_ical (EventEditor *ee)
{
iCalObject *ical;
GtkCList *clist;
int i;
time_t *t;
ical = ee->ical;
clist = GTK_CLIST (ee->recur_ex_clist);
free_exdate (ical);
for (i = 0; i < clist->rows; i++) {
t = gtk_clist_get_row_data (clist, i);
ical->exdate = g_list_prepend (ical->exdate, t);
}
}
static void
ee_store_recur_values_to_ical (EventEditor *ee)
{
if (ee_store_recur_rule_to_ical (ee)){
ee_store_recur_exceptions_to_ical (ee);
ee_store_recur_end_to_ical (ee);
} else if (ee->ical->recur) {
g_free (ee->ical->recur);
ee->ical->recur = NULL;
if (ee->ical->exdate){
GList *l = ee->ical->exdate;
for (; l; l = l->next)
g_free (l->data);
g_list_free (l);
}
}
}
/*
* Retrieves all of the information from the different widgets and updates
* the iCalObject accordingly.
*/
static void
ee_store_dlg_values_to_ical (EventEditor *ee)
{
time_t now;
ee_store_general_values_to_ical (ee);
ee_store_recur_values_to_ical (ee);
now = time (NULL);
/* FIXME: This is not entirely correct; we should check if the values actually changed */
ee->ical->last_mod = now;
if (ee->ical->new)
ee->ical->created = now;
}
static void
ee_ok (GtkWidget *widget, EventEditor *ee)
{
ee_store_dlg_values_to_ical (ee);
if (ee->ical->new)
gnome_calendar_add_object (ee->gnome_cal, ee->ical);
else
gnome_calendar_object_changed (ee->gnome_cal, ee->ical, CHANGE_ALL);
save_default_calendar (ee->gnome_cal);
ee->ical->new = 0;
}
static void
ee_cancel (GtkWidget *widget, EventEditor *ee)
{
if (ee->ical->new) {
ical_object_destroy (ee->ical);
ee->ical = NULL;
}
}
static void
ee_create_buttons (EventEditor *ee)
{
gnome_dialog_append_buttons(GNOME_DIALOG(ee),
GNOME_STOCK_BUTTON_OK,
GNOME_STOCK_BUTTON_CANCEL, NULL);
gnome_dialog_set_default (GNOME_DIALOG (ee), 0);
gnome_dialog_button_connect (GNOME_DIALOG (ee), 0, GTK_SIGNAL_FUNC(ee_ok), ee);
gnome_dialog_button_connect (GNOME_DIALOG (ee), 1, GTK_SIGNAL_FUNC(ee_cancel), ee);
return;
}
/*
* Load the contents in a delayed fashion, as the GtkText widget needs it
*/
static void
ee_fill_summary (GtkWidget *widget, EventEditor *ee)
{
int pos = 0;
gtk_editable_insert_text (GTK_EDITABLE (ee->general_summary), ee->ical->summary,
strlen (ee->ical->summary), &pos);
gtk_text_thaw (GTK_TEXT (ee->general_summary));
}
enum {
OWNER_LINE,
DESC_LINE,
SUMMARY_LINE,
TIME_LINE,
ALARM_LINE,
CLASS_LINE
};
/* Create/setup the general page */
static void
ee_init_general_page (EventEditor *ee)
{
GtkWidget *l;
GtkWidget *hbox;
ee->general_table = gtk_table_new (1, 1, FALSE);
gtk_container_border_width (GTK_CONTAINER (ee->general_table), 4);
gtk_table_set_row_spacings (GTK_TABLE (ee->general_table), 4);
gtk_table_set_col_spacings (GTK_TABLE (ee->general_table), 4);
gtk_notebook_append_page (GTK_NOTEBOOK (ee->notebook), GTK_WIDGET (ee->general_table),
gtk_label_new (_("General")));
hbox = gtk_hbox_new (FALSE, 0);
gtk_table_attach (GTK_TABLE (ee->general_table), hbox,
0, 1, OWNER_LINE, OWNER_LINE + 1,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 4);
l = gtk_label_new (_("Owner:"));
gtk_box_pack_start (GTK_BOX (hbox), l, FALSE, FALSE, 0);
ee->general_owner = gtk_label_new (ee->ical->organizer ? ee->ical->organizer : _("?"));
gtk_misc_set_alignment (GTK_MISC (ee->general_owner), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (hbox), ee->general_owner, TRUE, TRUE, 4);
l = gtk_label_new (_("Summary:"));
gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (ee->general_table), l,
0, 1, DESC_LINE, DESC_LINE + 1,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
ee->general_summary = gtk_text_new (NULL, NULL);
gtk_text_freeze (GTK_TEXT (ee->general_summary));
gtk_signal_connect (GTK_OBJECT (ee->general_summary), "realize",
GTK_SIGNAL_FUNC (ee_fill_summary), ee);
gtk_widget_set_usize (ee->general_summary, 0, 60);
gtk_text_set_editable (GTK_TEXT (ee->general_summary), 1);
gtk_table_attach (GTK_TABLE (ee->general_table), ee->general_summary,
0, 1, SUMMARY_LINE, SUMMARY_LINE+1,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
l = ee_alarm_widgets (ee);
gtk_table_attach (GTK_TABLE (ee->general_table), l,
0, 1, ALARM_LINE, ALARM_LINE + 1,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
l = event_editor_setup_time_frame (ee);
gtk_table_attach (GTK_TABLE (ee->general_table), l,
0, 1, TIME_LINE, TIME_LINE + 1,
GTK_EXPAND | GTK_FILL | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
l = ee_classification_widgets (ee);
gtk_table_attach (GTK_TABLE (ee->general_table), l,
0, 1, CLASS_LINE, CLASS_LINE + 1,
GTK_EXPAND | GTK_SHRINK,
GTK_FILL | GTK_SHRINK,
0, 0);
}
static void
ee_init_summary_page (EventEditor *ee)
{
}
struct {
char *name;
} recurrence_types [] = {
{ N_("None") },
{ N_("Daily") },
{ N_("Weekly") },
{ N_("Monthly") },
{ N_("Yearly") },
{ 0 }
};
static void
recurrence_toggled (GtkRadioButton *radio, EventEditor *ee)
{
GSList *list = ee->recur_rr_group;
int which;
if (!GTK_TOGGLE_BUTTON (radio)->active)
return;
for (which = 0; list; list = list->next, which++) {
if (list->data == radio) {
gtk_notebook_set_page (GTK_NOTEBOOK (ee->recur_rr_notebook), 4 - which);
return;
}
}
}
static struct numbered_item weekday_positions[] = {
{ N_("1st"), 1 },
{ N_("2nd"), 2 },
{ N_("3rd"), 3 },
{ N_("4th"), 4 },
{ N_("5th"), 5 },
{ 0 }
};
static struct numbered_item weekday_names[] = {
{ N_("Monday"), 1 },
{ N_("Tuesday"), 2 },
{ N_("Wednesday"), 3 },
{ N_("Thursday"), 4 },
{ N_("Friday"), 5 },
{ N_("Saturday"), 6 },
{ N_("Sunday"), 0 }, /* on the spec, Sunday is zero */
{ 0 }
};
static GtkWidget *
make_numbered_menu (struct numbered_item *items, int sel)
{
GtkWidget *option_menu, *menu;
int i;
option_menu = gtk_option_menu_new ();
menu = gtk_menu_new ();
for (i = 0; items[i].text; i++) {
GtkWidget *item;
item = gtk_menu_item_new_with_label (_(items[i].text));
gtk_object_set_user_data (GTK_OBJECT (item), &items[i]);
gtk_menu_append (GTK_MENU (menu), item);
gtk_widget_show (item);
}
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), sel);
return option_menu;
}
static void
month_sensitize (EventEditor *ee, int state)
{
gtk_widget_set_sensitive (ee->recur_rr_month_date, state);
gtk_widget_set_sensitive (ee->recur_rr_month_date_label, state);
gtk_widget_set_sensitive (ee->recur_rr_month_day, !state);
gtk_widget_set_sensitive (ee->recur_rr_month_weekday, !state);
}
static void
recur_month_enable_date (GtkToggleButton *button, EventEditor *ee)
{
month_sensitize (ee, button->active);
}
static void
desensitize_on_toggle (GtkToggleButton *toggle, gpointer data)
{
gtk_widget_set_sensitive (GTK_WIDGET (data), !toggle->active);
}
static void
ee_rp_init_rule (EventEditor *ee)
{
static char *day_names [] = { N_("Mon"), N_("Tue"), N_("Wed"), N_("Thu"), N_("Fri"), N_("Sat"), N_("Sun") };
GtkWidget *r, *re, *r1, *f, *vbox, *hbox, *b, *week_hbox, *week_day, *w;
GtkWidget *none, *daily, *weekly, *monthly, *yearly;
GtkNotebook *notebook;
GSList *group;
int i, page, day_period, week_period, month_period, year_period;
int week_vector, default_day, def_pos, def_off;
struct tm tm;
tm = *localtime (&ee->ical->dtstart);
f = gtk_frame_new (_("Recurrence rule"));
hbox = gtk_hbox_new (FALSE, 4);
gtk_container_border_width (GTK_CONTAINER (hbox), 4);
gtk_container_add (GTK_CONTAINER (f), hbox);
vbox = gtk_vbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), gtk_vseparator_new (), FALSE, FALSE, 0);
ee->recur_rr_notebook = gtk_notebook_new ();
notebook = GTK_NOTEBOOK (ee->recur_rr_notebook);
gtk_box_pack_start (GTK_BOX (hbox), ee->recur_rr_notebook, TRUE, TRUE, 0);
day_period = 1;
week_period = 1;
month_period = 1;
year_period = 1;
/* Default to today */
week_vector = 1 << tm.tm_wday;
default_day = tm.tm_mday;
def_pos = 0;
def_off = 0;
/* Determine which should be the default selection */
page = 0;
if (ee->ical->recur) {
enum RecurType type = ee->ical->recur->type;
int interval = ee->ical->recur->interval;
switch (type) {
case RECUR_DAILY:
page = 1;
day_period = interval;
break;
case RECUR_WEEKLY:
page = 2;
week_period = interval;
week_vector = ee->ical->recur->weekday;
break;
case RECUR_MONTHLY_BY_POS:
page = 3;
month_period = interval;
def_pos = ee->ical->recur->u.month_pos;
default_day = ee->ical->recur->weekday; /* you can't use u.month_pos and u.month_day-- it's a union... */
break;
case RECUR_MONTHLY_BY_DAY:
page = 3;
month_period = interval;
default_day = ee->ical->recur->u.month_day;
break;
case RECUR_YEARLY_BY_MONTH:
page = 4;
year_period = interval;
break;
case RECUR_YEARLY_BY_DAY:
page = 4;
year_period = interval;
break;
}
} else
page = 0;
/* The recurrency selector */
for (i = 0, group = NULL; recurrence_types [i].name; i++) {
r = gtk_radio_button_new_with_label (group, _(recurrence_types [i].name));
group = gtk_radio_button_group (GTK_RADIO_BUTTON (r));
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (r), i == page);
gtk_signal_connect (GTK_OBJECT (r), "toggled", GTK_SIGNAL_FUNC (recurrence_toggled), ee);
gtk_box_pack_start (GTK_BOX (vbox), r, FALSE, FALSE, 0);
if (i == 0)
gtk_signal_connect (GTK_OBJECT (r), "toggled",
(GtkSignalFunc) desensitize_on_toggle,
ee->recur_hbox);
}
ee->recur_rr_group = group;
/* 0. No recurrence */
none = gtk_label_new ("");
/* 1. The daily recurrence */
daily = gtk_vbox_new (FALSE, 0);
b = gtk_hbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (daily), b, FALSE, FALSE, 0);
ee->recur_rr_day_period = make_spin_button (day_period, 1, 10000);
/* in some languages "Every" can follow the gender of the word it
refers to (here "day(s)"). leave the two leadin letter "d_"
in the translation they are ther on purpose */
gtk_box_pack_start (GTK_BOX (b), gtk_label_new (_("d_Every") +2), FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (b), ee->recur_rr_day_period, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (b), gtk_label_new (_("day(s)")), FALSE, FALSE, 0);
/* 2. The weekly recurrence */
weekly = gtk_vbox_new (FALSE, 4);
week_hbox = gtk_hbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (weekly), week_hbox, FALSE, FALSE, 0);
/* 2.1 The week period selector */
ee->recur_rr_week_period = make_spin_button (week_period, 1, 10000);
/* in some languages "Every" can follow the gender of the word it
refers to (here "week(s)"). leave the two leadin letter "w_"
in the translation they are ther on purpose */
gtk_box_pack_start (GTK_BOX (week_hbox), gtk_label_new (_("w_Every") +2), FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (week_hbox), ee->recur_rr_week_period, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (week_hbox), gtk_label_new (_("week(s)")), FALSE, FALSE, 0);
/* 2.2 The week day selector */
week_day = gtk_hbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (weekly), week_day, FALSE, FALSE, 0);
for (i = 0; i < 7; i++) {
ee->recur_rr_week_days [i] = gtk_check_button_new_with_label (_(day_names [i]));
gtk_box_pack_start (GTK_BOX (week_day), ee->recur_rr_week_days [i], FALSE, FALSE, 0);
if (week_vector & (1 << ((i + 1) % 7))) /* on the spec, Sunday is 0 */
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ee->recur_rr_week_days [i]), TRUE);
}
/* 3. The monthly recurrence */
monthly = gtk_table_new (0, 0, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (monthly), 4);
gtk_table_set_col_spacings (GTK_TABLE (monthly), 4);
re = gtk_radio_button_new_with_label (NULL, _("Recur on the"));
ee->recur_rr_month_date = make_spin_button (default_day, 1, 31);
ee->recur_rr_month_date_label = w = gtk_label_new (_("th day of the month"));
gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (monthly), re,
0, 1, 0, 1, FS, FS, 0, 0);
gtk_table_attach (GTK_TABLE (monthly), ee->recur_rr_month_date,
1, 2, 0, 1, FS, FS, 0, 0);
gtk_table_attach (GTK_TABLE (monthly), w,
2, 3, 0, 1, FS, FS, 0, 0);
gtk_signal_connect (GTK_OBJECT (re), "toggled", GTK_SIGNAL_FUNC (recur_month_enable_date), ee);
r1 = gtk_radio_button_new_with_label (gtk_radio_button_group (GTK_RADIO_BUTTON (re)), _("Recur on the"));
ee->recur_rr_month_day = make_numbered_menu (weekday_positions, def_pos);
ee->recur_rr_month_weekday = make_numbered_menu (weekday_names, default_day);
gtk_table_attach (GTK_TABLE (monthly), r1,
0, 1, 1, 2, FS, FS, 0, 0);
gtk_table_attach (GTK_TABLE (monthly), ee->recur_rr_month_day,
1, 2, 1, 2, FS, FS, 0, 0);
gtk_table_attach (GTK_TABLE (monthly), ee->recur_rr_month_weekday,
2, 3, 1, 2, FS, FS, 0, 0);
/* in some languages "Every" can follow the gender of the word it
refers to (here "month(s)"). leave the two leadin letter "m_"
in the translation they are ther on purpose */
gtk_table_attach (GTK_TABLE (monthly), gtk_label_new (_("m_Every") +2),
3, 4, 0, 2, FS, FS, 0, 0);
ee->recur_rr_month_period = make_spin_button (month_period, 1, 10000);
gtk_table_attach (GTK_TABLE (monthly), ee->recur_rr_month_period,
4, 5, 0, 2, FS, FS, 0, 0);
gtk_table_attach (GTK_TABLE (monthly), gtk_label_new (_("month(s)")),
5, 6, 0, 2, FS, FS, 0, 0);
if (ee->ical->recur) {
if (ee->ical->recur->type == RECUR_MONTHLY_BY_POS)
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (r1), 1);
} else
recur_month_enable_date (GTK_TOGGLE_BUTTON (re), ee);
/* 4. The yearly recurrence */
yearly = gtk_vbox_new (FALSE, 0);
b = gtk_hbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (yearly), b, FALSE, FALSE, 0);
ee->recur_rr_year_period = make_spin_button (year_period, 1, 10000);
/* in some languages "Every" can follow the gender of the word it
refers to (here "year(s)"). leave the two leadin letter "y_"
in the translation they are ther on purpose */
gtk_box_pack_start (GTK_BOX (b), gtk_label_new (_("y_Every") +2), FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (b), ee->recur_rr_year_period, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (b), gtk_label_new (_("year(s)")), FALSE, FALSE, 0);
/* Finish setting this up */
gtk_notebook_append_page (notebook, none, gtk_label_new (""));
gtk_notebook_append_page (notebook, daily, gtk_label_new (""));
gtk_notebook_append_page (notebook, weekly, gtk_label_new (""));
gtk_notebook_append_page (notebook, monthly, gtk_label_new (""));
gtk_notebook_append_page (notebook, yearly, gtk_label_new (""));
gtk_notebook_set_show_tabs (notebook, FALSE);
gtk_notebook_set_show_border (notebook, FALSE);
gtk_notebook_set_page (notebook, page);
/* Attach to the main box */
gtk_box_pack_start (GTK_BOX (ee->recur_vbox), f, FALSE, FALSE, 0);
}
static void
sensitize_on_toggle (GtkToggleButton *toggle, gpointer data)
{
gtk_widget_set_sensitive (GTK_WIDGET (data), toggle->active);
}
static void
ee_rp_init_ending_date (EventEditor *ee)
{
GtkWidget *frame;
GtkWidget *vbox;
GSList *group;
GtkWidget *radio0, *radio1, *radio2;
GtkWidget *hbox;
GtkWidget *ihbox;
GtkWidget *widget;
time_t enddate;
int repeat;
frame = gtk_frame_new (_("Ending date"));
vbox = gtk_vbox_new (TRUE, 4);
gtk_container_border_width (GTK_CONTAINER (vbox), 4);
gtk_container_add (GTK_CONTAINER (frame), vbox);
group = NULL;
/* repeat forever */
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
radio0 = gtk_radio_button_new_with_label (group, _("Repeat forever"));
group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio0));
gtk_box_pack_start (GTK_BOX (hbox), radio0, FALSE, FALSE, 0);
/* end on date */
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
radio1 = gtk_radio_button_new_with_label (group, _("End on"));
group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio1));
gtk_box_pack_start (GTK_BOX (hbox), radio1, FALSE, FALSE, 0);
ihbox = gtk_hbox_new (FALSE, 4);
gtk_widget_set_sensitive (ihbox, FALSE);
gtk_box_pack_start (GTK_BOX (hbox), ihbox, FALSE, FALSE, 0);
if (ee->ical->recur) {
/* Shorten by one day, as we store end-on date a day ahead */
enddate = ee->ical->recur->enddate - 86400;
} else
enddate = ee->ical->dtend;
ee->recur_ed_end_on = widget = date_edit_new (enddate, FALSE);
gtk_box_pack_start (GTK_BOX (ihbox), widget, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (radio1), "toggled",
(GtkSignalFunc) sensitize_on_toggle,
ihbox);
/* end after n occurrences */
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
radio2 = gtk_radio_button_new_with_label (group, _("End after"));
group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio2));
gtk_box_pack_start (GTK_BOX (hbox), radio2, FALSE, FALSE, 0);
ihbox = gtk_hbox_new (FALSE, 4);
gtk_widget_set_sensitive (ihbox, FALSE);
gtk_box_pack_start (GTK_BOX (hbox), ihbox, FALSE, FALSE, 0);
if (ee->ical->recur && ee->ical->recur->duration)
repeat = ee->ical->recur->duration;
else
repeat = 2;
ee->recur_ed_end_after = widget = make_spin_button (repeat, 1, 10000);
gtk_box_pack_start (GTK_BOX (ihbox), widget, FALSE, FALSE, 0);
widget = gtk_label_new (_("occurrence(s)"));
gtk_box_pack_start (GTK_BOX (ihbox), widget, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (radio2), "toggled",
(GtkSignalFunc) sensitize_on_toggle,
ihbox);
/* Activate appropriate item */
if (ee->ical->recur) {
if (ee->ical->recur->_enddate == 0) {
if (ee->ical->recur->duration == 0)
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (radio0), TRUE);
else {
gtk_spin_button_set_value (GTK_SPIN_BUTTON (ee->recur_ed_end_after),
ee->ical->recur->duration);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (radio2), TRUE);
}
} else {
gnome_date_edit_set_time (GNOME_DATE_EDIT (ee->recur_ed_end_on), ee->ical->recur->enddate);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (radio1), TRUE);
}
}
/* Done, add to main table */
ee->recur_ed_group = group;
gtk_box_pack_start (GTK_BOX (ee->recur_hbox), frame, FALSE, FALSE, 0);
}
static char *
get_exception_string (time_t t)
{
static char buf[256];
strftime (buf, sizeof(buf), _("%a %b %d %Y"), localtime (&t));
return buf;
}
static void
append_exception (EventEditor *ee, time_t t)
{
time_t *tt;
char *c[1];
int i;
c[0] = get_exception_string (t);
tt = g_new (time_t, 1);
*tt = t;
i = gtk_clist_append (GTK_CLIST (ee->recur_ex_clist), c);
gtk_clist_set_row_data (GTK_CLIST (ee->recur_ex_clist), i, tt);
gtk_clist_select_row (GTK_CLIST (ee->recur_ex_clist), i, 0);
gtk_widget_set_sensitive (ee->recur_ex_vbox, TRUE);
}
static void
fill_exception_clist (EventEditor *ee)
{
GList *list;
for (list = ee->ical->exdate; list; list = list->next)
append_exception (ee, *((time_t *) list->data));
}
static void
add_exception (GtkWidget *widget, EventEditor *ee)
{
time_t t;
t = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->recur_ex_date));
append_exception (ee, t);
}
static void
change_exception (GtkWidget *widget, EventEditor *ee)
{
GtkCList *clist;
time_t *t;
int sel;
clist = GTK_CLIST (ee->recur_ex_clist);
sel = GPOINTER_TO_INT(clist->selection->data);
t = gtk_clist_get_row_data (clist, sel);
*t = gnome_date_edit_get_date (GNOME_DATE_EDIT (ee->recur_ex_date));
gtk_clist_set_text (clist, sel, 0, get_exception_string (*t));
}
static void
delete_exception (GtkWidget *widget, EventEditor *ee)
{
GtkCList *clist;
int sel, length;
clist = GTK_CLIST (ee->recur_ex_clist);
sel = GPOINTER_TO_INT(clist->selection->data);
g_free (gtk_clist_get_row_data (clist, sel)); /* free the time_t stored there */
gtk_clist_remove (clist, sel);
length = g_list_length(clist->row_list);
if (sel >= length)
sel--;
gtk_clist_select_row (GTK_CLIST (ee->recur_ex_clist), sel, 0);
if (clist->rows == 0)
gtk_widget_set_sensitive (ee->recur_ex_vbox, FALSE);
}
static void
ee_rp_init_exceptions (EventEditor *ee)
{
GtkWidget *frame;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *ivbox;
GtkWidget *widget;
GtkWidget *sw;
frame = gtk_frame_new (_("Exceptions"));
hbox = gtk_hbox_new (FALSE, 4);
gtk_container_border_width (GTK_CONTAINER (hbox), 4);
gtk_container_add (GTK_CONTAINER (frame), hbox);
vbox = gtk_vbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
ee->recur_ex_date = widget = date_edit_new (time (NULL), FALSE);
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
widget = gtk_button_new_with_label (_("Add exception"));
gtk_signal_connect (GTK_OBJECT (widget), "clicked",
(GtkSignalFunc) add_exception,
ee);
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
ee->recur_ex_vbox = ivbox = gtk_vbox_new (FALSE, 4);
gtk_widget_set_sensitive (ivbox, FALSE); /* at first there are no items to change or delete */
gtk_box_pack_start (GTK_BOX (vbox), ivbox, FALSE, FALSE, 0);
widget = gtk_button_new_with_label (_("Change selected"));
gtk_signal_connect (GTK_OBJECT (widget), "clicked",
(GtkSignalFunc) change_exception,
ee);
gtk_box_pack_start (GTK_BOX (ivbox), widget, FALSE, FALSE, 0);
widget = gtk_button_new_with_label (_("Delete selected"));
gtk_signal_connect (GTK_OBJECT (widget), "clicked",
(GtkSignalFunc) delete_exception,
ee);
gtk_box_pack_start (GTK_BOX (ivbox), widget, FALSE, FALSE, 0);
ee->recur_ex_clist = widget = gtk_clist_new (1);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (sw), widget);
gtk_clist_set_selection_mode (GTK_CLIST (widget), GTK_SELECTION_BROWSE);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
fill_exception_clist (ee);
gtk_box_pack_start (GTK_BOX (hbox), sw, TRUE, TRUE, 0);
/* Done, add to main table */
gtk_box_pack_start (GTK_BOX (ee->recur_hbox), frame, TRUE, TRUE, 0);
}
static void
ee_init_recurrence_page (EventEditor *ee)
{
ee->recur_vbox = gtk_vbox_new (FALSE, 4);
gtk_container_border_width (GTK_CONTAINER (ee->recur_vbox), 4);
ee->recur_hbox = gtk_hbox_new (FALSE, 4);
gtk_widget_set_sensitive (ee->recur_hbox, FALSE);
ee->recur_page_label = gtk_label_new (_("Recurrence"));
gtk_notebook_append_page (GTK_NOTEBOOK (ee->notebook), ee->recur_vbox,
ee->recur_page_label);
ee_rp_init_rule (ee);
/* pack here so that the box gets inserted after the recurrence rule frame */
gtk_box_pack_start (GTK_BOX (ee->recur_vbox), ee->recur_hbox, FALSE, FALSE, 0);
ee_rp_init_ending_date (ee);
ee_rp_init_exceptions (ee);
}
static void
event_editor_init_widgets (EventEditor *ee)
{
ee->notebook = gtk_notebook_new ();
gtk_box_pack_start (GTK_BOX (GNOME_DIALOG(ee)->vbox), ee->notebook, 1, 1, 0);
/* Init the various configuration pages */
ee_init_general_page (ee);
ee_init_summary_page (ee);
ee_init_recurrence_page (ee);
/* Buttons */
ee_create_buttons(ee);
/* We show all of the contained widgets */
gtk_widget_show_all (GTK_BIN (ee)->child);
}
static void
event_editor_init (EventEditor *ee)
{
ee->ical = 0;
gnome_dialog_set_close (GNOME_DIALOG(ee), TRUE);
}
static void
event_editor_destroy (GtkObject *object)
{
EventEditor *ee;
g_return_if_fail (object != NULL);
g_return_if_fail (IS_EVENT_EDITOR (object));
ee = EVENT_EDITOR (object);
if (ee->ical)
ee->ical->user_data = NULL; /* we are no longer editing it */
}
GtkWidget *
event_editor_new (GnomeCalendar *gcal, iCalObject *ical)
{
GtkWidget *retval;
EventEditor *ee;
gdk_pointer_ungrab (GDK_CURRENT_TIME);
gdk_flush ();
retval = gtk_type_new (event_editor_get_type ());
ee = EVENT_EDITOR (retval);
if (ical == 0){
ical = ical_new ("", user_name, "");
ical->new = 1;
}
if (ical->new){
gtk_window_set_title (GTK_WINDOW (ee), _("Create new appointment"));
} else {
gtk_window_set_title (GTK_WINDOW (ee), _("Edit appointment"));
}
ical->user_data = ee; /* so that the world can know we are editing it */
ee->ical = ical;
ee->gnome_cal = gcal;
event_editor_init_widgets (ee);
return retval;
}
void
event_editor_new_whole_day (GnomeCalendar *owner, time_t day)
{
struct tm tm;
iCalObject *ico;
GtkWidget *ee;
g_return_if_fail (owner != NULL);
g_return_if_fail (GNOME_IS_CALENDAR (owner));
ico = ical_new ("", user_name, "");
ico->new = TRUE;
tm = *localtime (&day);
/* Set the start time of the event to the beginning of the day */
tm.tm_hour = day_begin;
tm.tm_min = 0;
tm.tm_sec = 0;
ico->dtstart = mktime (&tm);
/* Set the end time of the event to the end of the day */
tm.tm_hour = day_end;
ico->dtend = mktime (&tm);
/* Launch the event editor */
ee = event_editor_new (owner, ico);
gtk_widget_show (ee);
}