diff options
Diffstat (limited to 'calendar/gui/e-day-view.c')
-rw-r--r-- | calendar/gui/e-day-view.c | 425 |
1 files changed, 381 insertions, 44 deletions
diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index c1da656ccd..9d7782462c 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -222,6 +222,9 @@ typedef gboolean (* EDayViewForeachEventCallback) (EDayView *day_view, gint event_num, gpointer data); +static void e_day_view_foreach_event (EDayView *day_view, + EDayViewForeachEventCallback callback, + gpointer data); static void e_day_view_foreach_event_with_uid (EDayView *day_view, const gchar *uid, EDayViewForeachEventCallback callback, @@ -380,6 +383,14 @@ static gboolean e_day_view_remove_event_cb (EDayView *day_view, gint event_num, gpointer data); static void e_day_view_normalize_selection (EDayView *day_view); +static gboolean e_day_view_set_show_times_cb (EDayView *day_view, + gint day, + gint event_num, + gpointer data); +static time_t e_day_view_find_work_week_start (EDayView *day_view, + time_t start_time); +static void e_day_view_recalc_work_week (EDayView *day_view); +static void e_day_view_recalc_work_week_days_shown (EDayView *day_view); static GtkTableClass *parent_class; @@ -463,7 +474,6 @@ e_day_view_init (EDayView *day_view) day_view->lower = 0; day_view->upper = 0; - /* FIXME: Initialize day_starts. */ day_view->work_week_view = FALSE; day_view->days_shown = 1; @@ -490,6 +500,8 @@ e_day_view_init (EDayView *day_view) day_view->work_day_start_minute = 0; day_view->work_day_end_hour = 17; day_view->work_day_end_minute = 0; + day_view->show_event_end_times = TRUE; + day_view->week_start_day = 0; day_view->scroll_to_work_day = TRUE; day_view->editing_event_day = -1; @@ -522,6 +534,12 @@ e_day_view_init (EDayView *day_view) if (!day_view->large_font) g_warning ("Couldn't load font"); + /* String to use in 12-hour time format for times in the morning. */ + day_view->am_string = _("am"); + + /* String to use in 12-hour time format for times in the afternoon. */ + day_view->pm_string = _("pm"); + /* * Top Canvas @@ -1065,6 +1083,11 @@ e_day_view_style_set (GtkWidget *widget, day_view->max_minute_width = max_minute_width; day_view->colon_width = gdk_string_width (font, ":"); + day_view->am_string_width = gdk_string_width (font, + day_view->am_string); + day_view->pm_string_width = gdk_string_width (font, + day_view->pm_string); + /* Calculate the width of the time column. */ times_width = e_day_view_time_item_get_column_width (E_DAY_VIEW_TIME_ITEM (day_view->time_canvas_item)); gtk_widget_set_usize (day_view->time_canvas, times_width, -1); @@ -1252,8 +1275,6 @@ e_day_view_set_calendar (EDayView *day_view, g_return_if_fail (E_IS_DAY_VIEW (day_view)); day_view->calendar = calendar; - - /* FIXME: free current events? */ } @@ -1285,6 +1306,9 @@ obj_updated_cb (CalClient *client, const char *uid, gpointer data) day_view = E_DAY_VIEW (data); + /* Sanity check. */ + g_return_if_fail (client == day_view->client); + /* If our time hasn't been set yet, just return. */ if (day_view->lower == 0 && day_view->upper == 0) return; @@ -1459,8 +1483,46 @@ e_day_view_update_event_cb (EDayView *day_view, } +/* This calls a given function for each event instance (in both views). + If the callback returns TRUE the iteration is stopped. + Note that it is safe for the callback to remove the event (since we + step backwards through the arrays). */ +static void +e_day_view_foreach_event (EDayView *day_view, + EDayViewForeachEventCallback callback, + gpointer data) +{ + EDayViewEvent *event; + gint day, event_num; + + for (day = 0; day < day_view->days_shown; day++) { + for (event_num = day_view->events[day]->len - 1; + event_num >= 0; + event_num--) { + event = &g_array_index (day_view->events[day], + EDayViewEvent, event_num); + + if (!(*callback) (day_view, day, event_num, data)) + return; + } + } + + for (event_num = day_view->long_events->len - 1; + event_num >= 0; + event_num--) { + event = &g_array_index (day_view->long_events, + EDayViewEvent, event_num); + + if (!(*callback) (day_view, E_DAY_VIEW_LONG_EVENT, event_num, + data)) + return; + } +} + + /* This calls a given function for each event instance that matches the given - uid. Note that it is safe for the callback to remove the event (since we + uid. If the callback returns TRUE the iteration is stopped. + Note that it is safe for the callback to remove the event (since we step backwards through the arrays). */ static void e_day_view_foreach_event_with_uid (EDayView *day_view, @@ -1553,9 +1615,9 @@ e_day_view_update_event_label (EDayView *day_view, gint event_num) { EDayViewEvent *event; - char *text; + char *text, *start_suffix, *end_suffix; gboolean free_text = FALSE, editing_event = FALSE; - gint offset, start_minute, end_minute; + gint offset, start_hour, start_minute, end_hour, end_minute; CalComponentText summary; event = &g_array_index (day_view->events[day], EDayViewEvent, @@ -1574,17 +1636,70 @@ e_day_view_update_event_label (EDayView *day_view, if (!editing_event && (event->start_minute % day_view->mins_per_row != 0 - || event->end_minute % day_view->mins_per_row != 0)) { + || (day_view->show_event_end_times + && event->end_minute % day_view->mins_per_row != 0))) { offset = day_view->first_hour_shown * 60 + day_view->first_minute_shown; start_minute = offset + event->start_minute; end_minute = offset + event->end_minute; - text = g_strdup_printf ("%02i:%02i-%02i:%02i %s", - start_minute / 60, - start_minute % 60, - end_minute / 60, - end_minute % 60, - text); + + start_hour = start_minute / 60; + start_minute = start_minute % 60; + + end_hour = end_minute / 60; + end_minute = end_minute % 60; + + if (day_view->use_24_hour_format) { + if (day_view->show_event_end_times) { + /* 24 hour format with end time. */ + text = g_strdup_printf + ("%02i:%02i-%02i:%02i %s", + start_hour, start_minute, + end_hour, end_minute, + text); + } else { + /* 24 hour format without end time. */ + text = g_strdup_printf + ("%02i:%02i %s", + start_hour, start_minute, + text); + } + } else { + start_suffix = end_suffix = day_view->am_string; + + if (start_hour >= 12) { + start_hour -= 12; + start_suffix = day_view->pm_string; + } + if (end_hour >= 12) { + end_hour -= 12; + end_suffix = day_view->pm_string; + } + + /* We display 1-12 rather than 0-11 for hours. */ + if (start_hour == 0) + start_hour = 12; + if (end_hour == 0) + end_hour = 12; + + if (day_view->show_event_end_times) { + /* 12 hour format with end time. */ + text = g_strdup_printf + ("%02i:%02i%s-%02i:%02i%s %s", + start_hour, start_minute, + start_suffix, + end_hour, end_minute, + end_suffix, + text); + } else { + /* 12 hour format without end time. */ + text = g_strdup_printf + ("%02i:%02i%s %s", + start_hour % 12, start_minute, + start_suffix, + text); + } + } free_text = TRUE; } @@ -1717,7 +1832,6 @@ e_day_view_set_selected_time_range (EDayView *day_view, time_t start_time, time_t end_time) { - GDate date; time_t lower; gint start_row, start_col, end_row, end_col; gboolean need_redraw = FALSE, start_in_grid, end_in_grid; @@ -1727,16 +1841,11 @@ e_day_view_set_selected_time_range (EDayView *day_view, /* Calculate the first day that should be shown, based on start_time and the days_shown setting. If we are showing 1 day it is just the start of the day given by start_time, otherwise it is the previous - Monday. */ + work-week start day. */ if (!day_view->work_week_view) { lower = time_day_begin (start_time); } else { - g_date_clear (&date, 1); - g_date_set_time (&date, start_time); - g_date_subtract_days (&date, g_date_weekday (&date) - 1); - lower = time_from_day (g_date_year (&date), - g_date_month (&date) - 1, - g_date_day (&date)); + lower = e_day_view_find_work_week_start (day_view, start_time); } /* See if we need to change the days shown. */ @@ -1790,6 +1899,46 @@ e_day_view_set_selected_time_range (EDayView *day_view, } +/* Finds the start of the working week which includes the given time. */ +static time_t +e_day_view_find_work_week_start (EDayView *day_view, + time_t start_time) +{ + GDate date; + gint weekday, day, i, offset; + + g_date_clear (&date, 1); + g_date_set_time (&date, start_time); + + /* The start of the work-week is the first working day after the + week start day. */ + + /* Get the weekday corresponding to start_time, 0 (Sun) to 6 (Sat). */ + weekday = g_date_weekday (&date) % 7; + + /* Calculate the first working day of the week, 0 (Sun) to 6 (Sat). + It will automatically default to the week start day if no days + are set as working days. */ + day = (day_view->week_start_day + 1) % 7; + for (i = 0; i < 7; i++) { + if (day_view->working_days & (1 << day)) + break; + day = (day + 1) % 7; + } + + /* Calculate how many days we need to go back to the first workday. */ + offset = (weekday + 7 - day) % 7; + + g_print ("Weekday: %i Day: %i Offset: %i\n", weekday, day, offset); + + g_date_subtract_days (&date, offset); + + return time_from_day (g_date_year (&date), + g_date_month (&date) - 1, + g_date_day (&date)); +} + + /* Returns the selected time range. */ void e_day_view_get_selected_time_range (EDayView *day_view, @@ -1868,7 +2017,8 @@ e_day_view_set_work_week_view (EDayView *day_view, day_view->work_week_view = work_week_view; - /* FIXME: need to recalc the first day shown if now work-week view. */ + if (day_view->work_week_view) + e_day_view_recalc_work_week (day_view); } @@ -1889,12 +2039,18 @@ e_day_view_set_days_shown (EDayView *day_view, g_return_if_fail (days_shown >= 1); g_return_if_fail (days_shown <= E_DAY_VIEW_MAX_DAYS); - if (day_view->days_shown != days_shown) { - day_view->days_shown = days_shown; - e_day_view_recalc_day_starts (day_view, day_view->lower); - e_day_view_recalc_cell_sizes (day_view); - e_day_view_queue_reload_events (day_view); - } + if (day_view->days_shown = days_shown) + return; + + day_view->days_shown = days_shown; + + /* If the date isn't set, just return. */ + if (day_view->lower == 0 && day_view->upper == 0) + return; + + e_day_view_recalc_day_starts (day_view, day_view->lower); + e_day_view_recalc_cell_sizes (day_view); + e_day_view_queue_reload_events (day_view); } @@ -1934,6 +2090,11 @@ e_day_view_set_mins_per_row (EDayView *day_view, for (day = 0; day < E_DAY_VIEW_MAX_DAYS; day++) day_view->need_layout[day] = TRUE; + /* We need to update all the day event labels since the start & end + times may or may not be on row boundaries any more. */ + e_day_view_foreach_event (day_view, + e_day_view_set_show_times_cb, NULL); + /* We must layout the events before updating the scroll region, since that will result in a redraw which would crash otherwise. */ e_day_view_check_layout (day_view); @@ -1961,10 +2122,55 @@ e_day_view_set_working_days (EDayView *day_view, { g_return_if_fail (E_IS_DAY_VIEW (day_view)); - if (day_view->working_days != days) { - day_view->working_days = days; - gtk_widget_queue_draw (day_view->main_canvas); + if (day_view->working_days == days) + return; + + day_view->working_days = days; + + if (day_view->work_week_view) + e_day_view_recalc_work_week (day_view); + + /* We have to do this, as the new working days may have no effect on + the days shown, but we still want the background color to change. */ + gtk_widget_queue_draw (day_view->main_canvas); +} + + +static void +e_day_view_recalc_work_week_days_shown (EDayView *day_view) +{ + gint first_day, last_day, i, days_shown; + gboolean has_working_days = FALSE; + + /* Find the first working day in the week, 0 (Sun) to 6 (Sat). */ + first_day = (day_view->week_start_day + 1) % 7; + for (i = 0; i < 7; i++) { + if (day_view->working_days & (1 << first_day)) { + has_working_days = TRUE; + break; + } + first_day = (first_day + 1) % 7; + } + + if (has_working_days) { + /* Now find the last working day of the week, backwards. */ + last_day = day_view->week_start_day % 7; + for (i = 0; i < 7; i++) { + if (day_view->working_days & (1 << last_day)) + break; + last_day = (last_day + 6) % 7; + } + /* Now calculate the days we need to show to include all the + working days in the week. Add 1 to make it inclusive. */ + days_shown = (last_day + 7 - first_day) % 7 + 1; + g_print ("First day: %i Last: %i Days: %i\n", + first_day, last_day, days_shown); + } else { + /* If no working days are set, just use 7. */ + days_shown = 7; } + + e_day_view_set_days_shown (day_view, days_shown); } @@ -2020,11 +2226,120 @@ e_day_view_set_24_hour_format (EDayView *day_view, { g_return_if_fail (E_IS_DAY_VIEW (day_view)); - if (day_view->use_24_hour_format != use_24_hour) { - day_view->use_24_hour_format = use_24_hour; + if (day_view->use_24_hour_format == use_24_hour) + return; - /* FIXME: Eventually we need to do a re-layout. */ - gtk_widget_queue_draw (day_view->main_canvas); + day_view->use_24_hour_format = use_24_hour; + + /* We need to update all the text in the events since they may contain + the time in the old format. */ + e_day_view_foreach_event (day_view, e_day_view_set_show_times_cb, + NULL); + + /* FIXME: We need to re-layout the top canvas since the time + format affects the sizes. */ + gtk_widget_queue_draw (day_view->time_canvas); + gtk_widget_queue_draw (day_view->top_canvas); +} + + +/* Whether we display event end times in the main canvas. */ +gboolean +e_day_view_get_show_event_end_times (EDayView *day_view) +{ + g_return_val_if_fail (E_IS_DAY_VIEW (day_view), TRUE); + + return day_view->show_event_end_times; +} + + +void +e_day_view_set_show_event_end_times (EDayView *day_view, + gboolean show) +{ + g_return_if_fail (E_IS_DAY_VIEW (day_view)); + + if (day_view->show_event_end_times != show) { + day_view->show_event_end_times = show; + e_day_view_foreach_event (day_view, + e_day_view_set_show_times_cb, NULL); + } +} + + +/* This is a callback used to update all day event labels. */ +static gboolean +e_day_view_set_show_times_cb (EDayView *day_view, + gint day, + gint event_num, + gpointer data) +{ + g_print ("In e_day_view_set_show_times_cb day:%i event_num:%i\n", + day, event_num); + + if (day != E_DAY_VIEW_LONG_EVENT) { + e_day_view_update_event_label (day_view, day, event_num); + } + + return TRUE; +} + + +/* The first day of the week, 0 (Monday) to 6 (Sunday). */ +gint +e_day_view_get_week_start_day (EDayView *day_view) +{ + g_return_val_if_fail (E_IS_DAY_VIEW (day_view), 0); + + return day_view->week_start_day; +} + + +void +e_day_view_set_week_start_day (EDayView *day_view, + gint week_start_day) +{ + g_return_if_fail (E_IS_DAY_VIEW (day_view)); + g_return_if_fail (week_start_day >= 0); + g_return_if_fail (week_start_day < 7); + + g_print ("In e_day_view_set_week_start_day day: %i\n", week_start_day); + + if (day_view->week_start_day == week_start_day) + return; + + day_view->week_start_day = week_start_day; + + if (day_view->work_week_view) + e_day_view_recalc_work_week (day_view); +} + + +static void +e_day_view_recalc_work_week (EDayView *day_view) +{ + time_t lower; + + /* If we aren't showing the work week, just return. */ + if (!day_view->work_week_view) + return; + + /* If the date isn't set, just return. */ + if (day_view->lower == 0 && day_view->upper == 0) + return; + + e_day_view_recalc_work_week_days_shown (day_view); + + lower = e_day_view_find_work_week_start (day_view, day_view->lower); + if (lower != day_view->lower) { + /* Reset the selection, as it may disappear. */ + day_view->selection_start_day = -1; + + e_day_view_recalc_day_starts (day_view, lower); + e_day_view_queue_reload_events (day_view); + + /* This updates the date navigator. */ + e_day_view_update_calendar_selection_time (day_view); } } @@ -2719,7 +3034,11 @@ e_day_view_on_new_appointment (GtkWidget *widget, gpointer data) cal_component_commit_sequence (comp); - gnome_calendar_edit_object (day_view->calendar, comp); + if (day_view->calendar) + gnome_calendar_edit_object (day_view->calendar, comp); + else + g_warning ("Calendar not set"); + gtk_object_unref (GTK_OBJECT (comp)); } @@ -2736,7 +3055,10 @@ e_day_view_on_edit_appointment (GtkWidget *widget, gpointer data) if (event == NULL) return; - gnome_calendar_edit_object (day_view->calendar, event->comp); + if (day_view->calendar) + gnome_calendar_edit_object (day_view->calendar, event->comp); + else + g_warning ("Calendar not set"); } @@ -2805,6 +3127,9 @@ e_day_view_on_unrecur_appointment (GtkWidget *widget, gpointer data) if (event == NULL) return; + date.value = &itt; + date.tzid = NULL; + /* For the recurring object, we add an exception to get rid of the instance. */ @@ -2917,8 +3242,13 @@ e_day_view_update_calendar_selection_time (EDayView *day_view) time_t start, end; e_day_view_get_selected_time_range (day_view, &start, &end); - gnome_calendar_set_selected_time_range (day_view->calendar, - start, end); + + g_print ("Start: %s", ctime (&start)); + g_print ("End : %s", ctime (&end)); + + if (day_view->calendar) + gnome_calendar_set_selected_time_range (day_view->calendar, + start, end); } @@ -3500,8 +3830,11 @@ e_day_view_reload_events (EDayView *day_view) /* If both lower & upper are 0, then the time range hasn't been set, so we don't try to load any events. */ - if (day_view->calendar - && (day_view->lower != 0 || day_view->upper != 0)) { + if (day_view->lower != 0 || day_view->upper != 0) { +#if 0 + g_print ("EDayView (%s) generating instances\n", + day_view->work_week_view ? "Work Week" : "1 Day View"); +#endif cal_client_generate_instances (day_view->client, CALOBJ_TYPE_EVENT, day_view->lower, @@ -3969,7 +4302,9 @@ e_day_view_layout_day_events (EDayView *day_view, rows. */ guint16 group_starts[12 * 24]; - /* Reset the cols_per_row array, and initialize the connected rows. */ + /* Reset the cols_per_row array, and initialize the connected rows so + that all rows are not connected - each row is the start of a new + group. */ for (row = 0; row < day_view->rows; row++) { day_view->cols_per_row[day][row] = 0; group_starts[row] = row; @@ -4647,7 +4982,8 @@ static void e_day_view_cursor_key_left (EDayView *day_view, GdkEventKey *event) { if (day_view->selection_start_day == 0) { - gnome_calendar_previous (day_view->calendar); + if (day_view->calendar) + gnome_calendar_previous (day_view->calendar); } else { day_view->selection_start_day--; day_view->selection_end_day--; @@ -4665,7 +5001,8 @@ static void e_day_view_cursor_key_right (EDayView *day_view, GdkEventKey *event) { if (day_view->selection_end_day == day_view->days_shown - 1) { - gnome_calendar_next (day_view->calendar); + if (day_view->calendar) + gnome_calendar_next (day_view->calendar); } else { day_view->selection_start_day++; day_view->selection_end_day++; |