From acdcd71d3074ebe3b3a758769eaa300dd50c3207 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 6 Mar 2013 15:24:08 -0500 Subject: EDayView cleanups. --- calendar/gui/e-day-view.c | 2411 ++++++++++++++++++++++----------------------- calendar/gui/e-day-view.h | 240 ++--- 2 files changed, 1325 insertions(+), 1326 deletions(-) (limited to 'calendar') diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index 6f2b53507c..980c8ed990 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -55,6 +55,10 @@ #include "misc.h" #include "print.h" +#define E_DAY_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_DAY_VIEW, EDayViewPrivate)) + /* The minimum amount of space wanted on each side of the date string. */ #define E_DAY_VIEW_DATE_X_PAD 4 @@ -90,6 +94,10 @@ * caption item and DnD space */ #define E_DAY_VIEW_MAX_ROWS_AT_TOP 6 +struct _EDayViewPrivate { + gint placeholder; +}; + typedef struct { EDayView *day_view; ECalModelComponent *comp_data; @@ -100,23 +108,8 @@ static GtkTargetEntry target_table[] = { { (gchar *) "application/x-e-calendar-event", 0, 0 } }; -static void e_day_view_dispose (GObject *object); -static void e_day_view_realize (GtkWidget *widget); static void e_day_view_set_colors (EDayView *day_view, GtkWidget *widget); -static void e_day_view_unrealize (GtkWidget *widget); -static void e_day_view_style_set (GtkWidget *widget, - GtkStyle *previous_style); -static void e_day_view_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); static gboolean e_day_view_update_scroll_regions (EDayView *day_view); -static gint e_day_view_focus_in (GtkWidget *widget, - GdkEventFocus *event); -static gint e_day_view_focus_out (GtkWidget *widget, - GdkEventFocus *event); -static gboolean e_day_view_key_press (GtkWidget *widget, - GdkEventKey *event); -static gboolean e_day_view_focus (GtkWidget *widget, - GtkDirectionType direction); static gboolean e_day_view_get_next_tab_event (EDayView *day_view, GtkDirectionType direction, gint *day, gint *event_num); @@ -132,12 +125,6 @@ static gboolean e_day_view_get_extreme_event (EDayView *day_view, gint *event_num_out); static gboolean e_day_view_do_key_press (GtkWidget *widget, GdkEventKey *event); -static gboolean e_day_view_popup_menu (GtkWidget *widget); -static GList *e_day_view_get_selected_events (ECalendarView *cal_view); -static gboolean e_day_view_get_selected_time_range (ECalendarView *cal_view, time_t *start_time, time_t *end_time); -static void e_day_view_set_selected_time_range (ECalendarView *cal_view, time_t start_time, time_t end_time); -static gboolean e_day_view_get_visible_time_range (ECalendarView *cal_view, time_t *start_time, time_t *end_time); -static void e_day_view_paste_text (ECalendarView *day_view); static void e_day_view_update_query (EDayView *day_view); static void e_day_view_goto_start_of_work_day (EDayView *day_view); static void e_day_view_goto_end_of_work_day (EDayView *day_view); @@ -468,6 +455,206 @@ day_view_notify_week_start_day_cb (EDayView *day_view) e_day_view_recalc_work_week (day_view); } +static void +e_day_view_recalc_main_canvas_size (EDayView *day_view) +{ + ECalModel *model; + gint work_day_start_hour; + gint work_day_start_minute; + gint day, scroll_y; + gboolean need_reshape; + + model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); + work_day_start_hour = e_cal_model_get_work_day_start_hour (model); + work_day_start_minute = e_cal_model_get_work_day_start_minute (model); + + /* Set the scroll region of the top canvas */ + e_day_view_update_top_scroll (day_view, TRUE); + + need_reshape = e_day_view_update_scroll_regions (day_view); + + e_day_view_recalc_cell_sizes (day_view); + + /* Scroll to the start of the working day, if this is the initial + * allocation. */ + if (day_view->scroll_to_work_day) { + scroll_y = e_day_view_convert_time_to_position ( + day_view, work_day_start_hour, work_day_start_minute); + gnome_canvas_scroll_to ( + GNOME_CANVAS (day_view->main_canvas), 0, scroll_y); + day_view->scroll_to_work_day = FALSE; + } + + /* Flag that we need to reshape the events. Note that changes in height + * don't matter, since the rows are always the same height. */ + if (need_reshape) { + day_view->long_events_need_reshape = TRUE; + for (day = 0; day < E_DAY_VIEW_MAX_DAYS; day++) + day_view->need_reshape[day] = TRUE; + + e_day_view_check_layout (day_view); + } +} + +static GdkColor +e_day_view_get_text_color (EDayView *day_view, + EDayViewEvent *event, + GtkWidget *widget) +{ + GtkStyle *style; + GdkColor bg_color; + guint16 red, green, blue; + gdouble cc = 65535.0; + + red = day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].red; + green = day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].green; + blue = day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].blue; + + if (is_comp_data_valid (event) && gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), event->comp_data), + &bg_color)) { + red = bg_color.red; + green = bg_color.green; + blue = bg_color.blue; + } + + style = gtk_widget_get_style (widget); + + if ((red / cc > 0.7) || (green / cc > 0.7) || (blue / cc > 0.7)) + return style->black; + else + return style->white; +} + +/* Returns the selected time range. */ +static gboolean +day_view_get_selected_time_range (ECalendarView *cal_view, + time_t *start_time, + time_t *end_time) +{ + gint start_col, start_row, end_col, end_row; + time_t start, end; + EDayView *day_view = E_DAY_VIEW (cal_view); + + start_col = day_view->selection_start_day; + start_row = day_view->selection_start_row; + end_col = day_view->selection_end_day; + end_row = day_view->selection_end_row; + + if (start_col == -1) { + start_col = 0; + start_row = 0; + end_col = 0; + end_row = 0; + } + + /* Check if the selection is only in the top canvas, in which case + * we can simply use the day_starts array. */ + if (day_view->selection_in_top_canvas) { + start = day_view->day_starts[start_col]; + end = day_view->day_starts[end_col + 1]; + } else { + /* Convert the start col + row into a time. */ + start = e_day_view_convert_grid_position_to_time (day_view, start_col, start_row); + end = e_day_view_convert_grid_position_to_time (day_view, end_col, end_row + 1); + } + + if (start_time) + *start_time = start; + + if (end_time) + *end_time = end; + + return TRUE; +} + +static gboolean +e_day_view_add_new_event_in_selected_range (EDayView *day_view, + GdkEventKey *key_event) +{ + icalcomponent *icalcomp; + ECalClient *client; + ECalModel *model; + ECalComponent *comp; + gint day, event_num; + time_t dtstart, dtend; + ECalComponentDateTime start_dt, end_dt; + struct icaltimetype start_tt, end_tt; + const gchar *uid; + AddEventData add_event_data; + ESourceRegistry *registry; + + model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); + + registry = e_cal_model_get_registry (model); + client = e_cal_model_get_default_client (model); + + /* Check if the client is read only */ + if (e_client_is_readonly (E_CLIENT (client))) + return FALSE; + + icalcomp = e_cal_model_create_component_with_defaults (model, day_view->selection_in_top_canvas); + if (!icalcomp) + return FALSE; + + uid = icalcomponent_get_uid (icalcomp); + + comp = e_cal_component_new (); + e_cal_component_set_icalcomponent (comp, icalcomp); + + day_view_get_selected_time_range ((ECalendarView *) day_view, &dtstart, &dtend); + + start_tt = icaltime_from_timet_with_zone ( + dtstart, FALSE, + e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); + + end_tt = icaltime_from_timet_with_zone ( + dtend, FALSE, + e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); + + if (day_view->selection_in_top_canvas) { + start_dt.tzid = NULL; + start_tt.is_date = 1; + end_tt.is_date = 1; + + /* Editor default in day/work-week view - top canvas */ + e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT); + } else { + start_dt.tzid = icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); + + /* Editor default in day/work-week view - main canvas */ + e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_OPAQUE); + } + + start_dt.value = &start_tt; + end_dt.value = &end_tt; + end_dt.tzid = start_dt.tzid; + e_cal_component_set_dtstart (comp, &start_dt); + e_cal_component_set_dtend (comp, &end_dt); + + e_cal_component_set_categories ( + comp, e_calendar_view_get_default_category (E_CALENDAR_VIEW (day_view))); + + /* We add the event locally and start editing it. We don't send it + * to the server until the user finishes editing it. */ + add_event_data.day_view = day_view; + add_event_data.comp_data = NULL; + e_day_view_add_event (registry, comp, dtstart, dtend, &add_event_data); + e_day_view_check_layout (day_view); + gtk_widget_queue_draw (day_view->top_canvas); + gtk_widget_queue_draw (day_view->main_canvas); + + if (!e_day_view_find_event_from_uid (day_view, client, uid, NULL, &day, &event_num)) { + g_warning ("Couldn't find event to start editing.\n"); + g_object_unref (comp); + return FALSE; + } + + e_day_view_start_editing_event (day_view, day, event_num, key_event); + + g_object_unref (comp); + return TRUE; +} + static void day_view_set_property (GObject *object, guint property_id, @@ -543,393 +730,759 @@ day_view_get_property (GObject *object, } static void -day_view_constructed (GObject *object) +day_view_dispose (GObject *object) { EDayView *day_view; - ECalModel *model; + gint day; day_view = E_DAY_VIEW (object); - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_day_view_parent_class)->constructed (object); - - model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); + e_day_view_cancel_layout (day_view); - g_signal_connect_swapped ( - day_view, "notify::time-divisions", - G_CALLBACK (day_view_notify_time_divisions_cb), day_view); + e_day_view_stop_auto_scroll (day_view); - g_signal_connect_swapped ( - model, "notify::week-start-day", - G_CALLBACK (day_view_notify_week_start_day_cb), day_view); + if (day_view->large_font_desc) { + pango_font_description_free (day_view->large_font_desc); + day_view->large_font_desc = NULL; + } - g_signal_connect_swapped ( - model, "notify::work-day-start-hour", - G_CALLBACK (gtk_widget_queue_draw), day_view->main_canvas); + if (day_view->small_font_desc) { + pango_font_description_free (day_view->small_font_desc); + day_view->small_font_desc = NULL; + } - g_signal_connect_swapped ( - model, "notify::work-day-start-minute", - G_CALLBACK (gtk_widget_queue_draw), day_view->main_canvas); + if (day_view->normal_cursor) { + g_object_unref (day_view->normal_cursor); + day_view->normal_cursor = NULL; + } + if (day_view->move_cursor) { + g_object_unref (day_view->move_cursor); + day_view->move_cursor = NULL; + } + if (day_view->resize_width_cursor) { + g_object_unref (day_view->resize_width_cursor); + day_view->resize_width_cursor = NULL; + } + if (day_view->resize_height_cursor) { + g_object_unref (day_view->resize_height_cursor); + day_view->resize_height_cursor = NULL; + } - g_signal_connect_swapped ( - model, "notify::work-day-end-hour", - G_CALLBACK (gtk_widget_queue_draw), day_view->main_canvas); + if (day_view->long_events) { + e_day_view_free_events (day_view); + g_array_free (day_view->long_events, TRUE); + day_view->long_events = NULL; + } - g_signal_connect_swapped ( - model, "notify::work-day-end-minute", - G_CALLBACK (gtk_widget_queue_draw), day_view->main_canvas); + for (day = 0; day < E_DAY_VIEW_MAX_DAYS; day++) { + if (day_view->events[day]) { + g_array_free (day_view->events[day], TRUE); + day_view->events[day] = NULL; + } + } + + if (day_view->grabbed_pointer != NULL) { + gdk_device_ungrab ( + day_view->grabbed_pointer, + GDK_CURRENT_TIME); + g_object_unref (day_view->grabbed_pointer); + day_view->grabbed_pointer = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_day_view_parent_class)->dispose (object); } static void -e_day_view_class_init (EDayViewClass *class) +day_view_constructed (GObject *object) { - GObjectClass *object_class; - GtkWidgetClass *widget_class; - ECalendarViewClass *view_class; + EDayView *day_view; + ECalModel *model; - object_class = G_OBJECT_CLASS (class); - object_class->set_property = day_view_set_property; - object_class->get_property = day_view_get_property; - object_class->constructed = day_view_constructed; - object_class->dispose = e_day_view_dispose; + day_view = E_DAY_VIEW (object); - widget_class = GTK_WIDGET_CLASS (class); - widget_class->realize = e_day_view_realize; - widget_class->unrealize = e_day_view_unrealize; - widget_class->style_set = e_day_view_style_set; - widget_class->size_allocate = e_day_view_size_allocate; - widget_class->focus_in_event = e_day_view_focus_in; - widget_class->focus_out_event = e_day_view_focus_out; - widget_class->key_press_event = e_day_view_key_press; - widget_class->focus = e_day_view_focus; - widget_class->popup_menu = e_day_view_popup_menu; + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_day_view_parent_class)->constructed (object); - view_class = E_CALENDAR_VIEW_CLASS (class); - view_class->get_selected_events = e_day_view_get_selected_events; - view_class->get_selected_time_range = e_day_view_get_selected_time_range; - view_class->set_selected_time_range = e_day_view_set_selected_time_range; - view_class->get_visible_time_range = e_day_view_get_visible_time_range; - view_class->paste_text = e_day_view_paste_text; + model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); - /* XXX Should these be constructor properties? */ + g_signal_connect_swapped ( + day_view, "notify::time-divisions", + G_CALLBACK (day_view_notify_time_divisions_cb), day_view); - g_object_class_install_property ( - object_class, - PROP_MARCUS_BAINS_SHOW_LINE, - g_param_spec_boolean ( - "marcus-bains-show-line", - "Marcus Bains Show Line", - NULL, - TRUE, - G_PARAM_READWRITE)); + g_signal_connect_swapped ( + model, "notify::week-start-day", + G_CALLBACK (day_view_notify_week_start_day_cb), day_view); - g_object_class_install_property ( - object_class, - PROP_MARCUS_BAINS_DAY_VIEW_COLOR, - g_param_spec_string ( - "marcus-bains-day-view-color", - "Marcus Bains Day View Color", - NULL, - NULL, - G_PARAM_READWRITE)); + g_signal_connect_swapped ( + model, "notify::work-day-start-hour", + G_CALLBACK (gtk_widget_queue_draw), day_view->main_canvas); - g_object_class_install_property ( - object_class, - PROP_MARCUS_BAINS_TIME_BAR_COLOR, - g_param_spec_string ( - "marcus-bains-time-bar-color", - "Marcus Bains Time Bar Color", - NULL, - NULL, - G_PARAM_READWRITE)); + g_signal_connect_swapped ( + model, "notify::work-day-start-minute", + G_CALLBACK (gtk_widget_queue_draw), day_view->main_canvas); - /* FIXME Make this a real GFlags type. */ - g_object_class_install_property ( - object_class, - PROP_WORKING_DAYS, - g_param_spec_int ( - "working-days", - "Working Days", - NULL, - 0x00, - 0x7f, - 0, - G_PARAM_READWRITE)); + g_signal_connect_swapped ( + model, "notify::work-day-end-hour", + G_CALLBACK (gtk_widget_queue_draw), day_view->main_canvas); - /* init the accessibility support for e_day_view */ - e_day_view_a11y_init (); + g_signal_connect_swapped ( + model, "notify::work-day-end-minute", + G_CALLBACK (gtk_widget_queue_draw), day_view->main_canvas); } static void -time_range_changed_cb (ECalModel *model, - time_t start_time, - time_t end_time, - gpointer user_data) +day_view_realize (GtkWidget *widget) { - EDayView *day_view = E_DAY_VIEW (user_data); - EDayViewTimeItem *eti; - time_t lower; - - g_return_if_fail (E_IS_DAY_VIEW (day_view)); - - /* Calculate the first day that should be shown, based on start_time - * and the days_shown setting. If we are showing 1 day it is just the - * start of the day given by start_time, otherwise it is the previous - * work-week start day. */ - if (!day_view->work_week_view) { - lower = time_day_begin_with_zone (start_time, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); - } else { - lower = e_day_view_find_work_week_start (day_view, start_time); - } - - /* See if we need to change the days shown. */ - if (lower != day_view->lower) - e_day_view_recalc_day_starts (day_view, lower); - - if (!E_CALENDAR_VIEW (day_view)->in_focus) { - e_day_view_free_events (day_view); - day_view->requires_update = TRUE; - return; - } - - /* If we don't show the new selection, don't preserve it */ - if (day_view->selection_start_day == -1 || day_view->days_shown <= day_view->selection_start_day) - e_day_view_set_selected_time_range (E_CALENDAR_VIEW (day_view), start_time, end_time); - - if (day_view->selection_start_row != -1) - e_day_view_ensure_rows_visible (day_view, day_view->selection_start_row, day_view->selection_start_row); - - /* update the time canvas to show proper date in it */ - eti = E_DAY_VIEW_TIME_ITEM (day_view->time_canvas_item); - if (eti && e_day_view_time_item_get_second_zone (eti)) - gtk_widget_queue_draw (day_view->time_canvas); -} + EDayView *day_view; -static void -process_component (EDayView *day_view, - ECalModelComponent *comp_data) -{ - const gchar *uid; - gchar *rid = NULL; - ECalModel *model; - ECalComponent *comp; - ESourceRegistry *registry; - AddEventData add_event_data; + if (GTK_WIDGET_CLASS (e_day_view_parent_class)->realize) + (*GTK_WIDGET_CLASS (e_day_view_parent_class)->realize)(widget); - model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); - registry = e_cal_model_get_registry (model); + day_view = E_DAY_VIEW (widget); - /* If our time hasn't been set yet, just return. */ - if (day_view->lower == 0 && day_view->upper == 0) - return; + /* Allocate the colors. */ - comp = e_cal_component_new (); - if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp))) { - g_object_unref (comp); + e_day_view_set_colors (day_view, widget); - g_message (G_STRLOC ": Could not set icalcomponent on ECalComponent"); - return; - } + /* Create the pixmaps. */ + day_view->reminder_icon = e_icon_factory_get_icon ("stock_bell", GTK_ICON_SIZE_MENU); + day_view->recurrence_icon = e_icon_factory_get_icon ("view-refresh", GTK_ICON_SIZE_MENU); + day_view->timezone_icon = e_icon_factory_get_icon ("stock_timezone", GTK_ICON_SIZE_MENU); + day_view->meeting_icon = e_icon_factory_get_icon ("stock_people", GTK_ICON_SIZE_MENU); + day_view->attach_icon = e_icon_factory_get_icon ("mail-attachment", GTK_ICON_SIZE_MENU); - e_cal_component_get_uid (comp, &uid); - if (e_cal_component_is_instance (comp)) - rid = e_cal_component_get_recurid_as_string (comp); - else - rid = NULL; - /* rid is never used below here, why? */ + /* Set the canvas item colors. */ + 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); - /* Add the object */ - add_event_data.day_view = day_view; - add_event_data.comp_data = comp_data; - e_day_view_add_event ( - registry, comp, comp_data->instance_start, - comp_data->instance_end, &add_event_data); + 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); - g_object_unref (comp); - g_free (rid); + 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); } static void -update_row (EDayView *day_view, - gint row) +day_view_unrealize (GtkWidget *widget) { - ECalModelComponent *comp_data; - ECalModel *model; - gint day, event_num; - const gchar *uid = NULL; - gchar *rid = NULL; - - e_day_view_stop_editing_event (day_view); - - model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); - comp_data = e_cal_model_get_component_at (model, row); - g_return_if_fail (comp_data != NULL); - - uid = icalcomponent_get_uid (comp_data->icalcomp); - if (e_cal_util_component_is_instance (comp_data->icalcomp)) { - icalproperty *prop; - - prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_RECURRENCEID_PROPERTY); - if (prop) - rid = icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (comp_data->icalcomp)); - } - - if (e_day_view_find_event_from_uid (day_view, comp_data->client, uid, rid, &day, &event_num)) - e_day_view_remove_event_cb (day_view, day, event_num, NULL); + EDayView *day_view; - g_free (rid); + day_view = E_DAY_VIEW (widget); - process_component (day_view, comp_data); + g_object_unref (day_view->reminder_icon); + day_view->reminder_icon = NULL; + g_object_unref (day_view->recurrence_icon); + day_view->recurrence_icon = NULL; + g_object_unref (day_view->timezone_icon); + day_view->timezone_icon = NULL; + g_object_unref (day_view->meeting_icon); + day_view->meeting_icon = NULL; + g_object_unref (day_view->attach_icon); + day_view->attach_icon = NULL; - gtk_widget_queue_draw (day_view->top_canvas); - gtk_widget_queue_draw (day_view->main_canvas); - e_day_view_queue_layout (day_view); + if (GTK_WIDGET_CLASS (e_day_view_parent_class)->unrealize) + (*GTK_WIDGET_CLASS (e_day_view_parent_class)->unrealize)(widget); } static void -model_row_changed_cb (ETableModel *etm, - gint row, - gpointer user_data) +day_view_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) { - EDayView *day_view = E_DAY_VIEW (user_data); - - if (!E_CALENDAR_VIEW (day_view)->in_focus) { - e_day_view_free_events (day_view); - day_view->requires_update = TRUE; - return; - } + (*GTK_WIDGET_CLASS (e_day_view_parent_class)->size_allocate) (widget, allocation); - update_row (day_view, row); + e_day_view_recalc_main_canvas_size (E_DAY_VIEW (widget)); } static void -model_cell_changed_cb (ETableModel *etm, - gint col, - gint row, - gpointer user_data) +day_view_style_set (GtkWidget *widget, + GtkStyle *previous_style) { - EDayView *day_view = E_DAY_VIEW (user_data); + EDayView *day_view; + gint hour; + gint minute, max_minute_width, i; + gint month, day, width; + gint longest_month_width, longest_abbreviated_month_width; + gint longest_weekday_width, longest_abbreviated_weekday_width; + gchar buffer[128]; + const gchar *name; + gint times_width; + PangoFontDescription *font_desc; + PangoContext *pango_context; + PangoFontMetrics *font_metrics; + PangoLayout *layout; + gint week_day, event_num; + GtkAdjustment *adjustment; + EDayViewEvent *event; + GdkColor color; - if (!E_CALENDAR_VIEW (day_view)->in_focus) { - e_day_view_free_events (day_view); - day_view->requires_update = TRUE; - return; + if (GTK_WIDGET_CLASS (e_day_view_parent_class)->style_set) + (*GTK_WIDGET_CLASS (e_day_view_parent_class)->style_set)(widget, previous_style); + + day_view = E_DAY_VIEW (widget); + e_day_view_set_colors (day_view, widget); + + for (week_day = 0; week_day < E_DAY_VIEW_MAX_DAYS; week_day++) { + for (event_num = 0; event_num < day_view->events[week_day]->len; event_num++) { + event = &g_array_index (day_view->events[week_day], EDayViewEvent, event_num); + if (event->canvas_item) { + color = e_day_view_get_text_color (day_view, event, widget); + gnome_canvas_item_set ( + event->canvas_item, + "fill_color_gdk", &color, + NULL); + } + } + } + for (event_num = 0; event_num < day_view->long_events->len; event_num++) { + event = &g_array_index (day_view->long_events, EDayViewEvent, event_num); + if (event->canvas_item) { + color = e_day_view_get_text_color (day_view, event, widget); + gnome_canvas_item_set ( + event->canvas_item, + "fill_color_gdk", &color, + NULL); + } } - update_row (day_view, row); + /* Set up Pango prerequisites */ + font_desc = gtk_widget_get_style (widget)->font_desc; + pango_context = gtk_widget_get_pango_context (widget); + font_metrics = pango_context_get_metrics ( + pango_context, font_desc, + pango_context_get_language (pango_context)); + layout = pango_layout_new (pango_context); + + /* Create the large font. */ + if (day_view->large_font_desc != NULL) + pango_font_description_free (day_view->large_font_desc); + + day_view->large_font_desc = pango_font_description_copy (font_desc); + pango_font_description_set_size ( + day_view->large_font_desc, + E_DAY_VIEW_LARGE_FONT_PTSIZE * PANGO_SCALE); + + /* Create the small fonts. */ + if (day_view->small_font_desc != NULL) + pango_font_description_free (day_view->small_font_desc); + + day_view->small_font_desc = pango_font_description_copy (font_desc); + pango_font_description_set_size ( + day_view->small_font_desc, + E_DAY_VIEW_SMALL_FONT_PTSIZE * PANGO_SCALE); + + /* Recalculate the height of each row based on the font size. */ + day_view->row_height = + PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) + + PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics)) + + E_DAY_VIEW_EVENT_BORDER_HEIGHT + E_DAY_VIEW_EVENT_Y_PAD * 2 + 2 /* FIXME */; + day_view->row_height = MAX ( + day_view->row_height, + E_DAY_VIEW_ICON_HEIGHT + E_DAY_VIEW_ICON_Y_PAD + 2); + + adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (day_view->main_canvas)); + gtk_adjustment_set_step_increment (adjustment, day_view->row_height); + + day_view->top_row_height = + PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) + + PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics)) + + E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT * 2 + E_DAY_VIEW_LONG_EVENT_Y_PAD * 2 + + E_DAY_VIEW_TOP_CANVAS_Y_GAP; + day_view->top_row_height = + MAX ( + day_view->top_row_height, + E_DAY_VIEW_ICON_HEIGHT + E_DAY_VIEW_ICON_Y_PAD + 2 + + E_DAY_VIEW_TOP_CANVAS_Y_GAP); + + adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (day_view->top_canvas)); + gtk_adjustment_set_step_increment (adjustment, day_view->top_row_height); + gtk_widget_set_size_request (day_view->top_dates_canvas, -1, day_view->top_row_height - 2); + + e_day_view_update_top_scroll (day_view, TRUE); + + /* Find the longest full & abbreviated month names. */ + longest_month_width = 0; + longest_abbreviated_month_width = 0; + for (month = 0; month < 12; month++) { + name = e_get_month_name (month + 1, FALSE); + pango_layout_set_text (layout, name, -1); + pango_layout_get_pixel_size (layout, &width, NULL); + + if (width > longest_month_width) { + longest_month_width = width; + day_view->longest_month_name = month; + } + + name = e_get_month_name (month + 1, TRUE); + pango_layout_set_text (layout, name, -1); + pango_layout_get_pixel_size (layout, &width, NULL); + + if (width > longest_abbreviated_month_width) { + longest_abbreviated_month_width = width; + day_view->longest_abbreviated_month_name = month; + } + } + + /* Find the longest full & abbreviated weekday names. */ + longest_weekday_width = 0; + longest_abbreviated_weekday_width = 0; + for (day = 0; day < 7; day++) { + name = e_get_weekday_name (day + 1, FALSE); + pango_layout_set_text (layout, name, -1); + pango_layout_get_pixel_size (layout, &width, NULL); + + if (width > longest_weekday_width) { + longest_weekday_width = width; + day_view->longest_weekday_name = day; + } + + name = e_get_weekday_name (day + 1, TRUE); + pango_layout_set_text (layout, name, -1); + pango_layout_get_pixel_size (layout, &width, NULL); + + if (width > longest_abbreviated_weekday_width) { + longest_abbreviated_weekday_width = width; + day_view->longest_abbreviated_weekday_name = day; + } + } + + /* Calculate the widths of all the time strings necessary. */ + day_view->max_small_hour_width = 0; + for (hour = 0; hour < 24; hour++) { + g_snprintf (buffer, sizeof (buffer), "%02i", hour); + pango_layout_set_text (layout, buffer, -1); + pango_layout_get_pixel_size (layout, &day_view->small_hour_widths[hour], NULL); + + day_view->max_small_hour_width = MAX (day_view->max_small_hour_width, day_view->small_hour_widths[hour]); + } + + max_minute_width = 0; + for (minute = 0, i = 0; minute < 60; minute += 5, i++) { + gint minute_width; + + g_snprintf (buffer, sizeof (buffer), "%02i", minute); + pango_layout_set_text (layout, buffer, -1); + pango_layout_get_pixel_size (layout, &minute_width, NULL); + + max_minute_width = MAX (max_minute_width, minute_width); + } + day_view->max_minute_width = max_minute_width; + + pango_layout_set_text (layout, ":", 1); + pango_layout_get_pixel_size (layout, &day_view->colon_width, NULL); + pango_layout_set_text (layout, "0", 1); + pango_layout_get_pixel_size (layout, &day_view->digit_width, NULL); + + pango_layout_set_text (layout, day_view->am_string, -1); + pango_layout_get_pixel_size (layout, &day_view->am_string_width, NULL); + pango_layout_set_text (layout, day_view->pm_string, -1); + pango_layout_get_pixel_size (layout, &day_view->pm_string_width, NULL); + + /* Calculate the width of the time column. */ + times_width = e_day_view_time_item_get_column_width (E_DAY_VIEW_TIME_ITEM (day_view->time_canvas_item)); + gtk_widget_set_size_request (day_view->time_canvas, times_width, -1); + + g_object_unref (layout); + pango_font_metrics_unref (font_metrics); } -static void -model_rows_inserted_cb (ETableModel *etm, - gint row, - gint count, - gpointer user_data) +static gboolean +day_view_focus (GtkWidget *widget, + GtkDirectionType direction) { - EDayView *day_view = E_DAY_VIEW (user_data); - ECalModel *model; - gint i; + EDayView *day_view; + gint new_day; + gint new_event_num; + gint start_row, end_row; - if (!E_CALENDAR_VIEW (day_view)->in_focus) { - e_day_view_free_events (day_view); - day_view->requires_update = TRUE; - return; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_DAY_VIEW (widget), FALSE); + day_view = E_DAY_VIEW (widget); + + if (!e_day_view_get_next_tab_event (day_view, direction, + &new_day, &new_event_num)) + return FALSE; + + if ((new_day == -1) && (new_event_num == -1)) { + /* focus should go to the day view widget itself + */ + gtk_widget_grab_focus (GTK_WIDGET (day_view)); + return TRUE; } - e_day_view_stop_editing_event (day_view); + if (new_day != E_DAY_VIEW_LONG_EVENT && new_day != -1) { + if (e_day_view_get_event_rows (day_view, new_day, + new_event_num, + &start_row, &end_row)) + /* ensure the event to be seen */ + e_day_view_ensure_rows_visible ( + day_view, + start_row, end_row); + } + e_day_view_start_editing_event ( + day_view, new_day, + new_event_num, NULL); - model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); - for (i = 0; i < count; i++) { - ECalModelComponent *comp_data; + return TRUE; +} - comp_data = e_cal_model_get_component_at (model, row + i); - if (comp_data == NULL) { - g_warning ("comp_data is NULL\n"); - continue; +static gboolean +day_view_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + gboolean handled = FALSE; + handled = e_day_view_do_key_press (widget, event); + + /* if not handled, try key bindings */ + if (!handled) + handled = GTK_WIDGET_CLASS (e_day_view_parent_class)->key_press_event (widget, event); + return handled; +} + +static gint +day_view_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + EDayView *day_view; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_DAY_VIEW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + day_view = E_DAY_VIEW (widget); + + /* XXX Can't access flags directly anymore, but is it really needed? + * If so, could we call gtk_widget_send_focus_change() instead? */ +#if 0 + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); +#endif + + if (E_CALENDAR_VIEW (day_view)->in_focus && day_view->requires_update) { + time_t my_start = 0, my_end = 0, model_start = 0, model_end = 0; + + day_view->requires_update = FALSE; + + e_cal_model_get_time_range (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), &model_start, &model_end); + + if (e_calendar_view_get_visible_time_range (E_CALENDAR_VIEW (day_view), &my_start, &my_end) && + model_start == my_start && model_end == my_end) { + /* update only when the same time range is set in a view and in a model; + * otherwise time range change invokes also query update */ + e_day_view_recalc_day_starts (day_view, day_view->lower); + e_day_view_update_query (day_view); } - process_component (day_view, comp_data); } gtk_widget_queue_draw (day_view->top_canvas); gtk_widget_queue_draw (day_view->main_canvas); - e_day_view_queue_layout (day_view); + return FALSE; +} + +static gint +day_view_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + EDayView *day_view; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (E_IS_DAY_VIEW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + day_view = E_DAY_VIEW (widget); + + /* XXX Can't access flags directly anymore, but is it really needed? + * If so, could we call gtk_widget_send_focus_change() instead? */ +#if 0 + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); +#endif + + gtk_widget_queue_draw (day_view->top_canvas); + gtk_widget_queue_draw (day_view->main_canvas); + + return FALSE; +} + +static gboolean +day_view_popup_menu (GtkWidget *widget) +{ + EDayView *day_view = E_DAY_VIEW (widget); + e_day_view_show_popup_menu ( + day_view, NULL, + day_view->editing_event_day, + day_view->editing_event_num); + return TRUE; +} + +/* Returns the currently-selected event, or NULL if none */ +static GList * +day_view_get_selected_events (ECalendarView *cal_view) +{ + EDayViewEvent *event = NULL; + GList *list = NULL; + EDayView *day_view = (EDayView *) cal_view; + + g_return_val_if_fail (E_IS_DAY_VIEW (day_view), NULL); + + if (day_view->editing_event_num != -1) { + if (day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT) { + if (!is_array_index_in_bounds (day_view->long_events, day_view->editing_event_num)) + return NULL; + + event = &g_array_index (day_view->long_events, + EDayViewEvent, + day_view->editing_event_num); + } else { + if (!is_array_index_in_bounds (day_view->events[day_view->editing_event_day], day_view->editing_event_num)) + return NULL; + + event = &g_array_index (day_view->events[day_view->editing_event_day], + EDayViewEvent, + day_view->editing_event_num); + } + } else if (day_view->popup_event_num != -1) { + if (day_view->popup_event_day == E_DAY_VIEW_LONG_EVENT) { + if (!is_array_index_in_bounds (day_view->long_events, day_view->popup_event_num)) + return NULL; + + event = &g_array_index (day_view->long_events, + EDayViewEvent, + day_view->popup_event_num); + } else { + if (!is_array_index_in_bounds (day_view->events[day_view->popup_event_day], day_view->popup_event_num)) + return NULL; + + event = &g_array_index (day_view->events[day_view->popup_event_day], + EDayViewEvent, + day_view->popup_event_num); + } + } + + if (event) + list = g_list_append (list, event); + + return list; } +/* This sets the selected time range. If the start_time & end_time are not equal + * and are both visible in the view, then the selection is set to those times, + * otherwise it is set to 1 hour from the start of the working day. */ static void -model_comps_deleted_cb (ETableModel *etm, - gpointer data, - gpointer user_data) +day_view_set_selected_time_range (ECalendarView *cal_view, + time_t start_time, + time_t end_time) { - EDayView *day_view = E_DAY_VIEW (user_data); - GSList *l, *list = data; + ECalModel *model; + EDayView *day_view; + gint work_day_start_hour; + gint work_day_start_minute; + gint start_row, start_col, end_row, end_col; + gboolean need_redraw = FALSE, start_in_grid, end_in_grid; - if (!E_CALENDAR_VIEW (day_view)->in_focus) { - e_day_view_free_events (day_view); - day_view->requires_update = TRUE; - return; + day_view = E_DAY_VIEW (cal_view); + model = e_calendar_view_get_model (cal_view); + work_day_start_hour = e_cal_model_get_work_day_start_hour (model); + work_day_start_minute = e_cal_model_get_work_day_start_minute (model); + + if (start_time == end_time) + end_time += e_calendar_view_get_time_divisions (cal_view) * 60; + + /* Set the selection. */ + start_in_grid = e_day_view_convert_time_to_grid_position ( + day_view, + start_time, + &start_col, + &start_row); + end_in_grid = e_day_view_convert_time_to_grid_position ( + day_view, + end_time - 60, + &end_col, + &end_row); + + /* If either of the times isn't in the grid, or the selection covers + * an entire day, we set the selection to 1 row from the start of the + * working day, in the day corresponding to the start time. */ + if (!start_in_grid || !end_in_grid + || (start_row == 0 && end_row == day_view->rows - 1)) { + end_col = start_col; + + start_row = e_day_view_convert_time_to_row ( + day_view, work_day_start_hour, work_day_start_minute); + start_row = CLAMP (start_row, 0, day_view->rows - 1); + end_row = start_row; } - e_day_view_stop_editing_event (day_view); + if (start_row != day_view->selection_start_row + || start_col != day_view->selection_start_day) { + need_redraw = TRUE; + day_view->selection_in_top_canvas = FALSE; + day_view->selection_start_row = start_row; + day_view->selection_start_day = start_col; + } - for (l = list; l != NULL; l = g_slist_next (l)) { - ECalModelComponent *comp_data = l->data; - gint day, event_num; - const gchar *uid = NULL; - gchar *rid = NULL; + if (end_row != day_view->selection_end_row + || end_col != day_view->selection_end_day) { + need_redraw = TRUE; + day_view->selection_in_top_canvas = FALSE; + day_view->selection_end_row = end_row; + day_view->selection_end_day = end_col; + } - uid = icalcomponent_get_uid (comp_data->icalcomp); - if (e_cal_util_component_is_instance (comp_data->icalcomp)) { - icalproperty *prop; + if (need_redraw) { + gtk_widget_queue_draw (day_view->top_canvas); + gtk_widget_queue_draw (day_view->top_dates_canvas); + gtk_widget_queue_draw (day_view->main_canvas); + } +} - prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_RECURRENCEID_PROPERTY); - if (prop) - rid = icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (comp_data->icalcomp)); - } +/* Gets the visible time range. Returns FALSE if no time range has been set. */ +static gboolean +day_view_get_visible_time_range (ECalendarView *cal_view, + time_t *start_time, + time_t *end_time) +{ + EDayView *day_view = E_DAY_VIEW (cal_view); + + /* If the date isn't set, return FALSE. */ + if (day_view->lower == 0 && day_view->upper == 0) + return FALSE; + + *start_time = day_view->day_starts[0]; + *end_time = day_view->day_starts[day_view->days_shown]; + + return TRUE; +} + +static void +day_view_paste_text (ECalendarView *cal_view) +{ + EDayView *day_view; + EDayViewEvent *event; + + g_return_if_fail (E_IS_DAY_VIEW (cal_view)); + + day_view = E_DAY_VIEW (cal_view); + + if (day_view->editing_event_num == -1 && + !e_day_view_add_new_event_in_selected_range (day_view, NULL)) + return; + + if (day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT) { + if (!is_array_index_in_bounds (day_view->long_events, day_view->editing_event_num)) + return; - if (e_day_view_find_event_from_uid (day_view, comp_data->client, uid, rid, &day, &event_num)) - e_day_view_remove_event_cb (day_view, day, event_num, NULL); + event = &g_array_index (day_view->long_events, + EDayViewEvent, + day_view->editing_event_num); + } else { + if (!is_array_index_in_bounds (day_view->events[day_view->editing_event_day], day_view->editing_event_num)) + return; - g_free (rid); + event = &g_array_index (day_view->events[day_view->editing_event_day], + EDayViewEvent, + day_view->editing_event_num); } - gtk_widget_queue_draw (day_view->top_canvas); - gtk_widget_queue_draw (day_view->main_canvas); - e_day_view_queue_layout (day_view); + if (event->canvas_item && + E_IS_TEXT (event->canvas_item) && + E_TEXT (event->canvas_item)->editing) { + e_text_paste_clipboard (E_TEXT (event->canvas_item)); + } } static void -timezone_changed_cb (ECalModel *cal_model, - icaltimezone *old_zone, - icaltimezone *new_zone, - gpointer user_data) +e_day_view_class_init (EDayViewClass *class) { - struct icaltimetype tt; - time_t lower; - EDayView *day_view = (EDayView *) user_data; - ECalendarView *cal_view = (ECalendarView *) day_view; + GObjectClass *object_class; + GtkWidgetClass *widget_class; + ECalendarViewClass *view_class; - g_return_if_fail (E_IS_DAY_VIEW (day_view)); + g_type_class_add_private (class, sizeof (EDayViewPrivate)); - if (!cal_view->in_focus) { - e_day_view_free_events (day_view); - day_view->requires_update = TRUE; - return; - } + object_class = G_OBJECT_CLASS (class); + object_class->set_property = day_view_set_property; + object_class->get_property = day_view_get_property; + object_class->constructed = day_view_constructed; + object_class->dispose = day_view_dispose; - /* If our time hasn't been set yet, just return. */ - if (day_view->lower == 0 && day_view->upper == 0) - return; + widget_class = GTK_WIDGET_CLASS (class); + widget_class->realize = day_view_realize; + widget_class->unrealize = day_view_unrealize; + widget_class->size_allocate = day_view_size_allocate; + widget_class->style_set = day_view_style_set; + widget_class->focus = day_view_focus; + widget_class->key_press_event = day_view_key_press; + widget_class->focus_in_event = day_view_focus_in; + widget_class->focus_out_event = day_view_focus_out; + widget_class->popup_menu = day_view_popup_menu; - /* Recalculate the new start of the first day. We just use exactly - * the same time, but with the new timezone. */ - tt = icaltime_from_timet_with_zone ( - day_view->lower, FALSE, - old_zone); + view_class = E_CALENDAR_VIEW_CLASS (class); + view_class->get_selected_events = day_view_get_selected_events; + view_class->get_selected_time_range = day_view_get_selected_time_range; + view_class->set_selected_time_range = day_view_set_selected_time_range; + view_class->get_visible_time_range = day_view_get_visible_time_range; + view_class->paste_text = day_view_paste_text; - lower = icaltime_as_timet_with_zone (tt, new_zone); + /* XXX Should these be constructor properties? */ - e_day_view_recalc_day_starts (day_view, lower); - e_day_view_update_query (day_view); + g_object_class_install_property ( + object_class, + PROP_MARCUS_BAINS_SHOW_LINE, + g_param_spec_boolean ( + "marcus-bains-show-line", + "Marcus Bains Show Line", + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_MARCUS_BAINS_DAY_VIEW_COLOR, + g_param_spec_string ( + "marcus-bains-day-view-color", + "Marcus Bains Day View Color", + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_MARCUS_BAINS_TIME_BAR_COLOR, + g_param_spec_string ( + "marcus-bains-time-bar-color", + "Marcus Bains Time Bar Color", + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /* FIXME Make this a real GFlags type. */ + g_object_class_install_property ( + object_class, + PROP_WORKING_DAYS, + g_param_spec_int ( + "working-days", + "Working Days", + NULL, + 0x00, + 0x7f, + 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /* init the accessibility support for e_day_view */ + e_day_view_a11y_init (); } static void @@ -941,6 +1494,8 @@ e_day_view_init (EDayView *day_view) GtkScrollable *scrollable; GtkWidget *w; + day_view->priv = E_DAY_VIEW_GET_PRIVATE (day_view); + gtk_widget_set_can_focus (GTK_WIDGET (day_view), TRUE); day_view->long_events = g_array_new ( @@ -1286,529 +1841,402 @@ e_day_view_init (EDayView *day_view) } static void -init_model (EDayView *day_view, - ECalModel *model) -{ - /* connect to ECalModel's signals */ - g_signal_connect ( - model, "time_range_changed", - G_CALLBACK (time_range_changed_cb), day_view); - g_signal_connect ( - model, "model_row_changed", - G_CALLBACK (model_row_changed_cb), day_view); - g_signal_connect ( - model, "model_cell_changed", - G_CALLBACK (model_cell_changed_cb), day_view); - g_signal_connect ( - model, "model_rows_inserted", - G_CALLBACK (model_rows_inserted_cb), day_view); - g_signal_connect ( - model, "comps_deleted", - G_CALLBACK (model_comps_deleted_cb), day_view); - g_signal_connect ( - model, "timezone_changed", - G_CALLBACK (timezone_changed_cb), day_view); -} - -/* Turn off the background of the canvas windows. This reduces flicker - * considerably when scrolling. (Why isn't it in GnomeCanvas?). */ -static void -e_day_view_on_canvas_realized (GtkWidget *widget, - EDayView *day_view) -{ - GdkWindow *window; - - window = gtk_layout_get_bin_window (GTK_LAYOUT (widget)); - gdk_window_set_background_pattern (window, NULL); -} - -/** - * e_day_view_new: - * @Returns: a new #EDayView. - * - * Creates a new #EDayView. - **/ -ECalendarView * -e_day_view_new (ECalModel *model) -{ - ECalendarView *day_view; - - g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); - - day_view = g_object_new (E_TYPE_DAY_VIEW, "model", model, NULL); - init_model (E_DAY_VIEW (day_view), model); - - return day_view; -} - -static void -e_day_view_dispose (GObject *object) +time_range_changed_cb (ECalModel *model, + time_t start_time, + time_t end_time, + gpointer user_data) { - EDayView *day_view; - gint day; - - day_view = E_DAY_VIEW (object); - - e_day_view_cancel_layout (day_view); - - e_day_view_stop_auto_scroll (day_view); - - if (day_view->large_font_desc) { - pango_font_description_free (day_view->large_font_desc); - day_view->large_font_desc = NULL; - } - - if (day_view->small_font_desc) { - pango_font_description_free (day_view->small_font_desc); - day_view->small_font_desc = NULL; - } - - if (day_view->normal_cursor) { - g_object_unref (day_view->normal_cursor); - day_view->normal_cursor = NULL; - } - if (day_view->move_cursor) { - g_object_unref (day_view->move_cursor); - day_view->move_cursor = NULL; - } - if (day_view->resize_width_cursor) { - g_object_unref (day_view->resize_width_cursor); - day_view->resize_width_cursor = NULL; - } - if (day_view->resize_height_cursor) { - g_object_unref (day_view->resize_height_cursor); - day_view->resize_height_cursor = NULL; - } - - if (day_view->long_events) { - e_day_view_free_events (day_view); - g_array_free (day_view->long_events, TRUE); - day_view->long_events = NULL; - } + EDayView *day_view = E_DAY_VIEW (user_data); + EDayViewTimeItem *eti; + time_t lower; - for (day = 0; day < E_DAY_VIEW_MAX_DAYS; day++) { - if (day_view->events[day]) { - g_array_free (day_view->events[day], TRUE); - day_view->events[day] = NULL; - } - } + g_return_if_fail (E_IS_DAY_VIEW (day_view)); - if (day_view->grabbed_pointer != NULL) { - gdk_device_ungrab ( - day_view->grabbed_pointer, - GDK_CURRENT_TIME); - g_object_unref (day_view->grabbed_pointer); - day_view->grabbed_pointer = NULL; + /* Calculate the first day that should be shown, based on start_time + * and the days_shown setting. If we are showing 1 day it is just the + * start of the day given by start_time, otherwise it is the previous + * work-week start day. */ + if (!day_view->work_week_view) { + lower = time_day_begin_with_zone (start_time, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); + } else { + lower = e_day_view_find_work_week_start (day_view, start_time); } - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_day_view_parent_class)->dispose (object); -} - -static void -e_day_view_realize (GtkWidget *widget) -{ - EDayView *day_view; - - if (GTK_WIDGET_CLASS (e_day_view_parent_class)->realize) - (*GTK_WIDGET_CLASS (e_day_view_parent_class)->realize)(widget); - - day_view = E_DAY_VIEW (widget); - - /* Allocate the colors. */ - - e_day_view_set_colors (day_view, widget); - - /* Create the pixmaps. */ - day_view->reminder_icon = e_icon_factory_get_icon ("stock_bell", GTK_ICON_SIZE_MENU); - day_view->recurrence_icon = e_icon_factory_get_icon ("view-refresh", GTK_ICON_SIZE_MENU); - day_view->timezone_icon = e_icon_factory_get_icon ("stock_timezone", GTK_ICON_SIZE_MENU); - day_view->meeting_icon = e_icon_factory_get_icon ("stock_people", GTK_ICON_SIZE_MENU); - day_view->attach_icon = e_icon_factory_get_icon ("mail-attachment", GTK_ICON_SIZE_MENU); + /* See if we need to change the days shown. */ + if (lower != day_view->lower) + e_day_view_recalc_day_starts (day_view, lower); - /* Set the canvas item colors. */ - 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); + if (!E_CALENDAR_VIEW (day_view)->in_focus) { + e_day_view_free_events (day_view); + day_view->requires_update = TRUE; + return; + } - 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); + /* If we don't show the new selection, don't preserve it */ + if (day_view->selection_start_day == -1 || day_view->days_shown <= day_view->selection_start_day) + day_view_set_selected_time_range (E_CALENDAR_VIEW (day_view), start_time, end_time); - 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); + if (day_view->selection_start_row != -1) + e_day_view_ensure_rows_visible (day_view, day_view->selection_start_row, day_view->selection_start_row); + + /* update the time canvas to show proper date in it */ + eti = E_DAY_VIEW_TIME_ITEM (day_view->time_canvas_item); + if (eti && e_day_view_time_item_get_second_zone (eti)) + gtk_widget_queue_draw (day_view->time_canvas); } static void -e_day_view_set_colors (EDayView *day_view, - GtkWidget *widget) +process_component (EDayView *day_view, + ECalModelComponent *comp_data) { - GtkStyle *style; + const gchar *uid; + gchar *rid = NULL; + ECalModel *model; + ECalComponent *comp; + ESourceRegistry *registry; + AddEventData add_event_data; - style = gtk_widget_get_style (widget); + model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); + registry = e_cal_model_get_registry (model); - day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING] = style->base[GTK_STATE_NORMAL]; - day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING] = style->bg[GTK_STATE_ACTIVE]; - day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED] = style->base[GTK_STATE_SELECTED]; - day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED] = style->bg[GTK_STATE_SELECTED]; - day_view->colors[E_DAY_VIEW_COLOR_BG_GRID] = style->dark[GTK_STATE_NORMAL]; - day_view->colors[E_DAY_VIEW_COLOR_BG_MULTIDAY_TODAY] = get_today_background (day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING]); - day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS] = style->dark[GTK_STATE_NORMAL]; - day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED] = style->bg[GTK_STATE_SELECTED]; - day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID] = style->light[GTK_STATE_NORMAL]; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR] = style->base[GTK_STATE_SELECTED]; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND] = style->base[GTK_STATE_NORMAL]; - day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER] = style->dark[GTK_STATE_NORMAL]; - day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND] = style->bg[GTK_STATE_ACTIVE]; - day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER] = style->dark[GTK_STATE_NORMAL]; - day_view->colors[E_DAY_VIEW_COLOR_MARCUS_BAINS_LINE] = style->dark[GTK_STATE_PRELIGHT]; -} + /* If our time hasn't been set yet, just return. */ + if (day_view->lower == 0 && day_view->upper == 0) + return; -static void -e_day_view_unrealize (GtkWidget *widget) -{ - EDayView *day_view; + comp = e_cal_component_new (); + if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp))) { + g_object_unref (comp); - day_view = E_DAY_VIEW (widget); + g_message (G_STRLOC ": Could not set icalcomponent on ECalComponent"); + return; + } - g_object_unref (day_view->reminder_icon); - day_view->reminder_icon = NULL; - g_object_unref (day_view->recurrence_icon); - day_view->recurrence_icon = NULL; - g_object_unref (day_view->timezone_icon); - day_view->timezone_icon = NULL; - g_object_unref (day_view->meeting_icon); - day_view->meeting_icon = NULL; - g_object_unref (day_view->attach_icon); - day_view->attach_icon = NULL; + e_cal_component_get_uid (comp, &uid); + if (e_cal_component_is_instance (comp)) + rid = e_cal_component_get_recurid_as_string (comp); + else + rid = NULL; + /* rid is never used below here, why? */ - if (GTK_WIDGET_CLASS (e_day_view_parent_class)->unrealize) - (*GTK_WIDGET_CLASS (e_day_view_parent_class)->unrealize)(widget); + /* Add the object */ + add_event_data.day_view = day_view; + add_event_data.comp_data = comp_data; + e_day_view_add_event ( + registry, comp, comp_data->instance_start, + comp_data->instance_end, &add_event_data); + + g_object_unref (comp); + g_free (rid); } -static GdkColor -e_day_view_get_text_color (EDayView *day_view, - EDayViewEvent *event, - GtkWidget *widget) +static void +update_row (EDayView *day_view, + gint row) { - GtkStyle *style; - GdkColor bg_color; - guint16 red, green, blue; - gdouble cc = 65535.0; + ECalModelComponent *comp_data; + ECalModel *model; + gint day, event_num; + const gchar *uid = NULL; + gchar *rid = NULL; - red = day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].red; - green = day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].green; - blue = day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND].blue; + e_day_view_stop_editing_event (day_view); - if (is_comp_data_valid (event) && gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), event->comp_data), - &bg_color)) { - red = bg_color.red; - green = bg_color.green; - blue = bg_color.blue; + model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); + comp_data = e_cal_model_get_component_at (model, row); + g_return_if_fail (comp_data != NULL); + + uid = icalcomponent_get_uid (comp_data->icalcomp); + if (e_cal_util_component_is_instance (comp_data->icalcomp)) { + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_RECURRENCEID_PROPERTY); + if (prop) + rid = icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (comp_data->icalcomp)); } - style = gtk_widget_get_style (widget); + if (e_day_view_find_event_from_uid (day_view, comp_data->client, uid, rid, &day, &event_num)) + e_day_view_remove_event_cb (day_view, day, event_num, NULL); - if ((red / cc > 0.7) || (green / cc > 0.7) || (blue / cc > 0.7)) - return style->black; - else - return style->white; + g_free (rid); + + process_component (day_view, comp_data); + + gtk_widget_queue_draw (day_view->top_canvas); + gtk_widget_queue_draw (day_view->main_canvas); + e_day_view_queue_layout (day_view); } static void -e_day_view_update_top_scroll (EDayView *day_view, - gboolean scroll_to_top) +model_row_changed_cb (ETableModel *etm, + gint row, + gpointer user_data) { - GtkAllocation allocation; - gint top_rows, top_canvas_height; - gdouble old_x2, old_y2, new_x2, new_y2; + EDayView *day_view = E_DAY_VIEW (user_data); - /* Set the height of the top canvas based on the row height and the - * number of rows needed (min 1 + 1 for the dates + 1 space for DnD).*/ - top_rows = MAX (1, day_view->rows_in_top_display); - top_canvas_height = (top_rows + 1) * day_view->top_row_height; - if (top_rows <= E_DAY_VIEW_MAX_ROWS_AT_TOP) { - gtk_widget_set_size_request (day_view->top_canvas, -1, top_canvas_height); - gtk_widget_hide (day_view->tc_vscrollbar); - } else { - gtk_widget_set_size_request (day_view->top_canvas, -1, (E_DAY_VIEW_MAX_ROWS_AT_TOP + 1) * day_view->top_row_height); - gtk_widget_show (day_view->tc_vscrollbar); + if (!E_CALENDAR_VIEW (day_view)->in_focus) { + e_day_view_free_events (day_view); + day_view->requires_update = TRUE; + return; } - /* Set the scroll region of the top canvas */ - gnome_canvas_get_scroll_region ( - GNOME_CANVAS (day_view->top_canvas), - NULL, NULL, &old_x2, &old_y2); - gtk_widget_get_allocation (day_view->top_canvas, &allocation); - new_x2 = allocation.width - 1; - new_y2 = (MAX (1, day_view->rows_in_top_display) + 1) * day_view->top_row_height - 1; - if (old_x2 != new_x2 || old_y2 != new_y2) { - gnome_canvas_set_scroll_region ( - GNOME_CANVAS (day_view->top_canvas), - 0, 0, new_x2, new_y2); + update_row (day_view, row); +} - if (scroll_to_top) - gnome_canvas_scroll_to (GNOME_CANVAS (day_view->top_canvas), 0, 0); - } - new_y2 = day_view->top_row_height - 1 - 2; - gnome_canvas_get_scroll_region (GNOME_CANVAS (day_view->top_dates_canvas), NULL, NULL, &old_x2, &old_y2); +static void +model_cell_changed_cb (ETableModel *etm, + gint col, + gint row, + gpointer user_data) +{ + EDayView *day_view = E_DAY_VIEW (user_data); - if (old_x2 != new_x2 || old_y2 != new_y2) { - gnome_canvas_set_scroll_region (GNOME_CANVAS (day_view->top_dates_canvas), 0, 0, new_x2, new_y2); - gnome_canvas_scroll_to (GNOME_CANVAS (day_view->top_dates_canvas), 0, 0); + if (!E_CALENDAR_VIEW (day_view)->in_focus) { + e_day_view_free_events (day_view); + day_view->requires_update = TRUE; + return; } + + update_row (day_view, row); } static void -e_day_view_style_set (GtkWidget *widget, - GtkStyle *previous_style) +model_rows_inserted_cb (ETableModel *etm, + gint row, + gint count, + gpointer user_data) { - EDayView *day_view; - gint hour; - gint minute, max_minute_width, i; - gint month, day, width; - gint longest_month_width, longest_abbreviated_month_width; - gint longest_weekday_width, longest_abbreviated_weekday_width; - gchar buffer[128]; - const gchar *name; - gint times_width; - PangoFontDescription *font_desc; - PangoContext *pango_context; - PangoFontMetrics *font_metrics; - PangoLayout *layout; - gint week_day, event_num; - GtkAdjustment *adjustment; - EDayViewEvent *event; - GdkColor color; + EDayView *day_view = E_DAY_VIEW (user_data); + ECalModel *model; + gint i; - if (GTK_WIDGET_CLASS (e_day_view_parent_class)->style_set) - (*GTK_WIDGET_CLASS (e_day_view_parent_class)->style_set)(widget, previous_style); + if (!E_CALENDAR_VIEW (day_view)->in_focus) { + e_day_view_free_events (day_view); + day_view->requires_update = TRUE; + return; + } - day_view = E_DAY_VIEW (widget); - e_day_view_set_colors (day_view, widget); + e_day_view_stop_editing_event (day_view); - for (week_day = 0; week_day < E_DAY_VIEW_MAX_DAYS; week_day++) { - for (event_num = 0; event_num < day_view->events[week_day]->len; event_num++) { - event = &g_array_index (day_view->events[week_day], EDayViewEvent, event_num); - if (event->canvas_item) { - color = e_day_view_get_text_color (day_view, event, widget); - gnome_canvas_item_set ( - event->canvas_item, - "fill_color_gdk", &color, - NULL); - } - } - } - for (event_num = 0; event_num < day_view->long_events->len; event_num++) { - event = &g_array_index (day_view->long_events, EDayViewEvent, event_num); - if (event->canvas_item) { - color = e_day_view_get_text_color (day_view, event, widget); - gnome_canvas_item_set ( - event->canvas_item, - "fill_color_gdk", &color, - NULL); + model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); + for (i = 0; i < count; i++) { + ECalModelComponent *comp_data; + + comp_data = e_cal_model_get_component_at (model, row + i); + if (comp_data == NULL) { + g_warning ("comp_data is NULL\n"); + continue; } + process_component (day_view, comp_data); } - /* Set up Pango prerequisites */ - font_desc = gtk_widget_get_style (widget)->font_desc; - pango_context = gtk_widget_get_pango_context (widget); - font_metrics = pango_context_get_metrics ( - pango_context, font_desc, - pango_context_get_language (pango_context)); - layout = pango_layout_new (pango_context); + gtk_widget_queue_draw (day_view->top_canvas); + gtk_widget_queue_draw (day_view->main_canvas); + e_day_view_queue_layout (day_view); - /* Create the large font. */ - if (day_view->large_font_desc != NULL) - pango_font_description_free (day_view->large_font_desc); +} - day_view->large_font_desc = pango_font_description_copy (font_desc); - pango_font_description_set_size ( - day_view->large_font_desc, - E_DAY_VIEW_LARGE_FONT_PTSIZE * PANGO_SCALE); +static void +model_comps_deleted_cb (ETableModel *etm, + gpointer data, + gpointer user_data) +{ + EDayView *day_view = E_DAY_VIEW (user_data); + GSList *l, *list = data; - /* Create the small fonts. */ - if (day_view->small_font_desc != NULL) - pango_font_description_free (day_view->small_font_desc); + if (!E_CALENDAR_VIEW (day_view)->in_focus) { + e_day_view_free_events (day_view); + day_view->requires_update = TRUE; + return; + } - day_view->small_font_desc = pango_font_description_copy (font_desc); - pango_font_description_set_size ( - day_view->small_font_desc, - E_DAY_VIEW_SMALL_FONT_PTSIZE * PANGO_SCALE); + e_day_view_stop_editing_event (day_view); - /* Recalculate the height of each row based on the font size. */ - day_view->row_height = - PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) + - PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics)) + - E_DAY_VIEW_EVENT_BORDER_HEIGHT + E_DAY_VIEW_EVENT_Y_PAD * 2 + 2 /* FIXME */; - day_view->row_height = MAX ( - day_view->row_height, - E_DAY_VIEW_ICON_HEIGHT + E_DAY_VIEW_ICON_Y_PAD + 2); + for (l = list; l != NULL; l = g_slist_next (l)) { + ECalModelComponent *comp_data = l->data; + gint day, event_num; + const gchar *uid = NULL; + gchar *rid = NULL; - adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (day_view->main_canvas)); - gtk_adjustment_set_step_increment (adjustment, day_view->row_height); + uid = icalcomponent_get_uid (comp_data->icalcomp); + if (e_cal_util_component_is_instance (comp_data->icalcomp)) { + icalproperty *prop; - day_view->top_row_height = - PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) + - PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics)) + - E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT * 2 + E_DAY_VIEW_LONG_EVENT_Y_PAD * 2 + - E_DAY_VIEW_TOP_CANVAS_Y_GAP; - day_view->top_row_height = - MAX ( - day_view->top_row_height, - E_DAY_VIEW_ICON_HEIGHT + E_DAY_VIEW_ICON_Y_PAD + 2 + - E_DAY_VIEW_TOP_CANVAS_Y_GAP); + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_RECURRENCEID_PROPERTY); + if (prop) + rid = icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (comp_data->icalcomp)); + } - adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (day_view->top_canvas)); - gtk_adjustment_set_step_increment (adjustment, day_view->top_row_height); - gtk_widget_set_size_request (day_view->top_dates_canvas, -1, day_view->top_row_height - 2); + if (e_day_view_find_event_from_uid (day_view, comp_data->client, uid, rid, &day, &event_num)) + e_day_view_remove_event_cb (day_view, day, event_num, NULL); - e_day_view_update_top_scroll (day_view, TRUE); + g_free (rid); + } - /* Find the longest full & abbreviated month names. */ - longest_month_width = 0; - longest_abbreviated_month_width = 0; - for (month = 0; month < 12; month++) { - name = e_get_month_name (month + 1, FALSE); - pango_layout_set_text (layout, name, -1); - pango_layout_get_pixel_size (layout, &width, NULL); + gtk_widget_queue_draw (day_view->top_canvas); + gtk_widget_queue_draw (day_view->main_canvas); + e_day_view_queue_layout (day_view); +} - if (width > longest_month_width) { - longest_month_width = width; - day_view->longest_month_name = month; - } +static void +timezone_changed_cb (ECalModel *cal_model, + icaltimezone *old_zone, + icaltimezone *new_zone, + gpointer user_data) +{ + struct icaltimetype tt; + time_t lower; + EDayView *day_view = (EDayView *) user_data; + ECalendarView *cal_view = (ECalendarView *) day_view; - name = e_get_month_name (month + 1, TRUE); - pango_layout_set_text (layout, name, -1); - pango_layout_get_pixel_size (layout, &width, NULL); + g_return_if_fail (E_IS_DAY_VIEW (day_view)); - if (width > longest_abbreviated_month_width) { - longest_abbreviated_month_width = width; - day_view->longest_abbreviated_month_name = month; - } + if (!cal_view->in_focus) { + e_day_view_free_events (day_view); + day_view->requires_update = TRUE; + return; } - /* Find the longest full & abbreviated weekday names. */ - longest_weekday_width = 0; - longest_abbreviated_weekday_width = 0; - for (day = 0; day < 7; day++) { - name = e_get_weekday_name (day + 1, FALSE); - pango_layout_set_text (layout, name, -1); - pango_layout_get_pixel_size (layout, &width, NULL); + /* If our time hasn't been set yet, just return. */ + if (day_view->lower == 0 && day_view->upper == 0) + return; - if (width > longest_weekday_width) { - longest_weekday_width = width; - day_view->longest_weekday_name = day; - } + /* Recalculate the new start of the first day. We just use exactly + * the same time, but with the new timezone. */ + tt = icaltime_from_timet_with_zone ( + day_view->lower, FALSE, + old_zone); - name = e_get_weekday_name (day + 1, TRUE); - pango_layout_set_text (layout, name, -1); - pango_layout_get_pixel_size (layout, &width, NULL); + lower = icaltime_as_timet_with_zone (tt, new_zone); - if (width > longest_abbreviated_weekday_width) { - longest_abbreviated_weekday_width = width; - day_view->longest_abbreviated_weekday_name = day; - } - } + e_day_view_recalc_day_starts (day_view, lower); + e_day_view_update_query (day_view); +} - /* Calculate the widths of all the time strings necessary. */ - day_view->max_small_hour_width = 0; - for (hour = 0; hour < 24; hour++) { - g_snprintf (buffer, sizeof (buffer), "%02i", hour); - pango_layout_set_text (layout, buffer, -1); - pango_layout_get_pixel_size (layout, &day_view->small_hour_widths[hour], NULL); +static void +init_model (EDayView *day_view, + ECalModel *model) +{ + /* connect to ECalModel's signals */ + g_signal_connect ( + model, "time_range_changed", + G_CALLBACK (time_range_changed_cb), day_view); + g_signal_connect ( + model, "model_row_changed", + G_CALLBACK (model_row_changed_cb), day_view); + g_signal_connect ( + model, "model_cell_changed", + G_CALLBACK (model_cell_changed_cb), day_view); + g_signal_connect ( + model, "model_rows_inserted", + G_CALLBACK (model_rows_inserted_cb), day_view); + g_signal_connect ( + model, "comps_deleted", + G_CALLBACK (model_comps_deleted_cb), day_view); + g_signal_connect ( + model, "timezone_changed", + G_CALLBACK (timezone_changed_cb), day_view); +} - day_view->max_small_hour_width = MAX (day_view->max_small_hour_width, day_view->small_hour_widths[hour]); - } +/* Turn off the background of the canvas windows. This reduces flicker + * considerably when scrolling. (Why isn't it in GnomeCanvas?). */ +static void +e_day_view_on_canvas_realized (GtkWidget *widget, + EDayView *day_view) +{ + GdkWindow *window; - max_minute_width = 0; - for (minute = 0, i = 0; minute < 60; minute += 5, i++) { - gint minute_width; + window = gtk_layout_get_bin_window (GTK_LAYOUT (widget)); + gdk_window_set_background_pattern (window, NULL); +} - g_snprintf (buffer, sizeof (buffer), "%02i", minute); - pango_layout_set_text (layout, buffer, -1); - pango_layout_get_pixel_size (layout, &minute_width, NULL); +/** + * e_day_view_new: + * @Returns: a new #EDayView. + * + * Creates a new #EDayView. + **/ +ECalendarView * +e_day_view_new (ECalModel *model) +{ + ECalendarView *day_view; - max_minute_width = MAX (max_minute_width, minute_width); - } - day_view->max_minute_width = max_minute_width; + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); - pango_layout_set_text (layout, ":", 1); - pango_layout_get_pixel_size (layout, &day_view->colon_width, NULL); - pango_layout_set_text (layout, "0", 1); - pango_layout_get_pixel_size (layout, &day_view->digit_width, NULL); + day_view = g_object_new (E_TYPE_DAY_VIEW, "model", model, NULL); + init_model (E_DAY_VIEW (day_view), model); - pango_layout_set_text (layout, day_view->am_string, -1); - pango_layout_get_pixel_size (layout, &day_view->am_string_width, NULL); - pango_layout_set_text (layout, day_view->pm_string, -1); - pango_layout_get_pixel_size (layout, &day_view->pm_string_width, NULL); + return day_view; +} - /* Calculate the width of the time column. */ - times_width = e_day_view_time_item_get_column_width (E_DAY_VIEW_TIME_ITEM (day_view->time_canvas_item)); - gtk_widget_set_size_request (day_view->time_canvas, times_width, -1); +static void +e_day_view_set_colors (EDayView *day_view, + GtkWidget *widget) +{ + GtkStyle *style; - g_object_unref (layout); - pango_font_metrics_unref (font_metrics); + style = gtk_widget_get_style (widget); + + day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING] = style->base[GTK_STATE_NORMAL]; + day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING] = style->bg[GTK_STATE_ACTIVE]; + day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED] = style->base[GTK_STATE_SELECTED]; + day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED] = style->bg[GTK_STATE_SELECTED]; + day_view->colors[E_DAY_VIEW_COLOR_BG_GRID] = style->dark[GTK_STATE_NORMAL]; + day_view->colors[E_DAY_VIEW_COLOR_BG_MULTIDAY_TODAY] = get_today_background (day_view->colors[E_DAY_VIEW_COLOR_BG_WORKING]); + day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS] = style->dark[GTK_STATE_NORMAL]; + day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED] = style->bg[GTK_STATE_SELECTED]; + day_view->colors[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID] = style->light[GTK_STATE_NORMAL]; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR] = style->base[GTK_STATE_SELECTED]; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND] = style->base[GTK_STATE_NORMAL]; + day_view->colors[E_DAY_VIEW_COLOR_EVENT_BORDER] = style->dark[GTK_STATE_NORMAL]; + day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND] = style->bg[GTK_STATE_ACTIVE]; + day_view->colors[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER] = style->dark[GTK_STATE_NORMAL]; + day_view->colors[E_DAY_VIEW_COLOR_MARCUS_BAINS_LINE] = style->dark[GTK_STATE_PRELIGHT]; } static void -e_day_view_recalc_main_canvas_size (EDayView *day_view) +e_day_view_update_top_scroll (EDayView *day_view, + gboolean scroll_to_top) { - ECalModel *model; - gint work_day_start_hour; - gint work_day_start_minute; - gint day, scroll_y; - gboolean need_reshape; + GtkAllocation allocation; + gint top_rows, top_canvas_height; + gdouble old_x2, old_y2, new_x2, new_y2; - model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); - work_day_start_hour = e_cal_model_get_work_day_start_hour (model); - work_day_start_minute = e_cal_model_get_work_day_start_minute (model); + /* Set the height of the top canvas based on the row height and the + * number of rows needed (min 1 + 1 for the dates + 1 space for DnD).*/ + top_rows = MAX (1, day_view->rows_in_top_display); + top_canvas_height = (top_rows + 1) * day_view->top_row_height; + if (top_rows <= E_DAY_VIEW_MAX_ROWS_AT_TOP) { + gtk_widget_set_size_request (day_view->top_canvas, -1, top_canvas_height); + gtk_widget_hide (day_view->tc_vscrollbar); + } else { + gtk_widget_set_size_request (day_view->top_canvas, -1, (E_DAY_VIEW_MAX_ROWS_AT_TOP + 1) * day_view->top_row_height); + gtk_widget_show (day_view->tc_vscrollbar); + } /* Set the scroll region of the top canvas */ - e_day_view_update_top_scroll (day_view, TRUE); - - need_reshape = e_day_view_update_scroll_regions (day_view); - - e_day_view_recalc_cell_sizes (day_view); + gnome_canvas_get_scroll_region ( + GNOME_CANVAS (day_view->top_canvas), + NULL, NULL, &old_x2, &old_y2); + gtk_widget_get_allocation (day_view->top_canvas, &allocation); + new_x2 = allocation.width - 1; + new_y2 = (MAX (1, day_view->rows_in_top_display) + 1) * day_view->top_row_height - 1; + if (old_x2 != new_x2 || old_y2 != new_y2) { + gnome_canvas_set_scroll_region ( + GNOME_CANVAS (day_view->top_canvas), + 0, 0, new_x2, new_y2); - /* Scroll to the start of the working day, if this is the initial - * allocation. */ - if (day_view->scroll_to_work_day) { - scroll_y = e_day_view_convert_time_to_position ( - day_view, work_day_start_hour, work_day_start_minute); - gnome_canvas_scroll_to ( - GNOME_CANVAS (day_view->main_canvas), 0, scroll_y); - day_view->scroll_to_work_day = FALSE; + if (scroll_to_top) + gnome_canvas_scroll_to (GNOME_CANVAS (day_view->top_canvas), 0, 0); } + new_y2 = day_view->top_row_height - 1 - 2; + gnome_canvas_get_scroll_region (GNOME_CANVAS (day_view->top_dates_canvas), NULL, NULL, &old_x2, &old_y2); - /* Flag that we need to reshape the events. Note that changes in height - * don't matter, since the rows are always the same height. */ - if (need_reshape) { - day_view->long_events_need_reshape = TRUE; - for (day = 0; day < E_DAY_VIEW_MAX_DAYS; day++) - day_view->need_reshape[day] = TRUE; - - e_day_view_check_layout (day_view); + if (old_x2 != new_x2 || old_y2 != new_y2) { + gnome_canvas_set_scroll_region (GNOME_CANVAS (day_view->top_dates_canvas), 0, 0, new_x2, new_y2); + gnome_canvas_scroll_to (GNOME_CANVAS (day_view->top_dates_canvas), 0, 0); } } -/* This recalculates the sizes of each column. */ -static void -e_day_view_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - (*GTK_WIDGET_CLASS (e_day_view_parent_class)->size_allocate) (widget, allocation); - - e_day_view_recalc_main_canvas_size (E_DAY_VIEW (widget)); -} - static void e_day_view_recalc_cell_sizes (EDayView *day_view) { @@ -1914,70 +2342,6 @@ exit: g_object_unref (layout); } -static gint -e_day_view_focus_in (GtkWidget *widget, - GdkEventFocus *event) -{ - EDayView *day_view; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (E_IS_DAY_VIEW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - day_view = E_DAY_VIEW (widget); - - /* XXX Can't access flags directly anymore, but is it really needed? - * If so, could we call gtk_widget_send_focus_change() instead? */ -#if 0 - GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); -#endif - - if (E_CALENDAR_VIEW (day_view)->in_focus && day_view->requires_update) { - time_t my_start = 0, my_end = 0, model_start = 0, model_end = 0; - - day_view->requires_update = FALSE; - - e_cal_model_get_time_range (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), &model_start, &model_end); - - if (e_calendar_view_get_visible_time_range (E_CALENDAR_VIEW (day_view), &my_start, &my_end) && - model_start == my_start && model_end == my_end) { - /* update only when the same time range is set in a view and in a model; - * otherwise time range change invokes also query update */ - e_day_view_recalc_day_starts (day_view, day_view->lower); - e_day_view_update_query (day_view); - } - } - - gtk_widget_queue_draw (day_view->top_canvas); - gtk_widget_queue_draw (day_view->main_canvas); - - return FALSE; -} - -static gint -e_day_view_focus_out (GtkWidget *widget, - GdkEventFocus *event) -{ - EDayView *day_view; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (E_IS_DAY_VIEW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - day_view = E_DAY_VIEW (widget); - - /* XXX Can't access flags directly anymore, but is it really needed? - * If so, could we call gtk_widget_send_focus_change() instead? */ -#if 0 - GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); -#endif - - gtk_widget_queue_draw (day_view->top_canvas); - gtk_widget_queue_draw (day_view->main_canvas); - - return FALSE; -} - /* This calls a given function for each event instance (in both views). * If the callback returns FALSE the iteration is stopped. * Note that it is safe for the callback to remove the event (since we @@ -2532,157 +2896,26 @@ e_day_view_find_work_week_start (EDayView *day_view, day = week_start_day % 7; for (i = 0; i < 7; i++) { /* the working_days has stored 0 (Sun) to 6 (Sat) */ - if (day_view->working_days & (1 << ((day + 1) % 7))) - break; - day = (day + 1) % 7; - } - - /* Calculate how many days we need to go back to the first workday. */ - if (weekday < day) { - offset = (7 - day + weekday) % 7; - } else { - offset = (weekday - day) % 7; - } - - if (offset) - g_date_subtract_days (&date, offset); - - tt.year = g_date_get_year (&date); - tt.month = g_date_get_month (&date); - tt.day = g_date_get_day (&date); - - return icaltime_as_timet_with_zone (tt, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); -} - -/* This sets the selected time range. If the start_time & end_time are not equal - * and are both visible in the view, then the selection is set to those times, - * otherwise it is set to 1 hour from the start of the working day. */ -static void -e_day_view_set_selected_time_range (ECalendarView *cal_view, - time_t start_time, - time_t end_time) -{ - ECalModel *model; - EDayView *day_view; - gint work_day_start_hour; - gint work_day_start_minute; - gint start_row, start_col, end_row, end_col; - gboolean need_redraw = FALSE, start_in_grid, end_in_grid; - - day_view = E_DAY_VIEW (cal_view); - model = e_calendar_view_get_model (cal_view); - work_day_start_hour = e_cal_model_get_work_day_start_hour (model); - work_day_start_minute = e_cal_model_get_work_day_start_minute (model); - - if (start_time == end_time) - end_time += e_calendar_view_get_time_divisions (cal_view) * 60; - - /* Set the selection. */ - start_in_grid = e_day_view_convert_time_to_grid_position ( - day_view, - start_time, - &start_col, - &start_row); - end_in_grid = e_day_view_convert_time_to_grid_position ( - day_view, - end_time - 60, - &end_col, - &end_row); - - /* If either of the times isn't in the grid, or the selection covers - * an entire day, we set the selection to 1 row from the start of the - * working day, in the day corresponding to the start time. */ - if (!start_in_grid || !end_in_grid - || (start_row == 0 && end_row == day_view->rows - 1)) { - end_col = start_col; - - start_row = e_day_view_convert_time_to_row ( - day_view, work_day_start_hour, work_day_start_minute); - start_row = CLAMP (start_row, 0, day_view->rows - 1); - end_row = start_row; - } - - if (start_row != day_view->selection_start_row - || start_col != day_view->selection_start_day) { - need_redraw = TRUE; - day_view->selection_in_top_canvas = FALSE; - day_view->selection_start_row = start_row; - day_view->selection_start_day = start_col; - } - - if (end_row != day_view->selection_end_row - || end_col != day_view->selection_end_day) { - need_redraw = TRUE; - day_view->selection_in_top_canvas = FALSE; - day_view->selection_end_row = end_row; - day_view->selection_end_day = end_col; - } - - if (need_redraw) { - gtk_widget_queue_draw (day_view->top_canvas); - gtk_widget_queue_draw (day_view->top_dates_canvas); - gtk_widget_queue_draw (day_view->main_canvas); - } -} - -/* Returns the selected time range. */ -static gboolean -e_day_view_get_selected_time_range (ECalendarView *cal_view, - time_t *start_time, - time_t *end_time) -{ - gint start_col, start_row, end_col, end_row; - time_t start, end; - EDayView *day_view = E_DAY_VIEW (cal_view); - - start_col = day_view->selection_start_day; - start_row = day_view->selection_start_row; - end_col = day_view->selection_end_day; - end_row = day_view->selection_end_row; - - if (start_col == -1) { - start_col = 0; - start_row = 0; - end_col = 0; - end_row = 0; - } - - /* Check if the selection is only in the top canvas, in which case - * we can simply use the day_starts array. */ - if (day_view->selection_in_top_canvas) { - start = day_view->day_starts[start_col]; - end = day_view->day_starts[end_col + 1]; - } else { - /* Convert the start col + row into a time. */ - start = e_day_view_convert_grid_position_to_time (day_view, start_col, start_row); - end = e_day_view_convert_grid_position_to_time (day_view, end_col, end_row + 1); - } - - if (start_time) - *start_time = start; - - if (end_time) - *end_time = end; - - return TRUE; -} + if (day_view->working_days & (1 << ((day + 1) % 7))) + break; + day = (day + 1) % 7; + } -/* Gets the visible time range. Returns FALSE if no time range has been set. */ -static gboolean -e_day_view_get_visible_time_range (ECalendarView *cal_view, - time_t *start_time, - time_t *end_time) -{ - EDayView *day_view = E_DAY_VIEW (cal_view); + /* Calculate how many days we need to go back to the first workday. */ + if (weekday < day) { + offset = (7 - day + weekday) % 7; + } else { + offset = (weekday - day) % 7; + } - /* If the date isn't set, return FALSE. */ - if (day_view->lower == 0 && day_view->upper == 0) - return FALSE; + if (offset) + g_date_subtract_days (&date, offset); - *start_time = day_view->day_starts[0]; - *end_time = day_view->day_starts[day_view->days_shown]; + tt.year = g_date_get_year (&date); + tt.month = g_date_get_month (&date); + tt.day = g_date_get_day (&date); - return TRUE; + return icaltime_as_timet_with_zone (tt, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); } static void @@ -3163,11 +3396,11 @@ e_day_view_on_top_canvas_button_press (GtkWidget *widget, if (button_event->type == GDK_2BUTTON_PRESS) { time_t dtstart, dtend; - e_day_view_get_selected_time_range ((ECalendarView *) day_view, &dtstart, &dtend); + day_view_get_selected_time_range ((ECalendarView *) day_view, &dtstart, &dtend); if (dtstart < day_view->before_click_dtend && dtend > day_view->before_click_dtstart) { dtstart = day_view->before_click_dtstart; dtend = day_view->before_click_dtend; - e_day_view_set_selected_time_range ((ECalendarView *) day_view, dtstart, dtend); + day_view_set_selected_time_range ((ECalendarView *) day_view, dtstart, dtend); } e_calendar_view_new_appointment_for ( @@ -3195,7 +3428,7 @@ e_day_view_on_top_canvas_button_press (GtkWidget *widget, day_view->grabbed_pointer = g_object_ref (event_device); if (event_time - day_view->bc_event_time > 250) - e_day_view_get_selected_time_range ( + day_view_get_selected_time_range ( E_CALENDAR_VIEW (day_view), &day_view->before_click_dtstart, &day_view->before_click_dtend); @@ -3328,11 +3561,11 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget, if (button_event->type == GDK_2BUTTON_PRESS) { time_t dtstart, dtend; - e_day_view_get_selected_time_range ((ECalendarView *) day_view, &dtstart, &dtend); + day_view_get_selected_time_range ((ECalendarView *) day_view, &dtstart, &dtend); if (dtstart < day_view->before_click_dtend && dtend > day_view->before_click_dtstart) { dtstart = day_view->before_click_dtstart; dtend = day_view->before_click_dtend; - e_day_view_set_selected_time_range ((ECalendarView *) day_view, dtstart, dtend); + day_view_set_selected_time_range ((ECalendarView *) day_view, dtstart, dtend); } e_calendar_view_new_appointment_for ( E_CALENDAR_VIEW (day_view), @@ -3359,7 +3592,7 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget, day_view->grabbed_pointer = g_object_ref (event_device); if (event_time - day_view->bc_event_time > 250) - e_day_view_get_selected_time_range ( + day_view_get_selected_time_range ( E_CALENDAR_VIEW (day_view), &day_view->before_click_dtstart, &day_view->before_click_dtend); @@ -3807,67 +4040,6 @@ e_day_view_show_popup_menu (EDayView *day_view, e_calendar_view_popup_event (E_CALENDAR_VIEW (day_view), button_event); } -static gboolean -e_day_view_popup_menu (GtkWidget *widget) -{ - EDayView *day_view = E_DAY_VIEW (widget); - e_day_view_show_popup_menu ( - day_view, NULL, - day_view->editing_event_day, - day_view->editing_event_num); - return TRUE; -} - -/* Returns the currently-selected event, or NULL if none */ -static GList * -e_day_view_get_selected_events (ECalendarView *cal_view) -{ - EDayViewEvent *event = NULL; - GList *list = NULL; - EDayView *day_view = (EDayView *) cal_view; - - g_return_val_if_fail (E_IS_DAY_VIEW (day_view), NULL); - - if (day_view->editing_event_num != -1) { - if (day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT) { - if (!is_array_index_in_bounds (day_view->long_events, day_view->editing_event_num)) - return NULL; - - event = &g_array_index (day_view->long_events, - EDayViewEvent, - day_view->editing_event_num); - } else { - if (!is_array_index_in_bounds (day_view->events[day_view->editing_event_day], day_view->editing_event_num)) - return NULL; - - event = &g_array_index (day_view->events[day_view->editing_event_day], - EDayViewEvent, - day_view->editing_event_num); - } - } else if (day_view->popup_event_num != -1) { - if (day_view->popup_event_day == E_DAY_VIEW_LONG_EVENT) { - if (!is_array_index_in_bounds (day_view->long_events, day_view->popup_event_num)) - return NULL; - - event = &g_array_index (day_view->long_events, - EDayViewEvent, - day_view->popup_event_num); - } else { - if (!is_array_index_in_bounds (day_view->events[day_view->popup_event_day], day_view->popup_event_num)) - return NULL; - - event = &g_array_index (day_view->events[day_view->popup_event_day], - EDayViewEvent, - day_view->popup_event_num); - } - } - - if (event) - list = g_list_append (list, event); - - return list; -} - /* Restarts a query for the day view */ static void e_day_view_update_query (EDayView *day_view) @@ -3984,7 +4156,7 @@ e_day_view_update_calendar_selection_time (EDayView *day_view) { time_t start, end; - e_day_view_get_selected_time_range ((ECalendarView *) day_view, &start, &end); + day_view_get_selected_time_range ((ECalendarView *) day_view, &start, &end); } static gboolean @@ -5318,94 +5490,6 @@ e_day_view_event_sort_func (gconstpointer arg1, return 0; } -static gboolean -e_day_view_add_new_event_in_selected_range (EDayView *day_view, - GdkEventKey *key_event) -{ - icalcomponent *icalcomp; - ECalClient *client; - ECalModel *model; - ECalComponent *comp; - gint day, event_num; - time_t dtstart, dtend; - ECalComponentDateTime start_dt, end_dt; - struct icaltimetype start_tt, end_tt; - const gchar *uid; - AddEventData add_event_data; - ESourceRegistry *registry; - - model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)); - - registry = e_cal_model_get_registry (model); - client = e_cal_model_get_default_client (model); - - /* Check if the client is read only */ - if (e_client_is_readonly (E_CLIENT (client))) - return FALSE; - - icalcomp = e_cal_model_create_component_with_defaults (model, day_view->selection_in_top_canvas); - if (!icalcomp) - return FALSE; - - uid = icalcomponent_get_uid (icalcomp); - - comp = e_cal_component_new (); - e_cal_component_set_icalcomponent (comp, icalcomp); - - e_day_view_get_selected_time_range ((ECalendarView *) day_view, &dtstart, &dtend); - - start_tt = icaltime_from_timet_with_zone ( - dtstart, FALSE, - e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); - - end_tt = icaltime_from_timet_with_zone ( - dtend, FALSE, - e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); - - if (day_view->selection_in_top_canvas) { - start_dt.tzid = NULL; - start_tt.is_date = 1; - end_tt.is_date = 1; - - /* Editor default in day/work-week view - top canvas */ - e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT); - } else { - start_dt.tzid = icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view))); - - /* Editor default in day/work-week view - main canvas */ - e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_OPAQUE); - } - - start_dt.value = &start_tt; - end_dt.value = &end_tt; - end_dt.tzid = start_dt.tzid; - e_cal_component_set_dtstart (comp, &start_dt); - e_cal_component_set_dtend (comp, &end_dt); - - e_cal_component_set_categories ( - comp, e_calendar_view_get_default_category (E_CALENDAR_VIEW (day_view))); - - /* We add the event locally and start editing it. We don't send it - * to the server until the user finishes editing it. */ - add_event_data.day_view = day_view; - add_event_data.comp_data = NULL; - e_day_view_add_event (registry, comp, dtstart, dtend, &add_event_data); - e_day_view_check_layout (day_view); - gtk_widget_queue_draw (day_view->top_canvas); - gtk_widget_queue_draw (day_view->main_canvas); - - if (!e_day_view_find_event_from_uid (day_view, client, uid, NULL, &day, &event_num)) { - g_warning ("Couldn't find event to start editing.\n"); - g_object_unref (comp); - return FALSE; - } - - e_day_view_start_editing_event (day_view, day, event_num, key_event); - - g_object_unref (comp); - return TRUE; -} - static gboolean e_day_view_do_key_press (GtkWidget *widget, GdkEventKey *event) @@ -5548,19 +5632,6 @@ e_day_view_do_key_press (GtkWidget *widget, return e_day_view_add_new_event_in_selected_range (day_view, event); } -static gboolean -e_day_view_key_press (GtkWidget *widget, - GdkEventKey *event) -{ - gboolean handled = FALSE; - handled = e_day_view_do_key_press (widget, event); - - /* if not handled, try key bindings */ - if (!handled) - handled = GTK_WIDGET_CLASS (e_day_view_parent_class)->key_press_event (widget, event); - return handled; -} - /* Select the time that begins a work day*/ static void e_day_view_goto_start_of_work_day (EDayView *day_view) @@ -5737,46 +5808,6 @@ e_day_view_cursor_key_up_shifted (EDayView *day_view, gtk_widget_queue_draw (day_view->main_canvas); } -static gboolean -e_day_view_focus (GtkWidget *widget, - GtkDirectionType direction) -{ - EDayView *day_view; - gint new_day; - gint new_event_num; - gint start_row, end_row; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (E_IS_DAY_VIEW (widget), FALSE); - day_view = E_DAY_VIEW (widget); - - if (!e_day_view_get_next_tab_event (day_view, direction, - &new_day, &new_event_num)) - return FALSE; - - if ((new_day == -1) && (new_event_num == -1)) { - /* focus should go to the day view widget itself - */ - gtk_widget_grab_focus (GTK_WIDGET (day_view)); - return TRUE; - } - - if (new_day != E_DAY_VIEW_LONG_EVENT && new_day != -1) { - if (e_day_view_get_event_rows (day_view, new_day, - new_event_num, - &start_row, &end_row)) - /* ensure the event to be seen */ - e_day_view_ensure_rows_visible ( - day_view, - start_row, end_row); - } - e_day_view_start_editing_event ( - day_view, new_day, - new_event_num, NULL); - - return TRUE; -} - /** * e_day_view_get_extreme_event * @day_view: the day view widget operates on @@ -8751,39 +8782,3 @@ e_day_view_get_num_events_selected (EDayView *day_view) return (day_view->editing_event_day != -1) ? 1 : 0; } -static void -e_day_view_paste_text (ECalendarView *cal_view) -{ - EDayView *day_view; - EDayViewEvent *event; - - g_return_if_fail (E_IS_DAY_VIEW (cal_view)); - - day_view = E_DAY_VIEW (cal_view); - - if (day_view->editing_event_num == -1 && - !e_day_view_add_new_event_in_selected_range (day_view, NULL)) - return; - - if (day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT) { - if (!is_array_index_in_bounds (day_view->long_events, day_view->editing_event_num)) - return; - - event = &g_array_index (day_view->long_events, - EDayViewEvent, - day_view->editing_event_num); - } else { - if (!is_array_index_in_bounds (day_view->events[day_view->editing_event_day], day_view->editing_event_num)) - return; - - event = &g_array_index (day_view->events[day_view->editing_event_day], - EDayViewEvent, - day_view->editing_event_num); - } - - if (event->canvas_item && - E_IS_TEXT (event->canvas_item) && - E_TEXT (event->canvas_item)->editing) { - e_text_paste_clipboard (E_TEXT (event->canvas_item)); - } -} diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h index 5bf8974b69..e359b838dc 100644 --- a/calendar/gui/e-day-view.h +++ b/calendar/gui/e-day-view.h @@ -21,8 +21,8 @@ * */ -#ifndef _E_DAY_VIEW_H_ -#define _E_DAY_VIEW_H_ +#ifndef E_DAY_VIEW_H +#define E_DAY_VIEW_H #include #include @@ -31,12 +31,29 @@ #include "e-calendar-view.h" #include "gnome-cal.h" -G_BEGIN_DECLS - /* * EDayView - displays the Day & Work-Week views of the calendar. */ +/* Standard GObject macros */ +#define E_TYPE_DAY_VIEW \ + (e_day_view_get_type ()) +#define E_DAY_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_DAY_VIEW, EDayView)) +#define E_DAY_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_DAY_VIEW, EDayViewClass)) +#define E_IS_DAY_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_DAY_VIEW)) +#define E_IS_DAY_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_DAY_VIEW)) +#define E_DAY_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_DAY_VIEW, EDayViewClass)) + /* 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 @@ -96,11 +113,12 @@ G_BEGIN_DECLS /* The gap between rows in the top canvas. */ #define E_DAY_VIEW_TOP_CANVAS_Y_GAP 2 +G_BEGIN_DECLS + /* 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 -{ +typedef enum { E_DAY_VIEW_SUNDAY = 1 << 0, E_DAY_VIEW_MONDAY = 1 << 1, E_DAY_VIEW_TUESDAY = 1 << 2, @@ -112,8 +130,7 @@ typedef enum /* These are used to specify the type of an appointment. They match those * used in EMeetingTimeSelector. */ -typedef enum -{ +typedef enum { E_DAY_VIEW_BUSY_TENTATIVE = 0, E_DAY_VIEW_BUSY_OUT_OF_OFFICE = 1, E_DAY_VIEW_BUSY_BUSY = 2, @@ -126,8 +143,7 @@ typedef enum * like 'Thu 12 Sep'. The no weekday format is like '12 Sep'. The short format * is like '12'. The actual format used is determined in * e_day_view_recalc_cell_sizes (), once we know the font being used. */ -typedef enum -{ +typedef enum { E_DAY_VIEW_DATE_FULL, E_DAY_VIEW_DATE_ABBREVIATED, E_DAY_VIEW_DATE_NO_WEEKDAY, @@ -135,8 +151,7 @@ typedef enum } EDayViewDateFormat; /* These index our colors array. */ -typedef enum -{ +typedef enum { E_DAY_VIEW_COLOR_BG_WORKING, E_DAY_VIEW_COLOR_BG_NOT_WORKING, E_DAY_VIEW_COLOR_BG_SELECTED, @@ -161,8 +176,7 @@ typedef enum } EDayViewColors; /* These specify which part of the selection we are dragging, if any. */ -typedef enum -{ +typedef enum { E_DAY_VIEW_DRAG_START, E_DAY_VIEW_DRAG_END } EDayViewDragPosition; @@ -183,30 +197,13 @@ struct _EDayViewEvent { guint8 num_columns; }; -/* Standard GObject macros */ -#define E_TYPE_DAY_VIEW \ - (e_day_view_get_type ()) -#define E_DAY_VIEW(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_DAY_VIEW, EDayView)) -#define E_DAY_VIEW_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_DAY_VIEW, EDayViewClass)) -#define E_IS_DAY_VIEW(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_DAY_VIEW)) -#define E_IS_DAY_VIEW_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_DAY_VIEW)) -#define E_DAY_VIEW_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_DAY_VIEW, EDayViewClass)) - -typedef struct _EDayView EDayView; -typedef struct _EDayViewClass EDayViewClass; +typedef struct _EDayView EDayView; +typedef struct _EDayViewClass EDayViewClass; +typedef struct _EDayViewPrivate EDayViewPrivate; struct _EDayView { ECalendarView parent; + EDayViewPrivate *priv; /* The top canvas where the dates are shown. */ GtkWidget *top_dates_canvas; @@ -477,124 +474,131 @@ struct _EDayView { gboolean requires_update; }; -struct _EDayViewClass -{ +struct _EDayViewClass { ECalendarViewClass parent_class; }; -GType e_day_view_get_type (void); -ECalendarView * e_day_view_new (ECalModel *model); +GType e_day_view_get_type (void) G_GNUC_CONST; +ECalendarView * e_day_view_new (ECalModel *model); /* 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); +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). */ -gint e_day_view_get_days_shown (EDayView *day_view); -void e_day_view_set_days_shown (EDayView *day_view, - gint days_shown); +gint e_day_view_get_days_shown (EDayView *day_view); +void e_day_view_set_days_shown (EDayView *day_view, + gint days_shown); /* 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); +EDayViewDays e_day_view_get_working_days (EDayView *day_view); +void e_day_view_set_working_days (EDayView *day_view, + EDayViewDays days); /* Whether we display the Marcus Bains Line in the main canvas and time * canvas. */ -void e_day_view_marcus_bains_update (EDayView *day_view); -gboolean e_day_view_marcus_bains_get_show_line (EDayView *day_view); -void e_day_view_marcus_bains_set_show_line (EDayView *day_view, +void e_day_view_marcus_bains_update (EDayView *day_view); +gboolean e_day_view_marcus_bains_get_show_line + (EDayView *day_view); +void e_day_view_marcus_bains_set_show_line + (EDayView *day_view, gboolean show_line); -const gchar * - e_day_view_marcus_bains_get_day_view_color +const gchar * e_day_view_marcus_bains_get_day_view_color (EDayView *day_view); -void e_day_view_marcus_bains_set_day_view_color +void e_day_view_marcus_bains_set_day_view_color (EDayView *day_view, const gchar *day_view_color); -const gchar * - e_day_view_marcus_bains_get_time_bar_color +const gchar * e_day_view_marcus_bains_get_time_bar_color (EDayView *day_view); -void e_day_view_marcus_bains_set_time_bar_color +void e_day_view_marcus_bains_set_time_bar_color (EDayView *day_view, const gchar *time_bar_color); /* Whether we display event end times in the main canvas. */ -gboolean e_day_view_get_show_event_end_times (EDayView *day_view); -void e_day_view_set_show_event_end_times (EDayView *day_view, - gboolean show); +gboolean e_day_view_get_show_event_end_times + (EDayView *day_view); +void e_day_view_set_show_event_end_times + (EDayView *day_view, + gboolean show); -void e_day_view_delete_occurrence (EDayView *day_view); +void e_day_view_delete_occurrence (EDayView *day_view); /* Returns the number of selected events (0 or 1 at present). */ -gint e_day_view_get_num_events_selected (EDayView *day_view); +gint e_day_view_get_num_events_selected + (EDayView *day_view); /* * Internal functions called by the associated canvas items. */ -void e_day_view_check_layout (EDayView *day_view); -gint e_day_view_convert_time_to_row (EDayView *day_view, - gint hour, - gint minute); -gint e_day_view_convert_time_to_position (EDayView *day_view, - gint hour, - gint minute); -gboolean e_day_view_get_event_rows (EDayView *day_view, +void e_day_view_check_layout (EDayView *day_view); +gint e_day_view_convert_time_to_row (EDayView *day_view, + gint hour, + gint minute); +gint e_day_view_convert_time_to_position + (EDayView *day_view, + gint hour, + gint minute); +gboolean e_day_view_get_event_rows (EDayView *day_view, gint day, gint event_num, gint *start_row_out, gint *end_row_out); -gboolean e_day_view_get_event_position (EDayView *day_view, - gint day, - gint event_num, - gint *item_x, - gint *item_y, - gint *item_w, - gint *item_h); -gboolean e_day_view_get_long_event_position (EDayView *day_view, - gint event_num, - gint *start_day, - gint *end_day, - gint *item_x, - gint *item_y, - gint *item_w, - gint *item_h); - -void e_day_view_start_selection (EDayView *day_view, - gint day, - gint row); -void e_day_view_update_selection (EDayView *day_view, - gint day, - gint row); -void e_day_view_finish_selection (EDayView *day_view); - -void e_day_view_check_auto_scroll (EDayView *day_view, - gint event_x, - gint event_y); -void e_day_view_stop_auto_scroll (EDayView *day_view); - -void e_day_view_convert_time_to_display (EDayView *day_view, - gint hour, - gint *display_hour, - const gchar **suffix, - gint *suffix_width); -gint e_day_view_get_time_string_width (EDayView *day_view); - -gint e_day_view_event_sort_func (const void *arg1, - const void *arg2); - -gboolean e_day_view_find_event_from_item (EDayView *day_view, - GnomeCanvasItem *item, - gint *day_return, - gint *event_num_return); -void e_day_view_update_calendar_selection_time (EDayView *day_view); -void e_day_view_ensure_rows_visible (EDayView *day_view, - gint start_row, - gint end_row); +gboolean e_day_view_get_event_position (EDayView *day_view, + gint day, + gint event_num, + gint *item_x, + gint *item_y, + gint *item_w, + gint *item_h); +gboolean e_day_view_get_long_event_position + (EDayView *day_view, + gint event_num, + gint *start_day, + gint *end_day, + gint *item_x, + gint *item_y, + gint *item_w, + gint *item_h); + +void e_day_view_start_selection (EDayView *day_view, + gint day, + gint row); +void e_day_view_update_selection (EDayView *day_view, + gint day, + gint row); +void e_day_view_finish_selection (EDayView *day_view); + +void e_day_view_check_auto_scroll (EDayView *day_view, + gint event_x, + gint event_y); +void e_day_view_stop_auto_scroll (EDayView *day_view); + +void e_day_view_convert_time_to_display + (EDayView *day_view, + gint hour, + gint *display_hour, + const gchar **suffix, + gint *suffix_width); +gint e_day_view_get_time_string_width + (EDayView *day_view); + +gint e_day_view_event_sort_func (gconstpointer arg1, + gconstpointer arg2); + +gboolean e_day_view_find_event_from_item (EDayView *day_view, + GnomeCanvasItem *item, + gint *day_return, + gint *event_num_return); +void e_day_view_update_calendar_selection_time + (EDayView *day_view); +void e_day_view_ensure_rows_visible (EDayView *day_view, + gint start_row, + gint end_row); G_END_DECLS -#endif /* _E_DAY_VIEW_H_ */ +#endif /* E_DAY_VIEW_H */ -- cgit