diff options
author | JP Rosevear <jpr@ximian.com> | 2001-06-02 07:54:43 +0800 |
---|---|---|
committer | JP Rosevear <jpr@src.gnome.org> | 2001-06-02 07:54:43 +0800 |
commit | f4e8698fdd4c48422f217f409e92ec7a2d26c443 (patch) | |
tree | 52e697a2a46e790a2d8059680c7a3bff252e97ad /calendar/gui | |
parent | 58d8f86e64d42782ac80ec4ed40b5269a3493454 (diff) | |
download | gsoc2013-evolution-f4e8698fdd4c48422f217f409e92ec7a2d26c443.tar gsoc2013-evolution-f4e8698fdd4c48422f217f409e92ec7a2d26c443.tar.gz gsoc2013-evolution-f4e8698fdd4c48422f217f409e92ec7a2d26c443.tar.bz2 gsoc2013-evolution-f4e8698fdd4c48422f217f409e92ec7a2d26c443.tar.lz gsoc2013-evolution-f4e8698fdd4c48422f217f409e92ec7a2d26c443.tar.xz gsoc2013-evolution-f4e8698fdd4c48422f217f409e92ec7a2d26c443.tar.zst gsoc2013-evolution-f4e8698fdd4c48422f217f409e92ec7a2d26c443.zip |
renamed from editor-page for consistency, more complete implementation
2001-06-01 JP Rosevear <jpr@ximian.com>
* gui/dialogs/comp-editor-page.[hc]: renamed from editor-page for
consistency, more complete implementation
* gui/dialogs/comp-editor.[hc]: More complete implementation
* gui/dialogs/*-page.*: The various pages needed to construct the
event and task dialogs
* gui/dialogs/comp-editor-util.[hc]: useful utility functions for the
component editor pages to use
* gui/dialogs/Makefile.am: Build and install new files
* gui/event-editor*: Remove, obsoleted by the new comp-editor
stuff
* gui/dialogs/task-editor-dialog.glade: ditto
* gui/e-calendar-table.c (open_task): update to use comp editor
stuff
* gui/e-tasks.c (e_tasks_new_task): ditto
* gui/gnome-cal.c (gnome_calendar_edit_object): ditto
* gui/Makefile.am: don't build non-existent files nor try to
install them
svn path=/trunk/; revision=10088
Diffstat (limited to 'calendar/gui')
35 files changed, 3532 insertions, 7753 deletions
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index 571d4f6db8..55a19bbf4c 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -42,7 +42,6 @@ INCLUDES = \ gladedir = $(datadir)/evolution/glade glade_DATA = \ - event-editor-dialog.glade \ e-meeting-dialog.glade \ e-itip-control.glade \ goto-dialog.glade @@ -91,8 +90,6 @@ evolution_calendar_SOURCES = \ e-week-view.h \ e-tasks.c \ e-tasks.h \ - event-editor.c \ - event-editor.h \ gnome-cal.c \ gnome-cal.h \ goto.c \ @@ -131,8 +128,7 @@ evolution_calendar_LDADD = \ $(BONOBO_HTML_GNOME_LIBS) \ $(GNOME_VFS_LIBS) \ $(GAL_LIBS) \ - $(INTLLIBS) \ - $(DB3_LDADD) + $(INTLLIBS) #evolution_calendar_LDFLAGS = `gnome-config --libs gdk_pixbuf` diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am index 034e4060fc..74c65d72ab 100644 --- a/calendar/gui/dialogs/Makefile.am +++ b/calendar/gui/dialogs/Makefile.am @@ -24,10 +24,16 @@ libcal_dialogs_a_SOURCES = \ alarm-page.h \ cal-prefs-dialog.c \ cal-prefs-dialog.h \ + comp-editor.c \ + comp-editor.h \ + comp-editor-page.c \ + comp-editor-page.h \ + comp-editor-util.c \ + comp-editor-util.h \ delete-comp.c \ delete-comp.h \ - editor-page.c \ - editor-page.h \ + event-editor.c \ + event-editor.h \ event-page.c \ event-page.h \ recurrence-page.c \ @@ -35,7 +41,11 @@ libcal_dialogs_a_SOURCES = \ save-comp.c \ save-comp.h \ task-editor.c \ - task-editor.h + task-editor.h \ + task-details-page.c \ + task-details-page.h \ + task-page.c \ + task-page.h glade_DATA = \ alarm-notify.glade \ @@ -44,7 +54,6 @@ glade_DATA = \ event-page.glade \ recurrence-page.glade \ task-details-page.glade \ - task-editor-dialog.glade \ task-page.glade EXTRA_DIST = \ diff --git a/calendar/gui/dialogs/alarm-page.c b/calendar/gui/dialogs/alarm-page.c index 85141e9c47..74e728ad4c 100644 --- a/calendar/gui/dialogs/alarm-page.c +++ b/calendar/gui/dialogs/alarm-page.c @@ -26,13 +26,15 @@ #include <config.h> #endif +#include <string.h> #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 "cal-util/cal-util.h" +#include "comp-editor-util.h" #include "alarm-page.h" @@ -47,7 +49,7 @@ struct _AlarmPagePrivate { GtkWidget *main; GtkWidget *summary; - GtkWidget *starting_date; + GtkWidget *date_time; GtkWidget *list; GtkWidget *add; @@ -58,6 +60,8 @@ struct _AlarmPagePrivate { GtkWidget *value_units; GtkWidget *relative; GtkWidget *time; + + gboolean updating; }; @@ -66,14 +70,13 @@ 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_dates (EditorPage *page, time_t start, time_t end); +static GtkWidget *alarm_page_get_widget (CompEditorPage *page); +static void alarm_page_fill_widgets (CompEditorPage *page, CalComponent *comp); +static void alarm_page_fill_component (CompEditorPage *page, CalComponent *comp); +static void alarm_page_set_summary (CompEditorPage *page, const char *summary); +static void alarm_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates); -static EditorPageClass *parent_class = NULL; +static CompEditorPageClass *parent_class = NULL; @@ -102,7 +105,8 @@ alarm_page_get_type (void) (GtkClassInitFunc) NULL }; - alarm_page_type = gtk_type_unique (TYPE_EDITOR_PAGE, &alarm_page_info); + alarm_page_type = gtk_type_unique (TYPE_COMP_EDITOR_PAGE, + &alarm_page_info); } return alarm_page_type; @@ -112,19 +116,18 @@ alarm_page_get_type (void) static void alarm_page_class_init (AlarmPageClass *class) { - EditorPageClass *editor_page_class; + CompEditorPageClass *editor_page_class; GtkObjectClass *object_class; - editor_page_class = (EditorPageClass *) class; + editor_page_class = (CompEditorPageClass *) class; object_class = (GtkObjectClass *) class; - parent_class = gtk_type_class (TYPE_EDITOR_PAGE); + parent_class = gtk_type_class (TYPE_COMP_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_dates = alarm_page_set_dates; object_class->destroy = alarm_page_destroy; @@ -143,7 +146,7 @@ alarm_page_init (AlarmPage *apage) priv->main = NULL; priv->summary = NULL; - priv->starting_date = NULL; + priv->date_time = NULL; priv->list = NULL; priv->add = NULL; priv->delete = NULL; @@ -152,6 +155,8 @@ alarm_page_init (AlarmPage *apage) priv->value_units = NULL; priv->relative = NULL; priv->time = NULL; + + priv->updating = FALSE; } /* Frees all the alarm data and empties the list */ @@ -159,24 +164,25 @@ 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); + if (priv->list != NULL) { + GtkCList *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); } - - gtk_clist_clear (clist); } /* Destroy handler for the alarm page */ @@ -210,7 +216,7 @@ alarm_page_destroy (GtkObject *object) /* get_widget handler for the alarm page */ static GtkWidget * -alarm_page_get_widget (EditorPage *page) +alarm_page_get_widget (CompEditorPage *page) { AlarmPage *apage; AlarmPagePrivate *priv; @@ -230,10 +236,10 @@ clear_widgets (AlarmPage *apage) priv = apage->priv; /* Summary */ - e_dialog_editable_set (priv->summary, NULL); + gtk_label_set_text (GTK_LABEL (priv->summary), ""); /* Start date */ - gtk_label_set_text (GTK_LABEL (priv->starting_date), ""); + gtk_label_set_text (GTK_LABEL (priv->date_time), ""); /* List data */ free_alarms (apage); @@ -310,6 +316,7 @@ get_alarm_string (CalComponentAlarm *alarm) case CAL_ALARM_NONE: case CAL_ALARM_UNKNOWN: + default: base = _("Unknown"); break; } @@ -344,6 +351,7 @@ get_alarm_string (CalComponentAlarm *alarm) break; case CAL_ALARM_TRIGGER_NONE: case CAL_ALARM_TRIGGER_ABSOLUTE: + default: str = g_strdup_printf ("%s %s", base, _("Unknown")); break; @@ -377,22 +385,31 @@ append_reminder (AlarmPage *apage, CalComponentAlarm *alarm) /* fill_widgets handler for the alarm page */ static void -alarm_page_fill_widgets (EditorPage *page, CalComponent *comp) +alarm_page_fill_widgets (CompEditorPage *page, CalComponent *comp) { AlarmPage *apage; AlarmPagePrivate *priv; CalComponentText text; GList *alarms, *l; GtkCList *clist; - + CompEditorPageDates dates; + apage = ALARM_PAGE (page); priv = apage->priv; + /* Don't send off changes during this time */ + priv->updating = TRUE; + + /* Clean the page */ clear_widgets (apage); /* Summary */ cal_component_get_summary (comp, &text); - e_dialog_editable_set (priv->summary, text.value); + alarm_page_set_summary (page, text.value); + + /* Dates */ + comp_editor_dates (&dates, comp); + alarm_page_set_dates (page, &dates); /* List */ if (!cal_component_has_alarms (comp)) @@ -415,11 +432,13 @@ alarm_page_fill_widgets (EditorPage *page, CalComponent *comp) append_reminder (apage, ca_copy); } cal_obj_uid_list_free (alarms); + + priv->updating = FALSE; } /* fill_component handler for the alarm page */ static void -alarm_page_fill_component (EditorPage *page, CalComponent *comp) +alarm_page_fill_component (CompEditorPage *page, CalComponent *comp) { AlarmPage *apage; AlarmPagePrivate *priv; @@ -462,48 +481,31 @@ alarm_page_fill_component (EditorPage *page, CalComponent *comp) /* set_summary handler for the alarm page */ static void -alarm_page_set_summary (EditorPage *page, const char *summary) +alarm_page_set_summary (CompEditorPage *page, const char *summary) { AlarmPage *apage; AlarmPagePrivate *priv; - + gchar *s; + 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)); + s = e_utf8_to_gtk_string (priv->summary, summary); + gtk_label_set_text (GTK_LABEL (priv->summary), s); + g_free (s); } /* set_dates handler for the alarm page */ static void -alarm_page_set_dates (EditorPage *page, time_t start, time_t end) +alarm_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) { 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_label_set_text (GTK_LABEL (priv->starting_date), str); + comp_editor_date_label (dates, priv->date_time); } @@ -554,23 +556,18 @@ 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; - + g_assert (priv->main); 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->date_time = GW ("date-time"); priv->list = GW ("list"); priv->add = GW ("add"); @@ -585,7 +582,7 @@ get_widgets (AlarmPage *apage) #undef GW return (priv->summary - && priv->starting_date + && priv->date_time && priv->list && priv->add && priv->delete @@ -596,24 +593,18 @@ get_widgets (AlarmPage *apage) && 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; - + AlarmPagePrivate *priv; + apage = ALARM_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (apage)); + priv = apage->priv; + + if (!priv->updating) + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (apage)); } /* Callback used for the "add reminder" button */ @@ -639,15 +630,18 @@ add_clicked_cb (GtkButton *button, gpointer data) 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); + 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); + 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); + trigger.u.rel_duration.days = + e_dialog_spin_get_int (priv->interval_value); break; default: @@ -702,10 +696,6 @@ init_widgets (AlarmPage *apage) 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); @@ -739,14 +729,17 @@ alarm_page_construct (AlarmPage *apage) priv = apage->priv; - priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/alarm-page.glade", NULL); + 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!"); + 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!"); + g_message ("alarm_page_construct(): " + "Could not find all widgets in the XML file!"); return NULL; } diff --git a/calendar/gui/dialogs/alarm-page.glade b/calendar/gui/dialogs/alarm-page.glade index 3a4a8d6765..183ec1b95b 100644 --- a/calendar/gui/dialogs/alarm-page.glade +++ b/calendar/gui/dialogs/alarm-page.glade @@ -18,6 +18,7 @@ <widget> <class>GtkWindow</class> <name>alarm-toplevel</name> + <visible>False</visible> <title>window1</title> <type>GTK_WINDOW_TOPLEVEL</type> <position>GTK_WIN_POS_NONE</position> @@ -36,7 +37,7 @@ <widget> <class>GtkFrame</class> <name>frame33</name> - <label>Appointment Basics</label> + <label>Basics</label> <label_xalign>0</label_xalign> <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> <child> @@ -58,14 +59,13 @@ <widget> <class>GtkLabel</class> <name>label62</name> - <label>Su_mmary:</label> + <label>Summary:</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> @@ -83,42 +83,44 @@ </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> + <class>GtkLabel</class> + <name>label63</name> + <label>Date/Time:</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>0</top_attach> - <bottom_attach>1</bottom_attach> + <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>True</xexpand> + <xexpand>False</xexpand> <yexpand>False</yexpand> - <xshrink>True</xshrink> + <xshrink>False</xshrink> <yshrink>False</yshrink> <xfill>True</xfill> - <yfill>False</yfill> + <yfill>True</yfill> </child> </widget> <widget> <class>GtkLabel</class> - <name>label63</name> - <label>_Starting date:</label> - <justify>GTK_JUSTIFY_CENTER</justify> + <name>date-time</name> + <label></label> + <justify>GTK_JUSTIFY_LEFT</justify> <wrap>False</wrap> - <xalign>0</xalign> - <yalign>0</yalign> - <xpad>0</xpad> + <xalign>0.5</xalign> + <yalign>0.5</yalign> + <xpad>4</xpad> <ypad>0</ypad> <child> - <left_attach>0</left_attach> - <right_attach>1</right_attach> + <left_attach>1</left_attach> + <right_attach>2</right_attach> <top_attach>1</top_attach> <bottom_attach>2</bottom_attach> <xpad>0</xpad> @@ -134,19 +136,19 @@ <widget> <class>GtkLabel</class> - <name>starting date</name> - <label>assbarn it</label> - <justify>GTK_JUSTIFY_CENTER</justify> + <name>summary</name> + <label></label> + <justify>GTK_JUSTIFY_LEFT</justify> <wrap>False</wrap> <xalign>0</xalign> - <yalign>0</yalign> - <xpad>0</xpad> + <yalign>0.5</yalign> + <xpad>4</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> + <top_attach>0</top_attach> + <bottom_attach>1</bottom_attach> <xpad>0</xpad> <ypad>0</ypad> <xexpand>False</xexpand> @@ -154,7 +156,7 @@ <xshrink>False</xshrink> <yshrink>False</yshrink> <xfill>True</xfill> - <yfill>True</yfill> + <yfill>False</yfill> </child> </widget> </widget> @@ -192,7 +194,7 @@ <widget> <class>GtkOptionMenu</class> - <name>reminder-action</name> + <name>action</name> <can_focus>True</can_focus> <items>Show a dialog Play a sound @@ -209,7 +211,7 @@ Run a program <widget> <class>GtkSpinButton</class> - <name>reminder-interval-value</name> + <name>interval-value</name> <can_focus>True</can_focus> <climb_rate>1</climb_rate> <digits>0</digits> @@ -232,7 +234,7 @@ Run a program <widget> <class>GtkOptionMenu</class> - <name>reminder-value-units</name> + <name>value-units</name> <can_focus>True</can_focus> <items>minute(s) hour(s) @@ -248,7 +250,7 @@ day(s) <widget> <class>GtkOptionMenu</class> - <name>reminder-relative</name> + <name>relative</name> <can_focus>True</can_focus> <items>before after @@ -263,7 +265,7 @@ after <widget> <class>GtkOptionMenu</class> - <name>reminder-time</name> + <name>time</name> <can_focus>True</can_focus> <items>start of appointment end of appointment @@ -281,7 +283,6 @@ end of appointment <name>button9</name> <can_focus>True</can_focus> <label>Settings...</label> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> @@ -316,7 +317,7 @@ end of appointment <widget> <class>GtkCList</class> - <name>reminder-list</name> + <name>list</name> <can_focus>True</can_focus> <columns>1</columns> <column_widths>80</column_widths> @@ -356,20 +357,18 @@ end of appointment <widget> <class>GtkButton</class> - <name>reminder-add</name> + <name>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> + <name>delete</name> <can_default>True</can_default> <can_focus>True</can_focus> <label>Delete</label> - <relief>GTK_RELIEF_NORMAL</relief> </widget> </widget> </widget> diff --git a/calendar/gui/dialogs/alarm-page.h b/calendar/gui/dialogs/alarm-page.h index 1cb0b301bd..97c1361f4d 100644 --- a/calendar/gui/dialogs/alarm-page.h +++ b/calendar/gui/dialogs/alarm-page.h @@ -25,7 +25,7 @@ #ifndef ALARM_PAGE_H #define ALARM_PAGE_H -#include "editor-page.h" +#include "comp-editor-page.h" BEGIN_GNOME_DECLS @@ -33,29 +33,27 @@ 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 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; + CompEditorPage page; /* Private data */ AlarmPagePrivate *priv; } AlarmPage; typedef struct { - EditorPageClass parent_class; + CompEditorPageClass parent_class; } AlarmPageClass; -GtkType alarm_page_get_type (void); +GtkType alarm_page_get_type (void); AlarmPage *alarm_page_construct (AlarmPage *apage); - -AlarmPage *alarm_page_new (void); +AlarmPage *alarm_page_new (void); diff --git a/calendar/gui/dialogs/comp-editor-page.c b/calendar/gui/dialogs/comp-editor-page.c new file mode 100644 index 0000000000..f390e86dd8 --- /dev/null +++ b/calendar/gui/dialogs/comp-editor-page.c @@ -0,0 +1,277 @@ +/* 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 "comp-editor-page.h" + + + +static void comp_editor_page_class_init (CompEditorPageClass *class); + +/* Signal IDs */ + +enum { + CHANGED, + SUMMARY_CHANGED, + DATES_CHANGED, + LAST_SIGNAL +}; + +static guint comp_editor_page_signals[LAST_SIGNAL]; + +#define CLASS(page) (COMP_EDITOR_PAGE_CLASS (GTK_OBJECT (page)->klass)) + + + +/** + * comp_editor_page_get_type: + * + * Registers the #CompEditorPage class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #CompEditorPage class. + **/ +GtkType +comp_editor_page_get_type (void) +{ + static GtkType comp_editor_page_type = 0; + + if (!comp_editor_page_type) { + static const GtkTypeInfo comp_editor_page_info = { + "CompEditorPage", + sizeof (CompEditorPage), + sizeof (CompEditorPageClass), + (GtkClassInitFunc) comp_editor_page_class_init, + (GtkObjectInitFunc) NULL, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + comp_editor_page_type = + gtk_type_unique (GTK_TYPE_OBJECT, + &comp_editor_page_info); + } + + return comp_editor_page_type; +} + +/* Class initialization function for the abstract editor page */ +static void +comp_editor_page_class_init (CompEditorPageClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass *) class; + + comp_editor_page_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (CompEditorPageClass, + changed), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + comp_editor_page_signals[SUMMARY_CHANGED] = + gtk_signal_new ("summary_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (CompEditorPageClass, + summary_changed), + gtk_marshal_NONE__POINTER, + GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); + + comp_editor_page_signals[DATES_CHANGED] = + gtk_signal_new ("dates_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (CompEditorPageClass, + dates_changed), + gtk_marshal_NONE__POINTER, + GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); + + gtk_object_class_add_signals (object_class, + comp_editor_page_signals, + LAST_SIGNAL); + + class->changed = NULL; + class->summary_changed = NULL; + class->dates_changed = NULL; + + class->get_widget = NULL; + class->fill_widgets = NULL; + class->fill_component = NULL; + class->set_summary = NULL; + class->set_dates = NULL; +} + + + +/** + * comp_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 * +comp_editor_page_get_widget (CompEditorPage *page) +{ + g_return_val_if_fail (page != NULL, NULL); + g_return_val_if_fail (IS_COMP_EDITOR_PAGE (page), NULL); + + g_assert (CLASS (page)->get_widget != NULL); + return (* CLASS (page)->get_widget) (page); +} + +/** + * comp_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 +comp_editor_page_fill_widgets (CompEditorPage *page, CalComponent *comp) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); + g_return_if_fail (comp != NULL); + + g_assert (CLASS (page)->fill_widgets != NULL); + (* CLASS (page)->fill_widgets) (page, comp); +} + +/** + * 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 +comp_editor_page_fill_component (CompEditorPage *page, CalComponent *comp) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); + g_return_if_fail (comp != NULL); + + if (CLASS (page)->fill_component != NULL) + (* CLASS (page)->fill_component) (page, comp); +} + +/** + * comp_editor_page_set_summary: + * @page: An editor page + * @summary: The text of the new summary value + * + * Sets the summary value for this group of widgets + **/ +void +comp_editor_page_set_summary (CompEditorPage *page, const char *summary) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); + + if (CLASS (page)->set_summary != NULL) + (* CLASS (page)->set_summary) (page, summary); +} + +/** + * comp_editor_page_set_dates: + * @page: An editor page + * @dates: A collection of various dates in time_t format + * + * Sets the date values for this group of widgets + **/ +void +comp_editor_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); + + if (CLASS (page)->set_dates != NULL) + (* CLASS (page)->set_dates) (page, dates); +} + +/** + * comp_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 +comp_editor_page_notify_changed (CompEditorPage *page) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); + + gtk_signal_emit (GTK_OBJECT (page), comp_editor_page_signals[CHANGED]); +} + +/** + * comp_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 +comp_editor_page_notify_summary_changed (CompEditorPage *page, + const char *summary) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); + + + gtk_signal_emit (GTK_OBJECT (page), + comp_editor_page_signals[SUMMARY_CHANGED], + summary); +} + +/** + * comp_editor_page_notify_dates_changed: + * @page: An editor page. + * + * Makes an editor page emit the "dates_changed" signal. This is meant to be + * used only by page implementations. + **/ +void +comp_editor_page_notify_dates_changed (CompEditorPage *page, + CompEditorPageDates *dates) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); + + gtk_signal_emit (GTK_OBJECT (page), + comp_editor_page_signals[DATES_CHANGED], + dates); +} diff --git a/calendar/gui/dialogs/comp-editor-page.h b/calendar/gui/dialogs/comp-editor-page.h new file mode 100644 index 0000000000..ac088e7759 --- /dev/null +++ b/calendar/gui/dialogs/comp-editor-page.h @@ -0,0 +1,93 @@ +/* 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 COMP_EDITOR_PAGE_H +#define COMP_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_COMP_EDITOR_PAGE (comp_editor_page_get_type ()) +#define COMP_EDITOR_PAGE(obj) (GTK_CHECK_CAST ((obj), TYPE_COMP_EDITOR_PAGE, CompEditorPage)) +#define COMP_EDITOR_PAGE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_COMP_EDITOR_PAGE, CompEditorPageClass)) +#define IS_COMP_EDITOR_PAGE(obj) (GTK_CHECK_TYPE ((obj), TYPE_COMP_EDITOR_PAGE)) +#define IS_COMP_EDITOR_PAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), TYPE_COMP_EDITOR_PAGE)) + +typedef struct { + time_t start; + time_t end; + time_t due; + time_t complete; +} CompEditorPageDates; + +typedef struct { + GtkObject object; +} CompEditorPage; + +typedef struct { + GtkObjectClass parent_class; + + /* Notification signals */ + + void (* changed) (CompEditorPage *page); + void (* summary_changed) (CompEditorPage *page, const char *summary); + void (* dates_changed) (CompEditorPage *page, const char *dates); + + /* Virtual methods */ + + GtkWidget *(* get_widget) (CompEditorPage *page); + + void (* fill_widgets) (CompEditorPage *page, CalComponent *comp); + void (* fill_component) (CompEditorPage *page, CalComponent *comp); + + void (* set_summary) (CompEditorPage *page, const char *summary); + void (* set_dates) (CompEditorPage *page, CompEditorPageDates *dates); +} CompEditorPageClass; + + +GtkType comp_editor_page_get_type (void); +GtkWidget *comp_editor_page_get_widget (CompEditorPage *page); +void comp_editor_page_fill_widgets (CompEditorPage *page, + CalComponent *comp); +void comp_editor_page_fill_component (CompEditorPage *page, + CalComponent *comp); +void comp_editor_page_set_summary (CompEditorPage *page, + const char *summary); +void comp_editor_page_set_dates (CompEditorPage *page, + CompEditorPageDates *dates); +void comp_editor_page_notify_changed (CompEditorPage *page); +void comp_editor_page_notify_summary_changed (CompEditorPage *page, + const char *summary); +void comp_editor_page_notify_dates_changed (CompEditorPage *page, + CompEditorPageDates *dates); + + + + +END_GNOME_DECLS + +#endif diff --git a/calendar/gui/dialogs/comp-editor-util.c b/calendar/gui/dialogs/comp-editor-util.c new file mode 100644 index 0000000000..1110b5f18a --- /dev/null +++ b/calendar/gui/dialogs/comp-editor-util.c @@ -0,0 +1,129 @@ +/* Evolution calendar - Widget utilities + * + * Copyright (C) 2000 Helix Code, Inc. + * + * Author: Federico Mena-Quintero <federico@helixcode.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 <string.h> +#include <glib.h> +#include <libgnome/gnome-defs.h> +#include <libgnome/gnome-i18n.h> +#include <e-util/e-time-utils.h> +#include "../calendar-config.h" +#include "comp-editor-util.h" + + + +/** + * comp_editor_dates: + * @dates: A structure to be filled out with dates of a component + * @comp: The component to extract the dates from + * + * Extracts the dates from the calendar component into the + * CompEditorPageDates structure + **/ +void +comp_editor_dates (CompEditorPageDates *dates, CalComponent *comp) +{ + CalComponentDateTime dt; + struct icaltimetype *completed; + + dates->start = 0; + dates->end = 0; + dates->due = 0; + dates->complete = 0; + + cal_component_get_dtstart (comp, &dt); + if (dt.value) + dates->start = icaltime_as_timet (*dt.value); + + cal_component_get_dtend (comp, &dt); + if (dt.value) + dates->end = icaltime_as_timet (*dt.value); + + cal_component_get_due (comp, &dt); + if (dt.value) + dates->due = icaltime_as_timet (*dt.value); + + cal_component_get_completed (comp, &completed); + if (completed) { + dates->complete = icaltime_as_timet (*completed); + cal_component_free_icaltimetype (completed); + } +} + +static void +write_label_piece (time_t t, char *buffer, int size, char *stext, char *etext) +{ + struct tm *tmp_tm; + int len; + + tmp_tm = localtime (&t); + if (stext != NULL) + strcat (buffer, stext); + + len = strlen (buffer); + e_time_format_date_and_time (tmp_tm, + calendar_config_get_24_hour_format (), + FALSE, FALSE, + &buffer[len], size - len); + if (etext != NULL) + strcat (buffer, etext); +} + +/** + * comp_editor_date_label: + * @dates: The dates to use in constructing a label + * @label: The label whose text is to be set + * + * Set the text of a label based on the dates available and the user's + * formatting preferences + **/ +void +comp_editor_date_label (CompEditorPageDates *dates, GtkWidget *label) +{ + static char buffer[1024]; + + buffer[0] = '\0'; + + if (dates->start > 0) + write_label_piece (dates->start, buffer, 1024, NULL, NULL); + + if (dates->end > 0 && dates->start > 0) + write_label_piece (dates->end, buffer, 1024, _(" to "), NULL); + + if (dates->complete > 0) { + if (dates->start > 0) + write_label_piece (dates->complete, buffer, 1024, _(" (Completed "), ")"); + else + write_label_piece (dates->complete, buffer, 1024, _(" Completed "), NULL); + } + + if (dates->due > 0 && dates->complete == 0) { + if (dates->start > 0) + write_label_piece (dates->due, buffer, 1024, _(" (Due "), ")"); + else + write_label_piece (dates->due, buffer, 1024, _("Due "), NULL); + } + + gtk_label_set_text (GTK_LABEL (label), buffer); +} diff --git a/calendar/gui/dialogs/comp-editor-util.h b/calendar/gui/dialogs/comp-editor-util.h new file mode 100644 index 0000000000..ad27ab06ca --- /dev/null +++ b/calendar/gui/dialogs/comp-editor-util.h @@ -0,0 +1,31 @@ +/* Evolution calendar - Widget utilities + * + * Copyright (C) 2000 Helix Code, Inc. + * + * Author: 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 _COMP_EDITOR_UTIL_H_ +#define _COMP_EDITOR_UTIL_H_ + +#include <gtk/gtkwidget.h> +#include "comp-editor-page.h" + +void comp_editor_dates (CompEditorPageDates *date, CalComponent *comp); +void comp_editor_date_label (CompEditorPageDates *dates, GtkWidget *label); + +#endif diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index f101bfa15a..ddf9f9a9ae 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -23,12 +23,21 @@ #include <config.h> #endif +#include <gnome.h> +#include <gal/widgets/e-unicode.h> +#include "save-comp.h" #include "comp-editor.h" /* Private part of the CompEditor structure */ struct _CompEditorPrivate { + /* Client to use */ + CalClient *client; + + /* Calendar object/uid we are editing; this is an internal copy */ + CalComponent *comp; + /* The pages we have */ GList *pages; @@ -37,6 +46,8 @@ struct _CompEditorPrivate { /* Notebook to hold the pages */ GtkNotebook *notebook; + + gboolean changed; }; @@ -45,6 +56,15 @@ static void comp_editor_class_init (CompEditorClass *class); static void comp_editor_init (CompEditor *editor); static void comp_editor_destroy (GtkObject *object); +static void page_summary_changed_cb (GtkWidget *widget, const char *summary, gpointer data); +static void page_dates_changed_cb (GtkWidget *widget, CompEditorPageDates *dates, gpointer data); +static void page_changed_cb (GtkWidget *widget, gpointer data); + +static void save_clicked_cb (GtkWidget *widget, gpointer data); +static void close_clicked_cb (GtkWidget *widget, gpointer data); +static void help_clicked_cb (GtkWidget *widget, gpointer data); +static gint delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data); + static GtkObjectClass *parent_class; @@ -52,21 +72,22 @@ static GtkObjectClass *parent_class; GtkType comp_editor_get_type (void) { - static GtkType comp_editor_type; + static GtkType comp_editor_type = 0; if (!comp_editor_type) { - static const GtkTypeInfo comp_editor_info = { + GtkTypeInfo comp_editor_info = { "CompEditor", sizeof (CompEditor), sizeof (CompEditorClass), (GtkClassInitFunc) comp_editor_class_init, - (GtkObjectInitfunc) comp_editor_init, + (GtkObjectInitFunc) comp_editor_init, NULL, /* reserved_1 */ NULL, /* reserved_2 */ (GtkClassInitFunc) NULL - } + }; - comp_editor_type = gtk_type_unique (GTK_TYPE_OBJECT, &comp_editor_info); + comp_editor_type = gtk_type_unique (GTK_TYPE_OBJECT, + &comp_editor_info); } return comp_editor_type; @@ -110,23 +131,30 @@ setup_widgets (CompEditor *editor) /* Notebook */ priv->notebook = GTK_NOTEBOOK (gtk_notebook_new ()); - gtk_box_pack_start (GTK_BOX (vbox), priv->notebook, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (priv->notebook), + TRUE, TRUE, 0); /* Buttons */ bbox = gtk_hbutton_box_new (); - gtk_hbutton_box_set_layout_default (GTK_HBUTTON_BOX (bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0); pixmap = gnome_stock_pixmap_widget (NULL, GNOME_STOCK_PIXMAP_SAVE); button = gnome_pixmap_button (pixmap, _("Save")); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0); - + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (save_clicked_cb), editor); + button = gnome_stock_button (GNOME_STOCK_BUTTON_CLOSE); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (close_clicked_cb), editor); button = gnome_stock_button (GNOME_STOCK_BUTTON_HELP); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (help_clicked_cb), editor); } /* Object initialization function for the calendar component editor */ @@ -141,6 +169,7 @@ comp_editor_init (CompEditor *editor) setup_widgets (editor); priv->pages = NULL; + priv->changed = FALSE; } /* Destroy handler for the calendar component editor */ @@ -167,8 +196,18 @@ comp_editor_destroy (GtkObject *object) +/** + * comp_editor_append_page: + * @editor: A component editor + * @page: Top level widget of the page + * @label: Label of the page + * + * Appends a page to the editor notebook with the given label + **/ void -comp_editor_append_page (CompEditor *editor, EditorPage *page, const char *label) +comp_editor_append_page (CompEditor *editor, + CompEditorPage *page, + const char *label) { CompEditorPrivate *priv; GtkWidget *page_widget; @@ -177,7 +216,7 @@ comp_editor_append_page (CompEditor *editor, EditorPage *page, const char *label g_return_if_fail (editor != NULL); g_return_if_fail (IS_COMP_EDITOR (editor)); g_return_if_fail (page != NULL); - g_return_if_fail (IS_EDITOR_PAGE (page)); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); g_return_if_fail (label != NULL); priv = editor->priv; @@ -185,11 +224,333 @@ comp_editor_append_page (CompEditor *editor, EditorPage *page, const char *label /* Only allow adding the pages while a component has not been set */ g_return_if_fail (priv->comp == NULL); - page_widget = editor_page_get_widget (page); + page_widget = comp_editor_page_get_widget (page); g_assert (page_widget != NULL); - + label_widget = gtk_label_new (label); priv->pages = g_list_append (priv->pages, page); gtk_notebook_append_page (priv->notebook, page_widget, label_widget); + + /* Listen for things happening on the page */ + gtk_signal_connect (GTK_OBJECT (page), "summary_changed", + GTK_SIGNAL_FUNC (page_summary_changed_cb), editor); + gtk_signal_connect (GTK_OBJECT (page), "dates_changed", + GTK_SIGNAL_FUNC (page_dates_changed_cb), editor); + gtk_signal_connect (GTK_OBJECT (page), "changed", + GTK_SIGNAL_FUNC (page_changed_cb), editor); +} + +/** + * comp_editor_set_cal_client: + * @editor: A component editor + * @client: The calendar client to use + * + * Sets the calendar client used by the editor to update components + **/ +void +comp_editor_set_cal_client (CompEditor *editor, CalClient *client) +{ + CompEditorPrivate *priv; + + g_return_if_fail (editor != NULL); + g_return_if_fail (IS_COMP_EDITOR (editor)); + + priv = editor->priv; + + if (client == priv->client) + return; + + if (client) { + g_return_if_fail (IS_CAL_CLIENT (client)); + g_return_if_fail (cal_client_get_load_state (client) == + CAL_CLIENT_LOAD_LOADED); + gtk_object_ref (GTK_OBJECT (client)); + } + + if (priv->client) { + gtk_signal_disconnect_by_data (GTK_OBJECT (priv->client), + editor); + gtk_object_unref (GTK_OBJECT (priv->client)); + } + + priv->client = client; +} + +/** + * comp_editor_get_cal_client: + * @editor: A component editor + * + * Returns the calendar client of the editor + * + * Return value: The calendar client of the editor + **/ +CalClient * +comp_editor_get_cal_client (CompEditor *editor) +{ + CompEditorPrivate *priv; + + g_return_val_if_fail (editor != NULL, NULL); + g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL); + + priv = editor->priv; + + return priv->client; +} + +/* Creates an appropriate title for the event editor dialog */ +static char * +make_title_from_comp (CalComponent *comp) +{ + char *title; + const char *type_string; + CalComponentVType type; + CalComponentText text; + + if (!comp) + return g_strdup (_("Edit Appointment")); + + type = cal_component_get_vtype (comp); + switch (type) { + case CAL_COMPONENT_EVENT: + type_string = _("Appointment - %s"); + break; + case CAL_COMPONENT_TODO: + type_string = _("Task - %s"); + break; + case CAL_COMPONENT_JOURNAL: + type_string = _("Journal entry - %s"); + break; + default: + g_message ("make_title_from_comp(): Cannot handle object of type %d", type); + return NULL; + } + + cal_component_get_summary (comp, &text); + if (text.value) { + char *summary; + summary = e_utf8_to_locale_string (text.value); + title = g_strdup_printf (type_string, summary); + g_free (summary); + } else + title = g_strdup_printf (type_string, _("No summary")); + + return title; +} + +/* Sets the event editor's window title from a calendar component */ +static void +set_title_from_comp (CompEditor *editor) +{ + CompEditorPrivate *priv; + char *title; + + priv = editor->priv; + title = make_title_from_comp (priv->comp); + gtk_window_set_title (GTK_WINDOW (priv->window), title); + g_free (title); +} + +static void +fill_widgets (CompEditor *editor) +{ + CompEditorPrivate *priv; + GList *l; + + priv = editor->priv; + + for (l = priv->pages; l != NULL; l = l->next) + comp_editor_page_fill_widgets (l->data, priv->comp); +} + +/** + * comp_editor_edit_comp: + * @editor: A component editor + * @comp: A calendar component + * + * Starts the editor editing the given component + **/ +void +comp_editor_edit_comp (CompEditor *editor, CalComponent *comp) +{ + CompEditorPrivate *priv; + + g_return_if_fail (editor != NULL); + g_return_if_fail (IS_COMP_EDITOR (editor)); + + priv = editor->priv; + + if (priv->comp) { + gtk_object_unref (GTK_OBJECT (priv->comp)); + priv->comp = NULL; + } + + if (comp) + priv->comp = cal_component_clone (comp); + + set_title_from_comp (editor); + fill_widgets (editor); +} + + +/* Brings attention to a window by raising it and giving it focus */ +static void +raise_and_focus (GtkWidget *widget) +{ + g_assert (GTK_WIDGET_REALIZED (widget)); + gdk_window_show (widget->window); + gtk_widget_grab_focus (widget); +} + +/** + * comp_editor_focus: + * @editor: A component editor + * + * Brings the editor window to the front and gives it focus + **/ +void +comp_editor_focus (CompEditor *editor) +{ + CompEditorPrivate *priv; + + g_return_if_fail (editor != NULL); + g_return_if_fail (IS_COMP_EDITOR (editor)); + + priv = editor->priv; + + gtk_widget_show_all (priv->window); + raise_and_focus (priv->window); +} + +static void +save_comp (CompEditor *editor) +{ + CompEditorPrivate *priv; + GList *l; + + priv = editor->priv; + + for (l = priv->pages; l != NULL; l = l->next) + comp_editor_page_fill_component (l->data, priv->comp); + + if (!cal_client_update_object (priv->client, priv->comp)) + g_message ("save_comp (): Could not update the object!"); + else + priv->changed = FALSE; +} + +static gboolean +prompt_to_save_changes (CompEditor *editor) +{ + CompEditorPrivate *priv; + + priv = editor->priv; + + if (!priv->changed) + return TRUE; + + switch (save_component_dialog (GTK_WINDOW (priv->window))) { + case 0: /* Save */ + /* FIXME: If an error occurs here, we should popup a dialog + and then return FALSE. */ + save_comp (editor); + return TRUE; + case 1: /* Discard */ + return TRUE; + case 2: /* Cancel */ + default: + return FALSE; + break; + } +} + +/* Closes the dialog box and emits the appropriate signals */ +static void +close_dialog (CompEditor *editor) +{ + CompEditorPrivate *priv; + + priv = editor->priv; + + g_assert (priv->window != NULL); + + gtk_object_destroy (GTK_OBJECT (editor)); +} + +static void +save_clicked_cb (GtkWidget *widget, gpointer data) +{ + CompEditor *editor = COMP_EDITOR (data); + + save_comp (editor); + close_dialog (editor); +} + +static void +close_clicked_cb (GtkWidget *widget, gpointer data) +{ + CompEditor *editor = COMP_EDITOR (data); + + if (prompt_to_save_changes (editor)) + close_dialog (editor); +} + +static void +help_clicked_cb (GtkWidget *widget, gpointer data) +{ +} + +static void +page_summary_changed_cb (GtkWidget *widget, const char *summary, gpointer data) +{ + CompEditor *editor = COMP_EDITOR (data); + CompEditorPrivate *priv; + GList *l; + + priv = editor->priv; + + for (l = priv->pages; l != NULL; l = l->next) + comp_editor_page_set_summary (l->data, summary); + + priv->changed = TRUE; +} + +static void +page_dates_changed_cb (GtkWidget *widget, + CompEditorPageDates *dates, + gpointer data) +{ + CompEditor *editor = COMP_EDITOR (data); + CompEditorPrivate *priv; + GList *l; + + priv = editor->priv; + + for (l = priv->pages; l != NULL; l = l->next) + comp_editor_page_set_dates (l->data, dates); + + priv->changed = TRUE; +} + + +static void +page_changed_cb (GtkWidget *widget, gpointer data) +{ + CompEditor *editor = COMP_EDITOR (data); + CompEditorPrivate *priv; + + priv = editor->priv; + + priv->changed = TRUE; +} + +static gint +delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + CompEditor *editor = COMP_EDITOR (data); + + if (prompt_to_save_changes (editor)) + close_dialog (editor); + + return TRUE; } diff --git a/calendar/gui/dialogs/comp-editor.h b/calendar/gui/dialogs/comp-editor.h index 2362c1d012..225abeac3c 100644 --- a/calendar/gui/dialogs/comp-editor.h +++ b/calendar/gui/dialogs/comp-editor.h @@ -22,7 +22,9 @@ #ifndef COMP_EDITOR_H #define COMP_EDITOR_H -#include "editor-page.h" +#include <gtk/gtk.h> +#include "cal-client.h" +#include "comp-editor-page.h" BEGIN_GNOME_DECLS @@ -30,8 +32,7 @@ BEGIN_GNOME_DECLS #define TYPE_COMP_EDITOR (comp_editor_get_type ()) #define COMP_EDITOR(obj) (GTK_CHECK_CAST ((obj), TYPE_COMP_EDITOR, CompEditor)) -#define COMP_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_COMP_EDITOR, \ - CompEditorClass)) +#define COMP_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_COMP_EDITOR, CompEditorClass)) #define IS_COMP_EDITOR(obj) (GTK_CHECK_TYPE ((obj), TYPE_COMP_EDITOR)) #define IS_COMP_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), TYPE_COMP_EDITOR)) @@ -48,11 +49,17 @@ typedef struct { GtkObjectClass parent_class; } CompEditorClass; -GtkType comp_editor_get_type (void); - -CompEditor *comp_editor_new (void); - -void comp_editor_add_page (CompEditor *editor, EditorPage *page); +GtkType comp_editor_get_type (void); +CompEditor *comp_editor_new (void); +void comp_editor_append_page (CompEditor *editor, + CompEditorPage *page, + const char *label); +void comp_editor_set_cal_client (CompEditor *editor, + CalClient *client); +CalClient * comp_editor_get_cal_client (CompEditor *editor); +void comp_editor_edit_comp (CompEditor *ee, + CalComponent *comp); +void comp_editor_focus (CompEditor *editor); diff --git a/calendar/gui/dialogs/editor-page.c b/calendar/gui/dialogs/editor-page.c deleted file mode 100644 index 5aad3aa01e..0000000000 --- a/calendar/gui/dialogs/editor-page.c +++ /dev/null @@ -1,260 +0,0 @@ -/* 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_dates = 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_dates: - * @page: An editor page. - * @start: Start date for calendar component. - * @end: End date for calendar component. - * - * Sets the calendar component DTSTART and DTEND in an editor page. - **/ -void -editor_page_set_dates (EditorPage *page, time_t start, time_t end) -{ - 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_dates != NULL); - (* CLASS (page)->set_dates) (page, start, end); -} - -/** - * 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 deleted file mode 100644 index 48e688ae16..0000000000 --- a/calendar/gui/dialogs/editor-page.h +++ /dev/null @@ -1,86 +0,0 @@ -/* 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_dates) (EditorPage *page, time_t start, time_t end); -} 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_dates (EditorPage *page, time_t start, time_t end); - -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-editor.c b/calendar/gui/dialogs/event-editor.c new file mode 100644 index 0000000000..b53efe12aa --- /dev/null +++ b/calendar/gui/dialogs/event-editor.c @@ -0,0 +1,155 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Evolution calendar - Event editor dialog + * + * Copyright (C) 2000 Helix Code, Inc. + * Copyright (C) 2001 Ximian, Inc. + * + * Authors: Miguel de Icaza <miguel@ximian.com> + * Federico Mena-Quintero <federico@ximian.com> + * Seth Alves <alves@hungry.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include <string.h> +#include <glade/glade.h> +#include <gal/widgets/e-unicode.h> +#include <libgnome/gnome-i18n.h> +#include <widgets/misc/e-dateedit.h> + +#include "event-page.h" +#include "alarm-page.h" +#include "recurrence-page.h" +#include "event-editor.h" + +struct _EventEditorPrivate { + EventPage *event_page; + AlarmPage *alarm_page; + RecurrencePage *recur_page; +}; + + + +static void event_editor_class_init (EventEditorClass *class); +static void event_editor_init (EventEditor *ee); +static void event_editor_destroy (GtkObject *object); + +static CompEditor *parent_class; + + + +/** + * event_editor_get_type: + * + * Registers the #EventEditor class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #EventEditor class. + **/ +GtkType +event_editor_get_type (void) +{ + static GtkType event_editor_type = 0; + + if (!event_editor_type) { + static const GtkTypeInfo event_editor_info = { + "EventEditor", + sizeof (EventEditor), + sizeof (EventEditorClass), + (GtkClassInitFunc) event_editor_class_init, + (GtkObjectInitFunc) event_editor_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + event_editor_type = gtk_type_unique (TYPE_COMP_EDITOR, + &event_editor_info); + } + + return event_editor_type; +} + +/* Class initialization function for the event editor */ +static void +event_editor_class_init (EventEditorClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass *) class; + + parent_class = gtk_type_class (TYPE_COMP_EDITOR); + + object_class->destroy = event_editor_destroy; +} + +/* Object initialization function for the event editor */ +static void +event_editor_init (EventEditor *ee) +{ + EventEditorPrivate *priv; + + priv = g_new0 (EventEditorPrivate, 1); + ee->priv = priv; + + priv->event_page = event_page_new (); + comp_editor_append_page (COMP_EDITOR (ee), + COMP_EDITOR_PAGE (priv->event_page), + _("Appointment")); + + priv->alarm_page = alarm_page_new (); + comp_editor_append_page (COMP_EDITOR (ee), + COMP_EDITOR_PAGE (priv->alarm_page), + _("Reminder")); + + priv->recur_page = recurrence_page_new (); + comp_editor_append_page (COMP_EDITOR (ee), + COMP_EDITOR_PAGE (priv->recur_page), + _("Recurrence")); + +} + +/* Destroy handler for the event editor */ +static void +event_editor_destroy (GtkObject *object) +{ + EventEditor *ee; + EventEditorPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_EVENT_EDITOR (object)); + + ee = EVENT_EDITOR (object); + priv = ee->priv; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/** + * event_editor_new: + * + * Creates a new event editor dialog. + * + * Return value: A newly-created event editor dialog, or NULL if the event + * editor could not be created. + **/ +EventEditor * +event_editor_new (void) +{ + return EVENT_EDITOR (gtk_type_new (TYPE_EVENT_EDITOR)); +} diff --git a/calendar/gui/event-editor.h b/calendar/gui/dialogs/event-editor.h index 60be54c784..6f05b1cf46 100644 --- a/calendar/gui/event-editor.h +++ b/calendar/gui/dialogs/event-editor.h @@ -22,19 +22,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __EVENT_EDITOR_DIALOG_H__ -#define __EVENT_EDITOR_DIALOG_H__ +#ifndef __EVENT_EDITOR_H__ +#define __EVENT_EDITOR_H__ #include <libgnome/gnome-defs.h> #include <gtk/gtkobject.h> -#include "gnome-cal.h" +#include "comp-editor.h" #define TYPE_EVENT_EDITOR (event_editor_get_type ()) #define EVENT_EDITOR(obj) (GTK_CHECK_CAST ((obj), TYPE_EVENT_EDITOR, EventEditor)) -#define EVENT_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_EVENT_EDITOR, \ - EventEditorClass)) +#define EVENT_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_EVENT_EDITOR, EventEditorClass)) #define IS_EVENT_EDITOR(obj) (GTK_CHECK_TYPE ((obj), TYPE_EVENT_EDITOR)) #define IS_EVENT_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), TYPE_EVENT_EDITOR)) @@ -43,35 +42,21 @@ typedef struct _EventEditorClass EventEditorClass; typedef struct _EventEditorPrivate EventEditorPrivate; struct _EventEditor { - GtkObject object; + CompEditor parent; /* Private data */ EventEditorPrivate *priv; }; struct _EventEditorClass { - GtkObjectClass parent_class; + CompEditorClass parent_class; }; - -GtkType event_editor_get_type (void); -EventEditor *event_editor_construct (EventEditor *ee); - -EventEditor *event_editor_new (void); - -void event_editor_set_cal_client (EventEditor *ee, CalClient *client); -CalClient *event_editor_get_cal_client (EventEditor *ee); - -void event_editor_set_event_object (EventEditor *ee, CalComponent *comp); - -void event_editor_focus (EventEditor *ee); - -void event_editor_update_widgets (EventEditor *ee); - - -GtkWidget *make_date_edit (void); -GtkWidget *make_spin_button (int val, int low, int high); +GtkType event_editor_get_type (void); +EventEditor *event_editor_construct (EventEditor *ee); +EventEditor *event_editor_new (void); +void event_editor_update_widgets (EventEditor *ee); -#endif /* __EVENT_EDITOR_DIALOG_H__ */ +#endif /* __EVENT_EDITOR_H__ */ diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c index 940ccf815c..8ade431f36 100644 --- a/calendar/gui/dialogs/event-page.c +++ b/calendar/gui/dialogs/event-page.c @@ -31,9 +31,10 @@ #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 "cal-util/timeutil.h" +#include "../widget-util.h" #include "../calendar-config.h" #include "event-page.h" @@ -65,6 +66,8 @@ struct _EventPagePrivate { GtkWidget *categories_btn; GtkWidget *categories; + + gboolean updating; }; @@ -73,22 +76,15 @@ 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_dates (EditorPage *page, time_t start, time_t end); - -/* Signal IDs */ -enum { - DATES_CHANGED, - LAST_SIGNAL -}; +static GtkWidget *event_page_get_widget (CompEditorPage *page); +static void event_page_fill_widgets (CompEditorPage *page, CalComponent *comp); +static void event_page_fill_component (CompEditorPage *page, CalComponent *comp); +static void event_page_set_summary (CompEditorPage *page, const char *summary); +static void event_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates); -static guint event_page_signals[LAST_SIGNAL] = { 0 }; +GtkWidget *make_date_edit (void); -static EditorPageClass *parent_class = NULL; +static CompEditorPageClass *parent_class = NULL; @@ -117,7 +113,8 @@ event_page_get_type (void) (GtkClassInitFunc) NULL }; - event_page_type = gtk_type_unique (TYPE_EDITOR_PAGE, &event_page_info); + event_page_type = gtk_type_unique (TYPE_COMP_EDITOR_PAGE, + &event_page_info); } return event_page_type; @@ -127,31 +124,18 @@ event_page_get_type (void) static void event_page_class_init (EventPageClass *class) { - EditorPageClass *editor_page_class; + CompEditorPageClass *editor_page_class; GtkObjectClass *object_class; - editor_page_class = (EditorPageClass *) class; + editor_page_class = (CompEditorPageClass *) 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; + parent_class = gtk_type_class (TYPE_COMP_EDITOR_PAGE); 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_dates = event_page_set_dates; object_class->destroy = event_page_destroy; @@ -181,6 +165,8 @@ event_page_init (EventPage *epage) priv->contacts = NULL; priv->categories_btn = NULL; priv->categories = NULL; + + priv->updating = FALSE; } /* Destroy handler for the event page */ @@ -219,7 +205,7 @@ static const int classification_map[] = { /* get_widget handler for the event page */ static GtkWidget * -event_page_get_widget (EditorPage *page) +event_page_get_widget (CompEditorPage *page) { EventPage *epage; EventPagePrivate *priv; @@ -230,8 +216,8 @@ event_page_get_widget (EditorPage *page) return priv->main; } -/* Checks if the event's time starts and ends at midnight, and sets the "all day - * event" box accordingly. +/* 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) @@ -251,12 +237,15 @@ check_all_day (EventPage *epage) g_assert (ev_end != -1); /* all day event checkbox */ - if (time_day_begin (ev_start) == ev_start && time_day_begin (ev_end) == ev_end) + 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); + 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); + 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); @@ -278,14 +267,17 @@ clear_widgets (EventPage *epage) 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->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); + 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); @@ -299,7 +291,7 @@ clear_widgets (EventPage *epage) /* fill_widgets handler for the event page */ static void -event_page_fill_widgets (EditorPage *page, CalComponent *comp) +event_page_fill_widgets (CompEditorPage *page, CalComponent *comp) { EventPage *epage; EventPagePrivate *priv; @@ -313,6 +305,10 @@ event_page_fill_widgets (EditorPage *page, CalComponent *comp) epage = EVENT_PAGE (page); priv = epage->priv; + /* Don't send off changes during this time */ + priv->updating = TRUE; + + /* Clean the page */ clear_widgets (epage); /* Summary, description(s) */ @@ -341,17 +337,21 @@ event_page_fill_widgets (EditorPage *page, CalComponent *comp) dtend = icaltime_as_timet (*d.value); cal_component_free_datetime (&d); - if (time_day_begin (dtstart) == dtstart && time_day_begin (dtend) == dtend) + 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->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); + 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); @@ -361,17 +361,20 @@ event_page_fill_widgets (EditorPage *page, CalComponent *comp) switch (cl) { case CAL_COMPONENT_CLASS_PUBLIC: - e_dialog_radio_set (priv->classification_public, 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, + 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, + e_dialog_radio_set (priv->classification_public, + CAL_COMPONENT_CLASS_CONFIDENTIAL, classification_map); break; @@ -382,14 +385,15 @@ event_page_fill_widgets (EditorPage *page, CalComponent *comp) } /* Categories */ - cal_component_get_categories (comp, &categories); e_dialog_editable_set (priv->categories, categories); + + priv->updating = FALSE; } /* fill_component handler for the event page */ static void -event_page_fill_component (EditorPage *page, CalComponent *comp) +event_page_fill_component (CompEditorPage *page, CalComponent *comp) { EventPage *epage; EventPagePrivate *priv; @@ -477,13 +481,14 @@ event_page_fill_component (EditorPage *page, CalComponent *comp) /* Classification */ - classif = e_dialog_radio_get (priv->classification_public, classification_map); + 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) +event_page_set_summary (CompEditorPage *page, const char *summary) { EventPage *epage; EventPagePrivate *priv; @@ -496,24 +501,8 @@ event_page_set_summary (EditorPage *page, const char *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_dates handler for the event page. We do nothing since we are *the* - * only provider of the date values. - */ static void -event_page_set_dates (EditorPage *page, time_t start, time_t end) +event_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) { /* nothing */ } @@ -525,22 +514,17 @@ 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; - + g_assert (priv->main); gtk_widget_ref (priv->main); gtk_widget_unparent (priv->main); - gtk_widget_destroy (toplevel); - priv->summary = GW ("summary"); + priv->summary = GW ("general-summary"); priv->start_time = GW ("start-time"); priv->end_time = GW ("end-time"); @@ -579,9 +563,19 @@ static void summary_changed_cb (GtkEditable *editable, gpointer data) { EventPage *epage; + EventPagePrivate *priv; + gchar *summary; epage = EVENT_PAGE (data); - editor_page_notify_summary_changed (EDITOR_PAGE (epage)); + priv = epage->priv; + + if (priv->updating) + return; + + summary = gtk_editable_get_chars (editable, 0, -1); + comp_editor_page_notify_summary_changed (COMP_EDITOR_PAGE (epage), + summary); + g_free (summary); } /* Callback used when the start or end date widgets change. We check that the @@ -594,12 +588,15 @@ date_changed_cb (EDateEdit *dedit, gpointer data) EventPagePrivate *priv; time_t start, end; struct tm tm_start, tm_end; - + CompEditorPageDates dates; + epage = EVENT_PAGE (data); priv = epage->priv; - /* Ensure that start < end */ + if (priv->updating) + return; + /* 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)); @@ -611,10 +608,10 @@ date_changed_cb (EDateEdit *dedit, gpointer data) 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. + /* 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 */ @@ -627,7 +624,8 @@ date_changed_cb (EDateEdit *dedit, gpointer data) 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)); + end = mktime (&tm_end); + e_date_edit_set_time (E_DATE_EDIT (priv->end_time), 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 */ @@ -640,7 +638,8 @@ date_changed_cb (EDateEdit *dedit, gpointer data) 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)); + start = mktime (&tm_start); + e_date_edit_set_time (E_DATE_EDIT (priv->start_time), start); gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); } else g_assert_not_reached (); @@ -650,7 +649,12 @@ date_changed_cb (EDateEdit *dedit, gpointer data) check_all_day (epage); /* Notify upstream */ - gtk_signal_emit (GTK_OBJECT (epage), event_page_signals[DATES_CHANGED]); + dates.start = start; + dates.end = end; + dates.due = 0; + dates.complete = 0; + comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (epage), + &dates); } /* Callback: all day event button toggled. @@ -666,19 +670,21 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data) struct tm start_tm, end_tm; time_t start_t, end_t; gboolean all_day; - + CompEditorPageDates dates; + 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 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 @@ -737,20 +743,30 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data) } } - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); + 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)); + start_t = mktime (&start_tm); + end_t = mktime (&end_tm); + e_date_edit_set_time (E_DATE_EDIT (priv->start_time), start_t); + e_date_edit_set_time (E_DATE_EDIT (priv->end_time), end_t); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), epage); + 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]); + dates.start = start_t; + dates.end = end_t; + dates.due = 0; + comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (epage), + &dates); } /* Callback used when the categories button is clicked; we must bring up the @@ -792,9 +808,13 @@ static void field_changed_cb (GtkWidget *widget, gpointer data) { EventPage *epage; - + EventPagePrivate *priv; + epage = EVENT_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (epage)); + priv = epage->priv; + + if (!priv->updating) + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (epage)); } /* Hooks the widget signals */ @@ -836,12 +856,15 @@ init_widgets (EventPage *epage) 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->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); @@ -869,14 +892,17 @@ event_page_construct (EventPage *epage) priv = epage->priv; - priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/event-page.glade", NULL); + 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!"); + 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!"); + g_message ("event_page_construct(): " + "Could not find all widgets in the XML file!"); return NULL; } @@ -907,27 +933,8 @@ event_page_new (void) return epage; } -/** - * event_page_get_dates: - * @page: An event page. - * @start: Return value for the start date, can be NULL. - * @end: Return value for the end date, can be NULL. - * - * Queries the start and end dates for the calendar component in an event page. - **/ -void -event_page_get_dates (EventPage *page, time_t *start, time_t *end) +GtkWidget * +make_date_edit (void) { - EventPagePrivate *priv; - - g_return_if_fail (page != NULL); - g_return_if_fail (IS_EVENT_PAGE (page)); - - priv = page->priv; - - if (start) - *start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - - if (end) - *end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); + return date_edit_new (TRUE, TRUE); } diff --git a/calendar/gui/dialogs/event-page.glade b/calendar/gui/dialogs/event-page.glade index 76d2d4043e..e9b774fe41 100644 --- a/calendar/gui/dialogs/event-page.glade +++ b/calendar/gui/dialogs/event-page.glade @@ -18,6 +18,7 @@ <widget> <class>GtkWindow</class> <name>event-toplevel</name> + <visible>False</visible> <title>window1</title> <type>GTK_WINDOW_TOPLEVEL</type> <position>GTK_WIN_POS_NONE</position> @@ -349,7 +350,6 @@ <class>GtkButton</class> <name>contacts-button</name> <can_focus>True</can_focus> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> @@ -388,7 +388,6 @@ <class>GtkButton</class> <name>categories-button</name> <can_focus>True</can_focus> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> diff --git a/calendar/gui/dialogs/event-page.h b/calendar/gui/dialogs/event-page.h index 04b01a0333..232455e491 100644 --- a/calendar/gui/dialogs/event-page.h +++ b/calendar/gui/dialogs/event-page.h @@ -25,7 +25,7 @@ #ifndef EVENT_PAGE_H #define EVENT_PAGE_H -#include "editor-page.h" +#include "comp-editor-page.h" BEGIN_GNOME_DECLS @@ -33,35 +33,27 @@ 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 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; + CompEditorPage page; /* Private data */ EventPagePrivate *priv; } EventPage; typedef struct { - EditorPageClass parent_class; - - /* Notification signals */ - - void (* dates_changed) (EventPage *epage); + CompEditorPageClass parent_class; } EventPageClass; -GtkType event_page_get_type (void); +GtkType event_page_get_type (void); EventPage *event_page_construct (EventPage *epage); - -EventPage *event_page_new (void); - -void event_page_get_dates (EventPage *epage, time_t *start, time_t *end); +EventPage *event_page_new (void); diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c index 363ca94cc5..4d690be6dc 100644 --- a/calendar/gui/dialogs/recurrence-page.c +++ b/calendar/gui/dialogs/recurrence-page.c @@ -39,6 +39,7 @@ #include "../tag-calendar.h" #include "../weekday-picker.h" #include "../widget-util.h" +#include "comp-editor-util.h" #include "recurrence-page.h" @@ -102,6 +103,9 @@ static const int ending_types_map[] = { /* Private part of the RecurrencePage structure */ struct _RecurrencePagePrivate { + /* Component we use to expand the recurrence rules for the preview */ + CalComponent *comp; + /* Glade XML data */ GladeXML *xml; @@ -110,7 +114,7 @@ struct _RecurrencePagePrivate { GtkWidget *main; GtkWidget *summary; - GtkWidget *starting_date; + GtkWidget *date_time; GtkWidget *none; GtkWidget *simple; @@ -157,8 +161,7 @@ struct _RecurrencePagePrivate { /* For the recurrence preview, the actual widget */ GtkWidget *preview_calendar; - /* Component we use to expand the recurrence rules for the preview calendar */ - CalComponent *comp; + gboolean updating; }; @@ -167,14 +170,15 @@ static void recurrence_page_class_init (RecurrencePageClass *class); static void recurrence_page_init (RecurrencePage *rpage); static void recurrence_page_destroy (GtkObject *object); -static GtkWidget *recurrence_page_get_widget (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_dates (EditorPage *page, time_t start, time_t end); +static GtkWidget *recurrence_page_get_widget (CompEditorPage *page); +static void recurrence_page_fill_widgets (CompEditorPage *page, CalComponent *comp); +static void recurrence_page_fill_component (CompEditorPage *page, CalComponent *comp); +static void recurrence_page_set_summary (CompEditorPage *page, const char *summary); +static void recurrence_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates); -static EditorPageClass *parent_class = NULL; +static void field_changed (RecurrencePage *apage); + +static CompEditorPageClass *parent_class = NULL; @@ -203,7 +207,8 @@ recurrence_page_get_type (void) (GtkClassInitFunc) NULL }; - recurrence_page_type = gtk_type_unique (TYPE_EDITOR_PAGE, &recurrence_page_info); + recurrence_page_type = gtk_type_unique (TYPE_COMP_EDITOR_PAGE, + &recurrence_page_info); } return recurrence_page_type; @@ -213,19 +218,18 @@ recurrence_page_get_type (void) static void recurrence_page_class_init (RecurrencePageClass *class) { - EditorPageClass *editor_page_class; + CompEditorPageClass *editor_page_class; GtkObjectClass *object_class; - editor_page_class = (EditorPageClass *) class; + editor_page_class = (CompEditorPageClass *) class; object_class = (GtkObjectClass *) class; - parent_class = gtk_type_class (TYPE_EDITOR_PAGE); + parent_class = gtk_type_class (TYPE_COMP_EDITOR_PAGE); 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_dates = recurrence_page_set_dates; object_class->destroy = recurrence_page_destroy; @@ -244,7 +248,7 @@ recurrence_page_init (RecurrencePage *rpage) priv->main = NULL; priv->summary = NULL; - priv->starting_date = NULL; + priv->date_time = NULL; priv->none = NULL; priv->simple = NULL; priv->custom = NULL; @@ -276,22 +280,23 @@ 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; + if (priv->exception_list) { + GtkCList *clist = GTK_CLIST (priv->exception_list); - data = gtk_clist_get_row_data (clist, i); - g_free (data); - gtk_clist_set_row_data (clist, i, NULL); + 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); } - - gtk_clist_clear (clist); } /* Destroy handler for the recurrence page */ @@ -325,7 +330,7 @@ recurrence_page_destroy (GtkObject *object) /* get_widget handler for the recurrence page */ static GtkWidget * -recurrence_page_get_widget (EditorPage *page) +recurrence_page_get_widget (CompEditorPage *page) { RecurrencePage *rpage; RecurrencePagePrivate *priv; @@ -366,7 +371,9 @@ clear_widgets (RecurrencePage *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); + 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); @@ -374,7 +381,9 @@ clear_widgets (RecurrencePage *rpage) 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); + 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 */ @@ -455,8 +464,8 @@ fill_exception_widgets (RecurrencePage *rpage, CalComponent *comp) 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. +/* 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) @@ -533,9 +542,11 @@ sensitize_recur_widgets (RecurrencePage *rpage) gtk_widget_set_sensitive (priv->params, FALSE); gtk_widget_hide (priv->params); - label = gtk_label_new (_("This appointment contains recurrences that Evolution " + label = gtk_label_new (_("This appointment contains " + "recurrences that Evolution " "cannot edit.")); - gtk_container_add (GTK_CONTAINER (priv->custom_warning_bin), label); + gtk_container_add (GTK_CONTAINER (priv->custom_warning_bin), + label); gtk_widget_show_all (priv->custom_warning_bin); break; @@ -574,7 +585,8 @@ simple_recur_to_comp (RecurrencePage *rpage, CalComponent *comp) r.freq = e_dialog_option_menu_get (priv->interval_unit, freq_map); r.interval = e_dialog_spin_get_int (priv->interval_value); - r.week_start = ICAL_SUNDAY_WEEKDAY + calendar_config_get_week_start_day (); + r.week_start = ICAL_SUNDAY_WEEKDAY + + calendar_config_get_week_start_day (); /* Frequency-specific data */ @@ -639,31 +651,38 @@ simple_recur_to_comp (RecurrencePage *rpage, CalComponent *comp) break; case MONTH_DAY_MON: - r.by_day[0] = nth_weekday (day_index, ICAL_MONDAY_WEEKDAY); + r.by_day[0] = nth_weekday (day_index, + ICAL_MONDAY_WEEKDAY); break; case MONTH_DAY_TUE: - r.by_day[0] = nth_weekday (day_index, ICAL_TUESDAY_WEEKDAY); + r.by_day[0] = nth_weekday (day_index, + ICAL_TUESDAY_WEEKDAY); break; case MONTH_DAY_WED: - r.by_day[0] = nth_weekday (day_index, ICAL_WEDNESDAY_WEEKDAY); + r.by_day[0] = nth_weekday (day_index, + ICAL_WEDNESDAY_WEEKDAY); break; case MONTH_DAY_THU: - r.by_day[0] = nth_weekday (day_index, ICAL_THURSDAY_WEEKDAY); + r.by_day[0] = nth_weekday (day_index, + ICAL_THURSDAY_WEEKDAY); break; case MONTH_DAY_FRI: - r.by_day[0] = nth_weekday (day_index, ICAL_FRIDAY_WEEKDAY); + r.by_day[0] = nth_weekday (day_index, + ICAL_FRIDAY_WEEKDAY); break; case MONTH_DAY_SAT: - r.by_day[0] = nth_weekday (day_index, ICAL_SATURDAY_WEEKDAY); + r.by_day[0] = nth_weekday (day_index, + ICAL_SATURDAY_WEEKDAY); break; case MONTH_DAY_SUN: - r.by_day[0] = nth_weekday (day_index, ICAL_SUNDAY_WEEKDAY); + r.by_day[0] = nth_weekday (day_index, + ICAL_SUNDAY_WEEKDAY); break; default: @@ -683,7 +702,8 @@ simple_recur_to_comp (RecurrencePage *rpage, CalComponent *comp) /* Ending date */ - ending_type = e_dialog_option_menu_get (priv->ending_menu, ending_types_map); + ending_type = e_dialog_option_menu_get (priv->ending_menu, + ending_types_map); switch (ending_type) { case ENDING_FOR: @@ -842,7 +862,7 @@ weekday_picker_changed_cb (WeekdayPicker *wp, gpointer data) rpage = RECURRENCE_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); preview_recur (rpage); } @@ -882,7 +902,8 @@ make_weekly_special (RecurrencePage *rpage) weekday_picker_set_blocked_days (wp, priv->weekday_blocked_day_mask); gtk_signal_connect (GTK_OBJECT (wp), "changed", - GTK_SIGNAL_FUNC (weekday_picker_changed_cb), rpage); + GTK_SIGNAL_FUNC (weekday_picker_changed_cb), + rpage); } /* Creates the option menu for the monthly recurrence days */ @@ -938,7 +959,8 @@ adjust_day_index_spin (RecurrencePage *rpage) g_assert (priv->month_index_spin != NULL); g_assert (GTK_IS_SPIN_BUTTON (priv->month_index_spin)); - month_day = e_dialog_option_menu_get (priv->month_day_menu, month_day_options_map); + month_day = e_dialog_option_menu_get (priv->month_day_menu, + month_day_options_map); adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->month_index_spin)); @@ -970,9 +992,9 @@ adjust_day_index_spin (RecurrencePage *rpage) } } -/* Callback used when the monthly day selection menu changes. We need to change - * the valid range of the day index spin button; e.g. days are 1-31 while a - * Sunday is the 1st through 5th. +/* Callback used when the monthly day selection menu changes. We need + * to change the valid range of the day index spin button; e.g. days + * are 1-31 while a Sunday is the 1st through 5th. */ static void month_day_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) @@ -982,7 +1004,7 @@ month_day_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) rpage = RECURRENCE_PAGE (data); adjust_day_index_spin (rpage); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); preview_recur (rpage); } @@ -994,7 +1016,7 @@ month_index_value_changed_cb (GtkAdjustment *adj, gpointer data) rpage = RECURRENCE_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); preview_recur (rpage); } @@ -1024,13 +1046,15 @@ make_monthly_special (RecurrencePage *rpage) adj = GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 31, 1, 10, 10)); priv->month_index_spin = gtk_spin_button_new (adj, 1, 0); - gtk_box_pack_start (GTK_BOX (hbox), priv->month_index_spin, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), priv->month_index_spin, + FALSE, FALSE, 0); label = gtk_label_new (_("th")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); priv->month_day_menu = make_recur_month_menu (); - gtk_box_pack_start (GTK_BOX (hbox), priv->month_day_menu, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), priv->month_day_menu, + FALSE, FALSE, 0); gtk_widget_show_all (hbox); @@ -1043,11 +1067,13 @@ make_monthly_special (RecurrencePage *rpage) adjust_day_index_spin (rpage); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (month_index_value_changed_cb), rpage); + GTK_SIGNAL_FUNC (month_index_value_changed_cb), + rpage); menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->month_day_menu)); gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (month_day_menu_selection_done_cb), rpage); + GTK_SIGNAL_FUNC (month_day_menu_selection_done_cb), + rpage); } /* Changes the recurrence-special widget to match the interval units. @@ -1099,7 +1125,7 @@ make_recurrence_special (RecurrencePage *rpage) } } -/* Counts the number of elements in the by_xxx fields of an icalrecurrencetype */ +/* Counts the elements in the by_xxx fields of an icalrecurrencetype */ static int count_by_xxx (short *field, int max_elements) { @@ -1119,7 +1145,7 @@ ending_until_changed_cb (EDateEdit *de, gpointer data) RecurrencePage *rpage; rpage = RECURRENCE_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); preview_recur (rpage); } @@ -1140,7 +1166,8 @@ make_ending_until_special (RecurrencePage *rpage) priv->ending_date_edit = date_edit_new (TRUE, FALSE); de = E_DATE_EDIT (priv->ending_date_edit); - gtk_container_add (GTK_CONTAINER (priv->ending_special), GTK_WIDGET (de)); + gtk_container_add (GTK_CONTAINER (priv->ending_special), + GTK_WIDGET (de)); gtk_widget_show_all (GTK_WIDGET (de)); /* Set the value */ @@ -1158,7 +1185,7 @@ ending_count_value_changed_cb (GtkAdjustment *adj, gpointer data) RecurrencePage *rpage; rpage = RECURRENCE_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); preview_recur (rpage); } @@ -1183,7 +1210,8 @@ make_ending_count_special (RecurrencePage *rpage) adj = GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 10000, 1, 10, 10)); priv->ending_count_spin = gtk_spin_button_new (adj, 1, 0); - gtk_box_pack_start (GTK_BOX (hbox), priv->ending_count_spin, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), priv->ending_count_spin, + FALSE, FALSE, 0); label = gtk_label_new (_("occurrences")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); @@ -1195,10 +1223,11 @@ make_ending_count_special (RecurrencePage *rpage) e_dialog_spin_set (priv->ending_count_spin, priv->ending_count); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (ending_count_value_changed_cb), rpage); + GTK_SIGNAL_FUNC (ending_count_value_changed_cb), + rpage); } -/* Changes the recurrence-ending-special widget to match the ending date option. +/* Changes the recurrence-ending-special widget to match the ending date option * * For: <n> [days, weeks, months, years, occurrences] * Until: <date selector> @@ -1219,7 +1248,8 @@ make_ending_special (RecurrencePage *rpage) priv->ending_count_spin = NULL; } - ending_type = e_dialog_option_menu_get (priv->ending_menu, ending_types_map); + ending_type = e_dialog_option_menu_get (priv->ending_menu, + ending_types_map); switch (ending_type) { case ENDING_FOR: @@ -1290,10 +1320,12 @@ fill_ending_date (RecurrencePage *rpage, struct icalrecurrencetype *r) * no rdates or exrules (exdates are handled just fine elsewhere). */ static void -recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) +recurrence_page_fill_widgets (CompEditorPage *page, CalComponent *comp) { RecurrencePage *rpage; RecurrencePagePrivate *priv; + CalComponentText text; + CompEditorPageDates dates; GSList *rrule_list; int len; struct icalrecurrencetype *r; @@ -1306,8 +1338,8 @@ recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) rpage = RECURRENCE_PAGE (page); priv = rpage->priv; - /* Keep a copy of the component so that we can expand the recurrence set - * for the preview. + /* Keep a copy of the component so that we can expand the recurrence + * set for the preview. */ if (priv->comp) @@ -1315,10 +1347,21 @@ recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) priv->comp = cal_component_clone (comp); - /* Clean the page */ + /* Don't send off changes during this time */ + priv->updating = TRUE; + /* Clean the page */ clear_widgets (rpage); + /* Summary */ + cal_component_get_summary (comp, &text); + recurrence_page_set_summary (page, text.value); + + /* Dates */ + comp_editor_dates (&dates, comp); + recurrence_page_set_dates (page, &dates); + + /* Exceptions */ fill_exception_widgets (rpage, comp); /* Set up defaults for the special widgets */ @@ -1329,13 +1372,19 @@ recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) 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); + 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_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); @@ -1400,7 +1449,9 @@ recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) 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); + e_dialog_option_menu_set (priv->interval_unit, + ICAL_DAILY_RECURRENCE, + freq_map); gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); break; @@ -1465,7 +1516,9 @@ recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) 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); + e_dialog_option_menu_set (priv->interval_unit, + ICAL_WEEKLY_RECURRENCE, + freq_map); gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); break; } @@ -1537,7 +1590,9 @@ recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) 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); + e_dialog_option_menu_set (priv->interval_unit, + ICAL_MONTHLY_RECURRENCE, + freq_map); gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); break; @@ -1552,7 +1607,9 @@ recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) 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); + e_dialog_option_menu_set (priv->interval_unit, + ICAL_YEARLY_RECURRENCE, + freq_map); gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); break; @@ -1601,11 +1658,13 @@ recurrence_page_fill_widgets (EditorPage *page, CalComponent *comp) cal_component_free_recur_list (rrule_list); preview_recur (rpage); + + priv->updating = FALSE; } /* fill_component handler for the recurrence page */ static void -recurrence_page_fill_component (EditorPage *page, CalComponent *comp) +recurrence_page_fill_component (CompEditorPage *page, CalComponent *comp) { RecurrencePage *rpage; @@ -1615,52 +1674,33 @@ recurrence_page_fill_component (EditorPage *page, CalComponent *comp) /* set_summary handler for the recurrence page */ static void -recurrence_page_set_summary (EditorPage *page, const char *summary) +recurrence_page_set_summary (CompEditorPage *page, const char *summary) { RecurrencePage *rpage; RecurrencePagePrivate *priv; - + gchar *s; + rpage = RECURRENCE_PAGE (page); priv = rpage->priv; - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->summary), rpage); - e_utf8_gtk_entry_set_text (GTK_ENTRY (priv->summary), summary); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->summary), rpage); -} - -/* get_summary handler for the recurrence page */ -static char * -recurrence_page_get_summary (EditorPage *page) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - - rpage = RECURRENCE_PAGE (page); - priv = rpage->priv; - - return e_utf8_gtk_entry_get_text (GTK_ENTRY (priv->summary)); + s = e_utf8_to_gtk_string (priv->summary, summary); + gtk_label_set_text (GTK_LABEL (priv->summary), s); + g_free (s); } /* set_dates handler for the recurrence page */ static void -recurrence_page_set_dates (EditorPage *page, time_t start, time_t end) +recurrence_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) { RecurrencePage *rpage; RecurrencePagePrivate *priv; - char str[128]; - struct tm tm; CalComponentDateTime dt; struct icaltimetype icaltime; rpage = RECURRENCE_PAGE (page); priv = rpage->priv; - /* Set the starting date label */ - - tm = *localtime (&start); - strftime (str, sizeof (str), _("%A %b %d %Y %H:%M:%S"), &tm); - - gtk_label_set_text (GTK_LABEL (priv->starting_date), str); + comp_editor_date_label (dates, priv->date_time); /* Copy the dates to our component */ @@ -1670,11 +1710,13 @@ recurrence_page_set_dates (EditorPage *page, time_t start, time_t end) dt.value = &icaltime; dt.tzid = NULL; - *dt.value = icaltime_from_timet (start, FALSE); + *dt.value = icaltime_from_timet (dates->start, FALSE); cal_component_set_dtstart (priv->comp, &dt); - *dt.value = icaltime_from_timet (end, FALSE); - cal_component_set_dtend (priv->comp, &dt); + if (dates->end != 0) { + *dt.value = icaltime_from_timet (dates->end, FALSE); + cal_component_set_dtend (priv->comp, &dt); + } } @@ -1684,23 +1726,18 @@ 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 FALSE; - + g_assert (priv->main); 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->date_time = GW ("date-time"); priv->none = GW ("none"); priv->simple = GW ("simple"); @@ -1723,9 +1760,9 @@ get_widgets (RecurrencePage *rpage) priv->preview_bin = GW ("preview-bin"); #undef GW - + return (priv->summary - && priv->starting_date + && priv->date_time && priv->none && priv->simple && priv->custom @@ -1744,16 +1781,6 @@ get_widgets (RecurrencePage *rpage) && priv->preview_bin); } -/* Callback used when the summary changes; we emit the notification signal. */ -static void -summary_changed_cb (GtkEditable *editable, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - editor_page_notify_summary_changed (EDITOR_PAGE (rpage)); -} - /* Callback used when the displayed date range in the recurrence preview * calendar changes. */ @@ -1776,7 +1803,7 @@ type_toggled_cb (GtkToggleButton *toggle, gpointer data) rpage = RECURRENCE_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); if (toggle->active) { sensitize_recur_widgets (rpage); @@ -1792,7 +1819,7 @@ interval_value_changed_cb (GtkAdjustment *adj, gpointer data) rpage = RECURRENCE_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); preview_recur (rpage); } @@ -1806,7 +1833,7 @@ interval_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) rpage = RECURRENCE_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); make_recurrence_special (rpage); preview_recur (rpage); } @@ -1821,7 +1848,7 @@ ending_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) rpage = RECURRENCE_PAGE (data); - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); make_ending_special (rpage); preview_recur (rpage); } @@ -1837,7 +1864,7 @@ exception_add_cb (GtkWidget *widget, gpointer data) rpage = RECURRENCE_PAGE (data); priv = rpage->priv; - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); t = e_date_edit_get_time (E_DATE_EDIT (priv->exception_date)); append_exception (rpage, t); @@ -1861,7 +1888,7 @@ exception_modify_cb (GtkWidget *widget, gpointer data) if (!clist->selection) return; - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); sel = GPOINTER_TO_INT (clist->selection->data); @@ -1890,7 +1917,7 @@ exception_delete_cb (GtkWidget *widget, gpointer data) if (!clist->selection) return; - editor_page_notify_changed (EDITOR_PAGE (rpage)); + field_changed (rpage); sel = GPOINTER_TO_INT (clist->selection->data); @@ -1912,11 +1939,13 @@ exception_delete_cb (GtkWidget *widget, gpointer data) preview_recur (rpage); } -/* Callback used when a row is selected in the list of exception dates. We must - * update the date/time widgets to reflect the exception's value. +/* Callback used when a row is selected in the list of exception + * dates. We must update the date/time widgets to reflect the + * exception's value. */ static void -exception_select_row_cb (GtkCList *clist, gint row, gint col, GdkEvent *event, gpointer data) +exception_select_row_cb (GtkCList *clist, gint row, gint col, + GdkEvent *event, gpointer data) { RecurrencePage *rpage; RecurrencePagePrivate *priv; @@ -1931,6 +1960,18 @@ exception_select_row_cb (GtkCList *clist, gint row, gint col, GdkEvent *event, g e_date_edit_set_time (E_DATE_EDIT (priv->exception_date), *t); } +/* This is called when any field is changed; it notifies upstream. */ +static void +field_changed (RecurrencePage *rpage) +{ + RecurrencePagePrivate *priv; + + priv = rpage->priv; + + if (!priv->updating) + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (rpage)); +} + /* Hooks the widget signals */ static void init_widgets (RecurrencePage *rpage) @@ -1942,19 +1983,17 @@ init_widgets (RecurrencePage *rpage) priv = rpage->priv; - /* Summary */ - gtk_signal_connect (GTK_OBJECT (priv->summary), "changed", - GTK_SIGNAL_FUNC (summary_changed_cb), rpage); - /* Recurrence preview */ priv->preview_calendar = e_calendar_new (); ecal = E_CALENDAR (priv->preview_calendar); gtk_signal_connect (GTK_OBJECT (ecal->calitem), "date_range_changed", - GTK_SIGNAL_FUNC (preview_date_range_changed_cb), rpage); + GTK_SIGNAL_FUNC (preview_date_range_changed_cb), + rpage); calendar_config_configure_e_calendar (ecal); e_calendar_item_set_max_days_sel (ecal->calitem, 0); - gtk_container_add (GTK_CONTAINER (priv->preview_bin), priv->preview_calendar); + gtk_container_add (GTK_CONTAINER (priv->preview_bin), + priv->preview_calendar); gtk_widget_show (priv->preview_calendar); /* Recurrence types */ @@ -1970,13 +2009,15 @@ init_widgets (RecurrencePage *rpage) adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->interval_value)); gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (interval_value_changed_cb), rpage); + GTK_SIGNAL_FUNC (interval_value_changed_cb), + rpage); /* Recurrence units */ menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->interval_unit)); gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (interval_selection_done_cb), rpage); + GTK_SIGNAL_FUNC (interval_selection_done_cb), + rpage); /* Recurrence ending */ @@ -2017,14 +2058,17 @@ recurrence_page_construct (RecurrencePage *rpage) priv = rpage->priv; - priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/recurrence-page.glade", NULL); + priv->xml = glade_xml_new (EVOLUTION_GLADEDIR + "/recurrence-page.glade", NULL); if (!priv->xml) { - g_message ("recurrence_page_construct(): Could not load the Glade XML file!"); + g_message ("recurrence_page_construct(): " + "Could not load the Glade XML file!"); return NULL; } if (!get_widgets (rpage)) { - g_message ("recurrence_page_construct(): Could not find all widgets in the XML file!"); + g_message ("recurrence_page_construct(): " + "Could not find all widgets in the XML file!"); return NULL; } diff --git a/calendar/gui/dialogs/recurrence-page.glade b/calendar/gui/dialogs/recurrence-page.glade index b84a3c288c..1793e175d7 100644 --- a/calendar/gui/dialogs/recurrence-page.glade +++ b/calendar/gui/dialogs/recurrence-page.glade @@ -18,6 +18,7 @@ <widget> <class>GtkWindow</class> <name>recurrence-toplevel</name> + <visible>False</visible> <title>window1</title> <type>GTK_WINDOW_TOPLEVEL</type> <position>GTK_WIN_POS_NONE</position> @@ -36,7 +37,7 @@ <widget> <class>GtkFrame</class> <name>frame35</name> - <label>Appointment Basics</label> + <label>Basics</label> <label_xalign>0</label_xalign> <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> <child> @@ -58,14 +59,13 @@ <widget> <class>GtkLabel</class> <name>label66</name> - <label>Su_mmary:</label> + <label>Summary:</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> @@ -85,7 +85,7 @@ <widget> <class>GtkLabel</class> <name>label67</name> - <label>_Starting date:</label> + <label>Date/Time:</label> <justify>GTK_JUSTIFY_CENTER</justify> <wrap>False</wrap> <xalign>0</xalign> @@ -109,13 +109,15 @@ </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> + <class>GtkLabel</class> + <name>summary</name> + <label></label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>4</xpad> + <ypad>0</ypad> <child> <left_attach>1</left_attach> <right_attach>2</right_attach> @@ -123,9 +125,9 @@ <bottom_attach>1</bottom_attach> <xpad>0</xpad> <ypad>0</ypad> - <xexpand>True</xexpand> + <xexpand>False</xexpand> <yexpand>False</yexpand> - <xshrink>True</xshrink> + <xshrink>False</xshrink> <yshrink>False</yshrink> <xfill>True</xfill> <yfill>False</yfill> @@ -133,12 +135,15 @@ </widget> <widget> - <class>GtkAlignment</class> - <name>alignment40</name> + <class>GtkLabel</class> + <name>date-time</name> + <label></label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> <xalign>0</xalign> <yalign>0.5</yalign> - <xscale>0</xscale> - <yscale>0</yscale> + <xpad>4</xpad> + <ypad>0</ypad> <child> <left_attach>1</left_attach> <right_attach>2</right_attach> @@ -151,17 +156,8 @@ <xshrink>False</xshrink> <yshrink>False</yshrink> <xfill>True</xfill> - <yfill>True</yfill> + <yfill>False</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> @@ -209,7 +205,7 @@ <widget> <class>GtkRadioButton</class> - <name>recurrence-none</name> + <name>none</name> <can_focus>True</can_focus> <label>No recurrence</label> <active>False</active> @@ -224,7 +220,7 @@ <widget> <class>GtkRadioButton</class> - <name>recurrence-simple</name> + <name>simple</name> <can_focus>True</can_focus> <label>Simple recurrence</label> <active>False</active> @@ -239,7 +235,7 @@ <widget> <class>GtkRadioButton</class> - <name>recurrence-custom</name> + <name>custom</name> <can_focus>True</can_focus> <label>Custom recurrence</label> <active>False</active> @@ -266,7 +262,7 @@ <widget> <class>GtkHBox</class> - <name>recurrence-params</name> + <name>params</name> <homogeneous>False</homogeneous> <spacing>2</spacing> <child> @@ -294,7 +290,7 @@ <widget> <class>GtkSpinButton</class> - <name>recurrence-interval-value</name> + <name>interval-value</name> <can_focus>True</can_focus> <climb_rate>1</climb_rate> <digits>0</digits> @@ -317,7 +313,7 @@ <widget> <class>GtkOptionMenu</class> - <name>recurrence-interval-unit</name> + <name>interval-unit</name> <can_focus>True</can_focus> <items>day(s) week(s) @@ -334,7 +330,7 @@ year(s) <widget> <class>GtkAlignment</class> - <name>recurrence-special</name> + <name>special</name> <xalign>0.5</xalign> <yalign>0.5</yalign> <xscale>0</xscale> @@ -352,7 +348,7 @@ year(s) <widget> <class>GtkOptionMenu</class> - <name>recurrence-ending-menu</name> + <name>ending-menu</name> <can_focus>True</can_focus> <items>for until @@ -368,7 +364,7 @@ forever <widget> <class>GtkAlignment</class> - <name>recurrence-ending-special</name> + <name>ending-special</name> <xalign>0.5</xalign> <yalign>0.5</yalign> <xscale>0</xscale> @@ -387,7 +383,7 @@ forever <widget> <class>GtkAlignment</class> - <name>recurrence-custom-warning-bin</name> + <name>custom-warning-bin</name> <xalign>0</xalign> <yalign>0.5</yalign> <xscale>1</xscale> @@ -449,10 +445,9 @@ forever <widget> <class>GtkButton</class> - <name>recurrence-exception-add</name> + <name>exception-add</name> <can_focus>True</can_focus> <label>Add</label> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> @@ -462,10 +457,9 @@ forever <widget> <class>GtkButton</class> - <name>recurrence-exception-modify</name> + <name>exception-modify</name> <can_focus>True</can_focus> <label>Modify</label> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> @@ -475,10 +469,9 @@ forever <widget> <class>GtkButton</class> - <name>recurrence-exception-delete</name> + <name>exception-delete</name> <can_focus>True</can_focus> <label>Delete</label> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> @@ -500,7 +493,7 @@ forever <widget> <class>Custom</class> - <name>recurrence-exception-date</name> + <name>exception-date</name> <creation_function>make_date_edit</creation_function> <int1>0</int1> <int2>0</int2> @@ -527,7 +520,7 @@ forever <widget> <class>GtkCList</class> - <name>recurrence-exception-list</name> + <name>exception-list</name> <can_focus>True</can_focus> <columns>1</columns> <column_widths>80</column_widths> @@ -583,7 +576,7 @@ forever <widget> <class>GtkAlignment</class> - <name>recurrence-preview-bin</name> + <name>preview-bin</name> <xalign>0</xalign> <yalign>0</yalign> <xscale>1</xscale> diff --git a/calendar/gui/dialogs/recurrence-page.h b/calendar/gui/dialogs/recurrence-page.h index 39123644b4..aba59003f7 100644 --- a/calendar/gui/dialogs/recurrence-page.h +++ b/calendar/gui/dialogs/recurrence-page.h @@ -25,7 +25,7 @@ #ifndef RECURRENCE_PAGE_H #define RECURRENCE_PAGE_H -#include "editor-page.h" +#include "comp-editor-page.h" BEGIN_GNOME_DECLS @@ -33,29 +33,27 @@ 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 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; + CompEditorPage page; /* Private data */ RecurrencePagePrivate *priv; } RecurrencePage; typedef struct { - EditorPageClass parent_class; + CompEditorPageClass parent_class; } RecurrencePageClass; -GtkType recurrence_page_get_type (void); +GtkType recurrence_page_get_type (void); RecurrencePage *recurrence_page_construct (RecurrencePage *rpage); - -RecurrencePage *recurrence_page_new (void); +RecurrencePage *recurrence_page_new (void); diff --git a/calendar/gui/dialogs/task-details-page.c b/calendar/gui/dialogs/task-details-page.c new file mode 100644 index 0000000000..317f36dbe6 --- /dev/null +++ b/calendar/gui/dialogs/task-details-page.c @@ -0,0 +1,461 @@ +/* Evolution calendar - Main page of the task 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 <widgets/misc/e-dateedit.h> +#include "e-util/e-dialog-widgets.h" +#include "../widget-util.h" +#include "comp-editor-util.h" +#include "task-details-page.h" + + + +/* Private part of the TaskDetailsPage structure */ +struct _TaskDetailsPagePrivate { + /* Glade XML data */ + GladeXML *xml; + + /* Widgets from the Glade file */ + GtkWidget *main; + + GtkWidget *summary; + GtkWidget *date_time; + + GtkWidget *completed_date; + GtkWidget *url; + + gboolean updating; +}; + + + +static void task_details_page_class_init (TaskDetailsPageClass *class); +static void task_details_page_init (TaskDetailsPage *tdpage); +static void task_details_page_destroy (GtkObject *object); + +static GtkWidget *task_details_page_get_widget (CompEditorPage *page); +static void task_details_page_fill_widgets (CompEditorPage *page, CalComponent *comp); +static void task_details_page_fill_component (CompEditorPage *page, CalComponent *comp); +static void task_details_page_set_summary (CompEditorPage *page, const char *summary); +static void task_details_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates); + +static CompEditorPageClass *parent_class = NULL; + + + +/** + * task_details_page_get_type: + * + * Registers the #TaskDetailsPage class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #TaskDetailsPage class. + **/ +GtkType +task_details_page_get_type (void) +{ + static GtkType task_details_page_type; + + if (!task_details_page_type) { + static const GtkTypeInfo task_details_page_info = { + "TaskDetailsPage", + sizeof (TaskDetailsPage), + sizeof (TaskDetailsPageClass), + (GtkClassInitFunc) task_details_page_class_init, + (GtkObjectInitFunc) task_details_page_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + task_details_page_type = + gtk_type_unique (TYPE_COMP_EDITOR_PAGE, + &task_details_page_info); + } + + return task_details_page_type; +} + +/* Class initialization function for the task page */ +static void +task_details_page_class_init (TaskDetailsPageClass *class) +{ + CompEditorPageClass *editor_page_class; + GtkObjectClass *object_class; + + editor_page_class = (CompEditorPageClass *) class; + object_class = (GtkObjectClass *) class; + + parent_class = gtk_type_class (TYPE_COMP_EDITOR_PAGE); + + editor_page_class->get_widget = task_details_page_get_widget; + editor_page_class->fill_widgets = task_details_page_fill_widgets; + editor_page_class->fill_component = task_details_page_fill_component; + editor_page_class->set_summary = task_details_page_set_summary; + editor_page_class->set_dates = task_details_page_set_dates; + + object_class->destroy = task_details_page_destroy; +} + +/* Object initialization function for the task page */ +static void +task_details_page_init (TaskDetailsPage *tdpage) +{ + TaskDetailsPagePrivate *priv; + + priv = g_new0 (TaskDetailsPagePrivate, 1); + tdpage->priv = priv; + + priv->xml = NULL; + + priv->main = NULL; + priv->summary = NULL; + priv->date_time = NULL; + priv->completed_date = NULL; + priv->url = NULL; + + priv->updating = FALSE; +} + +/* Destroy handler for the task page */ +static void +task_details_page_destroy (GtkObject *object) +{ + TaskDetailsPage *tdpage; + TaskDetailsPagePrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_TASK_DETAILS_PAGE (object)); + + tdpage = TASK_DETAILS_PAGE (object); + priv = tdpage->priv; + + if (priv->xml) { + gtk_object_unref (GTK_OBJECT (priv->xml)); + priv->xml = NULL; + } + + g_free (priv); + tdpage->priv = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + + + +/* get_widget handler for the task page */ +static GtkWidget * +task_details_page_get_widget (CompEditorPage *page) +{ + TaskDetailsPage *tdpage; + TaskDetailsPagePrivate *priv; + + tdpage = TASK_DETAILS_PAGE (page); + priv = tdpage->priv; + + return priv->main; +} + +/* Fills the widgets with default values */ +static void +clear_widgets (TaskDetailsPage *tdpage) +{ + TaskDetailsPagePrivate *priv; + + priv = tdpage->priv; + + /* Summary */ + gtk_label_set_text (GTK_LABEL (priv->summary), ""); + + /* Start date */ + gtk_label_set_text (GTK_LABEL (priv->date_time), ""); + + /* Date completed */ + e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), -1); + + /* URL */ + e_dialog_editable_set (priv->url, NULL); +} + +/* fill_widgets handler for the task page */ +static void +task_details_page_fill_widgets (CompEditorPage *page, CalComponent *comp) +{ + TaskDetailsPage *tdpage; + TaskDetailsPagePrivate *priv; + CalComponentText text; + const char *url; + CompEditorPageDates dates; + + tdpage = TASK_DETAILS_PAGE (page); + priv = tdpage->priv; + + priv->updating = TRUE; + + /* Clean the screen */ + clear_widgets (tdpage); + + /* Summary */ + cal_component_get_summary (comp, &text); + task_details_page_set_summary (page, text.value); + + /* Dates */ + comp_editor_dates (&dates, comp); + task_details_page_set_dates (page, &dates); + + /* URL */ + cal_component_get_url (comp, &url); + e_dialog_editable_set (priv->url, url); + + priv->updating = FALSE; +} + +/* fill_component handler for the task page */ +static void +task_details_page_fill_component (CompEditorPage *page, CalComponent *comp) +{ + TaskDetailsPage *tdpage; + TaskDetailsPagePrivate *priv; + CalComponentDateTime date; + time_t t; + char *url; + + tdpage = TASK_DETAILS_PAGE (page); + priv = tdpage->priv; + + /* Completed Date. */ + date.value = g_new (struct icaltimetype, 1); + date.tzid = NULL; + + t = e_date_edit_get_time (E_DATE_EDIT (priv->completed_date)); + if (t != -1) { + *date.value = icaltime_from_timet (t, FALSE); + cal_component_set_completed (comp, date.value); + } else { + cal_component_set_completed (comp, NULL); + } + + g_free (date.value); + + /* URL. */ + url = e_dialog_editable_get (priv->url); + cal_component_set_url (comp, url); + if (url) + g_free (url); +} + +/* set_summary handler for the task page */ +static void +task_details_page_set_summary (CompEditorPage *page, const char *summary) +{ + TaskDetailsPage *tdpage; + TaskDetailsPagePrivate *priv; + gchar *s; + + tdpage = TASK_DETAILS_PAGE (page); + priv = tdpage->priv; + + s = e_utf8_to_gtk_string (priv->summary, summary); + gtk_label_set_text (GTK_LABEL (priv->summary), s); + g_free (s); +} + +static void +task_details_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) +{ + TaskDetailsPage *tdpage; + TaskDetailsPagePrivate *priv; + + tdpage = TASK_DETAILS_PAGE (page); + priv = tdpage->priv; + + comp_editor_date_label (dates, priv->date_time); +} + + + +/* Gets the widgets from the XML file and returns if they are all available. */ +static gboolean +get_widgets (TaskDetailsPage *tdpage) +{ + TaskDetailsPagePrivate *priv; + + priv = tdpage->priv; + +#define GW(name) glade_xml_get_widget (priv->xml, name) + + priv->main = GW ("task-details-page"); + g_assert (priv->main); + gtk_widget_ref (priv->main); + gtk_widget_unparent (priv->main); + + priv->summary = GW ("summary"); + priv->date_time = GW ("date-time"); + + priv->completed_date = GW ("completed-date"); + priv->url = GW ("url"); + +#undef GW + + return (priv->summary + && priv->date_time + && priv->completed_date + && priv->url); +} + +/* Callback used when the start or end date widgets change. We check that the + * start date < end date and we set the "all day task" button as appropriate. + */ +static void +date_changed_cb (EDateEdit *dedit, gpointer data) +{ + TaskDetailsPage *tdpage; + TaskDetailsPagePrivate *priv; + CompEditorPageDates dates; + + tdpage = TASK_DETAILS_PAGE (data); + priv = tdpage->priv; + + if (priv->updating) + return; + + dates.start = 0; + dates.end = 0; + dates.due = 0; + dates.complete = e_date_edit_get_time (E_DATE_EDIT (priv->completed_date)); + + /* Notify upstream */ + comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (tdpage), &dates); +} + +/* This is called when any field is changed; it notifies upstream. */ +static void +field_changed_cb (GtkWidget *widget, gpointer data) +{ + TaskDetailsPage *tdpage; + TaskDetailsPagePrivate *priv; + + tdpage = TASK_DETAILS_PAGE (data); + priv = tdpage->priv; + + if (!priv->updating) + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (tdpage)); +} + +/* Hooks the widget signals */ +static void +init_widgets (TaskDetailsPage *tdpage) +{ + TaskDetailsPagePrivate *priv; + + priv = tdpage->priv; + + /* Completed Date */ + gtk_signal_connect (GTK_OBJECT (priv->completed_date), "changed", + GTK_SIGNAL_FUNC (date_changed_cb), tdpage); + + /* URL */ + gtk_signal_connect (GTK_OBJECT (priv->url), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), tdpage); +} + + + +/** + * task_details_page_construct: + * @tdpage: An task details page. + * + * Constructs an task page by loading its Glade data. + * + * Return value: The same object as @tdpage, or NULL if the widgets could not + * be created. + **/ +TaskDetailsPage * +task_details_page_construct (TaskDetailsPage *tdpage) +{ + TaskDetailsPagePrivate *priv; + + priv = tdpage->priv; + + priv->xml = glade_xml_new (EVOLUTION_GLADEDIR + "/task-details-page.glade", NULL); + if (!priv->xml) { + g_message ("task_details_page_construct(): " + "Could not load the Glade XML file!"); + return NULL; + } + + if (!get_widgets (tdpage)) { + g_message ("task_details_page_construct(): " + "Could not find all widgets in the XML file!"); + return NULL; + } + + init_widgets (tdpage); + + return tdpage; +} + +/** + * task_details_page_new: + * + * Creates a new task details page. + * + * Return value: A newly-created task details page, or NULL if the page could + * not be created. + **/ +TaskDetailsPage * +task_details_page_new (void) +{ + TaskDetailsPage *tdpage; + + tdpage = gtk_type_new (TYPE_TASK_DETAILS_PAGE); + if (!task_details_page_construct (tdpage)) { + gtk_object_unref (GTK_OBJECT (tdpage)); + return NULL; + } + + return tdpage; +} + +GtkWidget *task_details_page_create_date_edit (void); + +GtkWidget * +task_details_page_create_date_edit (void) +{ + GtkWidget *dedit; + + dedit = date_edit_new (TRUE, TRUE); + e_date_edit_set_allow_no_date_set (E_DATE_EDIT (dedit), TRUE); + + return dedit; +} diff --git a/calendar/gui/dialogs/task-details-page.glade b/calendar/gui/dialogs/task-details-page.glade index 31e3aba6c4..9d13387d59 100644 --- a/calendar/gui/dialogs/task-details-page.glade +++ b/calendar/gui/dialogs/task-details-page.glade @@ -15,6 +15,7 @@ <widget> <class>GtkWindow</class> <name>task-details-toplevel</name> + <visible>False</visible> <title>window1</title> <type>GTK_WINDOW_TOPLEVEL</type> <position>GTK_WIN_POS_NONE</position> @@ -24,112 +25,253 @@ <auto_shrink>False</auto_shrink> <widget> - <class>GtkTable</class> + <class>GtkVBox</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> + <spacing>4</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> + <class>GtkFrame</class> + <name>frame1</name> + <label>Basics</label> + <label_xalign>0</label_xalign> + <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type> <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> + <class>GtkTable</class> + <name>table1</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>label15</name> + <label>Summary:</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>False</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkLabel</class> + <name>label16</name> + <label>Date/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>False</xfill> + <yfill>False</yfill> + </child> + </widget> + + <widget> + <class>GtkLabel</class> + <name>date-time</name> + <label></label> + <justify>GTK_JUSTIFY_CENTER</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>4</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>False</yfill> + </child> + </widget> + + <widget> + <class>GtkLabel</class> + <name>summary</name> + <label></label> + <justify>GTK_JUSTIFY_LEFT</justify> + <wrap>False</wrap> + <xalign>0</xalign> + <yalign>0.5</yalign> + <xpad>4</xpad> + <ypad>0</ypad> + <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>False</yexpand> + <xshrink>False</xshrink> + <yshrink>False</yshrink> + <xfill>True</xfill> + <yfill>False</yfill> + </child> + </widget> + </widget> </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> + <class>GtkTable</class> + <name>table1</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> <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> + <padding>0</padding> + <expand>True</expand> + <fill>True</fill> </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> + <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> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> - </widget> + <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>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> + <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> - <xexpand>True</xexpand> - <yexpand>False</yexpand> - <xshrink>False</xshrink> - <yshrink>False</yshrink> - <xfill>True</xfill> - <yfill>False</yfill> - </child> + <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_details_page_create_date_edit</creation_function> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Fri, 01 Jun 2001 18:58:51 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> </widget> diff --git a/calendar/gui/dialogs/task-details-page.h b/calendar/gui/dialogs/task-details-page.h new file mode 100644 index 0000000000..d285eb9cc0 --- /dev/null +++ b/calendar/gui/dialogs/task-details-page.h @@ -0,0 +1,62 @@ +/* Evolution calendar - Main page of the task 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 TASK_DETAILS_PAGE_H +#define TASK_DETAILS_PAGE_H + +#include "comp-editor-page.h" + +BEGIN_GNOME_DECLS + + + +#define TYPE_TASK_DETAILS_PAGE (task_details_page_get_type ()) +#define TASK_DETAILS_PAGE(obj) (GTK_CHECK_CAST ((obj), TYPE_TASK_DETAILS_PAGE, TaskDetailsPage)) +#define TASK_DETAILS_PAGE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_TASK_DETAILS_PAGE, TaskDetailsPageClass)) +#define IS_TASK_DETAILS_PAGE(obj) (GTK_CHECK_TYPE ((obj), TYPE_TASK_DETAILS_PAGE)) +#define IS_TASK_DETAILS_PAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), TYPE_TASK_DETAILS_PAGE)) + +typedef struct _TaskDetailsPagePrivate TaskDetailsPagePrivate; + +typedef struct { + CompEditorPage page; + + /* Private data */ + TaskDetailsPagePrivate *priv; +} TaskDetailsPage; + +typedef struct { + CompEditorPageClass parent_class; +} TaskDetailsPageClass; + + +GtkType task_details_page_get_type (void); +TaskDetailsPage *task_details_page_construct (TaskDetailsPage *epage); +TaskDetailsPage *task_details_page_new (void); + + + +END_GNOME_DECLS + +#endif diff --git a/calendar/gui/dialogs/task-editor-dialog.glade b/calendar/gui/dialogs/task-editor-dialog.glade deleted file mode 100644 index ae7ea9681a..0000000000 --- a/calendar/gui/dialogs/task-editor-dialog.glade +++ /dev/null @@ -1,695 +0,0 @@ -<?xml version="1.0"?> -<GTK-Interface> - -<project> - <name>task-editor-dialog</name> - <program_name>task-editor-dialog</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>GnomePropertyBox</class> - <name>task-editor-dialog</name> - <visible>False</visible> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>False</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> - - <widget> - <class>GtkVBox</class> - <name>vbox1</name> - <border_width>4</border_width> - <homogeneous>False</homogeneous> - <spacing>4</spacing> - - <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> - <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> - <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> - </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> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>True</fill> - </child> - - <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>hbox3</name> - <border_width>4</border_width> - <homogeneous>False</homogeneous> - <spacing>4</spacing> - - <widget> - <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> - - <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> - </child> - </widget> - - <widget> - <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>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>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> - <child> - <padding>0</padding> - <expand>False</expand> - <fill>False</fill> - </child> - </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>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>hbox2</name> - <homogeneous>False</homogeneous> - <spacing>2</spacing> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - - <widget> - <class>GtkButton</class> - <name>contacts-button</name> - <can_focus>True</can_focus> - <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> - <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> - <child> - <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> - <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> - <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> - </widget> - - <widget> - <class>GtkTable</class> - <name>table4</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> - <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> - </widget> -</widget> - -</GTK-Interface> diff --git a/calendar/gui/dialogs/task-editor.c b/calendar/gui/dialogs/task-editor.c index b21de4bd32..2a1f25cfbf 100644 --- a/calendar/gui/dialogs/task-editor.c +++ b/calendar/gui/dialogs/task-editor.c @@ -1,16 +1,18 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Author : - * Damon Chaplin <damon@ximian.com> +/* Evolution calendar - Event editor dialog * - * Copyright 2000, Helix Code, Inc. - * Copyright 2000, Ximian, Inc. + * Copyright (C) 2000 Helix Code, Inc. + * Copyright (C) 2001 Ximian, Inc. * - * 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. + * Authors: Miguel de Icaza <miguel@ximian.com> + * Federico Mena-Quintero <federico@ximian.com> + * Seth Alves <alves@hungry.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,1276 +21,127 @@ * * 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 - */ - -/* - * TaskEditor - a GtkObject which handles a libglade-loaded dialog to edit - * tasks. + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include <config.h> +#include <string.h> #include <glade/glade.h> -#include <libgnome/gnome-defs.h> -#include <libgnome/gnome-i18n.h> -#include <gal/util/e-util.h> #include <gal/widgets/e-unicode.h> -#include <gal/widgets/e-categories.h> -#include <e-util/e-dialog-widgets.h> -#include <widgets/misc/e-dateedit.h> -#include <cal-util/timeutil.h> -#include "delete-comp.h" -#include "save-comp.h" -#include "task-editor.h" -#include "../calendar-config.h" -#include "../widget-util.h" - - -typedef struct { - /* Glade XML data */ - GladeXML *xml; - - /* Client to use */ - CalClient *client; - - /* Calendar component we are editing; this is an internal copy and is - * not one of the read-only objects from the parent calendar. - */ - CalComponent *comp; - - - /* This is TRUE while we are setting the widget values. We just return - from any signal handlers. */ - gboolean ignore_callbacks; - - /* Widgets from the Glade file */ - - GtkWidget *app; - - GtkWidget *summary; - - GtkWidget *due_date; - GtkWidget *start_date; - - GtkWidget *percent_complete; - - GtkWidget *status; - GtkWidget *priority; - - GtkWidget *description; - - GtkWidget *classification_public; - GtkWidget *classification_private; - GtkWidget *classification_confidential; - - GtkWidget *contacts_btn; - GtkWidget *contacts; - - GtkWidget *categories_btn; - GtkWidget *categories; - - GtkWidget *completed_date; - GtkWidget *url; - - /* Call task_editor_set_changed() to set this to TRUE when any field - in the dialog is changed. When the user closes the dialog we will - prompt to save changes. */ - gboolean changed; -} TaskEditorPrivate; - - -/* Note that these two arrays must match. */ -static const int status_map[] = { - ICAL_STATUS_NEEDSACTION, - ICAL_STATUS_INPROCESS, - ICAL_STATUS_COMPLETED, - ICAL_STATUS_CANCELLED, - -1 -}; +#include <libgnome/gnome-i18n.h> -typedef enum { - PRIORITY_HIGH, - PRIORITY_NORMAL, - PRIORITY_LOW, - PRIORITY_UNDEFINED, -} TaskEditorPriority; +#include "task-page.h" +#include "task-details-page.h" +#include "recurrence-page.h" +#include "task-editor.h" -static const int priority_map[] = { - PRIORITY_HIGH, - PRIORITY_NORMAL, - PRIORITY_LOW, - PRIORITY_UNDEFINED, - -1 +struct _TaskEditorPrivate { + TaskPage *task_page; + TaskDetailsPage *task_details_page; }; -static const int classification_map[] = { - CAL_COMPONENT_CLASS_PUBLIC, - CAL_COMPONENT_CLASS_PRIVATE, - CAL_COMPONENT_CLASS_CONFIDENTIAL, - -1 -}; + static void task_editor_class_init (TaskEditorClass *class); -static void task_editor_init (TaskEditor *tedit); -static void tedit_apply_event_cb (GtkWidget *widget, gint page_num, gpointer data); -static gint tedit_close_event_cb (GtkWidget *widget, gpointer data); -static gint tedit_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data); -static void close_dialog (TaskEditor *tedit); -static gboolean get_widgets (TaskEditor *tedit); -static void init_widgets (TaskEditor *tedit); +static void task_editor_init (TaskEditor *te); static void task_editor_destroy (GtkObject *object); -static char * make_title_from_comp (CalComponent *comp); -static void set_title_from_comp (TaskEditor *tedit, CalComponent *comp); -static void clear_widgets (TaskEditor *tedit); -static void fill_widgets (TaskEditor *tedit); - -static void save_todo_object (TaskEditor *tedit); -static void dialog_to_comp_object (TaskEditor *tedit); - -static void obj_updated_cb (CalClient *client, const char *uid, gpointer data); -static void obj_removed_cb (CalClient *client, const char *uid, gpointer data); -static void raise_and_focus (GtkWidget *widget); - -static TaskEditorPriority priority_value_to_index (int priority_value); -static int priority_index_to_value (TaskEditorPriority priority); - -static void completed_changed (EDateEdit *dedit, - TaskEditor *tedit); -static void status_changed (GtkMenu *menu, - TaskEditor *tedit); -static void percent_complete_changed (GtkAdjustment *adj, - TaskEditor *tedit); -static void field_changed (GtkWidget *widget, - TaskEditor *tedit); -static void task_editor_set_changed (TaskEditor *tedit, - gboolean changed); -static gboolean prompt_to_save_changes (TaskEditor *tedit); -static CalComponentClassification classification_get (GtkWidget *widget); -static void categories_clicked (GtkWidget *button, - TaskEditor *editor); - -/* The function libglade calls to create the EDateEdit widgets in the GUI. */ -GtkWidget * task_editor_create_date_edit (void); - -static GtkObjectClass *parent_class; - -E_MAKE_TYPE(task_editor, "TaskEditor", TaskEditor, - task_editor_class_init, task_editor_init, GTK_TYPE_OBJECT) - - -static void -task_editor_class_init (TaskEditorClass *class) -{ - GtkObjectClass *object_class; - - object_class = (GtkObjectClass *) class; - - parent_class = gtk_type_class (GTK_TYPE_OBJECT); - - object_class->destroy = task_editor_destroy; -} - - -static void -task_editor_init (TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - - priv = g_new0 (TaskEditorPrivate, 1); - tedit->priv = priv; - - priv->ignore_callbacks = FALSE; - - task_editor_set_changed (tedit, FALSE); -} - -/** - * task_editor_new: - * @Returns: a new #TaskEditor. - * - * Creates a new #TaskEditor. - **/ -TaskEditor * -task_editor_new (void) -{ - TaskEditor *tedit; +static CompEditor *parent_class; - tedit = TASK_EDITOR (gtk_type_new (task_editor_get_type ())); - return task_editor_construct (tedit); -} + /** - * task_editor_construct: - * @tedit: A #TaskEditor. + * task_editor_get_type: * - * Constructs a task editor by loading its Glade XML file. + * Registers the #TaskEditor class if necessary, and returns the type ID + * associated to it. * - * Return value: The same object as @tedit, or NULL if the widgets could not be - * created. In the latter case, the task editor will automatically be - * destroyed. + * Return value: The type ID of the #TaskEditor class. **/ -TaskEditor * -task_editor_construct (TaskEditor *tedit) +GtkType +task_editor_get_type (void) { - TaskEditorPrivate *priv; + static GtkType task_editor_type = 0; - g_return_val_if_fail (tedit != NULL, NULL); - g_return_val_if_fail (IS_TASK_EDITOR (tedit), NULL); + if (!task_editor_type) { + static const GtkTypeInfo task_editor_info = { + "TaskEditor", + sizeof (TaskEditor), + sizeof (TaskEditorClass), + (GtkClassInitFunc) task_editor_class_init, + (GtkObjectInitFunc) task_editor_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; - priv = tedit->priv; - - /* Load the content widgets */ - - priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/task-editor-dialog.glade", NULL); - if (!priv->xml) { - g_message ("task_editor_construct(): Could not load the Glade XML file!"); - goto error; + task_editor_type = gtk_type_unique (TYPE_COMP_EDITOR, + &task_editor_info); } - if (!get_widgets (tedit)) { - g_message ("task_editor_construct(): Could not find all widgets in the XML file!"); - goto error; - } - - init_widgets (tedit); - - /* Hook to destruction of the dialog */ - gtk_signal_connect (GTK_OBJECT (priv->app), "apply", - GTK_SIGNAL_FUNC (tedit_apply_event_cb), tedit); - gtk_signal_connect (GTK_OBJECT (priv->app), "close", - GTK_SIGNAL_FUNC (tedit_close_event_cb), tedit); - gtk_signal_connect (GTK_OBJECT (priv->app), "delete_event", - GTK_SIGNAL_FUNC (tedit_delete_event_cb), tedit); - - /* Add focus to the summary entry */ - gtk_widget_grab_focus (GTK_WIDGET (priv->summary)); - - - return tedit; - - error: - - gtk_object_unref (GTK_OBJECT (tedit)); - return NULL; -} - - -/* Called by libglade to create our custom EDateEdit widgets. */ -GtkWidget * -task_editor_create_date_edit (void) -{ - GtkWidget *dedit; - - dedit = date_edit_new (TRUE, TRUE); - e_date_edit_set_allow_no_date_set (E_DATE_EDIT (dedit), TRUE); - - return dedit; -} - -/* Callback used when the dialog box is destroyed */ -static void -tedit_apply_event_cb (GtkWidget *widget, gint page_num, gpointer data) -{ - TaskEditor *tedit; - - g_return_if_fail (IS_TASK_EDITOR (data)); - - tedit = TASK_EDITOR (data); - - if (page_num != -1) - return; - - save_todo_object (tedit); -} - -/* Callback used when the dialog box is destroyed */ -static gint -tedit_close_event_cb (GtkWidget *widget, gpointer data) -{ - TaskEditor *tedit; - - g_return_val_if_fail (IS_TASK_EDITOR (data), TRUE); - - tedit = TASK_EDITOR (data); - - if (prompt_to_save_changes (tedit)) - close_dialog (tedit); - - return TRUE; -} - -/* Callback used when the dialog box is destroyed */ -static gint -tedit_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - TaskEditor *tedit; - - g_return_val_if_fail (IS_TASK_EDITOR (data), TRUE); - - tedit = TASK_EDITOR (data); - - if (prompt_to_save_changes (tedit)) - close_dialog (tedit); - - return TRUE; + return task_editor_type; } - -/* Closes the dialog box and emits the appropriate signals */ +/* Class initialization function for the event editor */ static void -close_dialog (TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - - priv = tedit->priv; - - g_assert (priv->app != NULL); - - gtk_object_destroy (GTK_OBJECT (tedit)); -} - - -/* Gets the widgets from the XML file and returns if they are all available. - * For the widgets whose values can be simply set with e-dialog-utils, it does - * that as well. - */ -static gboolean -get_widgets (TaskEditor *tedit) +task_editor_class_init (TaskEditorClass *class) { - TaskEditorPrivate *priv; - - priv = tedit->priv; - -#define GW(name) glade_xml_get_widget (priv->xml, name) - - priv->app = GW ("task-editor-dialog"); - - priv->summary = GW ("summary"); - - priv->due_date = GW ("due-date"); - priv->start_date = GW ("start-date"); - - priv->percent_complete = GW ("percent-complete"); - - priv->status = GW ("status"); - priv->priority = GW ("priority"); - - 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"); + GtkObjectClass *object_class; - priv->completed_date = GW ("completed-date"); - priv->url = GW ("url"); + object_class = (GtkObjectClass *) class; -#undef GW + parent_class = gtk_type_class (TYPE_COMP_EDITOR); - return (priv->app - && priv->summary - && priv->due_date - && priv->start_date - && priv->percent_complete - && priv->status - && priv->priority - && priv->classification_public - && priv->classification_private - && priv->classification_confidential - && priv->description - && priv->contacts_btn - && priv->contacts - && priv->categories_btn - && priv->categories - && priv->completed_date - && priv->url); + object_class->destroy = task_editor_destroy; } - -/* Hooks the widget signals */ +/* Object initialization function for the event editor */ static void -init_widgets (TaskEditor *tedit) +task_editor_init (TaskEditor *te) { TaskEditorPrivate *priv; + + priv = g_new0 (TaskEditorPrivate, 1); + te->priv = priv; - priv = tedit->priv; - - /* Connect signals. The Status, Percent Complete & Date Completed - properties are closely related so whenever one changes we may need - to update the other 2. */ - gtk_signal_connect (GTK_OBJECT (priv->completed_date), "changed", - GTK_SIGNAL_FUNC (completed_changed), tedit); - - gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (priv->status)->menu), - "deactivate", - GTK_SIGNAL_FUNC (status_changed), tedit); - - gtk_signal_connect (GTK_OBJECT (GTK_SPIN_BUTTON (priv->percent_complete)->adjustment), - "value_changed", - GTK_SIGNAL_FUNC (percent_complete_changed), tedit); - - /* Classification */ - gtk_signal_connect (GTK_OBJECT (priv->description), "changed", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->classification_public), - "toggled", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->classification_private), - "toggled", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->classification_confidential), - "toggled", - GTK_SIGNAL_FUNC (field_changed), tedit); - - /* Connect the default signal handler to use to make sure the "changed" - field gets set whenever a field is changed. */ - gtk_signal_connect (GTK_OBJECT (priv->summary), "changed", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->due_date), "changed", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->start_date), "changed", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (priv->priority)->menu), - "deactivate", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->description), "changed", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->contacts), "changed", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->categories), "changed", - GTK_SIGNAL_FUNC (field_changed), tedit); - gtk_signal_connect (GTK_OBJECT (priv->url), "changed", - GTK_SIGNAL_FUNC (field_changed), tedit); - - /* Button clicks */ - gtk_signal_connect (GTK_OBJECT (priv->categories_btn), "clicked", - GTK_SIGNAL_FUNC (categories_clicked), tedit); - - /* FIXME: we do not support these fields yet, so we disable them */ + priv->task_page = task_page_new (); + comp_editor_append_page (COMP_EDITOR (te), + COMP_EDITOR_PAGE (priv->task_page), + _("Task")); - gtk_widget_set_sensitive (priv->contacts_btn, FALSE); - gtk_widget_set_sensitive (priv->contacts, FALSE); + priv->task_details_page = task_details_page_new (); + comp_editor_append_page (COMP_EDITOR (te), + COMP_EDITOR_PAGE (priv->task_details_page), + _("Details")); } +/* Destroy handler for the event editor */ static void task_editor_destroy (GtkObject *object) { - TaskEditor *tedit; + TaskEditor *te; TaskEditorPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (IS_TASK_EDITOR (object)); - tedit = TASK_EDITOR (object); - priv = tedit->priv; - - if (priv->app) { - gtk_widget_destroy (priv->app); - priv->app = NULL; - } - - if (priv->comp) { - gtk_object_unref (GTK_OBJECT (priv->comp)); - priv->comp = NULL; - } - - if (priv->client) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->client), - tedit); - gtk_object_unref (GTK_OBJECT (priv->client)); - priv->client = NULL; - } - - if (priv->xml) { - gtk_object_unref (GTK_OBJECT (priv->xml)); - priv->xml = NULL; - } - - g_free (priv); - tedit->priv = NULL; + te = TASK_EDITOR (object); + priv = te->priv; if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } - -void -task_editor_set_cal_client (TaskEditor *tedit, - CalClient *client) -{ - TaskEditorPrivate *priv; - - g_return_if_fail (tedit != NULL); - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - - if (client == priv->client) - return; - - if (client) - g_return_if_fail (IS_CAL_CLIENT (client)); - - if (client) - g_return_if_fail (cal_client_get_load_state (client) == CAL_CLIENT_LOAD_LOADED); - - if (client) - gtk_object_ref (GTK_OBJECT (client)); - - if (priv->client) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->client), - tedit); - gtk_object_unref (GTK_OBJECT (priv->client)); - } - - priv->client = client; - - if (priv->client) { - gtk_signal_connect (GTK_OBJECT (priv->client), "obj_updated", - GTK_SIGNAL_FUNC (obj_updated_cb), tedit); - gtk_signal_connect (GTK_OBJECT (priv->client), "obj_removed", - GTK_SIGNAL_FUNC (obj_removed_cb), tedit); - } -} - - -/* Callback used when the calendar client tells us that an object changed */ -static void -obj_updated_cb (CalClient *client, const char *uid, gpointer data) -{ - /* FIXME: Do something sensible if the component changes under our feet */ -#if 0 - TaskEditor *tedit; - TaskEditorPrivate *priv; - CalComponent *comp; - CalClientGetStatus status; - const gchar *editing_uid; - - tedit = TASK_EDITOR (data); - - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - - /* If we aren't showing the object which has been updated, return. */ - if (!priv->comp) - return; - cal_component_get_uid (priv->comp, &editing_uid); - if (strcmp (uid, editing_uid)) - return; - - - /* Get the task from the server. */ - status = cal_client_get_object (priv->client, uid, &comp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: - /* Everything is fine */ - break; - - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("obj_updated_cb(): Syntax error when getting object `%s'", uid); - return; - - case CAL_CLIENT_GET_NOT_FOUND: - /* The object is no longer in the server, so do nothing */ - return; - - default: - g_assert_not_reached (); - return; - } - - raise_and_focus (priv->app); -#endif -} - -/* Callback used when the calendar client tells us that an object was removed */ -static void -obj_removed_cb (CalClient *client, const char *uid, gpointer data) -{ - /* FIXME: Do something sensible if the component is removed under our - * feet. - */ -#if 0 - TaskEditor *tedit; - TaskEditorPrivate *priv; - const gchar *editing_uid; - - tedit = TASK_EDITOR (data); - - g_return_if_fail (tedit != NULL); - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - - /* If we aren't showing the object which has been updated, return. */ - if (!priv->comp) - return; - cal_component_get_uid (priv->comp, &editing_uid); - if (strcmp (uid, editing_uid)) - return; - - - raise_and_focus (priv->app); -#endif -} - - -/* Brings attention to a window by raising it and giving it focus */ -static void -raise_and_focus (GtkWidget *widget) -{ - g_assert (GTK_WIDGET_REALIZED (widget)); - gdk_window_show (widget->window); - gtk_widget_grab_focus (widget); -} - - /** - * task_editor_set_todo_object: - * @tedit: A #TaskEditor. - * @comp: A todo object. + * task_editor_new: + * + * Creates a new event editor dialog. * - * Sets the todo object that a task editor dialog will manipulate. + * Return value: A newly-created event editor dialog, or NULL if the event + * editor could not be created. **/ -void -task_editor_set_todo_object (TaskEditor *tedit, - CalComponent *comp) -{ - TaskEditorPrivate *priv; - - g_return_if_fail (tedit != NULL); - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - - if (priv->comp) { - gtk_object_unref (GTK_OBJECT (priv->comp)); - priv->comp = NULL; - } - - if (comp) - priv->comp = cal_component_clone (comp); - - set_title_from_comp (tedit, priv->comp); - fill_widgets (tedit); -} - -void -task_editor_focus (TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - - g_return_if_fail (tedit != NULL); - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - gtk_widget_show_now (priv->app); - raise_and_focus (priv->app); -} - -#warning this is duplicated function from ../event-editor.c -/* Creates an appropriate title for the task editor dialog */ -static char * -make_title_from_comp (CalComponent *comp) -{ - char *title; - const char *type_string; - CalComponentVType type; - CalComponentText text; - - if (!comp) - return g_strdup (_("Edit Task")); - - type = cal_component_get_vtype (comp); - switch (type) { - case CAL_COMPONENT_EVENT: - type_string = _("Appointment - %s"); - break; - case CAL_COMPONENT_TODO: - type_string = _("Task - %s"); - break; - case CAL_COMPONENT_JOURNAL: - type_string = _("Journal entry - %s"); - break; - default: - g_message ("make_title_from_comp(): Cannot handle object of type %d", type); - return NULL; - } - - cal_component_get_summary (comp, &text); - if (text.value) { - char *summary; - summary = e_utf8_to_locale_string (text.value); - title = g_strdup_printf (type_string, summary); - g_free (summary); - } else - title = g_strdup_printf (type_string, _("No summary")); - - return title; -} - -/* Sets the event editor's window title from a calendar component */ -static void -set_title_from_comp (TaskEditor *tedit, CalComponent *comp) -{ - TaskEditorPrivate *priv = tedit->priv; - char *title; - - title = make_title_from_comp (comp); - gtk_window_set_title (GTK_WINDOW (priv->app), title); - g_free (title); -} - -/* Fills the widgets with default values */ -static void -clear_widgets (TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - - priv = tedit->priv; - - -} - -/* Fills in the widgets with the proper values */ -static void -fill_widgets (TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - CalComponentText text; - CalComponentDateTime d; - CalComponentClassification cl; - struct icaltimetype *completed; - GSList *l; - time_t t; - int *priority_value, *percent; - icalproperty_status status; - TaskEditorPriority priority; - const char *url; - const char *categories; - - priv = tedit->priv; - - task_editor_set_changed (tedit, FALSE); - - clear_widgets (tedit); - - if (!priv->comp) - return; - - /* We want to ignore any signals emitted while changing fields. */ - priv->ignore_callbacks = TRUE; - - - cal_component_get_summary (priv->comp, &text); - e_dialog_editable_set (priv->summary, text.value); - - cal_component_get_description_list (priv->comp, &l); - if (l) { - text = *(CalComponentText *)l->data; - e_dialog_editable_set (priv->description, text.value); - } else { - e_dialog_editable_set (priv->description, NULL); - } - cal_component_free_text_list (l); - - /* Due Date. */ - cal_component_get_due (priv->comp, &d); - if (d.value) { - t = icaltime_as_timet (*d.value); - } else { - t = -1; - } - e_date_edit_set_time (E_DATE_EDIT (priv->due_date), t); - - /* Start Date. */ - cal_component_get_dtstart (priv->comp, &d); - if (d.value) { - t = icaltime_as_timet (*d.value); - } else { - t = -1; - } - e_date_edit_set_time (E_DATE_EDIT (priv->start_date), t); - - /* Completed Date. */ - cal_component_get_completed (priv->comp, &completed); - if (completed) { - t = icaltime_as_timet (*completed); - cal_component_free_icaltimetype (completed); - } else { - t = -1; - } - e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), t); - - /* Percent Complete. */ - cal_component_get_percent (priv->comp, &percent); - if (percent) { - e_dialog_spin_set (priv->percent_complete, *percent); - cal_component_free_percent (percent); - } else { - /* FIXME: Could check if task is completed and set 100%. */ - e_dialog_spin_set (priv->percent_complete, 0); - } - - /* Status. */ - cal_component_get_status (priv->comp, &status); - if (status == ICAL_STATUS_NONE) { - /* Try to user the percent value. */ - if (percent) { - if (*percent == 0) - status = ICAL_STATUS_NEEDSACTION; - else if (*percent == 100) - status = ICAL_STATUS_COMPLETED; - else - status = ICAL_STATUS_INPROCESS; - } else - status = ICAL_STATUS_NEEDSACTION; - } - e_dialog_option_menu_set (priv->status, status, status_map); - - /* Priority. */ - cal_component_get_priority (priv->comp, &priority_value); - if (priority_value) { - priority = priority_value_to_index (*priority_value); - cal_component_free_priority (priority_value); - } else { - priority = PRIORITY_UNDEFINED; - } - e_dialog_option_menu_set (priv->priority, priority, priority_map); - - - /* Classification. */ - cal_component_get_classification (priv->comp, &cl); - - switch (cl) { - case CAL_COMPONENT_CLASS_PUBLIC: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PUBLIC, - classification_map); - case CAL_COMPONENT_CLASS_PRIVATE: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PRIVATE, - classification_map); - case CAL_COMPONENT_CLASS_CONFIDENTIAL: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_CONFIDENTIAL, - classification_map); - default: - /* What do do? We can't g_assert_not_reached() since it is a - * value from an external file. - */ - } - - /* Categories */ - cal_component_get_categories (priv->comp, &categories); - e_dialog_editable_set (priv->categories, categories); - - /* URL. */ - cal_component_get_url (priv->comp, &url); - e_dialog_editable_set (priv->url, url); - - priv->ignore_callbacks = FALSE; -} - - -static void -save_todo_object (TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - - priv = tedit->priv; - - g_return_if_fail (priv->client != NULL); - - if (!priv->comp) - return; - - dialog_to_comp_object (tedit); - set_title_from_comp (tedit, priv->comp); - - if (!cal_client_update_object (priv->client, priv->comp)) - g_message ("save_todo_object(): Could not update the object!"); - else - task_editor_set_changed (tedit, FALSE); -} - - -/* Get the values of the widgets in the event editor and put them in the iCalObject */ -static void -dialog_to_comp_object (TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - CalComponent *comp; - CalComponentDateTime date; - time_t t; - icalproperty_status status; - TaskEditorPriority priority; - int priority_value, percent; - char *url, *cat; - char *str; - - priv = tedit->priv; - comp = priv->comp; - - /* 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 = g_new (struct icaltimetype, 1); - date.tzid = NULL; - - /* Due Date. */ - t = e_date_edit_get_time (E_DATE_EDIT (priv->due_date)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_due (comp, &date); - } else { - cal_component_set_due (comp, NULL); - } - - /* Start Date. */ - t = e_date_edit_get_time (E_DATE_EDIT (priv->start_date)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_dtstart (comp, &date); - } else { - cal_component_set_dtstart (comp, NULL); - } - - /* Completed Date. */ - t = e_date_edit_get_time (E_DATE_EDIT (priv->completed_date)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_completed (comp, date.value); - } else { - cal_component_set_completed (comp, NULL); - } - - g_free (date.value); - - /* Percent Complete. */ - percent = e_dialog_spin_get_int (priv->percent_complete); - cal_component_set_percent (comp, &percent); - - /* Status. */ - status = e_dialog_option_menu_get (priv->status, status_map); - cal_component_set_status (comp, status); - - /* Priority. */ - priority = e_dialog_option_menu_get (priv->priority, priority_map); - priority_value = priority_index_to_value (priority); - cal_component_set_priority (comp, &priority_value); - - /* Classification. */ - cal_component_set_classification (comp, classification_get (priv->classification_public)); - - /* Categories */ - cat = e_dialog_editable_get (priv->categories); - cal_component_set_categories (comp, cat); - - if (cat) - g_free (cat); - - /* URL. */ - url = e_dialog_editable_get (priv->url); - cal_component_set_url (comp, url); - - if (url) - g_free (url); - - cal_component_commit_sequence (comp); -} - -static TaskEditorPriority -priority_value_to_index (int priority_value) -{ - TaskEditorPriority retval; - - if (priority_value == 0) - retval = PRIORITY_UNDEFINED; - else if (priority_value <= 4) - retval = PRIORITY_HIGH; - else if (priority_value == 5) - retval = PRIORITY_NORMAL; - else - retval = PRIORITY_LOW; - - return retval; -} - - -static int -priority_index_to_value (TaskEditorPriority priority) -{ - int retval; - - switch (priority) { - case PRIORITY_UNDEFINED: - retval = 0; - break; - case PRIORITY_HIGH: - retval = 3; - break; - case PRIORITY_NORMAL: - retval = 5; - break; - case PRIORITY_LOW: - retval = 7; - break; - default: - retval = -1; - g_assert_not_reached (); - break; - } - - return retval; -} - - -static void -completed_changed (EDateEdit *dedit, - TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - time_t t; - - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - - if (priv->ignore_callbacks) - return; - - task_editor_set_changed (tedit, TRUE); - - priv->ignore_callbacks = TRUE; - t = e_date_edit_get_time (E_DATE_EDIT (priv->completed_date)); - if (t == -1) { - /* If the 'Completed Date' is set to 'None', we set the - status to 'Not Started' and the percent-complete to 0. - The task may actually be partially-complete, but we leave - it to the user to set those fields. */ - e_dialog_option_menu_set (priv->status, ICAL_STATUS_NEEDSACTION, - status_map); - e_dialog_spin_set (priv->percent_complete, 0); - } else { - e_dialog_option_menu_set (priv->status, ICAL_STATUS_COMPLETED, - status_map); - e_dialog_spin_set (priv->percent_complete, 100); - } - priv->ignore_callbacks = FALSE; -} - - -static void -status_changed (GtkMenu *menu, - TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - icalproperty_status status; - - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - - if (priv->ignore_callbacks) - return; - - task_editor_set_changed (tedit, TRUE); - - status = e_dialog_option_menu_get (priv->status, status_map); - priv->ignore_callbacks = TRUE; - if (status == ICAL_STATUS_NEEDSACTION) { - e_dialog_spin_set (priv->percent_complete, 0); - e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), -1); - } else if (status == ICAL_STATUS_COMPLETED) { - e_dialog_spin_set (priv->percent_complete, 100); - e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), - time (NULL)); - } - priv->ignore_callbacks = FALSE; -} - - -static void -percent_complete_changed (GtkAdjustment *adj, - TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - gint percent; - icalproperty_status status; - time_t date_completed; - - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - - if (priv->ignore_callbacks) - return; - - task_editor_set_changed (tedit, TRUE); - - percent = e_dialog_spin_get_int (priv->percent_complete); - priv->ignore_callbacks = TRUE; - - if (percent == 100) { - date_completed = time (NULL); - status = ICAL_STATUS_COMPLETED; - } else { - /* FIXME: Set to 'None'. */ - date_completed = time (NULL); - - if (percent == 0) - status = ICAL_STATUS_NEEDSACTION; - else - status = ICAL_STATUS_INPROCESS; - } - - e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), - date_completed); - e_dialog_option_menu_set (priv->status, status, status_map); - - priv->ignore_callbacks = FALSE; -} - -/* Decode the radio button group for classifications */ -static CalComponentClassification -classification_get (GtkWidget *widget) -{ - return e_dialog_radio_get (widget, classification_map); -} - - -/* This is called when all fields except those handled above (status, percent - complete & completed date) are changed. It just sets the "changed" flag. */ -static void -field_changed (GtkWidget *widget, - TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - - g_return_if_fail (IS_TASK_EDITOR (tedit)); - - priv = tedit->priv; - - if (priv->ignore_callbacks) - return; - - task_editor_set_changed (tedit, TRUE); -} - - -static void -task_editor_set_changed (TaskEditor *tedit, - gboolean changed) -{ - TaskEditorPrivate *priv; - - priv = tedit->priv; - -#if 0 - g_print ("In task_editor_set_changed: %s\n", - changed ? "TRUE" : "FALSE"); -#endif - - priv->changed = changed; - - if (priv->app) - gnome_property_box_set_state (GNOME_PROPERTY_BOX (priv->app), changed); -} - - -/* This checks if the "changed" field is set, and if so it prompts to save - the changes using a "Save/Discard/Cancel" modal dialog. It then saves the - changes if requested. It returns TRUE if the dialog should now be closed. */ -static gboolean -prompt_to_save_changes (TaskEditor *tedit) -{ - TaskEditorPrivate *priv; - - priv = tedit->priv; - - if (!priv->changed) - return TRUE; - - switch (save_component_dialog (GTK_WINDOW (priv->app))) { - case 0: /* Save */ - /* FIXME: If an error occurs here, we should popup a dialog - and then return FALSE. */ - save_todo_object (tedit); - return TRUE; - case 1: /* Discard */ - return TRUE; - case 2: /* Cancel */ - default: - return FALSE; - break; - } - -} - -static void -categories_clicked(GtkWidget *button, TaskEditor *tedit) +TaskEditor * +task_editor_new (void) { - char *categories; - GnomeDialog *dialog; - int result; - GtkWidget *entry; - - entry = ((TaskEditorPrivate *)tedit->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)); + return TASK_EDITOR (gtk_type_new (TYPE_TASK_EDITOR)); } diff --git a/calendar/gui/dialogs/task-editor.h b/calendar/gui/dialogs/task-editor.h index 7327803a72..bd29d7989d 100644 --- a/calendar/gui/dialogs/task-editor.h +++ b/calendar/gui/dialogs/task-editor.h @@ -1,16 +1,16 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * Author : - * Damon Chaplin <damon@ximian.com> +/* Evolution calendar - Task editor dialog + * + * Copyright (C) 2000 Helix Code, Inc. + * Copyright (C) 2001 Ximian, Inc. * - * Copyright 2000, Helix Code, Inc. - * Copyright 2000, Ximian, Inc. + * Authors: Miguel de Icaza <miguel@ximian.com> + * Federico Mena-Quintero <federico@ximian.com> + * Seth Alves <alves@hungry.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * This program is 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 @@ -19,52 +19,45 @@ * * 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 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _TASK_EDITOR_H_ -#define _TASK_EDITOR_H_ - -#include <gtk/gtkobject.h> -#include <libgnome/gnome-defs.h> -#include <bonobo.h> -#include <cal-client/cal-client.h> -BEGIN_GNOME_DECLS +#ifndef __TASK_EDITOR_H__ +#define __TASK_EDITOR_H__ +#include <libgnome/gnome-defs.h> +#include <gtk/gtkobject.h> +#include "comp-editor.h" -#define TASK_EDITOR(obj) GTK_CHECK_CAST (obj, task_editor_get_type (), TaskEditor) -#define TASK_EDITOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, task_editor_get_type (), TaskEditorClass) -#define IS_TASK_EDITOR(obj) GTK_CHECK_TYPE (obj, task_editor_get_type ()) + +#define TYPE_TASK_EDITOR (task_editor_get_type ()) +#define TASK_EDITOR(obj) (GTK_CHECK_CAST ((obj), TYPE_TASK_EDITOR, TaskEditor)) +#define TASK_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_TASK_EDITOR, \ + TaskEditorClass)) +#define IS_TASK_EDITOR(obj) (GTK_CHECK_TYPE ((obj), TYPE_TASK_EDITOR)) +#define IS_TASK_EDITOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), TYPE_TASK_EDITOR)) -typedef struct _TaskEditor TaskEditor; -typedef struct _TaskEditorClass TaskEditorClass; +typedef struct _TaskEditor TaskEditor; +typedef struct _TaskEditorClass TaskEditorClass; +typedef struct _TaskEditorPrivate TaskEditorPrivate; -struct _TaskEditor -{ - GtkObject object; +struct _TaskEditor { + CompEditor parent; /* Private data */ - gpointer priv; + TaskEditorPrivate *priv; }; -struct _TaskEditorClass -{ - GtkObjectClass parent_class; +struct _TaskEditorClass { + CompEditorClass parent_class; }; -GtkType task_editor_get_type (void); -TaskEditor* task_editor_construct (TaskEditor *tedit); -TaskEditor* task_editor_new (void); -void task_editor_set_cal_client (TaskEditor *tedit, - CalClient *client); -void task_editor_set_todo_object (TaskEditor *tedit, - CalComponent *comp); -void task_editor_focus (TaskEditor *tedit); - - +GtkType task_editor_get_type (void); +TaskEditor *task_editor_construct (TaskEditor *ee); +TaskEditor *task_editor_new (void); +void task_editor_update_widgets (TaskEditor *ee); -END_GNOME_DECLS + -#endif /* _TASK_EDITOR_H_ */ +#endif /* __TASK_EDITOR_H__ */ diff --git a/calendar/gui/dialogs/task-page.c b/calendar/gui/dialogs/task-page.c new file mode 100644 index 0000000000..a1e66260c2 --- /dev/null +++ b/calendar/gui/dialogs/task-page.c @@ -0,0 +1,966 @@ +/* Evolution calendar - Main page of the task 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 <string.h> +#include <gtk/gtksignal.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtkspinbutton.h> +#include <gtk/gtkoptionmenu.h> +#include <glade/glade.h> +#include <gal/widgets/e-unicode.h> +#include <gal/widgets/e-categories.h> +#include <widgets/misc/e-dateedit.h> +#include "e-util/e-dialog-widgets.h" +#include "../widget-util.h" +#include "task-page.h" + + + +/* Private part of the TaskPage structure */ +struct _TaskPagePrivate { + /* Glade XML data */ + GladeXML *xml; + + /* Widgets from the Glade file */ + GtkWidget *main; + + GtkWidget *summary; + + GtkWidget *due_date; + GtkWidget *start_date; + + GtkWidget *percent_complete; + + GtkWidget *status; + GtkWidget *priority; + + GtkWidget *description; + + GtkWidget *classification_public; + GtkWidget *classification_private; + GtkWidget *classification_confidential; + + GtkWidget *contacts_btn; + GtkWidget *contacts; + + GtkWidget *categories_btn; + GtkWidget *categories; + + gboolean updating; +}; + +/* Note that these two arrays must match. */ +static const int status_map[] = { + ICAL_STATUS_NEEDSACTION, + ICAL_STATUS_INPROCESS, + ICAL_STATUS_COMPLETED, + ICAL_STATUS_CANCELLED, + -1 +}; + +typedef enum { + PRIORITY_HIGH, + PRIORITY_NORMAL, + PRIORITY_LOW, + PRIORITY_UNDEFINED, +} TaskEditorPriority; + +static const int priority_map[] = { + PRIORITY_HIGH, + PRIORITY_NORMAL, + PRIORITY_LOW, + PRIORITY_UNDEFINED, + -1 +}; + +static const int classification_map[] = { + CAL_COMPONENT_CLASS_PUBLIC, + CAL_COMPONENT_CLASS_PRIVATE, + CAL_COMPONENT_CLASS_CONFIDENTIAL, + -1 +}; + + + +static void task_page_class_init (TaskPageClass *class); +static void task_page_init (TaskPage *tpage); +static void task_page_destroy (GtkObject *object); + +static GtkWidget *task_page_get_widget (CompEditorPage *page); +static void task_page_fill_widgets (CompEditorPage *page, CalComponent *comp); +static void task_page_fill_component (CompEditorPage *page, CalComponent *comp); +static void task_page_set_summary (CompEditorPage *page, const char *summary); +static void task_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates); + +static CompEditorPageClass *parent_class = NULL; + + + +/** + * task_page_get_type: + * + * Registers the #TaskPage class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #TaskPage class. + **/ +GtkType +task_page_get_type (void) +{ + static GtkType task_page_type; + + if (!task_page_type) { + static const GtkTypeInfo task_page_info = { + "TaskPage", + sizeof (TaskPage), + sizeof (TaskPageClass), + (GtkClassInitFunc) task_page_class_init, + (GtkObjectInitFunc) task_page_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + task_page_type = gtk_type_unique (TYPE_COMP_EDITOR_PAGE, + &task_page_info); + } + + return task_page_type; +} + +/* Class initialization function for the task page */ +static void +task_page_class_init (TaskPageClass *class) +{ + CompEditorPageClass *editor_page_class; + GtkObjectClass *object_class; + + editor_page_class = (CompEditorPageClass *) class; + object_class = (GtkObjectClass *) class; + + parent_class = gtk_type_class (TYPE_COMP_EDITOR_PAGE); + + editor_page_class->get_widget = task_page_get_widget; + editor_page_class->fill_widgets = task_page_fill_widgets; + editor_page_class->fill_component = task_page_fill_component; + editor_page_class->set_summary = task_page_set_summary; + editor_page_class->set_dates = task_page_set_dates; + + object_class->destroy = task_page_destroy; +} + +/* Object initialization function for the task page */ +static void +task_page_init (TaskPage *tpage) +{ + TaskPagePrivate *priv; + + priv = g_new0 (TaskPagePrivate, 1); + tpage->priv = priv; + + priv->xml = NULL; + + priv->main = NULL; + priv->summary = NULL; + priv->due_date = NULL; + priv->start_date = NULL; + priv->percent_complete = NULL; + priv->status = 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; + + priv->updating = FALSE; +} + +/* Destroy handler for the task page */ +static void +task_page_destroy (GtkObject *object) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_TASK_PAGE (object)); + + tpage = TASK_PAGE (object); + priv = tpage->priv; + + if (priv->xml) { + gtk_object_unref (GTK_OBJECT (priv->xml)); + priv->xml = NULL; + } + + g_free (priv); + tpage->priv = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + + + +/* get_widget handler for the task page */ +static GtkWidget * +task_page_get_widget (CompEditorPage *page) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + + tpage = TASK_PAGE (page); + priv = tpage->priv; + + return priv->main; +} + +/* Fills the widgets with default values */ +static void +clear_widgets (TaskPage *tpage) +{ + TaskPagePrivate *priv; + time_t now; + + priv = tpage->priv; + + now = time (NULL); + + /* Summary, description */ + e_dialog_editable_set (priv->summary, NULL); + e_dialog_editable_set (priv->description, NULL); + + /* Start, due times */ + e_date_edit_set_time (E_DATE_EDIT (priv->start_date), now); + e_date_edit_set_time (E_DATE_EDIT (priv->due_date), now); + + /* Classification */ + e_dialog_radio_set (priv->classification_public, + CAL_COMPONENT_CLASS_PRIVATE, classification_map); + + /* Status, priority, complete percent */ + e_dialog_spin_set (priv->percent_complete, 0.0); + e_dialog_option_menu_set (priv->status, 0, status_map); + e_dialog_option_menu_set (priv->priority, 0, priority_map); + + /* Categories */ + e_dialog_editable_set (priv->categories, NULL); +} + +static TaskEditorPriority +priority_value_to_index (int priority_value) +{ + TaskEditorPriority retval; + + if (priority_value == 0) + retval = PRIORITY_UNDEFINED; + else if (priority_value <= 4) + retval = PRIORITY_HIGH; + else if (priority_value == 5) + retval = PRIORITY_NORMAL; + else + retval = PRIORITY_LOW; + + return retval; +} + +static int +priority_index_to_value (TaskEditorPriority priority) +{ + int retval; + + switch (priority) { + case PRIORITY_UNDEFINED: + retval = 0; + break; + case PRIORITY_HIGH: + retval = 3; + break; + case PRIORITY_NORMAL: + retval = 5; + break; + case PRIORITY_LOW: + retval = 7; + break; + default: + retval = -1; + g_assert_not_reached (); + break; + } + + return retval; +} + +/* Decode the radio button group for classifications */ +static CalComponentClassification +classification_get (GtkWidget *widget) +{ + return e_dialog_radio_get (widget, classification_map); +} + +/* fill_widgets handler for the task page */ +static void +task_page_fill_widgets (CompEditorPage *page, CalComponent *comp) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + CalComponentText text; + CalComponentDateTime d; + CalComponentClassification cl; + GSList *l; + time_t t; + int *priority_value, *percent; + icalproperty_status status; + TaskEditorPriority priority; + const char *categories; + + tpage = TASK_PAGE (page); + priv = tpage->priv; + + priv->updating = TRUE; + + /* Clean the screen */ + clear_widgets (tpage); + + /* 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); + } else { + e_dialog_editable_set (priv->description, NULL); + } + cal_component_free_text_list (l); + + /* Due Date. */ + cal_component_get_due (comp, &d); + if (d.value) { + t = icaltime_as_timet (*d.value); + } else { + t = -1; + } + e_date_edit_set_time (E_DATE_EDIT (priv->due_date), t); + + /* Start Date. */ + cal_component_get_dtstart (comp, &d); + if (d.value) { + t = icaltime_as_timet (*d.value); + } else { + t = -1; + } + e_date_edit_set_time (E_DATE_EDIT (priv->start_date), t); + + /* Percent Complete. */ + cal_component_get_percent (comp, &percent); + if (percent) { + e_dialog_spin_set (priv->percent_complete, *percent); + cal_component_free_percent (percent); + } else { + /* FIXME: Could check if task is completed and set 100%. */ + e_dialog_spin_set (priv->percent_complete, 0); + } + + /* Status. */ + cal_component_get_status (comp, &status); + if (status == ICAL_STATUS_NONE) { + /* Try to user the percent value. */ + if (percent) { + if (*percent == 0) + status = ICAL_STATUS_NEEDSACTION; + else if (*percent == 100) + status = ICAL_STATUS_COMPLETED; + else + status = ICAL_STATUS_INPROCESS; + } else + status = ICAL_STATUS_NEEDSACTION; + } + e_dialog_option_menu_set (priv->status, status, status_map); + + /* Priority. */ + cal_component_get_priority (comp, &priority_value); + if (priority_value) { + priority = priority_value_to_index (*priority_value); + cal_component_free_priority (priority_value); + } else { + priority = PRIORITY_UNDEFINED; + } + e_dialog_option_menu_set (priv->priority, priority, priority_map); + + + /* 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); + case CAL_COMPONENT_CLASS_PRIVATE: + e_dialog_radio_set (priv->classification_public, + CAL_COMPONENT_CLASS_PRIVATE, + classification_map); + case CAL_COMPONENT_CLASS_CONFIDENTIAL: + e_dialog_radio_set (priv->classification_public, + CAL_COMPONENT_CLASS_CONFIDENTIAL, + classification_map); + default: + /* What do do? We can't g_assert_not_reached() since it is a + * value from an external file. + */ + } + + /* Categories */ + cal_component_get_categories (comp, &categories); + e_dialog_editable_set (priv->categories, categories); + + priv->updating = FALSE; +} + +/* fill_component handler for the task page */ +static void +task_page_fill_component (CompEditorPage *page, CalComponent *comp) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + CalComponentDateTime date; + time_t t; + icalproperty_status status; + TaskEditorPriority priority; + int priority_value, percent; + char *cat; + char *str; + + tpage = TASK_PAGE (page); + priv = tpage->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 = g_new (struct icaltimetype, 1); + date.tzid = NULL; + + /* Due Date. */ + t = e_date_edit_get_time (E_DATE_EDIT (priv->due_date)); + if (t != -1) { + *date.value = icaltime_from_timet (t, FALSE); + cal_component_set_due (comp, &date); + } else { + cal_component_set_due (comp, NULL); + } + + /* Start Date. */ + t = e_date_edit_get_time (E_DATE_EDIT (priv->start_date)); + if (t != -1) { + *date.value = icaltime_from_timet (t, FALSE); + cal_component_set_dtstart (comp, &date); + } else { + cal_component_set_dtstart (comp, NULL); + } + + /* Percent Complete. */ + percent = e_dialog_spin_get_int (priv->percent_complete); + cal_component_set_percent (comp, &percent); + + /* Status. */ + status = e_dialog_option_menu_get (priv->status, status_map); + cal_component_set_status (comp, status); + + /* Priority. */ + priority = e_dialog_option_menu_get (priv->priority, priority_map); + priority_value = priority_index_to_value (priority); + cal_component_set_priority (comp, &priority_value); + + /* Classification. */ + cal_component_set_classification (comp, classification_get (priv->classification_public)); + + /* Categories */ + cat = e_dialog_editable_get (priv->categories); + cal_component_set_categories (comp, cat); + + if (cat) + g_free (cat); +} + +/* set_summary handler for the task page */ +static void +task_page_set_summary (CompEditorPage *page, const char *summary) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + + tpage = TASK_PAGE (page); + priv = tpage->priv; + + gtk_signal_handler_block_by_data (GTK_OBJECT (priv->summary), tpage); + e_utf8_gtk_entry_set_text (GTK_ENTRY (priv->summary), summary); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->summary), tpage); +} + +static void +task_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + + tpage = TASK_PAGE (page); + priv = tpage->priv; + + priv->updating = TRUE; + + if (dates->complete != 0) { + if (dates->complete == -1) { + /* If the 'Completed Date' is set to 'None', + we set the status to 'Not Started' and the + percent-complete to 0. The task may + actually be partially-complete, but we + leave it to the user to set those + fields. */ + e_dialog_option_menu_set (priv->status, + ICAL_STATUS_NEEDSACTION, + status_map); + e_dialog_spin_set (priv->percent_complete, 0); + } else { + e_dialog_option_menu_set (priv->status, + ICAL_STATUS_COMPLETED, + status_map); + e_dialog_spin_set (priv->percent_complete, 100); + } + } + + priv->updating = FALSE; +} + + + +/* Gets the widgets from the XML file and returns if they are all available. */ +static gboolean +get_widgets (TaskPage *tpage) +{ + TaskPagePrivate *priv; + + priv = tpage->priv; + +#define GW(name) glade_xml_get_widget (priv->xml, name) + + priv->main = GW ("task-page"); + g_assert (priv->main); + gtk_widget_ref (priv->main); + gtk_widget_unparent (priv->main); + + priv->summary = GW ("summary"); + + priv->due_date = GW ("due-date"); + priv->start_date = GW ("start-date"); + + priv->percent_complete = GW ("percent-complete"); + + priv->status = GW ("status"); + priv->priority = GW ("priority"); + + 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->due_date + && priv->start_date + && priv->percent_complete + && priv->status + && priv->priority + && priv->classification_public + && priv->classification_private + && priv->classification_confidential + && priv->description + && 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) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + gchar *summary; + + tpage = TASK_PAGE (data); + priv = tpage->priv; + + if (priv->updating) + return; + + summary = gtk_editable_get_chars (editable, 0, -1); + comp_editor_page_notify_summary_changed (COMP_EDITOR_PAGE (tpage), + summary); + g_free (summary); +} + +/* Callback used when the start or end date widgets change. We check that the + * start date < end date and we set the "all day task" button as appropriate. + */ +static void +date_changed_cb (EDateEdit *dedit, gpointer data) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + CompEditorPageDates dates; + + tpage = TASK_PAGE (data); + priv = tpage->priv; + + if (priv->updating) + return; + + dates.start = e_date_edit_get_time (E_DATE_EDIT (priv->start_date)); + dates.end = 0; + dates.due = e_date_edit_get_time (E_DATE_EDIT (priv->due_date)); + dates.complete = 0; + + /* Notify upstream */ + comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (tpage), + &dates); +} + +/* 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) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + char *categories; + GnomeDialog *dialog; + int result; + GtkWidget *entry; + + tpage = TASK_PAGE (data); + priv = tpage->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) +{ + TaskPage *tpage; + TaskPagePrivate *priv; + + tpage = TASK_PAGE (data); + priv = tpage->priv; + + if (!priv->updating) + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (tpage)); +} + +static void +complete_date_changed (TaskPage *tpage, time_t complete) +{ + TaskPagePrivate *priv; + CompEditorPageDates dates; + + priv = tpage->priv; + + if (priv->updating) + return; + + dates.start = 0; + dates.end = 0; + dates.due = 0; + dates.complete = complete; + + /* Notify upstream */ + comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (tpage), + &dates); +} + +static void +status_changed (GtkMenu *menu, TaskPage *tpage) +{ + TaskPagePrivate *priv; + icalproperty_status status; + + priv = tpage->priv; + + if (priv->updating) + return; + + status = e_dialog_option_menu_get (priv->status, status_map); + if (status == ICAL_STATUS_NEEDSACTION) { + e_dialog_spin_set (priv->percent_complete, 0); + complete_date_changed (tpage, -1); + } else if (status == ICAL_STATUS_INPROCESS) { + e_dialog_spin_set (priv->percent_complete, 50); + complete_date_changed (tpage, -1); + } else if (status == ICAL_STATUS_COMPLETED) { + e_dialog_spin_set (priv->percent_complete, 100); + complete_date_changed (tpage, time (NULL)); + } + + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (tpage)); +} + +static void +percent_complete_changed (GtkAdjustment *adj, TaskPage *tpage) +{ + TaskPagePrivate *priv; + gint percent; + icalproperty_status status; + time_t date_completed; + + priv = tpage->priv; + + if (priv->updating) + return; + + percent = e_dialog_spin_get_int (priv->percent_complete); + if (percent == 100) { + date_completed = time (NULL); + status = ICAL_STATUS_COMPLETED; + } else { + date_completed = -1; + + if (percent == 0) + status = ICAL_STATUS_NEEDSACTION; + else + status = ICAL_STATUS_INPROCESS; + } + + complete_date_changed (tpage, date_completed); + e_dialog_option_menu_set (priv->status, status, status_map); + + comp_editor_page_notify_changed (COMP_EDITOR_PAGE (tpage)); +} + + +/* Hooks the widget signals */ +static void +init_widgets (TaskPage *tpage) +{ + TaskPagePrivate *priv; + + priv = tpage->priv; + + + /* Summary */ + gtk_signal_connect (GTK_OBJECT (priv->summary), "changed", + GTK_SIGNAL_FUNC (summary_changed_cb), tpage); + + /* Dates */ + gtk_signal_connect (GTK_OBJECT (priv->start_date), "changed", + GTK_SIGNAL_FUNC (date_changed_cb), tpage); + gtk_signal_connect (GTK_OBJECT (priv->due_date), "changed", + GTK_SIGNAL_FUNC (date_changed_cb), tpage); + + /* Connect signals. The Status, Percent Complete & Date Completed + properties are closely related so whenever one changes we may need + to update the other 2. */ + gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (priv->status)->menu), + "deactivate", + GTK_SIGNAL_FUNC (status_changed), tpage); + + gtk_signal_connect (GTK_OBJECT (GTK_SPIN_BUTTON (priv->percent_complete)->adjustment), + "value_changed", + GTK_SIGNAL_FUNC (percent_complete_changed), tpage); + + /* Classification */ + gtk_signal_connect (GTK_OBJECT (priv->description), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), tpage); + gtk_signal_connect (GTK_OBJECT (priv->classification_public), + "toggled", + GTK_SIGNAL_FUNC (field_changed_cb), tpage); + gtk_signal_connect (GTK_OBJECT (priv->classification_private), + "toggled", + GTK_SIGNAL_FUNC (field_changed_cb), tpage); + gtk_signal_connect (GTK_OBJECT (priv->classification_confidential), + "toggled", + GTK_SIGNAL_FUNC (field_changed_cb), tpage); + + /* Connect the default signal handler to use to make sure the "changed" + field gets set whenever a field is changed. */ + gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (priv->priority)->menu), + "deactivate", + GTK_SIGNAL_FUNC (field_changed_cb), tpage); + gtk_signal_connect (GTK_OBJECT (priv->description), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), tpage); + gtk_signal_connect (GTK_OBJECT (priv->contacts), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), tpage); + gtk_signal_connect (GTK_OBJECT (priv->categories), "changed", + GTK_SIGNAL_FUNC (field_changed_cb), tpage); + + /* Button clicks */ + gtk_signal_connect (GTK_OBJECT (priv->categories_btn), "clicked", + GTK_SIGNAL_FUNC (categories_clicked_cb), tpage); + + /* 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); +} + + + +/** + * task_page_construct: + * @tpage: An task page. + * + * Constructs an task page by loading its Glade data. + * + * Return value: The same object as @tpage, or NULL if the widgets could not be + * created. + **/ +TaskPage * +task_page_construct (TaskPage *tpage) +{ + TaskPagePrivate *priv; + + priv = tpage->priv; + + priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/task-page.glade", + NULL); + if (!priv->xml) { + g_message ("task_page_construct(): " + "Could not load the Glade XML file!"); + return NULL; + } + + if (!get_widgets (tpage)) { + g_message ("task_page_construct(): " + "Could not find all widgets in the XML file!"); + return NULL; + } + + init_widgets (tpage); + + return tpage; +} + +/** + * task_page_new: + * + * Creates a new task page. + * + * Return value: A newly-created task page, or NULL if the page could + * not be created. + **/ +TaskPage * +task_page_new (void) +{ + TaskPage *tpage; + + tpage = gtk_type_new (TYPE_TASK_PAGE); + if (!task_page_construct (tpage)) { + gtk_object_unref (GTK_OBJECT (tpage)); + return NULL; + } + + return tpage; +} + +GtkWidget *task_page_create_date_edit (void); + +GtkWidget * +task_page_create_date_edit (void) +{ + GtkWidget *dedit; + + dedit = date_edit_new (TRUE, TRUE); + e_date_edit_set_allow_no_date_set (E_DATE_EDIT (dedit), TRUE); + + return dedit; +} diff --git a/calendar/gui/dialogs/task-page.glade b/calendar/gui/dialogs/task-page.glade index e9f0d4700d..b6182cd860 100644 --- a/calendar/gui/dialogs/task-page.glade +++ b/calendar/gui/dialogs/task-page.glade @@ -15,6 +15,7 @@ <widget> <class>GtkWindow</class> <name>task-toplevel</name> + <visible>False</visible> <title>window1</title> <type>GTK_WINDOW_TOPLEVEL</type> <position>GTK_WIN_POS_NONE</position> @@ -184,10 +185,10 @@ <widget> <class>Custom</class> <name>due-date</name> - <creation_function>task_editor_create_date_edit</creation_function> + <creation_function>task_page_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> + <last_modification_time>Fri, 01 Jun 2001 18:59:52 GMT</last_modification_time> <child> <left_attach>1</left_attach> <right_attach>2</right_attach> @@ -207,10 +208,10 @@ <widget> <class>Custom</class> <name>start-date</name> - <creation_function>task_editor_create_date_edit</creation_function> + <creation_function>task_page_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> + <last_modification_time>Fri, 01 Jun 2001 18:59:57 GMT</last_modification_time> <child> <left_attach>1</left_attach> <right_attach>2</right_attach> @@ -239,7 +240,7 @@ <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy> <child> <padding>0</padding> - <expand>False</expand> + <expand>True</expand> <fill>True</fill> </child> @@ -459,7 +460,7 @@ Undefined <spacing>2</spacing> <child> <padding>0</padding> - <expand>True</expand> + <expand>False</expand> <fill>True</fill> </child> @@ -467,7 +468,6 @@ Undefined <class>GtkButton</class> <name>contacts-button</name> <can_focus>True</can_focus> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> @@ -506,7 +506,6 @@ Undefined <class>GtkButton</class> <name>categories-button</name> <can_focus>True</can_focus> - <relief>GTK_RELIEF_NORMAL</relief> <child> <padding>0</padding> <expand>False</expand> diff --git a/calendar/gui/dialogs/task-page.h b/calendar/gui/dialogs/task-page.h new file mode 100644 index 0000000000..cc56892c5b --- /dev/null +++ b/calendar/gui/dialogs/task-page.h @@ -0,0 +1,61 @@ +/* Evolution calendar - Main page of the task 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 TASK_PAGE_H +#define TASK_PAGE_H + +#include "comp-editor-page.h" + +BEGIN_GNOME_DECLS + + + +#define TYPE_TASK_PAGE (task_page_get_type ()) +#define TASK_PAGE(obj) (GTK_CHECK_CAST ((obj), TYPE_TASK_PAGE, TaskPage)) +#define TASK_PAGE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), TYPE_TASK_PAGE, TaskPageClass)) +#define IS_TASK_PAGE(obj) (GTK_CHECK_TYPE ((obj), TYPE_TASK_PAGE)) +#define IS_TASK_PAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), TYPE_TASK_PAGE)) + +typedef struct _TaskPagePrivate TaskPagePrivate; + +typedef struct { + CompEditorPage page; + + /* Private data */ + TaskPagePrivate *priv; +} TaskPage; + +typedef struct { + CompEditorPageClass parent_class; +} TaskPageClass; + +GtkType task_page_get_type (void); +TaskPage *task_page_construct (TaskPage *epage); +TaskPage *task_page_new (void); + + + +END_GNOME_DECLS + +#endif diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c index 685a56d9f9..d95318cb04 100644 --- a/calendar/gui/e-calendar-table.c +++ b/calendar/gui/e-calendar-table.c @@ -31,6 +31,7 @@ #include <config.h> #include <sys/stat.h> #include <unistd.h> +#include <gnome.h> #include <gal/e-table/e-cell-checkbox.h> #include <gal/e-table/e-cell-toggle.h> #include <gal/e-table/e-cell-text.h> @@ -674,9 +675,9 @@ open_task (ECalendarTable *cal_table, CalComponent *comp) TaskEditor *tedit; tedit = task_editor_new (); - task_editor_set_cal_client (tedit, calendar_model_get_cal_client (cal_table->model)); - task_editor_set_todo_object (tedit, comp); - task_editor_focus (tedit); + comp_editor_set_cal_client (COMP_EDITOR (tedit), calendar_model_get_cal_client (cal_table->model)); + comp_editor_edit_comp (COMP_EDITOR (tedit), comp); + comp_editor_focus (COMP_EDITOR (tedit)); } /* Opens the task in the specified row */ diff --git a/calendar/gui/e-tasks.c b/calendar/gui/e-tasks.c index 609e2551c1..4a25646676 100644 --- a/calendar/gui/e-tasks.c +++ b/calendar/gui/e-tasks.c @@ -24,6 +24,7 @@ */ #include <config.h> +#include <gnome.h> #include <gal/util/e-util.h> #include <gal/e-table/e-table-scrolled.h> #include <gal/menus/gal-view-collection.h> @@ -468,15 +469,15 @@ e_tasks_new_task (ETasks *tasks) priv = tasks->priv; tedit = task_editor_new (); - task_editor_set_cal_client (tedit, priv->client); + comp_editor_set_cal_client (COMP_EDITOR (tedit), priv->client); comp = cal_component_new (); cal_component_set_new_vtype (comp, CAL_COMPONENT_TODO); - task_editor_set_todo_object (tedit, comp); + comp_editor_edit_comp (COMP_EDITOR (tedit), comp); gtk_object_unref (GTK_OBJECT (comp)); - task_editor_focus (tedit); + comp_editor_focus (COMP_EDITOR (tedit)); } /** diff --git a/calendar/gui/event-editor-dialog.glade b/calendar/gui/event-editor-dialog.glade deleted file mode 100644 index 615bd3eed3..0000000000 --- a/calendar/gui/event-editor-dialog.glade +++ /dev/null @@ -1,1408 +0,0 @@ -<?xml version="1.0"?> -<GTK-Interface> - -<project> - <name>event-editor-dialog</name> - <program_name>event-editor-dialog</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>GnomePropertyBox</class> - <name>event-editor-dialog</name> - <visible>False</visible> - <position>GTK_WIN_POS_NONE</position> - <modal>False</modal> - <allow_shrink>False</allow_shrink> - <allow_grow>False</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> - - <widget> - <class>GtkVBox</class> - <name>vbox51</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> - <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> - <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> - <class>GtkLabel</class> - <child_name>Notebook:tab</child_name> - <name>label61</name> - <label>Appointment</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> - <class>GtkVBox</class> - <name>vbox52</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>GtkLabel</class> - <name>label63</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>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>GtkAlignment</class> - <name>reminder-starting-data</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>reminder-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>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> - <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> - </widget> - - <widget> - <class>GtkButton</class> - <name>reminder-delete</name> - <can_default>True</can_default> - <can_focus>True</can_focus> - <label>Delete</label> - </widget> - </widget> - </widget> - </widget> - </widget> - </widget> - - <widget> - <class>GtkLabel</class> - <child_name>Notebook:tab</child_name> - <name>label65</name> - <label>Reminder</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> - <class>GtkVBox</class> - <name>vbox54</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> - <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> - <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> - <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> - <class>GtkLabel</class> - <child_name>Notebook:tab</child_name> - <name>label71</name> - <label>Recurrence</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> - -</GTK-Interface> diff --git a/calendar/gui/event-editor.c b/calendar/gui/event-editor.c deleted file mode 100644 index c96c94dadd..0000000000 --- a/calendar/gui/event-editor.c +++ /dev/null @@ -1,3377 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* Evolution calendar - Event editor dialog - * - * Copyright (C) 2000 Helix Code, Inc. - * Copyright (C) 2001 Ximian, Inc. - * - * Authors: Miguel de Icaza <miguel@ximian.com> - * Federico Mena-Quintero <federico@ximian.com> - * Seth Alves <alves@hungry.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <config.h> -#include <string.h> -#include <glade/glade.h> -#include <gal/widgets/e-unicode.h> -#include <gal/widgets/e-categories.h> -#include <libgnomeui/gnome-propertybox.h> -#include <libgnome/gnome-i18n.h> - -#include "calendar-config.h" -#include "cal-util/timeutil.h" -#include "dialogs/delete-comp.h" -#include "dialogs/save-comp.h" -#include "e-meeting-edit.h" -#include "e-util/e-dialog-widgets.h" -#include "event-editor.h" -#include "tag-calendar.h" -#include "weekday-picker.h" -#include "widgets/misc/e-dateedit.h" -#include "widget-util.h" - -enum {BEFORE, AFTER}; -enum {MINUTES, HOURS, DAYS}; - -/* Reminder maps */ -static const int reminder_action_map[] = { - CAL_ALARM_DISPLAY, - CAL_ALARM_AUDIO, - CAL_ALARM_EMAIL, - CAL_ALARM_PROCEDURE, - -1 -}; - -static const int reminder_value_map[] = { - MINUTES, - HOURS, - DAYS, - -1 -}; - -static const int reminder_relative_map[] = { - BEFORE, - AFTER, - -1 -}; - -static const int reminder_time_map[] = { - CAL_ALARM_TRIGGER_RELATIVE_START, - CAL_ALARM_TRIGGER_RELATIVE_END, - -1 -}; - -/* Recurrence maps */ -static const int recur_freq_map[] = { - ICAL_DAILY_RECURRENCE, - ICAL_WEEKLY_RECURRENCE, - ICAL_MONTHLY_RECURRENCE, - ICAL_YEARLY_RECURRENCE, - -1 -}; - -enum month_day_options { - MONTH_DAY_NTH, - MONTH_DAY_MON, - MONTH_DAY_TUE, - MONTH_DAY_WED, - MONTH_DAY_THU, - MONTH_DAY_FRI, - MONTH_DAY_SAT, - MONTH_DAY_SUN -}; - -static const int month_day_options_map[] = { - MONTH_DAY_NTH, - MONTH_DAY_MON, - MONTH_DAY_TUE, - MONTH_DAY_WED, - MONTH_DAY_THU, - MONTH_DAY_FRI, - MONTH_DAY_SAT, - MONTH_DAY_SUN, - -1 -}; - -/* Row data for the reminders */ -typedef enum {NEW_ALARM, EXISTING_ALARM} ReminderStatus; - -typedef struct { - ReminderStatus status; - CalComponentAlarm *alarm; -} ReminderData; - -struct _EventEditorPrivate { - /* Glade XML data */ - GladeXML *xml; - - /* Client to use */ - CalClient *client; - - /* Calendar object/uid we are editing; this is an internal copy */ - CalComponent *comp; - - /* Widgets from the Glade file */ - - GtkWidget *app; - - GtkWidget *general_summary; - - GtkWidget *start_time; - GtkWidget *end_time; - GtkWidget *all_day_event; - - GtkWidget *description; - - GtkWidget *classification_public; - GtkWidget *classification_private; - GtkWidget *classification_confidential; - - GtkWidget *contacts; - GtkWidget *contacts_btn; - - GtkWidget *categories; - GtkWidget *categories_btn; - - GtkWidget *reminder_summary; - GtkWidget *reminder_starting_date; - - GtkWidget *reminder_list; - GtkWidget *reminder_add; - GtkWidget *reminder_delete; - - GtkWidget *reminder_action; - GtkWidget *reminder_interval_value; - GtkWidget *reminder_value_units; - GtkWidget *reminder_relative; - GtkWidget *reminder_time; - - GtkWidget *recurrence_summary; - GtkWidget *recurrence_starting_date; - - GtkWidget *recurrence_none; - GtkWidget *recurrence_simple; - GtkWidget *recurrence_custom; - - GtkWidget *recurrence_params; - GtkWidget *recurrence_interval_value; - GtkWidget *recurrence_interval_unit; - GtkWidget *recurrence_special; - GtkWidget *recurrence_ending_menu; - GtkWidget *recurrence_ending_special; - GtkWidget *recurrence_custom_warning_bin; - - /* For weekly recurrences, created by hand */ - GtkWidget *recurrence_weekday_picker; - guint8 recurrence_weekday_day_mask; - guint8 recurrence_weekday_blocked_day_mask; - - /* For monthly recurrences, created by hand */ - GtkWidget *recurrence_month_index_spin; - int recurrence_month_index; - - GtkWidget *recurrence_month_day_menu; - enum month_day_options recurrence_month_day; - - /* For ending date, created by hand */ - GtkWidget *recurrence_ending_date_edit; - time_t recurrence_ending_date; - - /* For ending count of occurrences, created by hand */ - GtkWidget *recurrence_ending_count_spin; - int recurrence_ending_count; - - /* More widgets from the Glade file */ - - GtkWidget *recurrence_exception_date; - GtkWidget *recurrence_exception_list; - GtkWidget *recurrence_exception_add; - GtkWidget *recurrence_exception_modify; - GtkWidget *recurrence_exception_delete; - - GtkWidget *recurrence_preview_bin; - - /* For the recurrence preview, the actual widget */ - GtkWidget *recurrence_preview_calendar; - - /* Call event_editor_set_changed() to set this to TRUE when any field - in the dialog is changed. When the user closes the dialog we will - prompt to save changes. */ - gboolean changed; -}; - - - -static void event_editor_class_init (EventEditorClass *class); -static void event_editor_init (EventEditor *ee); -static void event_editor_destroy (GtkObject *object); - -static GtkObjectClass *parent_class; - - -static void append_reminder (EventEditor *ee, CalComponentAlarm *alarm, ReminderStatus status); -static void append_exception (EventEditor *ee, time_t t); -static void check_all_day (EventEditor *ee); -static void set_all_day (GtkWidget *toggle, EventEditor *ee); -static void date_changed_cb (EDateEdit *dedit, gpointer data); -static void preview_recur (EventEditor *ee); -static void recur_to_comp_object (EventEditor *ee, CalComponent *comp); -static void reminder_to_comp_object (EventEditor *ee, CalComponent *comp); -static void reminder_add_cb (GtkWidget *widget, EventEditor *ee); -static void reminder_delete_cb (GtkWidget *widget, EventEditor *ee); -static void recurrence_exception_add_cb (GtkWidget *widget, EventEditor *ee); -static void recurrence_exception_modify_cb (GtkWidget *widget, EventEditor *ee); -static void recurrence_exception_delete_cb (GtkWidget *widget, EventEditor *ee); -static void recurrence_exception_select_row_cb (GtkCList *clist, gint row, gint col, GdkEvent *event, - gpointer data); -static void field_changed (GtkWidget *widget, - EventEditor *ee); -static void event_editor_set_changed (EventEditor *ee, - gboolean changed); -static gboolean prompt_to_save_changes (EventEditor *ee); -static void categories_clicked (GtkWidget *button, EventEditor *ee); - - - -/** - * event_editor_get_type: - * - * Registers the #EventEditor class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the #EventEditor class. - **/ -GtkType -event_editor_get_type (void) -{ - static GtkType event_editor_type = 0; - - if (!event_editor_type) { - static const GtkTypeInfo event_editor_info = { - "EventEditor", - sizeof (EventEditor), - sizeof (EventEditorClass), - (GtkClassInitFunc) event_editor_class_init, - (GtkObjectInitFunc) event_editor_init, - NULL, /* reserved_1 */ - NULL, /* reserved_2 */ - (GtkClassInitFunc) NULL - }; - - event_editor_type = gtk_type_unique (GTK_TYPE_OBJECT, &event_editor_info); - } - - return event_editor_type; -} - -/* Class initialization function for the event editor */ -static void -event_editor_class_init (EventEditorClass *class) -{ - GtkObjectClass *object_class; - - object_class = (GtkObjectClass *) class; - - parent_class = gtk_type_class (GTK_TYPE_OBJECT); - - object_class->destroy = event_editor_destroy; -} - -/* Object initialization function for the event editor */ -static void -event_editor_init (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = g_new0 (EventEditorPrivate, 1); - ee->priv = priv; - - event_editor_set_changed (ee, FALSE); -} - -/* Frees the rows and the row data in the recurrence exceptions GtkCList */ -static void -free_exception_clist_data (GtkCList *clist) -{ - int i; - - for (i = 0; i < clist->rows; i++) { - gpointer data; - - data = gtk_clist_get_row_data (clist, i); - g_free (data); - gtk_clist_set_row_data (clist, i, NULL); - } - - gtk_clist_clear (clist); -} - -/* Destroy handler for the event editor */ -static void -event_editor_destroy (GtkObject *object) -{ - EventEditor *ee; - EventEditorPrivate *priv; - - g_return_if_fail (object != NULL); - g_return_if_fail (IS_EVENT_EDITOR (object)); - - ee = EVENT_EDITOR (object); - priv = ee->priv; - - free_exception_clist_data (GTK_CLIST (priv->recurrence_exception_list)); - - if (priv->app) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->app), ee); - gtk_widget_destroy (priv->app); - priv->app = NULL; - } - - if (priv->comp) { - gtk_object_unref (GTK_OBJECT (priv->comp)); - priv->comp = NULL; - } - - if (priv->client) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->client), ee); - gtk_object_unref (GTK_OBJECT (priv->client)); - priv->client = NULL; - } - - if (priv->xml) { - gtk_object_unref (GTK_OBJECT (priv->xml)); - priv->xml = NULL; - } - - g_free (priv); - ee->priv = NULL; - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -/* Creates an appropriate title for the event editor dialog */ -static char * -make_title_from_comp (CalComponent *comp) -{ - char *title; - const char *type_string; - CalComponentVType type; - CalComponentText text; - - if (!comp) - return g_strdup (_("Edit Appointment")); - - type = cal_component_get_vtype (comp); - switch (type) { - case CAL_COMPONENT_EVENT: - type_string = _("Appointment - %s"); - break; - case CAL_COMPONENT_TODO: - type_string = _("Task - %s"); - break; - case CAL_COMPONENT_JOURNAL: - type_string = _("Journal entry - %s"); - break; - default: - g_message ("make_title_from_comp(): Cannot handle object of type %d", type); - return NULL; - } - - cal_component_get_summary (comp, &text); - if (text.value) { - char *summary; - summary = e_utf8_to_locale_string (text.value); - title = g_strdup_printf (type_string, summary); - g_free (summary); - } else - title = g_strdup_printf (type_string, _("No summary")); - - return title; -} - -/* Sets the event editor's window title from a calendar component */ -static void -set_title_from_comp (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv = ee->priv; - char *title; - - title = make_title_from_comp (comp); - gtk_window_set_title (GTK_WINDOW (priv->app), title); - g_free (title); -} - -/* Callback used when the recurrence weekday picker changes */ -static void -recur_weekday_picker_changed_cb (WeekdayPicker *wp, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Creates the special contents for weekly recurrences */ -static void -make_recur_weekly_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - WeekdayPicker *wp; - - priv = ee->priv; - - g_assert (GTK_BIN (priv->recurrence_special)->child == NULL); - g_assert (priv->recurrence_weekday_picker == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->recurrence_special), hbox); - - label = gtk_label_new (_("on")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - wp = WEEKDAY_PICKER (weekday_picker_new ()); - - priv->recurrence_weekday_picker = GTK_WIDGET (wp); - gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (wp), FALSE, FALSE, 0); - - gtk_widget_show_all (hbox); - - /* Set the weekdays */ - - weekday_picker_set_week_start_day (wp, calendar_config_get_week_start_day ()); - weekday_picker_set_days (wp, priv->recurrence_weekday_day_mask); - weekday_picker_set_blocked_days (wp, priv->recurrence_weekday_blocked_day_mask); - - gtk_signal_connect (GTK_OBJECT (wp), "changed", - GTK_SIGNAL_FUNC (recur_weekday_picker_changed_cb), ee); -} - -/* Creates the option menu for the monthly recurrence days */ -static GtkWidget * -make_recur_month_menu (void) -{ - static const char *options[] = { - N_("day"), - N_("Monday"), - N_("Tuesday"), - N_("Wednesday"), - N_("Thursday"), - N_("Friday"), - N_("Saturday"), - N_("Sunday") - }; - - GtkWidget *menu; - GtkWidget *omenu; - int i; - - menu = gtk_menu_new (); - - for (i = 0; i < sizeof (options) / sizeof (options[0]); i++) { - GtkWidget *item; - - item = gtk_menu_item_new_with_label (_(options[i])); - gtk_menu_append (GTK_MENU (menu), item); - gtk_widget_show (item); - } - - omenu = gtk_option_menu_new (); - gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu); - - return omenu; -} - -/* For monthly recurrences, changes the valid range of the recurrence day index - * spin button; e.g. month days are 1-31 while the valid range for a Sunday is - * the 1st through 5th of the month. - */ -static void -adjust_day_index_spin (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkAdjustment *adj; - enum month_day_options month_day; - - priv = ee->priv; - - g_assert (priv->recurrence_month_day_menu != NULL); - g_assert (GTK_IS_OPTION_MENU (priv->recurrence_month_day_menu)); - g_assert (priv->recurrence_month_index_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->recurrence_month_index_spin)); - - month_day = e_dialog_option_menu_get (priv->recurrence_month_day_menu, month_day_options_map); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->recurrence_month_index_spin)); - - switch (month_day) { - case MONTH_DAY_NTH: - adj->upper = 31; - gtk_adjustment_changed (adj); - break; - - case MONTH_DAY_MON: - case MONTH_DAY_TUE: - case MONTH_DAY_WED: - case MONTH_DAY_THU: - case MONTH_DAY_FRI: - case MONTH_DAY_SAT: - case MONTH_DAY_SUN: - adj->upper = 5; - gtk_adjustment_changed (adj); - - if (adj->value > 5) { - adj->value = 5; - gtk_adjustment_value_changed (adj); - } - - break; - - default: - g_assert_not_reached (); - } -} - -/* Callback used when the monthly day selection menu changes. We need to change - * the valid range of the day index spin button; e.g. days are 1-31 while a - * Sunday is the 1st through 5th. - */ -static void -month_day_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - adjust_day_index_spin (ee); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Callback used when the month index value changes. */ -static void -recur_month_index_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Creates the special contents for monthly recurrences */ -static void -make_recur_monthly_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - GtkAdjustment *adj; - GtkWidget *menu; - - priv = ee->priv; - - g_assert (GTK_BIN (priv->recurrence_special)->child == NULL); - g_assert (priv->recurrence_month_index_spin == NULL); - g_assert (priv->recurrence_month_day_menu == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->recurrence_special), hbox); - - label = gtk_label_new (_("on the")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - adj = GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 31, 1, 10, 10)); - priv->recurrence_month_index_spin = gtk_spin_button_new (adj, 1, 0); - gtk_box_pack_start (GTK_BOX (hbox), priv->recurrence_month_index_spin, FALSE, FALSE, 0); - - label = gtk_label_new (_("th")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - priv->recurrence_month_day_menu = make_recur_month_menu (); - gtk_box_pack_start (GTK_BOX (hbox), priv->recurrence_month_day_menu, FALSE, FALSE, 0); - - gtk_widget_show_all (hbox); - - /* Set the options */ - - e_dialog_spin_set (priv->recurrence_month_index_spin, priv->recurrence_month_index); - e_dialog_option_menu_set (priv->recurrence_month_day_menu, - priv->recurrence_month_day, - month_day_options_map); - adjust_day_index_spin (ee); - - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (recur_month_index_value_changed_cb), ee); - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_month_day_menu)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (month_day_menu_selection_done_cb), ee); -} - -/* Changes the recurrence-special widget to match the interval units. - * - * For daily recurrences: nothing. - * For weekly recurrences: weekday selector. - * For monthly recurrences: "on the" <nth> [day, Weekday] - * For yearly recurrences: nothing. - */ -static void -make_recurrence_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - icalrecurrencetype_frequency frequency; - - priv = ee->priv; - - if (GTK_BIN (priv->recurrence_special)->child != NULL) { - gtk_widget_destroy (GTK_BIN (priv->recurrence_special)->child); - - priv->recurrence_weekday_picker = NULL; - priv->recurrence_month_index_spin = NULL; - priv->recurrence_month_day_menu = NULL; - } - - frequency = e_dialog_option_menu_get (priv->recurrence_interval_unit, recur_freq_map); - - switch (frequency) { - case ICAL_DAILY_RECURRENCE: - gtk_widget_hide (priv->recurrence_special); - break; - - case ICAL_WEEKLY_RECURRENCE: - make_recur_weekly_special (ee); - gtk_widget_show (priv->recurrence_special); - break; - - case ICAL_MONTHLY_RECURRENCE: - make_recur_monthly_special (ee); - gtk_widget_show (priv->recurrence_special); - break; - - case ICAL_YEARLY_RECURRENCE: - gtk_widget_hide (priv->recurrence_special); - break; - - default: - g_assert_not_reached (); - } -} - -/* Callback used when the ending-until date editor changes */ -static void -recur_ending_until_changed_cb (EDateEdit *de, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Creates the special contents for "ending until" (end date) recurrences */ -static void -make_recur_ending_until_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - EDateEdit *de; - - priv = ee->priv; - - g_assert (GTK_BIN (priv->recurrence_ending_special)->child == NULL); - g_assert (priv->recurrence_ending_date_edit == NULL); - - /* Create the widget */ - - priv->recurrence_ending_date_edit = date_edit_new (TRUE, FALSE); - de = E_DATE_EDIT (priv->recurrence_ending_date_edit); - - gtk_container_add (GTK_CONTAINER (priv->recurrence_ending_special), GTK_WIDGET (de)); - gtk_widget_show_all (GTK_WIDGET (de)); - - /* Set the value */ - - e_date_edit_set_time (de, priv->recurrence_ending_date); - - gtk_signal_connect (GTK_OBJECT (de), "changed", - GTK_SIGNAL_FUNC (recur_ending_until_changed_cb), ee); -} - -/* Callback used when the ending-count value changes */ -static void -recur_ending_count_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Creates the special contents for the occurrence count case */ -static void -make_recur_ending_count_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - GtkAdjustment *adj; - - priv = ee->priv; - - g_assert (GTK_BIN (priv->recurrence_ending_special)->child == NULL); - g_assert (priv->recurrence_ending_count_spin == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->recurrence_ending_special), hbox); - - adj = GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 10000, 1, 10, 10)); - priv->recurrence_ending_count_spin = gtk_spin_button_new (adj, 1, 0); - gtk_box_pack_start (GTK_BOX (hbox), priv->recurrence_ending_count_spin, FALSE, FALSE, 0); - - label = gtk_label_new (_("occurrences")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - gtk_widget_show_all (hbox); - - /* Set the values */ - - e_dialog_spin_set (priv->recurrence_ending_count_spin, - priv->recurrence_ending_count); - - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (recur_ending_count_value_changed_cb), ee); -} - -enum ending_type { - ENDING_FOR, - ENDING_UNTIL, - ENDING_FOREVER -}; - -static const int ending_types_map[] = { - ENDING_FOR, - ENDING_UNTIL, - ENDING_FOREVER, - -1 -}; - -/* Changes the recurrence-ending-special widget to match the ending date option. - * - * For: <n> [days, weeks, months, years, occurrences] - * Until: <date selector> - * Forever: nothing. - */ -static void -make_recurrence_ending_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - enum ending_type ending_type; - - priv = ee->priv; - - if (GTK_BIN (priv->recurrence_ending_special)->child != NULL) { - gtk_widget_destroy (GTK_BIN (priv->recurrence_ending_special)->child); - - priv->recurrence_ending_date_edit = NULL; - priv->recurrence_ending_count_spin = NULL; - } - - ending_type = e_dialog_option_menu_get (priv->recurrence_ending_menu, ending_types_map); - - switch (ending_type) { - case ENDING_FOR: - make_recur_ending_count_special (ee); - gtk_widget_show (priv->recurrence_ending_special); - break; - - case ENDING_UNTIL: - make_recur_ending_until_special (ee); - gtk_widget_show (priv->recurrence_ending_special); - break; - - case ENDING_FOREVER: - gtk_widget_hide (priv->recurrence_ending_special); - break; - - default: - g_assert_not_reached (); - } -} - -enum recur_type { - RECUR_NONE, - RECUR_SIMPLE, - RECUR_CUSTOM -}; - -static const int recur_type_map[] = { - RECUR_NONE, - RECUR_SIMPLE, - RECUR_CUSTOM, - -1 -}; - -/* Sensitizes the recurrence widgets based on the state of the recurrence type - * radio group. - */ -static void -sensitize_recur_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - enum recur_type type; - GtkWidget *label; - - priv = ee->priv; - - type = e_dialog_radio_get (priv->recurrence_none, recur_type_map); - - if (GTK_BIN (priv->recurrence_custom_warning_bin)->child) - gtk_widget_destroy (GTK_BIN (priv->recurrence_custom_warning_bin)->child); - - switch (type) { - case RECUR_NONE: - gtk_widget_set_sensitive (priv->recurrence_params, FALSE); - gtk_widget_show (priv->recurrence_params); - gtk_widget_hide (priv->recurrence_custom_warning_bin); - break; - - case RECUR_SIMPLE: - gtk_widget_set_sensitive (priv->recurrence_params, TRUE); - gtk_widget_show (priv->recurrence_params); - gtk_widget_hide (priv->recurrence_custom_warning_bin); - break; - - case RECUR_CUSTOM: - gtk_widget_set_sensitive (priv->recurrence_params, FALSE); - gtk_widget_hide (priv->recurrence_params); - - label = gtk_label_new (_("This appointment contains recurrences that Evolution " - "cannot edit.")); - gtk_container_add (GTK_CONTAINER (priv->recurrence_custom_warning_bin), label); - gtk_widget_show_all (priv->recurrence_custom_warning_bin); - break; - - default: - g_assert_not_reached (); - } -} - -/* Callback used when one of the recurrence type radio buttons is toggled. We - * enable or the recurrence parameters. - */ -static void -recurrence_type_toggled_cb (GtkToggleButton *toggle, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - - event_editor_set_changed (ee, TRUE); - - if (toggle->active) { - sensitize_recur_widgets (ee); - preview_recur (ee); - } -} - -/* Callback used when the recurrence interval value spin button changes. */ -static void -recur_interval_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Callback used when the recurrence interval option menu changes. We need to - * change the contents of the recurrence special widget. - */ -static void -recur_interval_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - make_recurrence_special (ee); - preview_recur (ee); -} - -/* Callback used when the recurrence ending option menu changes. We need to - * change the contents of the ending special widget. - */ -static void -recur_ending_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - make_recurrence_ending_special (ee); - preview_recur (ee); -} - -/* Gets the widgets from the XML file and returns if they are all available. - * For the widgets whose values can be simply set with e-dialog-utils, it does - * that as well. - */ -static gboolean -get_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - -#define GW(name) glade_xml_get_widget (priv->xml, name) - - priv->app = GW ("event-editor-dialog"); - - priv->general_summary = GW ("general-summary"); - - priv->start_time = GW ("start-time"); - priv->end_time = GW ("end-time"); - priv->all_day_event = GW ("all-day-event"); - - priv->description = GW ("description"); - - priv->classification_public = GW ("classification-public"); - priv->classification_private = GW ("classification-private"); - priv->classification_confidential = GW ("classification-confidential"); - - priv->contacts_btn = GW ("contacts-button"); - priv->contacts = GW ("contacts"); - - priv->categories_btn = GW ("categories-button"); - priv->categories = GW ("categories"); - - priv->reminder_summary = GW ("reminder-summary"); - priv->reminder_starting_date = GW ("reminder-starting-date"); - - priv->reminder_list = GW ("reminder-list"); - priv->reminder_add = GW ("reminder-add"); - priv->reminder_delete = GW ("reminder-delete"); - - priv->reminder_action = GW ("reminder-action"); - priv->reminder_interval_value = GW ("reminder-interval-value"); - priv->reminder_value_units = GW ("reminder-value-units"); - priv->reminder_relative = GW ("reminder-relative"); - priv->reminder_time = GW ("reminder-time"); - - priv->recurrence_summary = GW ("recurrence-summary"); - priv->recurrence_starting_date = GW ("recurrence-starting-date"); - - priv->recurrence_none = GW ("recurrence-none"); - priv->recurrence_simple = GW ("recurrence-simple"); - priv->recurrence_custom = GW ("recurrence-custom"); - priv->recurrence_params = GW ("recurrence-params"); - - priv->recurrence_interval_value = GW ("recurrence-interval-value"); - priv->recurrence_interval_unit = GW ("recurrence-interval-unit"); - priv->recurrence_special = GW ("recurrence-special"); - priv->recurrence_ending_menu = GW ("recurrence-ending-menu"); - priv->recurrence_ending_special = GW ("recurrence-ending-special"); - priv->recurrence_custom_warning_bin = GW ("recurrence-custom-warning-bin"); - - priv->recurrence_exception_date = GW ("recurrence-exception-date"); - priv->recurrence_exception_list = GW ("recurrence-exception-list"); - priv->recurrence_exception_add = GW ("recurrence-exception-add"); - priv->recurrence_exception_modify = GW ("recurrence-exception-modify"); - priv->recurrence_exception_delete = GW ("recurrence-exception-delete"); - - priv->recurrence_preview_bin = GW ("recurrence-preview-bin"); - -#undef GW - - return (priv->app - && priv->general_summary - && priv->start_time - && priv->end_time - && priv->all_day_event - && priv->description - && priv->classification_public - && priv->classification_private - && priv->classification_confidential - && priv->contacts_btn - && priv->contacts - && priv->categories_btn - && priv->categories - && priv->reminder_summary - && priv->reminder_starting_date - && priv->reminder_list - && priv->reminder_add - && priv->reminder_delete - && priv->reminder_action - && priv->reminder_interval_value - && priv->reminder_value_units - && priv->reminder_relative - && priv->reminder_time - && priv->recurrence_summary - && priv->recurrence_starting_date - && priv->recurrence_none - && priv->recurrence_simple - && priv->recurrence_custom - && priv->recurrence_params - && priv->recurrence_interval_value - && priv->recurrence_interval_unit - && priv->recurrence_special - && priv->recurrence_ending_menu - && priv->recurrence_ending_special - && priv->recurrence_custom_warning_bin - && priv->recurrence_exception_date - && priv->recurrence_exception_list - && priv->recurrence_exception_add - && priv->recurrence_exception_modify - && priv->recurrence_exception_delete - && priv->recurrence_preview_bin); -} - -/* Syncs the contents of two entry widgets, while blocking signals from each - * other. - */ -static void -sync_entries (EventEditor *ee, GtkEditable *source, GtkEditable *dest) -{ - char *str; - - gtk_signal_handler_block_by_data (GTK_OBJECT (dest), ee); - - str = gtk_editable_get_chars (source, 0, -1); - gtk_entry_set_text (GTK_ENTRY (dest), str); - g_free (str); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (dest), ee); -} - -/* Syncs the contents of two date editor widgets, while blocking signals on the - * specified data. - */ -static void -sync_date_edits (EventEditor *ee, EDateEdit *source, EDateEdit *dest) -{ - time_t t; - - gtk_signal_handler_block_by_data (GTK_OBJECT (dest), ee); - - t = e_date_edit_get_time (source); - e_date_edit_set_time (dest, t); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (dest), ee); -} - -/* Callback used when one of the general or recurrence summary entries change; - * we sync the other entry to it. - */ -static void -summary_changed_cb (GtkEditable *editable, gpointer data) -{ - EventEditor *ee; - EventEditorPrivate *priv; - - ee = EVENT_EDITOR (data); - priv = ee->priv; - - if (editable != GTK_EDITABLE (priv->general_summary)) - sync_entries (ee, editable, GTK_EDITABLE (priv->general_summary)); - if (editable != GTK_EDITABLE (priv->reminder_summary)) - sync_entries (ee, editable, GTK_EDITABLE (priv->reminder_summary)); - if (editable != GTK_EDITABLE (priv->recurrence_summary)) - sync_entries (ee, editable, GTK_EDITABLE (priv->recurrence_summary)); -} - -/* Callback used when one of the general or recurrence starting date widgets - * change; we sync the other date editor to it. - */ -static void -start_date_changed_cb (EDateEdit *de, gpointer data) -{ - EventEditor *ee; - EventEditorPrivate *priv; - - ee = EVENT_EDITOR (data); - priv = ee->priv; - - if (de != E_DATE_EDIT (priv->start_time)) - sync_date_edits (ee,de, E_DATE_EDIT (priv->start_time)); - if (de != E_DATE_EDIT (priv->reminder_starting_date)) - sync_date_edits (ee, de, E_DATE_EDIT (priv->reminder_starting_date)); - if (de != E_DATE_EDIT (priv->recurrence_starting_date)) - sync_date_edits (ee, de, E_DATE_EDIT (priv->recurrence_starting_date)); -} - -/* Callback used when the displayed date range in the recurrence preview - * calendar changes. - */ -static void -recur_preview_date_range_changed_cb (ECalendarItem *item, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - preview_recur (ee); -} - -/* Hooks the widget signals */ -static void -init_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkWidget *menu; - GtkAdjustment *adj; - ECalendar *ecal; - - priv = ee->priv; - - /* Summary in the main, reminder and recurrence pages */ - gtk_signal_connect (GTK_OBJECT (priv->general_summary), "changed", - GTK_SIGNAL_FUNC (summary_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->reminder_summary), "changed", - GTK_SIGNAL_FUNC (summary_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_summary), "changed", - GTK_SIGNAL_FUNC (summary_changed_cb), ee); - - /* Categories button */ - gtk_signal_connect (GTK_OBJECT (priv->categories_btn), "clicked", - GTK_SIGNAL_FUNC (categories_clicked), ee); - - /* Start dates in the main and recurrence pages */ - - gtk_signal_connect (GTK_OBJECT (priv->start_time), "changed", - GTK_SIGNAL_FUNC (start_date_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->reminder_starting_date), "changed", - GTK_SIGNAL_FUNC (start_date_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_starting_date), "changed", - GTK_SIGNAL_FUNC (start_date_changed_cb), ee); - - /* Start and end times */ - - gtk_signal_connect (GTK_OBJECT (priv->start_time), "changed", - GTK_SIGNAL_FUNC (date_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->end_time), "changed", - GTK_SIGNAL_FUNC (date_changed_cb), ee); - - gtk_signal_connect (GTK_OBJECT (priv->all_day_event), "toggled", - GTK_SIGNAL_FUNC (set_all_day), ee); - - /* Reminder buttons */ - - gtk_signal_connect (GTK_OBJECT (priv->reminder_add), "clicked", - GTK_SIGNAL_FUNC (reminder_add_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->reminder_delete), "clicked", - GTK_SIGNAL_FUNC (reminder_delete_cb), ee); - - /* Recurrence preview */ - - priv->recurrence_preview_calendar = e_calendar_new (); - ecal = E_CALENDAR (priv->recurrence_preview_calendar); - gtk_signal_connect (GTK_OBJECT (ecal->calitem), "date_range_changed", - GTK_SIGNAL_FUNC (recur_preview_date_range_changed_cb), ee); - calendar_config_configure_e_calendar (ecal); - e_calendar_item_set_max_days_sel (ecal->calitem, 0); - gtk_container_add (GTK_CONTAINER (priv->recurrence_preview_bin), - priv->recurrence_preview_calendar); - gtk_widget_show (priv->recurrence_preview_calendar); - - /* Recurrence types */ - - gtk_signal_connect (GTK_OBJECT (priv->recurrence_none), "toggled", - GTK_SIGNAL_FUNC (recurrence_type_toggled_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_simple), "toggled", - GTK_SIGNAL_FUNC (recurrence_type_toggled_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_custom), "toggled", - GTK_SIGNAL_FUNC (recurrence_type_toggled_cb), ee); - - /* Recurrence interval */ - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->recurrence_interval_value)); - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (recur_interval_value_changed_cb), ee); - - /* Recurrence units */ - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (recur_interval_selection_done_cb), ee); - - /* Recurrence ending */ - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_ending_menu)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (recur_ending_selection_done_cb), ee); - - /* Exception buttons */ - - gtk_signal_connect (GTK_OBJECT (priv->recurrence_exception_add), "clicked", - GTK_SIGNAL_FUNC (recurrence_exception_add_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_exception_modify), "clicked", - GTK_SIGNAL_FUNC (recurrence_exception_modify_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_exception_delete), "clicked", - GTK_SIGNAL_FUNC (recurrence_exception_delete_cb), ee); - - /* Selections in the exceptions list */ - - gtk_signal_connect (GTK_OBJECT (priv->recurrence_exception_list), "select_row", - GTK_SIGNAL_FUNC (recurrence_exception_select_row_cb), ee); - - /* - * Connect the default signal handler to use to make sure the "changed" - * field gets set whenever a field is changed. - */ - - /* Appointment Page */ - gtk_signal_connect (GTK_OBJECT (priv->general_summary), "changed", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->description), "changed", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->classification_public), "toggled", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->classification_private), "toggled", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->classification_confidential), "toggled", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->categories), "changed", - GTK_SIGNAL_FUNC (field_changed), ee); - - /* FIXME: we do not support these fields yet, so we disable them */ - - gtk_widget_set_sensitive (priv->contacts_btn, FALSE); - gtk_widget_set_sensitive (priv->contacts, FALSE); -} - -static const int classification_map[] = { - CAL_COMPONENT_CLASS_PUBLIC, - CAL_COMPONENT_CLASS_PRIVATE, - CAL_COMPONENT_CLASS_CONFIDENTIAL, - -1 -}; - -static const int month_pos_map[] = { 0, 1, 2, 3, 4, -1 }; -static const int weekday_map[] = { 0, 1, 2, 3, 4, 5, 6, -1 }; - -/* Fills the widgets with default values */ -static void -clear_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - time_t now; - GtkAdjustment *adj; - GtkWidget *menu; - - priv = ee->priv; - - now = time (NULL); - - /* Summary, description */ - - e_dialog_editable_set (priv->general_summary, NULL); /* will also change recur summary */ - e_dialog_editable_set (priv->description, NULL); - - /* Start and end times */ - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), ee); - - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), now); /* will set recur start too */ - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), now); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), ee); - - check_all_day (ee); - - /* Classification */ - - e_dialog_radio_set (priv->classification_public, - CAL_COMPONENT_CLASS_PRIVATE, classification_map); - - /* Recurrences */ - - priv->recurrence_weekday_day_mask = 0; - - priv->recurrence_month_index = 1; - priv->recurrence_month_day = MONTH_DAY_NTH; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - e_dialog_radio_set (priv->recurrence_none, RECUR_NONE, recur_type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->recurrence_interval_value)); - gtk_signal_handler_block_by_data (GTK_OBJECT (adj), ee); - e_dialog_spin_set (priv->recurrence_interval_value, 1); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), ee); - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_DAILY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - - priv->recurrence_ending_date = time (NULL); - priv->recurrence_ending_count = 1; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_ending_menu)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_ending_menu, ENDING_FOREVER, - ending_types_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - - /* Exceptions list */ - - free_exception_clist_data (GTK_CLIST (priv->recurrence_exception_list)); -} - -/* Fills the recurrence ending date widgets with the values from the calendar - * component. - */ -static void -fill_ending_date (EventEditor *ee, struct icalrecurrencetype *r) -{ - EventEditorPrivate *priv; - GtkWidget *menu; - - priv = ee->priv; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_ending_menu)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - - if (r->count == 0) { - if (r->until.year == 0) { - /* Forever */ - - e_dialog_option_menu_set (priv->recurrence_ending_menu, - ENDING_FOREVER, - ending_types_map); - } else { - /* Ending date */ - - priv->recurrence_ending_date = icaltime_as_timet (r->until); - e_dialog_option_menu_set (priv->recurrence_ending_menu, - ENDING_UNTIL, - ending_types_map); - } - } else { - /* Count of occurrences */ - - priv->recurrence_ending_count = r->count; - e_dialog_option_menu_set (priv->recurrence_ending_menu, - ENDING_FOR, - ending_types_map); - } - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - - make_recurrence_ending_special (ee); -} - -/* Counts the number of elements in the by_xxx fields of an icalrecurrencetype */ -static int -count_by_xxx (short *field, int max_elements) -{ - int i; - - for (i = 0; i < max_elements; i++) - if (field[i] == ICAL_RECURRENCE_ARRAY_MAX) - break; - - return i; -} - -/* Re-tags the recurrence preview calendar based on the current information of - * the event editor. - */ -static void -preview_recur (EventEditor *ee) -{ - EventEditorPrivate *priv; - CalComponent *comp; - CalComponentDateTime cdt; - GSList *l; - - priv = ee->priv; - g_assert (priv->comp != NULL); - - /* Create a scratch component with the start/end and - * recurrence/excepttion information from the one we are editing. - */ - - comp = cal_component_new (); - cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT); - - cal_component_get_dtstart (priv->comp, &cdt); - cal_component_set_dtstart (comp, &cdt); - cal_component_free_datetime (&cdt); - - cal_component_get_dtend (priv->comp, &cdt); - cal_component_set_dtend (comp, &cdt); - cal_component_free_datetime (&cdt); - - cal_component_get_exdate_list (priv->comp, &l); - cal_component_set_exdate_list (comp, l); - cal_component_free_exdate_list (l); - - cal_component_get_exrule_list (priv->comp, &l); - cal_component_set_exrule_list (comp, l); - cal_component_free_recur_list (l); - - cal_component_get_rdate_list (priv->comp, &l); - cal_component_set_rdate_list (comp, l); - cal_component_free_period_list (l); - - cal_component_get_rrule_list (priv->comp, &l); - cal_component_set_rrule_list (comp, l); - cal_component_free_recur_list (l); - - recur_to_comp_object (ee, comp); - - tag_calendar_by_comp (E_CALENDAR (priv->recurrence_preview_calendar), comp); - gtk_object_unref (GTK_OBJECT (comp)); -} - -/* Fills in the exception widgets with the data from the calendar component */ -static void -fill_exception_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - GSList *list, *l; - gboolean added; - - priv = ee->priv; - g_assert (priv->comp != NULL); - - /* Exceptions list */ - - cal_component_get_exdate_list (priv->comp, &list); - - added = FALSE; - - for (l = list; l; l = l->next) { - CalComponentDateTime *cdt; - time_t ext; - - added = TRUE; - - cdt = l->data; - ext = icaltime_as_timet (*cdt->value); - append_exception (ee, ext); - } - - cal_component_free_exdate_list (list); - - if (added) - gtk_clist_select_row (GTK_CLIST (priv->recurrence_exception_list), 0, 0); -} - -/* Computes a weekday mask for the start day of a calendar component, for use in - * a WeekdayPicker widget. - */ -static guint8 -get_start_weekday_mask (CalComponent *comp) -{ - CalComponentDateTime dt; - guint8 retval; - - cal_component_get_dtstart (comp, &dt); - - if (dt.value) { - time_t t; - struct tm tm; - - t = icaltime_as_timet (*dt.value); - tm = *localtime (&t); - - retval = 0x1 << tm.tm_wday; - } else - retval = 0; - - cal_component_free_datetime (&dt); - - return retval; -} - -/* Sets some sane defaults for the data sources for the recurrence special - * widgets, even if they will not be used immediately. - */ -static void -set_recur_special_defaults (EventEditor *ee) -{ - EventEditorPrivate *priv; - guint8 mask; - - priv = ee->priv; - - mask = get_start_weekday_mask (priv->comp); - - priv->recurrence_weekday_day_mask = mask; - priv->recurrence_weekday_blocked_day_mask = mask; -} - -static char * -get_alarm_duration_string (struct icaldurationtype *duration) -{ - GString *string = g_string_new (NULL); - char *ret; - - if (duration->days > 1) - g_string_sprintf (string, _(" %d days"), duration->days); - else if (duration->days == 1) - g_string_append (string, _(" 1 day")); - - if (duration->weeks > 1) - g_string_sprintf (string, _(" %d weeks"), duration->weeks); - else if (duration->weeks == 1) - g_string_append (string, _(" 1 week")); - - if (duration->hours > 1) - g_string_sprintf (string, _(" %d hours"), duration->hours); - else if (duration->hours == 1) - g_string_append (string, _(" 1 hour")); - - if (duration->minutes > 1) - g_string_sprintf (string, _(" %d minutes"), duration->minutes); - else if (duration->minutes == 1) - g_string_append (string, _(" 1 minute")); - - if (duration->seconds > 1) - g_string_sprintf (string, _(" %d seconds"), duration->seconds); - else if (duration->seconds == 1) - g_string_append (string, _(" 1 second")); - - ret = string->str; - g_string_free (string, FALSE); - - return ret; -} - -static char * -get_alarm_string (CalComponentAlarm *alarm) -{ - CalAlarmAction action; - CalAlarmTrigger trigger; - char string[256]; - char *dur; - - string [0] = '\0'; - - cal_component_alarm_get_action (alarm, &action); - cal_component_alarm_get_trigger (alarm, &trigger); - - switch (action) { - case CAL_ALARM_AUDIO: - strcat (string, _("Play a sound")); - break; - case CAL_ALARM_DISPLAY: - strcat (string, _("Show a dialog")); - break; - case CAL_ALARM_EMAIL: - strcat (string, _("Send an email")); - break; - case CAL_ALARM_PROCEDURE: - strcat (string, _("Run a program")); - break; - case CAL_ALARM_NONE: - case CAL_ALARM_UNKNOWN: - strcat (string, _("Unknown")); - break; - } - - switch (trigger.type) { - case CAL_ALARM_TRIGGER_RELATIVE_START: - dur = get_alarm_duration_string (&trigger.u.rel_duration); - strcat (string, dur); - g_free (dur); - - if (trigger.u.rel_duration.is_neg) - strcat (string, _(" before start of appointment")); - else - strcat (string, _(" after start of appointment")); - break; - case CAL_ALARM_TRIGGER_RELATIVE_END: - dur = get_alarm_duration_string (&trigger.u.rel_duration); - strcat (string, dur); - g_free (dur); - - if (trigger.u.rel_duration.is_neg) - strcat (string, _(" before end of appointment")); - else - strcat (string, _(" after end of appointment")); - break; - case CAL_ALARM_TRIGGER_NONE: - case CAL_ALARM_TRIGGER_ABSOLUTE: - strcat (string, _("Unknown")); - break; - } - - return g_strdup (string); -} - -static void -fill_reminder_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - GList *alarms, *l; - GtkCList *clist; - - int row = 0; - - priv = ee->priv; - g_assert (priv->comp != NULL); - - if (!cal_component_has_alarms (priv->comp)) - return; - - alarms = cal_component_get_alarm_uids (priv->comp); - - clist = GTK_CLIST (priv->reminder_list); - for (l = alarms; l != NULL; l = l->next, row++) { - CalComponentAlarm *ca = cal_component_get_alarm (priv->comp, l->data); - - /* Add it to the clist */ - append_reminder (ee, ca, EXISTING_ALARM); - } - cal_obj_uid_list_free (alarms); -} - -/* Fills in the recurrence widgets with the values from the calendar component. - * This function is particularly tricky because it has to discriminate between - * recurrences we support for editing and the ones we don't. We only support at - * most one recurrence rule; no rdates or exrules (exdates are handled just fine - * elsewhere). - */ -static void -fill_recurrence_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - GSList *rrule_list; - int len; - struct icalrecurrencetype *r; - int n_by_second, n_by_minute, n_by_hour; - int n_by_day, n_by_month_day, n_by_year_day; - int n_by_week_no, n_by_month, n_by_set_pos; - GtkWidget *menu; - GtkAdjustment *adj; - - priv = ee->priv; - g_assert (priv->comp != NULL); - - fill_exception_widgets (ee); - - /* Set up defaults for the special widgets */ - - set_recur_special_defaults (ee); - - /* No recurrences? */ - - if (!cal_component_has_rdates (priv->comp) - && !cal_component_has_rrules (priv->comp) - && !cal_component_has_exrules (priv->comp)) { - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - e_dialog_radio_set (priv->recurrence_none, RECUR_NONE, recur_type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - - gtk_widget_set_sensitive (priv->recurrence_custom, FALSE); - - sensitize_recur_widgets (ee); - preview_recur (ee); - return; - } - - /* See if it is a custom set we don't support */ - - cal_component_get_rrule_list (priv->comp, &rrule_list); - len = g_slist_length (rrule_list); - if (len > 1 - || cal_component_has_rdates (priv->comp) - || cal_component_has_exrules (priv->comp)) - goto custom; - - /* Down to one rule, so test that one */ - - g_assert (len == 1); - r = rrule_list->data; - - /* Any funky frequency? */ - - if (r->freq == ICAL_SECONDLY_RECURRENCE - || r->freq == ICAL_MINUTELY_RECURRENCE - || r->freq == ICAL_HOURLY_RECURRENCE) - goto custom; - - /* Any funky shit? */ - -#define N_HAS_BY(field) (count_by_xxx (field, sizeof (field) / sizeof (field[0]))) - - n_by_second = N_HAS_BY (r->by_second); - n_by_minute = N_HAS_BY (r->by_minute); - n_by_hour = N_HAS_BY (r->by_hour); - n_by_day = N_HAS_BY (r->by_day); - n_by_month_day = N_HAS_BY (r->by_month_day); - n_by_year_day = N_HAS_BY (r->by_year_day); - n_by_week_no = N_HAS_BY (r->by_week_no); - n_by_month = N_HAS_BY (r->by_month); - n_by_set_pos = N_HAS_BY (r->by_set_pos); - - if (n_by_second != 0 - || n_by_minute != 0 - || n_by_hour != 0) - goto custom; - - /* Filter the funky shit based on the frequency; if there is nothing - * weird we can actually set the widgets. - */ - - switch (r->freq) { - case ICAL_DAILY_RECURRENCE: - if (n_by_day != 0 - || n_by_month_day != 0 - || n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos != 0) - goto custom; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_DAILY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - break; - - case ICAL_WEEKLY_RECURRENCE: { - int i; - guint8 day_mask; - - if (n_by_month_day != 0 - || n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos != 0) - goto custom; - - day_mask = 0; - - for (i = 0; i < 8 && r->by_day[i] != ICAL_RECURRENCE_ARRAY_MAX; i++) { - enum icalrecurrencetype_weekday weekday; - int pos; - - weekday = icalrecurrencetype_day_day_of_week (r->by_day[i]); - pos = icalrecurrencetype_day_position (r->by_day[i]); - - if (pos != 0) - goto custom; - - switch (weekday) { - case ICAL_SUNDAY_WEEKDAY: - day_mask |= 1 << 0; - break; - - case ICAL_MONDAY_WEEKDAY: - day_mask |= 1 << 1; - break; - - case ICAL_TUESDAY_WEEKDAY: - day_mask |= 1 << 2; - break; - - case ICAL_WEDNESDAY_WEEKDAY: - day_mask |= 1 << 3; - break; - - case ICAL_THURSDAY_WEEKDAY: - day_mask |= 1 << 4; - break; - - case ICAL_FRIDAY_WEEKDAY: - day_mask |= 1 << 5; - break; - - case ICAL_SATURDAY_WEEKDAY: - day_mask |= 1 << 6; - break; - - default: - break; - } - } - - priv->recurrence_weekday_day_mask = day_mask; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_WEEKLY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - break; - } - - case ICAL_MONTHLY_RECURRENCE: - if (n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos != 0) - goto custom; - - if (n_by_month_day == 1) { - int nth; - - nth = r->by_month_day[0]; - if (nth < 1) - goto custom; - - priv->recurrence_month_index = nth; - priv->recurrence_month_day = MONTH_DAY_NTH; - } else if (n_by_day == 1) { - enum icalrecurrencetype_weekday weekday; - int pos; - enum month_day_options month_day; - - weekday = icalrecurrencetype_day_day_of_week (r->by_day[0]); - pos = icalrecurrencetype_day_position (r->by_day[0]); - - if (pos < 1) - goto custom; - - switch (weekday) { - case ICAL_MONDAY_WEEKDAY: - month_day = MONTH_DAY_MON; - break; - - case ICAL_TUESDAY_WEEKDAY: - month_day = MONTH_DAY_TUE; - break; - - case ICAL_WEDNESDAY_WEEKDAY: - month_day = MONTH_DAY_WED; - break; - - case ICAL_THURSDAY_WEEKDAY: - month_day = MONTH_DAY_THU; - break; - - case ICAL_FRIDAY_WEEKDAY: - month_day = MONTH_DAY_FRI; - break; - - case ICAL_SATURDAY_WEEKDAY: - month_day = MONTH_DAY_SAT; - break; - - case ICAL_SUNDAY_WEEKDAY: - month_day = MONTH_DAY_SUN; - break; - - default: - goto custom; - } - - priv->recurrence_month_index = pos; - priv->recurrence_month_day = month_day; - } else - goto custom; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_MONTHLY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - break; - - case ICAL_YEARLY_RECURRENCE: - if (n_by_day != 0 - || n_by_month_day != 0 - || n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos != 0) - goto custom; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_YEARLY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - break; - - default: - goto custom; - } - - /* If we got here it means it is a simple recurrence */ - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - e_dialog_radio_set (priv->recurrence_simple, RECUR_SIMPLE, recur_type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - - gtk_widget_set_sensitive (priv->recurrence_custom, FALSE); - - sensitize_recur_widgets (ee); - make_recurrence_special (ee); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->recurrence_interval_value)); - gtk_signal_handler_block_by_data (GTK_OBJECT (adj), ee); - e_dialog_spin_set (priv->recurrence_interval_value, r->interval); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), ee); - - fill_ending_date (ee, r); - - goto out; - - custom: - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - e_dialog_radio_set (priv->recurrence_custom, RECUR_CUSTOM, recur_type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - - gtk_widget_set_sensitive (priv->recurrence_custom, TRUE); - sensitize_recur_widgets (ee); - - out: - - cal_component_free_recur_list (rrule_list); - preview_recur (ee); -} - -/* Fills in the widgets with the value from the calendar component */ -static void -fill_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - CalComponentText text; - CalComponentClassification cl; - CalComponentDateTime d; - GSList *l; - time_t dtstart, dtend; - const char *categories; - - priv = ee->priv; - - clear_widgets (ee); - - if (!priv->comp) - return; - - /* Summary, description(s) */ - - cal_component_get_summary (priv->comp, &text); - e_dialog_editable_set (priv->general_summary, text.value); /* will also set recur summary */ - - cal_component_get_description_list (priv->comp, &l); - if (l) { - text = *(CalComponentText *)l->data; - e_dialog_editable_set (priv->description, text.value); - } - cal_component_free_text_list (l); - - /* Start and end times */ - - /* All-day events are inclusive, i.e. if the end date shown is 2nd Feb - then the event includes all of the 2nd Feb. We would normally show - 3rd Feb as the end date, since it really ends at midnight on 3rd, - so we have to subtract a day so we only show the 2nd. */ - cal_component_get_dtstart (priv->comp, &d); - dtstart = icaltime_as_timet (*d.value); - cal_component_free_datetime (&d); - - cal_component_get_dtend (priv->comp, &d); - dtend = icaltime_as_timet (*d.value); - cal_component_free_datetime (&d); - - if (time_day_begin (dtstart) == dtstart - && time_day_begin (dtend) == dtend) { - dtend = time_add_day (dtend, -1); - } - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), ee); - - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), dtstart); - e_date_edit_set_time (E_DATE_EDIT (priv->reminder_starting_date), dtstart); - e_date_edit_set_time (E_DATE_EDIT (priv->recurrence_starting_date), dtstart); - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), dtend); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), ee); - - check_all_day (ee); - - /* Classification */ - - cal_component_get_classification (priv->comp, &cl); - - switch (cl) { - case CAL_COMPONENT_CLASS_PUBLIC: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PUBLIC, - classification_map); - case CAL_COMPONENT_CLASS_PRIVATE: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PRIVATE, - classification_map); - case CAL_COMPONENT_CLASS_CONFIDENTIAL: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_CONFIDENTIAL, - classification_map); - default: - /* What do do? We can't g_assert_not_reached() since it is a - * value from an external file. - */ - } - - /* Categories */ - cal_component_get_categories (priv->comp, &categories); - e_dialog_editable_set (priv->categories, categories); - - /* Reminders */ - fill_reminder_widgets (ee); - - /* Recurrences */ - fill_recurrence_widgets (ee); - - /* Do this last, since the callbacks will set it to TRUE. */ - event_editor_set_changed (ee, FALSE); -} - - -/** - * event_editor_update_widgets: - * @ee: An event editor. - * - * Causes an event editor dialog to re-read the values of its calendar component - * object. This function should be used if the #CalComponent is changed by - * external means while it is open in the editor. - **/ -void -event_editor_update_widgets (EventEditor *ee) -{ - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - fill_widgets (ee); -} - - - -/* Decode the radio button group for classifications */ -static CalComponentClassification -classification_get (GtkWidget *widget) -{ - return e_dialog_radio_get (widget, classification_map); -} - -/* Encondes a position/weekday pair into the proper format for - * icalrecurrencetype.by_day. - */ -static short -nth_weekday (int pos, icalrecurrencetype_weekday weekday) -{ - g_assert (pos > 0 && pos <= 5); - - return (pos << 3) | (int) weekday; -} - -static void -reminder_to_comp_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - GtkCList *reminder_list; - ReminderData *rdata; - int i; - - priv = ee->priv; - - reminder_list = GTK_CLIST (priv->reminder_list); - for (i = 0; i < reminder_list->rows; i++) { - rdata = gtk_clist_get_row_data (reminder_list, i); - if (rdata->status == NEW_ALARM) - cal_component_add_alarm (priv->comp, rdata->alarm); - g_free (rdata); - } -} - -/* Gets the simple recurrence data from the recurrence widgets and stores it in - * the calendar component object. - */ -static void -simple_recur_to_comp_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - struct icalrecurrencetype r; - GSList l; - enum ending_type ending_type; - - priv = ee->priv; - - icalrecurrencetype_clear (&r); - - /* Frequency, interval, week start */ - - r.freq = e_dialog_option_menu_get (priv->recurrence_interval_unit, recur_freq_map); - r.interval = e_dialog_spin_get_int (priv->recurrence_interval_value); - r.week_start = ICAL_SUNDAY_WEEKDAY + calendar_config_get_week_start_day (); - - /* Frequency-specific data */ - - switch (r.freq) { - case ICAL_DAILY_RECURRENCE: - /* Nothing else is required */ - break; - - case ICAL_WEEKLY_RECURRENCE: { - guint8 day_mask; - int i; - - g_assert (GTK_BIN (priv->recurrence_special)->child != NULL); - g_assert (priv->recurrence_weekday_picker != NULL); - g_assert (IS_WEEKDAY_PICKER (priv->recurrence_weekday_picker)); - - day_mask = weekday_picker_get_days (WEEKDAY_PICKER (priv->recurrence_weekday_picker)); - - i = 0; - - if (day_mask & (1 << 0)) - r.by_day[i++] = ICAL_SUNDAY_WEEKDAY; - - if (day_mask & (1 << 1)) - r.by_day[i++] = ICAL_MONDAY_WEEKDAY; - - if (day_mask & (1 << 2)) - r.by_day[i++] = ICAL_TUESDAY_WEEKDAY; - - if (day_mask & (1 << 3)) - r.by_day[i++] = ICAL_WEDNESDAY_WEEKDAY; - - if (day_mask & (1 << 4)) - r.by_day[i++] = ICAL_THURSDAY_WEEKDAY; - - if (day_mask & (1 << 5)) - r.by_day[i++] = ICAL_FRIDAY_WEEKDAY; - - if (day_mask & (1 << 6)) - r.by_day[i++] = ICAL_SATURDAY_WEEKDAY; - - break; - } - - case ICAL_MONTHLY_RECURRENCE: { - int day_index; - enum month_day_options month_day; - - g_assert (GTK_BIN (priv->recurrence_special)->child != NULL); - g_assert (priv->recurrence_month_index_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->recurrence_month_index_spin)); - g_assert (priv->recurrence_month_day_menu != NULL); - g_assert (GTK_IS_OPTION_MENU (priv->recurrence_month_day_menu)); - - day_index = e_dialog_spin_get_int (priv->recurrence_month_index_spin); - month_day = e_dialog_option_menu_get (priv->recurrence_month_day_menu, - month_day_options_map); - - switch (month_day) { - case MONTH_DAY_NTH: - r.by_month_day[0] = day_index; - break; - - case MONTH_DAY_MON: - r.by_day[0] = nth_weekday (day_index, ICAL_MONDAY_WEEKDAY); - break; - - case MONTH_DAY_TUE: - r.by_day[0] = nth_weekday (day_index, ICAL_TUESDAY_WEEKDAY); - break; - - case MONTH_DAY_WED: - r.by_day[0] = nth_weekday (day_index, ICAL_WEDNESDAY_WEEKDAY); - break; - - case MONTH_DAY_THU: - r.by_day[0] = nth_weekday (day_index, ICAL_THURSDAY_WEEKDAY); - break; - - case MONTH_DAY_FRI: - r.by_day[0] = nth_weekday (day_index, ICAL_FRIDAY_WEEKDAY); - break; - - case MONTH_DAY_SAT: - r.by_day[0] = nth_weekday (day_index, ICAL_SATURDAY_WEEKDAY); - break; - - case MONTH_DAY_SUN: - r.by_day[0] = nth_weekday (day_index, ICAL_SUNDAY_WEEKDAY); - break; - - default: - g_assert_not_reached (); - } - - break; - } - - case ICAL_YEARLY_RECURRENCE: - /* Nothing else is required */ - break; - - default: - g_assert_not_reached (); - } - - /* Ending date */ - - ending_type = e_dialog_option_menu_get (priv->recurrence_ending_menu, ending_types_map); - - switch (ending_type) { - case ENDING_FOR: - g_assert (priv->recurrence_ending_count_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->recurrence_ending_count_spin)); - - r.count = e_dialog_spin_get_int (priv->recurrence_ending_count_spin); - break; - - case ENDING_UNTIL: - g_assert (priv->recurrence_ending_date_edit != NULL); - g_assert (E_IS_DATE_EDIT (priv->recurrence_ending_date_edit)); - - r.until = icaltime_from_timet ( - e_date_edit_get_time (E_DATE_EDIT (priv->recurrence_ending_date_edit)), - TRUE); - break; - - case ENDING_FOREVER: - /* Nothing to be done */ - break; - - default: - g_assert_not_reached (); - } - - /* Set the recurrence */ - - l.data = &r; - l.next = NULL; - - cal_component_set_rrule_list (comp, &l); -} - -/* Gets the data from the recurrence widgets and stores it in the calendar - * component object. - */ -static void -recur_to_comp_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - enum recur_type recur_type; - GtkCList *exception_list; - GSList *list; - int i; - - priv = ee->priv; - - recur_type = e_dialog_radio_get (priv->recurrence_none, recur_type_map); - - switch (recur_type) { - case RECUR_NONE: - cal_component_set_rdate_list (comp, NULL); - cal_component_set_rrule_list (comp, NULL); - cal_component_set_exrule_list (comp, NULL); - break; - - case RECUR_SIMPLE: - cal_component_set_rdate_list (comp, NULL); - cal_component_set_exrule_list (comp, NULL); - simple_recur_to_comp_object (ee, comp); - break; - - case RECUR_CUSTOM: - /* We just keep whatever the component has currently */ - break; - - default: - g_assert_not_reached (); - } - - /* Set exceptions */ - - list = NULL; - exception_list = GTK_CLIST (priv->recurrence_exception_list); - for (i = 0; i < exception_list->rows; i++) { - CalComponentDateTime *cdt; - time_t *tim; - - cdt = g_new (CalComponentDateTime, 1); - cdt->value = g_new (struct icaltimetype, 1); - cdt->tzid = NULL; - - tim = gtk_clist_get_row_data (exception_list, i); - g_assert (tim != NULL); - *cdt->value = icaltime_from_timet (*tim, FALSE); - - list = g_slist_prepend (list, cdt); - } - - cal_component_set_exdate_list (comp, list); - cal_component_free_exdate_list (list); -} - -/* Gets the data from the widgets and stores it in the calendar component object */ -static void -dialog_to_comp_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - CalComponentDateTime date; - time_t t; - gboolean all_day_event; - char *cat, *str; - - priv = ee->priv; - - /* Summary */ - - str = e_dialog_editable_get (priv->general_summary); - if (!str || strlen (str) == 0) - cal_component_set_summary (comp, NULL); - else { - CalComponentText text; - - text.value = str; - text.altrep = NULL; - - cal_component_set_summary (comp, &text); - } - - if (str) - g_free (str); - - /* Description */ - - str = e_dialog_editable_get (priv->description); - if (!str || strlen (str) == 0) - cal_component_set_description_list (comp, NULL); - else { - GSList l; - CalComponentText text; - - text.value = str; - text.altrep = NULL; - l.data = &text; - l.next = NULL; - - cal_component_set_description_list (comp, &l); - } - - if (str) - g_free (str); - - /* Dates */ - - date.value = g_new (struct icaltimetype, 1); - date.tzid = NULL; - - t = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_dtstart (comp, &date); - } else { - /* FIXME: What do we do here? */ - } - - /* If the all_day toggle is set, the end date is inclusive of the - entire day on which it points to. */ - all_day_event = e_dialog_toggle_get (priv->all_day_event); - t = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - if (t != -1) { - if (all_day_event) - t = time_day_end (t); - - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_dtend (comp, &date); - } else { - /* FIXME: What do we do here? */ - } - g_free (date.value); - - /* Categories */ - cat = e_dialog_editable_get (priv->categories); - cal_component_set_categories (comp, cat); - - if (cat) - g_free (cat); - - cal_component_set_classification (comp, classification_get (priv->classification_public)); - - /* Reminder information */ - reminder_to_comp_object (ee, comp); - - /* Recurrence information */ - recur_to_comp_object (ee, comp); - - cal_component_commit_sequence (comp); -} - -/* Fills the calendar component object from the data in the widgets and commits - * the component to the storage. - */ -static void -save_event_object (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - - if (!priv->comp) - return; - - dialog_to_comp_object (ee, priv->comp); - set_title_from_comp (ee, priv->comp); - - if (!cal_client_update_object (priv->client, priv->comp)) - g_message ("save_event_object(): Could not update the object!"); - else - event_editor_set_changed (ee, FALSE); -} - -/* Closes the dialog box and emits the appropriate signals */ -static void -close_dialog (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - - g_assert (priv->app != NULL); - - gtk_object_destroy (GTK_OBJECT (ee)); -} - - - -/* Callback used when the dialog box is "applied" */ -static void -ee_apply_event_cb (GtkWidget *widget, gint page_num, gpointer data) -{ - EventEditor *ee; - - g_return_if_fail (IS_EVENT_EDITOR (data)); - - ee = EVENT_EDITOR (data); - - if (page_num != -1) - return; - - save_event_object (ee); -} - -/* Callback used when the dialog box is destroyed */ -static gint -ee_close_event_cb (GtkWidget *widget, gpointer data) -{ - EventEditor *ee; - - g_return_val_if_fail (IS_EVENT_EDITOR (data), TRUE); - - ee = EVENT_EDITOR (data); - - if (prompt_to_save_changes (ee)) - close_dialog (ee); - - return TRUE; -} - -/* Callback used when the dialog box is destroyed */ -static gint -ee_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - EventEditor *ee; - - g_return_val_if_fail (IS_EVENT_EDITOR (data), TRUE); - - ee = EVENT_EDITOR (data); - - if (prompt_to_save_changes (ee)) - close_dialog (ee); - - return TRUE; -} - -/** - * event_editor_construct: - * @ee: An event editor. - * - * Constructs an event editor by loading its Glade data. - * - * Return value: The same object as @ee, or NULL if the widgets could not be - * created. In the latter case, the event editor will automatically be - * destroyed. - **/ -EventEditor * -event_editor_construct (EventEditor *ee) -{ - EventEditorPrivate *priv; - - g_return_val_if_fail (ee != NULL, NULL); - g_return_val_if_fail (IS_EVENT_EDITOR (ee), NULL); - - priv = ee->priv; - - /* Load the content widgets */ - - priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/event-editor-dialog.glade", NULL); - if (!priv->xml) { - g_message ("event_editor_construct(): Could not load the Glade XML file!"); - goto error; - } - - if (!get_widgets (ee)) { - g_message ("event_editor_construct(): Could not find all widgets in the XML file!"); - goto error; - } - - init_widgets (ee); - - /* Hook to destruction of the dialog */ - gtk_signal_connect (GTK_OBJECT (priv->app), "apply", - GTK_SIGNAL_FUNC (ee_apply_event_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->app), "close", - GTK_SIGNAL_FUNC (ee_close_event_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->app), "delete_event", - GTK_SIGNAL_FUNC (ee_delete_event_cb), ee); - - /* Add focus to the summary entry */ - gtk_widget_grab_focus (GTK_WIDGET (priv->general_summary)); - - return ee; - - error: - - gtk_object_unref (GTK_OBJECT (ee)); - return NULL; -} - -/** - * event_editor_new: - * - * Creates a new event editor dialog. - * - * Return value: A newly-created event editor dialog, or NULL if the event - * editor could not be created. - **/ -EventEditor * -event_editor_new (void) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (gtk_type_new (TYPE_EVENT_EDITOR)); - return event_editor_construct (EVENT_EDITOR (ee)); -} - -/* Brings attention to a window by raising it and giving it focus */ -static void -raise_and_focus (GtkWidget *widget) -{ - g_assert (GTK_WIDGET_REALIZED (widget)); - gdk_window_show (widget->window); - gtk_widget_grab_focus (widget); -} - -/* Callback used when the calendar client tells us that an object changed */ -static void -obj_updated_cb (CalClient *client, const char *uid, gpointer data) -{ - /* FIXME: Do something sensible if the component changes under our feet */ -#if 0 - EventEditor *ee; - EventEditorPrivate *priv; - CalComponent *comp; - CalClientGetStatus status; - const gchar *editing_uid; - - ee = EVENT_EDITOR (data); - - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - /* If we aren't showing the object which has been updated, return. */ - if (!priv->comp) - return; - cal_component_get_uid (priv->comp, &editing_uid); - if (strcmp (uid, editing_uid)) - return; - - - /* Get the event from the server. */ - status = cal_client_get_object (priv->client, uid, &comp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: - /* Everything is fine */ - break; - - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("obj_updated_cb(): Syntax error when getting object `%s'", uid); - return; - - case CAL_CLIENT_GET_NOT_FOUND: - /* The object is no longer in the server, so do nothing */ - return; - - default: - g_assert_not_reached (); - return; - } - - raise_and_focus (priv->app); -#endif -} - -/* Callback used when the calendar client tells us that an object was removed */ -static void -obj_removed_cb (CalClient *client, const char *uid, gpointer data) -{ - /* FIXME: Do something sensible if the component is removed under our - * feet. - */ -#if 0 - EventEditor *ee; - EventEditorPrivate *priv; - const gchar *editing_uid; - - ee = EVENT_EDITOR (data); - - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - /* If we aren't showing the object which has been updated, return. */ - if (!priv->comp) - return; - cal_component_get_uid (priv->comp, &editing_uid); - if (strcmp (uid, editing_uid)) - return; - - - raise_and_focus (priv->app); -#endif -} - -/** - * event_editor_set_cal_client: - * @ee: An event editor. - * @client: Calendar client. - * - * Sets the calendar client than an event editor will use for updating its - * calendar components. - **/ -void -event_editor_set_cal_client (EventEditor *ee, CalClient *client) -{ - EventEditorPrivate *priv; - - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - if (client == priv->client) - return; - - if (client) - g_return_if_fail (IS_CAL_CLIENT (client)); - - if (client) - g_return_if_fail (cal_client_get_load_state (client) == CAL_CLIENT_LOAD_LOADED); - - if (client) - gtk_object_ref (GTK_OBJECT (client)); - - if (priv->client) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->client), ee); - gtk_object_unref (GTK_OBJECT (priv->client)); - } - - priv->client = client; - - if (priv->client) { - gtk_signal_connect (GTK_OBJECT (priv->client), "obj_updated", - GTK_SIGNAL_FUNC (obj_updated_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->client), "obj_removed", - GTK_SIGNAL_FUNC (obj_removed_cb), ee); - } -} - -/** - * event_editor_get_cal_client: - * @ee: An event editor. - * - * Queries the calendar client that an event editor is using to update its - * calendar components. - * - * Return value: A calendar client object. - **/ -CalClient * -event_editor_get_cal_client (EventEditor *ee) -{ - EventEditorPrivate *priv; - - g_return_val_if_fail (ee != NULL, NULL); - g_return_val_if_fail (IS_EVENT_EDITOR (ee), NULL); - - priv = ee->priv; - return priv->client; -} - -/** - * event_editor_set_event_object: - * @ee: An event editor. - * @comp: A calendar object. - * - * Sets the calendar object that an event editor dialog will manipulate. - **/ -void -event_editor_set_event_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - if (priv->comp) { - gtk_object_unref (GTK_OBJECT (priv->comp)); - priv->comp = NULL; - } - - if (comp) { - priv->comp = cal_component_clone (comp); - } - - set_title_from_comp (ee, priv->comp); - fill_widgets (ee); -} - -/** - * event_editor_focus: - * @ee: An event editor. - * - * Makes sure an event editor is shown, on top of other windows, and focused. - **/ -void -event_editor_focus (EventEditor *ee) -{ - EventEditorPrivate *priv; - - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - gtk_widget_show_now (priv->app); - raise_and_focus (priv->app); -} - -/* Checks if the event's time starts and ends at midnight, and sets the - * "all day event" box accordingly. - */ -static void -check_all_day (EventEditor *ee) -{ - EventEditorPrivate *priv; - time_t ev_start, ev_end; - gboolean all_day = FALSE; - - priv = ee->priv; - - /* Currently we just return if the date is not set or not valid. - I'm not entirely sure this is the corrent thing to do. */ - ev_start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_return_if_fail (ev_start != -1); - - ev_end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_return_if_fail (ev_end != -1); - - /* all day event checkbox */ - if (time_day_begin (ev_start) == ev_start - && time_day_begin (ev_end) == ev_end) - all_day = TRUE; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->all_day_event), ee); - - e_dialog_toggle_set (priv->all_day_event, all_day); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->all_day_event), ee); - - e_date_edit_set_show_time (E_DATE_EDIT (priv->start_time), !all_day); - e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day); -} - -/* - * Callback: all day event button toggled. - * Note that this should only be called when the user explicitly toggles the - * button. Be sure to block this handler when the toggle button's state is set - * within the code. - */ -static void -set_all_day (GtkWidget *toggle, EventEditor *ee) -{ - EventEditorPrivate *priv; - struct tm start_tm, end_tm; - time_t start_t, end_t; - gboolean all_day; - - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); - - /* When the all_day toggle is turned on, the start date is rounded down - to the start of the day, and end date is rounded down to the start - of the day on which the event ends. The event is then taken to be - inclusive of the days between the start and end days. - Note that if the event end is at midnight, we do not round it down - to the previous day, since if we do that and the user repeatedly - turns the all_day toggle on and off, the event keeps shrinking. - (We'd also need to make sure we didn't adjust the time when the - radio button is initially set.) - - When the all_day_toggle is turned off, we set the event start to the - start of the working day, and if the event end is on or before the - day of the event start we set it to one hour after the event start. - */ - all_day = GTK_TOGGLE_BUTTON (toggle)->active; - - /* - * Start time. - */ - start_t = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_return_if_fail (start_t != -1); - - start_tm = *localtime (&start_t); - - if (all_day) { - /* Round down to the start of the day. */ - start_tm.tm_hour = 0; - start_tm.tm_min = 0; - start_tm.tm_sec = 0; - } else { - /* Set to the start of the working day. */ - start_tm.tm_hour = calendar_config_get_day_start_hour (); - start_tm.tm_min = calendar_config_get_day_start_minute (); - start_tm.tm_sec = 0; - } - - /* - * End time. - */ - end_t = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_return_if_fail (end_t != -1); - - end_tm = *localtime (&end_t); - - if (all_day) { - /* Round down to the start of the day. */ - end_tm.tm_hour = 0; - end_tm.tm_min = 0; - end_tm.tm_sec = 0; - } else { - /* If the event end is now on or before the event start day, - make it end one hour after the start. mktime() will fix any - overflows. */ - if (end_tm.tm_year < start_tm.tm_year - || (end_tm.tm_year == start_tm.tm_year - && end_tm.tm_mon < start_tm.tm_mon) - || (end_tm.tm_year == start_tm.tm_year - && end_tm.tm_mon == start_tm.tm_mon - && end_tm.tm_mday <= start_tm.tm_mday)) { - end_tm.tm_year = start_tm.tm_year; - end_tm.tm_mon = start_tm.tm_mon; - end_tm.tm_mday = start_tm.tm_mday; - end_tm.tm_hour = start_tm.tm_hour + 1; - } - } - - /* Block date_changed_cb, or dates_changed() will be called after the - start time is set (but before the end time is set) and will call - check_all_day() and mess us up. */ - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), ee); - - /* will set recur start too */ - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), mktime (&start_tm)); - - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), mktime (&end_tm)); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), ee); - - e_date_edit_set_show_time (E_DATE_EDIT (priv->start_time), !all_day); - e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day); - - preview_recur (ee); -} - -/* Callback used when the start or end date widgets change. We check that the - * start date < end date and we set the "all day event" button as appropriate. - */ -static void -date_changed_cb (EDateEdit *dedit, gpointer data) -{ - EventEditor *ee; - EventEditorPrivate *priv; - time_t start, end; - struct tm tm_start, tm_end; - - ee = EVENT_EDITOR (data); - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); - - /* Ensure that start < end */ - - start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_return_if_fail (start != -1); - end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_return_if_fail (end != -1); - - if (start >= end) { - tm_start = *localtime (&start); - tm_end = *localtime (&end); - - if (start == end && tm_start.tm_hour == 0 - && tm_start.tm_min == 0 && tm_start.tm_sec == 0) { - /* If the start and end times are the same, but both - are on day boundaries, then that is OK since it - means we have an all-day event lasting 1 day. - So we do nothing here. */ - - } else if (GTK_WIDGET (dedit) == priv->start_time) { - /* Modify the end time */ - - tm_end.tm_year = tm_start.tm_year; - tm_end.tm_mon = tm_start.tm_mon; - tm_end.tm_mday = tm_start.tm_mday; - tm_end.tm_hour = tm_start.tm_hour + 1; - tm_end.tm_min = tm_start.tm_min; - tm_end.tm_sec = tm_start.tm_sec; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), ee); - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), mktime (&tm_end)); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), ee); - } else if (GTK_WIDGET (dedit) == priv->end_time) { - /* Modify the start time */ - - tm_start.tm_year = tm_end.tm_year; - tm_start.tm_mon = tm_end.tm_mon; - tm_start.tm_mday = tm_end.tm_mday; - tm_start.tm_hour = tm_end.tm_hour - 1; - tm_start.tm_min = tm_end.tm_min; - tm_start.tm_sec = tm_end.tm_sec; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), ee); - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), mktime (&tm_start)); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), ee); - } else - g_assert_not_reached (); - } - - /* Set the "all day event" button as appropriate */ - - check_all_day (ee); - - /* Retag the recurrence preview calendar */ - - preview_recur (ee); -} - -/* Appends an alarm to the list */ -static void -append_reminder (EventEditor *ee, CalComponentAlarm *alarm, ReminderStatus status) -{ - EventEditorPrivate *priv; - GtkCList *clist; - ReminderData *rdata; - char *c[1]; - int i; - - priv = ee->priv; - - clist = GTK_CLIST (priv->reminder_list); - - c[0] = get_alarm_string (alarm); - i = gtk_clist_append (clist, c); - - rdata = g_new (ReminderData, 1); - rdata->status = status; - rdata->alarm = alarm; - gtk_clist_set_row_data (clist, i, rdata); - gtk_clist_select_row (clist, i, 0); - g_free (c[0]); - - gtk_widget_set_sensitive (priv->reminder_delete, TRUE); -} - -/* Callback for the "add reminder" button */ -static void -reminder_add_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - CalComponentAlarm *alarm; - CalAlarmTrigger trigger; - - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); - - alarm = cal_component_alarm_new (); - - memset (&trigger, 0, sizeof (CalAlarmTrigger)); - trigger.type = e_dialog_option_menu_get (priv->reminder_time, reminder_time_map); - if (e_dialog_option_menu_get (priv->reminder_relative, reminder_relative_map) == BEFORE) - trigger.u.rel_duration.is_neg = 1; - else - trigger.u.rel_duration.is_neg = 0; - - switch (e_dialog_option_menu_get (priv->reminder_value_units, reminder_value_map)) { - case MINUTES: - trigger.u.rel_duration.minutes = e_dialog_spin_get_int (priv->reminder_interval_value); - break; - case HOURS: - trigger.u.rel_duration.hours = e_dialog_spin_get_int (priv->reminder_interval_value); - break; - case DAYS: - trigger.u.rel_duration.days = e_dialog_spin_get_int (priv->reminder_interval_value); - break; - } - cal_component_alarm_set_trigger (alarm, trigger); - - cal_component_alarm_set_action (alarm, e_dialog_option_menu_get (priv->reminder_action, reminder_action_map)); - - append_reminder (ee, alarm, NEW_ALARM); -} - -/* Callback for the "delete reminder" button */ -static void -reminder_delete_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkCList *clist; - ReminderData *rdata; - int sel; - - priv = ee->priv; - - clist = GTK_CLIST (priv->reminder_list); - if (!clist->selection) - return; - - event_editor_set_changed (ee, TRUE); - - sel = GPOINTER_TO_INT (clist->selection->data); - - rdata = gtk_clist_get_row_data (clist, sel); - - if (rdata->status == EXISTING_ALARM) { - const char *uid; - - uid = cal_component_alarm_get_uid (rdata->alarm); - cal_component_remove_alarm (priv->comp, uid); - } - cal_component_alarm_free (rdata->alarm); - g_free (rdata); - - gtk_clist_remove (clist, sel); - if (sel >= clist->rows) - sel--; - - if (clist->rows > 0) - gtk_clist_select_row (clist, sel, 0); - else - gtk_widget_set_sensitive (priv->reminder_delete, FALSE); -} - - -/* Builds a static string out of an exception date */ -static char * -get_exception_string (time_t t) -{ - static char buf[256]; - - strftime (buf, sizeof (buf), _("%a %b %d %Y"), localtime (&t)); - return buf; -} - -/* Appends an exception date to the list */ -static void -append_exception (EventEditor *ee, time_t t) -{ - EventEditorPrivate *priv; - time_t *tt; - char *c[1]; - int i; - GtkCList *clist; - - priv = ee->priv; - - tt = g_new (time_t, 1); - *tt = t; - - clist = GTK_CLIST (priv->recurrence_exception_list); - - gtk_signal_handler_block_by_data (GTK_OBJECT (clist), ee); - - c[0] = get_exception_string (t); - i = gtk_clist_append (clist, c); - - gtk_clist_set_row_data (clist, i, tt); - - gtk_clist_select_row (clist, i, 0); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), ee); - - e_date_edit_set_time (E_DATE_EDIT (priv->recurrence_exception_date), t); - - gtk_widget_set_sensitive (priv->recurrence_exception_modify, TRUE); - gtk_widget_set_sensitive (priv->recurrence_exception_delete, TRUE); -} - - -/* Callback for the "add exception" button */ -static void -recurrence_exception_add_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - time_t t; - - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); - t = e_date_edit_get_time (E_DATE_EDIT (priv->recurrence_exception_date)); - append_exception (ee, t); - preview_recur (ee); -} - -/* Callback for the "modify exception" button */ -static void -recurrence_exception_modify_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkCList *clist; - time_t *t; - int sel; - - priv = ee->priv; - - clist = GTK_CLIST (priv->recurrence_exception_list); - if (!clist->selection) - return; - - event_editor_set_changed (ee, TRUE); - - sel = GPOINTER_TO_INT (clist->selection->data); - - t = gtk_clist_get_row_data (clist, sel); - *t = e_date_edit_get_time (E_DATE_EDIT (priv->recurrence_exception_date)); - - gtk_clist_set_text (clist, sel, 0, get_exception_string (*t)); - - preview_recur (ee); -} - -/* Callback for the "delete exception" button */ -static void -recurrence_exception_delete_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkCList *clist; - int sel; - time_t *t; - - priv = ee->priv; - - clist = GTK_CLIST (priv->recurrence_exception_list); - if (!clist->selection) - return; - - event_editor_set_changed (ee, TRUE); - - sel = GPOINTER_TO_INT (clist->selection->data); - - t = gtk_clist_get_row_data (clist, sel); - g_assert (t != NULL); - g_free (t); - - gtk_clist_remove (clist, sel); - if (sel >= clist->rows) - sel--; - - if (clist->rows > 0) - gtk_clist_select_row (clist, sel, 0); - else { - gtk_widget_set_sensitive (priv->recurrence_exception_modify, FALSE); - gtk_widget_set_sensitive (priv->recurrence_exception_delete, FALSE); - } - - preview_recur (ee); -} - -/* Callback used when a row is selected in the list of exception dates. We must - * update the date/time widgets to reflect the exception's value. - */ -static void -recurrence_exception_select_row_cb (GtkCList *clist, gint row, gint col, GdkEvent *event, - gpointer data) -{ - EventEditor *ee; - EventEditorPrivate *priv; - time_t *t; - - ee = EVENT_EDITOR (data); - priv = ee->priv; - - t = gtk_clist_get_row_data (clist, row); - g_assert (t != NULL); - - e_date_edit_set_time (E_DATE_EDIT (priv->recurrence_exception_date), *t); -} - -GtkWidget * -make_date_edit (void) -{ - return date_edit_new (TRUE, TRUE); -} - - -GtkWidget * -make_spin_button (int val, int low, int high) -{ - GtkAdjustment *adj; - GtkWidget *spin; - - adj = GTK_ADJUSTMENT (gtk_adjustment_new (val, low, high, 1, 10, 10)); - spin = gtk_spin_button_new (adj, 0.5, 0); - gtk_widget_set_usize (spin, 60, 0); - - return spin; -} - - -/* This is called when most fields are changed (except those which already - have signal handlers). It just sets the "changed" flag. */ -static void -field_changed (GtkWidget *widget, - EventEditor *ee) -{ - EventEditorPrivate *priv; - - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); -} - - -static void -event_editor_set_changed (EventEditor *ee, - gboolean changed) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - -#if 0 - g_print ("In event_editor_set_changed: %s\n", - changed ? "TRUE" : "FALSE"); -#endif - - priv->changed = changed; - - if (priv->app) - gnome_property_box_set_state (GNOME_PROPERTY_BOX (priv->app), changed); -} - - -/* This checks if the "changed" field is set, and if so it prompts to save - the changes using a "Save/Discard/Cancel" modal dialog. It then saves the - changes if requested. It returns TRUE if the dialog should now be closed. */ -static gboolean -prompt_to_save_changes (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - - if (!priv->changed) - return TRUE; - - switch (save_component_dialog (GTK_WINDOW (priv->app))) { - case 0: /* Save */ - /* FIXME: If an error occurs here, we should popup a dialog - and then return FALSE. */ - save_event_object (ee); - return TRUE; - case 1: /* Discard */ - return TRUE; - case 2: /* Cancel */ - default: - return FALSE; - break; - } -} - -static void -categories_clicked (GtkWidget *button, EventEditor *ee) -{ - char *categories; - GnomeDialog *dialog; - int result; - GtkWidget *entry; - - entry = ee->priv->categories; - categories = e_utf8_gtk_entry_get_text (GTK_ENTRY (entry)); - - dialog = GNOME_DIALOG (e_categories_new (categories)); - result = gnome_dialog_run (dialog); - g_free (categories); - - if (result == 0) { - gtk_object_get (GTK_OBJECT (dialog), - "categories", &categories, - NULL); - e_utf8_gtk_entry_set_text (GTK_ENTRY (entry), categories); - g_free (categories); - } - gtk_object_destroy (GTK_OBJECT (dialog)); -} diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index 96f88d79a7..46cc26292f 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -40,10 +40,10 @@ #include "widgets/misc/e-search-bar.h" #include "widgets/misc/e-filter-bar.h" #include "dialogs/alarm-notify-dialog.h" +#include "dialogs/event-editor.h" #include "e-calendar-table.h" #include "e-day-view.h" #include "e-week-view.h" -#include "event-editor.h" #include "gnome-cal.h" #include "component-factory.h" #include "calendar-commands.h" @@ -1308,11 +1308,11 @@ gnome_calendar_edit_object (GnomeCalendar *gcal, CalComponent *comp) GTK_SIGNAL_FUNC (editor_closed_cb), ec); - event_editor_set_cal_client (EVENT_EDITOR (ee), priv->client); - event_editor_set_event_object (EVENT_EDITOR (ee), comp); + comp_editor_set_cal_client (COMP_EDITOR (ee), priv->client); + comp_editor_edit_comp (COMP_EDITOR (ee), comp); } - event_editor_focus (ee); + comp_editor_focus (COMP_EDITOR (ee)); } /** |