1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * EDayView - displays the Day & Work-Week views of the calendar.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * Damon Chaplin <damon@ximian.com>
19 * Rodrigo Moya <rodrigo@ximian.com>
21 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
24 #include "evolution-config.h"
26 #include "e-day-view.h"
31 #include <glib/gi18n.h>
32 #include <gdk/gdkkeysyms.h>
34 #include "libgnomecanvas/libgnomecanvas.h"
36 #include "e-cal-dialogs.h"
37 #include "e-util/e-util.h"
39 #include "calendar-config.h"
40 #include "comp-util.h"
41 #include "e-cal-ops.h"
42 #include "e-cal-model-calendar.h"
43 #include "e-day-view-layout.h"
44 #include "e-day-view-main-item.h"
45 #include "e-day-view-time-item.h"
46 #include "e-day-view-top-item.h"
47 #include "ea-calendar.h"
48 #include "itip-utils.h"
51 #include "ea-day-view.h"
53 #define E_DAY_VIEW_GET_PRIVATE(obj) \
54 (G_TYPE_INSTANCE_GET_PRIVATE \
55 ((obj), E_TYPE_DAY_VIEW, EDayViewPrivate))
57 /* The minimum amount of space wanted on each side of the date string. */
58 #define E_DAY_VIEW_DATE_X_PAD 4
60 #define E_DAY_VIEW_LARGE_FONT_PTSIZE 18
61 #define E_DAY_VIEW_SMALL_FONT_PTSIZE 10
63 /* The offset from the top/bottom of the canvas before auto-scrolling starts.*/
64 #define E_DAY_VIEW_AUTO_SCROLL_OFFSET 16
66 /* The time between each auto-scroll, in milliseconds. */
67 #define E_DAY_VIEW_AUTO_SCROLL_TIMEOUT 50
69 /* The number of timeouts we skip before we start scrolling. */
70 #define E_DAY_VIEW_AUTO_SCROLL_DELAY 5
72 /* The amount we scroll the main canvas when the Page Up/Down keys are pressed,
73 * as a fraction of the page size. */
74 #define E_DAY_VIEW_PAGE_STEP 0.5
76 /* The amount we scroll the main canvas when the mouse wheel buttons are
77 * pressed, as a fraction of the page size. */
78 #define E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE 0.25
80 /* The timeout before we do a layout, so we don't do a layout for each event
81 * we get from the server. */
82 #define E_DAY_VIEW_LAYOUT_TIMEOUT 100
84 /* How many rows can be shown at a top_canvas; there will be always + 2 for
85 * caption item and DnD space */
86 #define E_DAY_VIEW_MAX_ROWS_AT_TOP 6
88 struct _EDayViewPrivate
{
90 gulong notify_work_day_monday_handler_id
;
91 gulong notify_work_day_tuesday_handler_id
;
92 gulong notify_work_day_wednesday_handler_id
;
93 gulong notify_work_day_thursday_handler_id
;
94 gulong notify_work_day_friday_handler_id
;
95 gulong notify_work_day_saturday_handler_id
;
96 gulong notify_work_day_sunday_handler_id
;
97 gulong notify_week_start_day_handler_id
;
98 gulong notify_work_day_start_hour_handler_id
;
99 gulong notify_work_day_start_minute_handler_id
;
100 gulong notify_work_day_end_hour_handler_id
;
101 gulong notify_work_day_end_minute_handler_id
;
102 gulong notify_work_day_start_mon_handler_id
;
103 gulong notify_work_day_end_mon_handler_id
;
104 gulong notify_work_day_start_tue_handler_id
;
105 gulong notify_work_day_end_tue_handler_id
;
106 gulong notify_work_day_start_wed_handler_id
;
107 gulong notify_work_day_end_wed_handler_id
;
108 gulong notify_work_day_start_thu_handler_id
;
109 gulong notify_work_day_end_thu_handler_id
;
110 gulong notify_work_day_start_fri_handler_id
;
111 gulong notify_work_day_end_fri_handler_id
;
112 gulong notify_work_day_start_sat_handler_id
;
113 gulong notify_work_day_end_sat_handler_id
;
114 gulong notify_work_day_start_sun_handler_id
;
115 gulong notify_work_day_end_sun_handler_id
;
116 gulong time_range_changed_handler_id
;
117 gulong model_row_changed_handler_id
;
118 gulong model_cell_changed_handler_id
;
119 gulong model_rows_inserted_handler_id
;
120 gulong comps_deleted_handler_id
;
121 gulong timezone_changed_handler_id
;
123 /* "top_canvas" signal handlers */
124 gulong top_canvas_button_press_event_handler_id
;
125 gulong top_canvas_button_release_event_handler_id
;
126 gulong top_canvas_scroll_event_handler_id
;
127 gulong top_canvas_motion_notify_event_handler_id
;
128 gulong top_canvas_drag_motion_handler_id
;
129 gulong top_canvas_drag_leave_handler_id
;
130 gulong top_canvas_drag_begin_handler_id
;
131 gulong top_canvas_drag_end_handler_id
;
132 gulong top_canvas_drag_data_get_handler_id
;
133 gulong top_canvas_drag_data_received_handler_id
;
135 /* "main_canvas" signal handlers */
136 gulong main_canvas_realize_handler_id
;
137 gulong main_canvas_button_press_event_handler_id
;
138 gulong main_canvas_button_release_event_handler_id
;
139 gulong main_canvas_scroll_event_handler_id
;
140 gulong main_canvas_motion_notify_event_handler_id
;
141 gulong main_canvas_drag_motion_handler_id
;
142 gulong main_canvas_drag_leave_handler_id
;
143 gulong main_canvas_drag_begin_handler_id
;
144 gulong main_canvas_drag_end_handler_id
;
145 gulong main_canvas_drag_data_get_handler_id
;
146 gulong main_canvas_drag_data_received_handler_id
;
148 /* "time_canvas" signal handlers */
149 gulong time_canvas_scroll_event_handler_id
;
151 /* Whether we are showing the work-week view. */
152 gboolean work_week_view
;
154 /* The number of days we are shoing. Usually 1 or 5, but can be
155 * up to E_DAY_VIEW_MAX_DAYS, e.g. when the user selects a range
156 * of days in the date navigator. */
159 /* Work days. Indices are based on GDateWeekday.
160 * The first element (G_DATE_BAD_WEEKDAY) is unused. */
161 gboolean work_days
[G_DATE_SUNDAY
+ 1];
163 /* Whether we show the Marcus Bains Line in the main
164 * canvas and time canvas, and the colors for each. */
165 gboolean marcus_bains_show_line
;
166 gchar
*marcus_bains_day_view_color
;
167 gchar
*marcus_bains_time_bar_color
;
169 GtkWidget
*timezone_name_1_label
; /* not referenced */
170 GtkWidget
*timezone_name_2_label
; /* not referenced */
172 GdkDragContext
*drag_context
;
174 gboolean draw_flat_events
;
179 ECalModelComponent
*comp_data
;
182 /* Drag and Drop stuff. */
183 static GtkTargetEntry target_table
[] = {
184 { (gchar
*) "application/x-e-calendar-event", 0, 0 }
187 static void e_day_view_set_colors (EDayView
*day_view
);
188 static gboolean
e_day_view_update_scroll_regions (EDayView
*day_view
);
189 static gboolean
e_day_view_get_next_tab_event (EDayView
*day_view
,
190 GtkDirectionType direction
,
191 gint
*day
, gint
*event_num
);
192 static gboolean
e_day_view_get_extreme_long_event (EDayView
*day_view
,
195 gint
*event_num_out
);
196 static gboolean
e_day_view_get_extreme_event (EDayView
*day_view
,
201 gint
*event_num_out
);
202 static gboolean
e_day_view_do_key_press (GtkWidget
*widget
,
204 static void e_day_view_update_query (EDayView
*day_view
);
205 static void e_day_view_goto_start_of_work_day (EDayView
*day_view
);
206 static void e_day_view_goto_end_of_work_day (EDayView
*day_view
);
207 static void e_day_view_change_duration_to_start_of_work_day (EDayView
*day_view
);
208 static void e_day_view_change_duration_to_end_of_work_day (EDayView
*day_view
);
209 static void e_day_view_cursor_key_up_shifted (EDayView
*day_view
,
211 static void e_day_view_cursor_key_down_shifted (EDayView
*day_view
,
213 static void e_day_view_cursor_key_left_shifted (EDayView
*day_view
,
215 static void e_day_view_cursor_key_right_shifted (EDayView
*day_view
,
217 static void e_day_view_cursor_key_up (EDayView
*day_view
,
219 static void e_day_view_cursor_key_down (EDayView
*day_view
,
221 static void e_day_view_cursor_key_left (EDayView
*day_view
,
223 static void e_day_view_cursor_key_right (EDayView
*day_view
,
225 static void e_day_view_scroll (EDayView
*day_view
,
226 gfloat pages_to_scroll
);
228 static void e_day_view_top_scroll (EDayView
*day_view
,
229 gfloat pages_to_scroll
);
231 static void e_day_view_update_top_scroll (EDayView
*day_view
, gboolean scroll_to_top
);
233 static void e_day_view_on_canvas_realized (GtkWidget
*widget
,
236 static gboolean
e_day_view_on_top_canvas_button_press (GtkWidget
*widget
,
237 GdkEvent
*button_event
,
239 static gboolean
e_day_view_on_top_canvas_button_release (GtkWidget
*widget
,
240 GdkEvent
*button_event
,
242 static gboolean
e_day_view_on_top_canvas_motion (GtkWidget
*widget
,
243 GdkEventMotion
*event
,
246 static gboolean
e_day_view_on_main_canvas_button_press (GtkWidget
*widget
,
247 GdkEvent
*button_event
,
249 static gboolean
e_day_view_on_main_canvas_button_release (GtkWidget
*widget
,
250 GdkEvent
*button_event
,
253 static gboolean
e_day_view_on_top_canvas_scroll (GtkWidget
*widget
,
254 GdkEventScroll
*scroll
,
257 static gboolean
e_day_view_on_main_canvas_scroll (GtkWidget
*widget
,
258 GdkEventScroll
*scroll
,
260 static gboolean
e_day_view_on_time_canvas_scroll (GtkWidget
*widget
,
261 GdkEventScroll
*scroll
,
263 static gboolean
e_day_view_on_main_canvas_motion (GtkWidget
*widget
,
264 GdkEventMotion
*event
,
266 static gboolean
e_day_view_convert_event_coords (EDayView
*day_view
,
271 static void e_day_view_update_long_event_resize (EDayView
*day_view
,
273 static void e_day_view_update_resize (EDayView
*day_view
,
275 static void e_day_view_finish_long_event_resize (EDayView
*day_view
);
276 static void e_day_view_finish_resize (EDayView
*day_view
);
277 static void e_day_view_abort_resize (EDayView
*day_view
);
279 static gboolean
e_day_view_on_long_event_button_press (EDayView
*day_view
,
281 GdkEvent
*button_event
,
282 ECalendarViewPosition pos
,
285 static gboolean
e_day_view_on_event_button_press (EDayView
*day_view
,
288 GdkEvent
*button_event
,
289 ECalendarViewPosition pos
,
292 static void e_day_view_on_long_event_click (EDayView
*day_view
,
294 GdkEvent
*button_event
,
295 ECalendarViewPosition pos
,
298 static void e_day_view_on_event_click (EDayView
*day_view
,
301 GdkEvent
*button_event
,
302 ECalendarViewPosition pos
,
305 static void e_day_view_on_event_double_click (EDayView
*day_view
,
308 static void e_day_view_on_event_right_click (EDayView
*day_view
,
309 GdkEvent
*button_event
,
312 static void e_day_view_show_popup_menu (EDayView
*day_view
,
313 GdkEvent
*button_event
,
317 static void e_day_view_recalc_day_starts (EDayView
*day_view
,
319 static void e_day_view_recalc_num_rows (EDayView
*day_view
);
320 static void e_day_view_recalc_cell_sizes (EDayView
*day_view
);
322 static ECalendarViewPosition
e_day_view_convert_position_in_top_canvas (EDayView
*day_view
,
326 gint
*event_num_return
);
327 static ECalendarViewPosition
e_day_view_convert_position_in_main_canvas (EDayView
*day_view
,
332 gint
*event_num_return
);
333 static gboolean
e_day_view_find_event_from_uid (EDayView
*day_view
,
338 gint
*event_num_return
);
340 typedef gboolean (* EDayViewForeachEventCallback
) (EDayView
*day_view
,
345 static void e_day_view_foreach_event (EDayView
*day_view
,
346 EDayViewForeachEventCallback callback
,
348 static void e_day_view_foreach_event_with_uid (EDayView
*day_view
,
350 EDayViewForeachEventCallback callback
,
353 static void e_day_view_free_events (EDayView
*day_view
);
354 static void e_day_view_free_event_array (EDayView
*day_view
,
356 static void e_day_view_add_event (ESourceRegistry
*registry
,
362 static void e_day_view_update_event_label (EDayView
*day_view
,
365 static void e_day_view_update_long_event_label (EDayView
*day_view
,
368 static void e_day_view_reshape_long_events (EDayView
*day_view
);
369 static void e_day_view_reshape_long_event (EDayView
*day_view
,
371 static void e_day_view_reshape_day_events (EDayView
*day_view
,
373 static void e_day_view_reshape_day_event (EDayView
*day_view
,
376 static void e_day_view_reshape_main_canvas_resize_bars (EDayView
*day_view
);
378 static void e_day_view_ensure_events_sorted (EDayView
*day_view
);
380 static void e_day_view_start_editing_event (EDayView
*day_view
,
383 GdkEventKey
*key_event
);
384 static void e_day_view_stop_editing_event (EDayView
*day_view
);
385 static void cancel_editing (EDayView
*day_view
);
386 static gboolean
e_day_view_on_text_item_event (GnomeCanvasItem
*item
,
389 static gboolean
e_day_view_event_move (ECalendarView
*cal_view
, ECalViewMoveDirection direction
);
390 static void e_day_view_change_event_time (EDayView
*day_view
, time_t start_dt
,
392 static void e_day_view_change_event_end_time_up (EDayView
*day_view
);
393 static void e_day_view_change_event_end_time_down (EDayView
*day_view
);
394 static void e_day_view_on_editing_started (EDayView
*day_view
,
395 GnomeCanvasItem
*item
);
396 static void e_day_view_on_editing_stopped (EDayView
*day_view
,
397 GnomeCanvasItem
*item
);
399 static time_t e_day_view_convert_grid_position_to_time (EDayView
*day_view
,
402 static gboolean
e_day_view_convert_time_to_grid_position (EDayView
*day_view
,
407 static void e_day_view_start_auto_scroll (EDayView
*day_view
,
409 static gboolean
e_day_view_auto_scroll_handler (gpointer data
);
411 static gboolean
e_day_view_on_top_canvas_drag_motion (GtkWidget
*widget
,
412 GdkDragContext
*context
,
417 static void e_day_view_update_top_canvas_drag (EDayView
*day_view
,
419 static void e_day_view_reshape_top_canvas_drag_item (EDayView
*day_view
);
420 static gboolean
e_day_view_on_main_canvas_drag_motion (GtkWidget
*widget
,
421 GdkDragContext
*context
,
426 static void e_day_view_reshape_main_canvas_drag_item (EDayView
*day_view
);
427 static void e_day_view_update_main_canvas_drag (EDayView
*day_view
,
430 static void e_day_view_on_top_canvas_drag_leave (GtkWidget
*widget
,
431 GdkDragContext
*context
,
434 static void e_day_view_on_main_canvas_drag_leave (GtkWidget
*widget
,
435 GdkDragContext
*context
,
438 static void e_day_view_on_drag_begin (GtkWidget
*widget
,
439 GdkDragContext
*context
,
441 static void e_day_view_on_drag_end (GtkWidget
*widget
,
442 GdkDragContext
*context
,
444 static void e_day_view_on_drag_data_get (GtkWidget
*widget
,
445 GdkDragContext
*context
,
446 GtkSelectionData
*selection_data
,
450 static void e_day_view_on_top_canvas_drag_data_received (GtkWidget
*widget
,
451 GdkDragContext
*context
,
454 GtkSelectionData
*data
,
458 static void e_day_view_on_main_canvas_drag_data_received (GtkWidget
*widget
,
459 GdkDragContext
*context
,
462 GtkSelectionData
*data
,
467 static gboolean
e_day_view_remove_event_cb (EDayView
*day_view
,
471 static void e_day_view_normalize_selection (EDayView
*day_view
);
472 static gboolean
e_day_view_set_show_times_cb (EDayView
*day_view
,
476 static time_t e_day_view_find_work_week_start (EDayView
*day_view
,
478 static void e_day_view_recalc_work_week (EDayView
*day_view
);
479 static void e_day_view_recalc_work_week_days_shown (EDayView
*day_view
);
481 static void e_day_view_precalc_visible_time_range (ECalendarView
*cal_view
,
482 time_t in_start_time
,
484 time_t *out_start_time
,
485 time_t *out_end_time
);
486 static void e_day_view_queue_layout (EDayView
*day_view
);
487 static void e_day_view_cancel_layout (EDayView
*day_view
);
488 static gboolean
e_day_view_layout_timeout_cb (gpointer data
);
489 static void tooltip_destroy (EDayView
*day_view
, GnomeCanvasItem
*item
);
490 static EDayViewEvent
*tooltip_get_view_event (EDayView
*day_view
, gint day
, gint event_num
);
494 PROP_DRAW_FLAT_EVENTS
,
495 PROP_MARCUS_BAINS_SHOW_LINE
,
496 PROP_MARCUS_BAINS_DAY_VIEW_COLOR
,
497 PROP_MARCUS_BAINS_TIME_BAR_COLOR
,
501 G_DEFINE_TYPE (EDayView
, e_day_view
, E_TYPE_CALENDAR_VIEW
)
504 day_view_notify_time_divisions_cb (EDayView
*day_view
)
508 e_day_view_recalc_num_rows (day_view
);
510 /* If we aren't visible, we'll sort it out later. */
511 if (!E_CALENDAR_VIEW (day_view
)->in_focus
) {
512 e_day_view_free_events (day_view
);
513 day_view
->requires_update
= TRUE
;
517 for (day
= 0; day
< E_DAY_VIEW_MAX_DAYS
; day
++)
518 day_view
->need_layout
[day
] = TRUE
;
520 /* We need to update all the day event labels since the start & end
521 * times may or may not be on row boundaries any more. */
522 e_day_view_foreach_event (day_view
,
523 e_day_view_set_show_times_cb
, NULL
);
525 /* We must layout the events before updating the scroll region, since
526 * that will result in a redraw which would crash otherwise. */
527 e_day_view_check_layout (day_view
);
528 gtk_widget_queue_draw (day_view
->time_canvas
);
529 gtk_widget_queue_draw (day_view
->main_canvas
);
531 e_day_view_update_scroll_regions (day_view
);
535 day_view_notify_week_start_day_cb (EDayView
*day_view
)
537 /* FIXME Write an EWorkWeekView subclass, like EMonthView. */
539 if (day_view
->priv
->work_week_view
)
540 e_day_view_recalc_work_week (day_view
);
544 day_view_notify_work_day_cb (ECalModel
*model
,
548 /* FIXME Write an EWorkWeekView subclass, like EMonthView. */
550 if (day_view
->priv
->work_week_view
)
551 e_day_view_recalc_work_week (day_view
);
553 /* We have to do this, as the new working days may have no effect on
554 * the days shown, but we still want the background color to change. */
555 gtk_widget_queue_draw (day_view
->main_canvas
);
559 e_day_view_get_work_day_range_for_day (EDayView
*day_view
,
568 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
569 g_return_if_fail (start_hour
!= NULL
);
570 g_return_if_fail (start_minute
!= NULL
);
571 g_return_if_fail (end_hour
!= NULL
);
572 g_return_if_fail (end_minute
!= NULL
);
574 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
576 if (day
>= 0 && day
< e_day_view_get_days_shown (day_view
)) {
577 GDateWeekday weekday
;
578 struct icaltimetype tt
;
580 tt
= icaltime_from_timet_with_zone (day_view
->day_starts
[day
], FALSE
,
581 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
583 switch (icaltime_day_of_week (tt
)) {
585 weekday
= G_DATE_SUNDAY
;
588 weekday
= G_DATE_MONDAY
;
591 weekday
= G_DATE_TUESDAY
;
594 weekday
= G_DATE_WEDNESDAY
;
597 weekday
= G_DATE_THURSDAY
;
600 weekday
= G_DATE_FRIDAY
;
603 weekday
= G_DATE_SATURDAY
;
606 weekday
= G_DATE_BAD_WEEKDAY
;
610 e_cal_model_get_work_day_range_for (model
, weekday
,
611 start_hour
, start_minute
,
612 end_hour
, end_minute
);
614 *start_hour
= e_cal_model_get_work_day_start_hour (model
);
615 *start_minute
= e_cal_model_get_work_day_start_minute (model
);
616 *end_hour
= e_cal_model_get_work_day_end_hour (model
);
617 *end_minute
= e_cal_model_get_work_day_end_minute (model
);
622 e_day_view_recalc_main_canvas_size (EDayView
*day_view
)
625 gboolean need_reshape
;
627 /* Set the scroll region of the top canvas */
628 e_day_view_update_top_scroll (day_view
, TRUE
);
630 need_reshape
= e_day_view_update_scroll_regions (day_view
);
632 e_day_view_recalc_cell_sizes (day_view
);
634 /* Scroll to the start of the working day, if this is the initial
636 if (day_view
->scroll_to_work_day
) {
637 gint work_day_start_hour
;
638 gint work_day_start_minute
;
639 gint work_day_end_hour
;
640 gint work_day_end_minute
;
642 e_day_view_get_work_day_range_for_day (day_view
, 0,
643 &work_day_start_hour
, &work_day_start_minute
,
644 &work_day_end_hour
, &work_day_end_minute
);
646 scroll_y
= e_day_view_convert_time_to_position (
647 day_view
, work_day_start_hour
, work_day_start_minute
);
648 gnome_canvas_scroll_to (
649 GNOME_CANVAS (day_view
->main_canvas
), 0, scroll_y
);
650 day_view
->scroll_to_work_day
= FALSE
;
653 /* Flag that we need to reshape the events. Note that changes in height
654 * don't matter, since the rows are always the same height. */
656 day_view
->long_events_need_reshape
= TRUE
;
657 for (day
= 0; day
< E_DAY_VIEW_MAX_DAYS
; day
++)
658 day_view
->need_reshape
[day
] = TRUE
;
660 e_day_view_check_layout (day_view
);
665 e_day_view_get_text_color (EDayView
*day_view
,
666 EDayViewEvent
*event
)
671 if (is_comp_data_valid (event
) &&
672 e_cal_model_get_rgba_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
)), event
->comp_data
, &rgba
)) {
674 gdouble cc
= 65535.0;
676 rgba
.red
= day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BACKGROUND
].red
/ cc
;
677 rgba
.green
= day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BACKGROUND
].green
/ cc
;
678 rgba
.blue
= day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BACKGROUND
].blue
/ cc
;
682 if ((rgba
.red
> 0.7) || (rgba
.green
> 0.7) || (rgba
.blue
> 0.7)) {
687 color
.red
= 65535.0f
;
688 color
.green
= 65535.0f
;
689 color
.blue
= 65535.0f
;
697 /* Returns the selected time range. */
699 day_view_get_selected_time_range (ECalendarView
*cal_view
,
703 gint start_col
, start_row
, end_col
, end_row
;
705 EDayView
*day_view
= E_DAY_VIEW (cal_view
);
707 start_col
= day_view
->selection_start_day
;
708 start_row
= day_view
->selection_start_row
;
709 end_col
= day_view
->selection_end_day
;
710 end_row
= day_view
->selection_end_row
;
712 if (start_col
== -1) {
719 /* Check if the selection is only in the top canvas, in which case
720 * we can simply use the day_starts array. */
721 if (day_view
->selection_in_top_canvas
) {
722 start
= day_view
->day_starts
[start_col
];
723 end
= day_view
->day_starts
[end_col
+ 1];
725 /* Convert the start col + row into a time. */
726 start
= e_day_view_convert_grid_position_to_time (day_view
, start_col
, start_row
);
727 end
= e_day_view_convert_grid_position_to_time (day_view
, end_col
, end_row
+ 1);
741 GdkEventKey
*key_event
;
742 time_t dtstart
, dtend
;
743 gboolean in_top_canvas
;
744 gboolean paste_clipboard
;
745 } NewEventInRangeData
;
748 new_event_in_rage_data_free (gpointer ptr
)
750 NewEventInRangeData
*ned
= ptr
;
753 g_clear_object (&ned
->day_view
);
754 g_free (ned
->key_event
);
760 day_view_new_event_in_selected_range_cb (ECalModel
*model
,
762 icalcomponent
*default_component
,
765 NewEventInRangeData
*ned
= user_data
;
766 ECalComponent
*comp
= NULL
;
768 ECalComponentDateTime start_dt
, end_dt
;
769 struct icaltimetype start_tt
, end_tt
;
771 AddEventData add_event_data
;
772 ESourceRegistry
*registry
;
775 g_return_if_fail (ned
!= NULL
);
776 g_return_if_fail (E_IS_CAL_MODEL (model
));
777 g_return_if_fail (E_IS_CAL_CLIENT (client
));
778 g_return_if_fail (default_component
!= NULL
);
780 /* Check if the client is read only */
781 if (e_client_is_readonly (E_CLIENT (client
)))
784 registry
= e_cal_model_get_registry (model
);
785 zone
= e_cal_model_get_timezone (model
);
786 uid
= icalcomponent_get_uid (default_component
);
788 comp
= e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (default_component
));
789 g_return_if_fail (comp
!= NULL
);
791 start_tt
= icaltime_from_timet_with_zone (ned
->dtstart
, FALSE
, zone
);
792 end_tt
= icaltime_from_timet_with_zone (ned
->dtend
, FALSE
, zone
);
794 if (ned
->in_top_canvas
) {
795 start_dt
.tzid
= NULL
;
796 start_tt
.is_date
= 1;
799 /* Editor default in day/work-week view - top canvas */
800 e_cal_component_set_transparency (comp
, E_CAL_COMPONENT_TRANSP_TRANSPARENT
);
802 start_dt
.tzid
= icaltimezone_get_tzid (zone
);
804 /* Editor default in day/work-week view - main canvas */
805 e_cal_component_set_transparency (comp
, E_CAL_COMPONENT_TRANSP_OPAQUE
);
808 start_dt
.value
= &start_tt
;
809 end_dt
.value
= &end_tt
;
810 end_dt
.tzid
= start_dt
.tzid
;
811 e_cal_component_set_dtstart (comp
, &start_dt
);
812 e_cal_component_set_dtend (comp
, &end_dt
);
814 /* We add the event locally and start editing it. We don't send it
815 * to the server until the user finishes editing it. */
816 add_event_data
.day_view
= ned
->day_view
;
817 add_event_data
.comp_data
= NULL
;
818 e_day_view_add_event (registry
, client
, comp
, ned
->dtstart
, ned
->dtend
, &add_event_data
);
819 e_day_view_check_layout (ned
->day_view
);
820 gtk_widget_queue_draw (ned
->day_view
->top_canvas
);
821 gtk_widget_queue_draw (ned
->day_view
->main_canvas
);
823 if (!e_day_view_find_event_from_uid (ned
->day_view
, client
, uid
, NULL
, &day
, &event_num
)) {
824 g_warning ("Couldn't find event to start editing.\n");
826 e_day_view_start_editing_event (ned
->day_view
, day
, event_num
, ned
->key_event
);
828 if (ned
->paste_clipboard
) {
829 EDayViewEvent
*event
;
831 g_clear_object (&comp
);
833 if (ned
->day_view
->editing_event_day
== E_DAY_VIEW_LONG_EVENT
) {
834 if (!is_array_index_in_bounds (ned
->day_view
->long_events
, ned
->day_view
->editing_event_num
))
837 event
= &g_array_index (ned
->day_view
->long_events
,
839 ned
->day_view
->editing_event_num
);
841 if (!is_array_index_in_bounds (ned
->day_view
->events
[ned
->day_view
->editing_event_day
], ned
->day_view
->editing_event_num
))
844 event
= &g_array_index (ned
->day_view
->events
[ned
->day_view
->editing_event_day
],
846 ned
->day_view
->editing_event_num
);
849 if (event
->canvas_item
&&
850 E_IS_TEXT (event
->canvas_item
) &&
851 E_TEXT (event
->canvas_item
)->editing
) {
852 e_text_paste_clipboard (E_TEXT (event
->canvas_item
));
858 g_clear_object (&comp
);
862 e_day_view_add_new_event_in_selected_range (EDayView
*day_view
,
863 GdkEventKey
*key_event
,
864 gboolean paste_clipboard
)
866 NewEventInRangeData
*ned
;
868 const gchar
*source_uid
;
870 ned
= g_new0 (NewEventInRangeData
, 1);
871 ned
->day_view
= g_object_ref (day_view
);
873 ned
->key_event
= g_new0 (GdkEventKey
, 1);
874 *ned
->key_event
= *key_event
;
876 day_view_get_selected_time_range (E_CALENDAR_VIEW (day_view
), &ned
->dtstart
, &ned
->dtend
);
877 ned
->in_top_canvas
= day_view
->selection_in_top_canvas
;
878 ned
->paste_clipboard
= paste_clipboard
;
880 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
881 source_uid
= e_cal_model_get_default_source_uid (model
);
883 e_cal_ops_get_default_component (model
, source_uid
, ned
->in_top_canvas
,
884 day_view_new_event_in_selected_range_cb
, ned
, new_event_in_rage_data_free
);
888 day_view_set_property (GObject
*object
,
893 switch (property_id
) {
894 case PROP_DRAW_FLAT_EVENTS
:
895 e_day_view_set_draw_flat_events (
897 g_value_get_boolean (value
));
900 case PROP_MARCUS_BAINS_SHOW_LINE
:
901 e_day_view_marcus_bains_set_show_line (
903 g_value_get_boolean (value
));
906 case PROP_MARCUS_BAINS_DAY_VIEW_COLOR
:
907 e_day_view_marcus_bains_set_day_view_color (
909 g_value_get_string (value
));
912 case PROP_MARCUS_BAINS_TIME_BAR_COLOR
:
913 e_day_view_marcus_bains_set_time_bar_color (
915 g_value_get_string (value
));
919 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
923 day_view_get_property (GObject
*object
,
928 switch (property_id
) {
929 case PROP_DRAW_FLAT_EVENTS
:
930 g_value_set_boolean (
932 e_day_view_get_draw_flat_events (
933 E_DAY_VIEW (object
)));
936 case PROP_MARCUS_BAINS_SHOW_LINE
:
937 g_value_set_boolean (
939 e_day_view_marcus_bains_get_show_line (
940 E_DAY_VIEW (object
)));
943 case PROP_MARCUS_BAINS_DAY_VIEW_COLOR
:
946 e_day_view_marcus_bains_get_day_view_color (
947 E_DAY_VIEW (object
)));
950 case PROP_MARCUS_BAINS_TIME_BAR_COLOR
:
953 e_day_view_marcus_bains_get_time_bar_color (
954 E_DAY_VIEW (object
)));
957 case PROP_IS_EDITING
:
958 g_value_set_boolean (value
, e_day_view_is_editing (E_DAY_VIEW (object
)));
962 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
966 day_view_dispose (GObject
*object
)
971 day_view
= E_DAY_VIEW (object
);
973 e_day_view_cancel_layout (day_view
);
975 e_day_view_stop_auto_scroll (day_view
);
977 if (day_view
->large_font_desc
) {
978 pango_font_description_free (day_view
->large_font_desc
);
979 day_view
->large_font_desc
= NULL
;
982 if (day_view
->small_font_desc
) {
983 pango_font_description_free (day_view
->small_font_desc
);
984 day_view
->small_font_desc
= NULL
;
987 if (day_view
->normal_cursor
) {
988 g_object_unref (day_view
->normal_cursor
);
989 day_view
->normal_cursor
= NULL
;
991 if (day_view
->move_cursor
) {
992 g_object_unref (day_view
->move_cursor
);
993 day_view
->move_cursor
= NULL
;
995 if (day_view
->resize_width_cursor
) {
996 g_object_unref (day_view
->resize_width_cursor
);
997 day_view
->resize_width_cursor
= NULL
;
999 if (day_view
->resize_height_cursor
) {
1000 g_object_unref (day_view
->resize_height_cursor
);
1001 day_view
->resize_height_cursor
= NULL
;
1004 if (day_view
->long_events
) {
1005 e_day_view_free_events (day_view
);
1006 g_array_free (day_view
->long_events
, TRUE
);
1007 day_view
->long_events
= NULL
;
1010 for (day
= 0; day
< E_DAY_VIEW_MAX_DAYS
; day
++) {
1011 if (day_view
->events
[day
]) {
1012 g_array_free (day_view
->events
[day
], TRUE
);
1013 day_view
->events
[day
] = NULL
;
1017 if (day_view
->grabbed_pointer
!= NULL
) {
1019 day_view
->grabbed_pointer
,
1021 g_object_unref (day_view
->grabbed_pointer
);
1022 day_view
->grabbed_pointer
= NULL
;
1025 #define disconnect_model_handler(x) G_STMT_START { \
1027 g_signal_handler_disconnect (day_view->priv->model, (x)); \
1032 disconnect_model_handler (day_view
->priv
->notify_work_day_monday_handler_id
);
1033 disconnect_model_handler (day_view
->priv
->notify_work_day_tuesday_handler_id
);
1034 disconnect_model_handler (day_view
->priv
->notify_work_day_wednesday_handler_id
);
1035 disconnect_model_handler (day_view
->priv
->notify_work_day_thursday_handler_id
);
1036 disconnect_model_handler (day_view
->priv
->notify_work_day_friday_handler_id
);
1037 disconnect_model_handler (day_view
->priv
->notify_work_day_saturday_handler_id
);
1038 disconnect_model_handler (day_view
->priv
->notify_work_day_sunday_handler_id
);
1039 disconnect_model_handler (day_view
->priv
->notify_week_start_day_handler_id
);
1040 disconnect_model_handler (day_view
->priv
->notify_work_day_start_hour_handler_id
);
1041 disconnect_model_handler (day_view
->priv
->notify_work_day_start_minute_handler_id
);
1042 disconnect_model_handler (day_view
->priv
->notify_work_day_end_hour_handler_id
);
1043 disconnect_model_handler (day_view
->priv
->notify_work_day_end_minute_handler_id
);
1044 disconnect_model_handler (day_view
->priv
->notify_work_day_start_mon_handler_id
);
1045 disconnect_model_handler (day_view
->priv
->notify_work_day_end_mon_handler_id
);
1046 disconnect_model_handler (day_view
->priv
->notify_work_day_start_tue_handler_id
);
1047 disconnect_model_handler (day_view
->priv
->notify_work_day_end_tue_handler_id
);
1048 disconnect_model_handler (day_view
->priv
->notify_work_day_start_wed_handler_id
);
1049 disconnect_model_handler (day_view
->priv
->notify_work_day_end_wed_handler_id
);
1050 disconnect_model_handler (day_view
->priv
->notify_work_day_start_thu_handler_id
);
1051 disconnect_model_handler (day_view
->priv
->notify_work_day_end_thu_handler_id
);
1052 disconnect_model_handler (day_view
->priv
->notify_work_day_start_fri_handler_id
);
1053 disconnect_model_handler (day_view
->priv
->notify_work_day_end_fri_handler_id
);
1054 disconnect_model_handler (day_view
->priv
->notify_work_day_start_sat_handler_id
);
1055 disconnect_model_handler (day_view
->priv
->notify_work_day_end_sat_handler_id
);
1056 disconnect_model_handler (day_view
->priv
->notify_work_day_start_sun_handler_id
);
1057 disconnect_model_handler (day_view
->priv
->notify_work_day_end_sun_handler_id
);
1058 disconnect_model_handler (day_view
->priv
->time_range_changed_handler_id
);
1059 disconnect_model_handler (day_view
->priv
->model_row_changed_handler_id
);
1060 disconnect_model_handler (day_view
->priv
->model_cell_changed_handler_id
);
1061 disconnect_model_handler (day_view
->priv
->model_rows_inserted_handler_id
);
1062 disconnect_model_handler (day_view
->priv
->comps_deleted_handler_id
);
1063 disconnect_model_handler (day_view
->priv
->timezone_changed_handler_id
);
1065 #undef disconnect_model_handler
1067 if (day_view
->priv
->top_canvas_button_press_event_handler_id
> 0) {
1068 g_signal_handler_disconnect (
1069 day_view
->top_canvas
,
1070 day_view
->priv
->top_canvas_button_press_event_handler_id
);
1071 day_view
->priv
->top_canvas_button_press_event_handler_id
= 0;
1074 if (day_view
->priv
->top_canvas_button_release_event_handler_id
> 0) {
1075 g_signal_handler_disconnect (
1076 day_view
->top_canvas
,
1077 day_view
->priv
->top_canvas_button_release_event_handler_id
);
1078 day_view
->priv
->top_canvas_button_release_event_handler_id
= 0;
1081 if (day_view
->priv
->top_canvas_scroll_event_handler_id
> 0) {
1082 g_signal_handler_disconnect (
1083 day_view
->top_canvas
,
1084 day_view
->priv
->top_canvas_scroll_event_handler_id
);
1085 day_view
->priv
->top_canvas_scroll_event_handler_id
= 0;
1088 if (day_view
->priv
->top_canvas_motion_notify_event_handler_id
> 0) {
1089 g_signal_handler_disconnect (
1090 day_view
->top_canvas
,
1091 day_view
->priv
->top_canvas_motion_notify_event_handler_id
);
1092 day_view
->priv
->top_canvas_motion_notify_event_handler_id
= 0;
1095 if (day_view
->priv
->top_canvas_drag_motion_handler_id
> 0) {
1096 g_signal_handler_disconnect (
1097 day_view
->top_canvas
,
1098 day_view
->priv
->top_canvas_drag_motion_handler_id
);
1099 day_view
->priv
->top_canvas_drag_motion_handler_id
= 0;
1102 if (day_view
->priv
->top_canvas_drag_leave_handler_id
> 0) {
1103 g_signal_handler_disconnect (
1104 day_view
->top_canvas
,
1105 day_view
->priv
->top_canvas_drag_leave_handler_id
);
1106 day_view
->priv
->top_canvas_drag_leave_handler_id
= 0;
1109 if (day_view
->priv
->top_canvas_drag_begin_handler_id
> 0) {
1110 g_signal_handler_disconnect (
1111 day_view
->top_canvas
,
1112 day_view
->priv
->top_canvas_drag_begin_handler_id
);
1113 day_view
->priv
->top_canvas_drag_begin_handler_id
= 0;
1116 if (day_view
->priv
->top_canvas_drag_end_handler_id
> 0) {
1117 g_signal_handler_disconnect (
1118 day_view
->top_canvas
,
1119 day_view
->priv
->top_canvas_drag_end_handler_id
);
1120 day_view
->priv
->top_canvas_drag_end_handler_id
= 0;
1123 if (day_view
->priv
->top_canvas_drag_data_get_handler_id
> 0) {
1124 g_signal_handler_disconnect (
1125 day_view
->top_canvas
,
1126 day_view
->priv
->top_canvas_drag_data_get_handler_id
);
1127 day_view
->priv
->top_canvas_drag_data_get_handler_id
= 0;
1130 if (day_view
->priv
->top_canvas_drag_data_received_handler_id
> 0) {
1131 g_signal_handler_disconnect (
1132 day_view
->top_canvas
,
1133 day_view
->priv
->top_canvas_drag_data_received_handler_id
);
1134 day_view
->priv
->top_canvas_drag_data_received_handler_id
= 0;
1137 if (day_view
->priv
->main_canvas_realize_handler_id
> 0) {
1138 g_signal_handler_disconnect (
1139 day_view
->main_canvas
,
1140 day_view
->priv
->main_canvas_realize_handler_id
);
1141 day_view
->priv
->main_canvas_realize_handler_id
= 0;
1144 if (day_view
->priv
->main_canvas_button_press_event_handler_id
> 0) {
1145 g_signal_handler_disconnect (
1146 day_view
->main_canvas
,
1147 day_view
->priv
->main_canvas_button_press_event_handler_id
);
1148 day_view
->priv
->main_canvas_button_press_event_handler_id
= 0;
1151 if (day_view
->priv
->main_canvas_button_release_event_handler_id
> 0) {
1152 g_signal_handler_disconnect (
1153 day_view
->main_canvas
,
1154 day_view
->priv
->main_canvas_button_release_event_handler_id
);
1155 day_view
->priv
->main_canvas_button_release_event_handler_id
= 0;
1158 if (day_view
->priv
->main_canvas_scroll_event_handler_id
> 0) {
1159 g_signal_handler_disconnect (
1160 day_view
->main_canvas
,
1161 day_view
->priv
->main_canvas_scroll_event_handler_id
);
1162 day_view
->priv
->main_canvas_scroll_event_handler_id
= 0;
1165 if (day_view
->priv
->main_canvas_motion_notify_event_handler_id
> 0) {
1166 g_signal_handler_disconnect (
1167 day_view
->main_canvas
,
1168 day_view
->priv
->main_canvas_motion_notify_event_handler_id
);
1169 day_view
->priv
->main_canvas_motion_notify_event_handler_id
= 0;
1172 if (day_view
->priv
->main_canvas_drag_motion_handler_id
> 0) {
1173 g_signal_handler_disconnect (
1174 day_view
->main_canvas
,
1175 day_view
->priv
->main_canvas_drag_motion_handler_id
);
1176 day_view
->priv
->main_canvas_drag_motion_handler_id
= 0;
1179 if (day_view
->priv
->main_canvas_drag_leave_handler_id
> 0) {
1180 g_signal_handler_disconnect (
1181 day_view
->main_canvas
,
1182 day_view
->priv
->main_canvas_drag_leave_handler_id
);
1183 day_view
->priv
->main_canvas_drag_leave_handler_id
= 0;
1186 if (day_view
->priv
->main_canvas_drag_begin_handler_id
> 0) {
1187 g_signal_handler_disconnect (
1188 day_view
->main_canvas
,
1189 day_view
->priv
->main_canvas_drag_begin_handler_id
);
1190 day_view
->priv
->main_canvas_drag_begin_handler_id
= 0;
1193 if (day_view
->priv
->main_canvas_drag_end_handler_id
> 0) {
1194 g_signal_handler_disconnect (
1195 day_view
->main_canvas
,
1196 day_view
->priv
->main_canvas_drag_end_handler_id
);
1197 day_view
->priv
->main_canvas_drag_end_handler_id
= 0;
1200 if (day_view
->priv
->main_canvas_drag_data_get_handler_id
> 0) {
1201 g_signal_handler_disconnect (
1202 day_view
->main_canvas
,
1203 day_view
->priv
->main_canvas_drag_data_get_handler_id
);
1204 day_view
->priv
->main_canvas_drag_data_get_handler_id
= 0;
1207 if (day_view
->priv
->main_canvas_drag_data_received_handler_id
> 0) {
1208 g_signal_handler_disconnect (
1209 day_view
->main_canvas
,
1210 day_view
->priv
->main_canvas_drag_data_received_handler_id
);
1211 day_view
->priv
->main_canvas_drag_data_received_handler_id
= 0;
1214 if (day_view
->priv
->time_canvas_scroll_event_handler_id
> 0) {
1215 g_signal_handler_disconnect (
1216 day_view
->time_canvas
,
1217 day_view
->priv
->time_canvas_scroll_event_handler_id
);
1218 day_view
->priv
->time_canvas_scroll_event_handler_id
= 0;
1221 g_clear_object (&day_view
->top_canvas
);
1222 g_clear_object (&day_view
->main_canvas
);
1223 g_clear_object (&day_view
->time_canvas
);
1224 g_clear_object (&day_view
->priv
->model
);
1225 g_clear_object (&day_view
->priv
->drag_context
);
1227 g_free (day_view
->priv
->marcus_bains_day_view_color
);
1228 day_view
->priv
->marcus_bains_day_view_color
= NULL
;
1230 g_free (day_view
->priv
->marcus_bains_time_bar_color
);
1231 day_view
->priv
->marcus_bains_time_bar_color
= NULL
;
1233 /* Chain up to parent's dispose() method. */
1234 G_OBJECT_CLASS (e_day_view_parent_class
)->dispose (object
);
1238 day_view_notify (GObject
*object
,
1241 /* Don't chain up. None of our parent classes, not
1242 * even GObjectClass itself, implements this method. */
1244 if (g_str_equal (pspec
->name
, "time-divisions"))
1245 day_view_notify_time_divisions_cb (E_DAY_VIEW (object
));
1249 day_view_constructed (GObject
*object
)
1255 day_view
= E_DAY_VIEW (object
);
1257 /* Chain up to parent's constructed() method. */
1258 G_OBJECT_CLASS (e_day_view_parent_class
)->constructed (object
);
1260 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
1262 /* Keep our own model reference so we can
1263 * disconnect signal handlers in dispose(). */
1264 day_view
->priv
->model
= g_object_ref (model
);
1266 handler_id
= e_signal_connect_notify (
1267 model
, "notify::work-day-monday",
1268 G_CALLBACK (day_view_notify_work_day_cb
), day_view
);
1269 day_view
->priv
->notify_work_day_monday_handler_id
= handler_id
;
1271 handler_id
= e_signal_connect_notify (
1272 model
, "notify::work-day-tuesday",
1273 G_CALLBACK (day_view_notify_work_day_cb
), day_view
);
1274 day_view
->priv
->notify_work_day_tuesday_handler_id
= handler_id
;
1276 handler_id
= e_signal_connect_notify (
1277 model
, "notify::work-day-wednesday",
1278 G_CALLBACK (day_view_notify_work_day_cb
), day_view
);
1279 day_view
->priv
->notify_work_day_wednesday_handler_id
= handler_id
;
1281 handler_id
= e_signal_connect_notify (
1282 model
, "notify::work-day-thursday",
1283 G_CALLBACK (day_view_notify_work_day_cb
), day_view
);
1284 day_view
->priv
->notify_work_day_thursday_handler_id
= handler_id
;
1286 handler_id
= e_signal_connect_notify (
1287 model
, "notify::work-day-friday",
1288 G_CALLBACK (day_view_notify_work_day_cb
), day_view
);
1289 day_view
->priv
->notify_work_day_friday_handler_id
= handler_id
;
1291 handler_id
= e_signal_connect_notify (
1292 model
, "notify::work-day-saturday",
1293 G_CALLBACK (day_view_notify_work_day_cb
), day_view
);
1294 day_view
->priv
->notify_work_day_saturday_handler_id
= handler_id
;
1296 handler_id
= e_signal_connect_notify (
1297 model
, "notify::work-day-sunday",
1298 G_CALLBACK (day_view_notify_work_day_cb
), day_view
);
1299 day_view
->priv
->notify_work_day_sunday_handler_id
= handler_id
;
1301 handler_id
= e_signal_connect_notify_swapped (
1302 model
, "notify::week-start-day",
1303 G_CALLBACK (day_view_notify_week_start_day_cb
), day_view
);
1304 day_view
->priv
->notify_week_start_day_handler_id
= handler_id
;
1306 handler_id
= e_signal_connect_notify_swapped (
1307 model
, "notify::work-day-start-hour",
1308 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1309 day_view
->priv
->notify_work_day_start_hour_handler_id
= handler_id
;
1311 handler_id
= e_signal_connect_notify_swapped (
1312 model
, "notify::work-day-start-minute",
1313 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1314 day_view
->priv
->notify_work_day_start_minute_handler_id
= handler_id
;
1316 handler_id
= e_signal_connect_notify_swapped (
1317 model
, "notify::work-day-end-hour",
1318 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1319 day_view
->priv
->notify_work_day_end_hour_handler_id
= handler_id
;
1321 handler_id
= e_signal_connect_notify_swapped (
1322 model
, "notify::work-day-end-minute",
1323 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1324 day_view
->priv
->notify_work_day_end_minute_handler_id
= handler_id
;
1326 handler_id
= e_signal_connect_notify_swapped (
1327 model
, "notify::work-day-start-mon",
1328 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1329 day_view
->priv
->notify_work_day_start_mon_handler_id
= handler_id
;
1331 handler_id
= e_signal_connect_notify_swapped (
1332 model
, "notify::work-day-end-mon",
1333 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1334 day_view
->priv
->notify_work_day_end_mon_handler_id
= handler_id
;
1336 handler_id
= e_signal_connect_notify_swapped (
1337 model
, "notify::work-day-start-tue",
1338 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1339 day_view
->priv
->notify_work_day_start_tue_handler_id
= handler_id
;
1341 handler_id
= e_signal_connect_notify_swapped (
1342 model
, "notify::work-day-end-tue",
1343 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1344 day_view
->priv
->notify_work_day_end_tue_handler_id
= handler_id
;
1346 handler_id
= e_signal_connect_notify_swapped (
1347 model
, "notify::work-day-start-wed",
1348 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1349 day_view
->priv
->notify_work_day_start_wed_handler_id
= handler_id
;
1351 handler_id
= e_signal_connect_notify_swapped (
1352 model
, "notify::work-day-end-wed",
1353 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1354 day_view
->priv
->notify_work_day_end_wed_handler_id
= handler_id
;
1356 handler_id
= e_signal_connect_notify_swapped (
1357 model
, "notify::work-day-start-thu",
1358 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1359 day_view
->priv
->notify_work_day_start_thu_handler_id
= handler_id
;
1361 handler_id
= e_signal_connect_notify_swapped (
1362 model
, "notify::work-day-end-thu",
1363 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1364 day_view
->priv
->notify_work_day_end_thu_handler_id
= handler_id
;
1366 handler_id
= e_signal_connect_notify_swapped (
1367 model
, "notify::work-day-start-fri",
1368 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1369 day_view
->priv
->notify_work_day_start_fri_handler_id
= handler_id
;
1371 handler_id
= e_signal_connect_notify_swapped (
1372 model
, "notify::work-day-end-fri",
1373 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1374 day_view
->priv
->notify_work_day_end_fri_handler_id
= handler_id
;
1376 handler_id
= e_signal_connect_notify_swapped (
1377 model
, "notify::work-day-start-sat",
1378 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1379 day_view
->priv
->notify_work_day_start_sat_handler_id
= handler_id
;
1381 handler_id
= e_signal_connect_notify_swapped (
1382 model
, "notify::work-day-end-sat",
1383 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1384 day_view
->priv
->notify_work_day_end_sat_handler_id
= handler_id
;
1386 handler_id
= e_signal_connect_notify_swapped (
1387 model
, "notify::work-day-start-sun",
1388 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1389 day_view
->priv
->notify_work_day_start_sun_handler_id
= handler_id
;
1391 handler_id
= e_signal_connect_notify_swapped (
1392 model
, "notify::work-day-end-sun",
1393 G_CALLBACK (gtk_widget_queue_draw
), day_view
->main_canvas
);
1394 day_view
->priv
->notify_work_day_end_sun_handler_id
= handler_id
;
1396 e_day_view_update_timezone_name_labels (day_view
);
1400 day_view_update_style_settings (EDayView
*day_view
)
1403 gint minute
, max_minute_width
, i
;
1404 gint month
, day
, width
;
1405 gint longest_month_width
, longest_abbreviated_month_width
;
1406 gint longest_weekday_width
, longest_abbreviated_weekday_width
;
1410 PangoFontDescription
*font_desc
;
1411 PangoContext
*pango_context
;
1412 PangoFontMetrics
*font_metrics
;
1413 PangoLayout
*layout
;
1414 gint week_day
, event_num
;
1415 GtkAdjustment
*adjustment
;
1416 EDayViewEvent
*event
;
1419 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
1421 e_day_view_set_colors (day_view
);
1423 for (week_day
= 0; week_day
< E_DAY_VIEW_MAX_DAYS
; week_day
++) {
1424 for (event_num
= 0; event_num
< day_view
->events
[week_day
]->len
; event_num
++) {
1425 event
= &g_array_index (day_view
->events
[week_day
], EDayViewEvent
, event_num
);
1426 if (event
->canvas_item
) {
1427 color
= e_day_view_get_text_color (day_view
, event
);
1428 gnome_canvas_item_set (
1430 "fill_color_gdk", &color
,
1435 for (event_num
= 0; event_num
< day_view
->long_events
->len
; event_num
++) {
1436 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
, event_num
);
1437 if (event
->canvas_item
) {
1438 color
= e_day_view_get_text_color (day_view
, event
);
1439 gnome_canvas_item_set (
1441 "fill_color_gdk", &color
,
1446 /* Set up Pango prerequisites */
1447 pango_context
= gtk_widget_get_pango_context (GTK_WIDGET (day_view
));
1448 font_desc
= pango_context_get_font_description (pango_context
);
1449 font_metrics
= pango_context_get_metrics (
1450 pango_context
, font_desc
,
1451 pango_context_get_language (pango_context
));
1452 layout
= pango_layout_new (pango_context
);
1454 /* Create the large font. */
1455 if (day_view
->large_font_desc
!= NULL
)
1456 pango_font_description_free (day_view
->large_font_desc
);
1458 day_view
->large_font_desc
= pango_font_description_copy (font_desc
);
1459 pango_font_description_set_size (
1460 day_view
->large_font_desc
,
1461 E_DAY_VIEW_LARGE_FONT_PTSIZE
* PANGO_SCALE
);
1463 /* Create the small fonts. */
1464 if (day_view
->small_font_desc
!= NULL
)
1465 pango_font_description_free (day_view
->small_font_desc
);
1467 day_view
->small_font_desc
= pango_font_description_copy (font_desc
);
1468 pango_font_description_set_size (
1469 day_view
->small_font_desc
,
1470 E_DAY_VIEW_SMALL_FONT_PTSIZE
* PANGO_SCALE
);
1472 /* Recalculate the height of each row based on the font size. */
1473 day_view
->row_height
=
1474 PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics
)) +
1475 PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics
)) +
1476 E_DAY_VIEW_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_EVENT_Y_PAD
* 2 + 2 /* FIXME */;
1477 day_view
->row_height
= MAX (
1478 day_view
->row_height
,
1479 E_DAY_VIEW_ICON_HEIGHT
+ E_DAY_VIEW_ICON_Y_PAD
+ 2);
1481 adjustment
= gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (day_view
->main_canvas
));
1482 gtk_adjustment_set_step_increment (adjustment
, day_view
->row_height
);
1484 day_view
->top_row_height
=
1485 PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics
)) +
1486 PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics
)) +
1487 E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT
* 2 + E_DAY_VIEW_LONG_EVENT_Y_PAD
* 2 +
1488 E_DAY_VIEW_TOP_CANVAS_Y_GAP
;
1489 day_view
->top_row_height
=
1491 day_view
->top_row_height
,
1492 E_DAY_VIEW_ICON_HEIGHT
+ E_DAY_VIEW_ICON_Y_PAD
+ 2 +
1493 E_DAY_VIEW_TOP_CANVAS_Y_GAP
);
1495 adjustment
= gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (day_view
->top_canvas
));
1496 gtk_adjustment_set_step_increment (adjustment
, day_view
->top_row_height
);
1497 gtk_widget_set_size_request (day_view
->top_dates_canvas
, -1, day_view
->top_row_height
- 2);
1499 e_day_view_update_top_scroll (day_view
, TRUE
);
1501 /* Find the longest full & abbreviated month names. */
1502 longest_month_width
= 0;
1503 longest_abbreviated_month_width
= 0;
1504 for (month
= 0; month
< 12; month
++) {
1505 name
= e_get_month_name (month
+ 1, FALSE
);
1506 pango_layout_set_text (layout
, name
, -1);
1507 pango_layout_get_pixel_size (layout
, &width
, NULL
);
1509 if (width
> longest_month_width
) {
1510 longest_month_width
= width
;
1511 day_view
->longest_month_name
= month
;
1514 name
= e_get_month_name (month
+ 1, TRUE
);
1515 pango_layout_set_text (layout
, name
, -1);
1516 pango_layout_get_pixel_size (layout
, &width
, NULL
);
1518 if (width
> longest_abbreviated_month_width
) {
1519 longest_abbreviated_month_width
= width
;
1520 day_view
->longest_abbreviated_month_name
= month
;
1524 /* Find the longest full & abbreviated weekday names. */
1525 longest_weekday_width
= 0;
1526 longest_abbreviated_weekday_width
= 0;
1527 for (day
= 0; day
< 7; day
++) {
1528 name
= e_get_weekday_name (day
+ 1, FALSE
);
1529 pango_layout_set_text (layout
, name
, -1);
1530 pango_layout_get_pixel_size (layout
, &width
, NULL
);
1532 if (width
> longest_weekday_width
) {
1533 longest_weekday_width
= width
;
1534 day_view
->longest_weekday_name
= day
;
1537 name
= e_get_weekday_name (day
+ 1, TRUE
);
1538 pango_layout_set_text (layout
, name
, -1);
1539 pango_layout_get_pixel_size (layout
, &width
, NULL
);
1541 if (width
> longest_abbreviated_weekday_width
) {
1542 longest_abbreviated_weekday_width
= width
;
1543 day_view
->longest_abbreviated_weekday_name
= day
;
1547 /* Calculate the widths of all the time strings necessary. */
1548 day_view
->max_small_hour_width
= 0;
1549 for (hour
= 0; hour
< 24; hour
++) {
1550 g_snprintf (buffer
, sizeof (buffer
), "%02i", hour
);
1551 pango_layout_set_text (layout
, buffer
, -1);
1552 pango_layout_get_pixel_size (layout
, &day_view
->small_hour_widths
[hour
], NULL
);
1554 day_view
->max_small_hour_width
= MAX (day_view
->max_small_hour_width
, day_view
->small_hour_widths
[hour
]);
1557 max_minute_width
= 0;
1558 for (minute
= 0, i
= 0; minute
< 60; minute
+= 5, i
++) {
1561 g_snprintf (buffer
, sizeof (buffer
), "%02i", minute
);
1562 pango_layout_set_text (layout
, buffer
, -1);
1563 pango_layout_get_pixel_size (layout
, &minute_width
, NULL
);
1565 max_minute_width
= MAX (max_minute_width
, minute_width
);
1567 day_view
->max_minute_width
= max_minute_width
;
1569 pango_layout_set_text (layout
, ":", 1);
1570 pango_layout_get_pixel_size (layout
, &day_view
->colon_width
, NULL
);
1571 pango_layout_set_text (layout
, "0", 1);
1572 pango_layout_get_pixel_size (layout
, &day_view
->digit_width
, NULL
);
1574 pango_layout_set_text (layout
, day_view
->am_string
, -1);
1575 pango_layout_get_pixel_size (layout
, &day_view
->am_string_width
, NULL
);
1576 pango_layout_set_text (layout
, day_view
->pm_string
, -1);
1577 pango_layout_get_pixel_size (layout
, &day_view
->pm_string_width
, NULL
);
1579 /* Calculate the width of the time column. */
1580 times_width
= e_day_view_time_item_get_column_width (E_DAY_VIEW_TIME_ITEM (day_view
->time_canvas_item
));
1581 gtk_widget_set_size_request (day_view
->time_canvas
, times_width
, -1);
1583 g_object_unref (layout
);
1584 pango_font_metrics_unref (font_metrics
);
1588 day_view_realize (GtkWidget
*widget
)
1592 if (GTK_WIDGET_CLASS (e_day_view_parent_class
)->realize
)
1593 (*GTK_WIDGET_CLASS (e_day_view_parent_class
)->realize
)(widget
);
1595 day_view
= E_DAY_VIEW (widget
);
1597 day_view_update_style_settings (day_view
);
1599 /* Create the pixmaps. */
1600 day_view
->reminder_icon
= e_icon_factory_get_icon ("stock_bell", GTK_ICON_SIZE_MENU
);
1601 day_view
->recurrence_icon
= e_icon_factory_get_icon ("view-refresh", GTK_ICON_SIZE_MENU
);
1602 day_view
->timezone_icon
= e_icon_factory_get_icon ("stock_timezone", GTK_ICON_SIZE_MENU
);
1603 day_view
->meeting_icon
= e_icon_factory_get_icon ("stock_people", GTK_ICON_SIZE_MENU
);
1604 day_view
->attach_icon
= e_icon_factory_get_icon ("mail-attachment", GTK_ICON_SIZE_MENU
);
1606 /* Set the canvas item colors. */
1607 gnome_canvas_item_set (
1608 day_view
->drag_long_event_rect_item
,
1609 "fill_color_gdk", &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BACKGROUND
],
1610 "outline_color_gdk", &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BORDER
],
1613 gnome_canvas_item_set (
1614 day_view
->drag_rect_item
,
1615 "fill_color_gdk", &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BACKGROUND
],
1616 "outline_color_gdk", &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BORDER
],
1619 gnome_canvas_item_set (
1620 day_view
->drag_bar_item
,
1621 "fill_color_gdk", &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_VBAR
],
1622 "outline_color_gdk", &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BORDER
],
1627 day_view_unrealize (GtkWidget
*widget
)
1631 day_view
= E_DAY_VIEW (widget
);
1633 g_object_unref (day_view
->reminder_icon
);
1634 day_view
->reminder_icon
= NULL
;
1635 g_object_unref (day_view
->recurrence_icon
);
1636 day_view
->recurrence_icon
= NULL
;
1637 g_object_unref (day_view
->timezone_icon
);
1638 day_view
->timezone_icon
= NULL
;
1639 g_object_unref (day_view
->meeting_icon
);
1640 day_view
->meeting_icon
= NULL
;
1641 g_object_unref (day_view
->attach_icon
);
1642 day_view
->attach_icon
= NULL
;
1644 if (GTK_WIDGET_CLASS (e_day_view_parent_class
)->unrealize
)
1645 (*GTK_WIDGET_CLASS (e_day_view_parent_class
)->unrealize
)(widget
);
1649 day_view_size_allocate (GtkWidget
*widget
,
1650 GtkAllocation
*allocation
)
1652 (*GTK_WIDGET_CLASS (e_day_view_parent_class
)->size_allocate
) (widget
, allocation
);
1654 e_day_view_recalc_main_canvas_size (E_DAY_VIEW (widget
));
1658 day_view_style_updated (GtkWidget
*widget
)
1660 if (GTK_WIDGET_CLASS (e_day_view_parent_class
)->style_updated
)
1661 (*GTK_WIDGET_CLASS (e_day_view_parent_class
)->style_updated
) (widget
);
1663 day_view_update_style_settings (E_DAY_VIEW (widget
));
1667 day_view_focus (GtkWidget
*widget
,
1668 GtkDirectionType direction
)
1673 gint start_row
, end_row
;
1675 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1676 g_return_val_if_fail (E_IS_DAY_VIEW (widget
), FALSE
);
1677 day_view
= E_DAY_VIEW (widget
);
1679 if (!e_day_view_get_next_tab_event (day_view
, direction
,
1680 &new_day
, &new_event_num
))
1683 if ((new_day
== -1) && (new_event_num
== -1)) {
1684 /* focus should go to the day view widget itself
1686 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
1690 if (new_day
!= E_DAY_VIEW_LONG_EVENT
&& new_day
!= -1) {
1691 if (e_day_view_get_event_rows (day_view
, new_day
,
1693 &start_row
, &end_row
))
1694 /* ensure the event to be seen */
1695 e_day_view_ensure_rows_visible (
1697 start_row
, end_row
);
1698 } else if (new_day
!= -1) {
1699 e_day_view_start_editing_event (
1701 new_event_num
, NULL
);
1708 day_view_key_press (GtkWidget
*widget
,
1711 gboolean handled
= FALSE
;
1712 handled
= e_day_view_do_key_press (widget
, event
);
1714 /* if not handled, try key bindings */
1716 handled
= GTK_WIDGET_CLASS (e_day_view_parent_class
)->key_press_event (widget
, event
);
1721 day_view_focus_in (GtkWidget
*widget
,
1722 GdkEventFocus
*event
)
1726 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1727 g_return_val_if_fail (E_IS_DAY_VIEW (widget
), FALSE
);
1728 g_return_val_if_fail (event
!= NULL
, FALSE
);
1730 day_view
= E_DAY_VIEW (widget
);
1732 /* XXX Can't access flags directly anymore, but is it really needed?
1733 * If so, could we call gtk_widget_send_focus_change() instead? */
1735 GTK_WIDGET_SET_FLAGS (widget
, GTK_HAS_FOCUS
);
1738 if (E_CALENDAR_VIEW (day_view
)->in_focus
&& day_view
->requires_update
) {
1739 time_t my_start
= 0, my_end
= 0, model_start
= 0, model_end
= 0;
1741 day_view
->requires_update
= FALSE
;
1743 e_cal_model_get_time_range (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
)), &model_start
, &model_end
);
1745 if (e_calendar_view_get_visible_time_range (E_CALENDAR_VIEW (day_view
), &my_start
, &my_end
) &&
1746 model_start
== my_start
&& model_end
== my_end
) {
1747 /* update only when the same time range is set in a view and in a model;
1748 * otherwise time range change invokes also query update */
1749 e_day_view_recalc_day_starts (day_view
, day_view
->lower
);
1750 e_day_view_update_query (day_view
);
1754 gtk_widget_queue_draw (day_view
->top_canvas
);
1755 gtk_widget_queue_draw (day_view
->main_canvas
);
1761 day_view_focus_out (GtkWidget
*widget
,
1762 GdkEventFocus
*event
)
1766 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1767 g_return_val_if_fail (E_IS_DAY_VIEW (widget
), FALSE
);
1768 g_return_val_if_fail (event
!= NULL
, FALSE
);
1770 day_view
= E_DAY_VIEW (widget
);
1772 /* XXX Can't access flags directly anymore, but is it really needed?
1773 * If so, could we call gtk_widget_send_focus_change() instead? */
1775 GTK_WIDGET_UNSET_FLAGS (widget
, GTK_HAS_FOCUS
);
1778 gtk_widget_queue_draw (day_view
->top_canvas
);
1779 gtk_widget_queue_draw (day_view
->main_canvas
);
1785 day_view_popup_menu (GtkWidget
*widget
)
1787 EDayView
*day_view
= E_DAY_VIEW (widget
);
1788 e_day_view_show_popup_menu (
1790 day_view
->editing_event_day
,
1791 day_view
->editing_event_num
);
1795 /* Returns the currently-selected event, or NULL if none */
1797 day_view_get_selected_events (ECalendarView
*cal_view
)
1799 EDayViewEvent
*event
= NULL
;
1801 EDayView
*day_view
= (EDayView
*) cal_view
;
1803 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), NULL
);
1805 if (day_view
->editing_event_num
!= -1) {
1806 if (day_view
->editing_event_day
== E_DAY_VIEW_LONG_EVENT
) {
1807 if (!is_array_index_in_bounds (day_view
->long_events
, day_view
->editing_event_num
))
1810 event
= &g_array_index (day_view
->long_events
,
1812 day_view
->editing_event_num
);
1814 if (!is_array_index_in_bounds (day_view
->events
[day_view
->editing_event_day
], day_view
->editing_event_num
))
1817 event
= &g_array_index (day_view
->events
[day_view
->editing_event_day
],
1819 day_view
->editing_event_num
);
1821 } else if (day_view
->popup_event_num
!= -1) {
1822 if (day_view
->popup_event_day
== E_DAY_VIEW_LONG_EVENT
) {
1823 if (!is_array_index_in_bounds (day_view
->long_events
, day_view
->popup_event_num
))
1826 event
= &g_array_index (day_view
->long_events
,
1828 day_view
->popup_event_num
);
1830 if (!is_array_index_in_bounds (day_view
->events
[day_view
->popup_event_day
], day_view
->popup_event_num
))
1833 event
= &g_array_index (day_view
->events
[day_view
->popup_event_day
],
1835 day_view
->popup_event_num
);
1840 list
= g_list_append (list
, event
);
1845 /* This sets the selected time range. If the start_time & end_time are not equal
1846 * and are both visible in the view, then the selection is set to those times,
1847 * otherwise it is set to 1 hour from the start of the working day. */
1849 day_view_set_selected_time_range (ECalendarView
*cal_view
,
1854 gint work_day_start_hour
;
1855 gint work_day_start_minute
;
1856 gint work_day_end_hour
;
1857 gint work_day_end_minute
;
1858 gint start_row
, start_col
, end_row
, end_col
;
1859 gboolean need_redraw
= FALSE
, start_in_grid
, end_in_grid
;
1861 day_view
= E_DAY_VIEW (cal_view
);
1863 if (start_time
== end_time
)
1864 end_time
+= e_calendar_view_get_time_divisions (cal_view
) * 60;
1866 /* Set the selection. */
1867 start_in_grid
= e_day_view_convert_time_to_grid_position (
1872 end_in_grid
= e_day_view_convert_time_to_grid_position (
1878 e_day_view_get_work_day_range_for_day (day_view
, start_col
,
1879 &work_day_start_hour
, &work_day_start_minute
,
1880 &work_day_end_hour
, &work_day_end_minute
);
1882 /* If either of the times isn't in the grid, or the selection covers
1883 * an entire day, we set the selection to 1 row from the start of the
1884 * working day, in the day corresponding to the start time. */
1885 if (!start_in_grid
|| !end_in_grid
1886 || (start_row
== 0 && end_row
== day_view
->rows
- 1)) {
1887 end_col
= start_col
;
1889 start_row
= e_day_view_convert_time_to_row (
1890 day_view
, work_day_start_hour
, work_day_start_minute
);
1891 start_row
= CLAMP (start_row
, 0, day_view
->rows
- 1);
1892 end_row
= start_row
;
1895 if (start_row
!= day_view
->selection_start_row
1896 || start_col
!= day_view
->selection_start_day
) {
1898 day_view
->selection_in_top_canvas
= FALSE
;
1899 day_view
->selection_start_row
= start_row
;
1900 day_view
->selection_start_day
= start_col
;
1903 if (end_row
!= day_view
->selection_end_row
1904 || end_col
!= day_view
->selection_end_day
) {
1906 day_view
->selection_in_top_canvas
= FALSE
;
1907 day_view
->selection_end_row
= end_row
;
1908 day_view
->selection_end_day
= end_col
;
1912 gtk_widget_queue_draw (day_view
->top_canvas
);
1913 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
1914 gtk_widget_queue_draw (day_view
->main_canvas
);
1916 e_day_view_ensure_rows_visible (day_view
, day_view
->selection_start_row
, day_view
->selection_end_row
);
1920 /* Gets the visible time range. Returns FALSE if no time range has been set. */
1922 day_view_get_visible_time_range (ECalendarView
*cal_view
,
1926 EDayView
*day_view
= E_DAY_VIEW (cal_view
);
1929 /* If the date isn't set, return FALSE. */
1930 if (day_view
->lower
== 0 && day_view
->upper
== 0)
1933 days_shown
= e_day_view_get_days_shown (day_view
);
1934 if (days_shown
<= 0)
1937 *start_time
= day_view
->day_starts
[0];
1938 *end_time
= day_view
->day_starts
[days_shown
];
1944 day_view_paste_text (ECalendarView
*cal_view
)
1947 EDayViewEvent
*event
;
1949 g_return_if_fail (E_IS_DAY_VIEW (cal_view
));
1951 day_view
= E_DAY_VIEW (cal_view
);
1953 if (day_view
->editing_event_num
== -1) {
1954 e_day_view_add_new_event_in_selected_range (day_view
, NULL
, TRUE
);
1958 if (day_view
->editing_event_day
== E_DAY_VIEW_LONG_EVENT
) {
1959 if (!is_array_index_in_bounds (day_view
->long_events
, day_view
->editing_event_num
))
1962 event
= &g_array_index (day_view
->long_events
,
1964 day_view
->editing_event_num
);
1966 if (!is_array_index_in_bounds (day_view
->events
[day_view
->editing_event_day
], day_view
->editing_event_num
))
1969 event
= &g_array_index (day_view
->events
[day_view
->editing_event_day
],
1971 day_view
->editing_event_num
);
1974 if (event
->canvas_item
&&
1975 E_IS_TEXT (event
->canvas_item
) &&
1976 E_TEXT (event
->canvas_item
)->editing
) {
1977 e_text_paste_clipboard (E_TEXT (event
->canvas_item
));
1982 e_day_view_class_init (EDayViewClass
*class)
1984 GObjectClass
*object_class
;
1985 GtkWidgetClass
*widget_class
;
1986 ECalendarViewClass
*view_class
;
1988 g_type_class_add_private (class, sizeof (EDayViewPrivate
));
1990 object_class
= G_OBJECT_CLASS (class);
1991 object_class
->set_property
= day_view_set_property
;
1992 object_class
->get_property
= day_view_get_property
;
1993 object_class
->constructed
= day_view_constructed
;
1994 object_class
->dispose
= day_view_dispose
;
1995 object_class
->notify
= day_view_notify
;
1997 widget_class
= GTK_WIDGET_CLASS (class);
1998 widget_class
->realize
= day_view_realize
;
1999 widget_class
->unrealize
= day_view_unrealize
;
2000 widget_class
->size_allocate
= day_view_size_allocate
;
2001 widget_class
->style_updated
= day_view_style_updated
;
2002 widget_class
->focus
= day_view_focus
;
2003 widget_class
->key_press_event
= day_view_key_press
;
2004 widget_class
->focus_in_event
= day_view_focus_in
;
2005 widget_class
->focus_out_event
= day_view_focus_out
;
2006 widget_class
->popup_menu
= day_view_popup_menu
;
2008 view_class
= E_CALENDAR_VIEW_CLASS (class);
2009 view_class
->get_selected_events
= day_view_get_selected_events
;
2010 view_class
->get_selected_time_range
= day_view_get_selected_time_range
;
2011 view_class
->set_selected_time_range
= day_view_set_selected_time_range
;
2012 view_class
->get_visible_time_range
= day_view_get_visible_time_range
;
2013 view_class
->precalc_visible_time_range
= e_day_view_precalc_visible_time_range
;
2014 view_class
->paste_text
= day_view_paste_text
;
2016 g_object_class_install_property (
2018 PROP_DRAW_FLAT_EVENTS
,
2019 g_param_spec_boolean (
2026 G_PARAM_STATIC_STRINGS
));
2028 g_object_class_install_property (
2030 PROP_MARCUS_BAINS_SHOW_LINE
,
2031 g_param_spec_boolean (
2032 "marcus-bains-show-line",
2033 "Marcus Bains Show Line",
2038 G_PARAM_STATIC_STRINGS
));
2040 g_object_class_install_property (
2042 PROP_MARCUS_BAINS_DAY_VIEW_COLOR
,
2043 g_param_spec_string (
2044 "marcus-bains-day-view-color",
2045 "Marcus Bains Day View Color",
2049 G_PARAM_STATIC_STRINGS
));
2051 g_object_class_install_property (
2053 PROP_MARCUS_BAINS_TIME_BAR_COLOR
,
2054 g_param_spec_string (
2055 "marcus-bains-time-bar-color",
2056 "Marcus Bains Time Bar Color",
2060 G_PARAM_STATIC_STRINGS
));
2062 g_object_class_override_property (
2067 /* init the accessibility support for e_day_view */
2068 gtk_widget_class_set_accessible_type (widget_class
, EA_TYPE_DAY_VIEW
);
2072 e_day_view_init (EDayView
*day_view
)
2075 GnomeCanvasGroup
*canvas_group
;
2076 GtkAdjustment
*adjustment
;
2077 GtkScrollable
*scrollable
;
2078 GtkWidget
*container
;
2082 day_view
->priv
= E_DAY_VIEW_GET_PRIVATE (day_view
);
2084 gtk_widget_set_can_focus (GTK_WIDGET (day_view
), TRUE
);
2086 day_view
->long_events
= g_array_new (
2088 sizeof (EDayViewEvent
));
2089 day_view
->long_events_sorted
= TRUE
;
2090 day_view
->long_events_need_layout
= FALSE
;
2091 day_view
->long_events_need_reshape
= FALSE
;
2093 day_view
->layout_timeout_id
= 0;
2095 for (day
= 0; day
< E_DAY_VIEW_MAX_DAYS
; day
++) {
2096 day_view
->events
[day
] = g_array_new (
2098 sizeof (EDayViewEvent
));
2099 day_view
->events_sorted
[day
] = TRUE
;
2100 day_view
->need_layout
[day
] = FALSE
;
2101 day_view
->need_reshape
[day
] = FALSE
;
2104 /* These indicate that the times haven't been set. */
2105 day_view
->lower
= 0;
2106 day_view
->upper
= 0;
2108 day_view
->priv
->days_shown
= 1;
2110 day_view
->date_format
= E_DAY_VIEW_DATE_FULL
;
2111 day_view
->rows_in_top_display
= 0;
2113 /* Note that these don't work yet. It would need a few fixes to the
2114 * way event->start_minute and event->end_minute are used, and there
2115 * may be problems with events that go outside the visible times. */
2116 day_view
->first_hour_shown
= 0;
2117 day_view
->first_minute_shown
= 0;
2118 day_view
->last_hour_shown
= 24;
2119 day_view
->last_minute_shown
= 0;
2121 e_day_view_recalc_num_rows (day_view
);
2123 day_view
->show_event_end_times
= TRUE
;
2124 day_view
->scroll_to_work_day
= TRUE
;
2126 day_view
->editing_event_day
= -1;
2127 day_view
->editing_event_num
= -1;
2129 day_view
->resize_event_num
= -1;
2130 day_view
->resize_bars_event_day
= -1;
2131 day_view
->resize_bars_event_num
= -1;
2133 day_view
->last_edited_comp_string
= NULL
;
2135 day_view
->selection_start_row
= -1;
2136 day_view
->selection_start_day
= -1;
2137 day_view
->selection_end_row
= -1;
2138 day_view
->selection_end_day
= -1;
2139 day_view
->selection_is_being_dragged
= FALSE
;
2140 day_view
->selection_drag_pos
= E_DAY_VIEW_DRAG_END
;
2141 day_view
->selection_in_top_canvas
= FALSE
;
2142 day_view
->drag_last_day
= -1;
2143 day_view
->drag_event_day
= -1;
2144 day_view
->drag_event_num
= -1;
2145 day_view
->resize_drag_pos
= E_CALENDAR_VIEW_POS_NONE
;
2146 day_view
->priv
->drag_context
= NULL
;
2148 day_view
->pressed_event_day
= -1;
2150 day_view
->auto_scroll_timeout_id
= 0;
2152 day_view
->large_font_desc
= NULL
;
2153 day_view
->small_font_desc
= NULL
;
2155 /* String to use in 12-hour time format for times in the morning. */
2156 day_view
->am_string
= _("am");
2158 /* String to use in 12-hour time format for times in the afternoon. */
2159 day_view
->pm_string
= _("pm");
2161 day_view
->bc_event_time
= 0;
2162 day_view
->before_click_dtstart
= 0;
2163 day_view
->before_click_dtend
= 0;
2165 gtk_widget_set_margin_top (GTK_WIDGET (day_view
), 1);
2167 day_view
->week_number_label
= gtk_label_new ("");
2169 widget
= gtk_label_new (NULL
);
2170 gtk_label_set_ellipsize (GTK_LABEL (widget
), PANGO_ELLIPSIZE_END
);
2171 gtk_misc_set_alignment (GTK_MISC (widget
), 0.0, 1.0);
2172 day_view
->priv
->timezone_name_1_label
= widget
;
2174 widget
= gtk_label_new (NULL
);
2175 gtk_label_set_ellipsize (GTK_LABEL (widget
), PANGO_ELLIPSIZE_END
);
2176 gtk_misc_set_alignment (GTK_MISC (widget
), 0.0, 1.0);
2177 day_view
->priv
->timezone_name_2_label
= widget
;
2179 widget
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 2);
2181 gtk_grid_attach (GTK_GRID (day_view
), widget
, 0, 0, 1, 1);
2182 g_object_set (G_OBJECT (widget
),
2185 "halign", GTK_ALIGN_FILL
,
2186 "valign", GTK_ALIGN_FILL
,
2191 gtk_box_pack_start (GTK_BOX (container
), day_view
->week_number_label
, TRUE
, TRUE
, 2);
2193 widget
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 2);
2194 gtk_box_pack_end (GTK_BOX (container
), widget
, TRUE
, TRUE
, 2);
2196 gtk_widget_show_all (container
);
2200 gtk_box_set_homogeneous (GTK_BOX (container
), TRUE
);
2201 gtk_box_pack_start (GTK_BOX (container
), day_view
->priv
->timezone_name_1_label
, TRUE
, TRUE
, 2);
2202 gtk_box_pack_start (GTK_BOX (container
), day_view
->priv
->timezone_name_2_label
, TRUE
, TRUE
, 2);
2204 gtk_widget_show_all (container
);
2209 widget
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
2210 gtk_grid_attach (GTK_GRID (day_view
), widget
, 1, 0, 1, 1);
2211 g_object_set (G_OBJECT (widget
),
2214 "halign", GTK_ALIGN_FILL
,
2215 "valign", GTK_ALIGN_FILL
,
2217 gtk_widget_show (widget
);
2221 widget
= e_canvas_new ();
2222 gtk_box_pack_start (GTK_BOX (container
), widget
, TRUE
, TRUE
, 0);
2223 day_view
->top_dates_canvas
= widget
;
2224 gtk_widget_show (widget
);
2226 /* Keep our own canvas reference so we can
2227 * disconnect signal handlers in dispose(). */
2228 widget
= e_canvas_new ();
2229 gtk_box_pack_end (GTK_BOX (container
), widget
, TRUE
, TRUE
, 0);
2230 day_view
->top_canvas
= g_object_ref (widget
);
2231 gtk_widget_show (widget
);
2233 handler_id
= g_signal_connect_after (
2234 day_view
->top_canvas
, "button_press_event",
2235 G_CALLBACK (e_day_view_on_top_canvas_button_press
), day_view
);
2236 day_view
->priv
->top_canvas_button_press_event_handler_id
= handler_id
;
2238 handler_id
= g_signal_connect (
2239 day_view
->top_canvas
, "button_release_event",
2240 G_CALLBACK (e_day_view_on_top_canvas_button_release
), day_view
);
2241 day_view
->priv
->top_canvas_button_release_event_handler_id
= handler_id
;
2243 handler_id
= g_signal_connect (
2244 day_view
->top_canvas
, "scroll_event",
2245 G_CALLBACK (e_day_view_on_top_canvas_scroll
), day_view
);
2246 day_view
->priv
->top_canvas_scroll_event_handler_id
= handler_id
;
2248 handler_id
= g_signal_connect (
2249 day_view
->top_canvas
, "motion_notify_event",
2250 G_CALLBACK (e_day_view_on_top_canvas_motion
), day_view
);
2251 day_view
->priv
->top_canvas_motion_notify_event_handler_id
= handler_id
;
2253 handler_id
= g_signal_connect (
2254 day_view
->top_canvas
, "drag_motion",
2255 G_CALLBACK (e_day_view_on_top_canvas_drag_motion
), day_view
);
2256 day_view
->priv
->top_canvas_drag_motion_handler_id
= handler_id
;
2258 handler_id
= g_signal_connect (
2259 day_view
->top_canvas
, "drag_leave",
2260 G_CALLBACK (e_day_view_on_top_canvas_drag_leave
), day_view
);
2261 day_view
->priv
->top_canvas_drag_leave_handler_id
= handler_id
;
2263 handler_id
= g_signal_connect (
2264 day_view
->top_canvas
, "drag_begin",
2265 G_CALLBACK (e_day_view_on_drag_begin
), day_view
);
2266 day_view
->priv
->top_canvas_drag_begin_handler_id
= handler_id
;
2268 handler_id
= g_signal_connect (
2269 day_view
->top_canvas
, "drag_end",
2270 G_CALLBACK (e_day_view_on_drag_end
), day_view
);
2271 day_view
->priv
->top_canvas_drag_end_handler_id
= handler_id
;
2273 handler_id
= g_signal_connect (
2274 day_view
->top_canvas
, "drag_data_get",
2275 G_CALLBACK (e_day_view_on_drag_data_get
), day_view
);
2276 day_view
->priv
->top_canvas_drag_data_get_handler_id
= handler_id
;
2278 handler_id
= g_signal_connect (
2279 day_view
->top_canvas
, "drag_data_received",
2280 G_CALLBACK (e_day_view_on_top_canvas_drag_data_received
), day_view
);
2281 day_view
->priv
->top_canvas_drag_data_received_handler_id
= handler_id
;
2283 canvas_group
= GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view
->top_dates_canvas
)->root
);
2285 day_view
->top_dates_canvas_item
=
2286 gnome_canvas_item_new (
2288 e_day_view_top_item_get_type (),
2289 "EDayViewTopItem::day_view", day_view
,
2290 "EDayViewTopItem::show_dates", TRUE
,
2292 gtk_widget_set_size_request (day_view
->top_dates_canvas
, -1, day_view
->top_row_height
);
2294 canvas_group
= GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view
->top_canvas
)->root
);
2296 day_view
->top_canvas_item
=
2297 gnome_canvas_item_new (
2299 e_day_view_top_item_get_type (),
2300 "EDayViewTopItem::day_view", day_view
,
2301 "EDayViewTopItem::show_dates", FALSE
,
2304 day_view
->drag_long_event_rect_item
=
2305 gnome_canvas_item_new (
2307 gnome_canvas_rect_get_type (),
2310 gnome_canvas_item_hide (day_view
->drag_long_event_rect_item
);
2312 day_view
->drag_long_event_item
=
2313 gnome_canvas_item_new (
2320 "fill_color_rgba", GNOME_CANVAS_COLOR (0, 0, 0),
2322 gnome_canvas_item_hide (day_view
->drag_long_event_item
);
2328 /* Keep our own canvas reference so we can
2329 * disconnect signal handlers in dispose(). */
2330 widget
= e_canvas_new ();
2331 gtk_grid_attach (GTK_GRID (day_view
), widget
, 1, 1, 1, 1);
2332 g_object_set (G_OBJECT (widget
),
2335 "halign", GTK_ALIGN_FILL
,
2336 "valign", GTK_ALIGN_FILL
,
2338 day_view
->main_canvas
= g_object_ref (widget
);
2339 gtk_widget_show (widget
);
2341 handler_id
= g_signal_connect (
2342 day_view
->main_canvas
, "realize",
2343 G_CALLBACK (e_day_view_on_canvas_realized
), day_view
);
2344 day_view
->priv
->main_canvas_realize_handler_id
= handler_id
;
2346 handler_id
= g_signal_connect (
2347 day_view
->main_canvas
, "button_press_event",
2348 G_CALLBACK (e_day_view_on_main_canvas_button_press
), day_view
);
2349 day_view
->priv
->main_canvas_button_press_event_handler_id
= handler_id
;
2351 handler_id
= g_signal_connect (
2352 day_view
->main_canvas
, "button_release_event",
2353 G_CALLBACK (e_day_view_on_main_canvas_button_release
),
2355 day_view
->priv
->main_canvas_button_release_event_handler_id
= handler_id
;
2357 handler_id
= g_signal_connect (
2358 day_view
->main_canvas
, "scroll_event",
2359 G_CALLBACK (e_day_view_on_main_canvas_scroll
), day_view
);
2360 day_view
->priv
->main_canvas_scroll_event_handler_id
= handler_id
;
2362 handler_id
= g_signal_connect (
2363 day_view
->main_canvas
, "motion_notify_event",
2364 G_CALLBACK (e_day_view_on_main_canvas_motion
), day_view
);
2365 day_view
->priv
->main_canvas_motion_notify_event_handler_id
= handler_id
;
2367 handler_id
= g_signal_connect (
2368 day_view
->main_canvas
, "drag_motion",
2369 G_CALLBACK (e_day_view_on_main_canvas_drag_motion
), day_view
);
2370 day_view
->priv
->main_canvas_drag_motion_handler_id
= handler_id
;
2372 handler_id
= g_signal_connect (
2373 day_view
->main_canvas
, "drag_leave",
2374 G_CALLBACK (e_day_view_on_main_canvas_drag_leave
), day_view
);
2375 day_view
->priv
->main_canvas_drag_leave_handler_id
= handler_id
;
2377 handler_id
= g_signal_connect (
2378 day_view
->main_canvas
, "drag_begin",
2379 G_CALLBACK (e_day_view_on_drag_begin
), day_view
);
2380 day_view
->priv
->main_canvas_drag_begin_handler_id
= handler_id
;
2382 handler_id
= g_signal_connect (
2383 day_view
->main_canvas
, "drag_end",
2384 G_CALLBACK (e_day_view_on_drag_end
), day_view
);
2385 day_view
->priv
->main_canvas_drag_end_handler_id
= handler_id
;
2387 handler_id
= g_signal_connect (
2388 day_view
->main_canvas
, "drag_data_get",
2389 G_CALLBACK (e_day_view_on_drag_data_get
), day_view
);
2390 day_view
->priv
->main_canvas_drag_data_get_handler_id
= handler_id
;
2392 handler_id
= g_signal_connect (
2393 day_view
->main_canvas
, "drag_data_received",
2394 G_CALLBACK (e_day_view_on_main_canvas_drag_data_received
), day_view
);
2395 day_view
->priv
->main_canvas_drag_data_received_handler_id
= handler_id
;
2397 canvas_group
= GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view
->main_canvas
)->root
);
2399 day_view
->main_canvas_item
=
2400 gnome_canvas_item_new (
2402 e_day_view_main_item_get_type (),
2403 "EDayViewMainItem::day_view", day_view
,
2406 day_view
->drag_rect_item
=
2407 gnome_canvas_item_new (
2409 gnome_canvas_rect_get_type (),
2412 gnome_canvas_item_hide (day_view
->drag_rect_item
);
2414 day_view
->drag_bar_item
=
2415 gnome_canvas_item_new (
2417 gnome_canvas_rect_get_type (),
2420 gnome_canvas_item_hide (day_view
->drag_bar_item
);
2422 day_view
->drag_item
=
2423 gnome_canvas_item_new (
2429 "fill_color_rgba", GNOME_CANVAS_COLOR (0, 0, 0),
2431 gnome_canvas_item_hide (day_view
->drag_item
);
2437 /* Keep our own canvas reference so we can
2438 * disconnect signal handlers in dispose(). */
2439 widget
= e_canvas_new ();
2440 scrollable
= GTK_SCROLLABLE (day_view
->main_canvas
);
2441 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
2442 scrollable
= GTK_SCROLLABLE (widget
);
2443 gtk_scrollable_set_vadjustment (scrollable
, adjustment
);
2444 gtk_grid_attach (GTK_GRID (day_view
), widget
, 0, 1, 1, 1);
2445 g_object_set (G_OBJECT (widget
),
2448 "halign", GTK_ALIGN_FILL
,
2449 "valign", GTK_ALIGN_FILL
,
2451 day_view
->time_canvas
= g_object_ref (widget
);
2452 gtk_widget_show (widget
);
2454 handler_id
= g_signal_connect_after (
2455 day_view
->time_canvas
, "scroll_event",
2456 G_CALLBACK (e_day_view_on_time_canvas_scroll
), day_view
);
2457 day_view
->priv
->time_canvas_scroll_event_handler_id
= handler_id
;
2459 canvas_group
= GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view
->time_canvas
)->root
);
2461 day_view
->time_canvas_item
=
2462 gnome_canvas_item_new (
2464 e_day_view_time_item_get_type (),
2465 "EDayViewTimeItem::day_view", day_view
,
2471 scrollable
= GTK_SCROLLABLE (day_view
->main_canvas
);
2472 adjustment
= gtk_scrollable_get_hadjustment (scrollable
);
2473 day_view
->mc_hscrollbar
= gtk_scrollbar_new (
2474 GTK_ORIENTATION_HORIZONTAL
, adjustment
);
2475 gtk_grid_attach (GTK_GRID (day_view
), day_view
->mc_hscrollbar
, 1, 2, 1, 1);
2476 g_object_set (G_OBJECT (day_view
->mc_hscrollbar
),
2479 "halign", GTK_ALIGN_FILL
,
2480 "valign", GTK_ALIGN_START
,
2482 gtk_widget_show (day_view
->mc_hscrollbar
);
2484 scrollable
= GTK_SCROLLABLE (day_view
->top_canvas
);
2485 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
2486 day_view
->tc_vscrollbar
= gtk_scrollbar_new (
2487 GTK_ORIENTATION_VERTICAL
, adjustment
);
2488 gtk_grid_attach (GTK_GRID (day_view
), day_view
->tc_vscrollbar
, 2, 0, 1, 1);
2489 g_object_set (G_OBJECT (day_view
->tc_vscrollbar
),
2492 "halign", GTK_ALIGN_START
,
2493 "valign", GTK_ALIGN_FILL
,
2495 /* gtk_widget_show (day_view->tc_vscrollbar); */
2497 scrollable
= GTK_SCROLLABLE (day_view
->main_canvas
);
2498 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
2499 day_view
->vscrollbar
= gtk_scrollbar_new (
2500 GTK_ORIENTATION_VERTICAL
, adjustment
);
2501 gtk_grid_attach (GTK_GRID (day_view
), day_view
->vscrollbar
, 2, 1, 1, 1);
2502 g_object_set (G_OBJECT (day_view
->vscrollbar
),
2505 "halign", GTK_ALIGN_START
,
2506 "valign", GTK_ALIGN_FILL
,
2508 gtk_widget_show (day_view
->vscrollbar
);
2510 /* Create the cursors. */
2511 day_view
->normal_cursor
= gdk_cursor_new (GDK_LEFT_PTR
);
2512 day_view
->move_cursor
= gdk_cursor_new (GDK_FLEUR
);
2513 day_view
->resize_width_cursor
= gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW
);
2514 day_view
->resize_height_cursor
= gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW
);
2515 day_view
->last_cursor_set_in_top_canvas
= NULL
;
2516 day_view
->last_cursor_set_in_main_canvas
= NULL
;
2518 /* Set up the drop sites. */
2520 day_view
->top_canvas
, GTK_DEST_DEFAULT_ALL
,
2521 target_table
, G_N_ELEMENTS (target_table
),
2522 GDK_ACTION_COPY
| GDK_ACTION_MOVE
| GDK_ACTION_ASK
);
2524 e_drag_dest_add_calendar_targets (day_view
->top_canvas
);
2527 day_view
->main_canvas
, GTK_DEST_DEFAULT_ALL
,
2528 target_table
, G_N_ELEMENTS (target_table
),
2529 GDK_ACTION_COPY
| GDK_ACTION_MOVE
| GDK_ACTION_ASK
);
2531 e_drag_dest_add_calendar_targets (day_view
->main_canvas
);
2533 day_view
->requires_update
= FALSE
;
2537 e_day_view_precalc_visible_time_range (ECalendarView
*cal_view
,
2538 time_t in_start_time
,
2540 time_t *out_start_time
,
2541 time_t *out_end_time
)
2548 g_return_if_fail (E_IS_DAY_VIEW (cal_view
));
2549 g_return_if_fail (out_start_time
!= NULL
);
2550 g_return_if_fail (out_end_time
!= NULL
);
2552 day_view
= E_DAY_VIEW (cal_view
);
2553 days_shown
= e_day_view_get_days_shown (day_view
);
2554 zone
= e_calendar_view_get_timezone (cal_view
);
2556 /* Calculate the first day that should be shown, based on start_time
2557 * and the days_shown setting. If we are showing 1 day it is just the
2558 * start of the day given by start_time, otherwise it is the previous
2559 * work-week start day. */
2560 if (!e_day_view_get_work_week_view (day_view
)) {
2561 lower
= time_day_begin_with_zone (in_start_time
, zone
);
2563 lower
= e_day_view_find_work_week_start (day_view
, in_start_time
);
2566 /* See if we need to change the days shown. */
2567 if (lower
== day_view
->lower
) {
2568 *out_start_time
= day_view
->lower
;
2569 *out_end_time
= day_view
->upper
;
2573 *out_start_time
= lower
;
2574 *out_end_time
= lower
;
2576 for (day
= 1; day
<= days_shown
; day
++) {
2577 *out_end_time
= time_add_day_with_zone (*out_end_time
, 1, zone
);
2583 time_range_changed_cb (ECalModel
*model
,
2584 gint64 i64_start_time
,
2585 gint64 i64_end_time
,
2588 EDayView
*day_view
= E_DAY_VIEW (user_data
);
2589 EDayViewTimeItem
*eti
;
2591 time_t lower
, start_time
= (time_t) i64_start_time
, end_time
= (time_t) i64_end_time
;
2593 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
2595 days_shown
= e_day_view_get_days_shown (day_view
);
2597 /* Calculate the first day that should be shown, based on start_time
2598 * and the days_shown setting. If we are showing 1 day it is just the
2599 * start of the day given by start_time, otherwise it is the previous
2600 * work-week start day. */
2601 if (!e_day_view_get_work_week_view (day_view
)) {
2602 lower
= time_day_begin_with_zone (start_time
, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
2604 lower
= e_day_view_find_work_week_start (day_view
, start_time
);
2607 /* See if we need to change the days shown. */
2608 if (lower
!= day_view
->lower
)
2609 e_day_view_recalc_day_starts (day_view
, lower
);
2611 if (!E_CALENDAR_VIEW (day_view
)->in_focus
) {
2612 e_day_view_free_events (day_view
);
2613 day_view
->requires_update
= TRUE
;
2617 /* If we don't show the new selection, don't preserve it */
2618 if (day_view
->selection_start_day
== -1 || days_shown
<= day_view
->selection_start_day
)
2619 day_view_set_selected_time_range (E_CALENDAR_VIEW (day_view
), start_time
, end_time
);
2621 if (day_view
->selection_start_row
!= -1)
2622 e_day_view_ensure_rows_visible (day_view
, day_view
->selection_start_row
, day_view
->selection_start_row
);
2624 /* update the time canvas to show proper date in it */
2625 eti
= E_DAY_VIEW_TIME_ITEM (day_view
->time_canvas_item
);
2626 if (eti
&& e_day_view_time_item_get_second_zone (eti
))
2627 gtk_widget_queue_draw (day_view
->time_canvas
);
2631 process_component (EDayView
*day_view
,
2632 ECalModelComponent
*comp_data
)
2637 ECalComponent
*comp
;
2638 ESourceRegistry
*registry
;
2639 AddEventData add_event_data
;
2641 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
2642 registry
= e_cal_model_get_registry (model
);
2644 /* If our time hasn't been set yet, just return. */
2645 if (day_view
->lower
== 0 && day_view
->upper
== 0)
2648 comp
= e_cal_component_new ();
2649 if (!e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (comp_data
->icalcomp
))) {
2650 g_object_unref (comp
);
2652 g_message (G_STRLOC
": Could not set icalcomponent on ECalComponent");
2656 e_cal_component_get_uid (comp
, &uid
);
2657 if (e_cal_component_is_instance (comp
))
2658 rid
= e_cal_component_get_recurid_as_string (comp
);
2661 /* rid is never used below here, why? */
2663 /* Add the object */
2664 add_event_data
.day_view
= day_view
;
2665 add_event_data
.comp_data
= comp_data
;
2666 e_day_view_add_event (
2667 registry
, comp_data
->client
, comp
, comp_data
->instance_start
,
2668 comp_data
->instance_end
, &add_event_data
);
2670 g_object_unref (comp
);
2675 update_row (EDayView
*day_view
,
2677 gboolean do_cancel_editing
)
2679 ECalModelComponent
*comp_data
;
2681 gint day
, event_num
;
2682 const gchar
*uid
= NULL
;
2685 if (do_cancel_editing
)
2686 cancel_editing (day_view
);
2688 e_day_view_stop_editing_event (day_view
);
2690 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
2691 comp_data
= e_cal_model_get_component_at (model
, row
);
2692 g_return_if_fail (comp_data
!= NULL
);
2694 uid
= icalcomponent_get_uid (comp_data
->icalcomp
);
2695 if (e_cal_util_component_is_instance (comp_data
->icalcomp
)) {
2698 prop
= icalcomponent_get_first_property (comp_data
->icalcomp
, ICAL_RECURRENCEID_PROPERTY
);
2700 rid
= icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (comp_data
->icalcomp
));
2703 if (e_day_view_find_event_from_uid (day_view
, comp_data
->client
, uid
, rid
, &day
, &event_num
))
2704 e_day_view_remove_event_cb (day_view
, day
, event_num
, NULL
);
2708 process_component (day_view
, comp_data
);
2710 gtk_widget_queue_draw (day_view
->top_canvas
);
2711 gtk_widget_queue_draw (day_view
->main_canvas
);
2712 e_day_view_queue_layout (day_view
);
2716 model_row_changed_cb (ETableModel
*etm
,
2720 EDayView
*day_view
= E_DAY_VIEW (user_data
);
2722 if (!E_CALENDAR_VIEW (day_view
)->in_focus
) {
2723 e_day_view_free_events (day_view
);
2724 day_view
->requires_update
= TRUE
;
2728 update_row (day_view
, row
, TRUE
);
2732 model_cell_changed_cb (ETableModel
*etm
,
2737 EDayView
*day_view
= E_DAY_VIEW (user_data
);
2739 if (!E_CALENDAR_VIEW (day_view
)->in_focus
) {
2740 e_day_view_free_events (day_view
);
2741 day_view
->requires_update
= TRUE
;
2745 update_row (day_view
, row
, FALSE
);
2749 model_rows_inserted_cb (ETableModel
*etm
,
2754 EDayView
*day_view
= E_DAY_VIEW (user_data
);
2758 if (!E_CALENDAR_VIEW (day_view
)->in_focus
) {
2759 e_day_view_free_events (day_view
);
2760 day_view
->requires_update
= TRUE
;
2764 e_day_view_stop_editing_event (day_view
);
2766 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
2767 for (i
= 0; i
< count
; i
++) {
2768 ECalModelComponent
*comp_data
;
2770 comp_data
= e_cal_model_get_component_at (model
, row
+ i
);
2771 if (comp_data
== NULL
) {
2772 g_warning ("comp_data is NULL\n");
2775 process_component (day_view
, comp_data
);
2778 gtk_widget_queue_draw (day_view
->top_canvas
);
2779 gtk_widget_queue_draw (day_view
->main_canvas
);
2780 e_day_view_queue_layout (day_view
);
2785 model_comps_deleted_cb (ETableModel
*etm
,
2789 EDayView
*day_view
= E_DAY_VIEW (user_data
);
2790 GSList
*l
, *list
= data
;
2792 if (!E_CALENDAR_VIEW (day_view
)->in_focus
) {
2793 e_day_view_free_events (day_view
);
2794 day_view
->requires_update
= TRUE
;
2798 e_day_view_stop_editing_event (day_view
);
2800 for (l
= list
; l
!= NULL
; l
= g_slist_next (l
)) {
2801 ECalModelComponent
*comp_data
= l
->data
;
2802 gint day
, event_num
;
2803 const gchar
*uid
= NULL
;
2806 uid
= icalcomponent_get_uid (comp_data
->icalcomp
);
2807 if (e_cal_util_component_is_instance (comp_data
->icalcomp
)) {
2810 prop
= icalcomponent_get_first_property (comp_data
->icalcomp
, ICAL_RECURRENCEID_PROPERTY
);
2812 rid
= icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (comp_data
->icalcomp
));
2815 if (e_day_view_find_event_from_uid (day_view
, comp_data
->client
, uid
, rid
, &day
, &event_num
))
2816 e_day_view_remove_event_cb (day_view
, day
, event_num
, NULL
);
2821 gtk_widget_queue_draw (day_view
->top_canvas
);
2822 gtk_widget_queue_draw (day_view
->main_canvas
);
2823 e_day_view_queue_layout (day_view
);
2827 timezone_changed_cb (ECalModel
*cal_model
,
2828 icaltimezone
*old_zone
,
2829 icaltimezone
*new_zone
,
2832 struct icaltimetype tt
;
2834 EDayView
*day_view
= (EDayView
*) user_data
;
2835 ECalendarView
*cal_view
= (ECalendarView
*) day_view
;
2837 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
2839 if (!cal_view
->in_focus
) {
2840 e_day_view_free_events (day_view
);
2841 day_view
->requires_update
= TRUE
;
2845 /* If our time hasn't been set yet, just return. */
2846 if (day_view
->lower
== 0 && day_view
->upper
== 0)
2849 /* Recalculate the new start of the first day. We just use exactly
2850 * the same time, but with the new timezone. */
2851 tt
= icaltime_from_timet_with_zone (
2852 day_view
->lower
, FALSE
,
2855 lower
= icaltime_as_timet_with_zone (tt
, new_zone
);
2857 e_day_view_recalc_day_starts (day_view
, lower
);
2858 e_day_view_update_query (day_view
);
2859 e_day_view_update_timezone_name_labels (day_view
);
2863 init_model (EDayView
*day_view
,
2868 handler_id
= g_signal_connect (
2869 model
, "time_range_changed",
2870 G_CALLBACK (time_range_changed_cb
), day_view
);
2871 day_view
->priv
->time_range_changed_handler_id
= handler_id
;
2873 handler_id
= g_signal_connect (
2874 model
, "model_row_changed",
2875 G_CALLBACK (model_row_changed_cb
), day_view
);
2876 day_view
->priv
->model_row_changed_handler_id
= handler_id
;
2878 handler_id
= g_signal_connect (
2879 model
, "model_cell_changed",
2880 G_CALLBACK (model_cell_changed_cb
), day_view
);
2881 day_view
->priv
->model_cell_changed_handler_id
= handler_id
;
2883 handler_id
= g_signal_connect (
2884 model
, "model_rows_inserted",
2885 G_CALLBACK (model_rows_inserted_cb
), day_view
);
2886 day_view
->priv
->model_rows_inserted_handler_id
= handler_id
;
2888 handler_id
= g_signal_connect (
2889 model
, "comps_deleted",
2890 G_CALLBACK (model_comps_deleted_cb
), day_view
);
2891 day_view
->priv
->comps_deleted_handler_id
= handler_id
;
2893 handler_id
= g_signal_connect (
2894 model
, "timezone_changed",
2895 G_CALLBACK (timezone_changed_cb
), day_view
);
2896 day_view
->priv
->timezone_changed_handler_id
= handler_id
;
2899 /* Turn off the background of the canvas windows. This reduces flicker
2900 * considerably when scrolling. (Why isn't it in GnomeCanvas?). */
2902 e_day_view_on_canvas_realized (GtkWidget
*widget
,
2907 window
= gtk_layout_get_bin_window (GTK_LAYOUT (widget
));
2908 gdk_window_set_background_pattern (window
, NULL
);
2913 * @Returns: a new #EDayView.
2915 * Creates a new #EDayView.
2918 e_day_view_new (ECalModel
*model
)
2920 ECalendarView
*day_view
;
2922 g_return_val_if_fail (E_IS_CAL_MODEL (model
), NULL
);
2924 day_view
= g_object_new (E_TYPE_DAY_VIEW
, "model", model
, NULL
);
2925 init_model (E_DAY_VIEW (day_view
), model
);
2931 e_day_view_set_colors (EDayView
*day_view
)
2933 GtkWidget
*widget
= GTK_WIDGET (day_view
);
2934 GdkRGBA base_bg
, bg_bg
, selected_bg
, unfocused_selected_bg
, dark_bg
, light_bg
;
2936 e_utils_get_theme_color (widget
, "theme_base_color", E_UTILS_DEFAULT_THEME_BASE_COLOR
, &base_bg
);
2937 e_utils_get_theme_color (widget
, "theme_bg_color", E_UTILS_DEFAULT_THEME_BG_COLOR
, &bg_bg
);
2938 e_utils_get_theme_color (widget
, "theme_selected_bg_color", E_UTILS_DEFAULT_THEME_SELECTED_BG_COLOR
, &selected_bg
);
2939 e_utils_get_theme_color (widget
, "theme_unfocused_selected_bg_color,theme_selected_bg_color", E_UTILS_DEFAULT_THEME_UNFOCUSED_SELECTED_BG_COLOR
, &unfocused_selected_bg
);
2941 e_utils_shade_color (&bg_bg
, &dark_bg
, E_UTILS_DARKNESS_MULT
);
2942 e_utils_shade_color (&bg_bg
, &light_bg
, E_UTILS_LIGHTNESS_MULT
);
2944 e_rgba_to_color (&base_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_BG_WORKING
]);
2945 e_rgba_to_color (&bg_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_BG_NOT_WORKING
]);
2946 e_rgba_to_color (&selected_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_BG_SELECTED
]);
2947 e_rgba_to_color (&unfocused_selected_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED
]);
2948 e_rgba_to_color (&dark_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_BG_GRID
]);
2949 e_rgba_to_color (&dark_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_BG_TOP_CANVAS
]);
2950 e_rgba_to_color (&selected_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_SELECTED
]);
2951 e_rgba_to_color (&light_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_BG_TOP_CANVAS_GRID
]);
2952 e_rgba_to_color (&selected_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_VBAR
]);
2953 e_rgba_to_color (&base_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BACKGROUND
]);
2954 e_rgba_to_color (&dark_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_EVENT_BORDER
]);
2955 e_rgba_to_color (&base_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_LONG_EVENT_BACKGROUND
]);
2956 e_rgba_to_color (&dark_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_LONG_EVENT_BORDER
]);
2958 day_view
->colors
[E_DAY_VIEW_COLOR_BG_MULTIDAY_TODAY
] = get_today_background (day_view
->colors
[E_DAY_VIEW_COLOR_BG_WORKING
]);
2964 e_rgba_to_color (&bg_bg
, &day_view
->colors
[E_DAY_VIEW_COLOR_MARCUS_BAINS_LINE
]);
2968 e_day_view_update_top_scroll (EDayView
*day_view
,
2969 gboolean scroll_to_top
)
2971 GtkAllocation allocation
;
2972 gint top_rows
, top_canvas_height
;
2973 gdouble old_x2
, old_y2
, new_x2
, new_y2
;
2975 /* Set the height of the top canvas based on the row height and the
2976 * number of rows needed (min 1 + 1 for the dates + 1 space for DnD).*/
2977 top_rows
= MAX (1, day_view
->rows_in_top_display
);
2978 top_canvas_height
= (top_rows
+ 1) * day_view
->top_row_height
;
2979 if (top_rows
<= E_DAY_VIEW_MAX_ROWS_AT_TOP
) {
2980 gtk_widget_set_size_request (day_view
->top_canvas
, -1, top_canvas_height
);
2981 gtk_widget_hide (day_view
->tc_vscrollbar
);
2983 gtk_widget_set_size_request (day_view
->top_canvas
, -1, (E_DAY_VIEW_MAX_ROWS_AT_TOP
+ 1) * day_view
->top_row_height
);
2984 gtk_widget_show (day_view
->tc_vscrollbar
);
2987 /* Set the scroll region of the top canvas */
2988 gnome_canvas_get_scroll_region (
2989 GNOME_CANVAS (day_view
->top_canvas
),
2990 NULL
, NULL
, &old_x2
, &old_y2
);
2991 gtk_widget_get_allocation (day_view
->top_canvas
, &allocation
);
2992 new_x2
= allocation
.width
- 1;
2993 new_y2
= (MAX (1, day_view
->rows_in_top_display
) + 1) * day_view
->top_row_height
- 1;
2994 if (old_x2
!= new_x2
|| old_y2
!= new_y2
) {
2995 gnome_canvas_set_scroll_region (
2996 GNOME_CANVAS (day_view
->top_canvas
),
2997 0, 0, new_x2
, new_y2
);
3000 gnome_canvas_scroll_to (GNOME_CANVAS (day_view
->top_canvas
), 0, 0);
3002 new_y2
= day_view
->top_row_height
- 1 - 2;
3003 gnome_canvas_get_scroll_region (GNOME_CANVAS (day_view
->top_dates_canvas
), NULL
, NULL
, &old_x2
, &old_y2
);
3005 if (old_x2
!= new_x2
|| old_y2
!= new_y2
) {
3006 gnome_canvas_set_scroll_region (GNOME_CANVAS (day_view
->top_dates_canvas
), 0, 0, new_x2
, new_y2
);
3007 gnome_canvas_scroll_to (GNOME_CANVAS (day_view
->top_dates_canvas
), 0, 0);
3012 e_day_view_recalc_cell_sizes (EDayView
*day_view
)
3014 /* An array of dates, one for each month in the year 2000. They must
3015 * all be Sundays. */
3016 static const gint days
[12] = { 23, 20, 19, 23, 21, 18,
3017 23, 20, 17, 22, 19, 24 };
3018 gfloat width
, offset
;
3019 gint day
, max_width
;
3022 GtkAllocation allocation
;
3023 PangoContext
*pango_context
;
3024 PangoLayout
*layout
;
3028 days_shown
= e_day_view_get_days_shown (day_view
);
3030 gtk_widget_get_allocation (day_view
->main_canvas
, &allocation
);
3032 /* Set up Pango prerequisites */
3033 pango_context
= gtk_widget_get_pango_context (GTK_WIDGET (day_view
));
3034 layout
= pango_layout_new (pango_context
);
3036 /* Calculate the column sizes, using floating point so that pixels
3037 * get divided evenly. Note that we use one more element than the
3038 * number of columns, to make it easy to get the column widths. */
3039 width
= allocation
.width
;
3040 if (days_shown
== 1)
3041 width
= MAX (width
, day_view
->max_cols
* (E_DAY_VIEW_MIN_DAY_COL_WIDTH
+ E_DAY_VIEW_GAP_WIDTH
) - E_DAY_VIEW_MIN_DAY_COL_WIDTH
- 1);
3042 width
/= days_shown
;
3044 for (day
= 0; day
<= days_shown
; day
++) {
3045 day_view
->day_offsets
[day
] = floor (offset
+ 0.5);
3049 /* Calculate the days widths based on the offsets. */
3050 for (day
= 0; day
< days_shown
; day
++) {
3051 day_view
->day_widths
[day
] = day_view
->day_offsets
[day
+ 1] - day_view
->day_offsets
[day
];
3054 /* Determine which date format to use, based on the column widths.
3055 * We want to check the widths using the longest full or abbreviated
3056 * month name and the longest full or abbreviated weekday name, as
3058 max_width
= day_view
->day_widths
[0];
3060 memset (&date_tm
, 0, sizeof (date_tm
));
3061 date_tm
.tm_year
= 100;
3063 /* Try "Thursday 21 January". */
3064 date_tm
.tm_mon
= day_view
->longest_month_name
;
3065 date_tm
.tm_mday
= days
[date_tm
.tm_mon
]
3066 + day_view
->longest_weekday_name
;
3067 date_tm
.tm_wday
= day_view
->longest_weekday_name
;
3068 date_tm
.tm_isdst
= -1;
3069 /* strftime format %A = full weekday name, %d = day of month,
3070 * %B = full month name. Don't use any other specifiers. */
3071 e_utf8_strftime (buffer
, sizeof (buffer
), _("%A %d %B"), &date_tm
);
3072 pango_layout_set_text (layout
, buffer
, -1);
3073 pango_layout_get_pixel_size (layout
, &pango_width
, NULL
);
3075 if (pango_width
< max_width
) {
3076 day_view
->date_format
= E_DAY_VIEW_DATE_FULL
;
3080 /* Try "Thu 21 Jan". */
3081 date_tm
.tm_mon
= day_view
->longest_abbreviated_month_name
;
3082 date_tm
.tm_mday
= days
[date_tm
.tm_mon
]
3083 + day_view
->longest_abbreviated_weekday_name
;
3084 date_tm
.tm_wday
= day_view
->longest_abbreviated_weekday_name
;
3085 date_tm
.tm_isdst
= -1;
3086 /* strftime format %a = abbreviated weekday name, %d = day of month,
3087 * %b = abbreviated month name. Don't use any other specifiers. */
3088 e_utf8_strftime (buffer
, sizeof (buffer
), _("%a %d %b"), &date_tm
);
3089 pango_layout_set_text (layout
, buffer
, -1);
3090 pango_layout_get_pixel_size (layout
, &pango_width
, NULL
);
3092 if (pango_width
< max_width
) {
3093 day_view
->date_format
= E_DAY_VIEW_DATE_ABBREVIATED
;
3098 date_tm
.tm_mon
= day_view
->longest_abbreviated_month_name
;
3099 date_tm
.tm_mday
= 23;
3100 date_tm
.tm_wday
= 0;
3101 date_tm
.tm_isdst
= -1;
3102 /* strftime format %d = day of month, %b = abbreviated month name.
3103 * Don't use any other specifiers. */
3104 e_utf8_strftime (buffer
, sizeof (buffer
), _("%d %b"), &date_tm
);
3105 pango_layout_set_text (layout
, buffer
, -1);
3106 pango_layout_get_pixel_size (layout
, &pango_width
, NULL
);
3108 if (pango_width
< max_width
)
3109 day_view
->date_format
= E_DAY_VIEW_DATE_NO_WEEKDAY
;
3111 day_view
->date_format
= E_DAY_VIEW_DATE_SHORT
;
3114 g_object_unref (layout
);
3117 /* This calls a given function for each event instance (in both views).
3118 * If the callback returns FALSE the iteration is stopped.
3119 * Note that it is safe for the callback to remove the event (since we
3120 * step backwards through the arrays). */
3122 e_day_view_foreach_event (EDayView
*day_view
,
3123 EDayViewForeachEventCallback callback
,
3126 gint day
, event_num
;
3129 days_shown
= e_day_view_get_days_shown (day_view
);
3131 for (day
= 0; day
< days_shown
; day
++) {
3132 for (event_num
= day_view
->events
[day
]->len
- 1;
3135 if (!(*callback
) (day_view
, day
, event_num
, data
))
3140 for (event_num
= day_view
->long_events
->len
- 1;
3143 if (!(*callback
) (day_view
, E_DAY_VIEW_LONG_EVENT
, event_num
,
3149 /* This calls a given function for each event instance that matches the given
3150 * uid. If the callback returns FALSE the iteration is stopped.
3151 * Note that it is safe for the callback to remove the event (since we
3152 * step backwards through the arrays). */
3154 e_day_view_foreach_event_with_uid (EDayView
*day_view
,
3156 EDayViewForeachEventCallback callback
,
3159 EDayViewEvent
*event
;
3160 gint day
, event_num
;
3167 days_shown
= e_day_view_get_days_shown (day_view
);
3169 for (day
= 0; day
< days_shown
; day
++) {
3170 for (event_num
= day_view
->events
[day
]->len
- 1;
3173 event
= &g_array_index (day_view
->events
[day
],
3174 EDayViewEvent
, event_num
);
3176 if (!is_comp_data_valid (event
))
3179 u
= icalcomponent_get_uid (event
->comp_data
->icalcomp
);
3180 if (u
&& !strcmp (uid
, u
)) {
3181 if (!(*callback
) (day_view
, day
, event_num
, data
))
3187 for (event_num
= day_view
->long_events
->len
- 1;
3190 event
= &g_array_index (day_view
->long_events
,
3191 EDayViewEvent
, event_num
);
3193 if (!is_comp_data_valid (event
))
3196 u
= icalcomponent_get_uid (event
->comp_data
->icalcomp
);
3197 if (u
&& !strcmp (uid
, u
)) {
3198 if (!(*callback
) (day_view
, E_DAY_VIEW_LONG_EVENT
, event_num
, data
))
3205 e_day_view_remove_event_cb (EDayView
*day_view
,
3210 EDayViewEvent
*event
;
3212 if (day
== E_DAY_VIEW_LONG_EVENT
) {
3213 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
3216 event
= &g_array_index (day_view
->long_events
,
3217 EDayViewEvent
, event_num
);
3219 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
3222 event
= &g_array_index (day_view
->events
[day
],
3223 EDayViewEvent
, event_num
);
3229 /* If we were editing this event, set editing_event_day to -1 so
3230 * on_editing_stopped doesn't try to update the event. */
3231 if (day_view
->editing_event_num
== event_num
&& day_view
->editing_event_day
== day
) {
3232 cancel_editing (day_view
);
3233 day_view
->editing_event_num
= -1;
3234 day_view
->editing_event_day
= -1;
3235 g_object_notify (G_OBJECT (day_view
), "is-editing");
3236 } else if (day_view
->editing_event_num
> event_num
&& day_view
->editing_event_day
== day
) {
3237 day_view
->editing_event_num
--;
3240 if (day_view
->popup_event_num
== event_num
&& day_view
->popup_event_day
== day
) {
3241 day_view
->popup_event_num
= -1;
3242 day_view
->popup_event_day
= -1;
3243 } else if (day_view
->popup_event_num
> event_num
&& day_view
->popup_event_day
== day
) {
3244 day_view
->popup_event_num
--;
3247 if (event
->timeout
> 0) {
3248 g_source_remove (event
->timeout
);
3249 event
->timeout
= -1;
3252 if (day_view
->resize_bars_event_num
>= event_num
&& day_view
->resize_bars_event_day
== day
) {
3253 if (day_view
->resize_bars_event_num
== event_num
) {
3254 day_view
->resize_bars_event_num
= -1;
3255 day_view
->resize_bars_event_day
= -1;
3257 day_view
->resize_bars_event_num
--;
3261 if (day_view
->resize_event_num
>= event_num
&& day_view
->resize_event_day
== day
) {
3262 if (day_view
->resize_event_num
== event_num
) {
3263 e_day_view_abort_resize (day_view
);
3264 day_view
->resize_event_num
= -1;
3265 day_view
->resize_event_day
= -1;
3267 day_view
->resize_event_num
--;
3271 if (day_view
->pressed_event_num
>= event_num
&& day_view
->pressed_event_day
== day
) {
3272 if (day_view
->pressed_event_num
== event_num
) {
3273 day_view
->pressed_event_num
= -1;
3274 day_view
->pressed_event_day
= -1;
3276 day_view
->pressed_event_num
--;
3280 if (day_view
->drag_event_num
>= event_num
&& day_view
->drag_event_day
== day
) {
3281 if (day_view
->drag_event_num
== event_num
) {
3282 day_view
->drag_event_num
= -1;
3283 day_view
->drag_event_day
= -1;
3284 if (day_view
->priv
->drag_context
) {
3285 gtk_drag_cancel (day_view
->priv
->drag_context
);
3288 day_view
->drag_event_num
--;
3292 if (event
->canvas_item
)
3293 g_object_run_dispose (G_OBJECT (event
->canvas_item
));
3295 if (is_comp_data_valid (event
))
3296 g_object_unref (event
->comp_data
);
3297 event
->comp_data
= NULL
;
3299 if (day
== E_DAY_VIEW_LONG_EVENT
) {
3300 g_array_remove_index (day_view
->long_events
, event_num
);
3301 day_view
->long_events_need_layout
= TRUE
;
3302 gtk_widget_grab_focus (GTK_WIDGET (day_view
->top_canvas
));
3304 g_array_remove_index (day_view
->events
[day
], event_num
);
3305 day_view
->need_layout
[day
] = TRUE
;
3306 gtk_widget_grab_focus (GTK_WIDGET (day_view
->main_canvas
));
3312 /* Checks if the users participation status is NEEDS-ACTION and shows the summary as bold text */
3314 set_style_from_attendee (EDayViewEvent
*event
,
3315 ESourceRegistry
*registry
)
3317 ECalComponent
*comp
;
3318 GSList
*attendees
= NULL
, *l
;
3320 ECalComponentAttendee
*at
= NULL
;
3322 if (!is_comp_data_valid (event
))
3325 comp
= e_cal_component_new ();
3326 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
3327 address
= itip_get_comp_attendee (
3328 registry
, comp
, event
->comp_data
->client
);
3329 e_cal_component_get_attendee_list (comp
, &attendees
);
3330 for (l
= attendees
; l
; l
= l
->next
) {
3331 ECalComponentAttendee
*attendee
= l
->data
;
3333 if ((attendee
->value
&& g_strcmp0 (itip_strip_mailto (attendee
->value
), address
) == 0)
3334 || (attendee
->sentby
&& g_strcmp0 (itip_strip_mailto (attendee
->sentby
), address
) == 0)) {
3340 /* The attendee has not yet accepted the meeting, display the summary as bolded.
3341 * If the attendee is not present, it might have come through a mailing list.
3342 * In that case, we never show the meeting as bold even if it is unaccepted. */
3343 if (at
&& (at
->status
== ICAL_PARTSTAT_NEEDSACTION
))
3344 gnome_canvas_item_set (event
->canvas_item
, "bold", TRUE
, NULL
);
3345 else if (at
&& at
->status
== ICAL_PARTSTAT_DECLINED
)
3346 gnome_canvas_item_set (event
->canvas_item
, "strikeout", TRUE
, NULL
);
3347 else if (at
&& at
->status
== ICAL_PARTSTAT_TENTATIVE
)
3348 gnome_canvas_item_set (event
->canvas_item
, "italic", TRUE
, NULL
);
3349 else if (at
&& at
->status
== ICAL_PARTSTAT_DELEGATED
)
3350 gnome_canvas_item_set (event
->canvas_item
, "italic", TRUE
, "strikeout", TRUE
, NULL
);
3352 e_cal_component_free_attendee_list (attendees
);
3354 g_object_unref (comp
);
3357 /* This updates the text shown for an event. If the event start or end do not
3358 * lie on a row boundary, the time is displayed before the summary. */
3360 e_day_view_update_event_label (EDayView
*day_view
,
3364 EDayViewEvent
*event
;
3365 ECalendarView
*cal_view
;
3366 ESourceRegistry
*registry
;
3368 gboolean free_text
= FALSE
, editing_event
= FALSE
, short_event
= FALSE
;
3369 const gchar
*summary
;
3371 gint time_divisions
;
3374 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
3377 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
, event_num
);
3379 /* If the event isn't visible just return. */
3380 if (!event
->canvas_item
|| !is_comp_data_valid (event
))
3383 summary
= icalcomponent_get_summary (event
->comp_data
->icalcomp
);
3384 text
= summary
? (gchar
*) summary
: (gchar
*) "";
3386 if (day_view
->editing_event_day
== day
3387 && day_view
->editing_event_num
== event_num
)
3388 editing_event
= TRUE
;
3390 interval
= event
->end_minute
- event
->start_minute
;
3392 cal_view
= E_CALENDAR_VIEW (day_view
);
3393 model
= e_calendar_view_get_model (cal_view
);
3394 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
3396 registry
= e_cal_model_get_registry (model
);
3398 if ((interval
/ time_divisions
) >= 2)
3399 short_event
= FALSE
;
3400 else if ((interval
% time_divisions
) == 0) {
3401 if (((event
->end_minute
% time_divisions
) == 0) ||
3402 ((event
->start_minute
% time_divisions
) == 0)) {
3406 short_event
= FALSE
;
3408 if (!editing_event
) {
3410 const gchar
*description
, *location
;
3413 days_shown
= e_day_view_get_days_shown (day_view
);
3414 description
= icalcomponent_get_description (event
->comp_data
->icalcomp
);
3415 location
= icalcomponent_get_location (event
->comp_data
->icalcomp
);
3417 if (description
&& *description
) {
3418 if (location
&& *location
)
3419 text
= g_strdup_printf (" \n%s%c(%s)\n\n%s", text
, days_shown
== 1 ? ' ' : '\n', location
, description
);
3421 text
= g_strdup_printf (" \n%s\n\n%s", text
, description
);
3422 } else if (location
&& *location
)
3423 text
= g_strdup_printf (" \n%s%c(%s)", text
, days_shown
== 1 ? ' ' : '\n', location
);
3425 text
= g_strdup_printf (" \n%s", text
);
3431 gnome_canvas_item_set (
3436 if (e_cal_util_component_has_attendee (event
->comp_data
->icalcomp
))
3437 set_style_from_attendee (event
, registry
);
3444 e_day_view_update_long_event_label (EDayView
*day_view
,
3447 EDayViewEvent
*event
;
3448 ECalendarView
*cal_view
;
3450 ESourceRegistry
*registry
;
3451 const gchar
*summary
;
3452 gboolean free_text
= FALSE
;
3454 cal_view
= E_CALENDAR_VIEW (day_view
);
3455 model
= e_calendar_view_get_model (cal_view
);
3457 registry
= e_cal_model_get_registry (model
);
3459 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
3462 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
3465 /* If the event isn't visible just return. */
3466 if (!event
->canvas_item
|| !is_comp_data_valid (event
))
3469 summary
= e_calendar_view_get_icalcomponent_summary (event
->comp_data
->client
, event
->comp_data
->icalcomp
, &free_text
);
3471 gnome_canvas_item_set (
3473 "text", summary
? summary
: "",
3477 g_free ((gchar
*) summary
);
3479 if (e_cal_util_component_has_attendee (event
->comp_data
->icalcomp
))
3480 set_style_from_attendee (event
, registry
);
3483 /* Finds the day and index of the event with the given canvas item.
3484 * If is is a long event, -1 is returned as the day.
3485 * Returns TRUE if the event was found. */
3487 e_day_view_find_event_from_item (EDayView
*day_view
,
3488 GnomeCanvasItem
*item
,
3490 gint
*event_num_return
)
3492 EDayViewEvent
*event
;
3493 gint day
, event_num
;
3496 days_shown
= e_day_view_get_days_shown (day_view
);
3498 for (day
= 0; day
< days_shown
; day
++) {
3499 for (event_num
= 0; event_num
< day_view
->events
[day
]->len
;
3501 event
= &g_array_index (day_view
->events
[day
],
3502 EDayViewEvent
, event_num
);
3503 if (event
->canvas_item
== item
) {
3505 *event_num_return
= event_num
;
3511 for (event_num
= 0; event_num
< day_view
->long_events
->len
;
3513 event
= &g_array_index (day_view
->long_events
,
3514 EDayViewEvent
, event_num
);
3515 if (event
->canvas_item
== item
) {
3516 *day_return
= E_DAY_VIEW_LONG_EVENT
;
3517 *event_num_return
= event_num
;
3525 /* Finds the day and index of the event with the given uid.
3526 * If is is a long event, E_DAY_VIEW_LONG_EVENT is returned as the day.
3527 * Returns TRUE if an event with the uid was found.
3528 * Note that for recurring events there may be several EDayViewEvents, one
3529 * for each instance, all with the same iCalObject and uid. So only use this
3530 * function if you know the event doesn't recur or you are just checking to
3531 * see if any events with the uid exist. */
3533 e_day_view_find_event_from_uid (EDayView
*day_view
,
3538 gint
*event_num_return
)
3540 EDayViewEvent
*event
;
3541 gint day
, event_num
;
3549 days_shown
= e_day_view_get_days_shown (day_view
);
3551 for (day
= 0; day
< days_shown
; day
++) {
3552 for (event_num
= 0; event_num
< day_view
->events
[day
]->len
;
3554 event
= &g_array_index (day_view
->events
[day
],
3555 EDayViewEvent
, event_num
);
3557 if (!is_comp_data_valid (event
))
3560 if (event
->comp_data
->client
!= client
)
3563 u
= icalcomponent_get_uid (event
->comp_data
->icalcomp
);
3564 if (u
&& !strcmp (uid
, u
)) {
3566 r
= icaltime_as_ical_string_r (icalcomponent_get_recurrenceid (event
->comp_data
->icalcomp
));
3569 if (strcmp (rid
, r
) != 0) {
3577 *event_num_return
= event_num
;
3583 for (event_num
= 0; event_num
< day_view
->long_events
->len
;
3585 event
= &g_array_index (day_view
->long_events
,
3586 EDayViewEvent
, event_num
);
3588 if (!is_comp_data_valid (event
))
3591 if (event
->comp_data
->client
!= client
)
3594 u
= icalcomponent_get_uid (event
->comp_data
->icalcomp
);
3595 if (u
&& !strcmp (uid
, u
)) {
3596 *day_return
= E_DAY_VIEW_LONG_EVENT
;
3597 *event_num_return
= event_num
;
3606 e_day_view_set_selected_time_range_in_top_visible (EDayView
*day_view
,
3610 gint start_row
, start_col
, end_row
, end_col
;
3611 gboolean need_redraw
= FALSE
, start_in_grid
, end_in_grid
;
3613 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3615 /* Set the selection. */
3616 start_in_grid
= e_day_view_convert_time_to_grid_position (
3621 end_in_grid
= e_day_view_convert_time_to_grid_position (
3630 end_col
= e_day_view_get_days_shown (day_view
) - 1;
3632 if (start_row
!= day_view
->selection_start_row
3633 || start_col
!= day_view
->selection_start_day
) {
3635 day_view
->selection_in_top_canvas
= TRUE
;
3636 day_view
->selection_start_row
= -1;
3637 day_view
->selection_start_day
= start_col
;
3640 if (end_row
!= day_view
->selection_end_row
3641 || end_col
!= day_view
->selection_end_day
) {
3643 day_view
->selection_in_top_canvas
= TRUE
;
3644 day_view
->selection_end_row
= -1;
3645 day_view
->selection_end_day
= end_col
;
3649 gtk_widget_queue_draw (day_view
->top_canvas
);
3650 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
3651 gtk_widget_queue_draw (day_view
->main_canvas
);
3656 e_day_view_set_selected_time_range_visible (EDayView
*day_view
,
3660 gint work_day_start_hour
;
3661 gint work_day_start_minute
;
3662 gint work_day_end_hour
;
3663 gint work_day_end_minute
;
3664 gint start_row
, start_col
, end_row
, end_col
;
3665 gboolean need_redraw
= FALSE
, start_in_grid
, end_in_grid
;
3667 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3669 /* Set the selection. */
3670 start_in_grid
= e_day_view_convert_time_to_grid_position (
3675 end_in_grid
= e_day_view_convert_time_to_grid_position (
3681 e_day_view_get_work_day_range_for_day (day_view
, start_col
,
3682 &work_day_start_hour
, &work_day_start_minute
,
3683 &work_day_end_hour
, &work_day_end_minute
);
3685 /* If either of the times isn't in the grid, or the selection covers
3686 * an entire day, we set the selection to 1 row from the start of the
3687 * working day, in the day corresponding to the start time. */
3688 if (!start_in_grid
|| !end_in_grid
3689 || (start_row
== 0 && end_row
== day_view
->rows
- 1)) {
3690 end_col
= start_col
;
3692 start_row
= e_day_view_convert_time_to_row (
3693 day_view
, work_day_start_hour
, work_day_start_minute
);
3694 start_row
= CLAMP (start_row
, 0, day_view
->rows
- 1);
3695 end_row
= start_row
;
3698 if (start_row
!= day_view
->selection_start_row
3699 || start_col
!= day_view
->selection_start_day
) {
3701 day_view
->selection_in_top_canvas
= FALSE
;
3702 day_view
->selection_start_row
= start_row
;
3703 day_view
->selection_start_day
= start_col
;
3706 if (end_row
!= day_view
->selection_end_row
3707 || end_col
!= day_view
->selection_end_day
) {
3709 day_view
->selection_in_top_canvas
= FALSE
;
3710 day_view
->selection_end_row
= end_row
;
3711 day_view
->selection_end_day
= end_col
;
3715 gtk_widget_queue_draw (day_view
->top_canvas
);
3716 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
3717 gtk_widget_queue_draw (day_view
->main_canvas
);
3721 /* Finds the start of the working week which includes the given time. */
3723 e_day_view_find_work_week_start (EDayView
*day_view
,
3729 GDateWeekday weekday
;
3730 GDateWeekday first_work_day
;
3731 struct icaltimetype tt
= icaltime_null_time ();
3734 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
3735 zone
= e_cal_model_get_timezone (model
);
3737 time_to_gdate_with_zone (&date
, start_time
, zone
);
3739 /* The start of the work-week is the first working day after the
3740 * week start day. */
3742 /* Get the weekday corresponding to start_time. */
3743 weekday
= g_date_get_weekday (&date
);
3745 /* Calculate the first working day of the week. */
3746 first_work_day
= e_cal_model_get_work_day_first (model
);
3747 if (first_work_day
== G_DATE_BAD_WEEKDAY
)
3748 first_work_day
= e_cal_model_get_week_start_day (model
);
3750 /* Calculate how many days we need to go back to the first workday. */
3751 if (weekday
< first_work_day
)
3752 offset
= (weekday
+ 7) - first_work_day
;
3754 offset
= weekday
- first_work_day
;
3757 g_date_subtract_days (&date
, offset
);
3759 tt
.year
= g_date_get_year (&date
);
3760 tt
.month
= g_date_get_month (&date
);
3761 tt
.day
= g_date_get_day (&date
);
3763 return icaltime_as_timet_with_zone (tt
, zone
);
3767 e_day_view_recalc_day_starts (EDayView
*day_view
,
3773 struct icaltimetype tt
;
3776 days_shown
= e_day_view_get_days_shown (day_view
);
3777 if (days_shown
<= 0)
3780 day_view
->day_starts
[0] = start_time
;
3781 for (day
= 1; day
<= days_shown
; day
++) {
3782 day_view
->day_starts
[day
] = time_add_day_with_zone (day_view
->day_starts
[day
- 1], 1, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
3785 day_view
->lower
= start_time
;
3786 day_view
->upper
= day_view
->day_starts
[days_shown
];
3788 tt
= icaltime_from_timet_with_zone (day_view
->day_starts
[0], FALSE
, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
3789 g_date_clear (&dt
, 1);
3790 g_date_set_dmy (&dt
, tt
.day
, tt
.month
, tt
.year
);
3791 /* To Translators: the %d stands for a week number, it's value between 1 and 52/53 */
3792 str
= g_strdup_printf (_("Week %d"), g_date_get_iso8601_week_of_year (&dt
));
3793 gtk_label_set_text (GTK_LABEL (day_view
->week_number_label
), str
);
3796 e_day_view_recalc_work_week (day_view
);
3799 /* Whether we are displaying a work-week, in which case the display always
3800 * starts on the first day of the working week. */
3802 e_day_view_get_work_week_view (EDayView
*day_view
)
3804 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), FALSE
);
3806 return day_view
->priv
->work_week_view
;
3810 e_day_view_set_work_week_view (EDayView
*day_view
,
3811 gboolean work_week_view
)
3813 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3815 if (work_week_view
== day_view
->priv
->work_week_view
)
3818 day_view
->priv
->work_week_view
= work_week_view
;
3820 e_day_view_recalc_work_week (day_view
);
3824 e_day_view_get_days_shown (EDayView
*day_view
)
3826 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), -1);
3828 return day_view
->priv
->days_shown
;
3832 e_day_view_set_days_shown (EDayView
*day_view
,
3835 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3836 g_return_if_fail (days_shown
>= 1);
3837 g_return_if_fail (days_shown
<= E_DAY_VIEW_MAX_DAYS
);
3839 if (days_shown
== day_view
->priv
->days_shown
)
3842 day_view
->priv
->days_shown
= days_shown
;
3844 /* If the date isn't set, just return. */
3845 if (day_view
->lower
== 0 && day_view
->upper
== 0)
3848 e_day_view_recalc_day_starts (day_view
, day_view
->lower
);
3849 e_day_view_recalc_cell_sizes (day_view
);
3851 e_day_view_update_query (day_view
);
3855 e_day_view_recalc_work_week_days_shown (EDayView
*day_view
)
3858 GDateWeekday first_work_day
;
3859 GDateWeekday last_work_day
;
3862 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
3864 /* Find the first working day in the week. */
3865 first_work_day
= e_cal_model_get_work_day_first (model
);
3867 if (first_work_day
!= G_DATE_BAD_WEEKDAY
) {
3868 last_work_day
= e_cal_model_get_work_day_last (model
);
3870 /* Now calculate the days we need to show to include all the
3871 * working days in the week. Add 1 to make it inclusive. */
3872 days_shown
= e_weekday_get_days_between (
3873 first_work_day
, last_work_day
) + 1;
3875 /* If no working days are set, just use 7. */
3879 e_day_view_set_days_shown (day_view
, days_shown
);
3882 /* Force a redraw of the Marcus Bains Lines */
3884 e_day_view_marcus_bains_update (EDayView
*day_view
)
3886 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3887 gtk_widget_queue_draw (day_view
->main_canvas
);
3888 gtk_widget_queue_draw (day_view
->time_canvas
);
3892 e_day_view_marcus_bains_get_show_line (EDayView
*day_view
)
3894 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), FALSE
);
3896 return day_view
->priv
->marcus_bains_show_line
;
3900 e_day_view_marcus_bains_set_show_line (EDayView
*day_view
,
3903 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3905 if (show_line
== day_view
->priv
->marcus_bains_show_line
)
3908 day_view
->priv
->marcus_bains_show_line
= show_line
;
3910 e_day_view_marcus_bains_update (day_view
);
3912 g_object_notify (G_OBJECT (day_view
), "marcus-bains-show-line");
3916 e_day_view_get_draw_flat_events (EDayView
*day_view
)
3918 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), FALSE
);
3920 return day_view
->priv
->draw_flat_events
;
3924 e_day_view_set_draw_flat_events (EDayView
*day_view
,
3925 gboolean draw_flat_events
)
3927 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3929 if ((day_view
->priv
->draw_flat_events
? 1 : 0) == (draw_flat_events
? 1 : 0))
3932 day_view
->priv
->draw_flat_events
= draw_flat_events
;
3934 gtk_widget_queue_draw (day_view
->top_canvas
);
3935 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
3936 gtk_widget_queue_draw (day_view
->main_canvas
);
3938 g_object_notify (G_OBJECT (day_view
), "draw-flat-events");
3942 e_day_view_marcus_bains_get_day_view_color (EDayView
*day_view
)
3944 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), NULL
);
3946 return day_view
->priv
->marcus_bains_day_view_color
;
3950 e_day_view_marcus_bains_set_day_view_color (EDayView
*day_view
,
3951 const gchar
*day_view_color
)
3953 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3955 g_free (day_view
->priv
->marcus_bains_day_view_color
);
3956 day_view
->priv
->marcus_bains_day_view_color
= g_strdup (day_view_color
);
3958 e_day_view_marcus_bains_update (day_view
);
3960 g_object_notify (G_OBJECT (day_view
), "marcus-bains-day-view-color");
3964 e_day_view_marcus_bains_get_time_bar_color (EDayView
*day_view
)
3966 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), NULL
);
3968 return day_view
->priv
->marcus_bains_time_bar_color
;
3972 e_day_view_marcus_bains_set_time_bar_color (EDayView
*day_view
,
3973 const gchar
*time_bar_color
)
3975 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
3977 g_free (day_view
->priv
->marcus_bains_time_bar_color
);
3978 day_view
->priv
->marcus_bains_time_bar_color
= g_strdup (time_bar_color
);
3980 e_day_view_marcus_bains_update (day_view
);
3982 g_object_notify (G_OBJECT (day_view
), "marcus-bains-time-bar-color");
3985 /* Whether we display event end times in the main canvas. */
3987 e_day_view_get_show_event_end_times (EDayView
*day_view
)
3989 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), TRUE
);
3991 return day_view
->show_event_end_times
;
3995 e_day_view_set_show_event_end_times (EDayView
*day_view
,
3998 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
4000 if (day_view
->show_event_end_times
!= show
) {
4001 day_view
->show_event_end_times
= show
;
4002 e_day_view_foreach_event (day_view
,
4003 e_day_view_set_show_times_cb
, NULL
);
4007 /* This is a callback used to update all day event labels. */
4009 e_day_view_set_show_times_cb (EDayView
*day_view
,
4014 if (day
!= E_DAY_VIEW_LONG_EVENT
) {
4015 e_day_view_update_event_label (day_view
, day
, event_num
);
4022 e_day_view_recalc_work_week (EDayView
*day_view
)
4026 /* If we aren't showing the work week, just return. */
4027 if (!e_day_view_get_work_week_view (day_view
))
4030 e_day_view_recalc_work_week_days_shown (day_view
);
4032 /* If the date isn't set, just return. */
4033 if (day_view
->lower
== 0 && day_view
->upper
== 0)
4036 lower
= e_day_view_find_work_week_start (day_view
, day_view
->lower
);
4037 if (lower
!= day_view
->lower
) {
4038 /* Reset the selection, as it may disappear. */
4039 day_view
->selection_start_day
= -1;
4041 e_day_view_recalc_day_starts (day_view
, lower
);
4042 e_day_view_update_query (day_view
);
4044 /* This updates the date navigator. */
4045 e_day_view_update_calendar_selection_time (day_view
);
4050 e_day_view_update_scroll_regions (EDayView
*day_view
)
4052 GtkAllocation main_canvas_allocation
;
4053 GtkAllocation time_canvas_allocation
;
4054 gdouble old_x2
, old_y2
, new_x2
, new_y2
;
4055 gboolean need_reshape
= FALSE
;
4057 gtk_widget_get_allocation (
4058 day_view
->main_canvas
, &main_canvas_allocation
);
4059 gtk_widget_get_allocation (
4060 day_view
->time_canvas
, &time_canvas_allocation
);
4062 /* Set the scroll region of the time canvas to its allocated width,
4063 * but with the height the same as the main canvas. */
4064 gnome_canvas_get_scroll_region (
4065 GNOME_CANVAS (day_view
->time_canvas
),
4066 NULL
, NULL
, &old_x2
, &old_y2
);
4067 new_x2
= time_canvas_allocation
.width
- 1;
4069 day_view
->rows
* day_view
->row_height
,
4070 main_canvas_allocation
.height
- 1);
4071 if (old_x2
!= new_x2
|| old_y2
!= new_y2
)
4072 gnome_canvas_set_scroll_region (GNOME_CANVAS (day_view
->time_canvas
),
4073 0, 0, new_x2
, new_y2
);
4075 /* Set the scroll region of the main canvas to its allocated width,
4076 * but with the height depending on the number of rows needed. */
4077 gnome_canvas_get_scroll_region (
4078 GNOME_CANVAS (day_view
->main_canvas
),
4079 NULL
, NULL
, &old_x2
, &old_y2
);
4080 new_x2
= main_canvas_allocation
.width
- 1;
4082 if (e_day_view_get_days_shown (day_view
) == 1)
4083 new_x2
= MAX (new_x2
, day_view
->max_cols
* (E_DAY_VIEW_MIN_DAY_COL_WIDTH
+ E_DAY_VIEW_GAP_WIDTH
) - E_DAY_VIEW_MIN_DAY_COL_WIDTH
- 1);
4085 if (old_x2
!= new_x2
|| old_y2
!= new_y2
) {
4086 need_reshape
= TRUE
;
4087 gnome_canvas_set_scroll_region (
4088 GNOME_CANVAS (day_view
->main_canvas
),
4089 0, 0, new_x2
, new_y2
);
4092 if (new_x2
<= main_canvas_allocation
.width
- 1)
4093 gtk_widget_hide (day_view
->mc_hscrollbar
);
4095 gtk_widget_show (day_view
->mc_hscrollbar
);
4097 return need_reshape
;
4100 /* This recalculates the number of rows to display, based on the time range
4101 * shown and the minutes per row. */
4103 e_day_view_recalc_num_rows (EDayView
*day_view
)
4105 ECalendarView
*cal_view
;
4106 gint time_divisions
;
4107 gint hours
, minutes
, total_minutes
;
4109 cal_view
= E_CALENDAR_VIEW (day_view
);
4110 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
4112 hours
= day_view
->last_hour_shown
- day_view
->first_hour_shown
;
4113 /* This could be negative but it works out OK. */
4114 minutes
= day_view
->last_minute_shown
- day_view
->first_minute_shown
;
4115 total_minutes
= hours
* 60 + minutes
;
4116 day_view
->rows
= total_minutes
/ time_divisions
;
4119 /* Converts an hour and minute to a row in the canvas. Note that if we aren't
4120 * showing all 24 hours of the day, the returned row may be negative or
4121 * greater than day_view->rows. */
4123 e_day_view_convert_time_to_row (EDayView
*day_view
,
4127 ECalendarView
*cal_view
;
4128 gint time_divisions
;
4129 gint total_minutes
, start_minute
, offset
;
4131 cal_view
= E_CALENDAR_VIEW (day_view
);
4132 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
4134 total_minutes
= hour
* 60 + minute
;
4135 start_minute
= day_view
->first_hour_shown
* 60
4136 + day_view
->first_minute_shown
;
4137 offset
= total_minutes
- start_minute
;
4141 return offset
/ time_divisions
;
4144 /* Converts an hour and minute to a y coordinate in the canvas. */
4146 e_day_view_convert_time_to_position (EDayView
*day_view
,
4150 ECalendarView
*cal_view
;
4151 gint time_divisions
;
4152 gint total_minutes
, start_minute
, offset
;
4154 cal_view
= E_CALENDAR_VIEW (day_view
);
4155 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
4157 total_minutes
= hour
* 60 + minute
;
4158 start_minute
= day_view
->first_hour_shown
* 60
4159 + day_view
->first_minute_shown
;
4160 offset
= total_minutes
- start_minute
;
4162 return offset
* day_view
->row_height
/ time_divisions
;
4166 e_day_view_on_top_canvas_button_press (GtkWidget
*widget
,
4167 GdkEvent
*button_event
,
4170 gint event_x
, event_y
, day
, event_num
;
4171 ECalendarViewPosition pos
;
4174 GdkDevice
*event_device
;
4175 guint event_button
= 0;
4178 layout
= GTK_LAYOUT (widget
);
4179 window
= gtk_layout_get_bin_window (layout
);
4181 gdk_event_get_button (button_event
, &event_button
);
4182 event_device
= gdk_event_get_device (button_event
);
4183 event_time
= gdk_event_get_time (button_event
);
4185 if (day_view
->resize_event_num
!= -1)
4186 day_view
->resize_event_num
= -1;
4188 if (day_view
->drag_event_num
!= -1)
4189 day_view
->drag_event_num
= -1;
4191 /* Convert the coords to the main canvas window, or return if the
4192 * window is not found. */
4193 if (!e_day_view_convert_event_coords (
4194 day_view
, button_event
, window
, &event_x
, &event_y
))
4197 pos
= e_day_view_convert_position_in_top_canvas (
4202 if (pos
== E_CALENDAR_VIEW_POS_OUTSIDE
)
4205 if (pos
!= E_CALENDAR_VIEW_POS_NONE
)
4206 return e_day_view_on_long_event_button_press (
4214 e_day_view_stop_editing_event (day_view
);
4216 if (event_button
== 1) {
4217 GdkGrabStatus grab_status
;
4219 if (button_event
->type
== GDK_2BUTTON_PRESS
) {
4220 time_t dtstart
, dtend
;
4222 day_view_get_selected_time_range ((ECalendarView
*) day_view
, &dtstart
, &dtend
);
4223 if (dtstart
< day_view
->before_click_dtend
&& dtend
> day_view
->before_click_dtstart
) {
4224 dtstart
= day_view
->before_click_dtstart
;
4225 dtend
= day_view
->before_click_dtend
;
4226 day_view_set_selected_time_range ((ECalendarView
*) day_view
, dtstart
, dtend
);
4229 e_cal_ops_new_component_editor_from_model (
4230 e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
)), NULL
,
4231 dtstart
, dtend
, calendar_config_get_prefer_meeting (), TRUE
);
4235 if (!gtk_widget_has_focus (GTK_WIDGET (day_view
)))
4236 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
4238 grab_status
= gdk_device_grab (
4243 GDK_POINTER_MOTION_MASK
|
4244 GDK_BUTTON_RELEASE_MASK
,
4248 if (grab_status
== GDK_GRAB_SUCCESS
) {
4249 g_warn_if_fail (day_view
->grabbed_pointer
== NULL
);
4250 day_view
->grabbed_pointer
= g_object_ref (event_device
);
4252 if (event_time
- day_view
->bc_event_time
> 250)
4253 day_view_get_selected_time_range (
4254 E_CALENDAR_VIEW (day_view
),
4255 &day_view
->before_click_dtstart
,
4256 &day_view
->before_click_dtend
);
4257 day_view
->bc_event_time
= event_time
;
4258 e_day_view_start_selection (day_view
, day
, -1);
4260 } else if (event_button
== 3) {
4261 if (!gtk_widget_has_focus (GTK_WIDGET (day_view
)))
4262 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
4264 if (day
< day_view
->selection_start_day
|| day
> day_view
->selection_end_day
) {
4265 e_day_view_start_selection (day_view
, day
, -1);
4266 e_day_view_finish_selection (day_view
);
4269 e_day_view_on_event_right_click (day_view
, button_event
, -1, -1);
4276 e_day_view_convert_event_coords (EDayView
*day_view
,
4282 gint event_x
, event_y
, win_x
, win_y
;
4283 GdkWindow
*event_window
;;
4285 /* Get the event window, x & y from the appropriate event struct. */
4286 switch (event
->type
) {
4287 case GDK_BUTTON_PRESS
:
4288 case GDK_2BUTTON_PRESS
:
4289 case GDK_3BUTTON_PRESS
:
4290 case GDK_BUTTON_RELEASE
:
4291 event_x
= event
->button
.x
;
4292 event_y
= event
->button
.y
;
4293 event_window
= event
->button
.window
;
4295 case GDK_MOTION_NOTIFY
:
4296 event_x
= event
->motion
.x
;
4297 event_y
= event
->motion
.y
;
4298 event_window
= event
->motion
.window
;
4300 case GDK_ENTER_NOTIFY
:
4301 case GDK_LEAVE_NOTIFY
:
4302 event_x
= event
->crossing
.x
;
4303 event_y
= event
->crossing
.y
;
4304 event_window
= event
->crossing
.window
;
4307 /* Shouldn't get here. */
4308 g_return_val_if_reached (FALSE
);
4311 while (event_window
&& event_window
!= window
4312 && event_window
!= gdk_get_default_root_window ()) {
4313 gdk_window_get_position (event_window
, &win_x
, &win_y
);
4316 event_window
= gdk_window_get_parent (event_window
);
4319 *x_return
= event_x
;
4320 *y_return
= event_y
;
4322 return (event_window
== window
) ? TRUE
: FALSE
;
4326 e_day_view_on_main_canvas_button_press (GtkWidget
*widget
,
4327 GdkEvent
*button_event
,
4330 gint event_x
, event_y
, row
, day
, event_num
;
4331 ECalendarViewPosition pos
;
4334 GdkDevice
*event_device
;
4335 guint event_button
= 0;
4338 layout
= GTK_LAYOUT (widget
);
4339 window
= gtk_layout_get_bin_window (layout
);
4341 gdk_event_get_button (button_event
, &event_button
);
4342 event_device
= gdk_event_get_device (button_event
);
4343 event_time
= gdk_event_get_time (button_event
);
4345 if (day_view
->resize_event_num
!= -1)
4346 day_view
->resize_event_num
= -1;
4348 if (day_view
->drag_event_num
!= -1)
4349 day_view
->drag_event_num
= -1;
4351 /* Convert the coords to the main canvas window, or return if the
4352 * window is not found. */
4353 if (!e_day_view_convert_event_coords (
4354 day_view
, button_event
, window
, &event_x
, &event_y
))
4357 /* Find out where the mouse is. */
4358 pos
= e_day_view_convert_position_in_main_canvas (
4364 if (pos
== E_CALENDAR_VIEW_POS_OUTSIDE
)
4367 if (pos
!= E_CALENDAR_VIEW_POS_NONE
)
4368 return e_day_view_on_event_button_press (
4377 e_day_view_stop_editing_event (day_view
);
4379 /* Start the selection drag. */
4380 if (event_button
== 1) {
4381 GdkGrabStatus grab_status
;
4383 if (button_event
->type
== GDK_2BUTTON_PRESS
) {
4384 time_t dtstart
, dtend
;
4386 day_view_get_selected_time_range ((ECalendarView
*) day_view
, &dtstart
, &dtend
);
4387 if (dtstart
< day_view
->before_click_dtend
&& dtend
> day_view
->before_click_dtstart
) {
4388 dtstart
= day_view
->before_click_dtstart
;
4389 dtend
= day_view
->before_click_dtend
;
4390 day_view_set_selected_time_range ((ECalendarView
*) day_view
, dtstart
, dtend
);
4392 e_cal_ops_new_component_editor_from_model (
4393 e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
)), NULL
,
4394 dtstart
, dtend
, calendar_config_get_prefer_meeting (), FALSE
);
4398 if (!gtk_widget_has_focus (GTK_WIDGET (day_view
)) && !gtk_widget_has_focus (GTK_WIDGET (day_view
->main_canvas
)))
4399 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
4401 grab_status
= gdk_device_grab (
4406 GDK_POINTER_MOTION_MASK
|
4407 GDK_BUTTON_RELEASE_MASK
,
4411 if (grab_status
== GDK_GRAB_SUCCESS
) {
4412 g_warn_if_fail (day_view
->grabbed_pointer
== NULL
);
4413 day_view
->grabbed_pointer
= g_object_ref (event_device
);
4415 if (event_time
- day_view
->bc_event_time
> 250)
4416 day_view_get_selected_time_range (
4417 E_CALENDAR_VIEW (day_view
),
4418 &day_view
->before_click_dtstart
,
4419 &day_view
->before_click_dtend
);
4420 day_view
->bc_event_time
= event_time
;
4421 e_day_view_start_selection (day_view
, day
, row
);
4422 g_signal_emit_by_name (day_view
, "selected_time_changed");
4424 } else if (event_button
== 3) {
4425 if (!gtk_widget_has_focus (GTK_WIDGET (day_view
)))
4426 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
4428 if ((day
< day_view
->selection_start_day
|| day
> day_view
->selection_end_day
)
4429 || (day
== day_view
->selection_start_day
&& row
< day_view
->selection_start_row
)
4430 || (day
== day_view
->selection_end_day
&& row
> day_view
->selection_end_row
)) {
4431 e_day_view_start_selection (day_view
, day
, row
);
4432 e_day_view_finish_selection (day_view
);
4435 e_day_view_on_event_right_click (day_view
, button_event
, -1, -1);
4442 e_day_view_on_main_canvas_scroll (GtkWidget
*widget
,
4443 GdkEventScroll
*scroll
,
4446 switch (scroll
->direction
) {
4448 e_day_view_scroll (day_view
, E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
);
4450 case GDK_SCROLL_DOWN
:
4451 e_day_view_scroll (day_view
, -E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
);
4453 case GDK_SCROLL_SMOOTH
:
4454 if (scroll
->delta_y
< -0.001 || scroll
->delta_y
> 0.001) {
4455 e_day_view_scroll (day_view
, -E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
* scroll
->delta_y
);
4467 e_day_view_on_top_canvas_scroll (GtkWidget
*widget
,
4468 GdkEventScroll
*scroll
,
4471 switch (scroll
->direction
) {
4473 e_day_view_top_scroll (day_view
, E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
);
4475 case GDK_SCROLL_DOWN
:
4476 e_day_view_top_scroll (day_view
, -E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
);
4478 case GDK_SCROLL_SMOOTH
:
4479 if (scroll
->delta_y
< -0.001 || scroll
->delta_y
> 0.001) {
4480 e_day_view_top_scroll (day_view
, -E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
* scroll
->delta_y
);
4492 e_day_view_on_time_canvas_scroll (GtkWidget
*widget
,
4493 GdkEventScroll
*scroll
,
4496 GtkWidget
*tool_window
= g_object_get_data ((GObject
*) day_view
, "tooltip-window");
4499 gtk_widget_destroy (tool_window
);
4500 g_object_set_data (G_OBJECT (day_view
), "tooltip-window", NULL
);
4503 switch (scroll
->direction
) {
4505 e_day_view_scroll (day_view
, E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
);
4507 case GDK_SCROLL_DOWN
:
4508 e_day_view_scroll (day_view
, -E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
);
4510 case GDK_SCROLL_SMOOTH
:
4511 if (scroll
->delta_y
< -0.001 || scroll
->delta_y
> 0.001) {
4512 e_day_view_scroll (day_view
, -E_DAY_VIEW_WHEEL_MOUSE_STEP_SIZE
* scroll
->delta_y
);
4524 e_day_view_on_long_event_button_press (EDayView
*day_view
,
4526 GdkEvent
*button_event
,
4527 ECalendarViewPosition pos
,
4531 guint event_button
= 0;
4533 gdk_event_get_button (button_event
, &event_button
);
4535 if (event_button
== 1) {
4536 if (button_event
->type
== GDK_BUTTON_PRESS
) {
4537 e_day_view_on_long_event_click (
4538 day_view
, event_num
,
4542 } else if (button_event
->type
== GDK_2BUTTON_PRESS
) {
4543 e_day_view_on_event_double_click (
4546 g_signal_stop_emission_by_name (day_view
->top_canvas
, "button_press_event");
4549 } else if (event_button
== 3) {
4552 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
4555 e
= &g_array_index (day_view
->long_events
, EDayViewEvent
, event_num
);
4557 e_day_view_set_selected_time_range_in_top_visible (day_view
, e
->start
, e
->end
);
4559 e_day_view_on_event_right_click (
4560 day_view
, button_event
,
4561 E_DAY_VIEW_LONG_EVENT
,
4570 e_day_view_on_event_button_press (EDayView
*day_view
,
4573 GdkEvent
*button_event
,
4574 ECalendarViewPosition pos
,
4578 guint event_button
= 0;
4580 gdk_event_get_button (button_event
, &event_button
);
4582 if (event_button
== 1) {
4583 if (button_event
->type
== GDK_BUTTON_PRESS
) {
4584 e_day_view_on_event_click (
4585 day_view
, day
, event_num
,
4589 } else if (button_event
->type
== GDK_2BUTTON_PRESS
) {
4590 e_day_view_on_event_double_click (
4594 g_signal_stop_emission_by_name (day_view
->main_canvas
, "button_press_event");
4597 } else if (event_button
== 3) {
4600 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
4603 e
= &g_array_index (day_view
->events
[day
], EDayViewEvent
, event_num
);
4605 e_day_view_set_selected_time_range_visible (day_view
, e
->start
, e
->end
);
4607 e_day_view_on_event_right_click (
4608 day_view
, button_event
, day
, event_num
);
4616 e_day_view_on_long_event_click (EDayView
*day_view
,
4618 GdkEvent
*button_event
,
4619 ECalendarViewPosition pos
,
4623 EDayViewEvent
*event
;
4626 gint start_day
, end_day
, day
;
4627 gint item_x
, item_y
, item_w
, item_h
;
4629 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
4632 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
4635 if (!is_comp_data_valid (event
))
4638 /* Ignore clicks on the EText while editing. */
4639 if (pos
== E_CALENDAR_VIEW_POS_EVENT
4640 && E_TEXT (event
->canvas_item
)->editing
) {
4641 GNOME_CANVAS_ITEM_GET_CLASS (event
->canvas_item
)->event (
4642 event
->canvas_item
, button_event
);
4646 if ((e_cal_util_component_is_instance (event
->comp_data
->icalcomp
) ||
4647 !e_cal_util_component_has_recurrences (event
->comp_data
->icalcomp
))
4648 && (pos
== E_CALENDAR_VIEW_POS_LEFT_EDGE
4649 || pos
== E_CALENDAR_VIEW_POS_RIGHT_EDGE
)) {
4650 GdkGrabStatus grab_status
;
4651 GdkDevice
*event_device
;
4654 if (!e_day_view_find_long_event_days (
4656 e_day_view_get_days_shown (day_view
),
4657 day_view
->day_starts
,
4658 &start_day
, &end_day
))
4661 /* Grab the keyboard focus, so the event being edited is saved
4662 * and we can use the Escape key to abort the resize. */
4663 if (!gtk_widget_has_focus (GTK_WIDGET (day_view
)))
4664 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
4666 layout
= GTK_LAYOUT (day_view
->top_canvas
);
4667 window
= gtk_layout_get_bin_window (layout
);
4669 event_device
= gdk_event_get_device (button_event
);
4670 event_time
= gdk_event_get_time (button_event
);
4672 grab_status
= gdk_device_grab (
4677 GDK_POINTER_MOTION_MASK
|
4678 GDK_BUTTON_RELEASE_MASK
,
4682 if (grab_status
== GDK_GRAB_SUCCESS
) {
4683 g_warn_if_fail (day_view
->grabbed_pointer
== NULL
);
4684 day_view
->grabbed_pointer
= g_object_ref (event_device
);
4686 day_view
->resize_event_day
= E_DAY_VIEW_LONG_EVENT
;
4687 day_view
->resize_event_num
= event_num
;
4688 day_view
->resize_drag_pos
= pos
;
4689 day_view
->resize_start_row
= start_day
;
4690 day_view
->resize_end_row
= end_day
;
4692 /* Raise the event's item, above the rect as well. */
4693 gnome_canvas_item_raise_to_top (event
->canvas_item
);
4695 } else if (e_day_view_get_long_event_position (day_view
, event_num
,
4696 &start_day
, &end_day
,
4698 &item_w
, &item_h
)) {
4699 /* Remember the item clicked and the mouse position,
4700 * so we can start a drag if the mouse moves. */
4701 day_view
->pressed_event_day
= E_DAY_VIEW_LONG_EVENT
;
4702 day_view
->pressed_event_num
= event_num
;
4704 day_view
->drag_event_x
= event_x
;
4705 day_view
->drag_event_y
= event_y
;
4707 pos
= e_day_view_convert_position_in_top_canvas (
4712 if (pos
!= E_CALENDAR_VIEW_POS_NONE
&& pos
!= E_CALENDAR_VIEW_POS_OUTSIDE
)
4713 day_view
->drag_event_offset
= day
- start_day
;
4718 e_day_view_on_event_click (EDayView
*day_view
,
4721 GdkEvent
*button_event
,
4722 ECalendarViewPosition pos
,
4726 EDayViewEvent
*event
;
4727 ECalendarView
*cal_view
;
4730 gint time_divisions
;
4731 gint tmp_day
, row
, start_row
;
4733 cal_view
= E_CALENDAR_VIEW (day_view
);
4734 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
4736 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
4739 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
4742 if (!is_comp_data_valid (event
))
4745 /* Ignore clicks on the EText while editing. */
4746 if (pos
== E_CALENDAR_VIEW_POS_EVENT
4747 && E_TEXT (event
->canvas_item
)->editing
) {
4748 GNOME_CANVAS_ITEM_GET_CLASS (event
->canvas_item
)->event (
4749 event
->canvas_item
, button_event
);
4753 if ((e_cal_util_component_is_instance (event
->comp_data
->icalcomp
) ||
4754 !e_cal_util_component_has_recurrences (event
->comp_data
->icalcomp
))
4755 && (pos
== E_CALENDAR_VIEW_POS_TOP_EDGE
4756 || pos
== E_CALENDAR_VIEW_POS_BOTTOM_EDGE
)) {
4757 GdkGrabStatus grab_status
;
4758 GdkDevice
*event_device
;
4761 if (event
&& (!event
->is_editable
|| e_client_is_readonly (E_CLIENT (event
->comp_data
->client
)))) {
4765 /* Grab the keyboard focus, so the event being edited is saved
4766 * and we can use the Escape key to abort the resize. */
4767 if (!gtk_widget_has_focus (GTK_WIDGET (day_view
)))
4768 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
4770 layout
= GTK_LAYOUT (day_view
->main_canvas
);
4771 window
= gtk_layout_get_bin_window (layout
);
4773 event_device
= gdk_event_get_device (button_event
);
4774 event_time
= gdk_event_get_time (button_event
);
4776 grab_status
= gdk_device_grab (
4781 GDK_POINTER_MOTION_MASK
|
4782 GDK_BUTTON_RELEASE_MASK
,
4786 if (grab_status
== GDK_GRAB_SUCCESS
) {
4787 g_warn_if_fail (day_view
->grabbed_pointer
== NULL
);
4788 day_view
->grabbed_pointer
= g_object_ref (event_device
);
4790 day_view
->resize_event_day
= day
;
4791 day_view
->resize_event_num
= event_num
;
4792 day_view
->resize_drag_pos
= pos
;
4793 day_view
->resize_start_row
= event
->start_minute
/ time_divisions
;
4794 day_view
->resize_end_row
= (event
->end_minute
- 1) / time_divisions
;
4795 if (day_view
->resize_end_row
< day_view
->resize_start_row
)
4796 day_view
->resize_end_row
= day_view
->resize_start_row
;
4798 day_view
->resize_bars_event_day
= day
;
4799 day_view
->resize_bars_event_num
= event_num
;
4801 e_day_view_reshape_main_canvas_resize_bars (day_view
);
4803 /* Raise the event's item, above the rect as well. */
4804 gnome_canvas_item_raise_to_top (event
->canvas_item
);
4808 /* Remember the item clicked and the mouse position,
4809 * so we can start a drag if the mouse moves. */
4810 day_view
->pressed_event_day
= day
;
4811 day_view
->pressed_event_num
= event_num
;
4813 day_view
->drag_event_x
= event_x
;
4814 day_view
->drag_event_y
= event_y
;
4816 pos
= e_day_view_convert_position_in_main_canvas (
4822 if (pos
!= E_CALENDAR_VIEW_POS_NONE
&& pos
!= E_CALENDAR_VIEW_POS_OUTSIDE
) {
4823 start_row
= event
->start_minute
/ time_divisions
;
4824 day_view
->drag_event_offset
= row
- start_row
;
4830 e_day_view_on_event_double_click (EDayView
*day_view
,
4834 EDayViewEvent
*event
;
4837 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
4840 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
4843 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
4846 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
4850 if (!is_comp_data_valid (event
))
4853 e_calendar_view_edit_appointment ((ECalendarView
*) day_view
, event
->comp_data
->client
, event
->comp_data
->icalcomp
, EDIT_EVENT_AUTODETECT
);
4857 e_day_view_show_popup_menu (EDayView
*day_view
,
4858 GdkEvent
*button_event
,
4862 EDayViewEvent
*pevent
= NULL
;
4865 pevent
= tooltip_get_view_event (day_view
, day
, event_num
);
4867 if (pevent
&& pevent
->canvas_item
)
4868 tooltip_destroy (day_view
, pevent
->canvas_item
);
4870 day_view
->popup_event_day
= day
;
4871 day_view
->popup_event_num
= event_num
;
4873 e_calendar_view_popup_event (E_CALENDAR_VIEW (day_view
), button_event
);
4876 /* Restarts a query for the day view */
4878 e_day_view_update_query (EDayView
*day_view
)
4882 if (!E_CALENDAR_VIEW (day_view
)->in_focus
) {
4883 e_day_view_free_events (day_view
);
4884 day_view
->requires_update
= TRUE
;
4888 day_view
->requires_update
= FALSE
;
4890 e_day_view_stop_editing_event (day_view
);
4892 gtk_widget_queue_draw (day_view
->top_canvas
);
4893 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
4894 gtk_widget_queue_draw (day_view
->main_canvas
);
4895 e_day_view_free_events (day_view
);
4896 e_day_view_queue_layout (day_view
);
4898 rows
= e_table_model_row_count (E_TABLE_MODEL (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
))));
4899 for (r
= 0; r
< rows
; r
++) {
4900 ECalModelComponent
*comp_data
;
4902 comp_data
= e_cal_model_get_component_at (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
)), r
);
4903 g_return_if_fail (comp_data
!= NULL
);
4904 process_component (day_view
, comp_data
);
4909 e_day_view_on_event_right_click (EDayView
*day_view
,
4910 GdkEvent
*button_event
,
4914 e_day_view_show_popup_menu (day_view
, button_event
, day
, event_num
);
4918 e_day_view_on_top_canvas_button_release (GtkWidget
*widget
,
4919 GdkEvent
*button_event
,
4922 GdkDevice
*event_device
;
4925 event_device
= gdk_event_get_device (button_event
);
4926 event_time
= gdk_event_get_time (button_event
);
4928 if (day_view
->grabbed_pointer
== event_device
) {
4929 gdk_device_ungrab (day_view
->grabbed_pointer
, event_time
);
4930 g_object_unref (day_view
->grabbed_pointer
);
4931 day_view
->grabbed_pointer
= NULL
;
4934 if (day_view
->selection_is_being_dragged
) {
4935 e_day_view_finish_selection (day_view
);
4936 } else if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
) {
4937 e_day_view_finish_long_event_resize (day_view
);
4938 } else if (day_view
->pressed_event_day
!= -1) {
4939 e_day_view_start_editing_event (
4941 day_view
->pressed_event_day
,
4942 day_view
->pressed_event_num
,
4946 day_view
->pressed_event_day
= -1;
4952 e_day_view_on_main_canvas_button_release (GtkWidget
*widget
,
4953 GdkEvent
*button_event
,
4956 GdkDevice
*event_device
;
4959 event_device
= gdk_event_get_device (button_event
);
4960 event_time
= gdk_event_get_time (button_event
);
4962 if (day_view
->grabbed_pointer
== event_device
) {
4963 gdk_device_ungrab (day_view
->grabbed_pointer
, event_time
);
4964 g_object_unref (day_view
->grabbed_pointer
);
4965 day_view
->grabbed_pointer
= NULL
;
4968 if (day_view
->selection_is_being_dragged
) {
4969 e_day_view_finish_selection (day_view
);
4970 e_day_view_stop_auto_scroll (day_view
);
4971 } else if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
) {
4972 e_day_view_finish_resize (day_view
);
4973 e_day_view_stop_auto_scroll (day_view
);
4974 } else if (day_view
->pressed_event_day
!= -1) {
4975 e_day_view_start_editing_event (
4977 day_view
->pressed_event_day
,
4978 day_view
->pressed_event_num
,
4982 day_view
->pressed_event_day
= -1;
4988 e_day_view_update_calendar_selection_time (EDayView
*day_view
)
4992 day_view_get_selected_time_range ((ECalendarView
*) day_view
, &start
, &end
);
4996 e_day_view_on_top_canvas_motion (GtkWidget
*widget
,
4997 GdkEventMotion
*mevent
,
5000 EDayViewEvent
*event
= NULL
;
5001 ECalendarViewPosition pos
;
5002 gint event_x
, event_y
, canvas_x
, canvas_y
;
5003 gint day
, event_num
;
5007 window
= gtk_layout_get_bin_window (GTK_LAYOUT (widget
));
5009 /* Convert the coords to the main canvas window, or return if the
5010 * window is not found. */
5011 if (!e_day_view_convert_event_coords (
5012 day_view
, (GdkEvent
*) mevent
, window
, &event_x
, &event_y
))
5018 pos
= e_day_view_convert_position_in_top_canvas (
5022 if (event_num
!= -1) {
5023 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
5026 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
5030 if (day_view
->selection_is_being_dragged
) {
5031 e_day_view_update_selection (day_view
, day
, -1);
5033 } else if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
) {
5034 if (pos
!= E_CALENDAR_VIEW_POS_OUTSIDE
) {
5035 e_day_view_update_long_event_resize (day_view
, day
);
5038 } else if (day_view
->pressed_event_day
== E_DAY_VIEW_LONG_EVENT
) {
5039 GtkTargetList
*target_list
;
5041 if (!is_array_index_in_bounds (day_view
->long_events
, day_view
->pressed_event_num
))
5044 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
5045 day_view
->pressed_event_num
);
5047 if (!is_comp_data_valid (event
))
5050 if (!e_cal_util_component_has_recurrences (event
->comp_data
->icalcomp
)
5051 && gtk_drag_check_threshold (widget
, day_view
->drag_event_x
, day_view
->drag_event_y
, canvas_x
, canvas_y
)) {
5052 day_view
->drag_event_day
= day_view
->pressed_event_day
;
5053 day_view
->drag_event_num
= day_view
->pressed_event_num
;
5054 day_view
->pressed_event_day
= -1;
5056 /* Hide the horizontal bars. */
5057 if (day_view
->resize_bars_event_day
!= -1) {
5058 day_view
->resize_bars_event_day
= -1;
5059 day_view
->resize_bars_event_num
= -1;
5062 target_list
= gtk_target_list_new (
5063 target_table
, G_N_ELEMENTS (target_table
));
5064 e_target_list_add_calendar_targets (target_list
, 0);
5065 g_clear_object (&day_view
->priv
->drag_context
);
5066 day_view
->priv
->drag_context
= gtk_drag_begin (
5067 widget
, target_list
,
5068 GDK_ACTION_COPY
| GDK_ACTION_MOVE
,
5069 1, (GdkEvent
*) mevent
);
5070 gtk_target_list_unref (target_list
);
5072 if (day_view
->priv
->drag_context
)
5073 g_object_ref (day_view
->priv
->drag_context
);
5076 cursor
= day_view
->normal_cursor
;
5078 /* Recurring events can't be resized. */
5079 if (event
&& is_comp_data_valid (event
) && !e_cal_util_component_has_recurrences (event
->comp_data
->icalcomp
)) {
5081 case E_CALENDAR_VIEW_POS_LEFT_EDGE
:
5082 case E_CALENDAR_VIEW_POS_RIGHT_EDGE
:
5083 cursor
= day_view
->resize_width_cursor
;
5090 /* Only set the cursor if it is different to last one set. */
5091 if (day_view
->last_cursor_set_in_top_canvas
!= cursor
) {
5094 day_view
->last_cursor_set_in_top_canvas
= cursor
;
5096 window
= gtk_widget_get_window (widget
);
5097 gdk_window_set_cursor (window
, cursor
);
5100 if (event
&& E_IS_TEXT (event
->canvas_item
) && E_TEXT (event
->canvas_item
)->editing
) {
5101 GNOME_CANVAS_ITEM_GET_CLASS (event
->canvas_item
)->event (event
->canvas_item
, (GdkEvent
*) mevent
);
5109 e_day_view_on_main_canvas_motion (GtkWidget
*widget
,
5110 GdkEventMotion
*mevent
,
5113 EDayViewEvent
*event
= NULL
;
5114 ECalendarViewPosition pos
;
5115 gint event_x
, event_y
, canvas_x
, canvas_y
;
5116 gint row
, day
, event_num
;
5120 window
= gtk_layout_get_bin_window (GTK_LAYOUT (widget
));
5122 /* Convert the coords to the main canvas window, or return if the
5123 * window is not found. */
5124 if (!e_day_view_convert_event_coords (
5125 day_view
, (GdkEvent
*) mevent
, window
, &event_x
, &event_y
))
5131 pos
= e_day_view_convert_position_in_main_canvas (
5136 if (event_num
!= -1) {
5137 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
5140 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
5144 if (day_view
->selection_is_being_dragged
) {
5145 if (pos
!= E_CALENDAR_VIEW_POS_OUTSIDE
) {
5146 e_day_view_update_selection (day_view
, day
, row
);
5147 e_day_view_check_auto_scroll (
5152 } else if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
) {
5153 if (pos
!= E_CALENDAR_VIEW_POS_OUTSIDE
) {
5154 e_day_view_update_resize (day_view
, row
);
5155 e_day_view_check_auto_scroll (
5160 } else if (day_view
->pressed_event_day
!= -1
5161 && day_view
->pressed_event_day
!= E_DAY_VIEW_LONG_EVENT
) {
5162 GtkTargetList
*target_list
;
5164 if (gtk_drag_check_threshold (widget
, day_view
->drag_event_x
, day_view
->drag_event_y
, canvas_x
, canvas_y
)) {
5165 day_view
->drag_event_day
= day_view
->pressed_event_day
;
5166 day_view
->drag_event_num
= day_view
->pressed_event_num
;
5167 day_view
->pressed_event_day
= -1;
5169 /* Hide the horizontal bars. */
5170 if (day_view
->resize_bars_event_day
!= -1) {
5171 day_view
->resize_bars_event_day
= -1;
5172 day_view
->resize_bars_event_num
= -1;
5175 target_list
= gtk_target_list_new (
5176 target_table
, G_N_ELEMENTS (target_table
));
5177 e_target_list_add_calendar_targets (target_list
, 0);
5178 g_clear_object (&day_view
->priv
->drag_context
);
5179 day_view
->priv
->drag_context
= gtk_drag_begin (
5180 widget
, target_list
,
5181 GDK_ACTION_COPY
| GDK_ACTION_MOVE
,
5182 1, (GdkEvent
*) mevent
);
5183 gtk_target_list_unref (target_list
);
5185 if (day_view
->priv
->drag_context
)
5186 g_object_ref (day_view
->priv
->drag_context
);
5189 cursor
= day_view
->normal_cursor
;
5191 /* Check if the event is editable and client is not readonly while changing the cursor */
5192 if (event
&& event
->is_editable
&& is_comp_data_valid (event
) && !e_client_is_readonly (E_CLIENT (event
->comp_data
->client
))) {
5195 case E_CALENDAR_VIEW_POS_LEFT_EDGE
:
5196 cursor
= day_view
->move_cursor
;
5198 case E_CALENDAR_VIEW_POS_TOP_EDGE
:
5199 case E_CALENDAR_VIEW_POS_BOTTOM_EDGE
:
5200 cursor
= day_view
->resize_height_cursor
;
5207 /* Only set the cursor if it is different to last one set. */
5208 if (day_view
->last_cursor_set_in_main_canvas
!= cursor
) {
5211 day_view
->last_cursor_set_in_main_canvas
= cursor
;
5213 window
= gtk_widget_get_window (widget
);
5214 gdk_window_set_cursor (window
, cursor
);
5217 if (event
&& E_IS_TEXT (event
->canvas_item
) && E_TEXT (event
->canvas_item
)->editing
) {
5218 GNOME_CANVAS_ITEM_GET_CLASS (event
->canvas_item
)->event (event
->canvas_item
, (GdkEvent
*) mevent
);
5225 /* This sets the selection to a single cell. If day is -1 then the current
5226 * start day is reused. If row is -1 then the selection is in the top canvas.
5229 e_day_view_start_selection (EDayView
*day_view
,
5234 day
= day_view
->selection_start_day
;
5239 day_view
->selection_start_day
= day
;
5240 day_view
->selection_end_day
= day
;
5242 day_view
->selection_start_row
= row
;
5243 day_view
->selection_end_row
= row
;
5245 day_view
->selection_is_being_dragged
= TRUE
;
5246 day_view
->selection_drag_pos
= E_DAY_VIEW_DRAG_END
;
5247 day_view
->selection_in_top_canvas
= (row
== -1) ? TRUE
: FALSE
;
5249 /* FIXME: Optimise? */
5250 gtk_widget_queue_draw (day_view
->top_canvas
);
5251 gtk_widget_queue_draw (day_view
->main_canvas
);
5254 /* Updates the selection during a drag. If day is -1 the selection day is
5257 e_day_view_update_selection (EDayView
*day_view
,
5261 gboolean need_redraw
= FALSE
;
5263 day_view
->selection_in_top_canvas
= (row
== -1) ? TRUE
: FALSE
;
5266 day
= (day_view
->selection_drag_pos
== E_DAY_VIEW_DRAG_START
)
5267 ? day_view
->selection_start_day
5268 : day_view
->selection_end_day
;
5270 if (day_view
->selection_drag_pos
== E_DAY_VIEW_DRAG_START
) {
5271 if (row
!= day_view
->selection_start_row
5272 || day
!= day_view
->selection_start_day
) {
5274 day_view
->selection_start_row
= row
;
5275 day_view
->selection_start_day
= day
;
5278 if (row
!= day_view
->selection_end_row
5279 || day
!= day_view
->selection_end_day
) {
5281 day_view
->selection_end_row
= row
;
5282 day_view
->selection_end_day
= day
;
5286 e_day_view_normalize_selection (day_view
);
5288 /* FIXME: Optimise? */
5290 gtk_widget_queue_draw (day_view
->top_canvas
);
5291 gtk_widget_queue_draw (day_view
->main_canvas
);
5296 e_day_view_normalize_selection (EDayView
*day_view
)
5298 gint tmp_row
, tmp_day
;
5300 /* Switch the drag position if necessary. */
5301 if (day_view
->selection_start_day
> day_view
->selection_end_day
5302 || (day_view
->selection_start_day
== day_view
->selection_end_day
5303 && day_view
->selection_start_row
> day_view
->selection_end_row
)) {
5304 tmp_row
= day_view
->selection_start_row
;
5305 tmp_day
= day_view
->selection_start_day
;
5306 day_view
->selection_start_day
= day_view
->selection_end_day
;
5307 day_view
->selection_start_row
= day_view
->selection_end_row
;
5308 day_view
->selection_end_day
= tmp_day
;
5309 day_view
->selection_end_row
= tmp_row
;
5310 if (day_view
->selection_drag_pos
== E_DAY_VIEW_DRAG_START
)
5311 day_view
->selection_drag_pos
= E_DAY_VIEW_DRAG_END
;
5313 day_view
->selection_drag_pos
= E_DAY_VIEW_DRAG_START
;
5318 e_day_view_finish_selection (EDayView
*day_view
)
5320 day_view
->selection_is_being_dragged
= FALSE
;
5321 e_day_view_update_calendar_selection_time (day_view
);
5325 e_day_view_update_long_event_resize (EDayView
*day_view
,
5329 gboolean need_reshape
= FALSE
;
5331 event_num
= day_view
->resize_event_num
;
5333 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_LEFT_EDGE
) {
5334 day
= MIN (day
, day_view
->resize_end_row
);
5335 if (day
!= day_view
->resize_start_row
) {
5336 need_reshape
= TRUE
;
5337 day_view
->resize_start_row
= day
;
5341 day
= MAX (day
, day_view
->resize_start_row
);
5342 if (day
!= day_view
->resize_end_row
) {
5343 need_reshape
= TRUE
;
5344 day_view
->resize_end_row
= day
;
5348 /* FIXME: Optimise? */
5350 e_day_view_reshape_long_event (day_view
, event_num
);
5351 gtk_widget_queue_draw (day_view
->top_canvas
);
5356 e_day_view_update_resize (EDayView
*day_view
,
5359 /* Same thing again? */
5360 EDayViewEvent
*event
;
5361 gint day
, event_num
;
5362 gboolean need_reshape
= FALSE
;
5364 if (day_view
->resize_event_num
== -1)
5367 day
= day_view
->resize_event_day
;
5368 event_num
= day_view
->resize_event_num
;
5370 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
5373 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
5376 if (event
&& (!event
->is_editable
|| !is_comp_data_valid (event
) || e_client_is_readonly (E_CLIENT (event
->comp_data
->client
)))) {
5380 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_TOP_EDGE
) {
5381 row
= MIN (row
, day_view
->resize_end_row
);
5382 if (row
!= day_view
->resize_start_row
) {
5383 need_reshape
= TRUE
;
5384 day_view
->resize_start_row
= row
;
5388 row
= MAX (row
, day_view
->resize_start_row
);
5389 if (row
!= day_view
->resize_end_row
) {
5390 need_reshape
= TRUE
;
5391 day_view
->resize_end_row
= row
;
5395 /* FIXME: Optimise? */
5397 e_day_view_reshape_day_event (day_view
, day
, event_num
);
5398 e_day_view_reshape_main_canvas_resize_bars (day_view
);
5399 gtk_widget_queue_draw (day_view
->main_canvas
);
5403 /* This converts the resize start or end row back to a time and updates the
5406 e_day_view_finish_long_event_resize (EDayView
*day_view
)
5408 EDayViewEvent
*event
;
5410 ECalComponent
*comp
;
5411 ECalComponentDateTime date
;
5412 struct icaltimetype itt
;
5416 ESourceRegistry
*registry
;
5417 ECalObjModType mod
= E_CAL_OBJ_MOD_ALL
;
5420 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
5421 registry
= e_cal_model_get_registry (model
);
5423 event_num
= day_view
->resize_event_num
;
5425 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
5428 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
5431 if (!is_comp_data_valid (event
))
5434 client
= event
->comp_data
->client
;
5436 /* We use a temporary copy of the comp since we don't want to
5437 * change the original comp here. Otherwise we would not detect that
5438 * the event's time had changed in the "update_event" callback. */
5439 comp
= e_cal_component_new ();
5440 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
5442 if (e_cal_component_has_attendees (comp
) &&
5443 !itip_organizer_is_user (registry
, comp
, client
)) {
5444 g_object_unref (comp
);
5445 e_day_view_abort_resize (day_view
);
5452 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_LEFT_EDGE
) {
5453 ECalComponentDateTime ecdt
;
5455 e_cal_component_get_dtstart (comp
, &ecdt
);
5456 is_date
= ecdt
.value
&& ecdt
.value
->is_date
;
5458 date
.tzid
= icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5459 dt
= day_view
->day_starts
[day_view
->resize_start_row
];
5460 *date
.value
= icaltime_from_timet_with_zone (dt
, is_date
,
5461 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5462 cal_comp_set_dtstart_with_oldzone (client
, comp
, &date
);
5463 e_cal_component_free_datetime (&ecdt
);
5464 date
.tzid
= NULL
; /* do not reuse it later */
5466 ECalComponentDateTime ecdt
;
5468 e_cal_component_get_dtend (comp
, &ecdt
);
5469 is_date
= ecdt
.value
&& ecdt
.value
->is_date
;
5471 date
.tzid
= icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5472 dt
= day_view
->day_starts
[day_view
->resize_end_row
+ 1];
5473 *date
.value
= icaltime_from_timet_with_zone (dt
, is_date
,
5474 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5475 cal_comp_set_dtend_with_oldzone (client
, comp
, &date
);
5476 e_cal_component_free_datetime (&ecdt
);
5477 date
.tzid
= NULL
; /* do not reuse it later */
5480 e_cal_component_commit_sequence (comp
);
5481 if (e_cal_component_has_recurrences (comp
)) {
5482 if (!e_cal_dialogs_recur_component (client
, comp
, &mod
, NULL
, FALSE
)) {
5483 gtk_widget_queue_draw (day_view
->top_canvas
);
5487 if (mod
== E_CAL_OBJ_MOD_THIS
) {
5488 /* set the correct DTSTART/DTEND on the individual recurrence */
5489 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_TOP_EDGE
) {
5490 *date
.value
= icaltime_from_timet_with_zone (
5491 event
->comp_data
->instance_end
, FALSE
,
5492 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5493 cal_comp_set_dtend_with_oldzone (client
, comp
, &date
);
5495 *date
.value
= icaltime_from_timet_with_zone (
5496 event
->comp_data
->instance_start
, FALSE
,
5497 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5498 cal_comp_set_dtstart_with_oldzone (client
, comp
, &date
);
5501 e_cal_component_set_rdate_list (comp
, NULL
);
5502 e_cal_component_set_rrule_list (comp
, NULL
);
5503 e_cal_component_set_exdate_list (comp
, NULL
);
5504 e_cal_component_set_exrule_list (comp
, NULL
);
5506 } else if (e_cal_component_is_instance (comp
))
5507 mod
= E_CAL_OBJ_MOD_THIS
;
5509 e_cal_component_commit_sequence (comp
);
5511 e_cal_ops_modify_component (model
, client
, e_cal_component_get_icalcomponent (comp
),
5512 mod
, E_CAL_OPS_SEND_FLAG_ASK
| E_CAL_OPS_SEND_FLAG_IS_NEW_COMPONENT
);
5515 day_view
->resize_drag_pos
= E_CALENDAR_VIEW_POS_NONE
;
5517 g_object_unref (comp
);
5520 /* This converts the resize start or end row back to a time and updates the
5523 e_day_view_finish_resize (EDayView
*day_view
)
5525 EDayViewEvent
*event
;
5526 gint day
, event_num
;
5527 ECalComponent
*comp
;
5528 ECalComponentDateTime date
;
5529 struct icaltimetype itt
;
5533 ESourceRegistry
*registry
;
5534 ECalObjModType mod
= E_CAL_OBJ_MOD_ALL
;
5535 GtkWindow
*toplevel
;
5536 GtkResponseType send
= GTK_RESPONSE_NO
;
5537 gboolean only_new_attendees
= FALSE
;
5538 gboolean strip_alarms
= TRUE
;
5540 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
5541 registry
= e_cal_model_get_registry (model
);
5543 if (day_view
->resize_event_num
== -1)
5546 day
= day_view
->resize_event_day
;
5547 event_num
= day_view
->resize_event_num
;
5549 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
5552 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
5555 if (!is_comp_data_valid (event
))
5558 client
= event
->comp_data
->client
;
5560 /* We use a temporary shallow copy of the ico since we don't want to
5561 * change the original ico here. Otherwise we would not detect that
5562 * the event's time had changed in the "update_event" callback. */
5563 comp
= e_cal_component_new ();
5564 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
5566 if (e_cal_component_has_attendees (comp
) &&
5567 !itip_organizer_is_user (registry
, comp
, client
)) {
5568 g_object_unref (comp
);
5569 e_day_view_abort_resize (day_view
);
5573 toplevel
= GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view
)));
5575 if (itip_has_any_attendees (comp
) &&
5576 (itip_organizer_is_user (registry
, comp
, client
) ||
5577 itip_sentby_is_user (registry
, comp
, client
)))
5578 send
= e_cal_dialogs_send_dragged_or_resized_component (
5579 toplevel
, client
, comp
, &strip_alarms
, &only_new_attendees
);
5581 if (send
== GTK_RESPONSE_CANCEL
) {
5582 e_day_view_abort_resize (day_view
);
5587 date
.tzid
= icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5589 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_TOP_EDGE
) {
5590 dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, day_view
->resize_start_row
);
5591 *date
.value
= icaltime_from_timet_with_zone (dt
, FALSE
,
5592 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5593 cal_comp_set_dtstart_with_oldzone (client
, comp
, &date
);
5595 dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, day_view
->resize_end_row
+ 1);
5596 *date
.value
= icaltime_from_timet_with_zone (dt
, FALSE
,
5597 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5598 cal_comp_set_dtend_with_oldzone (client
, comp
, &date
);
5601 e_cal_component_commit_sequence (comp
);
5603 if (day_view
->last_edited_comp_string
!= NULL
) {
5604 g_free (day_view
->last_edited_comp_string
);
5605 day_view
->last_edited_comp_string
= NULL
;
5608 day_view
->last_edited_comp_string
= e_cal_component_get_as_string (comp
);
5610 /* Hide the horizontal bars. */
5611 day_view
->resize_bars_event_day
= -1;
5612 day_view
->resize_bars_event_num
= -1;
5614 day_view
->resize_drag_pos
= E_CALENDAR_VIEW_POS_NONE
;
5616 if (e_cal_component_has_recurrences (comp
)) {
5617 if (!e_cal_dialogs_recur_component (client
, comp
, &mod
, NULL
, FALSE
)) {
5618 gtk_widget_queue_draw (day_view
->main_canvas
);
5622 if (mod
== E_CAL_OBJ_MOD_THIS
) {
5623 /* set the correct DTSTART/DTEND on the individual recurrence */
5624 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_TOP_EDGE
) {
5625 *date
.value
= icaltime_from_timet_with_zone (
5626 event
->comp_data
->instance_end
, FALSE
,
5627 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5628 cal_comp_set_dtend_with_oldzone (client
, comp
, &date
);
5630 *date
.value
= icaltime_from_timet_with_zone (
5631 event
->comp_data
->instance_start
, FALSE
,
5632 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
5633 cal_comp_set_dtstart_with_oldzone (client
, comp
, &date
);
5636 e_cal_component_set_rdate_list (comp
, NULL
);
5637 e_cal_component_set_rrule_list (comp
, NULL
);
5638 e_cal_component_set_exdate_list (comp
, NULL
);
5639 e_cal_component_set_exrule_list (comp
, NULL
);
5641 } else if (e_cal_component_is_instance (comp
))
5642 mod
= E_CAL_OBJ_MOD_THIS
;
5644 e_cal_component_commit_sequence (comp
);
5646 e_cal_ops_modify_component (model
, client
, e_cal_component_get_icalcomponent (comp
), mod
,
5647 (send
== GTK_RESPONSE_YES
? E_CAL_OPS_SEND_FLAG_SEND
: E_CAL_OPS_SEND_FLAG_DONT_SEND
) |
5648 (strip_alarms
? E_CAL_OPS_SEND_FLAG_STRIP_ALARMS
: 0) |
5649 (only_new_attendees
? E_CAL_OPS_SEND_FLAG_ONLY_NEW_ATTENDEES
: 0));
5652 g_object_unref (comp
);
5656 e_day_view_abort_resize (EDayView
*day_view
)
5659 gint day
, event_num
;
5661 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_NONE
)
5664 day_view
->resize_drag_pos
= E_CALENDAR_VIEW_POS_NONE
;
5666 day
= day_view
->resize_event_day
;
5667 event_num
= day_view
->resize_event_num
;
5669 if (day
== E_DAY_VIEW_LONG_EVENT
) {
5670 e_day_view_reshape_long_event (day_view
, event_num
);
5671 gtk_widget_queue_draw (day_view
->top_canvas
);
5673 day_view
->last_cursor_set_in_top_canvas
= day_view
->normal_cursor
;
5674 window
= gtk_widget_get_window (day_view
->top_canvas
);
5675 gdk_window_set_cursor (window
, day_view
->normal_cursor
);
5677 e_day_view_reshape_day_event (day_view
, day
, event_num
);
5678 e_day_view_reshape_main_canvas_resize_bars (day_view
);
5679 gtk_widget_queue_draw (day_view
->main_canvas
);
5681 day_view
->last_cursor_set_in_main_canvas
= day_view
->normal_cursor
;
5682 window
= gtk_widget_get_window (day_view
->main_canvas
);
5683 gdk_window_set_cursor (window
, day_view
->normal_cursor
);
5688 e_day_view_free_events (EDayView
*day_view
)
5691 gboolean did_editing
= day_view
->editing_event_day
!= -1;
5693 /* Reset all our indices. */
5694 day_view
->editing_event_day
= -1;
5695 day_view
->popup_event_day
= -1;
5696 day_view
->resize_bars_event_day
= -1;
5697 day_view
->resize_event_day
= -1;
5698 day_view
->pressed_event_day
= -1;
5699 day_view
->drag_event_day
= -1;
5700 day_view
->editing_event_num
= -1;
5701 day_view
->popup_event_num
= -1;
5703 g_clear_object (&day_view
->priv
->drag_context
);
5705 e_day_view_free_event_array (day_view
, day_view
->long_events
);
5707 for (day
= 0; day
< E_DAY_VIEW_MAX_DAYS
; day
++)
5708 e_day_view_free_event_array (day_view
, day_view
->events
[day
]);
5711 g_object_notify (G_OBJECT (day_view
), "is-editing");
5715 e_day_view_free_event_array (EDayView
*day_view
,
5718 EDayViewEvent
*event
;
5721 for (event_num
= 0; event_num
< array
->len
; event_num
++) {
5722 event
= &g_array_index (array
, EDayViewEvent
, event_num
);
5723 if (event
->canvas_item
)
5724 g_object_run_dispose (G_OBJECT (event
->canvas_item
));
5726 if (is_comp_data_valid (event
))
5727 g_object_unref (event
->comp_data
);
5729 if (event
->timeout
> 0) {
5730 g_source_remove (event
->timeout
);
5731 event
->timeout
= -1;
5735 g_array_set_size (array
, 0);
5738 /* This adds one event to the view, adding it to the appropriate array. */
5740 e_day_view_add_event (ESourceRegistry
*registry
,
5742 ECalComponent
*comp
,
5748 EDayViewEvent event
;
5751 struct icaltimetype start_tt
, end_tt
;
5752 AddEventData
*add_event_data
;
5755 add_event_data
= data
;
5757 /*if (end < start || start >= add_event_data->day_view->upper || end < add_event_data->day_view->lower) {
5758 g_print ("%s: day_view: %p\n", G_STRFUNC, add_event_data->day_view);
5759 g_print ("\tDay view lower: %s", ctime (&add_event_data->day_view->lower));
5760 g_print ("\tDay view upper: %s", ctime (&add_event_data->day_view->upper));
5761 g_print ("\tEvent start: %s", ctime (&start));
5762 g_print ("\tEvent end : %s\n", ctime (&end));
5765 /* Check that the event times are valid. */
5766 g_return_if_fail (start
<= end
);
5767 g_return_if_fail (start
< add_event_data
->day_view
->upper
);
5769 if (end
!= start
|| end
< add_event_data
->day_view
->lower
)
5770 g_return_if_fail (end
> add_event_data
->day_view
->lower
);
5772 zone
= e_calendar_view_get_timezone (E_CALENDAR_VIEW (add_event_data
->day_view
));
5773 start_tt
= icaltime_from_timet_with_zone (start
, FALSE
, zone
);
5774 end_tt
= icaltime_from_timet_with_zone (end
, FALSE
, zone
);
5776 if (add_event_data
->comp_data
) {
5777 event
.comp_data
= g_object_ref (add_event_data
->comp_data
);
5779 event
.comp_data
= g_object_new (E_TYPE_CAL_MODEL_COMPONENT
, NULL
);
5780 event
.comp_data
->is_new_component
= TRUE
;
5781 event
.comp_data
->client
= g_object_ref (client
);
5782 e_cal_component_abort_sequence (comp
);
5783 event
.comp_data
->icalcomp
= icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp
));
5786 event
.start
= start
;
5787 event
.tooltip
= NULL
;
5791 event
.canvas_item
= NULL
;
5792 event
.comp_data
->instance_start
= start
;
5793 event
.comp_data
->instance_end
= end
;
5795 /* Calculate the start & end minute, relative to the top of the
5797 offset
= add_event_data
->day_view
->first_hour_shown
* 60
5798 + add_event_data
->day_view
->first_minute_shown
;
5799 event
.start_minute
= start_tt
.hour
* 60 + start_tt
.minute
- offset
;
5800 event
.end_minute
= end_tt
.hour
* 60 + end_tt
.minute
- offset
;
5802 event
.start_row_or_col
= 0;
5803 event
.num_columns
= 0;
5805 event
.different_timezone
= FALSE
;
5806 if (!cal_comp_util_compare_event_timezones (comp
, event
.comp_data
->client
, zone
))
5807 event
.different_timezone
= TRUE
;
5809 if (!e_cal_component_has_attendees (comp
) ||
5810 itip_organizer_is_user (registry
, comp
, event
.comp_data
->client
) ||
5811 itip_sentby_is_user (registry
, comp
, event
.comp_data
->client
))
5812 event
.is_editable
= TRUE
;
5814 event
.is_editable
= FALSE
;
5816 days_shown
= e_day_view_get_days_shown (add_event_data
->day_view
);
5818 /* Find out which array to add the event to. */
5819 for (day
= 0; day
< days_shown
; day
++) {
5820 if (start
>= add_event_data
->day_view
->day_starts
[day
]
5821 && end
<= add_event_data
->day_view
->day_starts
[day
+ 1]) {
5823 if (start
== end
&& start
== add_event_data
->day_view
->day_starts
[day
+ 1])
5826 /* Special case for when the appointment ends at
5827 * midnight, i.e. the start of the next day. */
5828 if (end
== add_event_data
->day_view
->day_starts
[day
+ 1] && start
!= end
) {
5830 /* If the event last the entire day, then we
5831 * skip it here so it gets added to the top
5833 if (start
== add_event_data
->day_view
->day_starts
[day
])
5836 event
.end_minute
= 24 * 60;
5839 g_array_append_val (add_event_data
->day_view
->events
[day
], event
);
5840 add_event_data
->day_view
->events_sorted
[day
] = FALSE
;
5841 add_event_data
->day_view
->need_layout
[day
] = TRUE
;
5846 /* The event wasn't within one day so it must be a long event,
5847 * i.e. shown in the top canvas. */
5848 g_array_append_val (add_event_data
->day_view
->long_events
, event
);
5849 add_event_data
->day_view
->long_events_sorted
= FALSE
;
5850 add_event_data
->day_view
->long_events_need_layout
= TRUE
;
5854 /* This lays out the short (less than 1 day) events in the columns.
5855 * Any long events are simply skipped. */
5857 e_day_view_check_layout (EDayView
*day_view
)
5859 ECalendarView
*cal_view
;
5860 gint time_divisions
;
5861 gint day
, rows_in_top_display
;
5865 days_shown
= e_day_view_get_days_shown (day_view
);
5867 cal_view
= E_CALENDAR_VIEW (day_view
);
5868 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
5870 /* Don't bother if we aren't visible. */
5871 if (!E_CALENDAR_VIEW (day_view
)->in_focus
) {
5872 e_day_view_free_events (day_view
);
5873 day_view
->requires_update
= TRUE
;
5877 /* Make sure the events are sorted (by start and size). */
5878 e_day_view_ensure_events_sorted (day_view
);
5880 for (day
= 0; day
< days_shown
; day
++) {
5881 if (day_view
->need_layout
[day
]) {
5884 cols
= e_day_view_layout_day_events (
5885 day_view
->events
[day
],
5888 day_view
->cols_per_row
[day
],
5889 days_shown
== 1 ? -1 :
5890 E_DAY_VIEW_MULTI_DAY_MAX_COLUMNS
);
5892 max_cols
= MAX (cols
, max_cols
);
5895 if (day_view
->need_layout
[day
]
5896 || day_view
->need_reshape
[day
]) {
5897 e_day_view_reshape_day_events (day_view
, day
);
5899 if (day_view
->resize_bars_event_day
== day
)
5900 e_day_view_reshape_main_canvas_resize_bars (day_view
);
5903 day_view
->need_layout
[day
] = FALSE
;
5904 day_view
->need_reshape
[day
] = FALSE
;
5907 if (day_view
->long_events_need_layout
) {
5908 e_day_view_layout_long_events (
5909 day_view
->long_events
,
5911 day_view
->day_starts
,
5912 &rows_in_top_display
);
5915 if (day_view
->long_events_need_layout
5916 || day_view
->long_events_need_reshape
)
5917 e_day_view_reshape_long_events (day_view
);
5919 if (day_view
->long_events_need_layout
5920 && day_view
->rows_in_top_display
!= rows_in_top_display
) {
5921 day_view
->rows_in_top_display
= rows_in_top_display
;
5922 e_day_view_update_top_scroll (day_view
, FALSE
);
5925 day_view
->long_events_need_layout
= FALSE
;
5926 day_view
->long_events_need_reshape
= FALSE
;
5928 if (max_cols
!= -1 && max_cols
!= day_view
->max_cols
) {
5929 day_view
->max_cols
= max_cols
;
5930 e_day_view_recalc_main_canvas_size (day_view
);
5935 e_day_view_reshape_long_events (EDayView
*day_view
)
5937 EDayViewEvent
*event
;
5940 for (event_num
= 0; event_num
< day_view
->long_events
->len
;
5942 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
5945 if (event
->num_columns
== 0) {
5946 if (event
->canvas_item
) {
5947 g_object_run_dispose (G_OBJECT (event
->canvas_item
));
5948 event
->canvas_item
= NULL
;
5951 e_day_view_reshape_long_event (day_view
, event_num
);
5957 e_day_view_reshape_long_event (EDayView
*day_view
,
5960 EDayViewEvent
*event
;
5961 gint start_day
, end_day
, item_x
, item_y
, item_w
, item_h
;
5962 gint text_x
, text_w
, num_icons
, icons_width
, width
, time_width
;
5963 ECalComponent
*comp
;
5964 gint min_text_x
, max_text_w
, text_width
, line_len
;
5965 gchar
*text
, *end_of_line
;
5966 gboolean show_icons
= TRUE
, use_max_width
= FALSE
;
5967 PangoContext
*pango_context
;
5968 PangoLayout
*layout
;
5970 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
5973 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
5976 if (!e_day_view_get_long_event_position (day_view
, event_num
,
5977 &start_day
, &end_day
,
5979 &item_w
, &item_h
)) {
5980 if (event
->canvas_item
) {
5981 g_object_run_dispose (G_OBJECT (event
->canvas_item
));
5982 event
->canvas_item
= NULL
;
5987 if (!is_comp_data_valid (event
))
5990 /* Take off the border and padding. */
5991 item_x
+= E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH
+ E_DAY_VIEW_LONG_EVENT_X_PAD
;
5992 item_w
-= (E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH
+ E_DAY_VIEW_LONG_EVENT_X_PAD
) * 2;
5993 item_y
+= E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_LONG_EVENT_Y_PAD
;
5994 item_h
-= (E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_LONG_EVENT_Y_PAD
) * 2;
5996 /* We don't show the icons while resizing, since we'd have to
5997 * draw them on top of the resize rect. Nor when editing. */
5999 comp
= e_cal_component_new ();
6000 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
6002 /* Set up Pango prerequisites */
6003 pango_context
= gtk_widget_get_pango_context (GTK_WIDGET (day_view
));
6004 layout
= pango_layout_new (pango_context
);
6006 if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
6007 && day_view
->resize_event_day
== E_DAY_VIEW_LONG_EVENT
6008 && day_view
->resize_event_num
== event_num
)
6011 if (day_view
->editing_event_day
== E_DAY_VIEW_LONG_EVENT
6012 && day_view
->editing_event_num
== event_num
) {
6014 use_max_width
= TRUE
;
6018 if (e_cal_component_has_alarms (comp
))
6020 if (e_cal_component_has_recurrences (comp
) || e_cal_component_is_instance (comp
))
6022 if (event
->different_timezone
)
6025 if (e_cal_component_has_attendees (comp
))
6027 if (e_cal_component_has_attachments (comp
))
6029 num_icons
+= cal_comp_util_get_n_icons (comp
, NULL
);
6032 if (!event
->canvas_item
) {
6035 color
= e_day_view_get_text_color (day_view
, event
);
6037 event
->canvas_item
=
6038 gnome_canvas_item_new (
6039 GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view
->top_canvas
)->root
),
6044 "use_ellipsis", TRUE
,
6045 "fill_color_gdk", &color
,
6046 "im_context", E_CANVAS (day_view
->top_canvas
)->im_context
,
6048 g_object_set_data (G_OBJECT (event
->canvas_item
), "event-num", GINT_TO_POINTER (event_num
));
6049 g_object_set_data (G_OBJECT (event
->canvas_item
), "event-day", GINT_TO_POINTER (E_DAY_VIEW_LONG_EVENT
));
6051 event
->canvas_item
, "event",
6052 G_CALLBACK (e_day_view_on_text_item_event
), day_view
);
6053 g_signal_emit_by_name (day_view
, "event_added", event
);
6055 e_day_view_update_long_event_label (day_view
, event_num
);
6056 } else if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event
->canvas_item
), "event-num")) != event_num
) {
6057 g_object_set_data (G_OBJECT (event
->canvas_item
), "event-num", GINT_TO_POINTER (event_num
));
6060 /* Calculate its position. We first calculate the ideal position which
6061 * is centered with the icons. We then make sure we haven't gone off
6062 * the left edge of the available space. Finally we make sure we don't
6063 * go off the right edge. */
6064 icons_width
= (E_DAY_VIEW_ICON_WIDTH
+ E_DAY_VIEW_ICON_X_PAD
)
6065 * num_icons
+ E_DAY_VIEW_LONG_EVENT_ICON_R_PAD
;
6066 time_width
= e_day_view_get_time_string_width (day_view
);
6068 if (use_max_width
) {
6072 /* Get the requested size of the label. */
6073 g_object_get (event
->canvas_item
, "text", &text
, NULL
);
6076 end_of_line
= strchr (text
, '\n');
6078 line_len
= end_of_line
- text
;
6080 line_len
= strlen (text
);
6081 pango_layout_set_text (layout
, text
, line_len
);
6082 pango_layout_get_pixel_size (layout
, &text_width
, NULL
);
6086 width
= text_width
+ icons_width
;
6087 text_x
= item_x
+ (item_w
- width
) / 2;
6089 min_text_x
= item_x
;
6090 if (event
->start
> day_view
->day_starts
[start_day
])
6091 min_text_x
+= time_width
+ E_DAY_VIEW_LONG_EVENT_TIME_X_PAD
;
6093 text_x
= MAX (text_x
, min_text_x
);
6095 max_text_w
= item_x
+ item_w
- text_x
;
6096 if (event
->end
< day_view
->day_starts
[end_day
+ 1])
6097 max_text_w
-= time_width
+ E_DAY_VIEW_LONG_EVENT_TIME_X_PAD
;
6099 text_w
= MIN (width
, max_text_w
);
6101 /* Now take out the space for the icons. */
6102 text_x
+= icons_width
;
6103 text_w
-= icons_width
;
6106 text_w
= MAX (text_w
, 0);
6107 gnome_canvas_item_set (
6109 "clip_width", (gdouble
) text_w
,
6110 "clip_height", (gdouble
) item_h
,
6112 e_canvas_item_move_absolute (
6116 g_object_unref (layout
);
6117 g_object_unref (comp
);
6120 /* This creates or updates the sizes of the canvas items for one day of the
6123 e_day_view_reshape_day_events (EDayView
*day_view
,
6128 for (event_num
= 0; event_num
< day_view
->events
[day
]->len
;
6130 EDayViewEvent
*event
;
6131 gchar
*current_comp_string
;
6133 e_day_view_reshape_day_event (day_view
, day
, event_num
);
6134 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
, event_num
);
6136 if (!is_comp_data_valid (event
))
6139 current_comp_string
= icalcomponent_as_ical_string_r (event
->comp_data
->icalcomp
);
6140 if (day_view
->last_edited_comp_string
== NULL
) {
6141 g_free (current_comp_string
);
6145 if (strncmp (current_comp_string
, day_view
->last_edited_comp_string
,50) == 0) {
6146 e_canvas_item_grab_focus (event
->canvas_item
, TRUE
);
6147 g_free (day_view
->last_edited_comp_string
);
6148 day_view
-> last_edited_comp_string
= NULL
;
6150 g_free (current_comp_string
);
6155 e_day_view_reshape_day_event (EDayView
*day_view
,
6159 EDayViewEvent
*event
;
6160 gint item_x
, item_y
, item_w
, item_h
;
6161 gint num_icons
, icons_offset
;
6163 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
6166 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
6169 if (!e_day_view_get_event_position (day_view
, day
, event_num
,
6171 &item_w
, &item_h
)) {
6172 if (event
->canvas_item
) {
6173 g_object_run_dispose (G_OBJECT (event
->canvas_item
));
6174 event
->canvas_item
= NULL
;
6177 /* Skip the border and padding. */
6178 item_x
+= E_DAY_VIEW_BAR_WIDTH
+ E_DAY_VIEW_EVENT_X_PAD
;
6179 item_w
-= E_DAY_VIEW_BAR_WIDTH
+ E_DAY_VIEW_EVENT_X_PAD
* 2;
6180 item_y
+= E_DAY_VIEW_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_EVENT_Y_PAD
;
6181 item_h
-= (E_DAY_VIEW_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_EVENT_Y_PAD
) * 2;
6183 /* We don't show the icons while resizing, since we'd have to
6184 * draw them on top of the resize rect. */
6187 if (is_comp_data_valid (event
) && (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_NONE
6188 || day_view
->resize_event_day
!= day
6189 || day_view
->resize_event_num
!= event_num
)) {
6190 ECalComponent
*comp
;
6192 comp
= e_cal_component_new ();
6193 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
6195 if (e_cal_component_has_alarms (comp
))
6197 if (e_cal_component_has_recurrences (comp
) || e_cal_component_is_instance (comp
))
6199 if (e_cal_component_has_attachments (comp
))
6201 if (event
->different_timezone
)
6203 if (e_cal_component_has_attendees (comp
))
6206 num_icons
+= cal_comp_util_get_n_icons (comp
, NULL
);
6207 g_object_unref (comp
);
6210 if (num_icons
> 0) {
6211 if (item_h
>= (E_DAY_VIEW_ICON_HEIGHT
+ E_DAY_VIEW_ICON_Y_PAD
) * num_icons
)
6212 icons_offset
= E_DAY_VIEW_ICON_WIDTH
+ E_DAY_VIEW_ICON_X_PAD
* 2;
6213 else if (item_h
<= (E_DAY_VIEW_ICON_HEIGHT
+ E_DAY_VIEW_ICON_Y_PAD
) * 2 || num_icons
== 1)
6214 icons_offset
= (E_DAY_VIEW_ICON_WIDTH
+ E_DAY_VIEW_ICON_X_PAD
) * num_icons
+ E_DAY_VIEW_ICON_X_PAD
;
6216 icons_offset
= E_DAY_VIEW_ICON_X_PAD
;
6219 if (!event
->canvas_item
) {
6222 color
= e_day_view_get_text_color (day_view
, event
);
6224 event
->canvas_item
= gnome_canvas_item_new (
6225 GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view
->main_canvas
)->root
),
6230 "use_ellipsis", TRUE
,
6231 "fill_color_gdk", &color
,
6232 "im_context", E_CANVAS (day_view
->main_canvas
)->im_context
,
6234 g_object_set_data (G_OBJECT (event
->canvas_item
), "event-num", GINT_TO_POINTER (event_num
));
6235 g_object_set_data (G_OBJECT (event
->canvas_item
), "event-day", GINT_TO_POINTER (day
));
6237 event
->canvas_item
, "event",
6238 G_CALLBACK (e_day_view_on_text_item_event
), day_view
);
6239 g_signal_emit_by_name (day_view
, "event_added", event
);
6241 e_day_view_update_event_label (day_view
, day
, event_num
);
6242 } else if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event
->canvas_item
), "event-num")) != event_num
) {
6243 g_object_set_data (G_OBJECT (event
->canvas_item
), "event-num", GINT_TO_POINTER (event_num
));
6246 item_w
= MAX (item_w
, 0);
6247 gnome_canvas_item_set (
6249 "clip_width", (gdouble
) item_w
,
6250 "clip_height", (gdouble
) item_h
,
6251 "x_offset", (gdouble
) icons_offset
,
6253 e_canvas_item_move_absolute (
6259 /* This creates or resizes the horizontal bars used to resize events in the
6262 e_day_view_reshape_main_canvas_resize_bars (EDayView
*day_view
)
6264 gint day
, event_num
;
6265 gint item_x
, item_y
, item_w
, item_h
;
6268 day
= day_view
->resize_bars_event_day
;
6269 event_num
= day_view
->resize_bars_event_num
;
6271 /* If we're not editing an event, or the event is not shown,
6272 * hide the resize bars. */
6273 if (day
!= -1 && day
== day_view
->drag_event_day
6274 && event_num
== day_view
->drag_event_num
) {
6276 day_view
->drag_rect_item
,
6285 } else if (day
!= -1
6286 && e_day_view_get_event_position (day_view
, day
, event_num
,
6288 &item_w
, &item_h
)) {
6289 x
= item_x
+ E_DAY_VIEW_BAR_WIDTH
;
6291 w
= item_w
- E_DAY_VIEW_BAR_WIDTH
;
6294 gtk_widget_queue_draw (day_view
->main_canvas
);
6301 e_day_view_ensure_events_sorted (EDayView
*day_view
)
6306 days_shown
= e_day_view_get_days_shown (day_view
);
6308 /* Sort the long events. */
6309 if (!day_view
->long_events_sorted
) {
6311 day_view
->long_events
->data
,
6312 day_view
->long_events
->len
,
6313 sizeof (EDayViewEvent
),
6314 e_day_view_event_sort_func
);
6315 day_view
->long_events_sorted
= TRUE
;
6318 /* Sort the events for each day. */
6319 for (day
= 0; day
< days_shown
; day
++) {
6320 if (!day_view
->events_sorted
[day
]) {
6322 day_view
->events
[day
]->data
,
6323 day_view
->events
[day
]->len
,
6324 sizeof (EDayViewEvent
),
6325 e_day_view_event_sort_func
);
6326 day_view
->events_sorted
[day
] = TRUE
;
6332 e_day_view_event_sort_func (gconstpointer arg1
,
6335 EDayViewEvent
*event1
, *event2
;
6337 event1
= (EDayViewEvent
*) arg1
;
6338 event2
= (EDayViewEvent
*) arg2
;
6340 if (event1
->start
< event2
->start
)
6342 if (event1
->start
> event2
->start
)
6345 if (event1
->end
> event2
->end
)
6347 if (event1
->end
< event2
->end
)
6354 e_day_view_do_key_press (GtkWidget
*widget
,
6359 gboolean stop_emission
;
6361 g_return_val_if_fail (widget
!= NULL
, FALSE
);
6362 g_return_val_if_fail (E_IS_DAY_VIEW (widget
), FALSE
);
6363 g_return_val_if_fail (event
!= NULL
, FALSE
);
6365 day_view
= E_DAY_VIEW (widget
);
6366 keyval
= event
->keyval
;
6368 /* The Escape key aborts a resize operation. */
6369 if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
) {
6370 if (keyval
== GDK_KEY_Escape
) {
6371 if (day_view
->grabbed_pointer
!= NULL
) {
6373 day_view
->grabbed_pointer
,
6375 g_object_unref (day_view
->grabbed_pointer
);
6376 day_view
->grabbed_pointer
= NULL
;
6378 e_day_view_abort_resize (day_view
);
6383 /* Alt + Arrow Keys to move a selected event through time lines */
6384 if (((event
->state
& GDK_SHIFT_MASK
) != GDK_SHIFT_MASK
)
6385 &&((event
->state
& GDK_CONTROL_MASK
) != GDK_CONTROL_MASK
)
6386 &&((event
->state
& GDK_MOD1_MASK
) == GDK_MOD1_MASK
)) {
6387 if (keyval
== GDK_KEY_Up
|| keyval
== GDK_KEY_KP_Up
)
6388 return e_day_view_event_move ((ECalendarView
*) day_view
, E_CAL_VIEW_MOVE_UP
);
6389 else if (keyval
== GDK_KEY_Down
|| keyval
== GDK_KEY_KP_Down
)
6390 return e_day_view_event_move ((ECalendarView
*) day_view
, E_CAL_VIEW_MOVE_DOWN
);
6391 else if (keyval
== GDK_KEY_Left
|| keyval
== GDK_KEY_KP_Left
)
6392 return e_day_view_event_move ((ECalendarView
*) day_view
, E_CAL_VIEW_MOVE_LEFT
);
6393 else if (keyval
== GDK_KEY_Right
|| keyval
== GDK_KEY_KP_Right
)
6394 return e_day_view_event_move ((ECalendarView
*) day_view
, E_CAL_VIEW_MOVE_RIGHT
);
6397 /*Go to the start/end of a work day*/
6398 if ((keyval
== GDK_KEY_Home
)
6399 &&((event
->state
& GDK_SHIFT_MASK
) != GDK_SHIFT_MASK
)
6400 &&((event
->state
& GDK_CONTROL_MASK
) != GDK_CONTROL_MASK
)
6401 &&((event
->state
& GDK_MOD1_MASK
) != GDK_MOD1_MASK
)) {
6402 e_day_view_goto_start_of_work_day (day_view
);
6405 if ((keyval
== GDK_KEY_End
)
6406 &&((event
->state
& GDK_SHIFT_MASK
) != GDK_SHIFT_MASK
)
6407 &&((event
->state
& GDK_CONTROL_MASK
) != GDK_CONTROL_MASK
)
6408 &&((event
->state
& GDK_MOD1_MASK
) != GDK_MOD1_MASK
)) {
6409 e_day_view_goto_end_of_work_day (day_view
);
6413 /* In DayView, Shift+Home/End, Change the duration to the time that begins/ends the current work day */
6414 if ((keyval
== GDK_KEY_Home
)
6415 &&((event
->state
& GDK_SHIFT_MASK
) == GDK_SHIFT_MASK
)
6416 &&((event
->state
& GDK_CONTROL_MASK
) != GDK_CONTROL_MASK
)
6417 &&((event
->state
& GDK_MOD1_MASK
) != GDK_MOD1_MASK
)) {
6418 e_day_view_change_duration_to_start_of_work_day (day_view
);
6421 if ((keyval
== GDK_KEY_End
)
6422 &&((event
->state
& GDK_SHIFT_MASK
) == GDK_SHIFT_MASK
)
6423 &&((event
->state
& GDK_CONTROL_MASK
) != GDK_CONTROL_MASK
)
6424 &&((event
->state
& GDK_MOD1_MASK
) != GDK_MOD1_MASK
)) {
6425 e_day_view_change_duration_to_end_of_work_day (day_view
);
6429 /* Handle the cursor keys for moving & extending the selection. */
6430 stop_emission
= TRUE
;
6431 if (event
->state
& GDK_SHIFT_MASK
) {
6434 e_day_view_cursor_key_up_shifted (day_view
, event
);
6437 e_day_view_cursor_key_down_shifted (day_view
, event
);
6440 e_day_view_cursor_key_left_shifted (day_view
, event
);
6443 e_day_view_cursor_key_right_shifted (day_view
, event
);
6446 stop_emission
= FALSE
;
6449 } else if (!(event
->state
& GDK_MOD1_MASK
)) {
6452 e_day_view_cursor_key_up (day_view
, event
);
6455 e_day_view_cursor_key_down (day_view
, event
);
6458 e_day_view_cursor_key_left (day_view
, event
);
6461 e_day_view_cursor_key_right (day_view
, event
);
6463 case GDK_KEY_Page_Up
:
6464 e_day_view_scroll (day_view
, E_DAY_VIEW_PAGE_STEP
);
6466 case GDK_KEY_Page_Down
:
6467 e_day_view_scroll (day_view
, -E_DAY_VIEW_PAGE_STEP
);
6470 stop_emission
= FALSE
;
6475 stop_emission
= FALSE
;
6479 if (day_view
->selection_start_day
== -1)
6482 /* We only want to start an edit with a return key or a simple
6484 if ((keyval
!= GDK_KEY_Return
&& keyval
!= GDK_KEY_KP_Enter
) &&
6485 (((keyval
>= 0x20) && (keyval
<= 0xFF)
6486 && (event
->state
& (GDK_CONTROL_MASK
| GDK_MOD1_MASK
)))
6487 || (event
->length
== 0)
6488 || (keyval
== GDK_KEY_Tab
)
6489 || (keyval
== GDK_KEY_Escape
)
6490 || (keyval
== GDK_KEY_Delete
)
6491 || (keyval
== GDK_KEY_KP_Delete
))) {
6495 e_day_view_add_new_event_in_selected_range (day_view
, event
, FALSE
);
6500 /* Select the time that begins a work day*/
6502 e_day_view_goto_start_of_work_day (EDayView
*day_view
)
6504 gint work_day_start_hour
;
6505 gint work_day_start_minute
;
6506 gint work_day_end_hour
;
6507 gint work_day_end_minute
;
6509 if (day_view
->selection_in_top_canvas
)
6512 e_day_view_get_work_day_range_for_day (day_view
, day_view
->selection_start_day
,
6513 &work_day_start_hour
, &work_day_start_minute
,
6514 &work_day_end_hour
, &work_day_end_minute
);
6516 day_view
->selection_start_row
=
6517 e_day_view_convert_time_to_row (
6518 day_view
, work_day_start_hour
, work_day_start_minute
);
6519 day_view
->selection_end_row
= day_view
->selection_start_row
;
6520 day_view
->selection_end_day
= day_view
->selection_start_day
;
6522 e_day_view_ensure_rows_visible (
6524 day_view
->selection_start_row
,
6525 day_view
->selection_end_row
);
6527 e_day_view_update_calendar_selection_time (day_view
);
6529 gtk_widget_queue_draw (day_view
->top_canvas
);
6530 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
6531 gtk_widget_queue_draw (day_view
->main_canvas
);
6534 /* Select the time that ends a work day*/
6536 e_day_view_goto_end_of_work_day (EDayView
*day_view
)
6538 gint work_day_start_hour
;
6539 gint work_day_start_minute
;
6540 gint work_day_end_hour
;
6541 gint work_day_end_minute
;
6543 if (day_view
->selection_in_top_canvas
)
6546 e_day_view_get_work_day_range_for_day (day_view
, day_view
->selection_end_day
,
6547 &work_day_start_hour
, &work_day_start_minute
,
6548 &work_day_end_hour
, &work_day_end_minute
);
6550 day_view
->selection_start_row
=
6551 e_day_view_convert_time_to_row (
6552 day_view
, work_day_end_hour
- 1, work_day_end_minute
+ 30);
6553 day_view
->selection_end_row
= day_view
->selection_start_row
;
6554 day_view
->selection_start_day
= day_view
->selection_end_day
;
6556 e_day_view_ensure_rows_visible (
6558 day_view
->selection_start_row
,
6559 day_view
->selection_end_row
);
6561 e_day_view_update_calendar_selection_time (day_view
);
6563 gtk_widget_queue_draw (day_view
->top_canvas
);
6564 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
6565 gtk_widget_queue_draw (day_view
->main_canvas
);
6568 /* Change the duration to the time that begins the current work day */
6570 e_day_view_change_duration_to_start_of_work_day (EDayView
*day_view
)
6572 gint work_start_row
;
6573 gint work_day_start_hour
;
6574 gint work_day_start_minute
;
6575 gint work_day_end_hour
;
6576 gint work_day_end_minute
;
6578 g_return_if_fail (day_view
!= NULL
);
6580 if (day_view
->selection_in_top_canvas
)
6583 e_day_view_get_work_day_range_for_day (day_view
, day_view
->selection_start_day
,
6584 &work_day_start_hour
, &work_day_start_minute
,
6585 &work_day_end_hour
, &work_day_end_minute
);
6587 work_start_row
= e_day_view_convert_time_to_row (day_view
, work_day_start_hour
, work_day_start_minute
);
6589 if (day_view
->selection_start_row
< work_start_row
)
6590 day_view
->selection_end_row
= work_start_row
- 1;
6592 day_view
->selection_start_row
= work_start_row
;
6594 e_day_view_ensure_rows_visible (
6596 day_view
->selection_start_row
,
6597 day_view
->selection_end_row
);
6599 e_day_view_update_calendar_selection_time (day_view
);
6601 gtk_widget_queue_draw (day_view
->top_canvas
);
6602 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
6603 gtk_widget_queue_draw (day_view
->main_canvas
);
6606 /* Change the duration to the time that ends the current work day */
6608 e_day_view_change_duration_to_end_of_work_day (EDayView
*day_view
)
6610 gint selection_start_row
, work_end_row
;
6611 gint work_day_start_hour
;
6612 gint work_day_start_minute
;
6613 gint work_day_end_hour
;
6614 gint work_day_end_minute
;
6616 g_return_if_fail (day_view
!= NULL
);
6618 if (day_view
->selection_in_top_canvas
)
6621 e_day_view_get_work_day_range_for_day (day_view
, day_view
->selection_start_day
,
6622 &work_day_start_hour
, &work_day_start_minute
,
6623 &work_day_end_hour
, &work_day_end_minute
);
6625 work_end_row
= e_day_view_convert_time_to_row (
6626 day_view
, work_day_end_hour
- 1, work_day_end_minute
+ 30);
6627 selection_start_row
= day_view
->selection_start_row
;
6629 if (selection_start_row
<= work_end_row
) {
6630 day_view
->selection_end_row
= work_end_row
;
6632 day_view
->selection_start_row
= work_end_row
+ 1;
6633 day_view
->selection_end_row
= selection_start_row
;
6636 e_day_view_ensure_rows_visible (
6638 day_view
->selection_start_row
,
6639 day_view
->selection_end_row
);
6641 e_day_view_update_calendar_selection_time (day_view
);
6643 gtk_widget_queue_draw (day_view
->top_canvas
);
6644 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
6645 gtk_widget_queue_draw (day_view
->main_canvas
);
6649 e_day_view_cursor_key_up_shifted (EDayView
*day_view
,
6654 if (day_view
->selection_in_top_canvas
)
6657 if (day_view
->selection_drag_pos
== E_DAY_VIEW_DRAG_START
)
6658 row
= &day_view
->selection_start_row
;
6660 row
= &day_view
->selection_end_row
;
6667 e_day_view_ensure_rows_visible (day_view
, *row
, *row
);
6669 e_day_view_normalize_selection (day_view
);
6671 e_day_view_update_calendar_selection_time (day_view
);
6673 /* FIXME: Optimise? */
6674 gtk_widget_queue_draw (day_view
->top_canvas
);
6675 gtk_widget_queue_draw (day_view
->main_canvas
);
6679 * e_day_view_get_extreme_event
6680 * @day_view: the day view widget operates on
6681 * @start_day, @end_day: range of search, both inclusive
6682 * @first: %TURE indicate to return the data for the first event in the range,
6683 * %FALSE to return data for the last event in the range.
6684 * @day_out: out value, day of the event found. -1 for no event found.
6685 * @event_num_out: out value, event number of the event found.
6686 * -1 for no event found.
6688 * Get day and event_num value for the first or last event found in the day range.
6690 * Return value: %TRUE, if a event found.
6693 e_day_view_get_extreme_event (EDayView
*day_view
,
6698 gint
*event_num_out
)
6702 g_return_val_if_fail (day_view
!= NULL
, FALSE
);
6703 g_return_val_if_fail (start_day
>= 0, FALSE
);
6704 g_return_val_if_fail (end_day
<= E_DAY_VIEW_LONG_EVENT
, FALSE
);
6705 g_return_val_if_fail (day_out
&& event_num_out
, FALSE
);
6707 if (start_day
> end_day
)
6710 for (loop_day
= start_day
; loop_day
<= end_day
; ++loop_day
)
6711 if (day_view
->events
[loop_day
]->len
> 0) {
6712 *day_out
= loop_day
;
6718 for (loop_day
= end_day
; loop_day
>= start_day
; --loop_day
)
6719 if (day_view
->events
[loop_day
]->len
> 0) {
6720 *day_out
= loop_day
;
6722 day_view
->events
[loop_day
]->len
- 1;
6727 *event_num_out
= -1;
6732 * e_day_view_get_extreme_long_event
6733 * @day_view: the day view widget operates on
6734 * @first: %TURE indicate to return the data for the first event in the range,
6735 * %FALSE to return data for the last event in the range.
6736 * @event_num_out: out value, event number of the event found.
6737 * -1 for no event found.
6739 * Similar to e_day_view_get_extreme_event, but run for long events.
6741 * Return value: %TRUE, if a event found.
6744 e_day_view_get_extreme_long_event (EDayView
*day_view
,
6747 gint
*event_num_out
)
6749 g_return_val_if_fail (day_view
!= NULL
, FALSE
);
6750 g_return_val_if_fail (day_out
&& event_num_out
, FALSE
);
6752 if (first
&& (day_view
->long_events
->len
> 0)) {
6753 *day_out
= E_DAY_VIEW_LONG_EVENT
;
6757 if ((!first
) && (day_view
->long_events
->len
> 0)) {
6758 *day_out
= E_DAY_VIEW_LONG_EVENT
;
6759 *event_num_out
= day_view
->long_events
->len
- 1;
6763 *event_num_out
= -1;
6768 * e_day_view_get_next_tab_event
6769 * @day_view: the day view widget operates on
6770 * @direction: GTK_DIR_TAB_BACKWARD or GTK_DIR_TAB_FORWARD
6771 * @day_out: out value, day of the event found. -1 for no event found.
6772 * @event_num_out: out value, event number of the event found.
6773 * -1 for no event found.
6775 * Decide on which event the focus should go next.
6776 * if ((day_out == -1) && (event_num_out == -1)) is true, focus should go
6777 * to day_view widget itself.
6779 * Return value: %TRUE, if a event found.
6782 e_day_view_get_next_tab_event (EDayView
*day_view
,
6783 GtkDirectionType direction
,
6785 gint
*event_num_out
)
6791 g_return_val_if_fail (day_view
!= NULL
, FALSE
);
6792 g_return_val_if_fail (day_out
!= NULL
, FALSE
);
6793 g_return_val_if_fail (event_num_out
!= NULL
, FALSE
);
6795 days_shown
= e_day_view_get_days_shown (day_view
);
6797 *event_num_out
= -1;
6799 g_return_val_if_fail (days_shown
> 0, FALSE
);
6801 switch (direction
) {
6802 case GTK_DIR_TAB_BACKWARD
:
6803 new_event_num
= day_view
->editing_event_num
- 1;
6805 case GTK_DIR_TAB_FORWARD
:
6806 new_event_num
= day_view
->editing_event_num
+ 1;
6812 new_day
= day_view
->editing_event_day
;
6814 /* not current editing event, set to first long event if there is one
6816 if (new_day
== -1) {
6817 if (direction
== GTK_DIR_TAB_FORWARD
) {
6818 if (e_day_view_get_extreme_long_event (day_view
, TRUE
,
6823 /* no long event, set to first event if there is
6825 e_day_view_get_extreme_event (
6827 days_shown
- 1, TRUE
,
6828 day_out
, event_num_out
);
6829 /* go to event if found, or day view widget
6834 if (e_day_view_get_extreme_event (day_view
, 0,
6835 days_shown
- 1, FALSE
,
6836 day_out
, event_num_out
))
6839 /* no event, set to last long event if there is
6841 e_day_view_get_extreme_long_event (
6846 /* go to long event if found, or day view widget
6851 /* go backward from the first long event */
6852 else if ((new_day
== E_DAY_VIEW_LONG_EVENT
) && (new_event_num
< 0)) {
6853 /* let focus go to day view widget in this case
6857 /* go forward from the last long event */
6858 else if ((new_day
== E_DAY_VIEW_LONG_EVENT
) &&
6859 (new_event_num
>= day_view
->long_events
->len
)) {
6860 e_day_view_get_extreme_event (
6862 days_shown
- 1, TRUE
,
6863 day_out
, event_num_out
);
6864 /* go to the next main item event if found or day view widget
6869 /* go backward from the first event in current editting day */
6870 else if ((new_day
< E_DAY_VIEW_LONG_EVENT
) && (new_event_num
< 0)) {
6871 /* try to find a event from the previous day in days shown
6873 if (e_day_view_get_extreme_event (day_view
, 0,
6875 day_out
, event_num_out
))
6877 /* try to find a long event
6879 e_day_view_get_extreme_long_event (
6881 day_out
, event_num_out
);
6882 /* go to a long event if found, or day view widget
6886 /* go forward from the last event in current editting day */
6887 else if ((new_day
< E_DAY_VIEW_LONG_EVENT
) &&
6888 (new_event_num
>= day_view
->events
[new_day
]->len
)) {
6889 /* try to find a event from the next day in days shown
6891 e_day_view_get_extreme_event (
6892 day_view
, (new_day
+ 1),
6893 days_shown
- 1, TRUE
,
6894 day_out
, event_num_out
);
6895 /* go to a event found, or day view widget
6899 /* in the normal case
6902 *event_num_out
= new_event_num
;
6907 e_day_view_cursor_key_down_shifted (EDayView
*day_view
,
6912 if (day_view
->selection_in_top_canvas
)
6915 if (day_view
->selection_drag_pos
== E_DAY_VIEW_DRAG_START
)
6916 row
= &day_view
->selection_start_row
;
6918 row
= &day_view
->selection_end_row
;
6920 if (*row
>= day_view
->rows
- 1)
6925 e_day_view_ensure_rows_visible (day_view
, *row
, *row
);
6927 e_day_view_normalize_selection (day_view
);
6929 e_day_view_update_calendar_selection_time (day_view
);
6931 /* FIXME: Optimise? */
6932 gtk_widget_queue_draw (day_view
->top_canvas
);
6933 gtk_widget_queue_draw (day_view
->main_canvas
);
6937 e_day_view_cursor_key_left_shifted (EDayView
*day_view
,
6942 if (day_view
->selection_drag_pos
== E_DAY_VIEW_DRAG_START
)
6943 day
= &day_view
->selection_start_day
;
6945 day
= &day_view
->selection_end_day
;
6952 e_day_view_normalize_selection (day_view
);
6954 e_day_view_update_calendar_selection_time (day_view
);
6956 /* FIXME: Optimise? */
6957 gtk_widget_queue_draw (day_view
->top_canvas
);
6958 gtk_widget_queue_draw (day_view
->main_canvas
);
6962 e_day_view_cursor_key_right_shifted (EDayView
*day_view
,
6967 if (day_view
->selection_drag_pos
== E_DAY_VIEW_DRAG_START
)
6968 day
= &day_view
->selection_start_day
;
6970 day
= &day_view
->selection_end_day
;
6972 if (*day
>= e_day_view_get_days_shown (day_view
) - 1)
6977 e_day_view_normalize_selection (day_view
);
6979 e_day_view_update_calendar_selection_time (day_view
);
6981 /* FIXME: Optimise? */
6982 gtk_widget_queue_draw (day_view
->top_canvas
);
6983 gtk_widget_queue_draw (day_view
->main_canvas
);
6987 e_day_view_cursor_key_up (EDayView
*day_view
,
6990 if (day_view
->selection_start_day
== -1) {
6991 day_view
->selection_start_day
= 0;
6992 day_view
->selection_start_row
= 0;
6994 day_view
->selection_end_day
= day_view
->selection_start_day
;
6996 if (day_view
->selection_in_top_canvas
) {
6998 } else if (day_view
->selection_start_row
== 0) {
6999 day_view
->selection_in_top_canvas
= TRUE
;
7000 day_view
->selection_start_row
= -1;
7002 day_view
->selection_start_row
--;
7004 day_view
->selection_end_row
= day_view
->selection_start_row
;
7006 if (!day_view
->selection_in_top_canvas
)
7007 e_day_view_ensure_rows_visible (
7009 day_view
->selection_start_row
,
7010 day_view
->selection_end_row
);
7012 g_signal_emit_by_name (day_view
, "selected_time_changed");
7013 e_day_view_update_calendar_selection_time (day_view
);
7015 /* FIXME: Optimise? */
7016 gtk_widget_queue_draw (day_view
->top_canvas
);
7017 gtk_widget_queue_draw (day_view
->main_canvas
);
7021 e_day_view_cursor_key_down (EDayView
*day_view
,
7024 if (day_view
->selection_start_day
== -1) {
7025 day_view
->selection_start_day
= 0;
7026 day_view
->selection_start_row
= 0;
7028 day_view
->selection_end_day
= day_view
->selection_start_day
;
7030 if (day_view
->selection_in_top_canvas
) {
7031 day_view
->selection_in_top_canvas
= FALSE
;
7032 day_view
->selection_start_row
= 0;
7033 } else if (day_view
->selection_start_row
>= day_view
->rows
- 1) {
7036 day_view
->selection_start_row
++;
7038 day_view
->selection_end_row
= day_view
->selection_start_row
;
7040 if (!day_view
->selection_in_top_canvas
)
7041 e_day_view_ensure_rows_visible (
7043 day_view
->selection_start_row
,
7044 day_view
->selection_end_row
);
7046 g_signal_emit_by_name (day_view
, "selected_time_changed");
7047 e_day_view_update_calendar_selection_time (day_view
);
7049 /* FIXME: Optimise? */
7050 gtk_widget_queue_draw (day_view
->top_canvas
);
7051 gtk_widget_queue_draw (day_view
->main_canvas
);
7055 e_day_view_cursor_key_left (EDayView
*day_view
,
7058 if (day_view
->selection_start_day
== 0) {
7059 e_calendar_view_move_view_range (E_CALENDAR_VIEW (day_view
), E_CALENDAR_VIEW_MOVE_PREVIOUS
, 0);
7061 day_view
->selection_start_day
--;
7062 day_view
->selection_end_day
--;
7064 e_day_view_update_calendar_selection_time (day_view
);
7066 /* FIXME: Optimise? */
7067 gtk_widget_queue_draw (day_view
->top_canvas
);
7068 gtk_widget_queue_draw (day_view
->main_canvas
);
7070 g_signal_emit_by_name (day_view
, "selected_time_changed");
7074 e_day_view_cursor_key_right (EDayView
*day_view
,
7079 days_shown
= e_day_view_get_days_shown (day_view
);
7081 if (day_view
->selection_end_day
== days_shown
- 1) {
7082 e_calendar_view_move_view_range (E_CALENDAR_VIEW (day_view
), E_CALENDAR_VIEW_MOVE_NEXT
, 0);
7084 day_view
->selection_start_day
++;
7085 day_view
->selection_end_day
++;
7087 e_day_view_update_calendar_selection_time (day_view
);
7089 /* FIXME: Optimise? */
7090 gtk_widget_queue_draw (day_view
->top_canvas
);
7091 gtk_widget_queue_draw (day_view
->main_canvas
);
7093 g_signal_emit_by_name (day_view
, "selected_time_changed");
7096 /* Scrolls the main canvas up or down. The pages_to_scroll argument
7097 * is multiplied with the adjustment's page size and added to the adjustment's
7098 * value, while ensuring we stay within the bounds. A positive value will
7099 * scroll the canvas down and a negative value will scroll it up. */
7101 e_day_view_scroll (EDayView
*day_view
,
7102 gfloat pages_to_scroll
)
7104 GtkAdjustment
*adjustment
;
7105 GtkScrollable
*scrollable
;
7112 scrollable
= GTK_SCROLLABLE (day_view
->main_canvas
);
7113 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
7115 page_size
= gtk_adjustment_get_page_size (adjustment
);
7116 lower
= gtk_adjustment_get_lower (adjustment
);
7117 upper
= gtk_adjustment_get_upper (adjustment
);
7118 value
= gtk_adjustment_get_value (adjustment
);
7120 new_value
= value
- page_size
* pages_to_scroll
;
7121 new_value
= CLAMP (new_value
, lower
, upper
- page_size
);
7122 gtk_adjustment_set_value (adjustment
, new_value
);
7126 e_day_view_top_scroll (EDayView
*day_view
,
7127 gfloat pages_to_scroll
)
7129 GtkAdjustment
*adjustment
;
7130 GtkScrollable
*scrollable
;
7137 scrollable
= GTK_SCROLLABLE (day_view
->top_canvas
);
7138 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
7140 page_size
= gtk_adjustment_get_page_size (adjustment
);
7141 lower
= gtk_adjustment_get_lower (adjustment
);
7142 upper
= gtk_adjustment_get_upper (adjustment
);
7143 value
= gtk_adjustment_get_value (adjustment
);
7145 new_value
= value
- page_size
* pages_to_scroll
;
7146 new_value
= CLAMP (new_value
, lower
, upper
- page_size
);
7147 gtk_adjustment_set_value (adjustment
, new_value
);
7151 e_day_view_ensure_rows_visible (EDayView
*day_view
,
7155 GtkAdjustment
*adjustment
;
7156 GtkScrollable
*scrollable
;
7162 scrollable
= GTK_SCROLLABLE (day_view
->main_canvas
);
7163 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
7165 value
= gtk_adjustment_get_value (adjustment
);
7166 page_size
= gtk_adjustment_get_page_size (adjustment
);
7168 min_value
= (end_row
+ 1) * day_view
->row_height
- page_size
;
7169 if (value
< min_value
)
7172 max_value
= start_row
* day_view
->row_height
;
7173 if (value
> max_value
)
7176 gtk_adjustment_set_value (adjustment
, value
);
7180 e_day_view_start_editing_event (EDayView
*day_view
,
7183 GdkEventKey
*key_event
)
7185 EDayViewEvent
*event
;
7186 ETextEventProcessor
*event_processor
= NULL
;
7187 ETextEventProcessorCommand command
;
7189 /* If we are already editing the event, just return. */
7190 if (day
== day_view
->editing_event_day
7191 && event_num
== day_view
->editing_event_num
)
7194 if (day
== E_DAY_VIEW_LONG_EVENT
) {
7195 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
7198 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
7201 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
7204 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
7208 if (!is_comp_data_valid (event
))
7211 if (e_client_is_readonly (E_CLIENT (event
->comp_data
->client
)))
7214 /* If the event is not shown, don't try to edit it. */
7215 if (!event
->canvas_item
)
7218 /* We must grab the focus before setting the initial text, since
7219 * grabbing the focus will result in a call to
7220 * e_day_view_on_editing_started (), which will reset the text to get
7221 * rid of the start and end times. */
7222 e_canvas_item_grab_focus (event
->canvas_item
, TRUE
);
7225 if (gtk_im_context_filter_keypress (((EText
*)(event
->canvas_item
))->im_context
, key_event
)) {
7226 ((EText
*)(event
->canvas_item
))->need_im_reset
= TRUE
;
7227 } else if (key_event
->keyval
!= GDK_KEY_Return
&& key_event
->keyval
!= GDK_KEY_KP_Enter
) {
7228 gchar
*initial_text
;
7230 initial_text
= e_utf8_from_gtk_event_key (GTK_WIDGET (day_view
), key_event
->keyval
, key_event
->string
);
7231 gnome_canvas_item_set (
7233 "text", initial_text
,
7236 g_free (initial_text
);
7240 /* Try to move the cursor to the end of the text. */
7243 "event_processor", &event_processor
,
7245 if (event_processor
) {
7246 command
.action
= E_TEP_MOVE
;
7247 command
.position
= E_TEP_END_OF_BUFFER
;
7248 g_signal_emit_by_name (
7250 "command", &command
);
7254 /* This stops the current edit. If accept is TRUE the event summary is updated,
7255 * else the edit is cancelled. */
7257 e_day_view_stop_editing_event (EDayView
*day_view
)
7259 GtkWidget
*toplevel
;
7261 /* Check we are editing an event. */
7262 if (day_view
->editing_event_day
== -1)
7265 /* Set focus to the toplevel so the item loses focus. */
7266 toplevel
= gtk_widget_get_toplevel (GTK_WIDGET (day_view
));
7267 if (toplevel
&& GTK_IS_WINDOW (toplevel
))
7268 gtk_window_set_focus (GTK_WINDOW (toplevel
), NULL
);
7271 /* Cancels the current edition by resetting the appointment's text to its original value */
7273 cancel_editing (EDayView
*day_view
)
7275 gint day
, event_num
;
7276 EDayViewEvent
*event
;
7277 const gchar
*summary
;
7279 day
= day_view
->editing_event_day
;
7280 event_num
= day_view
->editing_event_num
;
7285 if (day
== E_DAY_VIEW_LONG_EVENT
) {
7286 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
7289 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
, event_num
);
7291 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
7294 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
, event_num
);
7297 if (!is_comp_data_valid (event
))
7300 /* Reset the text to what was in the component */
7302 summary
= icalcomponent_get_summary (event
->comp_data
->icalcomp
);
7305 "text", summary
? summary
: "",
7309 e_day_view_stop_editing_event (day_view
);
7312 static EDayViewEvent
*
7313 tooltip_get_view_event (EDayView
*day_view
,
7317 EDayViewEvent
*pevent
;
7319 if (day
== E_DAY_VIEW_LONG_EVENT
) {
7320 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
7323 pevent
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
7326 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
7329 pevent
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
7337 tooltip_destroy (EDayView
*day_view
,
7338 GnomeCanvasItem
*item
)
7340 GtkWidget
*tooltip
= g_object_get_data (G_OBJECT (day_view
), "tooltip-window");
7343 gtk_widget_destroy (tooltip
);
7344 g_object_set_data (G_OBJECT (day_view
), "tooltip-window", NULL
);
7348 EDayViewEvent
*pevent
;
7349 gint event_num
, day
;
7351 e_day_view_check_layout (day_view
);
7353 event_num
= GPOINTER_TO_INT (g_object_get_data ((GObject
*) item
, "event-num"));
7354 day
= GPOINTER_TO_INT (g_object_get_data ((GObject
*) item
, "event-day"));
7355 pevent
= tooltip_get_view_event (day_view
, day
, event_num
);
7357 pevent
->tooltip
= NULL
;
7358 if (pevent
->timeout
!= -1) {
7359 g_source_remove (pevent
->timeout
);
7360 pevent
->timeout
= -1;
7367 e_day_view_on_text_item_event (GnomeCanvasItem
*item
,
7371 switch (event
->type
) {
7373 tooltip_destroy (day_view
, item
);
7374 if (!E_TEXT (item
)->preedit_len
&& event
&& (
7375 event
->key
.keyval
== GDK_KEY_Return
||
7376 event
->key
.keyval
== GDK_KEY_KP_Enter
)) {
7377 day_view
->resize_event_num
= -1;
7379 /* We set the keyboard focus to the EDayView, so the
7380 * EText item loses it and stops the edit. */
7381 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
7383 /* Stop the signal last or we will also stop any
7384 * other events getting to the EText item. */
7385 g_signal_stop_emission_by_name (item
, "event");
7387 } else if (event
->key
.keyval
== GDK_KEY_Escape
) {
7388 cancel_editing (day_view
);
7389 g_signal_stop_emission_by_name (item
, "event");
7390 /* focus should go to day view when stop editing */
7391 gtk_widget_grab_focus (GTK_WIDGET (day_view
));
7393 } else if ((event
->key
.keyval
== GDK_KEY_Up
)
7394 && (event
->key
.state
& GDK_SHIFT_MASK
)
7395 && (event
->key
.state
& GDK_CONTROL_MASK
)
7396 && !(event
->key
.state
& GDK_MOD1_MASK
)) {
7397 e_day_view_change_event_end_time_up (day_view
);
7399 } else if ((event
->key
.keyval
== GDK_KEY_Down
)
7400 && (event
->key
.state
& GDK_SHIFT_MASK
)
7401 && (event
->key
.state
& GDK_CONTROL_MASK
)
7402 && !(event
->key
.state
& GDK_MOD1_MASK
)) {
7403 e_day_view_change_event_end_time_down (day_view
);
7407 case GDK_2BUTTON_PRESS
:
7410 case GDK_BUTTON_RELEASE
:
7411 if (day_view
->resize_event_num
!= -1)
7412 day_view
->resize_event_num
= -1;
7414 if (day_view
->drag_event_num
!= -1)
7415 day_view
->drag_event_num
= -1;
7416 tooltip_destroy (day_view
, item
);
7417 /* Only let the EText handle the event while editing. */
7418 if (!E_TEXT (item
)->editing
)
7419 g_signal_stop_emission_by_name (item
, "event");
7422 case GDK_BUTTON_PRESS
:
7423 tooltip_destroy (day_view
, item
);
7424 /* Only let the EText handle the event while editing. */
7425 if (!E_TEXT (item
)->editing
)
7426 g_signal_stop_emission_by_name (item
, "event");
7428 case GDK_FOCUS_CHANGE
:
7429 if (event
->focus_change
.in
)
7430 e_day_view_on_editing_started (day_view
, item
);
7432 e_day_view_on_editing_stopped (day_view
, item
);
7435 case GDK_ENTER_NOTIFY
:
7437 EDayViewEvent
*pevent
;
7438 ECalendarViewEventData
*data
;
7439 gint event_x
, event_y
, row
, day
, event_num
;
7440 ECalendarViewPosition pos
;
7441 gboolean main_canvas
= TRUE
;
7445 if (day_view
->editing_event_num
!= -1)
7448 if (day_view
->resize_event_num
!= -1)
7451 if (day_view
->drag_event_num
!= -1)
7454 /* Convert the coords to the main canvas window, or return if the
7455 * window is not found. */
7456 layout
= GTK_LAYOUT (day_view
->main_canvas
);
7457 window
= gtk_layout_get_bin_window (layout
);
7458 if (!e_day_view_convert_event_coords (
7459 day_view
, (GdkEvent
*) event
,
7460 window
, &event_x
, &event_y
)) {
7462 main_canvas
= FALSE
;
7464 layout
= GTK_LAYOUT (day_view
->top_canvas
);
7465 window
= gtk_layout_get_bin_window (layout
);
7466 if (!e_day_view_convert_event_coords (
7467 day_view
, (GdkEvent
*) event
,
7468 window
, &event_x
, &event_y
)) {
7472 /* Find out where the mouse is. */
7474 pos
= e_day_view_convert_position_in_main_canvas (
7482 pos
= e_day_view_convert_position_in_top_canvas (
7486 day
= E_DAY_VIEW_LONG_EVENT
;
7489 if (pos
== E_CALENDAR_VIEW_POS_OUTSIDE
)
7492 /* even when returns position inside, or other, then the day and/or event_num
7493 * can be unknown, thus check for this here, otherwise it will crash later */
7494 if (day
== -1 || event_num
== -1)
7497 pevent
= tooltip_get_view_event (day_view
, day
, event_num
);
7501 g_object_set_data (G_OBJECT (item
), "event-num", GINT_TO_POINTER (event_num
));
7502 g_object_set_data (G_OBJECT (item
), "event-day", GINT_TO_POINTER (day
));
7504 data
= g_malloc (sizeof (ECalendarViewEventData
));
7505 pevent
->x
= ((GdkEventCrossing
*) event
)->x_root
;
7506 pevent
->y
= ((GdkEventCrossing
*) event
)->y_root
;
7507 pevent
->tooltip
= NULL
;
7509 data
->cal_view
= (ECalendarView
*) day_view
;
7511 data
->event_num
= event_num
;
7512 data
->get_view_event
= (ECalendarViewEvent
* (*)(ECalendarView
*, int, gint
)) tooltip_get_view_event
;
7513 pevent
->timeout
= e_named_timeout_add_full (
7514 G_PRIORITY_DEFAULT
, 500,
7515 (GSourceFunc
) e_calendar_view_get_tooltips
,
7516 data
, (GDestroyNotify
) g_free
);
7520 case GDK_LEAVE_NOTIFY
:
7521 tooltip_destroy (day_view
, item
);
7523 case GDK_MOTION_NOTIFY
:
7525 EDayViewEvent
*pevent
;
7526 gint event_num
, day
;
7528 e_day_view_check_layout (day_view
);
7530 event_num
= GPOINTER_TO_INT (g_object_get_data ((GObject
*) item
, "event-num"));
7531 day
= GPOINTER_TO_INT (g_object_get_data ((GObject
*) item
, "event-day"));
7533 pevent
= tooltip_get_view_event (day_view
, day
, event_num
);
7537 pevent
->x
= ((GdkEventMotion
*) event
)->x_root
;
7538 pevent
->y
= ((GdkEventMotion
*) event
)->y_root
;
7539 pevent
->tooltip
= (GtkWidget
*) g_object_get_data (G_OBJECT (day_view
), "tooltip-window");
7541 if (pevent
->tooltip
) {
7542 e_calendar_view_move_tip (pevent
->tooltip
, pevent
->x
+ 16, pevent
->y
+ 16);
7555 e_day_view_event_move (ECalendarView
*cal_view
,
7556 ECalViewMoveDirection direction
)
7558 EDayViewEvent
*event
;
7560 gint time_divisions
;
7561 gint day
, event_num
, resize_start_row
, resize_end_row
;
7562 time_t start_dt
, end_dt
;
7563 struct icaltimetype start_time
, end_time
;
7565 day_view
= E_DAY_VIEW (cal_view
);
7566 day
= day_view
->editing_event_day
;
7567 event_num
= day_view
->editing_event_num
;
7569 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
7571 if ((day
== -1) || (day
== E_DAY_VIEW_LONG_EVENT
))
7574 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
7577 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
7579 day_view
->resize_event_day
= day
;
7580 day_view
->resize_event_num
= event_num
;
7581 day_view
->resize_bars_event_day
= day
;
7582 day_view
->resize_bars_event_num
= event_num
;
7583 resize_start_row
= event
->start_minute
/ time_divisions
;
7584 resize_end_row
= (event
->end_minute
- 1) / time_divisions
;
7585 if (resize_end_row
< resize_start_row
)
7586 resize_end_row
= resize_start_row
;
7588 switch (direction
) {
7589 case E_CAL_VIEW_MOVE_UP
:
7590 if (resize_start_row
<= 0)
7594 start_dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, resize_start_row
);
7595 end_dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, resize_end_row
+ 1);
7597 case E_CAL_VIEW_MOVE_DOWN
:
7598 if (resize_end_row
>= day_view
->rows
- 1)
7602 start_dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, resize_start_row
);
7603 end_dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, resize_end_row
+ 1);
7605 case E_CAL_VIEW_MOVE_LEFT
:
7608 start_dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, resize_start_row
);
7609 end_dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, resize_end_row
+ 1);
7610 start_time
= icaltime_from_timet_with_zone (start_dt
, 0, NULL
);
7611 end_time
= icaltime_from_timet_with_zone (end_dt
, 0, NULL
);
7612 icaltime_adjust (&start_time
,-1,0,0,0);
7613 icaltime_adjust (&end_time
,-1,0,0,0);
7614 start_dt
= icaltime_as_timet (start_time
);
7615 end_dt
= icaltime_as_timet (end_time
);
7617 case E_CAL_VIEW_MOVE_RIGHT
:
7618 if (day
+ 1 >= e_day_view_get_days_shown (day_view
))
7620 start_dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, resize_start_row
);
7621 end_dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, resize_end_row
+ 1);
7622 start_time
= icaltime_from_timet_with_zone (start_dt
, 0, NULL
);
7623 end_time
= icaltime_from_timet_with_zone (end_dt
, 0, NULL
);
7624 icaltime_adjust (&start_time
,1,0,0,0);
7625 icaltime_adjust (&end_time
,1,0,0,0);
7626 start_dt
= icaltime_as_timet (start_time
);
7627 end_dt
= icaltime_as_timet (end_time
);
7633 e_day_view_change_event_time (day_view
, start_dt
, end_dt
);
7634 e_day_view_ensure_rows_visible (day_view
, resize_start_row
, resize_end_row
);
7640 e_day_view_change_event_time (EDayView
*day_view
,
7644 EDayViewEvent
*event
;
7645 gint day
, event_num
;
7646 ECalComponent
*comp
;
7647 ECalComponentDateTime date
;
7648 struct icaltimetype itt
;
7651 ESourceRegistry
*registry
;
7652 ECalObjModType mod
= E_CAL_OBJ_MOD_ALL
;
7654 day
= day_view
->editing_event_day
;
7655 event_num
= day_view
->editing_event_num
;
7657 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
7658 registry
= e_cal_model_get_registry (model
);
7660 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
7663 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
7666 if (!is_comp_data_valid (event
))
7669 client
= event
->comp_data
->client
;
7671 /* We use a temporary shallow copy of the ico since we don't want to
7672 * change the original ico here. Otherwise we would not detect that
7673 * the event's time had changed in the "update_event" callback. */
7674 comp
= e_cal_component_new ();
7675 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
7677 if (e_cal_component_has_attendees (comp
) &&
7678 !itip_organizer_is_user (registry
, comp
, client
)) {
7679 g_object_unref (comp
);
7684 /* FIXME: Should probably keep the timezone of the original start
7686 date
.tzid
= icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
7688 *date
.value
= icaltime_from_timet_with_zone (start_dt
, FALSE
,
7689 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
7690 cal_comp_set_dtstart_with_oldzone (client
, comp
, &date
);
7691 *date
.value
= icaltime_from_timet_with_zone (end_dt
, FALSE
,
7692 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
7693 cal_comp_set_dtend_with_oldzone (client
, comp
, &date
);
7695 e_cal_component_commit_sequence (comp
);
7697 if (day_view
->last_edited_comp_string
!= NULL
) {
7698 g_free (day_view
->last_edited_comp_string
);
7699 day_view
->last_edited_comp_string
= NULL
;
7702 day_view
->last_edited_comp_string
= e_cal_component_get_as_string (comp
);
7704 day_view
->resize_drag_pos
= E_CALENDAR_VIEW_POS_NONE
;
7706 if (e_cal_component_has_recurrences (comp
)) {
7707 if (!e_cal_dialogs_recur_component (client
, comp
, &mod
, NULL
, FALSE
)) {
7708 gtk_widget_queue_draw (day_view
->top_canvas
);
7712 if (mod
== E_CAL_OBJ_MOD_THIS
) {
7713 e_cal_component_set_rdate_list (comp
, NULL
);
7714 e_cal_component_set_rrule_list (comp
, NULL
);
7715 e_cal_component_set_exdate_list (comp
, NULL
);
7716 e_cal_component_set_exrule_list (comp
, NULL
);
7718 } else if (e_cal_component_is_instance (comp
))
7719 mod
= E_CAL_OBJ_MOD_THIS
;
7721 e_cal_component_commit_sequence (comp
);
7723 e_cal_ops_modify_component (model
, client
, e_cal_component_get_icalcomponent (comp
),
7724 mod
, E_CAL_OPS_SEND_FLAG_ASK
| E_CAL_OPS_SEND_FLAG_IS_NEW_COMPONENT
);
7727 g_object_unref (comp
);
7731 e_day_view_change_event_end_time_up (EDayView
*day_view
)
7733 EDayViewEvent
*event
;
7734 ECalendarView
*cal_view
;
7735 gint time_divisions
;
7736 gint day
, event_num
, resize_start_row
, resize_end_row
;
7738 day
= day_view
->editing_event_day
;
7739 event_num
= day_view
->editing_event_num
;
7740 if ((day
== -1) || (day
== E_DAY_VIEW_LONG_EVENT
))
7743 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
7746 cal_view
= E_CALENDAR_VIEW (day_view
);
7747 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
7749 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
7751 day_view
->resize_event_day
= day
;
7752 day_view
->resize_event_num
= event_num
;
7753 day_view
->resize_bars_event_day
= day
;
7754 day_view
->resize_bars_event_num
= event_num
;
7755 resize_start_row
= event
->start_minute
/ time_divisions
;
7756 resize_end_row
= (event
->end_minute
- 1) / time_divisions
;
7757 if (resize_end_row
< resize_start_row
)
7758 resize_end_row
= resize_start_row
;
7759 if (resize_end_row
== resize_start_row
)
7761 day_view
->resize_drag_pos
= E_CALENDAR_VIEW_POS_BOTTOM_EDGE
;
7763 day_view
->resize_start_row
= resize_start_row
;
7764 day_view
->resize_end_row
= resize_end_row
;
7765 e_day_view_finish_resize (day_view
);
7766 e_day_view_ensure_rows_visible (day_view
, resize_start_row
, resize_end_row
);
7770 e_day_view_change_event_end_time_down (EDayView
*day_view
)
7772 EDayViewEvent
*event
;
7773 ECalendarView
*cal_view
;
7774 gint time_divisions
;
7775 gint day
, event_num
, resize_start_row
, resize_end_row
;
7777 cal_view
= E_CALENDAR_VIEW (day_view
);
7778 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
7780 day
= day_view
->editing_event_day
;
7781 event_num
= day_view
->editing_event_num
;
7782 if ((day
== -1) || (day
== E_DAY_VIEW_LONG_EVENT
))
7785 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
7788 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
7790 day_view
->resize_event_day
= day
;
7791 day_view
->resize_event_num
= event_num
;
7792 day_view
->resize_bars_event_day
= day
;
7793 day_view
->resize_bars_event_num
= event_num
;
7794 resize_start_row
= event
->start_minute
/ time_divisions
;
7795 resize_end_row
= (event
->end_minute
- 1) / time_divisions
;
7796 if (resize_end_row
< resize_start_row
)
7797 resize_end_row
= resize_start_row
;
7798 if (resize_end_row
== day_view
->rows
-1)
7800 day_view
->resize_drag_pos
= E_CALENDAR_VIEW_POS_BOTTOM_EDGE
;
7802 day_view
->resize_start_row
= resize_start_row
;
7803 day_view
->resize_end_row
= resize_end_row
;
7804 e_day_view_finish_resize (day_view
);
7805 e_day_view_ensure_rows_visible (day_view
, resize_start_row
, resize_end_row
);
7809 e_day_view_on_editing_started (EDayView
*day_view
,
7810 GnomeCanvasItem
*item
)
7812 GtkAllocation allocation
;
7813 gint day
, event_num
;
7815 if (!e_day_view_find_event_from_item (day_view
, item
,
7819 /* FIXME: This is a temporary workaround for a bug which seems to stop
7820 * us getting focus_out signals. It is not a complete fix since if we
7821 * don't get focus_out signals we don't save the appointment text so
7822 * this may be lost. */
7823 if (day_view
->editing_event_day
== day
7824 && day_view
->editing_event_num
== event_num
)
7827 day_view
->editing_event_day
= day
;
7828 day_view
->editing_event_num
= event_num
;
7830 gtk_widget_get_allocation (day_view
->top_canvas
, &allocation
);
7832 if (day
== E_DAY_VIEW_LONG_EVENT
) {
7833 gint item_x
, item_y
, item_w
, item_h
, scroll_y
;
7834 gint start_day
, end_day
;
7836 e_day_view_reshape_long_event (day_view
, event_num
);
7838 if (e_day_view_get_long_event_position (day_view
, event_num
,
7839 &start_day
, &end_day
,
7841 &item_w
, &item_h
)) {
7842 GtkAdjustment
*adjustment
;
7843 GtkScrollable
*scrollable
;
7845 scrollable
= GTK_SCROLLABLE (day_view
->top_canvas
);
7846 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
7848 /* and ensure it's visible too */
7849 /*item_y = (event_num * (day_view->top_row_height + 1)) - 1;*/
7850 scroll_y
= gtk_adjustment_get_value (adjustment
);
7851 if (item_y
+ day_view
->top_row_height
> allocation
.height
+ scroll_y
|| item_y
< scroll_y
)
7852 gnome_canvas_scroll_to (GNOME_CANVAS (day_view
->top_canvas
), 0, item_y
);
7855 day_view
->resize_bars_event_day
= day
;
7856 day_view
->resize_bars_event_num
= event_num
;
7857 e_day_view_update_event_label (day_view
, day
, event_num
);
7858 e_day_view_reshape_main_canvas_resize_bars (day_view
);
7861 g_signal_emit_by_name (day_view
, "selection_changed");
7863 g_object_notify (G_OBJECT (day_view
), "is-editing");
7867 e_day_view_on_editing_stopped (EDayView
*day_view
,
7868 GnomeCanvasItem
*item
)
7870 gint day
, event_num
;
7871 EDayViewEvent
*event
;
7873 ECalComponentText summary
;
7874 ECalComponent
*comp
;
7878 /* Note: the item we are passed here isn't reliable, so we just stop
7879 * the edit of whatever item was being edited. We also receive this
7880 * event twice for some reason. */
7881 day
= day_view
->editing_event_day
;
7882 event_num
= day_view
->editing_event_num
;
7884 /* If no item is being edited, just return. */
7888 if (day
== E_DAY_VIEW_LONG_EVENT
) {
7889 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
7892 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
7895 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
7898 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
7903 if (!is_comp_data_valid (event
))
7906 /* Reset the edit fields. */
7907 day_view
->editing_event_day
= -1;
7908 day_view
->editing_event_num
= -1;
7910 day_view
->resize_bars_event_day
= -1;
7911 day_view
->resize_bars_event_num
= -1;
7913 g_object_set (event
->canvas_item
, "handle_popup", FALSE
, NULL
);
7918 g_return_if_fail (text
!= NULL
);
7920 comp
= e_cal_component_new ();
7921 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
7923 client
= event
->comp_data
->client
;
7924 on_server
= !event
->comp_data
->is_new_component
;
7926 if (string_is_empty (text
) && !on_server
) {
7929 e_cal_component_get_uid (comp
, &uid
);
7931 e_day_view_foreach_event_with_uid (day_view
, uid
,
7932 e_day_view_remove_event_cb
, NULL
);
7933 e_day_view_check_layout (day_view
);
7934 gtk_widget_queue_draw (day_view
->top_canvas
);
7935 gtk_widget_queue_draw (day_view
->main_canvas
);
7939 /* Only update the summary if necessary. */
7940 e_cal_component_get_summary (comp
, &summary
);
7941 if (summary
.value
&& !strcmp (text
, summary
.value
)) {
7942 if (day
== E_DAY_VIEW_LONG_EVENT
)
7943 e_day_view_reshape_long_event (day_view
, event_num
);
7945 e_day_view_update_event_label (
7948 } else if (summary
.value
|| !string_is_empty (text
)) {
7949 icalcomponent
*icalcomp
= e_cal_component_get_icalcomponent (comp
);
7951 summary
.value
= text
;
7952 summary
.altrep
= NULL
;
7953 e_cal_component_set_summary (comp
, &summary
);
7954 e_cal_component_commit_sequence (comp
);
7957 e_cal_ops_create_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
)), client
, icalcomp
,
7958 e_calendar_view_component_created_cb
, g_object_ref (day_view
), g_object_unref
);
7960 /* we remove the object since we either got the update from the server or failed */
7961 e_day_view_remove_event_cb (day_view
, day
, event_num
, NULL
);
7963 ECalObjModType mod
= E_CAL_OBJ_MOD_ALL
;
7965 if (e_cal_component_has_recurrences (comp
)) {
7966 if (!e_cal_dialogs_recur_component (client
, comp
, &mod
, NULL
, FALSE
)) {
7970 if (mod
== E_CAL_OBJ_MOD_THIS
) {
7971 ECalComponentDateTime olddt
, dt
;
7976 e_cal_component_get_dtstart (comp
, &olddt
);
7977 if (olddt
.value
->zone
) {
7978 *dt
.value
= icaltime_from_timet_with_zone (
7979 event
->comp_data
->instance_start
,
7980 olddt
.value
->is_date
,
7983 *dt
.value
= icaltime_from_timet_with_zone (
7984 event
->comp_data
->instance_start
,
7985 olddt
.value
->is_date
,
7986 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
7988 dt
.tzid
= olddt
.tzid
;
7989 e_cal_component_set_dtstart (comp
, &dt
);
7991 e_cal_component_free_datetime (&olddt
);
7993 e_cal_component_get_dtend (comp
, &olddt
);
7994 if (olddt
.value
->zone
) {
7995 *dt
.value
= icaltime_from_timet_with_zone (
7996 event
->comp_data
->instance_end
,
7997 olddt
.value
->is_date
,
8000 *dt
.value
= icaltime_from_timet_with_zone (
8001 event
->comp_data
->instance_end
,
8002 olddt
.value
->is_date
,
8003 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
8005 dt
.tzid
= olddt
.tzid
;
8006 e_cal_component_set_dtend (comp
, &dt
);
8008 e_cal_component_free_datetime (&olddt
);
8010 e_cal_component_set_rdate_list (comp
, NULL
);
8011 e_cal_component_set_rrule_list (comp
, NULL
);
8012 e_cal_component_set_exdate_list (comp
, NULL
);
8013 e_cal_component_set_exrule_list (comp
, NULL
);
8015 e_cal_component_commit_sequence (comp
);
8017 } else if (e_cal_component_is_instance (comp
))
8018 mod
= E_CAL_OBJ_MOD_THIS
;
8020 e_cal_ops_modify_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
)),
8021 client
, e_cal_component_get_icalcomponent (comp
), mod
, E_CAL_OPS_SEND_FLAG_ASK
);
8025 gtk_widget_queue_draw (day_view
->main_canvas
);
8029 g_object_unref (comp
);
8032 g_signal_emit_by_name (day_view
, "selection_changed");
8034 g_object_notify (G_OBJECT (day_view
), "is-editing");
8037 /* FIXME: It is possible that we may produce an invalid time due to daylight
8038 * saving times (i.e. when clocks go forward there is a range of time which
8039 * is not valid). I don't know the best way to handle daylight saving time. */
8041 e_day_view_convert_grid_position_to_time (EDayView
*day_view
,
8045 ECalendarView
*cal_view
;
8046 gint time_divisions
;
8047 struct icaltimetype tt
;
8051 cal_view
= E_CALENDAR_VIEW (day_view
);
8052 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
8054 /* Calulate the number of minutes since the start of the day. */
8055 minutes
= day_view
->first_hour_shown
* 60
8056 + day_view
->first_minute_shown
8057 + row
* time_divisions
;
8059 /* A special case for midnight, where we can use the start of the
8061 if (minutes
== 60 * 24)
8062 return day_view
->day_starts
[col
+ 1];
8064 /* Create an icaltimetype and convert to a time_t. */
8065 tt
= icaltime_from_timet_with_zone (
8066 day_view
->day_starts
[col
],
8067 FALSE
, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
8068 tt
.hour
= minutes
/ 60;
8069 tt
.minute
= minutes
% 60;
8072 val
= icaltime_as_timet_with_zone (tt
, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
8077 e_day_view_convert_time_to_grid_position (EDayView
*day_view
,
8082 ECalendarView
*cal_view
;
8083 struct icaltimetype tt
;
8084 gint time_divisions
;
8090 cal_view
= E_CALENDAR_VIEW (day_view
);
8091 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
8093 if (time
< day_view
->lower
|| time
>= day_view
->upper
)
8096 days_shown
= e_day_view_get_days_shown (day_view
);
8098 /* We can find the column easily using the day_starts array. */
8099 for (day
= 1; day
<= days_shown
; day
++) {
8100 if (time
< day_view
->day_starts
[day
]) {
8106 /* To find the row we need to convert the time to an icaltimetype,
8107 * calculate the offset in minutes from the top of the display and
8108 * divide it by the mins per row setting. */
8109 tt
= icaltime_from_timet_with_zone (time
, FALSE
, e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
8111 minutes
= tt
.hour
* 60 + tt
.minute
;
8112 minutes
-= day_view
->first_hour_shown
* 60 + day_view
->first_minute_shown
;
8114 *row
= minutes
/ time_divisions
;
8116 if (*row
< 0 || *row
>= day_view
->rows
)
8122 /* This starts or stops auto-scrolling when dragging a selection or resizing
8125 e_day_view_check_auto_scroll (EDayView
*day_view
,
8129 GtkAllocation allocation
;
8130 gint scroll_x
, scroll_y
;
8132 gnome_canvas_get_scroll_offsets (
8133 GNOME_CANVAS (day_view
->main_canvas
),
8134 &scroll_x
, &scroll_y
);
8136 event_x
-= scroll_x
;
8137 event_y
-= scroll_y
;
8139 day_view
->last_mouse_x
= event_x
;
8140 day_view
->last_mouse_y
= event_y
;
8142 gtk_widget_get_allocation (day_view
->main_canvas
, &allocation
);
8144 if (event_y
< E_DAY_VIEW_AUTO_SCROLL_OFFSET
)
8145 e_day_view_start_auto_scroll (day_view
, TRUE
);
8146 else if (event_y
>= allocation
.height
- E_DAY_VIEW_AUTO_SCROLL_OFFSET
)
8147 e_day_view_start_auto_scroll (day_view
, FALSE
);
8149 e_day_view_stop_auto_scroll (day_view
);
8153 e_day_view_start_auto_scroll (EDayView
*day_view
,
8156 if (day_view
->auto_scroll_timeout_id
== 0) {
8157 day_view
->auto_scroll_timeout_id
= e_named_timeout_add (
8158 E_DAY_VIEW_AUTO_SCROLL_TIMEOUT
,
8159 e_day_view_auto_scroll_handler
, day_view
);
8160 day_view
->auto_scroll_delay
= E_DAY_VIEW_AUTO_SCROLL_DELAY
;
8162 day_view
->auto_scroll_up
= scroll_up
;
8166 e_day_view_stop_auto_scroll (EDayView
*day_view
)
8168 if (day_view
->auto_scroll_timeout_id
!= 0) {
8169 g_source_remove (day_view
->auto_scroll_timeout_id
);
8170 day_view
->auto_scroll_timeout_id
= 0;
8175 e_day_view_auto_scroll_handler (gpointer data
)
8178 ECalendarViewPosition pos
;
8179 gint scroll_x
, scroll_y
, new_scroll_y
, canvas_x
, canvas_y
, row
, day
;
8180 GtkAdjustment
*adjustment
;
8181 GtkScrollable
*scrollable
;
8182 gdouble step_increment
;
8186 g_return_val_if_fail (E_IS_DAY_VIEW (data
), FALSE
);
8188 day_view
= E_DAY_VIEW (data
);
8190 if (day_view
->auto_scroll_delay
> 0) {
8191 day_view
->auto_scroll_delay
--;
8195 gnome_canvas_get_scroll_offsets (
8196 GNOME_CANVAS (day_view
->main_canvas
),
8197 &scroll_x
, &scroll_y
);
8199 scrollable
= GTK_SCROLLABLE (day_view
->main_canvas
);
8200 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
8202 step_increment
= gtk_adjustment_get_step_increment (adjustment
);
8203 page_size
= gtk_adjustment_get_page_size (adjustment
);
8204 upper
= gtk_adjustment_get_upper (adjustment
);
8206 if (day_view
->auto_scroll_up
)
8207 new_scroll_y
= MAX (scroll_y
- step_increment
, 0);
8209 new_scroll_y
= MIN (
8210 scroll_y
+ step_increment
,
8213 if (new_scroll_y
!= scroll_y
) {
8214 /* NOTE: This reduces flicker, but only works if we don't use
8215 * canvas items which have X windows. */
8216 gnome_canvas_scroll_to (
8217 GNOME_CANVAS (day_view
->main_canvas
),
8218 scroll_x
, new_scroll_y
);
8221 canvas_x
= day_view
->last_mouse_x
+ scroll_x
;
8222 canvas_y
= day_view
->last_mouse_y
+ new_scroll_y
;
8224 /* The last_mouse_x position is set to -1 when we are selecting using
8225 * the time column. In this case we set canvas_x to 0 and we ignore
8226 * the resulting day. */
8227 if (day_view
->last_mouse_x
== -1)
8230 /* Update the selection/resize/drag if necessary. */
8231 pos
= e_day_view_convert_position_in_main_canvas (
8236 if (day_view
->last_mouse_x
== -1)
8239 if (pos
!= E_CALENDAR_VIEW_POS_OUTSIDE
) {
8240 if (day_view
->selection_is_being_dragged
) {
8241 e_day_view_update_selection (day_view
, day
, row
);
8242 } else if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
) {
8243 e_day_view_update_resize (day_view
, row
);
8244 } else if (day_view
->drag_item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
) {
8245 e_day_view_update_main_canvas_drag (day_view
, row
, day
);
8253 e_day_view_get_event_rows (EDayView
*day_view
,
8256 gint
*start_row_out
,
8259 ECalendarView
*cal_view
;
8260 EDayViewEvent
*event
;
8261 gint time_divisions
;
8262 gint start_row
, end_row
;
8264 g_return_val_if_fail (day
>= 0, FALSE
);
8265 g_return_val_if_fail (day
< E_DAY_VIEW_LONG_EVENT
, FALSE
);
8266 g_return_val_if_fail (event_num
>= 0, FALSE
);
8268 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
8271 cal_view
= E_CALENDAR_VIEW (day_view
);
8272 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
8274 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
8276 start_row
= event
->start_minute
/ time_divisions
;
8277 end_row
= (event
->end_minute
- 1) / time_divisions
;
8278 if (end_row
< start_row
)
8279 end_row
= start_row
;
8281 *start_row_out
= start_row
;
8282 *end_row_out
= end_row
;
8287 e_day_view_get_event_position (EDayView
*day_view
,
8295 EDayViewEvent
*event
;
8296 gint start_row
, end_row
, cols_in_row
, start_col
, num_columns
;
8298 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
8301 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
8304 /* If the event is flagged as not displayed, return FALSE. */
8305 if (event
->num_columns
== 0)
8308 e_day_view_get_event_rows (day_view
, day
, event_num
, &start_row
, &end_row
);
8310 cols_in_row
= day_view
->cols_per_row
[day
][start_row
];
8311 start_col
= event
->start_row_or_col
;
8312 num_columns
= event
->num_columns
;
8314 if (cols_in_row
== 0)
8317 /* If the event is being resize, use the resize position. */
8318 if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
8319 && day_view
->resize_event_day
== day
8320 && day_view
->resize_event_num
== event_num
) {
8321 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_TOP_EDGE
)
8322 start_row
= day_view
->resize_start_row
;
8323 else if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_BOTTOM_EDGE
)
8324 end_row
= day_view
->resize_end_row
;
8327 *item_x
= day_view
->day_offsets
[day
]
8328 + day_view
->day_widths
[day
] * start_col
/ cols_in_row
;
8329 *item_w
= day_view
->day_widths
[day
] * num_columns
/ cols_in_row
8330 - E_DAY_VIEW_GAP_WIDTH
;
8331 *item_w
= MAX (*item_w
, 0);
8332 *item_y
= start_row
* day_view
->row_height
;
8334 /* This makes the event end on the grid line of the next row,
8335 * which maybe looks nicer if you have 2 events on consecutive rows. */
8336 *item_h
= (end_row
- start_row
+ 1) * day_view
->row_height
+ 1;
8342 e_day_view_get_long_event_position (EDayView
*day_view
,
8351 EDayViewEvent
*event
;
8354 days_shown
= e_day_view_get_days_shown (day_view
);
8356 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
8359 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
8362 /* If the event is flagged as not displayed, return FALSE. */
8363 if (event
->num_columns
== 0)
8366 if (!e_day_view_find_long_event_days (event
,
8368 day_view
->day_starts
,
8369 start_day
, end_day
))
8372 /* If the event is being resize, use the resize position. */
8373 if (day_view
->resize_drag_pos
!= E_CALENDAR_VIEW_POS_NONE
8374 && day_view
->resize_event_day
== E_DAY_VIEW_LONG_EVENT
8375 && day_view
->resize_event_num
== event_num
) {
8376 if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_LEFT_EDGE
)
8377 *start_day
= day_view
->resize_start_row
;
8378 else if (day_view
->resize_drag_pos
== E_CALENDAR_VIEW_POS_RIGHT_EDGE
)
8379 *end_day
= day_view
->resize_end_row
;
8382 *item_x
= day_view
->day_offsets
[*start_day
] + E_DAY_VIEW_BAR_WIDTH
;
8383 if (days_shown
== 1) {
8384 GtkAllocation allocation
;
8386 gtk_widget_get_allocation (day_view
->top_canvas
, &allocation
);
8387 *item_w
= allocation
.width
;
8389 *item_w
= day_view
->day_offsets
[*end_day
+ 1];
8390 *item_w
= MAX (*item_w
- *item_x
- E_DAY_VIEW_GAP_WIDTH
, 0);
8391 *item_y
= (event
->start_row_or_col
) * day_view
->top_row_height
;
8392 *item_h
= day_view
->top_row_height
- E_DAY_VIEW_TOP_CANVAS_Y_GAP
;
8396 /* Converts a position within the entire top canvas to a day & event and
8397 * a place within the event if appropriate. If event_num_return is NULL, it
8398 * simply returns the grid position without trying to find the event. */
8399 static ECalendarViewPosition
8400 e_day_view_convert_position_in_top_canvas (EDayView
*day_view
,
8404 gint
*event_num_return
)
8406 EDayViewEvent
*event
;
8408 gint event_num
, start_day
, end_day
, item_x
, item_y
, item_w
, item_h
;
8411 days_shown
= e_day_view_get_days_shown (day_view
);
8414 if (event_num_return
)
8415 *event_num_return
= -1;
8418 return E_CALENDAR_VIEW_POS_OUTSIDE
;
8420 row
= y
/ day_view
->top_row_height
;
8423 for (col
= 1; col
<= days_shown
; col
++) {
8424 if (x
< day_view
->day_offsets
[col
]) {
8430 return E_CALENDAR_VIEW_POS_OUTSIDE
;
8434 /* If only the grid position is wanted, return. */
8435 if (event_num_return
== NULL
)
8436 return E_CALENDAR_VIEW_POS_NONE
;
8438 for (event_num
= 0; event_num
< day_view
->long_events
->len
;
8440 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
8443 if (event
->start_row_or_col
!= row
)
8446 if (!e_day_view_get_long_event_position (day_view
, event_num
,
8447 &start_day
, &end_day
,
8455 if (x
>= item_x
+ item_w
)
8458 *event_num_return
= event_num
;
8460 if (x
< item_x
+ E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH
8461 + E_DAY_VIEW_LONG_EVENT_X_PAD
)
8462 return E_CALENDAR_VIEW_POS_LEFT_EDGE
;
8464 if (x
>= item_x
+ item_w
- E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH
8465 - E_DAY_VIEW_LONG_EVENT_X_PAD
)
8466 return E_CALENDAR_VIEW_POS_RIGHT_EDGE
;
8468 return E_CALENDAR_VIEW_POS_EVENT
;
8471 return E_CALENDAR_VIEW_POS_NONE
;
8474 /* Converts a position within the entire main canvas to a day, row, event and
8475 * a place within the event if appropriate. If event_num_return is NULL, it
8476 * simply returns the grid position without trying to find the event. */
8477 static ECalendarViewPosition
8478 e_day_view_convert_position_in_main_canvas (EDayView
*day_view
,
8483 gint
*event_num_return
)
8485 gint day
, row
, col
, event_num
;
8486 gint item_x
, item_y
, item_w
, item_h
;
8489 days_shown
= e_day_view_get_days_shown (day_view
);
8493 if (event_num_return
)
8494 *event_num_return
= -1;
8496 /* Check the position is inside the canvas, and determine the day
8499 return E_CALENDAR_VIEW_POS_OUTSIDE
;
8501 row
= y
/ day_view
->row_height
;
8502 if (row
>= day_view
->rows
)
8503 return E_CALENDAR_VIEW_POS_OUTSIDE
;
8506 for (col
= 1; col
<= days_shown
; col
++) {
8507 if (x
< day_view
->day_offsets
[col
]) {
8513 return E_CALENDAR_VIEW_POS_OUTSIDE
;
8518 /* If only the grid position is wanted, return. */
8519 if (event_num_return
== NULL
)
8520 return E_CALENDAR_VIEW_POS_NONE
;
8522 /* Check the selected item first, since the horizontal resizing bars
8523 * may be above other events. */
8524 if (day_view
->resize_bars_event_day
== day
) {
8525 if (e_day_view_get_event_position (day_view
, day
,
8526 day_view
->resize_bars_event_num
,
8528 &item_w
, &item_h
)) {
8529 if (x
>= item_x
&& x
< item_x
+ item_w
) {
8530 *event_num_return
= day_view
->resize_bars_event_num
;
8531 if (y
>= item_y
- E_DAY_VIEW_BAR_HEIGHT
8532 && y
< item_y
+ E_DAY_VIEW_EVENT_BORDER_HEIGHT
)
8533 return E_CALENDAR_VIEW_POS_TOP_EDGE
;
8534 if (y
>= item_y
+ item_h
- E_DAY_VIEW_EVENT_BORDER_HEIGHT
8535 && y
< item_y
+ item_h
+ E_DAY_VIEW_BAR_HEIGHT
)
8536 return E_CALENDAR_VIEW_POS_BOTTOM_EDGE
;
8541 /* Try to find the event at the found position. */
8542 *event_num_return
= -1;
8543 for (event_num
= 0; event_num
< day_view
->events
[day
]->len
;
8545 if (!e_day_view_get_event_position (day_view
, day
, event_num
,
8550 if (x
< item_x
|| x
>= item_x
+ item_w
8551 || y
< item_y
|| y
>= item_y
+ item_h
)
8554 *event_num_return
= event_num
;
8556 if (x
< item_x
+ E_DAY_VIEW_BAR_WIDTH
)
8557 return E_CALENDAR_VIEW_POS_LEFT_EDGE
;
8559 if (y
< item_y
+ E_DAY_VIEW_EVENT_BORDER_HEIGHT
8560 + E_DAY_VIEW_EVENT_Y_PAD
)
8561 return E_CALENDAR_VIEW_POS_TOP_EDGE
;
8563 if (y
>= item_y
+ item_h
- E_DAY_VIEW_EVENT_BORDER_HEIGHT
8564 - E_DAY_VIEW_EVENT_Y_PAD
)
8565 return E_CALENDAR_VIEW_POS_BOTTOM_EDGE
;
8567 return E_CALENDAR_VIEW_POS_EVENT
;
8570 return E_CALENDAR_VIEW_POS_NONE
;
8574 e_day_view_on_top_canvas_drag_motion (GtkWidget
*widget
,
8575 GdkDragContext
*context
,
8581 gint scroll_x
, scroll_y
;
8583 gnome_canvas_get_scroll_offsets (
8584 GNOME_CANVAS (widget
),
8585 &scroll_x
, &scroll_y
);
8586 day_view
->drag_event_x
= x
+ scroll_x
;
8587 day_view
->drag_event_y
= y
+ scroll_y
;
8589 e_day_view_reshape_top_canvas_drag_item (day_view
);
8595 e_day_view_reshape_top_canvas_drag_item (EDayView
*day_view
)
8597 ECalendarViewPosition pos
;
8600 /* Calculate the day & start row of the event being dragged, using
8601 * the current mouse position. */
8602 x
= day_view
->drag_event_x
;
8603 y
= day_view
->drag_event_y
;
8604 pos
= e_day_view_convert_position_in_top_canvas (
8607 /* This shouldn't really happen in a drag. */
8608 if (pos
== E_CALENDAR_VIEW_POS_OUTSIDE
)
8611 if (day_view
->drag_event_day
== E_DAY_VIEW_LONG_EVENT
)
8612 day
-= day_view
->drag_event_offset
;
8615 e_day_view_update_top_canvas_drag (day_view
, day
);
8619 e_day_view_update_top_canvas_drag (EDayView
*day_view
,
8622 EDayViewEvent
*event
= NULL
;
8623 gint row
, num_days
, start_day
, end_day
;
8624 gdouble item_x
, item_y
, item_w
, item_h
;
8628 days_shown
= e_day_view_get_days_shown (day_view
);
8630 /* Calculate the event's position. If the event is in the same
8631 * position we started in, we use the same columns. */
8632 row
= day_view
->rows_in_top_display
+ 1;
8635 if (day_view
->drag_event_day
== E_DAY_VIEW_LONG_EVENT
) {
8636 if (!is_array_index_in_bounds (day_view
->long_events
, day_view
->drag_event_num
))
8639 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
8640 day_view
->drag_event_num
);
8641 row
= event
->start_row_or_col
+ 1;
8643 if (!e_day_view_find_long_event_days (event
,
8645 day_view
->day_starts
,
8646 &start_day
, &end_day
))
8649 num_days
= end_day
- start_day
+ 1;
8651 /* Make sure we don't go off the screen. */
8652 day
= MIN (day
, days_shown
- num_days
);
8654 } else if (day_view
->drag_event_day
!= -1) {
8655 if (!is_array_index_in_bounds (day_view
->events
[day_view
->drag_event_day
], day_view
->drag_event_num
))
8658 event
= &g_array_index (day_view
->events
[day_view
->drag_event_day
],
8660 day_view
->drag_event_num
);
8663 /* If the position hasn't changed, just return. */
8664 if (day_view
->drag_last_day
== day
8665 && (day_view
->drag_long_event_item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
))
8668 day_view
->drag_last_day
= day
;
8670 item_x
= day_view
->day_offsets
[day
] + E_DAY_VIEW_BAR_WIDTH
;
8671 item_w
= day_view
->day_offsets
[day
+ num_days
] - item_x
8672 - E_DAY_VIEW_GAP_WIDTH
;
8673 item_y
= row
* day_view
->top_row_height
;
8674 item_h
= day_view
->top_row_height
- E_DAY_VIEW_TOP_CANVAS_Y_GAP
;
8676 /* Set the positions of the event & associated items. */
8677 gnome_canvas_item_set (
8678 day_view
->drag_long_event_rect_item
,
8681 "x2", item_x
+ item_w
- 1,
8682 "y2", item_y
+ item_h
- 1,
8685 gnome_canvas_item_set (
8686 day_view
->drag_long_event_item
,
8687 "clip_width", item_w
- (E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH
+ E_DAY_VIEW_LONG_EVENT_X_PAD
) * 2,
8688 "clip_height", item_h
- (E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_LONG_EVENT_Y_PAD
) * 2,
8690 e_canvas_item_move_absolute (
8691 day_view
->drag_long_event_item
,
8692 item_x
+ E_DAY_VIEW_LONG_EVENT_BORDER_WIDTH
+ E_DAY_VIEW_LONG_EVENT_X_PAD
,
8693 item_y
+ E_DAY_VIEW_LONG_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_LONG_EVENT_Y_PAD
);
8695 if (!(day_view
->drag_long_event_rect_item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)) {
8696 gnome_canvas_item_raise_to_top (day_view
->drag_long_event_rect_item
);
8697 gnome_canvas_item_show (day_view
->drag_long_event_rect_item
);
8700 /* Set the text, if necessary. We don't want to set the text every
8701 * time it moves, so we check if it is currently invisible and only
8702 * set the text then. */
8703 if (!(day_view
->drag_long_event_item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)) {
8704 const gchar
*summary
;
8706 if (event
&& is_comp_data_valid (event
)) {
8707 summary
= icalcomponent_get_summary (event
->comp_data
->icalcomp
);
8708 text
= g_strdup (summary
);
8713 gnome_canvas_item_set (
8714 day_view
->drag_long_event_item
,
8715 "text", text
? text
: "",
8717 gnome_canvas_item_raise_to_top (day_view
->drag_long_event_item
);
8718 gnome_canvas_item_show (day_view
->drag_long_event_item
);
8725 e_day_view_on_main_canvas_drag_motion (GtkWidget
*widget
,
8726 GdkDragContext
*context
,
8732 gint scroll_x
, scroll_y
;
8734 gnome_canvas_get_scroll_offsets (
8735 GNOME_CANVAS (widget
),
8736 &scroll_x
, &scroll_y
);
8738 day_view
->drag_event_x
= x
+ scroll_x
;
8739 day_view
->drag_event_y
= y
+ scroll_y
;
8741 e_day_view_reshape_main_canvas_drag_item (day_view
);
8742 e_day_view_reshape_main_canvas_resize_bars (day_view
);
8744 e_day_view_check_auto_scroll (day_view
, day_view
->drag_event_x
, day_view
->drag_event_y
);
8750 e_day_view_reshape_main_canvas_drag_item (EDayView
*day_view
)
8752 ECalendarViewPosition pos
;
8753 gint x
, y
, day
, row
;
8755 /* Calculate the day & start row of the event being dragged, using
8756 * the current mouse position. */
8757 x
= day_view
->drag_event_x
;
8758 y
= day_view
->drag_event_y
;
8759 pos
= e_day_view_convert_position_in_main_canvas (
8762 /* This shouldn't really happen in a drag. */
8763 if (pos
== E_CALENDAR_VIEW_POS_OUTSIDE
)
8766 if (day_view
->drag_event_day
!= -1
8767 && day_view
->drag_event_day
!= E_DAY_VIEW_LONG_EVENT
)
8768 row
-= day_view
->drag_event_offset
;
8771 e_day_view_update_main_canvas_drag (day_view
, row
, day
);
8775 e_day_view_update_main_canvas_drag (EDayView
*day_view
,
8779 EDayViewEvent
*event
= NULL
;
8780 ECalendarView
*cal_view
;
8781 gint time_divisions
;
8782 gint cols_in_row
, start_col
, num_columns
, num_rows
, start_row
, end_row
;
8783 gdouble item_x
, item_y
, item_w
, item_h
;
8786 cal_view
= E_CALENDAR_VIEW (day_view
);
8787 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
8789 /* If the position hasn't changed, just return. */
8790 if (day_view
->drag_last_day
== day
8791 && day_view
->drag_last_row
== row
8792 && (day_view
->drag_item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
))
8795 day_view
->drag_last_day
= day
;
8796 day_view
->drag_last_row
= row
;
8798 /* Calculate the event's position. If the event is in the same
8799 * position we started in, we use the same columns. */
8806 if (day_view
->drag_event_day
== E_DAY_VIEW_LONG_EVENT
) {
8807 if (!is_array_index_in_bounds (day_view
->long_events
, day_view
->drag_event_num
))
8810 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
8811 day_view
->drag_event_num
);
8812 } else if (day_view
->drag_event_day
!= -1) {
8813 if (!is_array_index_in_bounds (day_view
->events
[day_view
->drag_event_day
], day_view
->drag_event_num
))
8816 event
= &g_array_index (day_view
->events
[day_view
->drag_event_day
],
8818 day_view
->drag_event_num
);
8819 start_row
= event
->start_minute
/ time_divisions
;
8820 end_row
= (event
->end_minute
- 1) / time_divisions
;
8821 if (end_row
< start_row
)
8822 end_row
= start_row
;
8824 num_rows
= end_row
- start_row
+ 1;
8826 if (day_view
->drag_event_day
== day
&& start_row
== row
) {
8827 cols_in_row
= day_view
->cols_per_row
[day
][row
];
8828 start_col
= event
->start_row_or_col
;
8829 num_columns
= event
->num_columns
;
8833 item_x
= day_view
->day_offsets
[day
]
8834 + day_view
->day_widths
[day
] * start_col
/ cols_in_row
;
8835 item_w
= day_view
->day_widths
[day
] * num_columns
/ cols_in_row
8836 - E_DAY_VIEW_GAP_WIDTH
;
8837 item_y
= row
* day_view
->row_height
;
8838 item_h
= num_rows
* day_view
->row_height
;
8840 /* Set the positions of the event & associated items. */
8841 gnome_canvas_item_set (
8842 day_view
->drag_rect_item
,
8843 "x1", item_x
+ E_DAY_VIEW_BAR_WIDTH
- 1,
8845 "x2", item_x
+ item_w
- 1,
8846 "y2", item_y
+ item_h
- 1,
8849 gnome_canvas_item_set (
8850 day_view
->drag_bar_item
,
8853 "x2", item_x
+ E_DAY_VIEW_BAR_WIDTH
- 1,
8854 "y2", item_y
+ item_h
- 1,
8857 gnome_canvas_item_set (
8858 day_view
->drag_item
,
8859 "clip_width", item_w
- E_DAY_VIEW_BAR_WIDTH
- E_DAY_VIEW_EVENT_X_PAD
* 2,
8860 "clip_height", item_h
- (E_DAY_VIEW_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_EVENT_Y_PAD
) * 2,
8862 e_canvas_item_move_absolute (
8863 day_view
->drag_item
,
8864 item_x
+ E_DAY_VIEW_BAR_WIDTH
+ E_DAY_VIEW_EVENT_X_PAD
,
8865 item_y
+ E_DAY_VIEW_EVENT_BORDER_HEIGHT
+ E_DAY_VIEW_EVENT_Y_PAD
);
8867 if (!(day_view
->drag_bar_item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)) {
8868 gnome_canvas_item_raise_to_top (day_view
->drag_bar_item
);
8869 gnome_canvas_item_show (day_view
->drag_bar_item
);
8872 if (!(day_view
->drag_rect_item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)) {
8873 gnome_canvas_item_raise_to_top (day_view
->drag_rect_item
);
8874 gnome_canvas_item_show (day_view
->drag_rect_item
);
8877 /* Set the text, if necessary. We don't want to set the text every
8878 * time it moves, so we check if it is currently invisible and only
8879 * set the text then. */
8880 if (!(day_view
->drag_item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)) {
8881 const gchar
*summary
;
8883 if (event
&& is_comp_data_valid (event
)) {
8884 summary
= icalcomponent_get_summary (event
->comp_data
->icalcomp
);
8885 text
= g_strdup (summary
);
8890 gnome_canvas_item_set (
8891 day_view
->drag_item
,
8892 "text", text
? text
: "",
8894 gnome_canvas_item_raise_to_top (day_view
->drag_item
);
8895 gnome_canvas_item_show (day_view
->drag_item
);
8902 e_day_view_on_top_canvas_drag_leave (GtkWidget
*widget
,
8903 GdkDragContext
*context
,
8907 day_view
->drag_last_day
= -1;
8909 gnome_canvas_item_hide (day_view
->drag_long_event_rect_item
);
8910 gnome_canvas_item_hide (day_view
->drag_long_event_item
);
8914 e_day_view_on_main_canvas_drag_leave (GtkWidget
*widget
,
8915 GdkDragContext
*context
,
8919 day_view
->drag_last_day
= -1;
8921 e_day_view_stop_auto_scroll (day_view
);
8923 gnome_canvas_item_hide (day_view
->drag_rect_item
);
8924 gnome_canvas_item_hide (day_view
->drag_bar_item
);
8925 gnome_canvas_item_hide (day_view
->drag_item
);
8927 /* Hide the resize bars if they are being used in the drag. */
8928 if (day_view
->drag_event_day
== day_view
->resize_bars_event_day
8929 && day_view
->drag_event_num
== day_view
->resize_bars_event_num
) {
8934 e_day_view_on_drag_begin (GtkWidget
*widget
,
8935 GdkDragContext
*context
,
8938 EDayViewEvent
*event
;
8939 gint day
, event_num
;
8941 day
= day_view
->drag_event_day
;
8942 event_num
= day_view
->drag_event_num
;
8944 /* These should both be set. */
8946 g_warn_if_reached ();
8950 g_return_if_fail (event_num
!= -1);
8952 if (day
== E_DAY_VIEW_LONG_EVENT
) {
8953 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
8956 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
8959 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
8962 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
8966 /* Hide the text item, since it will be shown in the special drag
8968 gnome_canvas_item_hide (event
->canvas_item
);
8972 e_day_view_on_drag_end (GtkWidget
*widget
,
8973 GdkDragContext
*context
,
8976 EDayViewEvent
*event
;
8977 gint day
, event_num
;
8979 day
= day_view
->drag_event_day
;
8980 event_num
= day_view
->drag_event_num
;
8982 /* If the calendar has already been updated in drag_data_received()
8983 * we just return. */
8984 if (day
== -1 || event_num
== -1)
8987 if (day
== E_DAY_VIEW_LONG_EVENT
) {
8988 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
8991 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
8993 gtk_widget_queue_draw (day_view
->top_canvas
);
8995 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
8998 event
= &g_array_index (day_view
->events
[day
], EDayViewEvent
,
9000 gtk_widget_queue_draw (day_view
->main_canvas
);
9003 /* Show the text item again. */
9004 gnome_canvas_item_show (event
->canvas_item
);
9006 day_view
->drag_event_day
= -1;
9007 day_view
->drag_event_num
= -1;
9008 g_clear_object (&day_view
->priv
->drag_context
);
9012 e_day_view_on_drag_data_get (GtkWidget
*widget
,
9013 GdkDragContext
*context
,
9014 GtkSelectionData
*selection_data
,
9019 EDayViewEvent
*event
;
9020 icalcomponent
*vcal
;
9021 gint day
, event_num
;
9024 day
= day_view
->drag_event_day
;
9025 event_num
= day_view
->drag_event_num
;
9027 /* These should both be set. */
9029 g_warn_if_reached ();
9033 g_return_if_fail (event_num
!= -1);
9035 if (day
== E_DAY_VIEW_LONG_EVENT
) {
9036 if (!is_array_index_in_bounds (day_view
->long_events
, event_num
))
9039 event
= &g_array_index (day_view
->long_events
,
9040 EDayViewEvent
, event_num
);
9042 if (!is_array_index_in_bounds (day_view
->events
[day
], event_num
))
9045 event
= &g_array_index (day_view
->events
[day
],
9046 EDayViewEvent
, event_num
);
9049 if (!is_comp_data_valid (event
))
9052 vcal
= e_cal_util_new_top_level ();
9053 e_cal_util_add_timezones_from_component (
9054 vcal
, event
->comp_data
->icalcomp
);
9055 icalcomponent_add_component (
9056 vcal
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
9058 comp_str
= icalcomponent_as_ical_string_r (vcal
);
9061 const gchar
*source_uid
;
9065 source
= e_client_get_source (E_CLIENT (event
->comp_data
->client
));
9066 source_uid
= e_source_get_uid (source
);
9068 tmp
= g_strconcat (source_uid
, "\n", comp_str
, NULL
);
9069 target
= gtk_selection_data_get_target (selection_data
);
9070 gtk_selection_data_set (
9071 selection_data
, target
, 8,
9072 (guchar
*) tmp
, strlen (tmp
));
9077 icalcomponent_free (vcal
);
9082 e_day_view_on_top_canvas_drag_data_received (GtkWidget
*widget
,
9083 GdkDragContext
*context
,
9086 GtkSelectionData
*selection_data
,
9091 EDayViewEvent
*event
= NULL
;
9092 ECalendarViewPosition pos
;
9093 gint day
, start_day
, end_day
, num_days
;
9094 gint start_offset
, end_offset
;
9095 ECalComponent
*comp
;
9096 ECalComponentDateTime date
;
9097 ESourceRegistry
*registry
;
9098 struct icaltimetype itt
;
9100 gboolean all_day_event
;
9102 ECalendarView
*cal_view
;
9103 gboolean drag_from_same_window
;
9105 gint format
, length
;
9107 GtkResponseType send
= GTK_RESPONSE_NO
;
9108 gboolean only_new_attendees
= FALSE
;
9109 gboolean strip_alarms
= TRUE
;
9111 data
= gtk_selection_data_get_data (selection_data
);
9112 format
= gtk_selection_data_get_format (selection_data
);
9113 length
= gtk_selection_data_get_length (selection_data
);
9115 days_shown
= e_day_view_get_days_shown (day_view
);
9117 if (day_view
->drag_event_day
!= -1)
9118 drag_from_same_window
= TRUE
;
9120 drag_from_same_window
= FALSE
;
9122 cal_view
= E_CALENDAR_VIEW (day_view
);
9123 model
= e_calendar_view_get_model (cal_view
);
9125 registry
= e_cal_model_get_registry (model
);
9127 /* Note that we only support DnD within the EDayView at present. */
9128 if (length
>= 0 && format
== 8 && day_view
->drag_event_day
!= -1) {
9129 /* We are dragging in the same window */
9131 pos
= e_day_view_convert_position_in_top_canvas (
9135 if (pos
!= E_CALENDAR_VIEW_POS_OUTSIDE
) {
9136 ECalObjModType mod
= E_CAL_OBJ_MOD_ALL
;
9138 GtkWindow
*toplevel
;
9144 if (day_view
->drag_event_day
== E_DAY_VIEW_LONG_EVENT
) {
9145 if (!is_array_index_in_bounds (day_view
->long_events
, day_view
->drag_event_num
))
9148 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
9149 day_view
->drag_event_num
);
9151 if (!is_comp_data_valid (event
))
9154 day
-= day_view
->drag_event_offset
;
9157 e_day_view_find_long_event_days (
9160 day_view
->day_starts
,
9163 num_days
= end_day
- start_day
+ 1;
9164 /* Make sure we don't go off the screen. */
9165 day
= MIN (day
, days_shown
- num_days
);
9167 start_offset
= event
->start_minute
;
9168 end_offset
= event
->end_minute
;
9170 if (!is_array_index_in_bounds (day_view
->events
[day_view
->drag_event_day
], day_view
->drag_event_num
))
9173 event
= &g_array_index (day_view
->events
[day_view
->drag_event_day
],
9175 day_view
->drag_event_num
);
9177 if (!is_comp_data_valid (event
))
9181 client
= event
->comp_data
->client
;
9183 /* We clone the event since we don't want to change
9184 * the original comp here.
9185 * Otherwise we would not detect that the event's time
9186 * had changed in the "update_event" callback. */
9188 comp
= e_cal_component_new ();
9189 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
9191 if (e_cal_component_has_attendees (comp
) &&
9192 !itip_organizer_is_user (registry
, comp
, client
)) {
9193 g_object_unref (comp
);
9197 toplevel
= GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view
)));
9199 if (itip_has_any_attendees (comp
) &&
9200 (itip_organizer_is_user (registry
, comp
, client
) ||
9201 itip_sentby_is_user (registry
, comp
, client
)))
9202 send
= e_cal_dialogs_send_dragged_or_resized_component (
9203 toplevel
, client
, comp
, &strip_alarms
, &only_new_attendees
);
9205 if (send
== GTK_RESPONSE_CANCEL
) {
9206 e_day_view_abort_resize (day_view
);
9207 g_object_unref (comp
);
9211 if (start_offset
== 0 && end_offset
== 0)
9212 all_day_event
= TRUE
;
9214 all_day_event
= FALSE
;
9218 dt
= day_view
->day_starts
[day
] + start_offset
* 60;
9219 itt
= icaltime_from_timet_with_zone (
9221 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
9222 if (all_day_event
) {
9226 /* FIXME: Should probably keep the timezone of
9227 * the original start and end times. */
9228 date
.tzid
= icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
9230 cal_comp_set_dtstart_with_oldzone (client
, comp
, &date
);
9232 if (end_offset
== 0)
9233 dt
= day_view
->day_starts
[day
+ num_days
];
9235 dt
= day_view
->day_starts
[day
+ num_days
- 1] + end_offset
* 60;
9236 itt
= icaltime_from_timet_with_zone (
9238 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
9239 if (all_day_event
) {
9243 /* FIXME: Should probably keep the timezone of
9244 * the original start and end times. */
9245 date
.tzid
= icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
9247 cal_comp_set_dtend_with_oldzone (client
, comp
, &date
);
9249 gtk_drag_finish (context
, TRUE
, TRUE
, time
);
9251 /* Reset this since it will be invalid. */
9252 day_view
->drag_event_day
= -1;
9253 g_clear_object (&day_view
->priv
->drag_context
);
9255 /* Show the text item again, just in case it hasn't
9256 * moved. If we don't do this it may not appear. */
9257 if (event
->canvas_item
)
9258 gnome_canvas_item_show (event
->canvas_item
);
9260 e_cal_component_commit_sequence (comp
);
9261 if (e_cal_component_has_recurrences (comp
)) {
9262 if (!e_cal_dialogs_recur_component (client
, comp
, &mod
, NULL
, FALSE
)) {
9263 gtk_widget_queue_draw (day_view
->top_canvas
);
9264 g_object_unref (comp
);
9268 if (mod
== E_CAL_OBJ_MOD_THIS
) {
9269 e_cal_component_set_rdate_list (comp
, NULL
);
9270 e_cal_component_set_rrule_list (comp
, NULL
);
9271 e_cal_component_set_exdate_list (comp
, NULL
);
9272 e_cal_component_set_exrule_list (comp
, NULL
);
9274 } else if (e_cal_component_is_instance (comp
))
9275 mod
= E_CAL_OBJ_MOD_THIS
;
9277 e_cal_component_commit_sequence (comp
);
9279 e_cal_ops_modify_component (model
, client
, e_cal_component_get_icalcomponent (comp
), mod
,
9280 (send
== GTK_RESPONSE_YES
? E_CAL_OPS_SEND_FLAG_SEND
: E_CAL_OPS_SEND_FLAG_DONT_SEND
) |
9281 (strip_alarms
? E_CAL_OPS_SEND_FLAG_STRIP_ALARMS
: 0) |
9282 (only_new_attendees
? E_CAL_OPS_SEND_FLAG_ONLY_NEW_ATTENDEES
: 0));
9284 g_object_unref (comp
);
9290 if (length
>= 0 && format
== 8 && !drag_from_same_window
) {
9291 /* We are dragging between different window */
9292 icalcomponent
*icalcomp
;
9293 icalcomponent_kind kind
;
9295 pos
= e_day_view_convert_position_in_top_canvas (
9299 if (pos
== E_CALENDAR_VIEW_POS_OUTSIDE
)
9302 icalcomp
= icalparser_parse_string ((const gchar
*) data
);
9306 /* check the type of the component */
9307 kind
= icalcomponent_isa (icalcomp
);
9308 icalcomponent_free (icalcomp
);
9310 if (kind
!= ICAL_VCALENDAR_COMPONENT
&& kind
!= ICAL_VEVENT_COMPONENT
)
9313 e_cal_ops_paste_components (model
, (const gchar
*) data
);
9315 gtk_drag_finish (context
, TRUE
, TRUE
, time
);
9320 gtk_drag_finish (context
, FALSE
, FALSE
, time
);
9324 e_day_view_on_main_canvas_drag_data_received (GtkWidget
*widget
,
9325 GdkDragContext
*context
,
9328 GtkSelectionData
*selection_data
,
9333 ECalendarView
*cal_view
;
9334 EDayViewEvent
*event
= NULL
;
9335 ECalendarViewPosition pos
;
9336 gint time_divisions
;
9337 gint day
, row
, start_row
, end_row
, num_rows
, scroll_x
, scroll_y
;
9338 gint start_offset
, end_offset
;
9340 ECalComponent
*comp
;
9341 ECalComponentDateTime date
;
9342 ESourceRegistry
*registry
;
9343 struct icaltimetype itt
;
9345 gboolean drag_from_same_window
;
9347 gint format
, length
;
9348 GtkResponseType send
= GTK_RESPONSE_NO
;
9349 gboolean only_new_attendees
= FALSE
;
9350 gboolean strip_alarms
= TRUE
;
9352 cal_view
= E_CALENDAR_VIEW (day_view
);
9353 model
= e_calendar_view_get_model (cal_view
);
9354 time_divisions
= e_calendar_view_get_time_divisions (cal_view
);
9356 registry
= e_cal_model_get_registry (model
);
9358 data
= gtk_selection_data_get_data (selection_data
);
9359 format
= gtk_selection_data_get_format (selection_data
);
9360 length
= gtk_selection_data_get_length (selection_data
);
9362 if (day_view
->drag_event_day
!= -1)
9363 drag_from_same_window
= TRUE
;
9365 drag_from_same_window
= FALSE
;
9367 gnome_canvas_get_scroll_offsets (
9368 GNOME_CANVAS (widget
),
9369 &scroll_x
, &scroll_y
);
9373 /* Note that we only support DnD within the EDayView at present. */
9374 if (length
>= 0 && format
== 8 && (day_view
->drag_event_day
!= -1)) {
9375 /* We are dragging in the same window */
9377 pos
= e_day_view_convert_position_in_main_canvas (
9381 if (pos
!= E_CALENDAR_VIEW_POS_OUTSIDE
) {
9382 ECalObjModType mod
= E_CAL_OBJ_MOD_ALL
;
9384 GtkWindow
*toplevel
;
9390 if (day_view
->drag_event_day
== E_DAY_VIEW_LONG_EVENT
) {
9391 if (!is_array_index_in_bounds (day_view
->long_events
, day_view
->drag_event_num
))
9394 event
= &g_array_index (day_view
->long_events
, EDayViewEvent
,
9395 day_view
->drag_event_num
);
9397 if (!is_comp_data_valid (event
))
9400 if (!is_array_index_in_bounds (day_view
->events
[day_view
->drag_event_day
], day_view
->drag_event_num
))
9403 event
= &g_array_index (day_view
->events
[day_view
->drag_event_day
],
9405 day_view
->drag_event_num
);
9407 if (!is_comp_data_valid (event
))
9410 row
-= day_view
->drag_event_offset
;
9412 /* Calculate time offset from start row. */
9413 start_row
= event
->start_minute
/ time_divisions
;
9414 end_row
= (event
->end_minute
- 1) / time_divisions
;
9415 if (end_row
< start_row
)
9416 end_row
= start_row
;
9418 num_rows
= end_row
- start_row
+ 1;
9420 start_offset
= event
->start_minute
% time_divisions
;
9421 end_offset
= event
->end_minute
% time_divisions
;
9422 if (end_offset
!= 0)
9423 end_offset
= time_divisions
- end_offset
;
9426 client
= event
->comp_data
->client
;
9428 /* We use a temporary shallow copy of comp since we
9429 * don't want to change the original comp here.
9430 * Otherwise we would not detect that the event's time
9431 * had changed in the "update_event" callback. */
9432 comp
= e_cal_component_new ();
9433 e_cal_component_set_icalcomponent (comp
, icalcomponent_new_clone (event
->comp_data
->icalcomp
));
9435 if (e_cal_component_has_attendees (comp
) &&
9436 !itip_organizer_is_user (registry
, comp
, client
)) {
9437 g_object_unref (comp
);
9441 toplevel
= GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view
)));
9443 if (itip_has_any_attendees (comp
) &&
9444 (itip_organizer_is_user (registry
, comp
, client
) ||
9445 itip_sentby_is_user (registry
, comp
, client
)))
9446 send
= e_cal_dialogs_send_dragged_or_resized_component (
9447 toplevel
, client
, comp
, &strip_alarms
, &only_new_attendees
);
9449 if (send
== GTK_RESPONSE_CANCEL
) {
9450 e_day_view_abort_resize (day_view
);
9451 g_object_unref (comp
);
9456 date
.tzid
= icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
9458 dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, row
) + start_offset
* 60;
9459 *date
.value
= icaltime_from_timet_with_zone (dt
, FALSE
,
9460 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
9461 cal_comp_set_dtstart_with_oldzone (client
, comp
, &date
);
9462 dt
= e_day_view_convert_grid_position_to_time (day_view
, day
, row
+ num_rows
) - end_offset
* 60;
9463 *date
.value
= icaltime_from_timet_with_zone (dt
, FALSE
,
9464 e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view
)));
9465 cal_comp_set_dtend_with_oldzone (client
, comp
, &date
);
9466 e_cal_component_abort_sequence (comp
);
9468 gtk_drag_finish (context
, TRUE
, TRUE
, time
);
9470 /* Reset this since it will be invalid. */
9471 day_view
->drag_event_day
= -1;
9472 g_clear_object (&day_view
->priv
->drag_context
);
9474 /* Show the text item again, just in case it hasn't
9475 * moved. If we don't do this it may not appear. */
9476 if (event
->canvas_item
)
9477 gnome_canvas_item_show (event
->canvas_item
);
9479 e_cal_component_commit_sequence (comp
);
9480 if (e_cal_component_has_recurrences (comp
)) {
9481 if (!e_cal_dialogs_recur_component (client
, comp
, &mod
, NULL
, FALSE
)) {
9482 gtk_widget_queue_draw (day_view
->main_canvas
);
9483 g_object_unref (comp
);
9487 if (mod
== E_CAL_OBJ_MOD_THIS
) {
9488 e_cal_component_set_rdate_list (comp
, NULL
);
9489 e_cal_component_set_rrule_list (comp
, NULL
);
9490 e_cal_component_set_exdate_list (comp
, NULL
);
9491 e_cal_component_set_exrule_list (comp
, NULL
);
9493 } else if (e_cal_component_is_instance (comp
))
9494 mod
= E_CAL_OBJ_MOD_THIS
;
9496 e_cal_component_commit_sequence (comp
);
9498 e_cal_ops_modify_component (model
, client
, e_cal_component_get_icalcomponent (comp
), mod
,
9499 (send
== GTK_RESPONSE_YES
? E_CAL_OPS_SEND_FLAG_SEND
: E_CAL_OPS_SEND_FLAG_DONT_SEND
) |
9500 (strip_alarms
? E_CAL_OPS_SEND_FLAG_STRIP_ALARMS
: 0) |
9501 (only_new_attendees
? E_CAL_OPS_SEND_FLAG_ONLY_NEW_ATTENDEES
: 0));
9503 g_object_unref (comp
);
9509 if (length
>= 0 && format
== 8 && !drag_from_same_window
) {
9510 /* We are dragging between different window */
9511 icalcomponent
*icalcomp
;
9512 icalcomponent_kind kind
;
9514 pos
= e_day_view_convert_position_in_main_canvas (
9518 if (pos
== E_CALENDAR_VIEW_POS_OUTSIDE
)
9521 icalcomp
= icalparser_parse_string ((const gchar
*) data
);
9525 /* check the type of the component */
9526 kind
= icalcomponent_isa (icalcomp
);
9527 icalcomponent_free (icalcomp
);
9529 if (kind
!= ICAL_VCALENDAR_COMPONENT
&& kind
!= ICAL_VEVENT_COMPONENT
)
9532 e_cal_ops_paste_components (model
, (const gchar
*) data
);
9534 gtk_drag_finish (context
, TRUE
, TRUE
, time
);
9539 gtk_drag_finish (context
, FALSE
, FALSE
, time
);
9542 /* Converts an hour from 0-23 to the preferred time format, and returns the
9543 * suffix to add and the width of it in the normal font. */
9545 e_day_view_convert_time_to_display (EDayView
*day_view
,
9548 const gchar
**suffix
,
9553 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
9555 /* Calculate the actual hour number to display. For 12-hour
9556 * format we convert 0-23 to 12-11am/12-11pm. */
9557 *display_hour
= hour
;
9558 if (e_cal_model_get_use_24_hour_format (model
)) {
9563 *suffix
= day_view
->am_string
;
9564 *suffix_width
= day_view
->am_string_width
;
9566 *display_hour
-= 12;
9567 *suffix
= day_view
->pm_string
;
9568 *suffix_width
= day_view
->pm_string_width
;
9571 /* 12-hour uses 12:00 rather than 0:00. */
9572 if (*display_hour
== 0)
9578 e_day_view_get_time_string_width (EDayView
*day_view
)
9583 model
= e_calendar_view_get_model (E_CALENDAR_VIEW (day_view
));
9584 time_width
= day_view
->digit_width
* 4 + day_view
->colon_width
;
9586 if (!e_cal_model_get_use_24_hour_format (model
))
9587 time_width
+= MAX (day_view
->am_string_width
,
9588 day_view
->pm_string_width
);
9593 /* Queues a layout, unless one is already queued. */
9595 e_day_view_queue_layout (EDayView
*day_view
)
9597 if (day_view
->layout_timeout_id
== 0) {
9598 day_view
->layout_timeout_id
= e_named_timeout_add (
9599 E_DAY_VIEW_LAYOUT_TIMEOUT
,
9600 e_day_view_layout_timeout_cb
, day_view
);
9604 /* Removes any queued layout. */
9606 e_day_view_cancel_layout (EDayView
*day_view
)
9608 if (day_view
->layout_timeout_id
!= 0) {
9609 g_source_remove (day_view
->layout_timeout_id
);
9610 day_view
->layout_timeout_id
= 0;
9615 e_day_view_layout_timeout_cb (gpointer data
)
9617 EDayView
*day_view
= E_DAY_VIEW (data
);
9619 gtk_widget_queue_draw (day_view
->top_canvas
);
9620 gtk_widget_queue_draw (day_view
->top_dates_canvas
);
9621 gtk_widget_queue_draw (day_view
->main_canvas
);
9622 e_day_view_check_layout (day_view
);
9624 day_view
->layout_timeout_id
= 0;
9628 /* Returns the number of selected events (0 or 1 at present). */
9630 e_day_view_get_num_events_selected (EDayView
*day_view
)
9632 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), 0);
9634 return (day_view
->editing_event_day
!= -1) ? 1 : 0;
9638 e_day_view_is_editing (EDayView
*day_view
)
9640 g_return_val_if_fail (E_IS_DAY_VIEW (day_view
), FALSE
);
9642 return day_view
->editing_event_day
!= -1;
9646 day_view_update_timezone_name_label (GtkWidget
*label
,
9649 const gchar
*location
, *dash
;
9652 g_return_if_fail (GTK_IS_LABEL (label
));
9657 location
= icaltimezone_get_location (zone
);
9658 if (location
&& *location
)
9659 location
= _(location
);
9660 if (!location
|| !*location
)
9661 location
= icaltimezone_get_tzid (zone
);
9667 gtk_widget_set_tooltip_text (label
, location
);
9669 dash
= strchr (location
, '/');
9670 if (dash
&& *dash
&& dash
[1])
9671 location
= dash
+ 1;
9673 markup
= g_markup_printf_escaped ("<small>%s</small>", location
);
9674 gtk_label_set_markup (GTK_LABEL (label
), markup
);
9679 e_day_view_update_timezone_name_labels (EDayView
*day_view
)
9683 g_return_if_fail (E_IS_DAY_VIEW (day_view
));
9685 zone
= e_cal_model_get_timezone (day_view
->priv
->model
);
9686 day_view_update_timezone_name_label (day_view
->priv
->timezone_name_1_label
, zone
);
9688 zone
= e_day_view_time_item_get_second_zone (E_DAY_VIEW_TIME_ITEM (day_view
->time_canvas_item
));
9690 gtk_widget_hide (day_view
->priv
->timezone_name_2_label
);
9692 day_view_update_timezone_name_label (day_view
->priv
->timezone_name_2_label
, zone
);
9693 gtk_widget_show (day_view
->priv
->timezone_name_2_label
);