diff options
-rw-r--r-- | calendar/ChangeLog | 49 | ||||
-rw-r--r-- | calendar/cal-util/cal-component.c | 171 | ||||
-rw-r--r-- | calendar/cal-util/cal-component.h | 2 | ||||
-rw-r--r-- | calendar/gui/Makefile.am | 2 | ||||
-rw-r--r-- | calendar/gui/dialogs/Makefile.am | 19 | ||||
-rw-r--r-- | calendar/gui/dialogs/alarm-page.c | 778 | ||||
-rw-r--r-- | calendar/gui/dialogs/alarm-page.glade | 381 | ||||
-rw-r--r-- | calendar/gui/dialogs/alarm-page.h | 64 | ||||
-rw-r--r-- | calendar/gui/dialogs/editor-page.c | 259 | ||||
-rw-r--r-- | calendar/gui/dialogs/editor-page.h | 86 | ||||
-rw-r--r-- | calendar/gui/dialogs/event-page.c | 908 | ||||
-rw-r--r-- | calendar/gui/dialogs/event-page.glade | 429 | ||||
-rw-r--r-- | calendar/gui/dialogs/event-page.h | 70 | ||||
-rw-r--r-- | calendar/gui/dialogs/recurrence-page.c | 900 | ||||
-rw-r--r-- | calendar/gui/dialogs/recurrence-page.glade | 607 | ||||
-rw-r--r-- | calendar/gui/dialogs/recurrence-page.h | 64 | ||||
-rw-r--r-- | calendar/gui/dialogs/task-details-page.glade | 137 | ||||
-rw-r--r-- | calendar/gui/dialogs/task-page.glade | 944 | ||||
-rw-r--r-- | calendar/gui/e-day-view.c | 4 | ||||
-rw-r--r-- | calendar/gui/e-week-view.c | 1 | ||||
-rw-r--r-- | calendar/gui/event-editor.c | 2 |
21 files changed, 5239 insertions, 638 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index fecd71e071..c903d61031 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,52 @@ +2001-05-16 Federico Mena Quintero <federico@ximian.com> + + Split the event and task editors into different objects for the + separate pages; this way they can be shared by both editors. + + * gui/dialogs/editor-page.[ch]: New abstract class for a page in a + calendar component editor. + + * gui/dialogs/event-page.[ch]: Main page of an event editor. + + * gui/dialogs/alarm-page.[ch]: Alarm page of a calendar component + editor. + + * gui/dialogs/recurrence-page.[ch]: Recurrence page of a calendar + component editor. + + * gui/dialogs/event-page.c (event_page_fill_widgets): Eeek, this + was missing a bunch of break statements. + (event_page_fill_component): Use a temporary variable rather than + allocating a struct icaltimetype. + + * gui/dialogs/alarm-page.c (get_alarm_string): Do not use + fixed-size buffers. + (alarm_page_fill_widgets): Use cal_obj_uid_list_free(). + (append_reminder): Now the list stores the plain CalComponentAlarm + structures in the row data. We do *NOT* want to be frobbing the + component's data directly. Rather, we clone the alarms from the + component and maintain them on our own. + (alarm_page_fill_component): Clone the alarms before adding them + to the component so that we maintain the invariant that the alarm + structures in the list did *not* come from the component. + + * cal-util/cal-component.c (cal_component_add_alarm): Added + documentation. + (cal_component_remove_alarm): Added documentation. + (cal_component_remove_alarm): Do a lookup in our hash table of + alarms instead of scanning the whole component. + (CalComponentAlarm): Removed the `parent' field, since it was + unused. + (cal_component_free_alarm_uids): Removed function, since + cal_component_get_alarm_uids() is documented so that the user will + know that he must use cal_obj_uid_list_free(). + (cal_component_alarm_clone): New function. + +2001-05-09 Federico Mena Quintero <federico@ximian.com> + + * gui/Makefile.am (evolution_calendar_SOURCES): Added + editor-page.[ch] to the list of sources. + 2001-05-09 JP Rosevear <jpr@ximian.com> * gui/event-editor.c (reminder_add_cb): switch on the correct diff --git a/calendar/cal-util/cal-component.c b/calendar/cal-util/cal-component.c index d43234617a..d716c0e581 100644 --- a/calendar/cal-util/cal-component.c +++ b/calendar/cal-util/cal-component.c @@ -110,9 +110,6 @@ struct _CalComponentPrivate { /* Private structure for alarms */ struct _CalComponentAlarm { - /* Our parent component */ - CalComponent *parent; - /* Alarm icalcomponent we wrap */ icalcomponent *icalcomp; @@ -348,7 +345,7 @@ cal_component_gen_uid (void) iso = isodate_from_time_t (t); ret = g_strdup_printf ("%s-%d-%d-%d-%d@%s", - iso, + iso, getpid (), getgid (), getppid (), @@ -692,17 +689,6 @@ add_alarm (CalComponent *comp, icalcomponent *alarm, const char *auid) return auid; } -static void -remove_alarm (CalComponent *comp, const char *auid) -{ - CalComponentPrivate *priv; - - priv = comp->priv; - - g_hash_table_remove (priv->alarm_uid_hash, auid); -} - - /* Scans an alarm subcomponent, adds an UID extension property to it (so that we * can reference alarms by unique IDs), and adds its mapping to the component. */ static void @@ -1129,12 +1115,12 @@ cal_component_set_uid (CalComponent *comp, const char *uid) /** * cal_component_get_categories: - * @comp: A calendar component object. - * @categories: - * - * + * @comp: A calendar component object. + * @categories: + * + * **/ -void +void cal_component_get_categories (CalComponent *comp, const char **categories) { CalComponentPrivate *priv; @@ -1155,11 +1141,11 @@ cal_component_get_categories (CalComponent *comp, const char **categories) /** * cal_component_set_categories: * @comp: A calendar component object. - * @categories: - * - * + * @categories: + * + * **/ -void +void cal_component_set_categories (CalComponent *comp, const char *categories) { CalComponentPrivate *priv; @@ -1286,7 +1272,7 @@ cal_component_set_categories_list (CalComponent *comp, GSList *categ_list) icalcomponent_remove_property (priv->icalcomp, priv->categories); icalproperty_free (priv->categories); } - + return; } @@ -3457,63 +3443,64 @@ cal_component_has_alarms (CalComponent *comp) return g_hash_table_size (priv->alarm_uid_hash) != 0; } -void +/** + * cal_component_add_alarm: + * @comp: A calendar component. + * @alarm: An alarm. + * + * Adds an alarm subcomponent to a calendar component. You should have created + * the @alarm by using cal_component_alarm_new(); it is invalid to use a + * #CalComponentAlarm structure that came from cal_component_get_alarm(). After + * adding the alarm, the @alarm structure is no longer valid because the + * internal structures may change and you should get rid of it by using + * cal_component_alarm_free(). + **/ +void cal_component_add_alarm (CalComponent *comp, CalComponentAlarm *alarm) { CalComponentPrivate *priv; - + g_return_if_fail (comp != NULL); g_return_if_fail (IS_CAL_COMPONENT (comp)); g_return_if_fail (alarm != NULL); - + priv = comp->priv; - - alarm->parent = comp; + add_alarm (comp, alarm->icalcomp, icalproperty_get_x (alarm->uid)); icalcomponent_add_component (priv->icalcomp, alarm->icalcomp); } -void +/** + * cal_component_remove_alarm: + * @comp: A calendar component. + * @auid: UID of the alarm to remove. + * + * Removes an alarm subcomponent from a calendar component. If the alarm that + * corresponds to the specified @auid had been fetched with + * cal_component_get_alarm(), then those alarm structures will be invalid; you + * should get rid of them with cal_component_alarm_free() before using this + * function. + **/ +void cal_component_remove_alarm (CalComponent *comp, const char *auid) { CalComponentPrivate *priv; - icalcompiter iter; + icalcomponent *alarm; g_return_if_fail (comp != NULL); g_return_if_fail (IS_CAL_COMPONENT (comp)); g_return_if_fail (auid != NULL); priv = comp->priv; + g_return_if_fail (priv->icalcomp != NULL); - for (iter = icalcomponent_begin_component (priv->icalcomp, ICAL_VALARM_COMPONENT); - icalcompiter_deref (&iter) != NULL; - icalcompiter_next (&iter)) { - icalproperty *prop; - icalcomponent *subcomp; + alarm = g_hash_table_lookup (priv->alarm_uid_hash, auid); + if (!alarm) + return; - subcomp = icalcompiter_deref (&iter); - for (prop = icalcomponent_get_first_property (subcomp, ICAL_X_PROPERTY); - prop; - prop = icalcomponent_get_next_property (subcomp, ICAL_X_PROPERTY)) { - const char *xname; - const char *alarm_uid; - - xname = icalproperty_get_x_name (prop); - g_assert (xname != NULL); - - if (strcmp (xname, EVOLUTION_ALARM_UID_PROPERTY) == 0) { - alarm_uid = alarm_uid_from_prop (prop); - if (strcmp (alarm_uid, auid) == 0) { - remove_alarm (comp, auid); - icalcomponent_remove_component (priv->icalcomp, subcomp); - icalcomponent_free (subcomp); - break; - } - - return; - } - } - } + g_hash_table_remove (priv->alarm_uid_hash, auid); + icalcomponent_remove_component (priv->icalcomp, alarm); + icalcomponent_free (alarm); } @@ -3553,14 +3540,13 @@ scan_alarm_property (CalComponentAlarm *alarm, icalproperty *prop) /* Creates a CalComponentAlarm from a libical alarm subcomponent */ static CalComponentAlarm * -make_alarm (CalComponent *comp, icalcomponent *subcomp) +make_alarm (icalcomponent *subcomp) { CalComponentAlarm *alarm; icalproperty *prop; alarm = g_new (CalComponentAlarm, 1); - alarm->parent = comp; alarm->icalcomp = subcomp; alarm->uid = NULL; @@ -3590,10 +3576,10 @@ add_alarm_uid (gpointer key, gpointer value, gpointer data) /** * cal_component_get_alarm_uids: * @comp: A calendar component. - * + * * Builds a list of the unique identifiers of the alarm subcomponents inside a * calendar component. - * + * * Return value: List of unique identifiers for alarms. This should be freed * using cal_obj_uid_list_free(). **/ @@ -3619,9 +3605,9 @@ cal_component_get_alarm_uids (CalComponent *comp) * cal_component_get_alarm: * @comp: A calendar component. * @auid: Unique identifier for the sought alarm subcomponent. - * + * * Queries a particular alarm subcomponent of a calendar component. - * + * * Return value: The alarm subcomponent that corresponds to the specified @auid, * or #NULL if no alarm exists with that UID. This should be freed using * cal_component_alarm_free(). @@ -3643,21 +3629,15 @@ cal_component_get_alarm (CalComponent *comp, const char *auid) alarm = g_hash_table_lookup (priv->alarm_uid_hash, auid); if (alarm) - return make_alarm (comp, alarm); + return make_alarm (alarm); else return NULL; } -void -cal_component_free_alarm_uids (GList *alarm_uids) -{ - g_list_foreach (alarm_uids, (GFunc)g_free, NULL); -} - /** * cal_component_alarms_free: * @alarms: Component alarms structure. - * + * * Frees a #CalComponentAlarms structure. **/ void @@ -3684,17 +3664,19 @@ cal_component_alarms_free (CalComponentAlarms *alarms) /** * cal_component_alarm_new: - * - * - * + * + * + * * Return value: a new alarm component **/ CalComponentAlarm * cal_component_alarm_new (void) { - CalComponentAlarm *alarm = g_new0 (CalComponentAlarm, 1); + CalComponentAlarm *alarm; char *new_auid ; + alarm = g_new (CalComponentAlarm, 1); + alarm->icalcomp = icalcomponent_new (ICAL_VALARM_COMPONENT); new_auid = cal_component_gen_uid (); @@ -3702,16 +3684,39 @@ cal_component_alarm_new (void) icalproperty_set_x_name (alarm->uid, EVOLUTION_ALARM_UID_PROPERTY); icalcomponent_add_property (alarm->icalcomp, alarm->uid); g_free (new_auid); - + + alarm->action = NULL; + alarm->trigger = NULL; + return alarm; } /** - * cal_component_alarm_get_uid: + * cal_component_alarm_clone: * @alarm: An alarm subcomponent. * - * Queries the unique identifier of an alarm subcomponent. + * Creates a new alarm subcomponent by copying the information from another one. * + * Return value: A newly-created alarm subcomponent with the same values as the + * original one. Should be freed with cal_component_alarm_free(). + **/ +CalComponentAlarm * +cal_component_alarm_clone (CalComponentAlarm *alarm) +{ + icalcomponent *icalcomp; + + g_return_val_if_fail (alarm != NULL, NULL); + + icalcomp = icalcomponent_new_clone (alarm->icalcomp); + return make_alarm (icalcomp); +} + +/** + * cal_component_alarm_get_uid: + * @alarm: An alarm subcomponent. + * + * Queries the unique identifier of an alarm subcomponent. + * * Return value: UID of the alarm. **/ const char * @@ -4007,9 +4012,9 @@ cal_component_alarm_free (CalComponentAlarm *alarm) icalcomponent_free (alarm->icalcomp); alarm->icalcomp = NULL; - - alarm->parent = NULL; + alarm->uid = NULL; alarm->action = NULL; + alarm->trigger = NULL; g_free (alarm); } diff --git a/calendar/cal-util/cal-component.h b/calendar/cal-util/cal-component.h index 95d2b1eb0b..e4a2e2421e 100644 --- a/calendar/cal-util/cal-component.h +++ b/calendar/cal-util/cal-component.h @@ -336,12 +336,12 @@ void cal_component_remove_alarm (CalComponent *comp, const char *auid); GList *cal_component_get_alarm_uids (CalComponent *comp); CalComponentAlarm *cal_component_get_alarm (CalComponent *comp, const char *auid); -void cal_component_free_alarm_uids (GList *alarm_uids); void cal_component_alarms_free (CalComponentAlarms *alarms); /* CalComponentAlarms */ CalComponentAlarm *cal_component_alarm_new (void); +CalComponentAlarm *cal_component_alarm_clone (CalComponentAlarm *alarm); const char *cal_component_alarm_get_uid (CalComponentAlarm *alarm); diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index 292e1ebd28..8cd202c7c0 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -87,6 +87,8 @@ evolution_calendar_SOURCES = \ e-week-view.h \ e-tasks.c \ e-tasks.h \ + editor-page.c \ + editor-page.h \ event-editor.c \ event-editor.h \ gnome-cal.c \ diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am index 12342538ab..ec4e31379d 100644 --- a/calendar/gui/dialogs/Makefile.am +++ b/calendar/gui/dialogs/Makefile.am @@ -20,19 +20,30 @@ noinst_LIBRARIES = libcal-dialogs.a libcal_dialogs_a_SOURCES = \ alarm-notify-dialog.c \ alarm-notify-dialog.h \ + alarm-page.c \ + alarm-page.h \ cal-prefs-dialog.c \ cal-prefs-dialog.h \ delete-comp.c \ delete-comp.h \ + editor-page.c \ + editor-page.h \ + event-page.c \ + event-page.h \ save-comp.c \ save-comp.h \ task-editor.c \ task-editor.h -glade_DATA = \ - alarm-notify.glade \ - cal-prefs-dialog.glade \ - task-editor-dialog.glade +glade_DATA = \ + alarm-notify.glade \ + alarm-page.glade \ + cal-prefs-dialog.glade \ + event-page.glade \ + recurrence-page.glade \ + task-details-page.glade \ + task-editor-dialog.glade \ + task-page.glade EXTRA_DIST = \ $(glade_DATA) 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; +} diff --git a/calendar/gui/dialogs/alarm-page.glade b/calendar/gui/dialogs/alarm-page.glade new file mode 100644 index 0000000000..3a4a8d6765 --- /dev/null +++ b/calendar/gui/dialogs/alarm-page.glade @@ -0,0 +1,381 @@ +<?xml version="1.0"?> +<GTK-Interface> + +<project> + <name>alarm-page</name> + <program_name>alarm-page</program_name> + <directory></directory> + <source_directory>.</source_directory> + <pixmaps_directory>pixmaps</pixmaps_directory> + <language>C</language> + <gnome_support>True</gnome_support> + <gettext_support>True</gettext_support> + <output_main_file>False</output_main_file> + <output_support_files>False</output_support_files> + <output_build_files>False</output_build_files> +</project> + +<widget> + <class>GtkWindow</class> + <name>alarm-toplevel</name> + <title>window1</title> + <type>GTK_WINDOW_TOPLEVEL</type> + <position>GTK_WIN_POS_NONE</position> + <modal>False</modal> + <allow_shrink>False</allow_shrink> + <allow_grow>True</allow_grow> + <auto_shrink>False</auto_shrink> + + <widget> + <class>GtkVBox</class> + <name>alarm-page</name> + <border_width>4</border_width> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + + <widget> + <class>GtkFrame</class> + <name>frame33</name> + <label>Appointment Basics</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkTable</class> + <name>table13</name> + <border_width>4</border_width> + <rows>2</rows> + <columns>2</columns> + <homogeneous>False</homogeneous> + <row_spacing>2</row_spacing> + <column_spacing>2</column_spacing> + + <widget> + <class>GtkLabel</class> + <name>label62</name> + <label>Su_mmary:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <default_focus_target>reminder-summary</default_focus_target> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkEntry</class> + <name>reminder-summary</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text_visible>True</text_visible> + <text_max_length>0</text_max_length> + <text></text> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>True</xexpand> + <yexpand>False</yexpand> + <xshrink>True</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkLabel</class> + <name>label63</name> + <label>_Starting date:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>True</yfill> + </child> + </widget> + + <widget> + <class>GtkLabel</class> + <name>starting date</name> + <label>assbarn it</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>True</yfill> + </child> + </widget> + </widget> + </widget> + + <widget> + <class>GtkFrame</class> + <name>frame34</name> + <label>Reminders</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkVBox</class> + <name>vbox53</name> + <border_width>4</border_width> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + + <widget> + <class>GtkHBox</class> + <name>hbox54</name> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkOptionMenu</class> + <name>reminder-action</name> + <can_focus>True</can_focus> + <items>Show a dialog +Play a sound +Send an email +Run a program +</items> + <initial_choice>0</initial_choice> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkSpinButton</class> + <name>reminder-interval-value</name> + <can_focus>True</can_focus> + <climb_rate>1</climb_rate> + <digits>0</digits> + <numeric>True</numeric> + <update_policy>GTK_UPDATE_ALWAYS</update_policy> + <snap>False</snap> + <wrap>False</wrap> + <value>1</value> + <lower>0</lower> + <upper>100</upper> + <step>1</step> + <page>10</page> + <page_size>10</page_size> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> + </widget> + + <widget> + <class>GtkOptionMenu</class> + <name>reminder-value-units</name> + <can_focus>True</can_focus> + <items>minute(s) +hour(s) +day(s) +</items> + <initial_choice>0</initial_choice> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkOptionMenu</class> + <name>reminder-relative</name> + <can_focus>True</can_focus> + <items>before +after +</items> + <initial_choice>0</initial_choice> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkOptionMenu</class> + <name>reminder-time</name> + <can_focus>True</can_focus> + <items>start of appointment +end of appointment +</items> + <initial_choice>0</initial_choice> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkButton</class> + <name>button9</name> + <can_focus>True</can_focus> + <label>Settings...</label> + <relief>GTK_RELIEF_NORMAL</relief> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + </widget> + + <widget> + <class>GtkHBox</class> + <name>hbox55</name> + <homogeneous>False</homogeneous> + <spacing>0</spacing> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkScrolledWindow</class> + <name>scrolledwindow13</name> + <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> + <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> + <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> + <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkCList</class> + <name>reminder-list</name> + <can_focus>True</can_focus> + <columns>1</columns> + <column_widths>80</column_widths> + <selection_mode>GTK_SELECTION_BROWSE</selection_mode> + <show_titles>False</show_titles> + <shadow_type>GTK_SHADOW_IN</shadow_type> + + <widget> + <class>GtkLabel</class> + <child_name>CList:title</child_name> + <name>label64</name> + <label>label55</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + </widget> + </widget> + </widget> + + <widget> + <class>GtkVButtonBox</class> + <name>vbuttonbox2</name> + <layout_style>GTK_BUTTONBOX_START</layout_style> + <spacing>10</spacing> + <child_min_width>85</child_min_width> + <child_min_height>27</child_min_height> + <child_ipad_x>7</child_ipad_x> + <child_ipad_y>0</child_ipad_y> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkButton</class> + <name>reminder-add</name> + <can_default>True</can_default> + <can_focus>True</can_focus> + <label>Add</label> + <relief>GTK_RELIEF_NORMAL</relief> + </widget> + + <widget> + <class>GtkButton</class> + <name>reminder-delete</name> + <can_default>True</can_default> + <can_focus>True</can_focus> + <label>Delete</label> + <relief>GTK_RELIEF_NORMAL</relief> + </widget> + </widget> + </widget> + </widget> + </widget> + </widget> +</widget> + +</GTK-Interface> diff --git a/calendar/gui/dialogs/alarm-page.h b/calendar/gui/dialogs/alarm-page.h new file mode 100644 index 0000000000..1cb0b301bd --- /dev/null +++ b/calendar/gui/dialogs/alarm-page.h @@ -0,0 +1,64 @@ +/* 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. + */ + +#ifndef ALARM_PAGE_H +#define ALARM_PAGE_H + +#include "editor-page.h" + +BEGIN_GNOME_DECLS + + + +#define TYPE_ALARM_PAGE (alarm_page_get_type ()) +#define ALARM_PAGE(obj) (GTK_CHECK_CAST ((obj), TYPE_ALARM_PAGE, AlarmPage)) +#define ALARM_PAGE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_ALARM_PAGE, \ + AlarmPageClass)) +#define IS_ALARM_PAGE(obj) (GTK_CHECK_TYPE ((obj), TYPE_ALARM_PAGE)) +#define IS_ALARM_PAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), TYPE_ALARM_PAGE)) + +typedef struct _AlarmPagePrivate AlarmPagePrivate; + +typedef struct { + EditorPage page; + + /* Private data */ + AlarmPagePrivate *priv; +} AlarmPage; + +typedef struct { + EditorPageClass parent_class; +} AlarmPageClass; + +GtkType alarm_page_get_type (void); + +AlarmPage *alarm_page_construct (AlarmPage *apage); + +AlarmPage *alarm_page_new (void); + + + +END_GNOME_DECLS + +#endif diff --git a/calendar/gui/dialogs/editor-page.c b/calendar/gui/dialogs/editor-page.c new file mode 100644 index 0000000000..b46b247191 --- /dev/null +++ b/calendar/gui/dialogs/editor-page.c @@ -0,0 +1,259 @@ +/* Evolution calendar - Base class for calendar component editor pages + * + * Copyright (C) 2001 Ximian, Inc. + * + * Authors: Federico Mena-Quintero <federico@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 "editor-page.h" + + + +static void editor_page_class_init (EditorPageClass *class); + +/* Signal IDs */ + +enum { + CHANGED, + SUMMARY_CHANGED, + LAST_SIGNAL +}; + +static guint editor_page_signals[LAST_SIGNAL]; + +#define CLASS(page) (EDITOR_PAGE_CLASS (GTK_OBJECT (page)->klass)) + + + +/** + * editor_page_get_type: + * + * Registers the #EditorPage class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #EditorPage class. + **/ +GtkType +editor_page_get_type (void) +{ + static GtkType editor_page_type = 0; + + if (!editor_page_type) { + static const GtkTypeInfo editor_page_info = { + "EditorPage", + sizeof (EditorPage), + sizeof (EditorPageClass), + (GtkClassInitFunc) editor_page_class_init, + (GtkObjectInitFunc) NULL, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + editor_page_type = gtk_type_unique (GTK_TYPE_OBJECT, &editor_page_info); + } + + return editor_page_type; +} + +/* Class initialization function for the abstract editor page */ +static void +editor_page_class_init (EditorPageClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass *) class; + + editor_page_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EditorPageClass, changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + editor_page_signals[SUMMARY_CHANGED] = + gtk_signal_new ("summary_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EditorPageClass, summary_changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, editor_page_signals, LAST_SIGNAL); + + class->changed = NULL; + class->summary_changed = NULL; + + class->get_widget = NULL; + class->fill_widgets = NULL; + class->fill_component = NULL; + class->set_summary = NULL; + class->get_summary = NULL; + class->set_dtstart = NULL; +} + + + +/** + * editor_page_get_widget: + * @page: An editor page. + * + * Queries the main widget of an editor page. + * + * Return value: The widget that is the page's upper container. It should + * normally be inserted in a notebook widget. + **/ +GtkWidget * +editor_page_get_widget (EditorPage *page) +{ + g_return_val_if_fail (page != NULL, NULL); + g_return_val_if_fail (IS_EDITOR_PAGE (page), NULL); + + g_assert (CLASS (page)->get_widget != NULL); + return (* CLASS (page)->get_widget) (page); +} + +/** + * editor_page_fill_widgets: + * @page: An editor page. + * @comp: A calendar component. + * + * Fills the widgets of an editor page with the data from a calendar component. + **/ +void +editor_page_fill_widgets (EditorPage *page, CalComponent *comp) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_EDITOR_PAGE (page)); + g_return_if_fail (comp != NULL); + + g_assert (CLASS (page)->fill_widgets != NULL); + (* CLASS (page)->fill_widgets) (page, comp); +} + +/** + * editor_page_fill_component: + * @page: An editor page. + * @comp: A calendar component. + * + * Takes the data from the widgets of an editor page and sets it on a calendar + * component, replacing the contents of the properties that the editor page + * knows how to manipulate. + **/ +void +editor_page_fill_component (EditorPage *page, CalComponent *comp) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_EDITOR_PAGE (page)); + g_return_if_fail (comp != NULL); + + g_assert (CLASS (page)->fill_component != NULL); + (* CLASS (page)->fill_component) (page, comp); +} + +/** + * editor_page_set_summary: + * @page: An editor page. + * @summary: Summary string to set in the page's widgets, which must be encoded + * in UTF8. + * + * Sets the calendar component summary string in an editor page. + **/ +void +editor_page_set_summary (EditorPage *page, const char *summary) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_EDITOR_PAGE (page)); + g_return_if_fail (summary != NULL); + + g_assert (CLASS (page)->set_summary != NULL); + (* CLASS (page)->set_summary) (page, summary); +} + +/** + * editor_page_get_summary: + * @page: An editor page. + * + * Queries the current summary string in an editor page. + * + * Return value: Summary string in UTF8; must be freed by the caller. + **/ +char * +editor_page_get_summary (EditorPage *page) +{ + g_return_val_if_fail (page != NULL, NULL); + g_return_val_if_fail (IS_EDITOR_PAGE (page), NULL); + + g_assert (CLASS (page)->get_summary != NULL); + return (* CLASS (page)->get_summary) (page); +} + +/** + * editor_page_set_dtstart: + * @page: An editor page. + * @start: Start date for calendar component. + * + * Sets the calendar component DTSTART in an editor page. + **/ +void +editor_page_set_dtstart (EditorPage *page, time_t start) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_EDITOR_PAGE (page)); + g_return_if_fail (start != -1); + + g_assert (CLASS (page)->set_dtstart != NULL); + (* CLASS (page)->set_dtstart) (page, start); +} + +/** + * editor_page_notify_changed: + * @page: An editor page. + * + * Makes an editor page emit the "changed" signal. This is meant to be + * used only by page implementations. + **/ +void +editor_page_notify_changed (EditorPage *page) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_EDITOR_PAGE (page)); + + gtk_signal_emit (GTK_OBJECT (page), editor_page_signals[CHANGED]); +} + +/** + * editor_page_notify_summary_changed: + * @page: An editor page. + * + * Makes an editor page emit the "summary_changed" signal. This is meant to be + * used only by page implementations. + **/ +void +editor_page_notify_summary_changed (EditorPage *page) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_EDITOR_PAGE (page)); + + gtk_signal_emit (GTK_OBJECT (page), editor_page_signals[SUMMARY_CHANGED]); +} diff --git a/calendar/gui/dialogs/editor-page.h b/calendar/gui/dialogs/editor-page.h new file mode 100644 index 0000000000..3f9587c9de --- /dev/null +++ b/calendar/gui/dialogs/editor-page.h @@ -0,0 +1,86 @@ +/* Evolution calendar - Base class for calendar component editor pages + * + * Copyright (C) 2001 Ximian, Inc. + * + * Authors: Federico Mena-Quintero <federico@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. + */ + +#ifndef EDITOR_PAGE_H +#define EDITOR_PAGE_H + +#include <time.h> +#include <libgnome/gnome-defs.h> +#include <gtk/gtkwidget.h> +#include <cal-util/cal-component.h> + +BEGIN_GNOME_DECLS + + + +#define TYPE_EDITOR_PAGE (editor_page_get_type ()) +#define EDITOR_PAGE(obj) (GTK_CHECK_CAST ((obj), TYPE_EDITOR_PAGE, EditorPage)) +#define EDITOR_PAGE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_EDITOR_PAGE, \ + EditorPageClass)) +#define IS_EDITOR_PAGE(obj) (GTK_CHECK_TYPE ((obj), TYPE_EDITOR_PAGE)) +#define IS_EDITOR_PAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), TYPE_EDITOR_PAGE)) + +typedef struct { + GtkObject object; +} EditorPage; + +typedef struct { + GtkObjectClass parent_class; + + /* Notification signals */ + + void (* changed) (EditorPage *page); + void (* summary_changed) (EditorPage *page); + void (* dtstart_changed) (EditorPage *page); + + /* Virtual methods */ + + GtkWidget *(* get_widget) (EditorPage *page); + + void (* fill_widgets) (EditorPage *page, CalComponent *comp); + void (* fill_component) (EditorPage *page, CalComponent *comp); + + void (* set_summary) (EditorPage *page, const char *summary); + char *(* get_summary) (EditorPage *page); + + void (* set_dtstart) (EditorPage *page, time_t start); +} EditorPageClass; + +GtkType editor_page_get_type (void); + +GtkWidget *editor_page_get_widget (EditorPage *page); + +void editor_page_fill_widgets (EditorPage *page, CalComponent *comp); +void editor_page_fill_component (EditorPage *page, CalComponent *comp); + +void editor_page_set_summary (EditorPage *page, const char *summary); +char *editor_page_get_summary (EditorPage *page); + +void editor_page_set_dtstart (EditorPage *page, time_t start); + +void editor_page_notify_changed (EditorPage *page); +void editor_page_notify_summary_changed (EditorPage *page); + + + +END_GNOME_DECLS + +#endif diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c new file mode 100644 index 0000000000..f67b898dce --- /dev/null +++ b/calendar/gui/dialogs/event-page.c @@ -0,0 +1,908 @@ +/* Evolution calendar - Main page of the event editor dialog + * + * 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 <gtk/gtktogglebutton.h> +#include <glade/glade.h> +#include <gal/widgets/e-unicode.h> +#include <gal/widgets/e-categories.h> +#include "cal-util/timeutil.h" +#include "e-util/e-dialog-widgets.h" +#include "widgets/misc/e-dateedit.h" +#include "../calendar-config.h" +#include "event-page.h" + + + +/* Private part of the EventPage structure */ +struct _EventPagePrivate { + /* Glade XML data */ + GladeXML *xml; + + /* Widgets from the Glade file */ + + GtkWidget *main; + + GtkWidget *summary; + + GtkWidget *start_time; + GtkWidget *end_time; + GtkWidget *all_day_event; + + GtkWidget *description; + + GtkWidget *classification_public; + GtkWidget *classification_private; + GtkWidget *classification_confidential; + + GtkWidget *contacts_btn; + GtkWidget *contacts; + + GtkWidget *categories_btn; + GtkWidget *categories; +}; + + + +static void event_page_class_init (EventPageClass *class); +static void event_page_init (EventPage *epage); +static void event_page_destroy (GtkObject *object); + +static GtkWidget *event_page_get_widget (EditorPage *page); +static void event_page_fill_widgets (EditorPage *page, CalComponent *comp); +static void event_page_fill_component (EditorPage *page, CalComponent *comp); +static void event_page_set_summary (EditorPage *page, const char *summary); +static char *event_page_get_summary (EditorPage *page); +static void event_page_set_dtstart (EditorPage *page, time_t start); + +/* Signal IDs */ +enum { + DATES_CHANGED, + LAST_SIGNAL +}; + +static guint event_page_signals[LAST_SIGNAL] = { 0 }; + +static EditorPageClass *parent_class = NULL; + + + +/** + * event_page_get_type: + * + * Registers the #EventPage class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #EventPage class. + **/ +GtkType +event_page_get_type (void) +{ + static GtkType event_page_type; + + if (!event_page_type) { + static const GtkTypeInfo event_page_info = { + "EventPage", + sizeof (EventPage), + sizeof (EventPageClass), + (GtkClassInitFunc) event_page_class_init, + (GtkObjectInitFunc) event_page_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + event_page_type = gtk_type_unique (TYPE_EDITOR_PAGE, &event_page_info); + } + + return event_page_type; +} + +/* Class initialization function for the event page */ +static void +event_page_class_init (EventPageClass *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); + + event_page_signals[DATES_CHANGED] = + gtk_signal_new ("dates_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (EventPageClass, dates_changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, event_page_signals, LAST_SIGNAL); + + class->dates_changed = NULL; + + editor_page_class->get_widget = event_page_get_widget; + editor_page_class->fill_widgets = event_page_fill_widgets; + editor_page_class->fill_component = event_page_fill_component; + editor_page_class->set_summary = event_page_set_summary; + editor_page_class->get_summary = event_page_get_summary; + editor_page_class->set_dtstart = event_page_set_dtstart; + + object_class->destroy = event_page_destroy; +} + +/* Object initialization function for the event page */ +static void +event_page_init (EventPage *epage) +{ + EventPagePrivate *priv; + + priv = g_new0 (EventPagePrivate, 1); + epage->priv = priv; + + priv->xml = NULL; + + priv->main = NULL; + priv->summary = NULL; + priv->start_time = NULL; + priv->end_time = NULL; + priv->all_day_event = NULL; + priv->description = NULL; + priv->classification_public = NULL; + priv->classification_private = NULL; + priv->classification_confidential = NULL; + priv->contacts_btn = NULL; + priv->contacts = NULL; + priv->categories_btn = NULL; + priv->categories = NULL; +} + +/* Destroy handler for the event page */ +static void +event_page_destroy (GtkObject *object) +{ + EventPage *epage; + EventPagePrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EVENT_PAGE (object)); + + epage = EVENT_PAGE (object); + priv = epage->priv; + + if (priv->xml) { + gtk_object_unref (GTK_OBJECT (priv->xml)); + priv->xml = NULL; + } + + g_free (priv); + epage->priv = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + + + +static const int classification_map[] = { + CAL_COMPONENT_CLASS_PUBLIC, + CAL_COMPONENT_CLASS_PRIVATE, + CAL_COMPONENT_CLASS_CONFIDENTIAL, + -1 +}; + +/* get_widget handler for the event page */ +static GtkWidget * +event_page_get_widget (EditorPage *page) +{ + EventPage *epage; + EventPagePrivate *priv; + + epage = EVENT_PAGE (page); + priv = epage->priv; + + return priv->main; +} + +/* Checks if the event's time starts and ends at midnight, and sets the "all day + * event" box accordingly. + */ +static void +check_all_day (EventPage *epage) +{ + EventPagePrivate *priv; + time_t ev_start, ev_end; + gboolean all_day = FALSE; + + priv = epage->priv; + + /* Currently we just return if the date is not set or not valid. + I'm not entirely sure this is the corrent thing to do. */ + ev_start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); + g_assert (ev_start != -1); + + ev_end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); + g_assert (ev_end != -1); + + /* all day event checkbox */ + if (time_day_begin (ev_start) == ev_start && time_day_begin (ev_end) == ev_end) + all_day = TRUE; + + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->all_day_event), epage); + e_dialog_toggle_set (priv->all_day_event, all_day); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->all_day_event), epage); + + e_date_edit_set_show_time (E_DATE_EDIT (priv->start_time), !all_day); + e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day); +} + +/* Fills the widgets with default values */ +static void +clear_widgets (EventPage *epage) +{ + EventPagePrivate *priv; + time_t now; + + priv = epage->priv; + + now = time (NULL); + + /* Summary, description */ + e_dialog_editable_set (priv->summary, NULL); + e_dialog_editable_set (priv->description, NULL); + + /* Start and end times */ + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage); + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); + + e_date_edit_set_time (E_DATE_EDIT (priv->start_time), now); + e_date_edit_set_time (E_DATE_EDIT (priv->end_time), now); + + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), epage); + + check_all_day (epage); + + /* Classification */ + e_dialog_radio_set (priv->classification_public, + CAL_COMPONENT_CLASS_PRIVATE, classification_map); + + /* Categories */ + e_dialog_editable_set (priv->categories, NULL); +} + +/* fill_widgets handler for the event page */ +static void +event_page_fill_widgets (EditorPage *page, CalComponent *comp) +{ + EventPage *epage; + EventPagePrivate *priv; + CalComponentText text; + CalComponentClassification cl; + CalComponentDateTime d; + GSList *l; + time_t dtstart, dtend; + const char *categories; + + epage = EVENT_PAGE (page); + priv = epage->priv; + + clear_widgets (epage); + + /* Summary, description(s) */ + + cal_component_get_summary (comp, &text); + e_dialog_editable_set (priv->summary, text.value); + + cal_component_get_description_list (comp, &l); + if (l) { + text = *(CalComponentText *)l->data; + e_dialog_editable_set (priv->description, text.value); + } + cal_component_free_text_list (l); + + /* Start and end times */ + + /* All-day events are inclusive, i.e. if the end date shown is 2nd Feb + then the event includes all of the 2nd Feb. We would normally show + 3rd Feb as the end date, since it really ends at midnight on 3rd, + so we have to subtract a day so we only show the 2nd. */ + cal_component_get_dtstart (comp, &d); + dtstart = icaltime_as_timet (*d.value); + cal_component_free_datetime (&d); + + cal_component_get_dtend (comp, &d); + dtend = icaltime_as_timet (*d.value); + cal_component_free_datetime (&d); + + if (time_day_begin (dtstart) == dtstart && time_day_begin (dtend) == dtend) + dtend = time_add_day (dtend, -1); + + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage); + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); + + e_date_edit_set_time (E_DATE_EDIT (priv->start_time), dtstart); + e_date_edit_set_time (E_DATE_EDIT (priv->end_time), dtend); + + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), epage); + + check_all_day (epage); + + /* Classification */ + + cal_component_get_classification (comp, &cl); + + switch (cl) { + case CAL_COMPONENT_CLASS_PUBLIC: + e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PUBLIC, + classification_map); + break; + + case CAL_COMPONENT_CLASS_PRIVATE: + e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PRIVATE, + classification_map); + break; + + case CAL_COMPONENT_CLASS_CONFIDENTIAL: + e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_CONFIDENTIAL, + classification_map); + break; + + default: + /* What do do? We can't g_assert_not_reached() since it is a + * value from an external file. + */ + } + + /* Categories */ + + cal_component_get_categories (comp, &categories); + e_dialog_editable_set (priv->categories, categories); +} + +/* fill_component handler for the event page */ +static void +event_page_fill_component (EditorPage *page, CalComponent *comp) +{ + EventPage *epage; + EventPagePrivate *priv; + CalComponentDateTime date; + struct icaltimetype icaltime; + time_t t; + gboolean all_day_event; + char *cat, *str; + CalComponentClassification classif; + + epage = EVENT_PAGE (page); + priv = epage->priv; + + /* Summary */ + + str = e_dialog_editable_get (priv->summary); + if (!str || strlen (str) == 0) + cal_component_set_summary (comp, NULL); + else { + CalComponentText text; + + text.value = str; + text.altrep = NULL; + + cal_component_set_summary (comp, &text); + } + + if (str) + g_free (str); + + /* Description */ + + str = e_dialog_editable_get (priv->description); + if (!str || strlen (str) == 0) + cal_component_set_description_list (comp, NULL); + else { + GSList l; + CalComponentText text; + + text.value = str; + text.altrep = NULL; + l.data = &text; + l.next = NULL; + + cal_component_set_description_list (comp, &l); + } + + if (str) + g_free (str); + + /* Dates */ + + date.value = &icaltime; + date.tzid = NULL; + + t = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); + if (t != -1) { + *date.value = icaltime_from_timet (t, FALSE); + cal_component_set_dtstart (comp, &date); + } else { + /* FIXME: What do we do here? */ + } + + /* If the all_day toggle is set, the end date is inclusive of the + entire day on which it points to. */ + all_day_event = e_dialog_toggle_get (priv->all_day_event); + t = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); + if (t != -1) { + if (all_day_event) + t = time_day_end (t); + + *date.value = icaltime_from_timet (t, FALSE); + cal_component_set_dtend (comp, &date); + } else { + /* FIXME: What do we do here? */ + } + + /* Categories */ + + cat = e_dialog_editable_get (priv->categories); + cal_component_set_categories (comp, cat); + + if (cat) + g_free (cat); + + /* Classification */ + + classif = e_dialog_radio_get (priv->classification_public, classification_map); + cal_component_set_classification (comp, classif); +} + +/* set_summary handler for the event page */ +static void +event_page_set_summary (EditorPage *page, const char *summary) +{ + EventPage *epage; + EventPagePrivate *priv; + + epage = EVENT_PAGE (page); + priv = epage->priv; + + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->summary), epage); + e_utf8_gtk_entry_set_text (GTK_ENTRY (priv->summary), summary); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->summary), epage); +} + +/* get_summary handler for the event page */ +static char * +event_page_get_summary (EditorPage *page) +{ + EventPage *epage; + EventPagePrivate *priv; + + epage = EVENT_PAGE (page); + priv = epage->priv; + + return e_utf8_gtk_entry_get_text (GTK_ENTRY (priv->summary)); +} + +/* set_dtstart handler for the event page. We do nothing since we are *the* + * only provider of the dtstart value. + */ +static void +event_page_set_dtstart (EditorPage *page, time_t start) +{ + /* nothing */ +} + + + +/* Gets the widgets from the XML file and returns if they are all available. */ +static gboolean +get_widgets (EventPage *epage) +{ + EventPagePrivate *priv; + GtkWidget *toplevel; + + priv = epage->priv; + +#define GW(name) glade_xml_get_widget (priv->xml, name) + + toplevel = GW ("event-toplevel"); + priv->main = GW ("event-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->start_time = GW ("start-time"); + priv->end_time = GW ("end-time"); + priv->all_day_event = GW ("all-day-event"); + + priv->description = GW ("description"); + + priv->classification_public = GW ("classification-public"); + priv->classification_private = GW ("classification-private"); + priv->classification_confidential = GW ("classification-confidential"); + + priv->contacts_btn = GW ("contacts-button"); + priv->contacts = GW ("contacts"); + + priv->categories_btn = GW ("categories-button"); + priv->categories = GW ("categories"); + +#undef GW + + return (priv->summary + && priv->start_time + && priv->end_time + && priv->all_day_event + && priv->description + && priv->classification_public + && priv->classification_private + && priv->classification_confidential + && priv->contacts_btn + && priv->contacts + && priv->categories_btn + && priv->categories); +} + +/* Callback used when the summary changes; we emit the notification signal. */ +static void +summary_changed_cb (GtkEditable *editable, gpointer data) +{ + EventPage *epage; + + epage = EVENT_PAGE (data); + editor_page_notify_summary_changed (EDITOR_PAGE (epage)); +} + +/* Callback used when the start or end date widgets change. We check that the + * start date < end date and we set the "all day event" button as appropriate. + */ +static void +date_changed_cb (EDateEdit *dedit, gpointer data) +{ + EventPage *epage; + EventPagePrivate *priv; + time_t start, end; + struct tm tm_start, tm_end; + + epage = EVENT_PAGE (data); + priv = epage->priv; + + /* Ensure that start < end */ + + start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); + g_assert (start != -1); + end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); + g_assert (end != -1); + + if (start >= end) { + tm_start = *localtime (&start); + tm_end = *localtime (&end); + + if (start == end && tm_start.tm_hour == 0 + && tm_start.tm_min == 0 && tm_start.tm_sec == 0) { + /* If the start and end times are the same, but both are + * on day boundaries, then that is OK since it means we + * have an all-day event lasting 1 day. So we do + * nothing here. + */ + } else if (GTK_WIDGET (dedit) == priv->start_time) { + /* Modify the end time */ + + tm_end.tm_year = tm_start.tm_year; + tm_end.tm_mon = tm_start.tm_mon; + tm_end.tm_mday = tm_start.tm_mday; + tm_end.tm_hour = tm_start.tm_hour + 1; + tm_end.tm_min = tm_start.tm_min; + tm_end.tm_sec = tm_start.tm_sec; + + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); + e_date_edit_set_time (E_DATE_EDIT (priv->end_time), mktime (&tm_end)); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), epage); + } else if (GTK_WIDGET (dedit) == priv->end_time) { + /* Modify the start time */ + + tm_start.tm_year = tm_end.tm_year; + tm_start.tm_mon = tm_end.tm_mon; + tm_start.tm_mday = tm_end.tm_mday; + tm_start.tm_hour = tm_end.tm_hour - 1; + tm_start.tm_min = tm_end.tm_min; + tm_start.tm_sec = tm_end.tm_sec; + + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage); + e_date_edit_set_time (E_DATE_EDIT (priv->start_time), mktime (&tm_start)); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); + } else + g_assert_not_reached (); + } + + /* Set the "all day event" button as appropriate */ + check_all_day (epage); + + /* Notify upstream */ + gtk_signal_emit (GTK_OBJECT (epage), event_page_signals[DATES_CHANGED]); +} + +/* Callback: all day event button toggled. + * Note that this should only be called when the user explicitly toggles the + * button. Be sure to block this handler when the toggle button's state is set + * within the code. + */ +static void +all_day_event_toggled_cb (GtkWidget *toggle, gpointer data) +{ + EventPage *epage; + EventPagePrivate *priv; + struct tm start_tm, end_tm; + time_t start_t, end_t; + gboolean all_day; + + epage = EVENT_PAGE (data); + priv = epage->priv; + + /* When the all_day toggle is turned on, the start date is rounded down + * to the start of the day, and end date is rounded down to the start of + * the day on which the event ends. The event is then taken to be + * inclusive of the days between the start and end days. Note that if + * the event end is at midnight, we do not round it down to the previous + * day, since if we do that and the user repeatedly turns the all_day + * toggle on and off, the event keeps shrinking. (We'd also need to + * make sure we didn't adjust the time when the radio button is + * initially set.) + * + * When the all_day_toggle is turned off, we set the event start to the + * start of the working day, and if the event end is on or before the + * day of the event start we set it to one hour after the event start. + */ + all_day = GTK_TOGGLE_BUTTON (toggle)->active; + + /* + * Start time. + */ + start_t = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); + g_assert (start_t != -1); + + start_tm = *localtime (&start_t); + + if (all_day) { + /* Round down to the start of the day. */ + start_tm.tm_hour = 0; + start_tm.tm_min = 0; + start_tm.tm_sec = 0; + } else { + /* Set to the start of the working day. */ + start_tm.tm_hour = calendar_config_get_day_start_hour (); + start_tm.tm_min = calendar_config_get_day_start_minute (); + start_tm.tm_sec = 0; + } + + /* + * End time. + */ + end_t = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); + g_assert (end_t != -1); + + end_tm = *localtime (&end_t); + + if (all_day) { + /* Round down to the start of the day. */ + end_tm.tm_hour = 0; + end_tm.tm_min = 0; + end_tm.tm_sec = 0; + } else { + /* If the event end is now on or before the event start day, + * make it end one hour after the start. mktime() will fix any + * overflows. + */ + if (end_tm.tm_year < start_tm.tm_year + || (end_tm.tm_year == start_tm.tm_year + && end_tm.tm_mon < start_tm.tm_mon) + || (end_tm.tm_year == start_tm.tm_year + && end_tm.tm_mon == start_tm.tm_mon + && end_tm.tm_mday <= start_tm.tm_mday)) { + end_tm.tm_year = start_tm.tm_year; + end_tm.tm_mon = start_tm.tm_mon; + end_tm.tm_mday = start_tm.tm_mday; + end_tm.tm_hour = start_tm.tm_hour + 1; + } + } + + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage); + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); + + e_date_edit_set_time (E_DATE_EDIT (priv->start_time), mktime (&start_tm)); + e_date_edit_set_time (E_DATE_EDIT (priv->end_time), mktime (&end_tm)); + + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), epage); + + e_date_edit_set_show_time (E_DATE_EDIT (priv->start_time), !all_day); + e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day); + + /* Notify upstream */ + gtk_signal_emit (GTK_OBJECT (epage), event_page_signals[DATES_CHANGED]); +} + +/* Callback used when the categories button is clicked; we must bring up the + * category list dialog. + */ +static void +categories_clicked_cb (GtkWidget *button, gpointer data) +{ + EventPage *epage; + EventPagePrivate *priv; + char *categories; + GnomeDialog *dialog; + int result; + GtkWidget *entry; + + epage = EVENT_PAGE (data); + priv = epage->priv; + + entry = priv->categories; + categories = e_utf8_gtk_entry_get_text (GTK_ENTRY (entry)); + + dialog = GNOME_DIALOG (e_categories_new (categories)); + result = gnome_dialog_run (dialog); + g_free (categories); + + if (result == 0) { + gtk_object_get (GTK_OBJECT (dialog), + "categories", &categories, + NULL); + e_utf8_gtk_entry_set_text (GTK_ENTRY (entry), categories); + g_free (categories); + } + + gtk_object_destroy (GTK_OBJECT (dialog)); +} + +/* This is called when any field is changed; it notifies upstream. */ +static void +field_changed_cb (GtkWidget *widget, gpointer data) +{ + EventPage *epage; + + epage = EVENT_PAGE (data); + editor_page_notify_changed (EDITOR_PAGE (epage)); +} + +/* Hooks the widget signals */ +static void +init_widgets (EventPage *epage) +{ + EventPagePrivate *priv; + + priv = epage->priv; + + /* Summary */ + gtk_signal_connect (GTK_OBJECT (priv->summary), "changed", + GTK_SIGNAL_FUNC (summary_changed_cb), epage); + + /* Start and end times */ + gtk_signal_connect (GTK_OBJECT (priv->start_time), "changed", + GTK_SIGNAL_FUNC (date_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->end_time), "changed", + GTK_SIGNAL_FUNC (date_changed_cb), epage); + + gtk_signal_connect (GTK_OBJECT (priv->all_day_event), "toggled", + GTK_SIGNAL_FUNC (all_day_event_toggled_cb), epage); + + /* Categories button */ + gtk_signal_connect (GTK_OBJECT (priv->categories_btn), "clicked", + GTK_SIGNAL_FUNC (categories_clicked_cb), epage); + + /* 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->summary), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->start_time), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->end_time), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->all_day_event), "toggled", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->description), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->classification_public), "toggled", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->classification_private), "toggled", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->classification_confidential), "toggled", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + gtk_signal_connect (GTK_OBJECT (priv->categories), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), epage); + + /* FIXME: we do not support these fields yet, so we disable them */ + + gtk_widget_set_sensitive (priv->contacts_btn, FALSE); + gtk_widget_set_sensitive (priv->contacts, FALSE); +} + + + +/** + * event_page_construct: + * @epage: An event page. + * + * Constructs an event page by loading its Glade data. + * + * Return value: The same object as @epage, or NULL if the widgets could not be + * created. + **/ +EventPage * +event_page_construct (EventPage *epage) +{ + EventPagePrivate *priv; + + priv = epage->priv; + + priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/event-page.glade", NULL); + if (!priv->xml) { + g_message ("event_page_construct(): Could not load the Glade XML file!"); + return NULL; + } + + if (!get_widgets (epage)) { + g_message ("event_page_construct(): Could not find all widgets in the XML file!"); + return NULL; + } + + init_widgets (epage); + + return epage; +} + +/** + * event_page_new: + * + * Creates a new event page. + * + * Return value: A newly-created event page, or NULL if the page could + * not be created. + **/ +EventPage * +event_page_new (void) +{ + EventPage *epage; + + epage = gtk_type_new (TYPE_EVENT_PAGE); + if (!event_page_construct (epage)) { + gtk_object_unref (GTK_OBJECT (epage)); + return NULL; + } + + return epage; +} diff --git a/calendar/gui/dialogs/event-page.glade b/calendar/gui/dialogs/event-page.glade new file mode 100644 index 0000000000..76d2d4043e --- /dev/null +++ b/calendar/gui/dialogs/event-page.glade @@ -0,0 +1,429 @@ +<?xml version="1.0"?> +<GTK-Interface> + +<project> + <name>event-page</name> + <program_name>event-page</program_name> + <directory></directory> + <source_directory>.</source_directory> + <pixmaps_directory>pixmaps</pixmaps_directory> + <language>C</language> + <gnome_support>True</gnome_support> + <gettext_support>True</gettext_support> + <output_main_file>False</output_main_file> + <output_support_files>False</output_support_files> + <output_build_files>False</output_build_files> +</project> + +<widget> + <class>GtkWindow</class> + <name>event-toplevel</name> + <title>window1</title> + <type>GTK_WINDOW_TOPLEVEL</type> + <position>GTK_WIN_POS_NONE</position> + <modal>False</modal> + <allow_shrink>False</allow_shrink> + <allow_grow>True</allow_grow> + <auto_shrink>False</auto_shrink> + + <widget> + <class>GtkVBox</class> + <name>event-page</name> + <border_width>4</border_width> + <homogeneous>False</homogeneous> + <spacing>6</spacing> + + <widget> + <class>GtkTable</class> + <name>table11</name> + <rows>1</rows> + <columns>2</columns> + <homogeneous>False</homogeneous> + <row_spacing>4</row_spacing> + <column_spacing>4</column_spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkLabel</class> + <name>label56</name> + <label>Su_mmary:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>7.45058e-09</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <default_focus_target>general-summary</default_focus_target> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkEntry</class> + <name>general-summary</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text_visible>True</text_visible> + <text_max_length>0</text_max_length> + <text></text> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>True</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + </widget> + + <widget> + <class>GtkFrame</class> + <name>frame31</name> + <label>Date & Time</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkTable</class> + <name>table12</name> + <border_width>4</border_width> + <rows>2</rows> + <columns>3</columns> + <homogeneous>False</homogeneous> + <row_spacing>4</row_spacing> + <column_spacing>4</column_spacing> + + <widget> + <class>GtkLabel</class> + <name>label57</name> + <label>_Start time:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkLabel</class> + <name>label58</name> + <label>_End time:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkCheckButton</class> + <name>all-day-event</name> + <can_focus>True</can_focus> + <label>A_ll day event</label> + <active>False</active> + <draw_indicator>True</draw_indicator> + <child> + <left_attach>2</left_attach> + <right_attach>3</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>Custom</class> + <name>start-time</name> + <creation_function>make_date_edit</creation_function> + <string1></string1> + <string2></string2> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Tue, 16 May 2000 19:11:05 GMT</last_modification_time> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>True</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>False</xfill> + <yfill>True</yfill> + </child> + </widget> + + <widget> + <class>Custom</class> + <name>end-time</name> + <creation_function>make_date_edit</creation_function> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Tue, 16 May 2000 19:11:10 GMT</last_modification_time> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>True</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>False</xfill> + <yfill>True</yfill> + </child> + </widget> + </widget> + </widget> + + <widget> + <class>GtkScrolledWindow</class> + <name>scrolledwindow12</name> + <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> + <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> + <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> + <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkText</class> + <name>description</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text></text> + </widget> + </widget> + + <widget> + <class>GtkFrame</class> + <name>frame32</name> + <label>Classification</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkHBox</class> + <name>hbox52</name> + <border_width>2</border_width> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + + <widget> + <class>GtkRadioButton</class> + <name>classification-public</name> + <can_focus>True</can_focus> + <label>Pu_blic</label> + <active>True</active> + <draw_indicator>True</draw_indicator> + <group>classification_radio_group</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkRadioButton</class> + <name>classification-private</name> + <can_focus>True</can_focus> + <label>Pri_vate</label> + <active>False</active> + <draw_indicator>True</draw_indicator> + <group>classification_radio_group</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkRadioButton</class> + <name>classification-confidential</name> + <can_focus>True</can_focus> + <label>_Confidential</label> + <active>False</active> + <draw_indicator>True</draw_indicator> + <group>classification_radio_group</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + </widget> + </widget> + + <widget> + <class>GtkHBox</class> + <name>hbox53</name> + <homogeneous>False</homogeneous> + <spacing>2</spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkButton</class> + <name>contacts-button</name> + <can_focus>True</can_focus> + <relief>GTK_RELIEF_NORMAL</relief> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkLabel</class> + <name>label59</name> + <label>_Contacts...</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>4</xpad> + <ypad>0</ypad> + </widget> + </widget> + + <widget> + <class>GtkEntry</class> + <name>contacts</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text_visible>True</text_visible> + <text_max_length>0</text_max_length> + <text></text> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + </widget> + + <widget> + <class>GtkButton</class> + <name>categories-button</name> + <can_focus>True</can_focus> + <relief>GTK_RELIEF_NORMAL</relief> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkLabel</class> + <name>label60</name> + <label>Ca_tegories...</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>4</xpad> + <ypad>0</ypad> + </widget> + </widget> + + <widget> + <class>GtkEntry</class> + <name>categories</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text_visible>True</text_visible> + <text_max_length>0</text_max_length> + <text></text> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + </widget> + </widget> + </widget> +</widget> + +</GTK-Interface> diff --git a/calendar/gui/dialogs/event-page.h b/calendar/gui/dialogs/event-page.h new file mode 100644 index 0000000000..85281b9800 --- /dev/null +++ b/calendar/gui/dialogs/event-page.h @@ -0,0 +1,70 @@ +/* Evolution calendar - Main page of the event editor dialog + * + * 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. + */ + +#ifndef EVENT_PAGE_H +#define EVENT_PAGE_H + +#include "editor-page.h" + +BEGIN_GNOME_DECLS + + + +#define TYPE_EVENT_PAGE (event_page_get_type ()) +#define EVENT_PAGE(obj) (GTK_CHECK_CAST ((obj), TYPE_EVENT_PAGE, EventPage)) +#define EVENT_PAGE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_EVENT_PAGE, \ + EventPageClass)) +#define IS_EVENT_PAGE(obj) (GTK_CHECK_TYPE ((obj), TYPE_EVENT_PAGE)) +#define IS_EVENT_PAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), TYPE_EVENT_PAGE)) + +typedef struct _EventPagePrivate EventPagePrivate; + +typedef struct { + EditorPage page; + + /* Private data */ + EventPagePrivate *priv; +} EventPage; + +typedef struct { + EditorPageClass parent_class; + + /* Notification signals */ + + void (* dates_changed) (EventPage *epage); +} EventPageClass; + +GtkType event_page_get_type (void); + +EventPage *event_page_construct (EventPage *epage); + +EventPage *event_page_new (void); + +time_t event_page_get_dtstart (EventPage *epage); + + + +END_GNOME_DECLS + +#endif diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c new file mode 100644 index 0000000000..0b0eace9cf --- /dev/null +++ b/calendar/gui/dialogs/recurrence-page.c @@ -0,0 +1,900 @@ +/* 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 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 "e-util/e-dialog-widgets.h" +#include "recurrence-page.h" + + + +/* Private part of the RecurrencePage structure */ +struct _RecurrencePagePrivate { + /* Glade XML data */ + GladeXML *xml; + + /* Widgets from the Glade file */ + + GtkWidget *main; + + GtkWidget *summary; + GtkWidget *starting_date; + + 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; + time_t ending_date; + + /* 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; +}; + + + +static void recurrence_page_class_init (RecurrencePageClass *class); +static void recurrence_page_init (RecurrencePage *rpage); +static void recurrence_page_destroy (RecurrencePage *rpage); + +static GtkWidget *recurrence_page_get_widget (EditorPage *page); +static void recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp); +static void recurrence_page_fill_component (EditorPage *page, CalComponent *comp); +static void recurrence_page_set_summary (EditorPage *page, const char *summary); +static char *recurrence_page_get_summary (EditorPage *page); +static void recurrence_page_set_dtstart (EditorPage *page, time_t start); + +static EditorPageClass *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 (EDITOR_PAGE_TYPE, &recurrence_page_info); + } + + return recurrence_page_type; +} + +/* Class initialization function for the recurrence page */ +static void +recurrence_page_class_init (RecurrencePageClass *class) +{ + EditorPageClass *editor_page_class; + GtkObjectClass *object_class; + + editor_page_class = (EditorPageClass *) class; + object_class = (GtkObjectClass *) class; + + parent_class = gtk_type_class (EDITOR_PAGE_TYPE); + + editor_page_class->get_widget = recurrence_page_get_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->get_summary = recurrence_page_get_summary; + editor_page_class->set_dtstart = recurrence_page_set_dtstart; + + 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->starting_date = 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; +} + +/* Frees the rows and the row data in the exceptions GtkCList */ +static void +free_exception_clist_data (RecurrencePage *rpage) +{ + RecurrencePagePrivate *priv; + GtkCList *clist; + int i; + + priv = rpage->priv; + + clist = GTK_CLIST (priv->exception_list); + + for (i = 0; i < clist->rows; i++) { + gpointer data; + + data = gtk_clist_get_row_data (clist, i); + g_free (data); + gtk_clist_set_row_data (clist, i, NULL); + } + + gtk_clist_clear (clist); +} + +/* Destroy handler for the 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; + } + + free_exception_clist_data (rpage); + + 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 (EditorPage *page) +{ + RecurrencePage *rpage; + RecurrencePagePrivate *priv; + + rpage = RECURRENCE_PAGE (page); + priv = rpage->priv; + + return priv->main; +} + +/* Fills the widgets with default values */ +static void +clear_widgets (RecurrencePage *rpage) +{ + RecurrencePagePrivate *priv; + + 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 = time (NULL); + 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 */ + free_exception_clist_data (GTK_CLIST (priv->exception_list)); +} + +/* Builds a static string out of an exception date */ +static char * +get_exception_string (time_t t) +{ + static char buf[256]; + + strftime (buf, sizeof (buf), _("%a %b %d %Y"), localtime (&t)); + return buf; +} + +/* Appends an exception date to the list */ +static void +append_exception (RecurrencePage *rpage, time_t t) +{ + RecurrencePagePrivate *priv; + time_t *tt; + char *c[1]; + int i; + GtkCList *clist; + + priv = rpage->priv; + + tt = g_new (time_t, 1); + *tt = t; + + clist = GTK_CLIST (priv->exception_list); + + gtk_signal_handler_block_by_data (GTK_OBJECT (clist), rpage); + + c[0] = get_exception_string (t); + i = gtk_clist_append (clist, c); + + gtk_clist_set_row_data (clist, i, tt); + + gtk_clist_select_row (clist, i, 0); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), rpage); + + e_date_edit_set_time (E_DATE_EDIT (priv->exception_date), t); + + 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; + time_t ext; + + added = TRUE; + + cdt = l->data; + ext = icaltime_as_timet (*cdt->value); + append_exception (rpage, ext); + } + + 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) { + time_t t; + struct tm tm; + + t = icaltime_as_timet (*dt.value); + tm = *localtime (&t); + + retval = 0x1 << tm.tm_wday; + } else + retval = 0; + + cal_component_free_datetime (&dt); + + return retval; +} + +/* Sets some sane defaults for the data sources for the recurrence special + * widgets, even if they will not be used immediately. + */ +static void +set_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 (); + } +} + +/* 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; + g_assert (priv->comp != NULL); + + /* Create a scratch component with the start/end and + * recurrence/excepttion information from the one we are editing. + */ + + comp = cal_component_new (); + cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT); + + cal_component_get_dtstart (priv->comp, &cdt); + cal_component_set_dtstart (comp, &cdt); + cal_component_free_datetime (&cdt); + + cal_component_get_dtend (priv->comp, &cdt); + cal_component_set_dtend (comp, &cdt); + cal_component_free_datetime (&cdt); + + cal_component_get_exdate_list (priv->comp, &l); + cal_component_set_exdate_list (comp, l); + cal_component_free_exdate_list (l); + + cal_component_get_exrule_list (priv->comp, &l); + cal_component_set_exrule_list (comp, l); + cal_component_free_recur_list (l); + + cal_component_get_rdate_list (priv->comp, &l); + cal_component_set_rdate_list (comp, l); + cal_component_free_period_list (l); + + cal_component_get_rrule_list (priv->comp, &l); + cal_component_set_rrule_list (comp, l); + cal_component_free_recur_list (l); + + recur_to_comp_object (rpage, comp); + + tag_calendar_by_comp (E_CALENDAR (priv->preview_calendar), comp); + gtk_object_unref (GTK_OBJECT (comp)); +} + +/* 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 (EditorPage *page, CalComponent *comp) +{ + RecurrencePage *rpage; + RecurrencePagePrivate *priv; + GSList *rrule_list; + int len; + struct icalrecurrencetype *r; + int n_by_second, n_by_minute, n_by_hour; + int n_by_day, n_by_month_day, n_by_year_day; + int n_by_week_no, n_by_month, n_by_set_pos; + GtkWidget *menu; + GtkAdjustment *adj; + + rpage = RECURRENCE_PAGE (page); + priv = rpage->priv; + + clear_widgets (rpage); + + 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); + 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 != 0) + goto custom; + + if (n_by_month_day == 1) { + int nth; + + 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; + + weekday = icalrecurrencetype_day_day_of_week (r->by_day[0]); + pos = icalrecurrencetype_day_position (r->by_day[0]); + + if (pos < 1) + goto custom; + + switch (weekday) { + case ICAL_MONDAY_WEEKDAY: + month_day = MONTH_DAY_MON; + break; + + case ICAL_TUESDAY_WEEKDAY: + month_day = MONTH_DAY_TUE; + break; + + case ICAL_WEDNESDAY_WEEKDAY: + month_day = MONTH_DAY_WED; + break; + + case ICAL_THURSDAY_WEEKDAY: + month_day = MONTH_DAY_THU; + break; + + case ICAL_FRIDAY_WEEKDAY: + month_day = MONTH_DAY_FRI; + break; + + case ICAL_SATURDAY_WEEKDAY: + month_day = MONTH_DAY_SAT; + break; + + case ICAL_SUNDAY_WEEKDAY: + month_day = MONTH_DAY_SUN; + break; + + default: + goto custom; + } + + priv->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); +} + + + +/* Gets the widgets from the XML file and returns if they are all available. */ +static gboolean +get_widgets (RecurrencePage *rpage) +{ + RecurrencePagePrivate *priv; + GtkWidget *toplevel; + + priv = rpage->priv; + +#define GW(name) glade_xml_get_widget (priv->xml, name) + + toplevel = GW ("recurrence-toplevel"); + priv->main = GW ("recurrence-page"); + if (!(toplevel && priv->main)) + return NULL; + + 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->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->starting_date + && 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); +} diff --git a/calendar/gui/dialogs/recurrence-page.glade b/calendar/gui/dialogs/recurrence-page.glade new file mode 100644 index 0000000000..b84a3c288c --- /dev/null +++ b/calendar/gui/dialogs/recurrence-page.glade @@ -0,0 +1,607 @@ +<?xml version="1.0"?> +<GTK-Interface> + +<project> + <name>recurrence-page</name> + <program_name>recurrence-page</program_name> + <directory></directory> + <source_directory>.</source_directory> + <pixmaps_directory>pixmaps</pixmaps_directory> + <language>C</language> + <gnome_support>True</gnome_support> + <gettext_support>True</gettext_support> + <output_main_file>False</output_main_file> + <output_support_files>False</output_support_files> + <output_build_files>False</output_build_files> +</project> + +<widget> + <class>GtkWindow</class> + <name>recurrence-toplevel</name> + <title>window1</title> + <type>GTK_WINDOW_TOPLEVEL</type> + <position>GTK_WIN_POS_NONE</position> + <modal>False</modal> + <allow_shrink>False</allow_shrink> + <allow_grow>True</allow_grow> + <auto_shrink>False</auto_shrink> + + <widget> + <class>GtkVBox</class> + <name>recurrence-page</name> + <border_width>4</border_width> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + + <widget> + <class>GtkFrame</class> + <name>frame35</name> + <label>Appointment Basics</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkTable</class> + <name>table14</name> + <border_width>4</border_width> + <rows>2</rows> + <columns>2</columns> + <homogeneous>False</homogeneous> + <row_spacing>2</row_spacing> + <column_spacing>2</column_spacing> + + <widget> + <class>GtkLabel</class> + <name>label66</name> + <label>Su_mmary:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <default_focus_target>recurrence-summary</default_focus_target> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkLabel</class> + <name>label67</name> + <label>_Starting date:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkEntry</class> + <name>recurrence-summary</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text_visible>True</text_visible> + <text_max_length>0</text_max_length> + <text></text> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>True</xexpand> + <yexpand>False</yexpand> + <xshrink>True</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkAlignment</class> + <name>alignment40</name> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xscale>0</xscale> + <yscale>0</yscale> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>True</yfill> + </child> + + <widget> + <class>Custom</class> + <name>recurrence-starting-date</name> + <creation_function>make_date_edit</creation_function> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Fri, 22 Sep 2000 20:51:38 GMT</last_modification_time> + </widget> + </widget> + </widget> + </widget> + + <widget> + <class>GtkVBox</class> + <name>vbox55</name> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkFrame</class> + <name>frame36</name> + <label>Recurrence Rule</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkVBox</class> + <name>vbox56</name> + <border_width>4</border_width> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + + <widget> + <class>GtkHBox</class> + <name>hbox56</name> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkRadioButton</class> + <name>recurrence-none</name> + <can_focus>True</can_focus> + <label>No recurrence</label> + <active>False</active> + <draw_indicator>True</draw_indicator> + <group>recurrence-radio</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkRadioButton</class> + <name>recurrence-simple</name> + <can_focus>True</can_focus> + <label>Simple recurrence</label> + <active>False</active> + <draw_indicator>True</draw_indicator> + <group>recurrence-radio</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkRadioButton</class> + <name>recurrence-custom</name> + <can_focus>True</can_focus> + <label>Custom recurrence</label> + <active>False</active> + <draw_indicator>True</draw_indicator> + <group>recurrence-radio</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + </widget> + + <widget> + <class>GtkHBox</class> + <name>hbox57</name> + <homogeneous>False</homogeneous> + <spacing>0</spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkHBox</class> + <name>recurrence-params</name> + <homogeneous>False</homogeneous> + <spacing>2</spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkLabel</class> + <name>label68</name> + <label>Every</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkSpinButton</class> + <name>recurrence-interval-value</name> + <can_focus>True</can_focus> + <climb_rate>1</climb_rate> + <digits>0</digits> + <numeric>True</numeric> + <update_policy>GTK_UPDATE_ALWAYS</update_policy> + <snap>False</snap> + <wrap>False</wrap> + <value>1</value> + <lower>1</lower> + <upper>10000</upper> + <step>1</step> + <page>10</page> + <page_size>10</page_size> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkOptionMenu</class> + <name>recurrence-interval-unit</name> + <can_focus>True</can_focus> + <items>day(s) +week(s) +month(s) +year(s) +</items> + <initial_choice>0</initial_choice> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkAlignment</class> + <name>recurrence-special</name> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xscale>0</xscale> + <yscale>0</yscale> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>Placeholder</class> + </widget> + </widget> + + <widget> + <class>GtkOptionMenu</class> + <name>recurrence-ending-menu</name> + <can_focus>True</can_focus> + <items>for +until +forever +</items> + <initial_choice>0</initial_choice> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkAlignment</class> + <name>recurrence-ending-special</name> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xscale>0</xscale> + <yscale>0</yscale> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>Placeholder</class> + </widget> + </widget> + </widget> + + <widget> + <class>GtkAlignment</class> + <name>recurrence-custom-warning-bin</name> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xscale>1</xscale> + <yscale>1</yscale> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>Placeholder</class> + </widget> + </widget> + </widget> + </widget> + </widget> + + <widget> + <class>GtkHBox</class> + <name>hbox59</name> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkFrame</class> + <name>frame37</name> + <label>Exceptions</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkHBox</class> + <name>hbox60</name> + <border_width>4</border_width> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + + <widget> + <class>GtkVBox</class> + <name>vbox57</name> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkButton</class> + <name>recurrence-exception-add</name> + <can_focus>True</can_focus> + <label>Add</label> + <relief>GTK_RELIEF_NORMAL</relief> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkButton</class> + <name>recurrence-exception-modify</name> + <can_focus>True</can_focus> + <label>Modify</label> + <relief>GTK_RELIEF_NORMAL</relief> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkButton</class> + <name>recurrence-exception-delete</name> + <can_focus>True</can_focus> + <label>Delete</label> + <relief>GTK_RELIEF_NORMAL</relief> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + </widget> + + <widget> + <class>GtkVBox</class> + <name>vbox58</name> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>Custom</class> + <name>recurrence-exception-date</name> + <creation_function>make_date_edit</creation_function> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Tue, 16 May 2000 01:42:29 GMT</last_modification_time> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkScrolledWindow</class> + <name>scrolledwindow14</name> + <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> + <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> + <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> + <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkCList</class> + <name>recurrence-exception-list</name> + <can_focus>True</can_focus> + <columns>1</columns> + <column_widths>80</column_widths> + <selection_mode>GTK_SELECTION_BROWSE</selection_mode> + <show_titles>False</show_titles> + <shadow_type>GTK_SHADOW_IN</shadow_type> + + <widget> + <class>GtkLabel</class> + <child_name>CList:title</child_name> + <name>label69</name> + <label>label21</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + </widget> + </widget> + </widget> + </widget> + </widget> + </widget> + + <widget> + <class>GtkVBox</class> + <name>vbox59</name> + <homogeneous>False</homogeneous> + <spacing>0</spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + + <widget> + <class>GtkLabel</class> + <name>label70</name> + <label>Preview</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkAlignment</class> + <name>recurrence-preview-bin</name> + <xalign>0</xalign> + <yalign>0</yalign> + <xscale>1</xscale> + <yscale>1</yscale> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + + <widget> + <class>Placeholder</class> + </widget> + </widget> + </widget> + </widget> + </widget> + </widget> +</widget> + +</GTK-Interface> diff --git a/calendar/gui/dialogs/recurrence-page.h b/calendar/gui/dialogs/recurrence-page.h new file mode 100644 index 0000000000..39123644b4 --- /dev/null +++ b/calendar/gui/dialogs/recurrence-page.h @@ -0,0 +1,64 @@ +/* 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 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. + */ + +#ifndef RECURRENCE_PAGE_H +#define RECURRENCE_PAGE_H + +#include "editor-page.h" + +BEGIN_GNOME_DECLS + + + +#define TYPE_RECURRENCE_PAGE (recurrence_page_get_type ()) +#define RECURRENCE_PAGE(obj) (GTK_CHECK_CAST ((obj), TYPE_RECURRENCE_PAGE, RecurrencePage)) +#define RECURRENCE_PAGE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_RECURRENCE_PAGE, \ + RecurrencePageClass)) +#define IS_RECURRENCE_PAGE(obj) (GTK_CHECK_TYPE ((obj), TYPE_RECURRENCE_PAGE)) +#define IS_RECURRENCE_PAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), TYPE_RECURRENCE_PAGE)) + +typedef struct _RecurrencePagePrivate RecurrencePagePrivate; + +typedef struct { + EditorPage page; + + /* Private data */ + RecurrencePagePrivate *priv; +} RecurrencePage; + +typedef struct { + EditorPageClass parent_class; +} RecurrencePageClass; + +GtkType recurrence_page_get_type (void); + +RecurrencePage *recurrence_page_construct (RecurrencePage *rpage); + +RecurrencePage *recurrence_page_new (void); + + + +END_GNOME_DECLS + +#endif diff --git a/calendar/gui/dialogs/task-details-page.glade b/calendar/gui/dialogs/task-details-page.glade new file mode 100644 index 0000000000..31e3aba6c4 --- /dev/null +++ b/calendar/gui/dialogs/task-details-page.glade @@ -0,0 +1,137 @@ +<?xml version="1.0"?> +<GTK-Interface> + +<project> + <name>task-details-page</name> + <program_name>task-details-page</program_name> + <directory></directory> + <source_directory>src</source_directory> + <pixmaps_directory>pixmaps</pixmaps_directory> + <language>C</language> + <gnome_support>True</gnome_support> + <gettext_support>True</gettext_support> +</project> + +<widget> + <class>GtkWindow</class> + <name>task-details-toplevel</name> + <title>window1</title> + <type>GTK_WINDOW_TOPLEVEL</type> + <position>GTK_WIN_POS_NONE</position> + <modal>False</modal> + <allow_shrink>False</allow_shrink> + <allow_grow>True</allow_grow> + <auto_shrink>False</auto_shrink> + + <widget> + <class>GtkTable</class> + <name>task-details-page</name> + <border_width>4</border_width> + <rows>2</rows> + <columns>2</columns> + <homogeneous>False</homogeneous> + <row_spacing>2</row_spacing> + <column_spacing>4</column_spacing> + + <widget> + <class>GtkLabel</class> + <name>label12</name> + <label>Date Completed:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkLabel</class> + <name>label14</name> + <label>URL:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <child> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkEntry</class> + <name>url</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text_visible>True</text_visible> + <text_max_length>0</text_max_length> + <text></text> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>True</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>Custom</class> + <name>completed-date</name> + <creation_function>task_editor_create_date_edit</creation_function> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Sun, 10 Sep 2000 17:34:07 GMT</last_modification_time> + <child> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>True</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + </widget> +</widget> + +</GTK-Interface> diff --git a/calendar/gui/dialogs/task-page.glade b/calendar/gui/dialogs/task-page.glade index ae7ea9681a..e9f0d4700d 100644 --- a/calendar/gui/dialogs/task-page.glade +++ b/calendar/gui/dialogs/task-page.glade @@ -2,8 +2,8 @@ <GTK-Interface> <project> - <name>task-editor-dialog</name> - <program_name>task-editor-dialog</program_name> + <name>task-page</name> + <program_name>task-page</program_name> <directory></directory> <source_directory>src</source_directory> <pixmaps_directory>pixmaps</pixmaps_directory> @@ -13,681 +13,533 @@ </project> <widget> - <class>GnomePropertyBox</class> - <name>task-editor-dialog</name> - <visible>False</visible> + <class>GtkWindow</class> + <name>task-toplevel</name> + <title>window1</title> + <type>GTK_WINDOW_TOPLEVEL</type> <position>GTK_WIN_POS_NONE</position> <modal>False</modal> <allow_shrink>False</allow_shrink> - <allow_grow>False</allow_grow> + <allow_grow>True</allow_grow> <auto_shrink>False</auto_shrink> <widget> - <class>GtkNotebook</class> - <child_name>GnomeDock:contents</child_name> - <name>notebook1</name> - <border_width>2</border_width> - <can_focus>True</can_focus> - <show_tabs>True</show_tabs> - <show_border>True</show_border> - <tab_pos>GTK_POS_TOP</tab_pos> - <scrollable>False</scrollable> - <tab_hborder>2</tab_hborder> - <tab_vborder>2</tab_vborder> - <popup_enable>False</popup_enable> + <class>GtkVBox</class> + <name>task-page</name> + <border_width>4</border_width> + <homogeneous>False</homogeneous> + <spacing>4</spacing> <widget> - <class>GtkVBox</class> - <name>vbox1</name> - <border_width>4</border_width> + <class>GtkTable</class> + <name>table3</name> + <rows>1</rows> + <columns>2</columns> <homogeneous>False</homogeneous> - <spacing>4</spacing> + <row_spacing>4</row_spacing> + <column_spacing>4</column_spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> <widget> - <class>GtkTable</class> - <name>table3</name> - <rows>1</rows> - <columns>2</columns> - <homogeneous>False</homogeneous> - <row_spacing>4</row_spacing> - <column_spacing>4</column_spacing> + <class>GtkLabel</class> + <name>label3</name> + <label>Su_mmary:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <default_focus_target>summary</default_focus_target> <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkLabel</class> - <name>label3</name> - <label>Su_mmary:</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> <xpad>0</xpad> <ypad>0</ypad> - <default_focus_target>summary</default_focus_target> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>False</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkEntry</class> - <name>summary</name> - <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - </widget> - - <widget> - <class>GtkFrame</class> - <name>frame2</name> - <label>Date & Time</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>False</xfill> + <yfill>False</yfill> </child> - - <widget> - <class>GtkHBox</class> - <name>hbox4</name> - <border_width>4</border_width> - <homogeneous>False</homogeneous> - <spacing>0</spacing> - - <widget> - <class>GtkTable</class> - <name>table1</name> - <rows>2</rows> - <columns>2</columns> - <homogeneous>False</homogeneous> - <row_spacing>2</row_spacing> - <column_spacing>4</column_spacing> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkLabel</class> - <name>label6</name> - <label>Sta_rt Date:</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>GtkLabel</class> - <name>label5</name> - <label>_Due Date:</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>Custom</class> - <name>due-date</name> - <creation_function>task_editor_create_date_edit</creation_function> - <int1>0</int1> - <int2>0</int2> - <last_modification_time>Sun, 10 Sep 2000 17:32:18 GMT</last_modification_time> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - - <widget> - <class>Custom</class> - <name>start-date</name> - <creation_function>task_editor_create_date_edit</creation_function> - <int1>0</int1> - <int2>0</int2> - <last_modification_time>Sun, 10 Sep 2000 17:33:31 GMT</last_modification_time> - <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> - </widget> - </widget> </widget> <widget> - <class>GtkScrolledWindow</class> - <name>scrolledwindow1</name> - <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> - <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> - <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> - <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> + <class>GtkEntry</class> + <name>summary</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text_visible>True</text_visible> + <text_max_length>0</text_max_length> + <text></text> <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>True</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> </child> - - <widget> - <class>GtkText</class> - <name>description</name> - <height>80</height> - <can_focus>True</can_focus> - <editable>True</editable> - <text></text> - </widget> </widget> + </widget> + + <widget> + <class>GtkFrame</class> + <name>frame2</name> + <label>Date & Time</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> <widget> - <class>GtkFrame</class> - <name>frame23</name> - <label>Progress</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> + <class>GtkHBox</class> + <name>hbox4</name> + <border_width>4</border_width> + <homogeneous>False</homogeneous> + <spacing>0</spacing> <widget> - <class>GtkHBox</class> - <name>hbox3</name> - <border_width>4</border_width> + <class>GtkTable</class> + <name>table1</name> + <rows>2</rows> + <columns>2</columns> <homogeneous>False</homogeneous> - <spacing>4</spacing> + <row_spacing>2</row_spacing> + <column_spacing>4</column_spacing> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> <widget> <class>GtkLabel</class> - <name>label7</name> - <label>_Status:</label> + <name>label6</name> + <label>Sta_rt Date:</label> <justify>GTK_JUSTIFY_CENTER</justify> <wrap>False</wrap> - <xalign>0.5</xalign> + <xalign>0</xalign> <yalign>0.5</yalign> <xpad>0</xpad> <ypad>0</ypad> - <default_focus_target>status</default_focus_target> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkOptionMenu</class> - <name>status</name> - <can_focus>True</can_focus> - <items>Not Started -In Progress -Completed -Cancelled -</items> - <initial_choice>0</initial_choice> <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> </child> </widget> <widget> <class>GtkLabel</class> - <name>label8</name> - <label>_Priority:</label> + <name>label5</name> + <label>_Due Date:</label> <justify>GTK_JUSTIFY_CENTER</justify> <wrap>False</wrap> - <xalign>0.5</xalign> + <xalign>0</xalign> <yalign>0.5</yalign> <xpad>0</xpad> <ypad>0</ypad> - <default_focus_target>priority</default_focus_target> <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkOptionMenu</class> - <name>priority</name> - <can_focus>True</can_focus> - <items>High -Normal -Low -Undefined -</items> - <initial_choice>0</initial_choice> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> + <left_attach>0</left_attach> + <right_attach>1</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>False</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> </child> </widget> <widget> - <class>GtkLabel</class> - <name>label9</name> - <label>% Comp_lete:</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <default_focus_target>percent-complete</default_focus_target> + <class>Custom</class> + <name>due-date</name> + <creation_function>task_editor_create_date_edit</creation_function> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Sun, 10 Sep 2000 17:32:18 GMT</last_modification_time> <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>True</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> </child> </widget> <widget> - <class>GtkSpinButton</class> - <name>percent-complete</name> - <width>60</width> - <can_focus>True</can_focus> - <climb_rate>1</climb_rate> - <digits>0</digits> - <numeric>False</numeric> - <update_policy>GTK_UPDATE_ALWAYS</update_policy> - <snap>False</snap> - <wrap>False</wrap> - <value>0</value> - <lower>0</lower> - <upper>100</upper> - <step>10</step> - <page>10</page> - <page_size>10</page_size> + <class>Custom</class> + <name>start-date</name> + <creation_function>task_editor_create_date_edit</creation_function> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Sun, 10 Sep 2000 17:33:31 GMT</last_modification_time> <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> + <left_attach>1</left_attach> + <right_attach>2</right_attach> + <top_attach>1</top_attach> + <bottom_attach>2</bottom_attach> + <xpad>0</xpad> + <ypad>0</ypad> + <xexpand>True</xexpand> + <yexpand>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> </child> </widget> </widget> </widget> + </widget> - <widget> - <class>GtkFrame</class> - <name>frame24</name> - <label>Classification</label> - <label_xalign>0</label_xalign> - <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkHBox</class> - <name>hbox6</name> - <border_width>2</border_width> - <homogeneous>False</homogeneous> - <spacing>4</spacing> - - <widget> - <class>GtkRadioButton</class> - <name>classification-public</name> - <can_focus>True</can_focus> - <label>Pu_blic</label> - <active>True</active> - <draw_indicator>True</draw_indicator> - <group>classification_radio_group</group> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - - <widget> - <class>GtkRadioButton</class> - <name>classification-private</name> - <can_focus>True</can_focus> - <label>Pri_vate</label> - <active>False</active> - <draw_indicator>True</draw_indicator> - <group>classification_radio_group</group> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> + <widget> + <class>GtkScrolledWindow</class> + <name>scrolledwindow1</name> + <hscrollbar_policy>GTK_POLICY_NEVER</hscrollbar_policy> + <vscrollbar_policy>GTK_POLICY_AUTOMATIC</vscrollbar_policy> + <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy> + <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> - <widget> - <class>GtkRadioButton</class> - <name>classification-confidential</name> - <can_focus>True</can_focus> - <label>_Confidential</label> - <active>False</active> - <draw_indicator>True</draw_indicator> - <group>classification_radio_group</group> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </widget> - </widget> + <widget> + <class>GtkText</class> + <name>description</name> + <height>80</height> + <can_focus>True</can_focus> + <editable>True</editable> + <text></text> </widget> + </widget> + + <widget> + <class>GtkFrame</class> + <name>frame23</name> + <label>Progress</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> <widget> <class>GtkHBox</class> - <name>hbox2</name> + <name>hbox3</name> + <border_width>4</border_width> <homogeneous>False</homogeneous> - <spacing>2</spacing> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> + <spacing>4</spacing> <widget> - <class>GtkButton</class> - <name>contacts-button</name> - <can_focus>True</can_focus> + <class>GtkLabel</class> + <name>label7</name> + <label>_Status:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <default_focus_target>status</default_focus_target> <child> <padding>0</padding> <expand>False</expand> <fill>False</fill> </child> - - <widget> - <class>GtkLabel</class> - <name>label16</name> - <label>_Contacts...</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>4</xpad> - <ypad>0</ypad> - </widget> </widget> <widget> - <class>GtkEntry</class> - <name>contacts</name> + <class>GtkOptionMenu</class> + <name>status</name> <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> + <items>Not Started +In Progress +Completed +Cancelled +</items> + <initial_choice>0</initial_choice> <child> <padding>0</padding> - <expand>True</expand> - <fill>True</fill> + <expand>False</expand> + <fill>False</fill> </child> </widget> <widget> - <class>GtkButton</class> - <name>categories-button</name> + <class>GtkLabel</class> + <name>label8</name> + <label>_Priority:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <default_focus_target>priority</default_focus_target> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkOptionMenu</class> + <name>priority</name> <can_focus>True</can_focus> + <items>High +Normal +Low +Undefined +</items> + <initial_choice>0</initial_choice> <child> <padding>0</padding> <expand>False</expand> <fill>False</fill> </child> + </widget> - <widget> - <class>GtkLabel</class> - <name>label17</name> - <label>Ca_tegories...</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>4</xpad> - <ypad>0</ypad> - </widget> + <widget> + <class>GtkLabel</class> + <name>label9</name> + <label>% Comp_lete:</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>0</xpad> + <ypad>0</ypad> + <default_focus_target>percent-complete</default_focus_target> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> </widget> <widget> - <class>GtkEntry</class> - <name>categories</name> + <class>GtkSpinButton</class> + <name>percent-complete</name> + <width>60</width> <can_focus>True</can_focus> - <editable>True</editable> - <text_visible>True</text_visible> - <text_max_length>0</text_max_length> - <text></text> + <climb_rate>1</climb_rate> + <digits>0</digits> + <numeric>False</numeric> + <update_policy>GTK_UPDATE_ALWAYS</update_policy> + <snap>False</snap> + <wrap>False</wrap> + <value>0</value> + <lower>0</lower> + <upper>100</upper> + <step>10</step> + <page>10</page> + <page_size>10</page_size> <child> <padding>0</padding> - <expand>True</expand> - <fill>True</fill> + <expand>False</expand> + <fill>False</fill> </child> </widget> </widget> </widget> <widget> - <class>GtkLabel</class> - <child_name>Notebook:tab</child_name> - <name>label1</name> - <label>Task</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> + <class>GtkFrame</class> + <name>frame24</name> + <label>Classification</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>True</fill> + </child> + + <widget> + <class>GtkHBox</class> + <name>hbox6</name> + <border_width>2</border_width> + <homogeneous>False</homogeneous> + <spacing>4</spacing> + + <widget> + <class>GtkRadioButton</class> + <name>classification-public</name> + <can_focus>True</can_focus> + <label>Pu_blic</label> + <active>True</active> + <draw_indicator>True</draw_indicator> + <group>classification_radio_group</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkRadioButton</class> + <name>classification-private</name> + <can_focus>True</can_focus> + <label>Pri_vate</label> + <active>False</active> + <draw_indicator>True</draw_indicator> + <group>classification_radio_group</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + + <widget> + <class>GtkRadioButton</class> + <name>classification-confidential</name> + <can_focus>True</can_focus> + <label>_Confidential</label> + <active>False</active> + <draw_indicator>True</draw_indicator> + <group>classification_radio_group</group> + <child> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> + </child> + </widget> + </widget> </widget> <widget> - <class>GtkTable</class> - <name>table4</name> - <border_width>4</border_width> - <rows>2</rows> - <columns>2</columns> + <class>GtkHBox</class> + <name>hbox2</name> <homogeneous>False</homogeneous> - <row_spacing>2</row_spacing> - <column_spacing>4</column_spacing> + <spacing>2</spacing> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> <widget> - <class>GtkLabel</class> - <name>label12</name> - <label>Date Completed:</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> + <class>GtkButton</class> + <name>contacts-button</name> + <can_focus>True</can_focus> + <relief>GTK_RELIEF_NORMAL</relief> <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> </child> - </widget> - <widget> - <class>GtkLabel</class> - <name>label14</name> - <label>URL:</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> - <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> + <widget> + <class>GtkLabel</class> + <name>label16</name> + <label>_Contacts...</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>4</xpad> <ypad>0</ypad> - <xexpand>False</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> + </widget> </widget> <widget> <class>GtkEntry</class> - <name>url</name> + <name>contacts</name> <can_focus>True</can_focus> <editable>True</editable> <text_visible>True</text_visible> <text_max_length>0</text_max_length> <text></text> <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>1</top_attach> - <bottom_attach>2</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> </child> </widget> <widget> - <class>Custom</class> - <name>completed-date</name> - <creation_function>task_editor_create_date_edit</creation_function> - <int1>0</int1> - <int2>0</int2> - <last_modification_time>Sun, 10 Sep 2000 17:34:07 GMT</last_modification_time> + <class>GtkButton</class> + <name>categories-button</name> + <can_focus>True</can_focus> + <relief>GTK_RELIEF_NORMAL</relief> <child> - <left_attach>1</left_attach> - <right_attach>2</right_attach> - <top_attach>0</top_attach> - <bottom_attach>1</bottom_attach> - <xpad>0</xpad> - <ypad>0</ypad> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> + <padding>0</padding> + <expand>False</expand> + <fill>False</fill> </child> + + <widget> + <class>GtkLabel</class> + <name>label17</name> + <label>Ca_tegories...</label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>4</xpad> + <ypad>0</ypad> + </widget> </widget> - </widget> - <widget> - <class>GtkLabel</class> - <child_name>Notebook:tab</child_name> - <name>label2</name> - <label>Details</label> - <justify>GTK_JUSTIFY_CENTER</justify> - <wrap>False</wrap> - <xalign>0.5</xalign> - <yalign>0.5</yalign> - <xpad>0</xpad> - <ypad>0</ypad> + <widget> + <class>GtkEntry</class> + <name>categories</name> + <can_focus>True</can_focus> + <editable>True</editable> + <text_visible>True</text_visible> + <text_max_length>0</text_max_length> + <text></text> + <child> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> + </child> + </widget> </widget> </widget> </widget> diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index b10382a3ea..b19c7ff310 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -803,11 +803,11 @@ e_day_view_init (EDayView *day_view) gtk_drag_dest_set (day_view->top_canvas, GTK_DEST_DEFAULT_ALL, target_table, n_targets, - GDK_ACTION_COPY | GDK_ACTION_MOVE); + GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK); gtk_drag_dest_set (day_view->main_canvas, GTK_DEST_DEFAULT_ALL, target_table, n_targets, - GDK_ACTION_COPY | GDK_ACTION_MOVE); + GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK); } diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index c06b568d9d..96270c04aa 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -379,7 +379,6 @@ e_week_view_init (EWeekView *week_view) 2, 3, 1, 2, 0, GTK_EXPAND | GTK_FILL, 0, 0); gtk_widget_show (week_view->vscrollbar); - /* Create the cursors. */ week_view->normal_cursor = gdk_cursor_new (GDK_LEFT_PTR); week_view->move_cursor = gdk_cursor_new (GDK_FLEUR); diff --git a/calendar/gui/event-editor.c b/calendar/gui/event-editor.c index 242ef67226..c96c94dadd 100644 --- a/calendar/gui/event-editor.c +++ b/calendar/gui/event-editor.c @@ -1656,7 +1656,7 @@ fill_reminder_widgets (EventEditor *ee) /* Add it to the clist */ append_reminder (ee, ca, EXISTING_ALARM); } - cal_component_free_alarm_uids (alarms); + cal_obj_uid_list_free (alarms); } /* Fills in the recurrence widgets with the values from the calendar component. |