aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/gui/e-week-view.c
diff options
context:
space:
mode:
Diffstat (limited to 'calendar/gui/e-week-view.c')
-rw-r--r--calendar/gui/e-week-view.c430
1 files changed, 316 insertions, 114 deletions
diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c
index 61703486a4..14ed7f72c6 100644
--- a/calendar/gui/e-week-view.c
+++ b/calendar/gui/e-week-view.c
@@ -123,7 +123,7 @@ static GList *e_week_view_get_selected_events (ECalendarView *cal_view);
static gboolean e_week_view_get_selected_time_range (ECalendarView *cal_view, time_t *start_time, time_t *end_time);
static void e_week_view_set_selected_time_range (ECalendarView *cal_view, time_t start_time, time_t end_time);
static gboolean e_week_view_get_visible_time_range (ECalendarView *cal_view, time_t *start_time, time_t *end_time);
-static void e_week_view_update_query (ECalendarView *cal_view);
+static void e_week_view_update_query (EWeekView *week_view);
static void e_week_view_draw_shadow (EWeekView *week_view);
static gboolean e_week_view_on_button_press (GtkWidget *widget,
@@ -169,7 +169,9 @@ static gboolean e_week_view_find_event_from_uid (EWeekView *week_view,
typedef gboolean (* EWeekViewForeachEventCallback) (EWeekView *week_view,
gint event_num,
gpointer data);
-
+static void e_week_view_foreach_event (EWeekView *week_view,
+ EWeekViewForeachEventCallback callback,
+ gpointer data);
static void e_week_view_foreach_event_with_uid (EWeekView *week_view,
const gchar *uid,
EWeekViewForeachEventCallback callback,
@@ -242,7 +244,6 @@ e_week_view_class_init (EWeekViewClass *class)
view_class->get_selected_time_range = e_week_view_get_selected_time_range;
view_class->set_selected_time_range = e_week_view_set_selected_time_range;
view_class->get_visible_time_range = e_week_view_get_visible_time_range;
- view_class->update_query = e_week_view_update_query;
view_class->event_move = e_week_view_event_move;
/* init the accessibility support for e_week_view */
@@ -250,13 +251,272 @@ e_week_view_class_init (EWeekViewClass *class)
}
static void
+time_range_changed_cb (ECalModel *model, time_t start_time, time_t end_time, gpointer user_data)
+{
+ EWeekView *week_view = E_WEEK_VIEW (user_data);
+ GDate date, base_date, end_date;
+ gint day_offset, weekday, week_start_offset, num_days;
+ gboolean update_adjustment_value = FALSE;
+
+ g_return_if_fail (E_IS_WEEK_VIEW (week_view));
+
+ time_to_gdate_with_zone (&date, start_time, e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
+
+ if (week_view->multi_week_view) {
+ /* Find the number of days since the start of the month. */
+ day_offset = g_date_day (&date) - 1;
+
+ /* Find the 1st week which starts at or before the start of
+ the month. */
+ base_date = date;
+ g_date_set_day (&base_date, 1);
+
+ /* Calculate the weekday of the 1st of the month, 0 = Mon. */
+ weekday = g_date_weekday (&base_date) - 1;
+
+ /* Convert it to an offset from the start of the display. */
+ week_start_offset = (weekday + 7 - week_view->display_start_day) % 7;
+
+ /* Add it to the day offset so we go back to the 1st week at
+ or before the start of the month. */
+ day_offset += week_start_offset;
+ } else {
+ /* Calculate the weekday of the given date, 0 = Mon. */
+ weekday = g_date_weekday (&date) - 1;
+
+ /* Convert it to an offset from the start of the display. */
+ week_start_offset = (weekday + 7 - week_view->display_start_day) % 7;
+
+ /* Set the day_offset to the result, so we move back to the
+ start of the week. */
+ day_offset = week_start_offset;
+ }
+
+ /* Calculate the base date, i.e. the first day shown when the
+ scrollbar adjustment value is 0. */
+ base_date = date;
+ g_date_subtract_days (&base_date, day_offset);
+
+ /* See if we need to update the base date. */
+ if (!g_date_valid (&week_view->base_date)
+ || g_date_compare (&week_view->base_date, &base_date)) {
+ week_view->base_date = base_date;
+ update_adjustment_value = TRUE;
+ }
+
+ /* See if we need to update the first day shown. */
+ if (!g_date_valid (&week_view->first_day_shown)
+ || g_date_compare (&week_view->first_day_shown, &base_date)) {
+ week_view->first_day_shown = base_date;
+ start_time = time_add_day_with_zone (start_time, -day_offset,
+ e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
+ start_time = time_day_begin_with_zone (start_time,
+ e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
+ e_week_view_recalc_day_starts (week_view, start_time);
+ }
+
+ /* Reset the adjustment value to 0 if the base address has changed.
+ Note that we do this after updating first_day_shown so that our
+ signal handler will not try to reload the events. */
+ if (update_adjustment_value)
+ gtk_adjustment_set_value (GTK_RANGE (week_view->vscrollbar)->adjustment, 0);
+
+ gtk_widget_queue_draw (week_view->main_canvas);
+
+ /* FIXME Only select one day */
+ e_week_view_set_selected_time_range (E_CALENDAR_VIEW (week_view), start_time, end_time);
+}
+
+
+static void
+process_component (EWeekView *week_view, ECalModelComponent *comp_data)
+{
+ EWeekViewEvent *event;
+ gint event_num, num_days;
+ ECalComponent *comp = NULL;
+ AddEventData add_event_data;
+ const char *uid;
+
+ /* If we don't have a valid date set yet, just return. */
+ if (!g_date_valid (&week_view->first_day_shown))
+ return;
+
+ comp = e_cal_component_new ();
+ if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp))) {
+ g_object_unref (comp);
+
+ g_message ("process_component(): Could not set icalcomponent on ECalComponent");
+ return;
+ }
+
+ e_cal_component_get_uid (comp, &uid);
+
+ /* If the event already exists and the dates didn't change, we can
+ update the event fairly easily without changing the events arrays
+ or computing a new layout. */
+ if (e_week_view_find_event_from_uid (week_view, uid, &event_num)) {
+ ECalComponent *tmp_comp;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent,
+ event_num);
+
+ tmp_comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (tmp_comp, icalcomponent_new_clone (comp_data->icalcomp));
+ if (!e_cal_component_has_recurrences (comp)
+ && !e_cal_component_has_recurrences (tmp_comp)
+ && e_cal_component_event_dates_match (comp, tmp_comp)) {
+#if 0
+ g_print ("updated object's dates unchanged\n");
+#endif
+ e_week_view_foreach_event_with_uid (week_view, uid, e_week_view_update_event_cb, comp_data);
+ g_object_unref (comp);
+ g_object_unref (tmp_comp);
+ gtk_widget_queue_draw (week_view->main_canvas);
+ return;
+ }
+
+ /* The dates have changed, so we need to remove the
+ old occurrrences before adding the new ones. */
+#if 0
+ g_print ("dates changed - removing occurrences\n");
+#endif
+ e_week_view_foreach_event_with_uid (week_view, uid,
+ e_week_view_remove_event_cb,
+ NULL);
+
+ g_object_unref (tmp_comp);
+ }
+
+ /* Add the occurrences of the event */
+ num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7;
+
+ add_event_data.week_view = week_view;
+ add_event_data.comp_data = comp_data;
+ e_cal_recur_generate_instances (comp,
+ week_view->day_starts[0],
+ week_view->day_starts[num_days],
+ e_week_view_add_event, &add_event_data,
+ e_cal_resolve_tzid_cb, comp_data->client,
+ e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
+
+ g_object_unref (comp);
+
+ e_week_view_queue_layout (week_view);
+}
+
+static void
+model_changed_cb (ETableModel *etm, gpointer user_data)
+{
+ EWeekView *week_view = E_WEEK_VIEW (user_data);
+
+ e_week_view_update_query (week_view);
+}
+
+static void
+update_row (EWeekView *week_view, int row)
+{
+ ECalModelComponent *comp_data;
+ ECalModel *model;
+
+ model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
+ comp_data = e_cal_model_get_component_at (model, row);
+ g_assert (comp_data != NULL);
+ process_component (week_view, comp_data);
+
+ gtk_widget_queue_draw (week_view->main_canvas);
+ e_week_view_queue_layout (week_view);
+}
+
+static void
+model_row_changed_cb (ETableModel *etm, int row, gpointer user_data)
+{
+ EWeekView *week_view = E_WEEK_VIEW (user_data);
+
+ update_row (week_view, row);
+}
+
+static void
+model_cell_changed_cb (ETableModel *etm, int col, int row, gpointer user_data)
+{
+ EWeekView *week_view = E_WEEK_VIEW (user_data);
+
+ update_row (week_view, row);
+}
+
+static void
+model_rows_inserted_cb (ETableModel *etm, int row, int count, gpointer user_data)
+{
+ EWeekView *week_view = E_WEEK_VIEW (user_data);
+ ECalModel *model;
+ int i;
+
+ model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
+ for (i = 0; i < count; i++) {
+ ECalModelComponent *comp_data;
+
+ comp_data = e_cal_model_get_component_at (model, row + i);
+ g_assert (comp_data != NULL);
+ process_component (week_view, comp_data);
+ }
+
+ gtk_widget_queue_draw (week_view->main_canvas);
+ e_week_view_queue_layout (week_view);
+}
+
+static gboolean
+row_deleted_check_cb (EWeekView *week_view, gint event_num, gpointer data)
+{
+ GHashTable *uids = data;
+ EWeekViewEvent *event;
+ ECalModel *model;
+ const char *uid;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent, event_num);
+ uid = icalcomponent_get_uid (event->comp_data->icalcomp);
+ model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
+
+ if (!e_cal_model_get_component_for_uid (model, uid))
+ g_hash_table_insert (uids, (char *)uid, GINT_TO_POINTER (1));
+
+ return TRUE;
+}
+
+static void
+remove_uid_cb (gpointer key, gpointer value, gpointer data)
+{
+ EWeekView *week_view = data;
+ const char *uid = key;
+
+ e_week_view_foreach_event_with_uid (week_view, uid, e_week_view_remove_event_cb, NULL);
+}
+
+static void
+model_rows_deleted_cb (ETableModel *etm, int row, int count, gpointer user_data)
+{
+ EWeekView *week_view = E_WEEK_VIEW (user_data);
+ GHashTable *uids;
+
+ /* FIXME Stop editing? */
+
+ uids = g_hash_table_new (g_str_hash, g_str_equal);
+
+ e_week_view_foreach_event (week_view, row_deleted_check_cb, uids);
+ g_hash_table_foreach (uids, remove_uid_cb, week_view);
+
+ g_hash_table_destroy (uids);
+
+ gtk_widget_queue_draw (week_view->main_canvas);
+ e_week_view_queue_layout (week_view);
+}
+
+static void
timezone_changed_cb (ECalendarView *cal_view, icaltimezone *old_zone,
icaltimezone *new_zone, gpointer user_data)
{
struct icaltimetype tt = icaltime_null_time ();
time_t lower;
EWeekView *week_view = (EWeekView *) cal_view;
-
+
g_return_if_fail (E_IS_WEEK_VIEW (week_view));
/* If we don't have a valid date set yet, just return. */
@@ -272,7 +532,7 @@ timezone_changed_cb (ECalendarView *cal_view, icaltimezone *old_zone,
lower = icaltime_as_timet_with_zone (tt, new_zone);
e_week_view_recalc_day_starts (week_view, lower);
- e_week_view_update_query ((ECalendarView *) week_view);
+ e_week_view_update_query (week_view);
}
static void
@@ -281,6 +541,7 @@ e_week_view_init (EWeekView *week_view)
GnomeCanvasGroup *canvas_group;
GtkObject *adjustment;
GdkPixbuf *pixbuf;
+ ECalModel *model;
gint i;
GTK_WIDGET_SET_FLAGS (week_view, GTK_CAN_FOCUS);
@@ -415,6 +676,24 @@ e_week_view_init (EWeekView *week_view)
week_view->resize_width_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
week_view->last_cursor_set = NULL;
+ /* Set the default model */
+ model = E_CAL_MODEL (e_cal_model_calendar_new ());
+ e_calendar_view_set_model (E_CALENDAR_VIEW (week_view), model);
+
+ /* connect to ECalModel's signals */
+ g_signal_connect (G_OBJECT (model), "time_range_changed",
+ G_CALLBACK (time_range_changed_cb), week_view);
+ g_signal_connect (G_OBJECT (model), "model_changed",
+ G_CALLBACK (model_changed_cb), week_view);
+ g_signal_connect (G_OBJECT (model), "model_row_changed",
+ G_CALLBACK (model_row_changed_cb), week_view);
+ g_signal_connect (G_OBJECT (model), "model_cell_changed",
+ G_CALLBACK (model_cell_changed_cb), week_view);
+ g_signal_connect (G_OBJECT (model), "model_rows_inserted",
+ G_CALLBACK (model_rows_inserted_cb), week_view);
+ g_signal_connect (G_OBJECT (model), "model_rows_deleted",
+ G_CALLBACK (model_rows_deleted_cb), week_view);
+
/* connect to ECalendarView's signals */
g_signal_connect (G_OBJECT (week_view), "timezone_changed",
G_CALLBACK (timezone_changed_cb), NULL);
@@ -431,13 +710,8 @@ GtkWidget *
e_week_view_new (void)
{
GtkWidget *week_view;
- ECalModel *model;
- model = E_CAL_MODEL (e_cal_model_calendar_new ());
-
- week_view = GTK_WIDGET (g_object_new (e_week_view_get_type (), "model", model, NULL));
-
- g_object_unref (model);
+ week_view = GTK_WIDGET (g_object_new (e_week_view_get_type (), NULL));
return week_view;
}
@@ -1101,88 +1375,11 @@ e_week_view_get_selected_events (ECalendarView *cal_view)
return list;
}
-static void
-process_component (EWeekView *week_view, ECalModelComponent *comp_data)
-{
- EWeekViewEvent *event;
- gint event_num, num_days;
- ECalComponent *comp = NULL;
- AddEventData add_event_data;
- const char *uid;
-
- /* If we don't have a valid date set yet, just return. */
- if (!g_date_valid (&week_view->first_day_shown))
- return;
-
- comp = e_cal_component_new ();
- if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp))) {
- g_object_unref (comp);
-
- g_message ("process_component(): Could not set icalcomponent on ECalComponent");
- return;
- }
-
- e_cal_component_get_uid (comp, &uid);
-
- /* If the event already exists and the dates didn't change, we can
- update the event fairly easily without changing the events arrays
- or computing a new layout. */
- if (e_week_view_find_event_from_uid (week_view, uid, &event_num)) {
- ECalComponent *tmp_comp;
-
- event = &g_array_index (week_view->events, EWeekViewEvent,
- event_num);
-
- tmp_comp = e_cal_component_new ();
- e_cal_component_set_icalcomponent (tmp_comp, icalcomponent_new_clone (comp_data->icalcomp));
- if (!e_cal_component_has_recurrences (comp)
- && !e_cal_component_has_recurrences (tmp_comp)
- && e_cal_component_event_dates_match (comp, tmp_comp)) {
-#if 0
- g_print ("updated object's dates unchanged\n");
-#endif
- e_week_view_foreach_event_with_uid (week_view, uid, e_week_view_update_event_cb, comp_data);
- g_object_unref (comp);
- g_object_unref (tmp_comp);
- gtk_widget_queue_draw (week_view->main_canvas);
- return;
- }
-
- /* The dates have changed, so we need to remove the
- old occurrrences before adding the new ones. */
-#if 0
- g_print ("dates changed - removing occurrences\n");
-#endif
- e_week_view_foreach_event_with_uid (week_view, uid,
- e_week_view_remove_event_cb,
- NULL);
-
- g_object_unref (tmp_comp);
- }
-
- /* Add the occurrences of the event */
- num_days = week_view->multi_week_view ? week_view->weeks_shown * 7 : 7;
-
- add_event_data.week_view = week_view;
- add_event_data.comp_data = comp_data;
- e_cal_recur_generate_instances (comp,
- week_view->day_starts[0],
- week_view->day_starts[num_days],
- e_week_view_add_event, &add_event_data,
- e_cal_resolve_tzid_cb, comp_data->client,
- e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
-
- g_object_unref (comp);
-
- e_week_view_queue_layout (week_view);
-}
-
/* Restarts a query for the week view */
static void
-e_week_view_update_query (ECalendarView *cal_view)
+e_week_view_update_query (EWeekView *week_view)
{
gint rows, r;
- EWeekView *week_view = E_WEEK_VIEW (cal_view);
gtk_widget_queue_draw (week_view->main_canvas);
e_week_view_free_events (week_view);
@@ -1291,7 +1488,7 @@ e_week_view_set_selected_time_range (ECalendarView *cal_view,
start_time = time_day_begin_with_zone (start_time,
e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
e_week_view_recalc_day_starts (week_view, start_time);
- e_week_view_update_query ((ECalendarView *) week_view);
+ e_week_view_update_query (week_view);
}
/* Set the selection to the given days. */
@@ -1475,7 +1672,7 @@ e_week_view_set_first_day_shown (EWeekView *week_view,
e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
e_week_view_recalc_day_starts (week_view, start_time);
- e_week_view_update_query ((ECalendarView *) week_view);
+ e_week_view_update_query (week_view);
}
/* Try to keep the previous selection, but if it is no longer shown
@@ -1612,7 +1809,7 @@ e_week_view_set_weeks_shown (EWeekView *week_view,
if (g_date_valid (&week_view->first_day_shown))
e_week_view_set_first_day_shown (week_view, &week_view->first_day_shown);
- e_week_view_update_query ((ECalendarView *) week_view);
+ e_week_view_update_query (week_view);
}
}
@@ -1756,10 +1953,8 @@ e_week_view_update_event_cb (EWeekView *week_view,
event = &g_array_index (week_view->events, EWeekViewEvent, event_num);
- if (event->allocated_comp_data)
- e_cal_model_free_component_data (event->comp_data);
- event->comp_data = comp_data;
- event->allocated_comp_data = FALSE;
+ e_cal_model_free_component_data (event->comp_data);
+ event->comp_data = e_cal_model_copy_component_data (comp_data);
for (span_num = 0; span_num < event->num_spans; span_num++) {
span = &g_array_index (week_view->spans, EWeekViewEventSpan,
@@ -1782,6 +1977,26 @@ e_week_view_update_event_cb (EWeekView *week_view,
return TRUE;
}
+/* This calls a given function for each event instance Note that it is
+ safe for the callback to remove the event (since we step backwards
+ through the arrays). */
+static void
+e_week_view_foreach_event (EWeekView *week_view,
+ EWeekViewForeachEventCallback callback,
+ gpointer data)
+{
+ EWeekViewEvent *event;
+ gint event_num;
+
+ for (event_num = week_view->events->len - 1;
+ event_num >= 0;
+ event_num--) {
+ event = &g_array_index (week_view->events, EWeekViewEvent, event_num);
+
+ if (!(*callback) (week_view, event_num, data))
+ return;
+ }
+}
/* This calls a given function for each event instance that matches the given
uid. Note that it is safe for the callback to remove the event (since we
@@ -1844,10 +2059,7 @@ e_week_view_remove_event_cb (EWeekView *week_view,
}
}
- if (event->allocated_comp_data) {
- e_cal_model_free_component_data (event->comp_data);
- event->allocated_comp_data = FALSE;
- }
+ e_cal_model_free_component_data (event->comp_data);
g_array_remove_index (week_view->events, event_num);
week_view->events_need_layout = TRUE;
@@ -2018,8 +2230,6 @@ e_week_view_on_button_release (GtkWidget *widget,
GdkEventButton *event,
EWeekView *week_view)
{
- time_t start, end;
-
#if 0
g_print ("In e_week_view_on_button_release\n");
#endif
@@ -2027,11 +2237,6 @@ e_week_view_on_button_release (GtkWidget *widget,
if (week_view->selection_drag_pos != E_WEEK_VIEW_DRAG_NONE) {
week_view->selection_drag_pos = E_WEEK_VIEW_DRAG_NONE;
gdk_pointer_ungrab (event->time);
- start = week_view->day_starts[week_view->selection_start_day];
- end = week_view->day_starts[week_view->selection_end_day + 1];
-
- gnome_calendar_set_selected_time_range (e_calendar_view_get_calendar (E_CALENDAR_VIEW (week_view)),
- start, end);
}
return FALSE;
@@ -2203,8 +2408,7 @@ e_week_view_free_events (EWeekView *week_view)
for (event_num = 0; event_num < week_view->events->len; event_num++) {
event = &g_array_index (week_view->events, EWeekViewEvent,
event_num);
- if (event->allocated_comp_data)
- e_cal_model_free_component_data (event->comp_data);
+ e_cal_model_free_component_data (event->comp_data);
}
g_array_set_size (week_view->events, 0);
@@ -2270,13 +2474,11 @@ e_week_view_add_event (ECalComponent *comp,
e_calendar_view_get_timezone (E_CALENDAR_VIEW (add_event_data->week_view)));
if (add_event_data->comp_data) {
- event.comp_data = add_event_data->comp_data;
- event.allocated_comp_data = FALSE;
+ event.comp_data = e_cal_model_copy_component_data (add_event_data->comp_data);
} else {
event.comp_data = g_new0 (ECalModelComponent, 1);
- event.allocated_comp_data = TRUE;
- event.comp_data->client = e_cal_model_get_default_client (e_calendar_view_get_model (E_CALENDAR_VIEW (add_event_data->week_view)));
+ event.comp_data->client = g_object_ref (e_cal_model_get_default_client (e_calendar_view_get_model (E_CALENDAR_VIEW (add_event_data->week_view))));
e_cal_component_commit_sequence (comp);
event.comp_data->icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
}
@@ -2735,7 +2937,7 @@ e_week_view_on_adjustment_changed (GtkAdjustment *adjustment,
lower = icaltime_as_timet_with_zone (start_tt, e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));
e_week_view_recalc_day_starts (week_view, lower);
- e_week_view_update_query ((ECalendarView *) week_view);
+ e_week_view_update_query (week_view);
/* Update the selection, if needed. */
if (week_view->selection_start_day != -1) {