diff options
author | Damon Chaplin <damon@helixcode.com> | 2000-12-11 10:22:06 +0800 |
---|---|---|
committer | Damon Chaplin <damon@src.gnome.org> | 2000-12-11 10:22:06 +0800 |
commit | ba28f6622636fc3932aab4a0551e2d86b69fd6e4 (patch) | |
tree | 4fa39103cd28af9eff5a79778eb22fe2c9b8a9bf | |
parent | 50fcc2ad7d4c717aafa62195988a8362fc7a3f19 (diff) | |
download | gsoc2013-evolution-ba28f6622636fc3932aab4a0551e2d86b69fd6e4.tar.gz gsoc2013-evolution-ba28f6622636fc3932aab4a0551e2d86b69fd6e4.tar.zst gsoc2013-evolution-ba28f6622636fc3932aab4a0551e2d86b69fd6e4.zip |
added changed flags and added calls to a new function
2000-12-11 Damon Chaplin <damon@helixcode.com>
* gui/event-editor.c: added changed flags and added calls to a new
function event_editor_set_changed() to set & reset this flag.
Added prompt_to_save_changed() which is called when the user
selects File/Close or the window's close button.
Fixed the 'All day event' toggle button.
Made the 'Alarm' page sensitive as appropriate when filling widgets.
(Though note that the alarm widgets are not being set yet.)
* gui/dialogs/task-editor.c: added changed flag as above.
* gui/event-editor-dialog.glade: used good names for all the
classification radio buttons so we can access them in the code.
* gui/event-editor.c (init_widgets): use the "show week numbers" config
option in the recurrence preview calendar.
* gui/e-day-view.c (e_day_view_update_event_label): use 9:00 instead
of 09:00 in the main view, as we do everywhere else now. It means the
times won't line up, but they are easier to read which I think is
better.
Added support for Page Up/Down, though I think it should move the
selection rather than just scroll the canvas.
* cal-util/cal-recur.c (generate_instances_for_chunk): removed the
end parameter since we should be using the chunk end time now.
Added single_rule parameter for when we are generating the
occurrences of a single RRULE, in which case the event's start date is
not included in the occurrences output (unless it results from the
RRULE expansion). Both of these fix problems when using COUNT.
* gui/gnome-cal.c (gnome_calendar_on_date_navigator_selection_changed):
fixed bug when checking if the new start day starts on the week start
day. If you select a complete week it should now show the Week view.
svn path=/trunk/; revision=6896
-rw-r--r-- | calendar/ChangeLog | 36 | ||||
-rw-r--r-- | calendar/cal-util/cal-recur.c | 49 | ||||
-rw-r--r-- | calendar/gui/dialogs/task-editor.c | 140 | ||||
-rw-r--r-- | calendar/gui/e-day-view.c | 60 | ||||
-rw-r--r-- | calendar/gui/e-day-view.h | 26 | ||||
-rw-r--r-- | calendar/gui/event-editor-dialog.glade | 6 | ||||
-rw-r--r-- | calendar/gui/event-editor.c | 318 | ||||
-rw-r--r-- | calendar/gui/gnome-cal.c | 2 |
8 files changed, 534 insertions, 103 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index a2a7cf282e..aa0d96f03a 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,39 @@ +2000-12-11 Damon Chaplin <damon@helixcode.com> + + * gui/event-editor.c: added changed flags and added calls to a new + function event_editor_set_changed() to set & reset this flag. + Added prompt_to_save_changed() which is called when the user + selects File/Close or the window's close button. + Fixed the 'All day event' toggle button. + Made the 'Alarm' page sensitive as appropriate when filling widgets. + (Though note that the alarm widgets are not being set yet.) + + * gui/dialogs/task-editor.c: added changed flag as above. + + * gui/event-editor-dialog.glade: used good names for all the + classification radio buttons so we can access them in the code. + + * gui/event-editor.c (init_widgets): use the "show week numbers" config + option in the recurrence preview calendar. + + * gui/e-day-view.c (e_day_view_update_event_label): use 9:00 instead + of 09:00 in the main view, as we do everywhere else now. It means the + times won't line up, but they are easier to read which I think is + better. + Added support for Page Up/Down, though I think it should move the + selection rather than just scroll the canvas. + + * cal-util/cal-recur.c (generate_instances_for_chunk): removed the + end parameter since we should be using the chunk end time now. + Added single_rule parameter for when we are generating the + occurrences of a single RRULE, in which case the event's start date is + not included in the occurrences output (unless it results from the + RRULE expansion). Both of these fix problems when using COUNT. + + * gui/gnome-cal.c (gnome_calendar_on_date_navigator_selection_changed): + fixed bug when checking if the new start day starts on the week start + day. If you select a complete week it should now show the Week view. + 2000-12-08 Federico Mena Quintero <federico@helixcode.com> * gui/event-editor.c (dialog_to_comp_object): Free the strings we diff --git a/calendar/cal-util/cal-recur.c b/calendar/cal-util/cal-recur.c index 99e4991323..c2d1516f28 100644 --- a/calendar/cal-util/cal-recur.c +++ b/calendar/cal-util/cal-recur.c @@ -260,11 +260,11 @@ static gboolean generate_instances_for_chunk (CalComponent *comp, GSList *rdates, GSList *exrules, GSList *exdates, + gboolean single_rule, CalObjTime *event_start, + time_t interval_start, CalObjTime *chunk_start, CalObjTime *chunk_end, - time_t interval_start_time, - time_t interval_end_time, gint duration_days, gint duration_seconds, CalRecurInstanceFn cb, @@ -600,7 +600,7 @@ cal_recur_generate_instances (CalComponent *comp, * If the callback routine returns FALSE the occurrence generation stops. * * The use of the specific rule is for determining the end of a rule when - * COUNT is set. The callback will count instances and store the enddata + * COUNT is set. The callback will count instances and store the enddate * when COUNT is reached. * * Both start and end can be -1, in which case we start at the events first @@ -621,6 +621,7 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, CalObjTime interval_start, interval_end, event_start, event_end; CalObjTime chunk_start, chunk_end; gint days, seconds, year; + gboolean single_rule; g_return_if_fail (comp != NULL); g_return_if_fail (cb != NULL); @@ -662,10 +663,14 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, /* If a specific recurrence rule is being used, set up a simple list, else get the recurrence rules from the component. */ if (prop) { + single_rule = TRUE; + elem.data = prop; elem.next = NULL; rrules = &elem; } else { + single_rule = FALSE; + /* Make sure all the enddates for the rules are set. */ cal_recur_ensure_end_dates (comp, FALSE); @@ -738,9 +743,10 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, if (!generate_instances_for_chunk (comp, dtstart_time, rrules, rdates, exrules, exdates, + single_rule, &event_start, + start, &chunk_start, &chunk_end, - start, end, days, seconds, cb, cb_data)) break; @@ -934,11 +940,11 @@ generate_instances_for_chunk (CalComponent *comp, GSList *rdates, GSList *exrules, GSList *exdates, + gboolean single_rule, CalObjTime *event_start, + time_t interval_start, CalObjTime *chunk_start, CalObjTime *chunk_end, - time_t interval_start_time, - time_t interval_end_time, gint duration_days, gint duration_seconds, CalRecurInstanceFn cb, @@ -969,13 +975,17 @@ generate_instances_for_chunk (CalComponent *comp, rdate_periods = g_array_new (FALSE, FALSE, sizeof (CalObjRecurrenceDate)); - /* The original DTSTART property is included in the occurrence set. - So we add it if it is in this chunk. If it is after this chunk - we set finished to FALSE. */ - if (cal_obj_time_compare_func (event_start, chunk_end) >= 0) - finished = FALSE; - else if (cal_obj_time_compare_func (event_start, chunk_start) >= 0) - g_array_append_vals (occs, event_start, 1); + /* The original DTSTART property is included in the occurrence set, + but not if we are just generating occurrences for a single rule. */ + if (!single_rule) { + /* We add it if it is in this chunk. If it is after this chunk + we set finished to FALSE, since we know we aren't finished + yet. */ + if (cal_obj_time_compare_func (event_start, chunk_end) >= 0) + finished = FALSE; + else if (cal_obj_time_compare_func (event_start, chunk_start) >= 0) + g_array_append_vals (occs, event_start, 1); + } /* Expand each of the recurrence rules. */ for (elem = rrules; elem; elem = elem->next) { @@ -1102,9 +1112,14 @@ generate_instances_for_chunk (CalComponent *comp, break; } + /* Check to ensure that the start time is at or after the + events DTSTART time, that it is not after the end of the + interval we are generating instances for, and that it is + inside the chunk that we are currently working on. */ if (start_time < comp_dtstart - || (interval_end_time != -1 - && start_time >= interval_end_time)) + || start_time < interval_start + || cal_obj_time_compare_func (occ, chunk_start) < 0 + || cal_obj_time_compare_func (occ, chunk_end) > 0) continue; if (occ->is_rdate) { @@ -1133,7 +1148,9 @@ generate_instances_for_chunk (CalComponent *comp, break; } - if (end_time <= interval_start_time) + /* Check that the occurrence ends after the start of the + current chunk. */ + if (cal_obj_time_compare_func (occ, chunk_start) <= 0) continue; cb_status = (*cb) (comp, start_time, end_time, cb_data); diff --git a/calendar/gui/dialogs/task-editor.c b/calendar/gui/dialogs/task-editor.c index 8cd7c33ba9..211c31321a 100644 --- a/calendar/gui/dialogs/task-editor.c +++ b/calendar/gui/dialogs/task-editor.c @@ -81,6 +81,11 @@ typedef struct { 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; @@ -165,7 +170,13 @@ 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); +/* The function libglade calls to create the EDateEdit widgets in the GUI. */ GtkWidget * task_editor_create_date_edit (void); static GtkObjectClass *parent_class; @@ -196,6 +207,8 @@ task_editor_init (TaskEditor *tedit) tedit->priv = priv; priv->ignore_callbacks = FALSE; + + task_editor_set_changed (tedit, FALSE); } @@ -339,10 +352,12 @@ app_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) { TaskEditor *tedit; - /* FIXME: need to check for a dirty object */ + g_return_val_if_fail (IS_TASK_EDITOR (data), TRUE); tedit = TASK_EDITOR (data); - close_dialog (tedit); + + if (prompt_to_save_changes (tedit)) + close_dialog (tedit); return TRUE; } @@ -435,6 +450,30 @@ init_widgets (TaskEditor *tedit) gtk_signal_connect (GTK_OBJECT (GTK_SPIN_BUTTON (priv->percent_complete)->adjustment), "value_changed", GTK_SIGNAL_FUNC (percent_complete_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 (GTK_OPTION_MENU (priv->classification)->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); + } static void @@ -709,6 +748,8 @@ fill_widgets (TaskEditor *tedit) priv = tedit->priv; + task_editor_set_changed (tedit, FALSE); + clear_widgets (tedit); if (!priv->comp) @@ -785,7 +826,6 @@ fill_widgets (TaskEditor *tedit) status = ICAL_STATUS_NEEDSACTION; } } - g_print ("Setting status\n"); e_dialog_option_menu_set (priv->status, status, status_map); /* Priority. */ @@ -796,13 +836,11 @@ fill_widgets (TaskEditor *tedit) } else { priority = PRIORITY_UNDEFINED; } - g_print ("Setting priority\n"); e_dialog_option_menu_set (priv->priority, priority, priority_map); /* Classification. */ cal_component_get_classification (priv->comp, &classification); - g_print ("Setting classification\n"); e_dialog_option_menu_set (priv->classification, classification, classification_map); @@ -836,6 +874,8 @@ save_todo_object (TaskEditor *tedit) 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); } @@ -956,6 +996,7 @@ dialog_to_comp_object (TaskEditor *tedit) if (url) g_free (url); + cal_component_commit_sequence (comp); } @@ -1021,11 +1062,12 @@ file_close_cb (GtkWidget *widget, gpointer data) { TaskEditor *tedit; - tedit = TASK_EDITOR (data); + g_return_if_fail (IS_TASK_EDITOR (data)); - g_return_if_fail (IS_TASK_EDITOR (tedit)); + tedit = TASK_EDITOR (data); - close_dialog (tedit); + if (prompt_to_save_changes (tedit)) + close_dialog (tedit); } @@ -1119,6 +1161,8 @@ completed_changed (EDateEdit *dedit, 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) { @@ -1152,6 +1196,8 @@ status_changed (GtkMenu *menu, 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) { @@ -1182,6 +1228,8 @@ percent_complete_changed (GtkAdjustment *adj, if (priv->ignore_callbacks) return; + task_editor_set_changed (tedit, TRUE); + percent = e_dialog_spin_get_int (priv->percent_complete); priv->ignore_callbacks = TRUE; @@ -1205,3 +1253,79 @@ percent_complete_changed (GtkAdjustment *adj, priv->ignore_callbacks = FALSE; } + +/* 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; +} + + +/* 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; + GtkWidget *dialog; + + priv = tedit->priv; + + if (!priv->changed) + return TRUE; + + dialog = gnome_message_box_new (_("Do you want to save changes?"), + GNOME_MESSAGE_BOX_QUESTION, + GNOME_STOCK_BUTTON_YES, + GNOME_STOCK_BUTTON_NO, + GNOME_STOCK_BUTTON_CANCEL, + NULL); + + gnome_dialog_set_parent (GNOME_DIALOG (dialog), + GTK_WINDOW (priv->app)); + + switch (gnome_dialog_run_and_close (GNOME_DIALOG (dialog))) { + 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; + } + +} diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index 0f22f59a30..9078fcef73 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -69,6 +69,15 @@ we start a drag. */ #define E_DAY_VIEW_DRAG_START_OFFSET 4 +/* The amount we scroll the main canvas when the Page Up/Down keys are pressed, + as a fraction of the page size. */ +#define E_DAY_VIEW_PAGE_STEP 0.5 + +/* The amount we scroll the main canvas when the mouse wheel buttons are + pressed, as a fraction of the page size. */ +#define E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE 0.25 + + /* Drag and Drop stuff. */ enum { TARGET_CALENDAR_EVENT @@ -113,6 +122,8 @@ static void e_day_view_cursor_key_right (EDayView *day_view, static void e_day_view_ensure_rows_visible (EDayView *day_view, gint start_row, gint end_row); +static void e_day_view_scroll (EDayView *day_view, + gfloat pages_to_scroll); static gboolean e_day_view_check_if_new_event_fits (EDayView *day_view); @@ -1665,14 +1676,14 @@ e_day_view_update_event_label (EDayView *day_view, if (day_view->show_event_end_times) { /* 24 hour format with end time. */ text = g_strdup_printf - ("%02i:%02i-%02i:%02i %s", + ("%2i:%02i-%2i:%02i %s", start_display_hour, start_minute, end_display_hour, end_minute, text); } else { /* 24 hour format without end time. */ text = g_strdup_printf - ("%02i:%02i %s", + ("%2i:%02i %s", start_display_hour, start_minute, text); } @@ -1680,7 +1691,7 @@ e_day_view_update_event_label (EDayView *day_view, if (day_view->show_event_end_times) { /* 12 hour format with end time. */ text = g_strdup_printf - ("%02i:%02i%s-%02i:%02i%s %s", + ("%2i:%02i%s-%2i:%02i%s %s", start_display_hour, start_minute, start_suffix, end_display_hour, end_minute, @@ -1689,7 +1700,7 @@ e_day_view_update_event_label (EDayView *day_view, } else { /* 12 hour format without end time. */ text = g_strdup_printf - ("%02i:%02i%s %s", + ("%2i:%02i%s %s", start_display_hour, start_minute, start_suffix, text); @@ -2531,16 +2542,14 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget, EDayViewPosition pos; /* Handle scroll wheel events */ - if (event->button == 4 || event->button == 5) { - GtkAdjustment *adj = GTK_LAYOUT (day_view->main_canvas)->vadjustment; - gfloat new_value; - - new_value = adj->value + ((event->button == 4) ? - -adj->page_increment / 2: - adj->page_increment / 2); - new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size); - gtk_adjustment_set_value (adj, new_value); - + if (event->button == 4) { + /* The wheel has been moved up, so scroll the canvas down. */ + e_day_view_scroll (day_view, E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE); + return TRUE; + } + if (event->button == 5) { + /* The wheel has been moved down, so scroll the canvas up. */ + e_day_view_scroll (day_view, -E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE); return TRUE; } @@ -4724,6 +4733,12 @@ e_day_view_key_press (GtkWidget *widget, GdkEventKey *event) case GDK_Right: e_day_view_cursor_key_right (day_view, event); break; + case GDK_Page_Up: + e_day_view_scroll (day_view, E_DAY_VIEW_PAGE_STEP); + break; + case GDK_Page_Down: + e_day_view_scroll (day_view, -E_DAY_VIEW_PAGE_STEP); + break; default: stop_emission = FALSE; break; @@ -5006,6 +5021,23 @@ e_day_view_cursor_key_right (EDayView *day_view, GdkEventKey *event) } +/* Scrolls the main canvas up or down. The pages_to_scroll argument + is multiplied with the adjustment's page size and added to the adjustment's + value, while ensuring we stay within the bounds. A positive value will + scroll the canvas down and a negative value will scroll it up. */ +static void +e_day_view_scroll (EDayView *day_view, + gfloat pages_to_scroll) +{ + GtkAdjustment *adj = GTK_LAYOUT (day_view->main_canvas)->vadjustment; + gfloat new_value; + + new_value = adj->value - adj->page_size * pages_to_scroll; + new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size); + gtk_adjustment_set_value (adj, new_value); +} + + static gboolean e_day_view_check_if_new_event_fits (EDayView *day_view) { diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h index a6ecc165d5..7e6ea8ac2a 100644 --- a/calendar/gui/e-day-view.h +++ b/calendar/gui/e-day-view.h @@ -165,14 +165,30 @@ typedef enum typedef struct _EDayViewEvent EDayViewEvent; struct _EDayViewEvent { CalComponent *comp; + + /* These are the times of this specific occurrence of the event. */ time_t start; time_t end; - guint8 start_row_or_col;/* The start column for normal events, or the - start row for long events. */ - guint8 num_columns; /* 0 indicates not displayed. For long events - this is just 1 if the event is shown. */ - guint16 start_minute; /* Offsets from the start of the display. */ + + /* For events in the main canvas, this contains the start column. + For long events in the top canvas, this is its row. */ + guint8 start_row_or_col; + + /* For events in the main canvas, this is the number of columns that + it covers. For long events this is set to 1 if the event is shown. + For both types of events this is set to 0 if the event is not shown, + i.e. it couldn't fit into the display. Currently long events are + always shown as we just increase the height of the top canvas. */ + guint8 num_columns; + + /* These are minute offsets from the first time shown in the view. + They range from 0 to 24 * 60. Currently the main canvas always + starts at 12am and the code to handle starting at other times + isn't finished. */ + guint16 start_minute; guint16 end_minute; + + /* This is the EText item containing the event summary. */ GnomeCanvasItem *canvas_item; }; diff --git a/calendar/gui/event-editor-dialog.glade b/calendar/gui/event-editor-dialog.glade index cb4ae7c557..b3b580d1ea 100644 --- a/calendar/gui/event-editor-dialog.glade +++ b/calendar/gui/event-editor-dialog.glade @@ -318,7 +318,7 @@ <widget> <class>GtkRadioButton</class> - <name>classification-radio</name> + <name>classification-public</name> <can_focus>True</can_focus> <label>Pu_blic</label> <active>True</active> @@ -333,7 +333,7 @@ <widget> <class>GtkRadioButton</class> - <name></name> + <name>classification-private</name> <can_focus>True</can_focus> <label>Pri_vate</label> <active>False</active> @@ -348,7 +348,7 @@ <widget> <class>GtkRadioButton</class> - <name></name> + <name>classification-confidential</name> <can_focus>True</can_focus> <label>_Confidential</label> <active>False</active> diff --git a/calendar/gui/event-editor.c b/calendar/gui/event-editor.c index 8939e9bb64..85dc3025ef 100644 --- a/calendar/gui/event-editor.c +++ b/calendar/gui/event-editor.c @@ -105,7 +105,9 @@ struct _EventEditorPrivate { GtkWidget *alarm_mail_unit; GtkWidget *alarm_mail_mail_to; - GtkWidget *classification_radio; + GtkWidget *classification_public; + GtkWidget *classification_private; + GtkWidget *classification_confidential; GtkWidget *recurrence_summary; GtkWidget *recurrence_starting_date; @@ -154,6 +156,11 @@ struct _EventEditorPrivate { /* 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; }; @@ -180,6 +187,11 @@ static void recur_to_comp_object (EventEditor *ee, CalComponent *comp); 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 field_changed (GtkWidget *widget, + EventEditor *ee); +static void event_editor_set_changed (EventEditor *ee, + gboolean changed); +static gboolean prompt_to_save_changes (EventEditor *ee); @@ -235,6 +247,8 @@ event_editor_init (EventEditor *ee) 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 */ @@ -367,6 +381,7 @@ recur_weekday_picker_changed_cb (WeekdayPicker *wp, gpointer data) EventEditor *ee; ee = EVENT_EDITOR (data); + event_editor_set_changed (ee, TRUE); preview_recur (ee); } @@ -505,6 +520,7 @@ month_day_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) ee = EVENT_EDITOR (data); adjust_day_index_spin (ee); + event_editor_set_changed (ee, TRUE); preview_recur (ee); } @@ -515,6 +531,7 @@ 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); } @@ -634,6 +651,7 @@ recur_ending_until_changed_cb (EDateEdit *de, gpointer data) EventEditor *ee; ee = EVENT_EDITOR (data); + event_editor_set_changed (ee, TRUE); preview_recur (ee); } @@ -674,6 +692,7 @@ 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); } @@ -838,6 +857,8 @@ recurrence_type_toggled_cb (GtkToggleButton *toggle, gpointer data) ee = EVENT_EDITOR (data); + event_editor_set_changed (ee, TRUE); + if (toggle->active) { sensitize_recur_widgets (ee); preview_recur (ee); @@ -851,6 +872,7 @@ recur_interval_value_changed_cb (GtkAdjustment *adj, gpointer data) EventEditor *ee; ee = EVENT_EDITOR (data); + event_editor_set_changed (ee, TRUE); preview_recur (ee); } @@ -863,6 +885,7 @@ 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); } @@ -876,6 +899,7 @@ 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); } @@ -919,7 +943,9 @@ get_widgets (EventEditor *ee) priv->alarm_mail_unit = GW ("alarm-mail-unit"); priv->alarm_mail_mail_to = GW ("alarm-mail-mail-to"); - priv->classification_radio = GW ("classification-radio"); + priv->classification_public = GW ("classification-public"); + priv->classification_private = GW ("classification-private"); + priv->classification_confidential = GW ("classification-confidential"); priv->recurrence_summary = GW ("recurrence-summary"); priv->recurrence_starting_date = GW ("recurrence-starting-date"); @@ -966,7 +992,9 @@ get_widgets (EventEditor *ee) && priv->alarm_mail_amount && priv->alarm_mail_unit && priv->alarm_mail_mail_to - && priv->classification_radio + && priv->classification_public + && priv->classification_private + && priv->classification_confidential && priv->recurrence_summary && priv->recurrence_starting_date && priv->recurrence_none @@ -1108,6 +1136,7 @@ init_widgets (EventEditor *ee) gnome_canvas_item_set (GNOME_CANVAS_ITEM (ecal->calitem), "maximum_days_selected", 0, "week_start_day", (week_start_day + 6) % 7, + "show_week_numbers", calendar_config_get_dnav_show_week_no (), NULL); gtk_container_add (GTK_CONTAINER (priv->recurrence_preview_bin), priv->recurrence_preview_calendar); @@ -1148,6 +1177,64 @@ init_widgets (EventEditor *ee) 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); + + + /* + * Connect the default signal handler to use to make sure the "changed" + * field gets set whenever a field is changed. + */ + + /* General 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); + + /* Reminder Page. */ + gtk_signal_connect (GTK_OBJECT (GTK_SPIN_BUTTON (priv->alarm_display_amount)->adjustment), + "value_changed", + GTK_SIGNAL_FUNC (field_changed), ee); + gtk_signal_connect (GTK_OBJECT (GTK_SPIN_BUTTON (priv->alarm_audio_amount)->adjustment), + "value_changed", + GTK_SIGNAL_FUNC (field_changed), ee); + gtk_signal_connect (GTK_OBJECT (GTK_SPIN_BUTTON (priv->alarm_program_amount)->adjustment), + "value_changed", + GTK_SIGNAL_FUNC (field_changed), ee); + gtk_signal_connect (GTK_OBJECT (GTK_SPIN_BUTTON (priv->alarm_mail_amount)->adjustment), + "value_changed", + GTK_SIGNAL_FUNC (field_changed), ee); + + gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (priv->alarm_display_unit)->menu), + "deactivate", + GTK_SIGNAL_FUNC (field_changed), ee); + gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (priv->alarm_audio_unit)->menu), + "deactivate", + GTK_SIGNAL_FUNC (field_changed), ee); + gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (priv->alarm_program_unit)->menu), + "deactivate", + GTK_SIGNAL_FUNC (field_changed), ee); + gtk_signal_connect (GTK_OBJECT (GTK_OPTION_MENU (priv->alarm_mail_unit)->menu), + "deactivate", + GTK_SIGNAL_FUNC (field_changed), ee); + + gtk_signal_connect (GTK_OBJECT (priv->alarm_program_run_program_entry), + "changed", + GTK_SIGNAL_FUNC (field_changed), ee); + gtk_signal_connect (GTK_OBJECT (priv->alarm_mail_mail_to), + "changed", + GTK_SIGNAL_FUNC (field_changed), ee); + + + /* Recurrence Page. */ } static const int classification_map[] = { @@ -1238,7 +1325,7 @@ clear_widgets (EventEditor *ee) /* Classification */ - e_dialog_radio_set (priv->classification_radio, + e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PRIVATE, classification_map); /* Recurrences */ @@ -1851,19 +1938,27 @@ fill_widgets (EventEditor *ee) e_dialog_editable_set (priv->alarm_program_run_program_entry, priv->ico->palarm.data); e_dialog_editable_set (priv->alarm_mail_mail_to, priv->ico->malarm.data); #endif + + /* Call alarm_toggle to set the sensitivity of the widgets. */ + alarm_toggle (priv->alarm_display, ee); + alarm_toggle (priv->alarm_audio, ee); + alarm_toggle (priv->alarm_program, ee); + alarm_toggle (priv->alarm_mail, ee); + + /* Classification */ cal_component_get_classification (priv->comp, &cl); switch (cl) { case CAL_COMPONENT_CLASS_PUBLIC: - e_dialog_radio_set (priv->classification_radio, 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_radio, 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_radio, 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 @@ -1873,6 +1968,9 @@ fill_widgets (EventEditor *ee) /* Recurrences */ fill_recurrence_widgets (ee); + + /* Do this last, since the callbacks will set it to TRUE. */ + event_editor_set_changed (ee, FALSE); } @@ -2239,7 +2337,7 @@ dialog_to_comp_object (EventEditor *ee, CalComponent *comp) ico->malarm.data = e_dialog_editable_get (priv->alarm_mail_mail_to); #endif - cal_component_set_classification (comp, classification_get (priv->classification_radio)); + cal_component_set_classification (comp, classification_get (priv->classification_public)); /* Recurrence information */ recur_to_comp_object (ee, comp); @@ -2265,6 +2363,8 @@ save_event_object (EventEditor *ee) 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 */ @@ -2347,11 +2447,12 @@ file_close_cb (GtkWidget *widget, gpointer data) { EventEditor *ee; - ee = EVENT_EDITOR (data); + g_return_if_fail (IS_EVENT_EDITOR (data)); - g_return_if_fail (IS_EVENT_EDITOR (ee)); + ee = EVENT_EDITOR (data); - close_dialog (ee); + if (prompt_to_save_changes (ee)) + close_dialog (ee); } static void @@ -2398,10 +2499,12 @@ app_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) { EventEditor *ee; - /* FIXME: need to check for a dirty object */ + g_return_val_if_fail (IS_EVENT_EDITOR (data), TRUE); ee = EVENT_EDITOR (data); - close_dialog (ee); + + if (prompt_to_save_changes (ee)) + close_dialog (ee); return TRUE; } @@ -2718,6 +2821,8 @@ event_editor_focus (EventEditor *ee) raise_and_focus (priv->app); } +/* Sets the sensitivity of the relevant alarm widgets. Called when filling + the widgets initially and when the alarm button is toggled. */ static void alarm_toggle (GtkWidget *toggle, EventEditor *ee) { @@ -2728,6 +2833,8 @@ alarm_toggle (GtkWidget *toggle, EventEditor *ee) priv = ee->priv; + event_editor_set_changed (ee, TRUE); + active = GTK_TOGGLE_BUTTON (toggle)->active; if (toggle == priv->alarm_display) { @@ -2751,7 +2858,7 @@ alarm_toggle (GtkWidget *toggle, EventEditor *ee) gtk_widget_set_sensitive (alarm_unit, active); } -/* Checks if the day range occupies a single whole day, and if so, check. the +/* Checks if the event's time starts and ends at midnight, and sets the * "all day event" box accordingly. */ static void @@ -2759,9 +2866,7 @@ check_all_day (EventEditor *ee) { EventEditorPrivate *priv; time_t ev_start, ev_end; - time_t start_begin_day, end_begin_day; - struct tm tm_start, tm_end; - gboolean all_day; + gboolean all_day = FALSE; priv = ee->priv; @@ -2773,36 +2878,26 @@ check_all_day (EventEditor *ee) ev_end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); g_return_if_fail (ev_end != -1); -#if 0 /* all day event checkbox */ if (time_day_begin (ev_start) == ev_start && time_day_begin (ev_end) == ev_end) - e_dialog_toggle_set (priv->all_day_event, TRUE); -#endif - - start_begin_day = time_day_begin (ev_start); - end_begin_day = time_day_begin (ev_end); - - tm_start = *localtime (&start_begin_day); - tm_end = *localtime (&end_begin_day); - - /* FIXME: This will only set all_day to TRUE if the event lasts 1 day. - But we also want it TRUE for multiple-day events. */ - tm_end.tm_mday--; - if (mktime (&tm_start) == mktime (&tm_end)) all_day = TRUE; - else - all_day = FALSE; 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 box clicked + * 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) @@ -2814,9 +2909,11 @@ set_all_day (GtkWidget *toggle, EventEditor *ee) priv = ee->priv; - /* When the all_day toggle is 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 + 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 @@ -2824,40 +2921,48 @@ set_all_day (GtkWidget *toggle, EventEditor *ee) (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 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. */ + 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 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); - start_tm.tm_min = 0; - start_tm.tm_sec = 0; - if (all_day) + if (all_day) { + /* Round down to the start of the day. */ start_tm.tm_hour = 0; - else - start_tm.tm_hour = day_begin; - - /* will set recur start too */ - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), mktime (&start_tm)); + 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 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); - end_tm.tm_min = 0; - end_tm.tm_sec = 0; 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 before the event start, make it - end one hour after the start. mktime() will fix any + /* 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 @@ -2872,10 +2977,24 @@ set_all_day (GtkWidget *toggle, EventEditor *ee) } } + /* 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 @@ -2892,6 +3011,8 @@ date_changed_cb (EDateEdit *dedit, gpointer data) 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)); @@ -2899,11 +3020,18 @@ date_changed_cb (EDateEdit *dedit, gpointer data) end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); g_return_if_fail (end != -1); - if (start > end) { + if (start >= end) { tm_start = *localtime (&start); tm_end = *localtime (&end); - if (GTK_WIDGET (dedit) == priv->start_time) { + 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; @@ -2989,6 +3117,7 @@ recurrence_exception_add_cb (GtkWidget *widget, EventEditor *ee) 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); @@ -3009,6 +3138,8 @@ recurrence_exception_modify_cb (GtkWidget *widget, EventEditor *ee) 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); @@ -3033,6 +3164,8 @@ recurrence_exception_delete_cb (GtkWidget *widget, EventEditor *ee) if (!clist->selection) return; + event_editor_set_changed (ee, TRUE); + sel = GPOINTER_TO_INT (clist->selection->data); g_free (gtk_clist_get_row_data (clist, sel)); /* free the time_t stored there */ @@ -3092,3 +3225,76 @@ make_spin_button (int val, int low, int high) 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; +} + + +/* 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; + GtkWidget *dialog; + + priv = ee->priv; + + if (!priv->changed) + return TRUE; + + dialog = gnome_message_box_new (_("Do you want to save changes?"), + GNOME_MESSAGE_BOX_QUESTION, + GNOME_STOCK_BUTTON_YES, + GNOME_STOCK_BUTTON_NO, + GNOME_STOCK_BUTTON_CANCEL, + NULL); + + gnome_dialog_set_parent (GNOME_DIALOG (dialog), + GTK_WINDOW (priv->app)); + + switch (gnome_dialog_run_and_close (GNOME_DIALOG (dialog))) { + 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; + } +} diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index b423ffcd41..3b16c46f70 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -1959,7 +1959,7 @@ gnome_calendar_on_date_navigator_selection_changed (ECalendarItem *calitem, Note that if weekends are compressed and the week start day is set to Sunday we don't actually show complete weeks in the Week view, so this may need tweaking. */ - if ((g_date_weekday (&new_start_date) + 5) % 7 == calendar_config_get_week_start_day ()) + if (g_date_weekday (&new_start_date) % 7 == calendar_config_get_week_start_day ()) starts_on_week_start_day = TRUE; /* Switch views as appropriate, and change the number of days or weeks |