diff options
Diffstat (limited to 'calendar/gui')
-rw-r--r-- | calendar/gui/calendar-commands.c | 75 | ||||
-rw-r--r-- | calendar/gui/e-day-view-main-item.c | 45 | ||||
-rw-r--r-- | calendar/gui/e-day-view.c | 406 | ||||
-rw-r--r-- | calendar/gui/e-day-view.h | 54 | ||||
-rw-r--r-- | calendar/gui/e-week-view-main-item.c | 12 | ||||
-rw-r--r-- | calendar/gui/e-week-view.c | 363 | ||||
-rw-r--r-- | calendar/gui/e-week-view.h | 57 | ||||
-rw-r--r-- | calendar/gui/gnome-cal.c | 731 | ||||
-rw-r--r-- | calendar/gui/gnome-cal.h | 89 |
9 files changed, 1315 insertions, 517 deletions
diff --git a/calendar/gui/calendar-commands.c b/calendar/gui/calendar-commands.c index 564512dfe4..e5e04dbf8b 100644 --- a/calendar/gui/calendar-commands.c +++ b/calendar/gui/calendar-commands.c @@ -28,11 +28,11 @@ #include "workweekview.xpm" #include "weekview.xpm" #include "monthview.xpm" - #if 0 #include "yearview.xpm" #endif + /* The username, used to set the `owner' field of the event */ char *user_name; @@ -322,7 +322,12 @@ static void show_day_view_clicked (BonoboUIHandler *uih, void *user_data, const char *path) { GnomeCalendar *gcal = GNOME_CALENDAR (user_data); - gnome_calendar_set_view (gcal, "dayview"); + + /* If we are setting up a view internally we just ignore the clicks. */ + if (gcal->ignore_view_button_clicks) + return; + + gnome_calendar_set_view (gcal, "dayview", FALSE); gtk_widget_grab_focus (gcal->day_view); } @@ -330,7 +335,12 @@ static void show_work_week_view_clicked (BonoboUIHandler *uih, void *user_data, const char *path) { GnomeCalendar *gcal = GNOME_CALENDAR (user_data); - gnome_calendar_set_view (gcal, "workweekview"); + + /* If we are setting up a view internally we just ignore the clicks. */ + if (gcal->ignore_view_button_clicks) + return; + + gnome_calendar_set_view (gcal, "workweekview", FALSE); gtk_widget_grab_focus (gcal->work_week_view); } @@ -338,7 +348,12 @@ static void show_week_view_clicked (BonoboUIHandler *uih, void *user_data, const char *path) { GnomeCalendar *gcal = GNOME_CALENDAR (user_data); - gnome_calendar_set_view (gcal, "weekview"); + + /* If we are setting up a view internally we just ignore the clicks. */ + if (gcal->ignore_view_button_clicks) + return; + + gnome_calendar_set_view (gcal, "weekview", FALSE); gtk_widget_grab_focus (gcal->week_view); } @@ -346,19 +361,15 @@ static void show_month_view_clicked (BonoboUIHandler *uih, void *user_data, const char *path) { GnomeCalendar *gcal = GNOME_CALENDAR (user_data); - gnome_calendar_set_view (gcal, "monthview"); + + /* If we are setting up a view internally we just ignore the clicks. */ + if (gcal->ignore_view_button_clicks) + return; + + gnome_calendar_set_view (gcal, "monthview", FALSE); gtk_widget_grab_focus (gcal->month_view); } -#if 0 -static void -show_year_view_clicked (BonoboUIHandler *uih, void *user_data, const char *path) -{ - GnomeCalendar *gcal = GNOME_CALENDAR (user_data); - gnome_calendar_set_view (gcal, "yearview"); - gtk_widget_grab_focus (gcal->year_view); -} -#endif static void new_calendar_cmd (BonoboUIHandler *uih, void *user_data, const char *path) @@ -487,6 +498,8 @@ properties_cmd (BonoboUIHandler *uih, void *user_data, const char *path) } +/* Note: if the order of these is changed, make sure you change the indices + used to access the widgets in calendar_control_activate(). */ static GnomeUIInfo gnome_toolbar_view_buttons [] = { GNOMEUIINFO_RADIOITEM (N_("Day"), N_("Show 1 day"), show_day_view_clicked, @@ -564,8 +577,6 @@ calendar_control_activate (BonoboControl *control, BonoboControl *toolbar_control; GnomeUIBuilderData uibdata; BonoboUIHandler *uih; - gchar *page_name; - gint button, i; int behavior; uih = bonobo_control_get_ui_handler (control); @@ -591,30 +602,15 @@ calendar_control_activate (BonoboControl *control, /*gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));*/ - for (i = 0; i < GNOME_CALENDAR_NUM_VIEWS; i++) - cal->view_toolbar_buttons[i] = gnome_toolbar_view_buttons[i].widget; - /* Note that these indices should correspond with the button indices - in gnome_toolbar_view_buttons. */ - page_name = gnome_calendar_get_current_view_name (cal); - if (!strcmp (page_name, "dayview")) { - button = 0; - } else if (!strcmp (page_name, "workweekview")) { - button = 1; - } else if (!strcmp (page_name, "weekview")) { - button = 2; - } else if (!strcmp (page_name, "monthview")) { - button = 3; -#if 0 - } else if (!strcmp (page_name, "yearview")) { - button = 4; -#endif - } else { - g_warning ("Unknown calendar view: %s", page_name); - button = 0; - } + in the gnome_toolbar_view_buttons UIINFO struct. */ + cal->day_button = gnome_toolbar_view_buttons[0].widget; + cal->work_week_button = gnome_toolbar_view_buttons[1].widget; + cal->week_button = gnome_toolbar_view_buttons[2].widget; + cal->month_button = gnome_toolbar_view_buttons[3].widget; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cal->view_toolbar_buttons[button]), TRUE); + /* This makes the appropriate radio button in the toolbar active. */ + gnome_calendar_update_view_buttons (cal); gtk_widget_show_all (toolbar); @@ -730,7 +726,8 @@ new_calendar (char *full_name, char *geometry, char *page, gboolean hidden) } if (page) - gnome_calendar_set_view (GNOME_CALENDAR (toplevel), page); + gnome_calendar_set_view (GNOME_CALENDAR (toplevel), page, + FALSE); gtk_signal_connect (GTK_OBJECT (toplevel), "delete_event", GTK_SIGNAL_FUNC(calendar_close_event), toplevel); diff --git a/calendar/gui/e-day-view-main-item.c b/calendar/gui/e-day-view-main-item.c index 8353c0497e..7b2449b7bf 100644 --- a/calendar/gui/e-day-view-main-item.c +++ b/calendar/gui/e-day-view-main-item.c @@ -187,8 +187,9 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable, gint day, grid_y1, grid_y2; gint work_day_start_row, work_day_end_row; gint work_day_start_y, work_day_end_y; - gint work_day_x, work_day_w; + gint day_x, day_w, work_day; gint start_row, end_row, rect_x, rect_y, rect_width, rect_height; + struct tm *day_start; #if 0 g_print ("In e_day_view_main_item_draw %i,%i %ix%i\n", @@ -212,20 +213,34 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable, work_day_end_row = e_day_view_convert_time_to_row (day_view, day_view->work_day_end_hour, day_view->work_day_end_minute); work_day_end_y = work_day_end_row * day_view->row_height - y; - work_day_x = day_view->day_offsets[0] - x; - work_day_w = width - work_day_x; - gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]); - gdk_draw_rectangle (drawable, gc, TRUE, - work_day_x, 0 - y, - work_day_w, work_day_start_y - (0 - y)); - gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING]); - gdk_draw_rectangle (drawable, gc, TRUE, - work_day_x, work_day_start_y, - work_day_w, work_day_end_y - work_day_start_y); - gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]); - gdk_draw_rectangle (drawable, gc, TRUE, - work_day_x, work_day_end_y, - work_day_w, height - work_day_end_y); + for (day = 0; day < day_view->days_shown; day++) { + day_start = localtime (&day_view->day_starts[day]); + + work_day = day_view->working_days & (1 << day_start->tm_wday); + + day_x = day_view->day_offsets[day] - x; + day_w = day_view->day_widths[day]; + + if (work_day) { + gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]); + gdk_draw_rectangle (drawable, gc, TRUE, + day_x, 0 - y, + day_w, work_day_start_y - (0 - y)); + gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING]); + gdk_draw_rectangle (drawable, gc, TRUE, + day_x, work_day_start_y, + day_w, work_day_end_y - work_day_start_y); + gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]); + gdk_draw_rectangle (drawable, gc, TRUE, + day_x, work_day_end_y, + day_w, height - work_day_end_y); + } else { + gdk_gc_set_foreground (gc, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]); + gdk_draw_rectangle (drawable, gc, TRUE, + day_x, 0, + day_w, height); + } + } /* Paint the selection background. */ if (GTK_WIDGET_HAS_FOCUS (day_view) diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index 1767624627..32d9380bb5 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -194,6 +194,7 @@ static void e_day_view_on_event_right_click (EDayView *day_view, static void e_day_view_recalc_day_starts (EDayView *day_view, time_t start_time); static void e_day_view_recalc_num_rows (EDayView *day_view); +static void e_day_view_recalc_cell_sizes (EDayView *day_view); static EDayViewPosition e_day_view_convert_position_in_top_canvas (EDayView *day_view, gint x, @@ -225,6 +226,8 @@ static void e_day_view_foreach_event_with_uid (EDayView *day_view, EDayViewForeachEventCallback callback, gpointer data); +static void e_day_view_queue_reload_events (EDayView *day_view); +static gboolean e_day_view_reload_events_idle_cb (gpointer data); static void e_day_view_reload_events (EDayView *day_view); static void e_day_view_free_events (EDayView *day_view); static void e_day_view_free_event_array (EDayView *day_view, @@ -432,15 +435,11 @@ e_day_view_class_init (EDayViewClass *class) static void e_day_view_init (EDayView *day_view) { - GdkColormap *colormap; - gboolean success[E_DAY_VIEW_COLOR_LAST]; - gint day, nfailed; + gint day; GnomeCanvasGroup *canvas_group; GTK_WIDGET_SET_FLAGS (day_view, GTK_CAN_FOCUS); - colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view)); - day_view->calendar = NULL; day_view->client = NULL; @@ -449,6 +448,7 @@ e_day_view_init (EDayView *day_view) day_view->long_events_sorted = TRUE; day_view->long_events_need_layout = FALSE; day_view->long_events_need_reshape = FALSE; + day_view->reload_events_idle_id = 0; for (day = 0; day < E_DAY_VIEW_MAX_DAYS; day++) { day_view->events[day] = g_array_new (FALSE, FALSE, @@ -463,6 +463,7 @@ e_day_view_init (EDayView *day_view) day_view->upper = 0; /* FIXME: Initialize day_starts. */ + day_view->work_week_view = FALSE; day_view->days_shown = 1; day_view->mins_per_row = 30; @@ -480,6 +481,10 @@ e_day_view_init (EDayView *day_view) day_view->main_gc = NULL; e_day_view_recalc_num_rows (day_view); + day_view->working_days = E_DAY_VIEW_MONDAY | E_DAY_VIEW_TUESDAY + | E_DAY_VIEW_WEDNESDAY | E_DAY_VIEW_THURSDAY + | E_DAY_VIEW_FRIDAY; + day_view->work_day_start_hour = 9; day_view->work_day_start_minute = 0; day_view->work_day_end_hour = 17; @@ -518,48 +523,6 @@ e_day_view_init (EDayView *day_view) g_warning ("Couldn't load font"); - /* Allocate the colors. */ -#if 1 - day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].red = 247 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].green = 247 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].blue = 244 * 257; - - day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].red = 216 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].green = 216 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].blue = 214 * 257; -#else - - /* FG: MistyRose1, LightPink3 | RosyBrown | MistyRose3. */ - - day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].red = 255 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].green = 228 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].blue = 225 * 257; - - day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].red = 238 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].green = 162 * 257; - day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].blue = 173 * 257; -#endif - - day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].red = 0; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].green = 0; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].blue = 65535; - - day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].red = 65535; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].green = 65535; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].blue = 65535; - - day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].red = 0; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].green = 0; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].blue = 0; - - nfailed = gdk_colormap_alloc_colors (colormap, day_view->colors, - E_DAY_VIEW_COLOR_LAST, FALSE, - TRUE, success); - if (nfailed) - g_warning ("Failed to allocate all colors"); - - - /* * Top Canvas */ @@ -612,8 +575,6 @@ e_day_view_init (EDayView *day_view) day_view->resize_long_event_rect_item = gnome_canvas_item_new (canvas_group, gnome_canvas_rect_get_type(), - "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND], - "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], NULL); gnome_canvas_item_hide (day_view->resize_long_event_rect_item); @@ -621,8 +582,6 @@ e_day_view_init (EDayView *day_view) gnome_canvas_item_new (canvas_group, gnome_canvas_rect_get_type (), "width_pixels", 1, - "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND], - "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], NULL); gnome_canvas_item_hide (day_view->drag_long_event_rect_item); @@ -696,16 +655,12 @@ e_day_view_init (EDayView *day_view) day_view->resize_rect_item = gnome_canvas_item_new (canvas_group, gnome_canvas_rect_get_type(), - "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND], - "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], NULL); gnome_canvas_item_hide (day_view->resize_rect_item); day_view->resize_bar_item = gnome_canvas_item_new (canvas_group, gnome_canvas_rect_get_type(), - "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR], - "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], NULL); gnome_canvas_item_hide (day_view->resize_bar_item); @@ -713,8 +668,6 @@ e_day_view_init (EDayView *day_view) gnome_canvas_item_new (canvas_group, gnome_canvas_rect_get_type (), "width_pixels", 1, - "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR], - "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], NULL); gnome_canvas_item_hide (day_view->main_canvas_top_resize_bar_item); @@ -722,8 +675,6 @@ e_day_view_init (EDayView *day_view) gnome_canvas_item_new (canvas_group, gnome_canvas_rect_get_type (), "width_pixels", 1, - "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR], - "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], NULL); gnome_canvas_item_hide (day_view->main_canvas_bottom_resize_bar_item); @@ -732,8 +683,6 @@ e_day_view_init (EDayView *day_view) gnome_canvas_item_new (canvas_group, gnome_canvas_rect_get_type (), "width_pixels", 1, - "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND], - "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], NULL); gnome_canvas_item_hide (day_view->drag_rect_item); @@ -741,8 +690,6 @@ e_day_view_init (EDayView *day_view) gnome_canvas_item_new (canvas_group, gnome_canvas_rect_get_type (), "width_pixels", 1, - "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR], - "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], NULL); gnome_canvas_item_hide (day_view->drag_bar_item); @@ -790,11 +737,6 @@ e_day_view_init (EDayView *day_view) gtk_widget_show (day_view->vscrollbar); - /* Create the pixmaps. */ - day_view->reminder_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &day_view->reminder_mask, NULL, bell_xpm); - day_view->recurrence_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &day_view->recurrence_mask, NULL, recur_xpm); - - /* Create the cursors. */ day_view->normal_cursor = gdk_cursor_new (GDK_TOP_LEFT_ARROW); day_view->move_cursor = gdk_cursor_new (GDK_FLEUR); @@ -851,14 +793,19 @@ e_day_view_destroy (GtkObject *object) day_view = E_DAY_VIEW (object); + e_day_view_stop_auto_scroll (day_view); + + if (day_view->reload_events_idle_id != 0) { + g_source_remove (day_view->reload_events_idle_id); + day_view->reload_events_idle_id = 0; + } + if (day_view->client) { gtk_signal_disconnect_by_data (GTK_OBJECT (day_view->client), day_view); gtk_object_unref (GTK_OBJECT (day_view->client)); day_view->client = NULL; } - e_day_view_stop_auto_scroll (day_view); - if (day_view->large_font) gdk_font_unref (day_view->large_font); @@ -880,12 +827,104 @@ static void e_day_view_realize (GtkWidget *widget) { EDayView *day_view; + GdkColormap *colormap; + gboolean success[E_DAY_VIEW_COLOR_LAST]; + gint nfailed; if (GTK_WIDGET_CLASS (parent_class)->realize) (*GTK_WIDGET_CLASS (parent_class)->realize)(widget); day_view = E_DAY_VIEW (widget); day_view->main_gc = gdk_gc_new (widget->window); + + colormap = gtk_widget_get_colormap (widget); + + /* Allocate the colors. */ + day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].red = 247 * 257; + day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].green = 247 * 257; + day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING].blue = 244 * 257; + + day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].red = 216 * 257; + day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].green = 216 * 257; + day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING].blue = 214 * 257; + + day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].red = 0; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].green = 0; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR].blue = 65535; + + day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].red = 65535; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].green = 65535; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].blue = 65535; + + day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].red = 0; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].green = 0; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER].blue = 0; + + nfailed = gdk_colormap_alloc_colors (colormap, day_view->colors, + E_DAY_VIEW_COLOR_LAST, FALSE, + TRUE, success); + if (nfailed) + g_warning ("Failed to allocate all colors"); + + + /* Create the pixmaps. */ + day_view->reminder_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &day_view->reminder_mask, NULL, bell_xpm); + day_view->recurrence_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &day_view->recurrence_mask, NULL, recur_xpm); + + + + /* Set the canvas item colors. */ + gnome_canvas_item_set (day_view->resize_long_event_rect_item, + "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND], + "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], + NULL); + + gnome_canvas_item_set (day_view->drag_long_event_rect_item, + "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND], + "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], + NULL); + + + gnome_canvas_item_set (day_view->resize_rect_item, + "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND], + "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], + NULL); + + gnome_canvas_item_set (day_view->resize_bar_item, + "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR], + "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], + NULL); + + gnome_canvas_item_set (day_view->main_canvas_top_resize_bar_item, + "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR], + "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], + NULL); + + gnome_canvas_item_set (day_view->main_canvas_bottom_resize_bar_item, + "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR], + "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], + NULL); + + + gnome_canvas_item_set (day_view->drag_rect_item, + "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND], + "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], + NULL); + + gnome_canvas_item_set (day_view->drag_bar_item, + "fill_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR], + "outline_color_gdk", &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER], + NULL); + + + /* Set the fonts for the text items used when dragging. */ + gnome_canvas_item_set (day_view->drag_long_event_item, + "font_gdk", GTK_WIDGET (day_view)->style->font, + NULL); + + gnome_canvas_item_set (day_view->drag_item, + "font_gdk", GTK_WIDGET (day_view)->style->font, + NULL); } @@ -893,12 +932,23 @@ static void e_day_view_unrealize (GtkWidget *widget) { EDayView *day_view; + GdkColormap *colormap; + gint i; day_view = E_DAY_VIEW (widget); gdk_gc_unref (day_view->main_gc); day_view->main_gc = NULL; + colormap = gtk_widget_get_colormap (widget); + for (i = 0; i < E_DAY_VIEW_COLOR_LAST; i++) + gdk_colors_free (colormap, &day_view->colors[i].pixel, 1, 0); + + gdk_pixmap_unref (day_view->reminder_icon); + day_view->reminder_icon = NULL; + gdk_pixmap_unref (day_view->recurrence_icon); + day_view->recurrence_icon = NULL; + if (GTK_WIDGET_CLASS (parent_class)->unrealize) (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget); } @@ -992,8 +1042,7 @@ static void e_day_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { EDayView *day_view; - gfloat width, offset; - gint col, day, scroll_y; + gint day, scroll_y; gboolean need_reshape; gdouble old_x2, old_y2, new_x2, new_y2; @@ -1004,29 +1053,7 @@ e_day_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) (*GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation); - /* Calculate the column sizes, using floating point so that pixels - get divided evenly. Note that we use one more element than the - number of columns, to make it easy to get the column widths. */ - width = day_view->main_canvas->allocation.width; - width /= day_view->days_shown; - offset = 0; - for (col = 0; col <= day_view->days_shown; col++) { - day_view->day_offsets[col] = floor (offset + 0.5); - offset += width; - } - - /* Calculate the days widths based on the offsets. */ - for (col = 0; col < day_view->days_shown; col++) { - day_view->day_widths[col] = day_view->day_offsets[col + 1] - day_view->day_offsets[col]; - } - - /* Determine which date format to use, based on the column widths. */ - if (day_view->day_widths[0] > day_view->long_format_width) - day_view->date_format = E_DAY_VIEW_DATE_FULL; - else if (day_view->day_widths[0] > day_view->abbreviated_format_width) - day_view->date_format = E_DAY_VIEW_DATE_ABBREVIATED; - else - day_view->date_format = E_DAY_VIEW_DATE_SHORT; + e_day_view_recalc_cell_sizes (day_view); /* Set the scroll region of the top canvas to its allocated size. */ gnome_canvas_get_scroll_region (GNOME_CANVAS (day_view->top_canvas), @@ -1060,6 +1087,38 @@ e_day_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) } +static void +e_day_view_recalc_cell_sizes (EDayView *day_view) +{ + gfloat width, offset; + gint day; + + /* Calculate the column sizes, using floating point so that pixels + get divided evenly. Note that we use one more element than the + number of columns, to make it easy to get the column widths. */ + width = day_view->main_canvas->allocation.width; + width /= day_view->days_shown; + offset = 0; + for (day = 0; day <= day_view->days_shown; day++) { + day_view->day_offsets[day] = floor (offset + 0.5); + offset += width; + } + + /* Calculate the days widths based on the offsets. */ + for (day = 0; day < day_view->days_shown; day++) { + day_view->day_widths[day] = day_view->day_offsets[day + 1] - day_view->day_offsets[day]; + } + + /* Determine which date format to use, based on the column widths. */ + if (day_view->day_widths[0] > day_view->long_format_width) + day_view->date_format = E_DAY_VIEW_DATE_FULL; + else if (day_view->day_widths[0] > day_view->abbreviated_format_width) + day_view->date_format = E_DAY_VIEW_DATE_ABBREVIATED; + else + day_view->date_format = E_DAY_VIEW_DATE_SHORT; +} + + static gint e_day_view_focus_in (GtkWidget *widget, GdkEventFocus *event) { @@ -1123,7 +1182,7 @@ cal_loaded_cb (CalClient *client, CalClientLoadStatus status, gpointer data) if (status != CAL_CLIENT_LOAD_SUCCESS) return; - e_day_view_reload_events (day_view); + e_day_view_queue_reload_events (day_view); } /* Callback used when the calendar client tells us that an object changed */ @@ -1136,6 +1195,8 @@ obj_updated_cb (CalClient *client, const char *uid, gpointer data) CalClientGetStatus status; gint day, event_num; + g_return_if_fail (E_IS_DAY_VIEW (data)); + day_view = E_DAY_VIEW (data); /* If our time hasn't been set yet, just return. */ @@ -1182,6 +1243,20 @@ obj_updated_cb (CalClient *client, const char *uid, gpointer data) #ifndef NO_WARNINGS #warning "FIX ME" #endif + + /* If we are editing an event which we have just created, we + will get an update_event callback from the server. But we + need to ignore it or we will lose the text the user has + already typed in. */ + if (day_view->editing_new_event + && day_view->editing_event_day == day + && day_view->editing_event_num == event_num) { + gtk_object_unref (GTK_OBJECT (event->comp)); + event->comp = comp; /* Takes over ref count. */ + return; + } + + /* Do this the long way every time for now */ #if 0 if (ical_object_compare_dates (event->ico, ico)) { @@ -1429,7 +1504,7 @@ e_day_view_update_event_label (EDayView *day_view, return; cal_component_get_summary (event->comp, &summary); - text = summary.value ? (char *) summary.value : ""; + text = summary.value ? (char*) summary.value : ""; if (day_view->editing_event_day == day && day_view->editing_event_num == event_num) @@ -1591,9 +1666,9 @@ e_day_view_set_selected_time_range (EDayView *day_view, 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. */ - if (day_view->days_shown == 1) + if (!day_view->work_week_view) { lower = time_day_begin (start_time); - else { + } else { g_date_clear (&date, 1); g_date_set_time (&date, start_time); g_date_subtract_days (&date, g_date_weekday (&date) - 1); @@ -1605,8 +1680,7 @@ e_day_view_set_selected_time_range (EDayView *day_view, /* See if we need to change the days shown. */ if (lower != day_view->lower) { e_day_view_recalc_day_starts (day_view, lower); - e_day_view_reload_events (day_view); - need_redraw = TRUE; + e_day_view_queue_reload_events (day_view); } /* Set the selection. */ @@ -1710,6 +1784,32 @@ e_day_view_recalc_day_starts (EDayView *day_view, } +/* Whether we are displaying a work-week, in which case the display always + starts on the first day of the working week. */ +gboolean +e_day_view_get_work_week_view (EDayView *day_view) +{ + g_return_val_if_fail (E_IS_DAY_VIEW (day_view), FALSE); + + return day_view->work_week_view; +} + + +void +e_day_view_set_work_week_view (EDayView *day_view, + gboolean work_week_view) +{ + g_return_if_fail (E_IS_DAY_VIEW (day_view)); + + if (day_view->work_week_view == work_week_view) + return; + + day_view->work_week_view = work_week_view; + + /* FIXME: need to recalc the first day shown if now work-week view. */ +} + + gint e_day_view_get_days_shown (EDayView *day_view) { @@ -1729,8 +1829,9 @@ e_day_view_set_days_shown (EDayView *day_view, if (day_view->days_shown != days_shown) { day_view->days_shown = days_shown; - - /* FIXME: Update everything. */ + 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); } } @@ -1781,6 +1882,30 @@ e_day_view_set_mins_per_row (EDayView *day_view, } +/* This specifies the working days in the week. The value is a bitwise + combination of day flags. Defaults to Mon-Fri. */ +EDayViewDays +e_day_view_get_working_days (EDayView *day_view) +{ + g_return_val_if_fail (E_IS_DAY_VIEW (day_view), 0); + + return day_view->working_days; +} + + +void +e_day_view_set_working_days (EDayView *day_view, + EDayViewDays days) +{ + 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); + } +} + + static gboolean e_day_view_update_scroll_regions (EDayView *day_view) { @@ -2583,6 +2708,8 @@ e_day_view_on_unrecur_appointment (GtkWidget *widget, gpointer data) the start & end times to the instances times. */ new_comp = cal_component_clone (event->comp); cal_component_set_uid (new_comp, cal_component_gen_uid ()); + cal_component_set_rdate_list (new_comp, NULL); + cal_component_set_rrule_list (new_comp, NULL); cal_component_set_exdate_list (new_comp, NULL); cal_component_set_exrule_list (new_comp, NULL); @@ -3218,18 +3345,46 @@ e_day_view_abort_resize (EDayView *day_view, } +/* This frees any events currently loaded, and queues a reload. */ static void -e_day_view_reload_events (EDayView *day_view) +e_day_view_queue_reload_events (EDayView *day_view) { e_day_view_free_events (day_view); - /* Reset all our indices. */ - day_view->editing_event_day = -1; - day_view->popup_event_day = -1; - day_view->resize_bars_event_day = -1; - day_view->resize_event_day = -1; - day_view->pressed_event_day = -1; - day_view->drag_event_day = -1; + if (day_view->reload_events_idle_id == 0) { + /* We'll use a high idle priority here, so the events are + reloaded before the canvas is updated. */ + day_view->reload_events_idle_id = g_idle_add_full + (G_PRIORITY_HIGH_IDLE, + e_day_view_reload_events_idle_cb, day_view, NULL); + } +} + + +static gboolean +e_day_view_reload_events_idle_cb (gpointer data) +{ + EDayView *day_view; + + g_return_val_if_fail (E_IS_DAY_VIEW (data), FALSE); + + GDK_THREADS_ENTER (); + + day_view = E_DAY_VIEW (data); + + day_view->reload_events_idle_id = 0; + + e_day_view_reload_events (day_view); + + GDK_THREADS_LEAVE (); + return FALSE; +} + + +static void +e_day_view_reload_events (EDayView *day_view) +{ + e_day_view_free_events (day_view); if (!(day_view->client && cal_client_is_loaded (day_view->client))) return; @@ -3262,6 +3417,14 @@ e_day_view_free_events (EDayView *day_view) { gint day; + /* Reset all our indices. */ + day_view->editing_event_day = -1; + day_view->popup_event_day = -1; + day_view->resize_bars_event_day = -1; + day_view->resize_event_day = -1; + day_view->pressed_event_day = -1; + day_view->drag_event_day = -1; + e_day_view_free_event_array (day_view, day_view->long_events); for (day = 0; day < E_DAY_VIEW_MAX_DAYS; day++) @@ -4475,6 +4638,8 @@ e_day_view_start_editing_event (EDayView *day_view, ETextEventProcessor *event_processor = NULL; ETextEventProcessorCommand command; + g_print ("In e_day_view_start_editing_event\n"); + /* If we are already editing the event, just return. */ if (day == day_view->editing_event_day && event_num == day_view->editing_event_num) @@ -4492,6 +4657,8 @@ e_day_view_start_editing_event (EDayView *day_view, if (!event->canvas_item) return; + g_print ("In e_day_view_start_editing_event 2\n"); + /* We must grab the focus before setting the initial text, since grabbing the focus will result in a call to e_day_view_on_editing_started(), which will reset the text to get @@ -4586,7 +4753,7 @@ e_day_view_on_editing_started (EDayView *day_view, &day, &event_num)) return; -#if 0 +#if 1 g_print ("In e_day_view_on_editing_started Day:%i Event:%i\n", day, event_num); #endif @@ -4629,6 +4796,9 @@ e_day_view_on_editing_stopped (EDayView *day_view, day = day_view->editing_event_day; event_num = day_view->editing_event_num; + g_print ("In e_day_view_on_editing_stopped Day:%i Event:%i\n", + day, event_num); + /* If no item is being edited, just return. */ if (day == -1) return; @@ -5249,9 +5419,9 @@ e_day_view_update_top_canvas_drag (EDayView *day_view, "clip_width", item_w - (E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH + E_DAY_VIEW_LONG_EVENT_X_PAD) * 2, "clip_height", item_h - (E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT + E_DAY_VIEW_LONG_EVENT_Y_PAD) * 2, NULL); - e_canvas_item_move_absolute(day_view->drag_long_event_item, - item_x + E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH + E_DAY_VIEW_LONG_EVENT_X_PAD, - item_y + E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT + E_DAY_VIEW_LONG_EVENT_Y_PAD); + e_canvas_item_move_absolute (day_view->drag_long_event_item, + item_x + E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH + E_DAY_VIEW_LONG_EVENT_X_PAD, + item_y + E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT + E_DAY_VIEW_LONG_EVENT_Y_PAD); if (!(day_view->drag_long_event_rect_item->object.flags & GNOME_CANVAS_ITEM_VISIBLE)) { gnome_canvas_item_raise_to_top (day_view->drag_long_event_rect_item); @@ -5407,9 +5577,9 @@ e_day_view_update_main_canvas_drag (EDayView *day_view, "clip_width", item_w - E_DAY_VIEW_BAR_WIDTH - E_DAY_VIEW_EVENT_X_PAD * 2, "clip_height", item_h - (E_DAY_VIEW_EVENT_BORDER_HEIGHT + E_DAY_VIEW_EVENT_Y_PAD) * 2, NULL); - e_canvas_item_move_absolute(event->canvas_item, - item_x + E_DAY_VIEW_BAR_WIDTH + E_DAY_VIEW_EVENT_X_PAD, - item_y + E_DAY_VIEW_EVENT_BORDER_HEIGHT + E_DAY_VIEW_EVENT_Y_PAD); + e_canvas_item_move_absolute (day_view->drag_item, + item_x + E_DAY_VIEW_BAR_WIDTH + E_DAY_VIEW_EVENT_X_PAD, + item_y + E_DAY_VIEW_EVENT_BORDER_HEIGHT + E_DAY_VIEW_EVENT_Y_PAD); if (!(day_view->drag_bar_item->object.flags & GNOME_CANVAS_ITEM_VISIBLE)) { gnome_canvas_item_raise_to_top (day_view->drag_bar_item); diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h index 379699accd..cfd11b057c 100644 --- a/calendar/gui/e-day-view.h +++ b/calendar/gui/e-day-view.h @@ -38,8 +38,9 @@ extern "C" { * EDayView - displays the Day & Work-Week views of the calendar. */ -/* The maximum number of days shown. We use 7 since we only show 1 week max. */ -#define E_DAY_VIEW_MAX_DAYS 7 +/* The maximum number of days shown. We use the week view for anything more + than about 9 days. */ +#define E_DAY_VIEW_MAX_DAYS 10 /* This is used as a special code to signify a long event instead of the day of a normal event. */ @@ -90,6 +91,21 @@ extern "C" { #define E_DAY_VIEW_TOP_CANVAS_Y_GAP 2 +/* These are used to get/set the working days in the week. The bit-flags are + combined together. The bits must be from 0 (Sun) to 6 (Sat) to match the + day values used by localtime etc. */ +typedef enum +{ + E_DAY_VIEW_SUNDAY = 1 << 0, + E_DAY_VIEW_MONDAY = 1 << 1, + E_DAY_VIEW_TUESDAY = 1 << 2, + E_DAY_VIEW_WEDNESDAY = 1 << 3, + E_DAY_VIEW_THURSDAY = 1 << 4, + E_DAY_VIEW_FRIDAY = 1 << 5, + E_DAY_VIEW_SATURDAY = 1 << 6 +} EDayViewDays; + + /* These are used to specify the type of an appointment. They match those used in EMeetingTimeSelector. */ typedef enum @@ -195,7 +211,12 @@ struct _EDayView time_t lower; time_t upper; - /* The number of days we are showing. Usually 1 or 5. Maybe 6 or 7. */ + /* Whether we are showing the work-week view. */ + gboolean work_week_view; + + /* The number of days we are showing. Usually 1 or 5, but can be up + to E_DAY_VIEW_MAX_DAYS, e.g. when the user selects a range of + days in the mini calendar. */ gint days_shown; /* The start of each day & an extra element to hold the last time. */ @@ -221,6 +242,9 @@ struct _EDayView gboolean long_events_need_reshape; gboolean need_reshape[E_DAY_VIEW_MAX_DAYS]; + /* The id of our idle function to reload all events. */ + gint reload_events_idle_id; + /* The number of minutes per row. 5, 10, 15, 30 or 60. */ gint mins_per_row; @@ -244,6 +268,9 @@ struct _EDayView gint last_hour_shown; gint last_minute_shown; + /* Bitwise combination of working days. Defaults to Mon-Fri. */ + EDayViewDays working_days; + /* The start and end of the work day, rounded to the nearest row. */ gint work_day_start_hour; gint work_day_start_minute; @@ -433,6 +460,21 @@ void e_day_view_get_selected_time_range (EDayView *day_view, time_t *start_time, time_t *end_time); +/* This is called when one event has been added or updated. */ +void e_day_view_update_event (EDayView *day_view, + const gchar *uid); + +/* This removes all the events associated with the given uid. Note that for + recurring events there may be more than one. If any events are found and + removed we need to layout the events again. */ +void e_day_view_remove_event (EDayView *day_view, + const gchar *uid); + +/* Whether we are displaying a work-week, in which case the display always + starts on the first day of the working week. */ +gboolean e_day_view_get_work_week_view (EDayView *day_view); +void e_day_view_set_work_week_view (EDayView *day_view, + gboolean work_week_view); /* The number of days shown in the EDayView, from 1 to 7. This is normally either 1 or 5 (for the Work-Week view). */ @@ -446,6 +488,12 @@ gint e_day_view_get_mins_per_row (EDayView *day_view); void e_day_view_set_mins_per_row (EDayView *day_view, gint mins_per_row); +/* This specifies the working days in the week. The value is a bitwise + combination of day flags. Defaults to Mon-Fri. */ +EDayViewDays e_day_view_get_working_days (EDayView *day_view); +void e_day_view_set_working_days (EDayView *day_view, + EDayViewDays days); + /* diff --git a/calendar/gui/e-week-view-main-item.c b/calendar/gui/e-week-view-main-item.c index 49c2ca3d7d..d30404305d 100644 --- a/calendar/gui/e-week-view-main-item.c +++ b/calendar/gui/e-week-view-main-item.c @@ -193,7 +193,7 @@ e_week_view_main_item_draw (GnomeCanvasItem *canvas_item, if (!g_date_valid (&date)) g_date_set_dmy (&date, 27, 12, 1999); - num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; for (day = 0; day < num_days; day++) { e_week_view_get_day_position (week_view, day, &day_x, &day_y, @@ -246,6 +246,8 @@ e_week_view_main_item_draw_day (EWeekViewMainItem *wvmitem, selected_bg_gc = style->bg_gc[GTK_STATE_SELECTED]; gc = week_view->main_gc; + g_return_if_fail (gc != NULL); + month = g_date_month (date); day_of_month = g_date_day (date); line_y = y + E_WEEK_VIEW_DATE_T_PAD + font->ascent @@ -256,7 +258,7 @@ e_week_view_main_item_draw_day (EWeekViewMainItem *wvmitem, month starts (defaults are white for odd - January, March, ... and light gray for even). In the week view the background is always the same color, the color used for the odd months in the month view. */ - if (week_view->display_month && (month % 2 == 0)) + if (week_view->multi_week_view && (month % 2 == 0)) bg_color = &week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS]; else bg_color = &week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS]; @@ -283,7 +285,7 @@ e_week_view_main_item_draw_day (EWeekViewMainItem *wvmitem, || week_view->selection_end_day < day) selected = FALSE; if (selected) { - if (week_view->display_month) + if (week_view->multi_week_view) gdk_draw_rectangle (drawable, selected_bg_gc, TRUE, x + 2, y + 1, width - 5, @@ -302,7 +304,7 @@ e_week_view_main_item_draw_day (EWeekViewMainItem *wvmitem, the 1st of each month, otherwise use "10". */ show_day_name = FALSE; show_month_name = FALSE; - if (!week_view->display_month) { + if (!week_view->multi_week_view) { show_day_name = TRUE; show_month_name = TRUE; } else if (day == 0 || day_of_month == 1) { @@ -342,7 +344,7 @@ e_week_view_main_item_draw_day (EWeekViewMainItem *wvmitem, buffer); /* Draw the line under the date. */ - if (!week_view->display_month) { + if (!week_view->multi_week_view) { gdk_draw_line (drawable, fg_gc, x + E_WEEK_VIEW_DATE_LINE_L_PAD, line_y, right_edge, line_y); diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index fef239b065..04da509a92 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -99,6 +99,8 @@ static gint e_week_view_convert_position_to_day (EWeekView *week_view, static void e_week_view_update_selection (EWeekView *week_view, gint day); +static void e_week_view_queue_reload_events (EWeekView *week_view); +static gboolean e_week_view_reload_events_idle_cb (gpointer data); static void e_week_view_reload_events (EWeekView *week_view); static void e_week_view_free_events (EWeekView *week_view); static gboolean e_week_view_add_event (CalComponent *comp, @@ -229,9 +231,6 @@ e_week_view_class_init (EWeekViewClass *class) static void e_week_view_init (EWeekView *week_view) { - GdkColormap *colormap; - gboolean success[E_WEEK_VIEW_COLOR_LAST]; - gint nfailed; GnomeCanvasGroup *canvas_group; GtkObject *adjustment; GdkPixbuf *pixbuf; @@ -239,8 +238,6 @@ e_week_view_init (EWeekView *week_view) GTK_WIDGET_SET_FLAGS (week_view, GTK_CAN_FOCUS); - colormap = gtk_widget_get_colormap (GTK_WIDGET (week_view)); - week_view->calendar = NULL; week_view->client = NULL; @@ -249,10 +246,12 @@ e_week_view_init (EWeekView *week_view) week_view->events_sorted = TRUE; week_view->events_need_layout = FALSE; week_view->events_need_reshape = FALSE; + week_view->reload_events_idle_id = 0; week_view->spans = NULL; - week_view->display_month = FALSE; + week_view->multi_week_view = FALSE; + week_view->weeks_shown = 6; week_view->rows = 6; week_view->columns = 2; week_view->compress_weekend = TRUE; @@ -270,6 +269,8 @@ e_week_view_init (EWeekView *week_view) week_view->editing_event_num = -1; week_view->editing_new_event = FALSE; + week_view->main_gc = NULL; + /* Create the small font. */ week_view->use_small_font = TRUE; week_view->small_font = gdk_font_load (E_WEEK_VIEW_SMALL_FONT); @@ -278,29 +279,6 @@ e_week_view_init (EWeekView *week_view) if (!week_view->small_font) g_warning ("Couldn't load font"); - /* Allocate the colors. */ - week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].red = 0xeded; - week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].green = 0xeded; - week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].blue = 0xeded; - - week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].red = 65535; - week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].green = 65535; - week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].blue = 65535; - - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].red = 0xd6d6; - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green = 0xd6d6; - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].blue = 0xd6d6; - - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].red = 0; - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].green = 0; - week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].blue = 0; - - nfailed = gdk_colormap_alloc_colors (colormap, week_view->colors, - E_WEEK_VIEW_COLOR_LAST, FALSE, - TRUE, success); - if (nfailed) - g_warning ("Failed to allocate all colors"); - /* * Titles Canvas. Note that we don't show it is only shown in the @@ -379,11 +357,6 @@ e_week_view_init (EWeekView *week_view) gtk_widget_show (week_view->vscrollbar); - /* Create the pixmaps. */ - week_view->reminder_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &week_view->reminder_mask, NULL, bell_xpm); - week_view->recurrence_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &week_view->recurrence_mask, NULL, recur_xpm); - - /* Create the cursors. */ week_view->normal_cursor = gdk_cursor_new (GDK_TOP_LEFT_ARROW); week_view->move_cursor = gdk_cursor_new (GDK_FLEUR); @@ -416,15 +389,19 @@ e_week_view_destroy (GtkObject *object) week_view = E_WEEK_VIEW (object); + e_week_view_free_events (week_view); + + if (week_view->reload_events_idle_id != 0) { + g_source_remove (week_view->reload_events_idle_id); + week_view->reload_events_idle_id = 0; + } + if (week_view->client) { gtk_signal_disconnect_by_data (GTK_OBJECT (week_view->client), week_view); gtk_object_unref (GTK_OBJECT (week_view->client)); week_view->client = NULL; } - /* FIXME: free the colors. In EDayView as well. */ - /* FIXME: free the events and the spans. In EDayView as well? */ - if (week_view->small_font) gdk_font_unref (week_view->small_font); @@ -440,12 +417,45 @@ static void e_week_view_realize (GtkWidget *widget) { EWeekView *week_view; + GdkColormap *colormap; + gboolean success[E_WEEK_VIEW_COLOR_LAST]; + gint nfailed; if (GTK_WIDGET_CLASS (parent_class)->realize) (*GTK_WIDGET_CLASS (parent_class)->realize)(widget); week_view = E_WEEK_VIEW (widget); week_view->main_gc = gdk_gc_new (widget->window); + + colormap = gtk_widget_get_colormap (widget); + + /* Allocate the colors. */ + week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].red = 0xeded; + week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].green = 0xeded; + week_view->colors[E_WEEK_VIEW_COLOR_EVEN_MONTHS].blue = 0xeded; + + week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].red = 65535; + week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].green = 65535; + week_view->colors[E_WEEK_VIEW_COLOR_ODD_MONTHS].blue = 65535; + + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].red = 0xd6d6; + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green = 0xd6d6; + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].blue = 0xd6d6; + + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].red = 0; + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].green = 0; + week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER].blue = 0; + + nfailed = gdk_colormap_alloc_colors (colormap, week_view->colors, + E_WEEK_VIEW_COLOR_LAST, FALSE, + TRUE, success); + if (nfailed) + g_warning ("Failed to allocate all colors"); + + + /* Create the pixmaps. */ + week_view->reminder_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &week_view->reminder_mask, NULL, bell_xpm); + week_view->recurrence_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &week_view->recurrence_mask, NULL, recur_xpm); } @@ -453,12 +463,23 @@ static void e_week_view_unrealize (GtkWidget *widget) { EWeekView *week_view; + GdkColormap *colormap; + gint i; week_view = E_WEEK_VIEW (widget); gdk_gc_unref (week_view->main_gc); week_view->main_gc = NULL; + colormap = gtk_widget_get_colormap (widget); + for (i = 0; i < E_WEEK_VIEW_COLOR_LAST; i++) + gdk_colors_free (colormap, &week_view->colors[i].pixel, 1, 0); + + gdk_pixmap_unref (week_view->reminder_icon); + week_view->reminder_icon = NULL; + gdk_pixmap_unref (week_view->recurrence_icon); + week_view->recurrence_icon = NULL; + if (GTK_WIDGET_CLASS (parent_class)->unrealize) (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget); } @@ -557,7 +578,7 @@ e_week_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) /* Calculate the number of rows of events in each cell, for the large cells and the compressed weekend cells. */ - if (week_view->display_month) { + if (week_view->multi_week_view) { week_view->events_y_offset = E_WEEK_VIEW_DATE_T_PAD + font->ascent + font->descent + E_WEEK_VIEW_DATE_B_PAD; @@ -635,9 +656,9 @@ e_week_view_recalc_cell_sizes (EWeekView *week_view) gfloat width, height, offset; gint row, col; - if (week_view->display_month) { - week_view->rows = 10; - week_view->columns = 6; + if (week_view->multi_week_view) { + week_view->rows = week_view->weeks_shown * 2; + week_view->columns = week_view->compress_weekend ? 6 : 7; } else { week_view->rows = 6; week_view->columns = 2; @@ -807,6 +828,7 @@ static void obj_updated_cb (CalClient *client, const char *uid, gpointer data) { EWeekView *week_view; + EWeekViewEvent *event; gint event_num, num_days; CalComponent *comp; CalClientGetStatus status; @@ -847,11 +869,24 @@ obj_updated_cb (CalClient *client, const char *uid, gpointer data) #ifndef NO_WARNINGS #warning "FIX ME" #endif - /* Do this the long way every time for now */ -#if 0 + event = &g_array_index (week_view->events, EWeekViewEvent, event_num); + /* If we are editing an event which we have just created, we + will get an update_event callback from the server. But we + need to ignore it or we will lose the text the user has + already typed in. */ + if (week_view->editing_new_event + && week_view->editing_event_num == event_num) { + gtk_object_unref (GTK_OBJECT (event->comp)); + event->comp = comp; /* Takes over ref count. */ + return; + } + + + /* Do this the long way every time for now */ +#if 0 if (ical_object_compare_dates (event->ico, ico)) { e_week_view_foreach_event_with_uid (week_view, uid, e_week_view_update_event_cb, comp); gtk_object_unref (GTK_OBJECT (comp)); @@ -867,7 +902,7 @@ obj_updated_cb (CalClient *client, const char *uid, gpointer data) } /* Add the occurrences of the event. */ - num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; cal_recur_generate_instances (comp, week_view->day_starts[0], @@ -958,7 +993,7 @@ e_week_view_set_selected_time_range (EWeekView *week_view, g_date_clear (&date, 1); g_date_set_time (&date, start_time); - if (week_view->display_month) { + if (week_view->multi_week_view) { /* Find the number of days since the start of the month. */ day_offset = g_date_day (&date) - 1; @@ -990,7 +1025,7 @@ e_week_view_set_selected_time_range (EWeekView *week_view, start_time = time_add_day (start_time, -day_offset); start_time = time_day_begin (start_time); e_week_view_recalc_day_starts (week_view, start_time); - e_week_view_reload_events (week_view); + e_week_view_queue_reload_events (week_view); } /* Set the selection to the given days. */ @@ -1007,7 +1042,7 @@ e_week_view_set_selected_time_range (EWeekView *week_view, } /* Make sure the selection is valid. */ - num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; num_days--; week_view->selection_start_day = CLAMP (week_view->selection_start_day, 0, num_days); @@ -1050,6 +1085,96 @@ e_week_view_get_selected_time_range (EWeekView *week_view, } +/* Note that the returned date may be invalid if no date has been set yet. */ +void +e_week_view_get_first_day_shown (EWeekView *week_view, + GDate *date) +{ + *date = week_view->first_day_shown; +} + + +/* This sets the first day shown in the view. It will be rounded down to the + nearest week. */ +void +e_week_view_set_first_day_shown (EWeekView *week_view, + GDate *date) +{ + GDate base_date; + gint day_offset, num_days; + gboolean update_adjustment_value = FALSE; + guint32 old_selection_start_julian, old_selection_end_julian; + struct tm start_tm; + time_t start_time; + + g_return_if_fail (E_IS_WEEK_VIEW (week_view)); + + /* Calculate the old selection range. */ + if (week_view->selection_start_day != -1) { + old_selection_start_julian = + g_date_julian (&week_view->base_date) + + week_view->selection_start_day; + old_selection_end_julian = + g_date_julian (&week_view->base_date) + + week_view->selection_end_day; + } + + /* Find the 1st Monday at or before the given day. */ + day_offset = g_date_weekday (date) - 1; + + /* Calculate the base date, i.e. the first day shown when the + scrollbar adjustment value is 0. */ + base_date = *date; + g_date_subtract_days (&base_date, day_offset); + + /* See if we need to update the base date. */ + if (!g_date_valid (&week_view->base_date) + || g_date_compare (&week_view->base_date, &base_date)) { + week_view->base_date = base_date; + update_adjustment_value = TRUE; + } + + /* See if we need to update the first day shown. */ + if (!g_date_valid (&week_view->first_day_shown) + || g_date_compare (&week_view->first_day_shown, &base_date)) { + week_view->first_day_shown = base_date; + g_date_to_struct_tm (&base_date, &start_tm); + start_time = mktime (&start_tm); + e_week_view_recalc_day_starts (week_view, start_time); + e_week_view_queue_reload_events (week_view); + } + + /* Try to keep the previous selection, but if it is no longer shown + just select the first day. */ + if (week_view->selection_start_day != -1) { + week_view->selection_start_day = old_selection_start_julian + - g_date_julian (&base_date); + week_view->selection_end_day = old_selection_end_julian + - g_date_julian (&base_date); + + /* Make sure the selection is valid. */ + num_days = week_view->multi_week_view + ? week_view->weeks_shown * 7 : 7; + num_days--; + week_view->selection_start_day = + CLAMP (week_view->selection_start_day, 0, num_days); + week_view->selection_end_day = + CLAMP (week_view->selection_end_day, + week_view->selection_start_day, + num_days); + } + + /* Reset the adjustment value to 0 if the base address has changed. + Note that we do this after updating first_day_shown so that our + signal handler will not try to reload the events. */ + if (update_adjustment_value) + gtk_adjustment_set_value (GTK_RANGE (week_view->vscrollbar)->adjustment, 0); + + + gtk_widget_queue_draw (week_view->main_canvas); +} + + /* Recalculates the time_t corresponding to the start of each day. */ static void e_week_view_recalc_day_starts (EWeekView *week_view, @@ -1058,7 +1183,7 @@ e_week_view_recalc_day_starts (EWeekView *week_view, gint num_days, day; time_t tmp_time; - num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; tmp_time = lower; week_view->day_starts[0] = tmp_time; @@ -1074,29 +1199,29 @@ e_week_view_recalc_day_starts (EWeekView *week_view, gboolean -e_week_view_get_display_month (EWeekView *week_view) +e_week_view_get_multi_week_view (EWeekView *week_view) { g_return_val_if_fail (E_IS_WEEK_VIEW (week_view), FALSE); - return week_view->display_month; + return week_view->multi_week_view; } void -e_week_view_set_display_month (EWeekView *week_view, - gboolean display_month) +e_week_view_set_multi_week_view (EWeekView *week_view, + gboolean multi_week_view) { GtkAdjustment *adjustment; gint page_increment, page_size; g_return_if_fail (E_IS_WEEK_VIEW (week_view)); - if (week_view->display_month == display_month) + if (week_view->multi_week_view == multi_week_view) return; - week_view->display_month = display_month; + week_view->multi_week_view = multi_week_view; - if (display_month) { + if (multi_week_view) { gtk_widget_show (week_view->titles_canvas); page_increment = 4; page_size = 5; @@ -1114,7 +1239,50 @@ e_week_view_set_display_month (EWeekView *week_view, e_week_view_recalc_day_starts (week_view, week_view->day_starts[0]); e_week_view_recalc_cell_sizes (week_view); - e_week_view_reload_events (week_view); + e_week_view_queue_reload_events (week_view); +} + + +gint +e_week_view_get_weeks_shown (EWeekView *week_view) +{ + g_return_val_if_fail (E_IS_WEEK_VIEW (week_view), 1); + + return week_view->weeks_shown; +} + + +void +e_week_view_set_weeks_shown (EWeekView *week_view, + gint weeks_shown) +{ + GtkAdjustment *adjustment; + gint page_increment, page_size; + + g_return_if_fail (E_IS_WEEK_VIEW (week_view)); + + weeks_shown = MIN (weeks_shown, E_WEEK_VIEW_MAX_WEEKS); + + if (week_view->weeks_shown == weeks_shown) + return; + + week_view->weeks_shown = weeks_shown; + + if (week_view->multi_week_view) { + page_increment = 4; + page_size = 5; + + adjustment = GTK_RANGE (week_view->vscrollbar)->adjustment; + adjustment->page_increment = page_increment; + adjustment->page_size = page_size; + gtk_adjustment_changed (adjustment); + + /* FIXME: Need to change start date and adjustment value? */ + e_week_view_recalc_day_starts (week_view, + week_view->day_starts[0]); + e_week_view_recalc_cell_sizes (week_view); + e_week_view_queue_reload_events (week_view); + } } @@ -1139,7 +1307,7 @@ e_week_view_set_compress_weekend (EWeekView *week_view, week_view->compress_weekend = compress; /* The option only affects the month view. */ - if (!week_view->display_month) + if (!week_view->multi_week_view) return; /* FIXME: Need to update layout. */ @@ -1161,6 +1329,8 @@ e_week_view_update_event_cb (EWeekView *week_view, comp = data; event = &g_array_index (week_view->events, EWeekViewEvent, event_num); + + gtk_object_unref (GTK_OBJECT (event->comp)); event->comp = comp; gtk_object_ref (GTK_OBJECT (comp)); @@ -1180,11 +1350,10 @@ e_week_view_update_event_cb (EWeekView *week_view, CalComponentText t; cal_component_get_summary (event->comp, &t); - text = g_strdup (t.value); + text = (char*) t.value; gnome_canvas_item_set (span->text_item, "text", text ? text : "", NULL); - g_free (text); e_week_view_reshape_event_span (week_view, event_num, span_num); @@ -1279,8 +1448,8 @@ e_week_view_get_day_position (EWeekView *week_view, *day_x = *day_y = *day_w = *day_h = 0; g_return_if_fail (day >= 0); - if (week_view->display_month) { - g_return_if_fail (day < E_WEEK_VIEW_MAX_WEEKS * 7); + if (week_view->multi_week_view) { + g_return_if_fail (day < week_view->weeks_shown * 7); week = day / 7; day_of_week = day % 7; @@ -1367,7 +1536,7 @@ e_week_view_get_span_position (EWeekView *week_view, num_days = span->num_days; /* Check if the row will not be visible in compressed cells. */ if (span->row >= week_view->rows_per_compressed_cell) { - if (week_view->display_month) { + if (week_view->multi_week_view) { if (week_view->compress_weekend) { /* If it ends on a Saturday and is 1 day long we skip it, else we shorten it. If it ends @@ -1554,7 +1723,7 @@ e_week_view_convert_position_to_day (EWeekView *week_view, return -1; /* Now convert the grid position to a week and day. */ - if (week_view->display_month) { + if (week_view->multi_week_view) { week = grid_y / 2; if (week_view->compress_weekend && grid_x == 5 && grid_y % 2 == 1) @@ -1616,6 +1785,42 @@ e_week_view_update_selection (EWeekView *week_view, } +/* This frees any events currently loaded, and queues a reload. */ +static void +e_week_view_queue_reload_events (EWeekView *week_view) +{ + e_week_view_free_events (week_view); + + if (week_view->reload_events_idle_id == 0) { + /* We'll use a low priority here, so the user can scroll + the view quickly. */ + week_view->reload_events_idle_id = g_idle_add_full + (G_PRIORITY_LOW, + e_week_view_reload_events_idle_cb, week_view, NULL); + } +} + + +static gboolean +e_week_view_reload_events_idle_cb (gpointer data) +{ + EWeekView *week_view; + + g_return_val_if_fail (E_IS_WEEK_VIEW (data), FALSE); + + GDK_THREADS_ENTER (); + + week_view = E_WEEK_VIEW (data); + + week_view->reload_events_idle_id = 0; + + e_week_view_reload_events (week_view); + + GDK_THREADS_LEAVE (); + return FALSE; +} + + static void e_week_view_reload_events (EWeekView *week_view) { @@ -1628,8 +1833,8 @@ e_week_view_reload_events (EWeekView *week_view) if (week_view->calendar && g_date_valid (&week_view->first_day_shown)) { - num_days = week_view->display_month - ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view + ? week_view->weeks_shown * 7 : 7; cal_client_generate_instances (week_view->client, CALOBJ_TYPE_EVENT, @@ -1652,6 +1857,8 @@ e_week_view_free_events (EWeekView *week_view) EWeekViewEventSpan *span; gint event_num, span_num; + /* FIXME: set any indices into the arrays to -1? */ + for (event_num = 0; event_num < week_view->events->len; event_num++) { event = &g_array_index (week_view->events, EWeekViewEvent, event_num); @@ -1693,7 +1900,7 @@ e_week_view_add_event (CalComponent *comp, week_view = E_WEEK_VIEW (data); /* Check that the event times are valid. */ - num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; #if 0 g_print ("View start:%li end:%li Event start:%li end:%li\n", @@ -1770,7 +1977,7 @@ e_week_view_layout_events (EWeekView *week_view) spans = g_array_new (FALSE, FALSE, sizeof (EWeekViewEventSpan)); /* Clear the number of rows used per day. */ - num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; for (day = 0; day <= num_days; day++) { week_view->rows_per_day[day] = 0; } @@ -1817,7 +2024,7 @@ e_week_view_layout_event (EWeekView *week_view, start_day = e_week_view_find_day (week_view, event->start, FALSE); end_day = e_week_view_find_day (week_view, event->end, TRUE); - max_day = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 - 1 + max_day = week_view->multi_week_view ? week_view->weeks_shown * 7 - 1 : 7 - 1; start_day = CLAMP (start_day, 0, max_day); end_day = CLAMP (end_day, 0, max_day); @@ -1952,11 +2159,11 @@ e_week_view_reshape_events (EWeekView *week_view) } /* Reshape the jump buttons and show/hide them as appropriate. */ - num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; for (day = 0; day < num_days; day++) { is_weekend = (day % 7 >= 5) ? TRUE : FALSE; - if (!is_weekend || (week_view->display_month + if (!is_weekend || (week_view->multi_week_view && !week_view->compress_weekend)) max_rows = week_view->rows_per_cell; else @@ -2203,7 +2410,7 @@ e_week_view_find_day (EWeekView *week_view, gint num_days, day; time_t *day_starts; - num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7; + num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7; day_starts = week_view->day_starts; if (time_to_find < day_starts[0]) @@ -2237,7 +2444,7 @@ e_week_view_find_span_end (EWeekView *week_view, { gint week, day_of_week, end_day; - if (week_view->display_month) { + if (week_view->multi_week_view) { week = day / 7; day_of_week = day % 7; if (week_view->compress_weekend && day_of_week <= 5) @@ -2287,7 +2494,7 @@ e_week_view_on_adjustment_changed (GtkAdjustment *adjustment, lower = time_day_begin (lower); e_week_view_recalc_day_starts (week_view, lower); - e_week_view_reload_events (week_view); + e_week_view_queue_reload_events (week_view); /* Update the selection, if needed. */ if (week_view->selection_start_day != -1) { @@ -2937,6 +3144,8 @@ e_week_view_on_unrecur_appointment (GtkWidget *widget, gpointer data) the start & end times to the instances times. */ new_comp = cal_component_clone (event->comp); cal_component_set_uid (new_comp, cal_component_gen_uid ()); + cal_component_set_rdate_list (new_comp, NULL); + cal_component_set_rrule_list (new_comp, NULL); cal_component_set_exdate_list (new_comp, NULL); cal_component_set_exrule_list (new_comp, NULL); @@ -2970,11 +3179,9 @@ e_week_view_on_jump_button_event (GnomeCanvasItem *item, if (event->type == GDK_BUTTON_PRESS) { for (day = 0; day < E_WEEK_VIEW_MAX_WEEKS * 7; day++) { if (item == week_view->jump_buttons[day]) { - gnome_calendar_dayjump (week_view->calendar, - week_view->day_starts[day]); - /* A quick hack to make the 'Day' toolbar - button active. */ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (week_view->calendar->view_toolbar_buttons[0]), TRUE); + gnome_calendar_dayjump + (week_view->calendar, + week_view->day_starts[day]); return TRUE; } } diff --git a/calendar/gui/e-week-view.h b/calendar/gui/e-week-view.h index f27b5db336..42a1ced9f7 100644 --- a/calendar/gui/e-week-view.h +++ b/calendar/gui/e-week-view.h @@ -37,8 +37,9 @@ extern "C" { * EWeekView - displays the Week & Month views of the calendar. */ -/* The maximum number of weeks we show. 5 is usually enough for 1 month. */ -#define E_WEEK_VIEW_MAX_WEEKS 5 +/* The maximum number of weeks we show. 5 is usually enough for 1 month, + but we allow 6 for longer selections. */ +#define E_WEEK_VIEW_MAX_WEEKS 6 /* The size of the reminder & recurrence icons, and padding around them. */ #define E_WEEK_VIEW_ICON_WIDTH 16 @@ -177,6 +178,9 @@ struct _EWeekView gboolean events_need_layout; gboolean events_need_reshape; + /* The id of our idle function to reload all events. */ + gint reload_events_idle_id; + /* An array of EWeekViewEventSpan elements. Each event has its own space within this array, and uses the spans_index and num_spans fields of the EWeekViewEvent struct to access it. */ @@ -191,8 +195,13 @@ struct _EWeekView /* The first day shown in the view. */ GDate first_day_shown; - /* If we are displaying 1 week or 1 month. */ - gboolean display_month; + /* If we are displaying multiple weeks in rows. If this is FALSE only + one week is shown, with a different layout. */ + gboolean multi_week_view; + + /* How many weeks we are showing. This is only relevant if + display_month is TRUE. */ + gint weeks_shown; /* If Sat & Sun are compressed. Only applicable in month view, since they are always compressed into 1 cell in the week view. */ @@ -233,15 +242,17 @@ struct _EWeekView gint abbr_month_widths[12]; gint max_abbr_month_width; - /* The size of the main grid of days and of the cells. Note that the - offsets arrays have one more element than the widths/heights arrays - since they also contain the right/bottom edge. */ + /* The size of the main grid of days and of the cells. A row + corresponds to a compressed day, so normal days usually take + up 2 rows. Note that the offsets arrays have one more element + than the widths/heights arrays since they also contain the + right/bottom edge. */ gint rows; gint columns; gint col_widths[7]; gint col_offsets[8]; - gint row_heights[10]; - gint row_offsets[11]; + gint row_heights[E_WEEK_VIEW_MAX_WEEKS * 2]; + gint row_offsets[E_WEEK_VIEW_MAX_WEEKS * 2 + 1]; /* This specifies which times we are showing for the events, depending on how much room is available. */ @@ -312,25 +323,37 @@ GtkWidget* e_week_view_new (void); void e_week_view_set_calendar (EWeekView *week_view, GnomeCalendar *calendar); +/* The first day shown. Note that it will be rounded down to the start of a + week when set. The returned value will be invalid if no date has been set + yet. */ +void e_week_view_get_first_day_shown (EWeekView *week_view, + GDate *date); +void e_week_view_set_first_day_shown (EWeekView *week_view, + GDate *date); + void e_week_view_set_cal_client (EWeekView *week_view, CalClient *client); -/* This sets the selected time range. The EWeekView will show the corresponding +/* The selected time range. The EWeekView will show the corresponding month and the days between start_time and end_time will be selected. To select a single day, use the same value for start_time & end_time. */ +void e_week_view_get_selected_time_range (EWeekView *week_view, + time_t *start_time, + time_t *end_time); void e_week_view_set_selected_time_range (EWeekView *week_view, time_t start_time, time_t end_time); -/* Returns the selected time range. */ -void e_week_view_get_selected_time_range (EWeekView *week_view, - time_t *start_time, - time_t *end_time); /* Whether to display 1 week or 1 month (5 weeks). It defaults to 1 week. */ -gboolean e_week_view_get_display_month (EWeekView *week_view); -void e_week_view_set_display_month (EWeekView *week_view, - gboolean display_month); +gboolean e_week_view_get_multi_week_view (EWeekView *week_view); +void e_week_view_set_multi_week_view (EWeekView *week_view, + gboolean multi_week_view); + +/* The number of weeks shown in the multi-week view. */ +gint e_week_view_get_weeks_shown (EWeekView *week_view); +void e_week_view_set_weeks_shown (EWeekView *week_view, + gint weeks_shown); /* Whether the weekend (Sat/Sun) should be compressed into 1 cell in the Month view. In the Week view they are always compressed. */ diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index ea61dafabc..2f6a8ddf4a 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -42,13 +42,27 @@ static void gnome_calendar_class_init (GnomeCalendarClass *class); static void gnome_calendar_init (GnomeCalendar *gcal); static void gnome_calendar_destroy (GtkObject *object); -static void gnome_calendar_update_view_times (GnomeCalendar *gcal, - GtkWidget *page); -static void gnome_calendar_update_gtk_calendar (GnomeCalendar *gcal); -static void gnome_calendar_on_day_selected (GtkCalendar *calendar, - GnomeCalendar *gcal); -static void gnome_calendar_on_month_changed (GtkCalendar *calendar, - GnomeCalendar *gcal); +static void gnome_calendar_set_view_internal (GnomeCalendar *gcal, + char *page_name, + gboolean range_selected); +static void gnome_calendar_set_pane_positions (GnomeCalendar *gcal); +static void gnome_calendar_update_view_times (GnomeCalendar *gcal); +static void gnome_calendar_update_date_navigator (GnomeCalendar *gcal); + +static void gnome_calendar_on_date_navigator_style_set (GtkWidget *widget, + GtkStyle *previous_style, + GnomeCalendar *gcal); +static void gnome_calendar_on_date_navigator_size_allocate (GtkWidget *widget, + GtkAllocation *allocation, + GnomeCalendar *gcal); +static void gnome_calendar_on_date_navigator_date_range_changed (ECalendarItem *calitem, + GnomeCalendar *gcal); +static void gnome_calendar_on_date_navigator_selection_changed (ECalendarItem *calitem, + GnomeCalendar *gcal); +static gboolean gnome_calendar_get_days_shown (GnomeCalendar *gcal, + GDate *start_date, + gint *days_shown); + static GtkVBoxClass *parent_class; @@ -98,6 +112,19 @@ gnome_calendar_init (GnomeCalendar *gcal) { gcal->object_editor_hash = g_hash_table_new (g_str_hash, g_str_equal); gcal->alarms = g_hash_table_new (g_str_hash, g_str_equal); + + gcal->current_view_type = GNOME_CALENDAR_VIEW_NOT_SET; + gcal->range_selected = FALSE; + + /* Set the default pane positions. These will eventually come from + gconf settings. They are multiples of calendar month widths & + heights in the date navigator. */ + gcal->hpane_pos = 1.0; + gcal->vpane_pos = 1.0; + gcal->hpane_pos_month_view = 0.0; + gcal->vpane_pos_month_view = 1.0; + + gcal->ignore_view_button_clicks = FALSE; } /* Used from g_hash_table_foreach(); frees an object alarms entry */ @@ -157,56 +184,51 @@ gnome_calendar_destroy (GtkObject *object) static void setup_widgets (GnomeCalendar *gcal) { - GtkWidget *vpane, *w; - - /* The Main Notebook. */ - gcal->main_notebook = gtk_notebook_new (); - gtk_notebook_set_show_border (GTK_NOTEBOOK (gcal->main_notebook), - FALSE); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (gcal->main_notebook), FALSE); - gtk_widget_show (gcal->main_notebook); - gtk_box_pack_start (GTK_BOX (gcal), gcal->main_notebook, - TRUE, TRUE, 0); + GtkWidget *w; - /* The First Page of the Main Notebook, containing a HPaned with the - Sub-Notebook on the left and the GtkCalendar and ToDo list on the - right. */ + /* The main HPaned, with the notebook of calendar views on the left + and the ECalendar and ToDo list on the right. */ gcal->hpane = e_hpaned_new (); gtk_widget_show (gcal->hpane); - gtk_notebook_append_page (GTK_NOTEBOOK (gcal->main_notebook), - gcal->hpane, gtk_label_new ("")); - - /* The Sub-Notebook, to contain the Day, Work-Week & Week views. */ - gcal->sub_notebook = gtk_notebook_new (); - gtk_notebook_set_show_border (GTK_NOTEBOOK (gcal->sub_notebook), - FALSE); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (gcal->sub_notebook), FALSE); - gtk_widget_show (gcal->sub_notebook); - e_paned_pack1 (E_PANED (gcal->hpane), gcal->sub_notebook, - TRUE, TRUE); + gtk_box_pack_start (GTK_BOX (gcal), gcal->hpane, TRUE, TRUE, 0); + + /* The Notebook containing the 4 calendar views. */ + gcal->notebook = gtk_notebook_new (); + gtk_notebook_set_show_border (GTK_NOTEBOOK (gcal->notebook), FALSE); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (gcal->notebook), FALSE); + gtk_widget_show (gcal->notebook); + e_paned_pack1 (E_PANED (gcal->hpane), gcal->notebook, TRUE, TRUE); /* The VPaned widget, to contain the GtkCalendar & ToDo list. */ - vpane = e_vpaned_new (); - gtk_widget_show (vpane); - e_paned_pack2 (E_PANED (gcal->hpane), vpane, FALSE, TRUE); + gcal->vpane = e_vpaned_new (); + gtk_widget_show (gcal->vpane); + e_paned_pack2 (E_PANED (gcal->hpane), gcal->vpane, FALSE, TRUE); - /* The GtkCalendar. */ - w = gtk_calendar_new (); - gcal->gtk_calendar = GTK_CALENDAR (w); + /* The ECalendar. */ + w = e_calendar_new (); + gcal->date_navigator = E_CALENDAR (w); gtk_widget_show (w); - e_paned_pack1 (E_PANED (vpane), w, FALSE, TRUE); - gcal->day_selected_id = gtk_signal_connect (GTK_OBJECT (gcal->gtk_calendar), - "day_selected", - (GtkSignalFunc) gnome_calendar_on_day_selected, - gcal); - gtk_signal_connect (GTK_OBJECT (gcal->gtk_calendar), "month_changed", - GTK_SIGNAL_FUNC (gnome_calendar_on_month_changed), + e_paned_pack1 (E_PANED (gcal->vpane), w, FALSE, TRUE); + gtk_signal_connect (GTK_OBJECT (gcal->date_navigator), + "style_set", + GTK_SIGNAL_FUNC (gnome_calendar_on_date_navigator_style_set), + gcal); + gtk_signal_connect_after (GTK_OBJECT (gcal->date_navigator), + "size_allocate", + (GtkSignalFunc) gnome_calendar_on_date_navigator_size_allocate, + gcal); + gtk_signal_connect (GTK_OBJECT (gcal->date_navigator->calitem), + "selection_changed", + (GtkSignalFunc) gnome_calendar_on_date_navigator_selection_changed, + gcal); + gtk_signal_connect (GTK_OBJECT (gcal->date_navigator->calitem), + "date_range_changed", + GTK_SIGNAL_FUNC (gnome_calendar_on_date_navigator_date_range_changed), gcal); /* The ToDo list. */ - gcal->todo = e_calendar_table_new (); - e_paned_pack2 (E_PANED (vpane), gcal->todo, TRUE, TRUE); + e_paned_pack2 (E_PANED (gcal->vpane), gcal->todo, TRUE, TRUE); gtk_widget_show (gcal->todo); e_calendar_table_set_cal_client (E_CALENDAR_TABLE (gcal->todo), gcal->client); @@ -217,16 +239,18 @@ setup_widgets (GnomeCalendar *gcal) e_day_view_set_calendar (E_DAY_VIEW (gcal->day_view), gcal); e_day_view_set_cal_client (E_DAY_VIEW (gcal->day_view), gcal->client); gtk_widget_show (gcal->day_view); - gtk_notebook_append_page (GTK_NOTEBOOK (gcal->sub_notebook), + gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->day_view, gtk_label_new ("")); /* The Work Week View. */ gcal->work_week_view = e_day_view_new (); + e_day_view_set_work_week_view (E_DAY_VIEW (gcal->work_week_view), + TRUE); e_day_view_set_days_shown (E_DAY_VIEW (gcal->work_week_view), 5); e_day_view_set_calendar (E_DAY_VIEW (gcal->work_week_view), gcal); e_day_view_set_cal_client (E_DAY_VIEW (gcal->work_week_view), gcal->client); gtk_widget_show (gcal->work_week_view); - gtk_notebook_append_page (GTK_NOTEBOOK (gcal->sub_notebook), + gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->work_week_view, gtk_label_new ("")); /* The Week View. */ @@ -234,29 +258,23 @@ setup_widgets (GnomeCalendar *gcal) e_week_view_set_calendar (E_WEEK_VIEW (gcal->week_view), gcal); e_week_view_set_cal_client (E_WEEK_VIEW (gcal->week_view), gcal->client); gtk_widget_show (gcal->week_view); - gtk_notebook_append_page (GTK_NOTEBOOK (gcal->sub_notebook), + gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->week_view, gtk_label_new ("")); /* The Month View. */ gcal->month_view = e_week_view_new (); e_week_view_set_calendar (E_WEEK_VIEW (gcal->month_view), gcal); + e_week_view_set_multi_week_view (E_WEEK_VIEW (gcal->month_view), TRUE); e_week_view_set_cal_client (E_WEEK_VIEW (gcal->month_view), gcal->client); - e_week_view_set_display_month (E_WEEK_VIEW (gcal->month_view), TRUE); gtk_widget_show (gcal->month_view); - gtk_notebook_append_page (GTK_NOTEBOOK (gcal->main_notebook), + gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->month_view, gtk_label_new ("")); } static GtkWidget * get_current_page (GnomeCalendar *gcal) { - GtkWidget *page; - - page = GTK_NOTEBOOK (gcal->main_notebook)->cur_page->child; - if (page == gcal->hpane) - return GTK_NOTEBOOK (gcal->sub_notebook)->cur_page->child; - else - return page; + return GTK_NOTEBOOK (gcal->notebook)->cur_page->child; } char * @@ -291,29 +309,29 @@ gnome_calendar_goto (GnomeCalendar *gcal, time_t new_time) gcal->selection_start_time = time_day_begin (new_time); gcal->selection_end_time = time_add_day (gcal->selection_start_time, 1); - gnome_calendar_update_view_times (gcal, NULL); - gnome_calendar_update_gtk_calendar (gcal); + gnome_calendar_update_view_times (gcal); + gnome_calendar_update_date_navigator (gcal); } static void -gnome_calendar_update_view_times (GnomeCalendar *gcal, - GtkWidget *page) +gnome_calendar_update_view_times (GnomeCalendar *gcal) { - if (page == NULL) - page = get_current_page (gcal); + GtkWidget *page; - if (page == gcal->day_view - || page == gcal->work_week_view) - e_day_view_set_selected_time_range (E_DAY_VIEW (page), - gcal->selection_start_time, - gcal->selection_end_time); - else if (page == gcal->week_view - || page == gcal->month_view) - e_week_view_set_selected_time_range (E_WEEK_VIEW (page), - gcal->selection_start_time, - gcal->selection_end_time); - else { + page = get_current_page (gcal); + + if (page == gcal->day_view || page == gcal->work_week_view) { + e_day_view_set_selected_time_range + (E_DAY_VIEW (page), + gcal->selection_start_time, + gcal->selection_end_time); + } else if (page == gcal->week_view || page == gcal->month_view) { + e_week_view_set_selected_time_range + (E_WEEK_VIEW (page), + gcal->selection_start_time, + gcal->selection_end_time); + } else { g_warning ("My penguin is gone!"); g_assert_not_reached (); } @@ -350,8 +368,8 @@ gnome_calendar_direction (GnomeCalendar *gcal, int direction) gcal->selection_start_time = start_time; gcal->selection_end_time = end_time; - gnome_calendar_update_view_times (gcal, NULL); - gnome_calendar_update_gtk_calendar (gcal); + gnome_calendar_update_view_times (gcal); + gnome_calendar_update_date_navigator (gcal); } void @@ -378,8 +396,11 @@ gnome_calendar_dayjump (GnomeCalendar *gcal, time_t time) g_return_if_fail (gcal != NULL); g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - gnome_calendar_set_view (gcal, "dayview"); - gnome_calendar_goto (gcal, time); + gcal->selection_start_time = time_day_begin (time); + gcal->selection_end_time = time_add_day (gcal->selection_start_time, + 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gcal->day_button), + TRUE); } void @@ -389,48 +410,129 @@ gnome_calendar_goto_today (GnomeCalendar *gcal) g_return_if_fail (GNOME_IS_CALENDAR (gcal)); gnome_calendar_goto (gcal, time (NULL)); + + gtk_widget_grab_focus (get_current_page (gcal)); } /* This sets which view is currently shown. It also updates the selection time of the view so it shows the appropriate days. */ void -gnome_calendar_set_view (GnomeCalendar *gcal, char *page_name) +gnome_calendar_set_view (GnomeCalendar *gcal, + char *page_name, + gboolean range_selected) { - GtkWidget *page; - int main_page = 0, sub_page = -1; - g_return_if_fail (gcal != NULL); g_return_if_fail (GNOME_IS_CALENDAR (gcal)); g_return_if_fail (page_name != NULL); - if (strcmp (page_name, "dayview") == 0) { - page = gcal->day_view; - sub_page = 0; - } else if (strcmp (page_name, "workweekview") == 0) { - page = gcal->work_week_view; - sub_page = 1; - } else if (strcmp (page_name, "weekview") == 0) { - page = gcal->week_view; - sub_page = 2; - } else if (strcmp (page_name, "monthview") == 0) { - page = gcal->month_view; - main_page = 1; + gnome_calendar_set_view_internal (gcal, page_name, range_selected); + gnome_calendar_update_view_times (gcal); + gnome_calendar_update_date_navigator (gcal); +} + + +/* This sets the view without changing the selection or updating the date + navigator. If a range of dates isn't selected it will also reset the number + of days/weeks shown to the default (i.e. 1 day for the day view or 5 weeks + for the month view). */ +static void +gnome_calendar_set_view_internal (GnomeCalendar *gcal, + char *page_name, + gboolean range_selected) +{ + int view; + gboolean round_selection = FALSE; + + g_print ("In gnome_calendar_set_view_internal: %s\n", page_name); + + if (!strcmp (page_name, "dayview")) { + view = GNOME_CALENDAR_VIEW_DAY; + if (!range_selected) + e_day_view_set_days_shown + (E_DAY_VIEW (gcal->day_view), 1); + } else if (!strcmp (page_name, "workweekview")) { + view = GNOME_CALENDAR_VIEW_WORK_WEEK; + } else if (!strcmp (page_name, "weekview")) { + view = GNOME_CALENDAR_VIEW_WEEK; + round_selection = TRUE; + } else if (!strcmp (page_name, "monthview")) { + view = GNOME_CALENDAR_VIEW_MONTH; + if (!range_selected) + e_week_view_set_weeks_shown + (E_WEEK_VIEW (gcal->month_view), 5); + round_selection = TRUE; } else { g_warning ("Unknown calendar view: %s", page_name); return; } - gnome_calendar_update_view_times (gcal, page); + gcal->current_view_type = view; + gcal->range_selected = range_selected; + + gtk_notebook_set_page (GTK_NOTEBOOK (gcal->notebook), view); + + gnome_calendar_set_pane_positions (gcal); + + /* For the week & month views we want the selection in the date + navigator to be rounded to the nearest week when the arrow buttons + are pressed to move to the previous/next month. */ + gtk_object_set (GTK_OBJECT (gcal->date_navigator->calitem), + "round_selection_when_moving", round_selection, + NULL); +} + - if (sub_page != -1) - gtk_notebook_set_page (GTK_NOTEBOOK (gcal->sub_notebook), - sub_page); - gtk_notebook_set_page (GTK_NOTEBOOK (gcal->main_notebook), main_page); +static void +gnome_calendar_set_pane_positions (GnomeCalendar *gcal) +{ + gint top_border, bottom_border, left_border, right_border; + gint col_width, row_height; + gfloat right_pane_width, top_pane_height; + + /* Get the size of the calendar month width & height. */ + e_calendar_get_border_size (gcal->date_navigator, + &top_border, &bottom_border, + &left_border, &right_border); + gtk_object_get (GTK_OBJECT (gcal->date_navigator->calitem), + "row_height", &row_height, + "column_width", &col_width, + NULL); + + if (gcal->current_view_type == GNOME_CALENDAR_VIEW_MONTH + && !gcal->range_selected) { + right_pane_width = gcal->hpane_pos_month_view; + top_pane_height = gcal->vpane_pos_month_view; + } else { + right_pane_width = gcal->hpane_pos; + top_pane_height = gcal->vpane_pos; + } - gnome_calendar_update_gtk_calendar (gcal); + /* We add the borders before multiplying due to the way we are using + the EPaned quantum feature. */ + if (right_pane_width < 0.001) + right_pane_width = 0.0; + else + right_pane_width = right_pane_width * (col_width + + left_border + right_border) + 0.5; + if (top_pane_height < 0.001) + top_pane_height = 0.0; + else + top_pane_height = top_pane_height * (row_height + + top_border + bottom_border) + 0.5; + + g_print ("right width:%g top height:%g\n", right_pane_width, + top_pane_height); + + e_paned_set_position (E_PANED (gcal->hpane), -1); + e_paned_set_position (E_PANED (gcal->vpane), -1); + /* We add one to each dimension since we can't use 0. */ + gtk_widget_set_usize (gcal->vpane, right_pane_width + 1, -2); + gtk_widget_set_usize (GTK_WIDGET (gcal->date_navigator), + -2, top_pane_height + 1); } + #ifndef NO_WARNINGS /* Sends a mail notification of an alarm trigger */ static void @@ -811,7 +913,7 @@ static void gnome_calendar_update_all (GnomeCalendar *cal) { load_alarms (cal); - gnome_calendar_tag_calendar (cal, cal->gtk_calendar); + gnome_calendar_tag_calendar (cal, cal->date_navigator); } /* Removes any queued alarms for the specified UID */ @@ -873,7 +975,7 @@ gnome_calendar_object_updated_cb (GtkWidget *cal_client, remove_alarms_for_object (gcal, uid); add_alarms_for_object (gcal, uid); - gnome_calendar_tag_calendar (gcal, gcal->gtk_calendar); + gnome_calendar_tag_calendar (gcal, gcal->date_navigator); } @@ -884,7 +986,7 @@ gnome_calendar_object_removed_cb (GtkWidget *cal_client, { remove_alarms_for_object (gcal, uid); - gnome_calendar_tag_calendar (gcal, gcal->gtk_calendar); + gnome_calendar_tag_calendar (gcal, gcal->date_navigator); } @@ -904,7 +1006,7 @@ gnome_calendar_new (char *title) setup_widgets (gcal); - gnome_calendar_set_view (gcal, "dayview"); + gnome_calendar_set_view (gcal, "dayview", FALSE); gtk_signal_connect (GTK_OBJECT (gcal->client), "obj_updated", gnome_calendar_object_updated_cb, gcal); @@ -1134,91 +1236,93 @@ calendar_notify (time_t activation_time, CalendarAlarm *which, void *data) #endif +struct calendar_tag_closure +{ + ECalendarItem *calitem; + time_t start_time; + time_t end_time; +}; + /* Marks the specified range in a GtkCalendar */ -static void -mark_gtk_calendar_day (GtkCalendar *calendar, time_t start, time_t end) +static gboolean +gnome_calendar_tag_calendar_cb (CalComponent *comp, + time_t istart, + time_t iend, + gpointer data) { + struct calendar_tag_closure *c = data; time_t t; - t = time_day_begin (start); + t = time_day_begin (istart); do { struct tm tm; tm = *localtime (&t); - gtk_calendar_mark_day (calendar, tm.tm_mday); + + e_calendar_item_mark_day (c->calitem, tm.tm_year + 1900, + tm.tm_mon, tm.tm_mday, + E_CALENDAR_ITEM_MARK_BOLD); t = time_day_end (t); - } while (t < end); + } while (t < iend); + + return TRUE; } /* * Tags the dates with appointments in a GtkCalendar based on the * GnomeCalendar contents */ -struct calendar_tag_closure -{ - GtkCalendar *gtk_cal; - time_t month_begin; - time_t month_end; -}; - -static gboolean -gnome_calendar_tag_calendar_cb (CalComponent *comp, time_t istart, time_t iend, gpointer data) -{ - struct calendar_tag_closure *c = data; - time_t start, end; - - start = MAX (istart, c->month_begin); - end = MIN (iend, c->month_end); - - if (start > end) - return TRUE; - - /* Clip the occurrence's start and end times to the month's limits */ - mark_gtk_calendar_day (c->gtk_cal, start, end); - - return TRUE; -} - void -gnome_calendar_tag_calendar (GnomeCalendar *cal, GtkCalendar *gtk_cal) +gnome_calendar_tag_calendar (GnomeCalendar *gcal, ECalendar *ecal) { struct calendar_tag_closure c; + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + struct tm start_tm = { 0 }, end_tm = { 0 }; - g_return_if_fail (cal != NULL); - g_return_if_fail (GNOME_IS_CALENDAR (cal)); - g_return_if_fail (gtk_cal != NULL); - g_return_if_fail (GTK_IS_CALENDAR (gtk_cal)); - - /* If the GtkCalendar isn't visible, we just return. */ - if (!GTK_WIDGET_VISIBLE (cal->gtk_calendar)) - return; - - c.gtk_cal = gtk_cal; - - c.month_begin = time_from_day (gtk_cal->year, gtk_cal->month, 1); - if (c.month_begin == -1) { - g_message ("gnome_calendar_tag_calendar(): Generated invalid month begin!"); - return; - } + g_return_if_fail (gcal != NULL); + g_return_if_fail (GNOME_IS_CALENDAR (gcal)); + g_return_if_fail (ecal != NULL); + g_return_if_fail (E_IS_CALENDAR (ecal)); - c.month_end = time_month_end (c.month_begin); - if (c.month_end == -1) { - g_message ("gnome_calendar_tag_calendar(): Generated invalid month end!"); + /* If the ECalendar isn't visible, we just return. */ + if (!GTK_WIDGET_VISIBLE (ecal)) return; - } - gtk_calendar_freeze (gtk_cal); - gtk_calendar_clear_marks (gtk_cal); - - cal_client_generate_instances (cal->client, CALOBJ_TYPE_EVENT, - c.month_begin, c.month_end, + e_calendar_item_get_date_range (ecal->calitem, + &start_year, &start_month, &start_day, + &end_year, &end_month, &end_day); + + start_tm.tm_year = start_year - 1900; + start_tm.tm_mon = start_month; + start_tm.tm_mday = start_day; + start_tm.tm_hour = 0; + start_tm.tm_min = 0; + start_tm.tm_sec = 0; + start_tm.tm_isdst = -1; + + end_tm.tm_year = end_year - 1900; + end_tm.tm_mon = end_month; + end_tm.tm_mday = end_day; + end_tm.tm_hour = 0; + end_tm.tm_min = 0; + end_tm.tm_sec = 0; + end_tm.tm_isdst = -1; + + e_calendar_item_clear_marks (ecal->calitem); + + c.calitem = ecal->calitem; + c.start_time = mktime (&start_tm); + c.end_time = mktime (&end_tm); + + cal_client_generate_instances (gcal->client, CALOBJ_TYPE_EVENT, + c.start_time, c.end_time, gnome_calendar_tag_calendar_cb, &c); - - gtk_calendar_thaw (gtk_cal); } + /* This is called when the day begin & end times, the AM/PM flag, or the week_starts_on_monday flags are changed. FIXME: Which of these options do we want the new views to support? */ @@ -1227,13 +1331,14 @@ gnome_calendar_time_format_changed (GnomeCalendar *gcal) { g_return_if_fail (gcal != NULL); g_return_if_fail (GNOME_IS_CALENDAR (gcal)); - +#if 0 gtk_calendar_display_options (gcal->gtk_calendar, (week_starts_on_monday ? (gcal->gtk_calendar->display_flags | GTK_CALENDAR_WEEK_START_MONDAY) : (gcal->gtk_calendar->display_flags & ~GTK_CALENDAR_WEEK_START_MONDAY))); +#endif } /* This is called when any of the color settings are changed. @@ -1261,9 +1366,10 @@ gnome_calendar_set_selected_time_range (GnomeCalendar *gcal, gcal->selection_start_time = start_time; gcal->selection_end_time = end_time; - gnome_calendar_update_gtk_calendar (gcal); + gnome_calendar_update_date_navigator (gcal); } + /* Callback used when an event editor requests that an object be saved */ static void save_event_object_cb (EventEditor *ee, CalComponent *comp, gpointer data) @@ -1275,6 +1381,7 @@ save_event_object_cb (EventEditor *ee, CalComponent *comp, gpointer data) g_message ("save_event_object_cb(): Could not update the object!"); } + /* Callback used when an event editor finishes editing an object */ static void released_event_object_cb (EventEditor *ee, const char *uid, gpointer data) @@ -1328,7 +1435,6 @@ gnome_calendar_edit_object (GnomeCalendar *gcal, CalComponent *comp) g_hash_table_insert (gcal->object_editor_hash, g_strdup (uid), ee); - gtk_signal_connect (GTK_OBJECT (ee), "save_event_object", GTK_SIGNAL_FUNC (save_event_object_cb), gcal); @@ -1411,77 +1517,268 @@ gnome_calendar_get_current_time_range (GnomeCalendar *gcal, -/* This updates the month shown and the day selected in the calendar, if +/* This updates the month shown and the days selected in the calendar, if necessary. */ static void -gnome_calendar_update_gtk_calendar (GnomeCalendar *gcal) +gnome_calendar_update_date_navigator (GnomeCalendar *gcal) { - GDate date; - guint current_year, current_month, current_day; - guint new_year, new_month, new_day; - gboolean set_day = FALSE; + GDate start_date, end_date; + gint days_shown; - /* If the GtkCalendar isn't visible, we just return. */ - if (!GTK_WIDGET_VISIBLE (gcal->gtk_calendar)) + /* If the ECalendar isn't visible, we just return. */ + if (!GTK_WIDGET_VISIBLE (gcal->date_navigator)) return; - gtk_calendar_get_date (gcal->gtk_calendar, ¤t_year, - ¤t_month, ¤t_day); - - g_date_clear (&date, 1); - g_date_set_time (&date, gcal->selection_start_time); - new_year = g_date_year (&date); - new_month = g_date_month (&date) - 1; - new_day = g_date_day (&date); - - /* Block the "day_selected" signal while we update the calendar. */ - gtk_signal_handler_block (GTK_OBJECT (gcal->gtk_calendar), - gcal->day_selected_id); - - /* If the year & month don't match, update it. */ - if (new_year != current_year || new_month != current_month) { - /* FIXME: GtkCalendar bug workaround. If we select a month - which has less days than the currently selected day, it - causes a problem next time we set the day. */ - if (current_day > 28) { - gtk_calendar_select_day (gcal->gtk_calendar, 28); - set_day = TRUE; - } - gtk_calendar_select_month (gcal->gtk_calendar, new_month, - new_year); + if (gnome_calendar_get_days_shown (gcal, &start_date, &days_shown)) { + end_date = start_date; + g_date_add_days (&end_date, days_shown - 1); + + e_calendar_item_set_selection (gcal->date_navigator->calitem, + &start_date, &end_date); } +} + - /* If the day doesn't match, update it. */ - if (new_day != current_day || set_day) - gtk_calendar_select_day (gcal->gtk_calendar, new_day); +static gboolean +gnome_calendar_get_days_shown (GnomeCalendar *gcal, + GDate *start_date, + gint *days_shown) +{ + GtkWidget *page; + + page = get_current_page (gcal); - gtk_signal_handler_unblock (GTK_OBJECT (gcal->gtk_calendar), - gcal->day_selected_id); + if (page == gcal->day_view || page == gcal->work_week_view) { + g_date_clear (start_date, 1); + g_date_set_time (start_date, E_DAY_VIEW (page)->lower); + *days_shown = e_day_view_get_days_shown (E_DAY_VIEW (page)); + return TRUE; + } else if (page == gcal->week_view || page == gcal->month_view) { + *start_date = E_WEEK_VIEW (page)->first_day_shown; + if (e_week_view_get_multi_week_view (E_WEEK_VIEW (page))) + *days_shown = e_week_view_get_weeks_shown (E_WEEK_VIEW (page)) * 7; + else + *days_shown = 7; + return TRUE; + } else { + g_warning ("gnome_calendar_get_days_shown - Invalid page"); + return FALSE; + } } + static void -gnome_calendar_on_day_selected (GtkCalendar *calendar, - GnomeCalendar *gcal) +gnome_calendar_on_date_navigator_selection_changed (ECalendarItem *calitem, + GnomeCalendar *gcal) { - gint y, m, d; + GDate start_date, end_date, new_start_date, new_end_date; + gint days_shown, new_days_shown; + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + gboolean starts_on_week_start_day = FALSE; struct tm tm; - gtk_calendar_get_date (calendar, &y, &m, &d); + g_print ("In gnome_calendar_on_date_navigator_selection_changed\n"); + + if (!gnome_calendar_get_days_shown (gcal, &start_date, &days_shown)) + return; + + end_date = start_date; + g_date_add_days (&end_date, days_shown - 1); + + e_calendar_item_get_selection (calitem, &new_start_date, + &new_end_date); + + /* If the selection hasn't changed just return. */ + if (!g_date_compare (&start_date, &new_start_date) + && !g_date_compare (&end_date, &new_end_date)) + return; + + new_days_shown = g_date_julian (&new_end_date) + - g_date_julian (&new_start_date) + 1; + + /* FIXME: This assumes weeks start on Monday for now. */ + if (g_date_weekday (&new_start_date) - 1 == 0) + starts_on_week_start_day = TRUE; + + /* Switch views as appropriate, and change the number of days or weeks + shown. */ + if (new_days_shown > 9) { + e_week_view_set_weeks_shown (E_WEEK_VIEW (gcal->month_view), + (new_days_shown + 6) / 7); + e_week_view_set_first_day_shown (E_WEEK_VIEW (gcal->month_view), + &new_start_date); + gnome_calendar_set_view_internal (gcal, "monthview", TRUE); + gnome_calendar_update_date_navigator (gcal); + } else if (new_days_shown == 7 && starts_on_week_start_day) { + e_week_view_set_first_day_shown (E_WEEK_VIEW (gcal->week_view), + &new_start_date); + gnome_calendar_set_view_internal (gcal, "weekview", TRUE); + gnome_calendar_update_date_navigator (gcal); + } else { + start_year = g_date_year (&new_start_date); + start_month = g_date_month (&new_start_date) - 1; + start_day = g_date_day (&new_start_date); + end_year = g_date_year (&new_end_date); + end_month = g_date_month (&new_end_date) - 1; + end_day = g_date_day (&new_end_date); + + tm.tm_year = start_year - 1900; + tm.tm_mon = start_month; + tm.tm_mday = start_day; + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; + gcal->selection_start_time = mktime (&tm); + + tm.tm_year = end_year - 1900; + tm.tm_mon = end_month; + tm.tm_mday = end_day + 1; /* mktime() will normalize this. */ + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; + gcal->selection_end_time = mktime (&tm); + + e_day_view_set_days_shown (E_DAY_VIEW (gcal->day_view), + new_days_shown); + gnome_calendar_set_view (gcal, "dayview", TRUE); + } + + gnome_calendar_update_view_buttons (gcal); + gtk_widget_grab_focus (get_current_page (gcal)); +} + + +static void +gnome_calendar_on_date_navigator_date_range_changed (ECalendarItem *calitem, + GnomeCalendar *gcal) +{ + gnome_calendar_tag_calendar (gcal, gcal->date_navigator); +} - tm.tm_year = y - 1900; - tm.tm_mon = m; - tm.tm_mday = d; - tm.tm_hour = 5; /* for daylight savings time fix */ - tm.tm_min = 0; - tm.tm_sec = 0; - gnome_calendar_goto (gcal, mktime (&tm)); +static void +gnome_calendar_on_date_navigator_style_set (GtkWidget *widget, + GtkStyle *previous_style, + GnomeCalendar *gcal) +{ + ECalendar *ecal; + gint row_height, col_width; + gint top_border, bottom_border, left_border, right_border; + + g_return_if_fail (E_IS_CALENDAR (widget)); + g_return_if_fail (GNOME_IS_CALENDAR (gcal)); + + ecal = E_CALENDAR (widget); + + e_calendar_get_border_size (gcal->date_navigator, + &top_border, &bottom_border, + &left_border, &right_border); + gtk_object_get (GTK_OBJECT (ecal->calitem), + "row_height", &row_height, + "column_width", &col_width, + NULL); + + /* The EPaned quantum feature works better if we add on the calendar + borders to the quantum size. Otherwise if you shrink the date + navigator you get left with the border widths/heights which looks + bad. EPaned should be more flexible really. */ + col_width += left_border + right_border; + row_height += top_border + bottom_border; + + /* We don't have to use the EPaned quantum feature. We could just let + the calendar expand to fill the allocated space, showing as many + months as will fit. But for that to work nicely the EPaned should + resize the widgets as the bar is dragged. Otherwise the user has + to mess around to get the number of months that they want. */ +#if 1 + gtk_object_set (GTK_OBJECT (gcal->hpane), + "quantum", (guint) col_width, + NULL); + gtk_object_set (GTK_OBJECT (gcal->vpane), + "quantum", (guint) row_height, + NULL); +#endif + + gnome_calendar_set_pane_positions (gcal); } static void -gnome_calendar_on_month_changed (GtkCalendar *calendar, - GnomeCalendar *gcal) +gnome_calendar_on_date_navigator_size_allocate (GtkWidget *widget, + GtkAllocation *allocation, + GnomeCalendar *gcal) +{ + gint width, height, row_height, col_width; + gint top_border, bottom_border, left_border, right_border; + gfloat hpane_pos, vpane_pos; + + g_print ("In gnome_calendar_on_date_navigator_size_allocate %ix%i\n", + allocation->width, allocation->height); + + if (gcal->current_view_type != GNOME_CALENDAR_VIEW_NOT_SET) { + e_calendar_get_border_size (gcal->date_navigator, + &top_border, &bottom_border, + &left_border, &right_border); + gtk_object_get (GTK_OBJECT (gcal->date_navigator->calitem), + "row_height", &row_height, + "column_width", &col_width, + NULL); + + /* We subtract one from each dimension since we added 1 in + gnome_calendar_set_view_internal(). */ + width = allocation->width - 1; + height = allocation->height - 1; + + /* We add the border sizes to work around the EPaned + quantized feature. */ + col_width += left_border + right_border; + row_height += top_border + bottom_border; + + hpane_pos = (gfloat) width / col_width; + vpane_pos = (gfloat) height / row_height; + + if (gcal->current_view_type == GNOME_CALENDAR_VIEW_MONTH + && !gcal->range_selected) { + gcal->hpane_pos_month_view = hpane_pos; + gcal->vpane_pos_month_view = vpane_pos; + } else { + gcal->hpane_pos = hpane_pos; + gcal->vpane_pos = vpane_pos; + } + + g_print (" hpane_pos:%g vpane_pos:%g\n", hpane_pos, vpane_pos); + + } +} + + +/* This makes the appropriate radio button in the toolbar active. + It sets the ignore_view_button_clicks flag so the "clicked" signal handlers + just return without doing anything. */ +void +gnome_calendar_update_view_buttons (GnomeCalendar *gcal) { - gnome_calendar_tag_calendar (gcal, gcal->gtk_calendar); + GtkWidget *page, *button; + + page = get_current_page (gcal); + + if (page == gcal->day_view) + button = gcal->day_button; + else if (page == gcal->work_week_view) + button = gcal->work_week_button; + else if (page == gcal->week_view) + button = gcal->week_button; + else if (page == gcal->month_view) + button = gcal->month_button; + else { + g_warning ("Unknown calendar view"); + button = gcal->day_button; + } + + gcal->ignore_view_button_clicks = TRUE; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); + gcal->ignore_view_button_clicks = FALSE; } diff --git a/calendar/gui/gnome-cal.h b/calendar/gui/gnome-cal.h index df087395e1..b484caff1e 100644 --- a/calendar/gui/gnome-cal.h +++ b/calendar/gui/gnome-cal.h @@ -10,22 +10,31 @@ #define GNOME_CALENDAR_APP_H #include <time.h> -#include <gtk/gtkcalendar.h> -#include <gtk/gtkvbox.h> #include <libgnome/gnome-defs.h> +#include <gtk/gtkvbox.h> #include <bonobo.h> +#include <widgets/misc/e-calendar.h> #include <cal-client/cal-client.h> BEGIN_GNOME_DECLS +/* These must match the page numbers in the GtkNotebook. */ +typedef enum { + GNOME_CALENDAR_VIEW_DAY = 0, + GNOME_CALENDAR_VIEW_WORK_WEEK = 1, + GNOME_CALENDAR_VIEW_WEEK = 2, + GNOME_CALENDAR_VIEW_MONTH = 3, + + GNOME_CALENDAR_VIEW_NOT_SET = 9 +} GnomeCalendarViewType; + + #define GNOME_CALENDAR(obj) GTK_CHECK_CAST(obj, gnome_calendar_get_type(), GnomeCalendar) #define GNOME_CALENDAR_CLASS(class) GTK_CHECK_CAST_CLASS(class, gnome_calendar_get_type(), GnomeCalendarClass) #define GNOME_IS_CALENDAR(obj) GTK_CHECK_TYPE(obj, gnome_calendar_get_type()) -#define GNOME_CALENDAR_NUM_VIEWS 4 - typedef struct { GtkVBox vbox; @@ -36,13 +45,17 @@ typedef struct { GHashTable *object_editor_hash; + /* This is the last selection explicitly selected by the user. We try + to keep it the same when we switch views, but we may have to alter + it depending on the view (e.g. the week views only select days, so + any times are lost. */ time_t selection_start_time; time_t selection_end_time; - GtkWidget *main_notebook; - GtkWidget *sub_notebook; GtkWidget *hpane; - GtkCalendar *gtk_calendar; + GtkWidget *notebook; + GtkWidget *vpane; + ECalendar *date_navigator; GtkWidget *todo; GtkWidget *day_view; @@ -50,13 +63,33 @@ typedef struct { GtkWidget *week_view; GtkWidget *month_view; - GtkWidget *view_toolbar_buttons[GNOME_CALENDAR_NUM_VIEWS]; + /* These are the toolbar radio buttons for switching views. */ + GtkWidget *day_button; + GtkWidget *work_week_button; + GtkWidget *week_button; + GtkWidget *month_button; + + /* This is the view currently shown. We use it to keep track of the + positions of the panes. range_selected is TRUE if a range of dates + was selected in the date navigator to show the view. */ + GnomeCalendarViewType current_view_type; + gboolean range_selected; + + /* These are the saved positions of the panes. They are multiples of + calendar month widths & heights in the date navigator, so that they + will work OK after theme changes. */ + gfloat hpane_pos; + gfloat vpane_pos; + gfloat hpane_pos_month_view; + gfloat vpane_pos_month_view; + + /* This is TRUE when we just want to set the state of the toolbar + radio buttons without causing any related code to be executed. + The "clicked" signal handlers just return when this is set. */ + gboolean ignore_view_button_clicks; void *event_editor; - /* The signal handler id for our GtkCalendar "day_selected" handler. */ - guint day_selected_id; - /* Alarm ID for the midnight refresh function */ gpointer midnight_alarm_refresh_id; @@ -91,11 +124,12 @@ void gnome_calendar_dayjump (GnomeCalendar *gcal, time_t time); /* Jumps to the current day */ void gnome_calendar_goto_today (GnomeCalendar *gcal); -void gnome_calendar_tag_calendar (GnomeCalendar *cal, - GtkCalendar *gtk_cal); +void gnome_calendar_tag_calendar (GnomeCalendar *gcal, + ECalendar *ecal); char *gnome_calendar_get_current_view_name (GnomeCalendar *gcal); -void gnome_calendar_set_view (GnomeCalendar *gcal, - char *page_name); +void gnome_calendar_set_view (GnomeCalendar *gcal, + char *page_name, + gboolean reset_range_shown); void gnome_calendar_set_selected_time_range (GnomeCalendar *gcal, time_t start_time, @@ -114,18 +148,23 @@ void gnome_calendar_get_current_time_range (GnomeCalendar *gcal, time_t *end_time); -/* Notifies the calendar that the time format has changed and it must update all its views */ -void gnome_calendar_time_format_changed (GnomeCalendar *gcal); +/* Notifies the calendar that the time format has changed and it must update + all its views */ +void gnome_calendar_time_format_changed (GnomeCalendar *gcal); -/* Notifies the calendar that the todo list properties have changed and its time - * to update the views. - */ -void gnome_calendar_colors_changed (GnomeCalendar *gcal); +/* Notifies the calendar that the todo list properties have changed and its + time to update the views. */ +void gnome_calendar_colors_changed (GnomeCalendar *gcal); -/* Notifies the calendar that the todo list properties have changed and its time - * to update the views. - */ -void gnome_calendar_todo_properties_changed (GnomeCalendar *gcal); +/* Notifies the calendar that the todo list properties have changed and its + time to update the views. */ +void gnome_calendar_todo_properties_changed (GnomeCalendar *gcal); + + +/* This makes the appropriate radio button in the toolbar active. + It sets the ignore_view_button_clicks flag so the "clicked" signal handlers + just return without doing anything. */ +void gnome_calendar_update_view_buttons (GnomeCalendar *gcal); |