diff options
Diffstat (limited to 'calendar/gui/dialogs/alarm-page.c')
-rw-r--r-- | calendar/gui/dialogs/alarm-page.c | 778 |
1 files changed, 778 insertions, 0 deletions
diff --git a/calendar/gui/dialogs/alarm-page.c b/calendar/gui/dialogs/alarm-page.c new file mode 100644 index 0000000000..a4e0054c6b --- /dev/null +++ b/calendar/gui/dialogs/alarm-page.c @@ -0,0 +1,778 @@ +/* Evolution calendar - Alarm 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 the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gtk/gtksignal.h> +#include <libgnome/gnome-defs.h> +#include <libgnome/gnome-i18n.h> +#include <glade/glade.h> +#include <gal/widgets/e-unicode.h> +#include "cal-util/cal-util.h" +#include "e-util/e-dialog-widgets.h" +#include "alarm-page.h" + + + +/* Private part of the AlarmPage structure */ +struct _AlarmPagePrivate { + /* Glade XML data */ + GladeXML *xml; + + /* Widgets from the Glade file */ + + GtkWidget *main; + + GtkWidget *summary; + GtkWidget *starting_date; + + GtkWidget *list; + GtkWidget *add; + GtkWidget *delete; + + GtkWidget *action; + GtkWidget *interval_value; + GtkWidget *value_units; + GtkWidget *relative; + GtkWidget *time; +}; + + + +static void alarm_page_class_init (AlarmPageClass *class); +static void alarm_page_init (AlarmPage *apage); +static void alarm_page_destroy (GtkObject *object); + +static GtkWidget *alarm_page_get_widget (EditorPage *page); +static void alarm_page_fill_widgets (EditorPage *page, CalComponent *comp); +static void alarm_page_fill_component (EditorPage *page, CalComponent *comp); +static void alarm_page_set_summary (EditorPage *page, const char *summary); +static char *alarm_page_get_summary (EditorPage *page); +static void alarm_page_set_dtstart (EditorPage *page, time_t start); + +static EditorPageClass *parent_class = NULL; + + + +/** + * alarm_page_get_type: + * + * Registers the #AlarmPage class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #AlarmPage class. + **/ +GtkType +alarm_page_get_type (void) +{ + static GtkType alarm_page_type; + + if (!alarm_page_type) { + static const GtkTypeInfo alarm_page_info = { + "AlarmPage", + sizeof (AlarmPage), + sizeof (AlarmPageClass), + (GtkClassInitFunc) alarm_page_class_init, + (GtkObjectInitFunc) alarm_page_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + alarm_page_type = gtk_type_unique (TYPE_EDITOR_PAGE, &alarm_page_info); + } + + return alarm_page_type; +} + +/* Class initialization function for the alarm page */ +static void +alarm_page_class_init (AlarmPageClass *class) +{ + EditorPageClass *editor_page_class; + GtkObjectClass *object_class; + + editor_page_class = (EditorPageClass *) class; + object_class = (GtkObjectClass *) class; + + parent_class = gtk_type_class (TYPE_EDITOR_PAGE); + + editor_page_class->get_widget = alarm_page_get_widget; + editor_page_class->fill_widgets = alarm_page_fill_widgets; + editor_page_class->fill_component = alarm_page_fill_component; + editor_page_class->set_summary = alarm_page_set_summary; + editor_page_class->get_summary = alarm_page_get_summary; + editor_page_class->set_dtstart = alarm_page_set_dtstart; + + object_class->destroy = alarm_page_destroy; +} + +/* Object initialization function for the alarm page */ +static void +alarm_page_init (AlarmPage *apage) +{ + AlarmPagePrivate *priv; + + priv = g_new0 (AlarmPagePrivate, 1); + apage->priv = priv; + + priv->xml = NULL; + + priv->main = NULL; + priv->summary = NULL; + priv->starting_date = NULL; + priv->list = NULL; + priv->add = NULL; + priv->delete = NULL; + priv->action = NULL; + priv->interval_value = NULL; + priv->value_units = NULL; + priv->relative = NULL; + priv->time = NULL; +} + +/* Frees all the alarm data and empties the list */ +static void +free_alarms (AlarmPage *apage) +{ + AlarmPagePrivate *priv; + GtkCList *clist; + int i; + + priv = apage->priv; + + clist = GTK_CLIST (priv->list); + + for (i = 0; i < clist->rows; i++) { + CalComponentAlarm *alarm; + + alarm = gtk_clist_get_row_data (clist, i); + g_assert (alarm != NULL); + cal_component_alarm_free (alarm); + + gtk_clist_set_row_data (clist, i, NULL); + } + + gtk_clist_clear (clist); +} + +/* Destroy handler for the alarm page */ +static void +alarm_page_destroy (GtkObject *object) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_ALARM_PAGE (object)); + + apage = ALARM_PAGE (object); + priv = apage->priv; + + if (priv->xml) { + gtk_object_unref (GTK_OBJECT (priv->xml)); + priv->xml = NULL; + } + + free_alarms (apage); + + g_free (priv); + apage->priv = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + + + +/* get_widget handler for the alarm page */ +static GtkWidget * +alarm_page_get_widget (EditorPage *page) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + + apage = ALARM_PAGE (page); + priv = apage->priv; + + return priv->main; +} + +/* Fills the widgets with default values */ +static void +clear_widgets (AlarmPage *apage) +{ + AlarmPagePrivate *priv; + + priv = apage->priv; + + /* Summary */ + e_dialog_editable_set (priv->summary, NULL); + + /* Start date */ + gtk_label_set_text (GTK_LABEL (priv->starting_date), ""); + + /* List data */ + free_alarms (apage); +} + +static char * +get_alarm_duration_string (struct icaldurationtype *duration) +{ + GString *string = g_string_new (NULL); + char *ret; + + if (duration->days > 1) + g_string_sprintf (string, _("%d days"), duration->days); + else if (duration->days == 1) + g_string_append (string, _("1 day")); + + if (duration->weeks > 1) + g_string_sprintf (string, _("%d weeks"), duration->weeks); + else if (duration->weeks == 1) + g_string_append (string, _("1 week")); + + if (duration->hours > 1) + g_string_sprintf (string, _("%d hours"), duration->hours); + else if (duration->hours == 1) + g_string_append (string, _("1 hour")); + + if (duration->minutes > 1) + g_string_sprintf (string, _("%d minutes"), duration->minutes); + else if (duration->minutes == 1) + g_string_append (string, _("1 minute")); + + if (duration->seconds > 1) + g_string_sprintf (string, _("%d seconds"), duration->seconds); + else if (duration->seconds == 1) + g_string_append (string, _("1 second")); + + ret = string->str; + g_string_free (string, FALSE); + + return ret; +} + +static char * +get_alarm_string (CalComponentAlarm *alarm) +{ + CalAlarmAction action; + CalAlarmTrigger trigger; + char string[256]; + char *base; + char *str; + char *dur; + + string [0] = '\0'; + + cal_component_alarm_get_action (alarm, &action); + cal_component_alarm_get_trigger (alarm, &trigger); + + switch (action) { + case CAL_ALARM_AUDIO: + base = _("Play a sound"); + break; + + case CAL_ALARM_DISPLAY: + base = _("Show a dialog"); + break; + + case CAL_ALARM_EMAIL: + base = _("Send an email"); + break; + + case CAL_ALARM_PROCEDURE: + base = _("Run a program"); + break; + + case CAL_ALARM_NONE: + case CAL_ALARM_UNKNOWN: + base = _("Unknown"); + break; + } + + /* FIXME: This does not look like it will localize correctly. */ + + switch (trigger.type) { + case CAL_ALARM_TRIGGER_RELATIVE_START: + dur = get_alarm_duration_string (&trigger.u.rel_duration); + + if (trigger.u.rel_duration.is_neg) + str = g_strdup_printf ("%s %s %s", base, dur, + _(" before start of appointment")); + else + str = g_strdup_printf ("%s %s %s", base, dur, + _(" after start of appointment")); + + g_free (dur); + break; + + case CAL_ALARM_TRIGGER_RELATIVE_END: + dur = get_alarm_duration_string (&trigger.u.rel_duration); + + if (trigger.u.rel_duration.is_neg) + str = g_strdup_printf ("%s %s %s", base, dur, + _(" before end of appointment")); + else + str = g_strdup_printf ("%s %s %s", base, dur, + _(" after end of appointment")); + + g_free (dur); + break; + case CAL_ALARM_TRIGGER_NONE: + case CAL_ALARM_TRIGGER_ABSOLUTE: + str = g_strdup_printf ("%s %s", base, + _("Unknown")); + break; + } + + return str; +} + +/* Appends an alarm to the list */ +static void +append_reminder (AlarmPage *apage, CalComponentAlarm *alarm) +{ + AlarmPagePrivate *priv; + GtkCList *clist; + char *c[1]; + int i; + + priv = apage->priv; + + clist = GTK_CLIST (priv->list); + + c[0] = get_alarm_string (alarm); + i = gtk_clist_append (clist, c); + + gtk_clist_set_row_data (clist, i, alarm); + gtk_clist_select_row (clist, i, 0); + g_free (c[0]); + + gtk_widget_set_sensitive (priv->delete, TRUE); +} + +/* fill_widgets handler for the alarm page */ +static void +alarm_page_fill_widgets (EditorPage *page, CalComponent *comp) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + CalComponentText text; + GList *alarms, *l; + GtkCList *clist; + + apage = ALARM_PAGE (page); + priv = apage->priv; + + clear_widgets (apage); + + /* Summary */ + cal_component_get_summary (comp, &text); + e_dialog_editable_set (priv->summary, text.value); + + /* List */ + if (!cal_component_has_alarms (comp)) + return; + + alarms = cal_component_get_alarm_uids (comp); + + clist = GTK_CLIST (priv->list); + for (l = alarms; l != NULL; l = l->next) { + CalComponentAlarm *ca, *ca_copy; + const char *auid; + + auid = l->data; + ca = cal_component_get_alarm (comp, auid); + g_assert (ca != NULL); + + ca_copy = cal_component_alarm_clone (ca); + cal_component_alarm_free (ca); + + append_reminder (apage, ca_copy); + } + cal_obj_uid_list_free (alarms); +} + +/* fill_component handler for the alarm page */ +static void +alarm_page_fill_component (EditorPage *page, CalComponent *comp) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + GList *list, *l; + GtkCList *clist; + int i; + + apage = ALARM_PAGE (page); + priv = apage->priv; + + /* Remove all the alarms from the component */ + + list = cal_component_get_alarm_uids (comp); + for (l = list; l; l = l->next) { + const char *auid; + + auid = l->data; + cal_component_remove_alarm (comp, auid); + } + cal_obj_uid_list_free (list); + + /* Add the new alarms */ + + clist = GTK_CLIST (priv->list); + for (i = 0; i < clist->rows; i++) { + CalComponentAlarm *alarm, *alarm_copy; + + alarm = gtk_clist_get_row_data (clist, i); + g_assert (alarm != NULL); + + /* We clone the alarm to maintain the invariant that the alarm + * structures in the list did *not* come from the component. + */ + + alarm_copy = cal_component_alarm_clone (alarm); + cal_component_add_alarm (comp, alarm); + cal_component_alarm_free (alarm_copy); + } +} + +/* set_summary handler for the alarm page */ +static void +alarm_page_set_summary (EditorPage *page, const char *summary) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + + apage = ALARM_PAGE (page); + priv = apage->priv; + + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->summary), apage); + e_utf8_gtk_entry_set_text (GTK_ENTRY (priv->summary), summary); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->summary), apage); +} + +/* get_summary handler for the alarm page */ +static char * +alarm_page_get_summary (EditorPage *page) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + + apage = ALARM_PAGE (page); + priv = apage->priv; + + return e_utf8_gtk_entry_get_text (GTK_ENTRY (priv->summary)); +} + +/* set_dtstart handler for the alarm page */ +static void +alarm_page_set_dtstart (EditorPage *page, time_t start) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + char str[128]; + struct tm tm; + + apage = ALARM_PAGE (page); + priv = apage->priv; + + tm = *localtime (&start); + strftime (str, sizeof (str), _("%A %b %d %Y %H:%M:%S"), &tm); + + gtk_entry_set_text (GTK_ENTRY (priv->starting_date), str); +} + + + +/* "relative" types */ +enum { + BEFORE, + AFTER +}; + +/* Time units */ +enum { + MINUTES, + HOURS, + DAYS +}; + +/* Option menu maps */ +static const int action_map[] = { + CAL_ALARM_DISPLAY, + CAL_ALARM_AUDIO, + CAL_ALARM_EMAIL, + CAL_ALARM_PROCEDURE, + -1 +}; + +static const int value_map[] = { + MINUTES, + HOURS, + DAYS, + -1 +}; + +static const int relative_map[] = { + BEFORE, + AFTER, + -1 +}; + +static const int time_map[] = { + CAL_ALARM_TRIGGER_RELATIVE_START, + CAL_ALARM_TRIGGER_RELATIVE_END, + -1 +}; + +/* Gets the widgets from the XML file and returns if they are all available. */ +static gboolean +get_widgets (AlarmPage *apage) +{ + AlarmPagePrivate *priv; + GtkWidget *toplevel; + + priv = apage->priv; + +#define GW(name) glade_xml_get_widget (priv->xml, name) + + toplevel = GW ("alarm-toplevel"); + priv->main = GW ("alarm-page"); + if (!(toplevel && priv->main)) + return FALSE; + + gtk_widget_ref (priv->main); + gtk_widget_unparent (priv->main); + gtk_widget_destroy (toplevel); + + priv->summary = GW ("summary"); + priv->starting_date = GW ("starting-date"); + + priv->list = GW ("list"); + priv->add = GW ("add"); + priv->delete = GW ("delete"); + + priv->action = GW ("action"); + priv->interval_value = GW ("interval-value"); + priv->value_units = GW ("value-units"); + priv->relative = GW ("relative"); + priv->time = GW ("time"); + +#undef GW + + return (priv->summary + && priv->starting_date + && priv->list + && priv->add + && priv->delete + && priv->action + && priv->interval_value + && priv->value_units + && priv->relative + && priv->time); +} + +/* Callback used when the summary changes; we emit the notification signal. */ +static void +summary_changed_cb (GtkEditable *editable, gpointer data) +{ + AlarmPage *apage; + + apage = ALARM_PAGE (data); + editor_page_notify_summary_changed (EDITOR_PAGE (apage)); +} + +/* This is called when any field is changed; it notifies upstream. */ +static void +field_changed_cb (GtkWidget *widget, gpointer data) +{ + AlarmPage *apage; + + apage = ALARM_PAGE (data); + editor_page_notify_changed (EDITOR_PAGE (apage)); +} + +/* Callback used for the "add reminder" button */ +static void +add_clicked_cb (GtkButton *button, gpointer data) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + CalComponentAlarm *alarm; + CalAlarmTrigger trigger; + + apage = ALARM_PAGE (data); + priv = apage->priv; + + alarm = cal_component_alarm_new (); + + memset (&trigger, 0, sizeof (CalAlarmTrigger)); + trigger.type = e_dialog_option_menu_get (priv->time, time_map); + if (e_dialog_option_menu_get (priv->relative, relative_map) == BEFORE) + trigger.u.rel_duration.is_neg = 1; + else + trigger.u.rel_duration.is_neg = 0; + + switch (e_dialog_option_menu_get (priv->value_units, value_map)) { + case MINUTES: + trigger.u.rel_duration.minutes = e_dialog_spin_get_int (priv->interval_value); + break; + + case HOURS: + trigger.u.rel_duration.hours = e_dialog_spin_get_int (priv->interval_value); + break; + + case DAYS: + trigger.u.rel_duration.days = e_dialog_spin_get_int (priv->interval_value); + break; + + default: + g_assert_not_reached (); + } + cal_component_alarm_set_trigger (alarm, trigger); + + cal_component_alarm_set_action (alarm, e_dialog_option_menu_get (priv->action, action_map)); + + append_reminder (apage, alarm); +} + +/* Callback used for the "delete reminder" button */ +static void +delete_clicked_cb (GtkButton *button, gpointer data) +{ + AlarmPage *apage; + AlarmPagePrivate *priv; + GtkCList *clist; + CalComponentAlarm *alarm; + int sel; + + apage = ALARM_PAGE (data); + priv = apage->priv; + + clist = GTK_CLIST (priv->list); + if (!clist->selection) + return; + + sel = GPOINTER_TO_INT (clist->selection->data); + + alarm = gtk_clist_get_row_data (clist, sel); + g_assert (alarm != NULL); + cal_component_alarm_free (alarm); + gtk_clist_set_row_data (clist, sel, NULL); + + 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->delete, FALSE); +} + +/* Hooks the widget signals */ +static void +init_widgets (AlarmPage *apage) +{ + AlarmPagePrivate *priv; + + priv = apage->priv; + + /* Summary */ + gtk_signal_connect (GTK_OBJECT (priv->summary), "changed", + GTK_SIGNAL_FUNC (summary_changed_cb), apage); + + /* Reminder buttons */ + gtk_signal_connect (GTK_OBJECT (priv->add), "clicked", + GTK_SIGNAL_FUNC (add_clicked_cb), apage); + gtk_signal_connect (GTK_OBJECT (priv->delete), "clicked", + GTK_SIGNAL_FUNC (delete_clicked_cb), apage); + + /* Connect the default signal handler to use to make sure we notify + * upstream of changes to the widget values. + */ + gtk_signal_connect (GTK_OBJECT (priv->add), "clicked", + GTK_SIGNAL_FUNC (field_changed_cb), apage); + gtk_signal_connect (GTK_OBJECT (priv->delete), "clicked", + GTK_SIGNAL_FUNC (field_changed_cb), apage); +} + + + +/** + * alarm_page_construct: + * @apage: An alarm page. + * + * Constructs an alarm page by loading its Glade data. + * + * Return value: The same object as @apage, or NULL if the widgets could not be + * created. + **/ +AlarmPage * +alarm_page_construct (AlarmPage *apage) +{ + AlarmPagePrivate *priv; + + priv = apage->priv; + + priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/alarm-page.glade", NULL); + if (!priv->xml) { + g_message ("alarm_page_construct(): Could not load the Glade XML file!"); + return NULL; + } + + if (!get_widgets (apage)) { + g_message ("alarm_page_construct(): Could not find all widgets in the XML file!"); + return NULL; + } + + init_widgets (apage); + + return apage; +} + +/** + * alarm_page_new: + * + * Creates a new alarm page. + * + * Return value: A newly-created alarm page, or NULL if the page could not be + * created. + **/ +AlarmPage * +alarm_page_new (void) +{ + AlarmPage *apage; + + apage = gtk_type_new (TYPE_ALARM_PAGE); + if (!alarm_page_construct (apage)) { + gtk_object_unref (GTK_OBJECT (apage)); + return NULL; + } + + return apage; +} |