aboutsummaryrefslogtreecommitdiffstats
path: root/calendar
diff options
context:
space:
mode:
authorDamon Chaplin <damon@helixcode.com>2000-05-01 08:27:17 +0800
committerDamon Chaplin <damon@src.gnome.org>2000-05-01 08:27:17 +0800
commitc4f6855cebd5b13deca8109e79f0beb7dabdd0ce (patch)
tree95937961c0290907b5a469618c1b137f97c94480 /calendar
parent165bf85c4d07928acf01c43c49c7e65c16b28ac8 (diff)
downloadgsoc2013-evolution-c4f6855cebd5b13deca8109e79f0beb7dabdd0ce.tar
gsoc2013-evolution-c4f6855cebd5b13deca8109e79f0beb7dabdd0ce.tar.gz
gsoc2013-evolution-c4f6855cebd5b13deca8109e79f0beb7dabdd0ce.tar.bz2
gsoc2013-evolution-c4f6855cebd5b13deca8109e79f0beb7dabdd0ce.tar.lz
gsoc2013-evolution-c4f6855cebd5b13deca8109e79f0beb7dabdd0ce.tar.xz
gsoc2013-evolution-c4f6855cebd5b13deca8109e79f0beb7dabdd0ce.tar.zst
gsoc2013-evolution-c4f6855cebd5b13deca8109e79f0beb7dabdd0ce.zip
new function to see if the event dates have changed (including any
2000-05-01 Damon Chaplin <damon@helixcode.com> * cal-util/calobj.c (ical_object_compare_dates): new function to see if the event dates have changed (including any recurrence rules). It is used for optimization when we get the "object_changed" signal. We have to do far less work if the dates are unchanged. * gui/e-week-view.c: * gui/e-day-view.c: only draw the selection when we have the keyboard focus, since the user expects to be able to type in a new event when the selection is shown. Also keep the selection when we lose focus, but just don't show it. Also quite a few changes to cope with the new client/server architecture. * gui/e-day-view-top-item.c (e_day_view_top_item_draw): * gui/e-day-view-main-item.c (e_day_view_main_item_draw): * gui/e-week-view-main-item.c (e_week_view_main_item_draw_day): only draw the selection if the widget has the keyboard focus. * gui/gnome-cal.c (mark_gtk_calendar_day): fixed so it works with events longer than one day. And changed the code for updating events in the new views. svn path=/trunk/; revision=2701
Diffstat (limited to 'calendar')
-rw-r--r--calendar/ChangeLog25
-rw-r--r--calendar/cal-util/calobj.c108
-rw-r--r--calendar/cal-util/calobj.h5
-rw-r--r--calendar/gui/calendar-commands.c2
-rw-r--r--calendar/gui/e-day-view-main-item.c3
-rw-r--r--calendar/gui/e-day-view-top-item.c3
-rw-r--r--calendar/gui/e-day-view.c302
-rw-r--r--calendar/gui/e-day-view.h20
-rw-r--r--calendar/gui/e-week-view-event-item.c16
-rw-r--r--calendar/gui/e-week-view-main-item.c3
-rw-r--r--calendar/gui/e-week-view.c531
-rw-r--r--calendar/gui/e-week-view.h29
-rw-r--r--calendar/gui/gnome-cal.c75
13 files changed, 950 insertions, 172 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog
index fa05cff137..3937447d9c 100644
--- a/calendar/ChangeLog
+++ b/calendar/ChangeLog
@@ -1,3 +1,28 @@
+2000-05-01 Damon Chaplin <damon@helixcode.com>
+
+ * cal-util/calobj.c (ical_object_compare_dates): new function to see
+ if the event dates have changed (including any recurrence rules).
+ It is used for optimization when we get the "object_changed" signal.
+ We have to do far less work if the dates are unchanged.
+
+ * gui/e-week-view.c:
+ * gui/e-day-view.c: only draw the selection when we have the keyboard
+ focus, since the user expects to be able to type in a new event when
+ the selection is shown. Also keep the selection when we lose focus,
+ but just don't show it.
+
+ Also quite a few changes to cope with the new client/server
+ architecture.
+
+ * gui/e-day-view-top-item.c (e_day_view_top_item_draw):
+ * gui/e-day-view-main-item.c (e_day_view_main_item_draw):
+ * gui/e-week-view-main-item.c (e_week_view_main_item_draw_day):
+ only draw the selection if the widget has the keyboard focus.
+
+ * gui/gnome-cal.c (mark_gtk_calendar_day): fixed so it works with
+ events longer than one day. And changed the code for updating events
+ in the new views.
+
2000-04-27 Ettore Perazzoli <ettore@helixcode.com>
* gui/evolution-calendar-control.c
diff --git a/calendar/cal-util/calobj.c b/calendar/cal-util/calobj.c
index 03862d1dd1..1634ec084e 100644
--- a/calendar/cal-util/calobj.c
+++ b/calendar/cal-util/calobj.c
@@ -21,6 +21,8 @@
/* VCalendar product ID */
#define PRODID "-//Helix Code//NONSGML Evolution Calendar//EN"
+static gint compare_exdates (gconstpointer a, gconstpointer b);
+
static char *
@@ -1224,6 +1226,10 @@ ical_object_generate_events (iCalObject *ico, time_t start, time_t end, calendar
if (!ico->recur) {
if ((end && (ico->dtstart < end) && (ico->dtend > start))
|| ((end == 0) && (ico->dtend > start))) {
+ /* The new calendar views expect the times to not be
+ clipped, so they can show that it continues past
+ the end of the viewable area. */
+#if 0
time_t ev_s, ev_e;
/* Clip range */
@@ -1232,6 +1238,9 @@ ical_object_generate_events (iCalObject *ico, time_t start, time_t end, calendar
ev_e = MIN (ico->dtend, end);
(* cb) (ico, ev_s, ev_e, closure);
+#else
+ (* cb) (ico, ico->dtstart, ico->dtend, closure);
+#endif
}
return;
}
@@ -1631,3 +1640,102 @@ ical_object_to_string (iCalObject *ico)
return gbuf;
}
+
+
+/**
+ * ical_object_compare_dates:
+ * @ico1: A calendar event.
+ * @ico2: A calendar event to compare with @ico1.
+ *
+ * Returns TRUE if the dates of both objects match, including any recurrence
+ * rules. Both calendar objects must have a type of ICAL_EVENT.
+ *
+ * Return value: TRUE if both calendar objects have the same dates.
+ **/
+gboolean
+ical_object_compare_dates (iCalObject *ico1,
+ iCalObject *ico2)
+{
+ Recurrence *recur1, *recur2;
+ gint num_exdates;
+ GList *elem1, *elem2;
+ time_t *time1, *time2;
+
+ g_return_val_if_fail (ico1 != NULL, FALSE);
+ g_return_val_if_fail (ico2 != NULL, FALSE);
+ g_return_val_if_fail (ico1->type == ICAL_EVENT, FALSE);
+ g_return_val_if_fail (ico2->type == ICAL_EVENT, FALSE);
+
+ /* First check the base dates. */
+ if (ico1->dtstart != ico2->dtstart
+ || ico1->dtend != ico2->dtend)
+ return FALSE;
+
+ recur1 = ico1->recur;
+ recur2 = ico2->recur;
+
+ /* If the event doesn't recur, we already know it matches. */
+ if (!recur1 && !recur2)
+ return TRUE;
+
+ /* Check that both recur. */
+ if (!(recur1 && recur2))
+ return FALSE;
+
+ /* Now we need to see if the recurrence rules are the same. */
+ if (recur1->type != recur2->type
+ || recur1->interval != recur2->interval
+ || recur1->enddate != recur2->enddate
+ || recur1->weekday != recur2->weekday
+ || recur1->duration != recur2->duration
+ || recur1->_enddate != recur2->_enddate
+ || recur1->__count != recur2->__count)
+ return FALSE;
+
+ switch (recur1->type) {
+ case RECUR_MONTHLY_BY_POS:
+ if (recur1->u.month_pos != recur2->u.month_pos)
+ return FALSE;
+ break;
+ case RECUR_MONTHLY_BY_DAY:
+ if (recur1->u.month_day != recur2->u.month_day)
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+
+ /* Now check if the excluded dates match. */
+ num_exdates = g_list_length (ico1->exdate);
+ if (g_list_length (ico2->exdate) != num_exdates)
+ return FALSE;
+ if (num_exdates == 0)
+ return TRUE;
+
+ ico1->exdate = g_list_sort (ico1->exdate, compare_exdates);
+ ico2->exdate = g_list_sort (ico2->exdate, compare_exdates);
+
+ elem1 = ico1->exdate;
+ elem2 = ico2->exdate;
+ while (elem1) {
+ time1 = (time_t*) elem1->data;
+ time2 = (time_t*) elem2->data;
+
+ if (*time1 != *time2)
+ return FALSE;
+
+ elem1 = elem1->next;
+ elem2 = elem2->next;
+ }
+
+ return TRUE;
+}
+
+
+static gint
+compare_exdates (gconstpointer a, gconstpointer b)
+{
+ const time_t *ca = a, *cb = b;
+ time_t diff = *ca - *cb;
+ return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
+}
diff --git a/calendar/cal-util/calobj.h b/calendar/cal-util/calobj.h
index cb0e22f741..0fa82ee36e 100644
--- a/calendar/cal-util/calobj.h
+++ b/calendar/cal-util/calobj.h
@@ -258,6 +258,11 @@ int ical_object_get_first_weekday (int weekday_mask);
/* Returns the number of seconds configured to trigger the alarm in advance to an event */
int alarm_compute_offset (CalendarAlarm *a);
+
+/* Returns TRUE if the dates of both objects match, including any recurrence
+ rules. */
+gboolean ical_object_compare_dates (iCalObject *ico1, iCalObject *ico2);
+
END_GNOME_DECLS
#endif
diff --git a/calendar/gui/calendar-commands.c b/calendar/gui/calendar-commands.c
index 254030c675..e3ae6a4bc6 100644
--- a/calendar/gui/calendar-commands.c
+++ b/calendar/gui/calendar-commands.c
@@ -805,6 +805,8 @@ calendar_iterate (GnomeCalendar *cal,
break;
}
+ /* FIXME: add g_free (obj_string) ? */
+
g_free (l->data);
}
g_list_free (uids);
diff --git a/calendar/gui/e-day-view-main-item.c b/calendar/gui/e-day-view-main-item.c
index 1abff57c97..2ce8f9201f 100644
--- a/calendar/gui/e-day-view-main-item.c
+++ b/calendar/gui/e-day-view-main-item.c
@@ -228,7 +228,8 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
work_day_w, height - work_day_end_y);
/* Paint the selection background. */
- if (day_view->selection_start_col != -1
+ if (GTK_WIDGET_HAS_FOCUS (day_view)
+ && day_view->selection_start_col != -1
&& !day_view->selection_in_top_canvas) {
for (day = day_view->selection_start_col;
day <= day_view->selection_end_col;
diff --git a/calendar/gui/e-day-view-top-item.c b/calendar/gui/e-day-view-top-item.c
index 6d5ea60854..ac2d6bfb62 100644
--- a/calendar/gui/e-day-view-top-item.c
+++ b/calendar/gui/e-day-view-top-item.c
@@ -229,7 +229,8 @@ e_day_view_top_item_draw (GnomeCanvasItem *canvas_item,
item_height - 3);
/* Draw the selection background. */
- if (day_view->selection_start_col != -1) {
+ if (GTK_WIDGET_HAS_FOCUS (day_view)
+ && day_view->selection_start_col != -1) {
gint start_col, end_col, rect_x, rect_y, rect_w, rect_h;
start_col = day_view->selection_start_col;
diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c
index 65151e49a6..25b026407e 100644
--- a/calendar/gui/e-day-view.c
+++ b/calendar/gui/e-day-view.c
@@ -187,11 +187,21 @@ static gboolean e_day_view_find_event_from_item (EDayView *day_view,
GnomeCanvasItem *item,
gint *day_return,
gint *event_num_return);
-static gboolean e_day_view_find_event_from_ico (EDayView *day_view,
- iCalObject *ico,
+static gboolean e_day_view_find_event_from_uid (EDayView *day_view,
+ const gchar *uid,
gint *day_return,
gint *event_num_return);
+typedef gboolean (* EDayViewForeachEventCallback) (EDayView *day_view,
+ gint day,
+ gint event_num,
+ gpointer data);
+
+static void e_day_view_foreach_event_with_uid (EDayView *day_view,
+ const gchar *uid,
+ EDayViewForeachEventCallback callback,
+ gpointer data);
+
static void e_day_view_reload_events (EDayView *day_view);
static void e_day_view_free_events (EDayView *day_view);
static void e_day_view_free_event_array (EDayView *day_view,
@@ -338,6 +348,14 @@ static void e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget
guint info,
guint time,
EDayView *day_view);
+static gboolean e_day_view_update_event_cb (EDayView *day_view,
+ gint day,
+ gint event_num,
+ gpointer data);
+static gboolean e_day_view_remove_event_cb (EDayView *day_view,
+ gint day,
+ gint event_num,
+ gpointer data);
static GtkTableClass *parent_class;
@@ -449,6 +467,7 @@ e_day_view_init (EDayView *day_view)
day_view->editing_event_day = -1;
day_view->editing_event_num = -1;
+ day_view->editing_new_event = FALSE;
day_view->resize_bars_event_day = -1;
day_view->resize_bars_event_num = -1;
@@ -1012,12 +1031,18 @@ e_day_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
static gint
e_day_view_focus_in (GtkWidget *widget, GdkEventFocus *event)
{
+ EDayView *day_view;
+
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (E_IS_DAY_VIEW (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
+ day_view = E_DAY_VIEW (widget);
+
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
- gtk_widget_draw_focus (widget);
+
+ gtk_widget_queue_draw (day_view->top_canvas);
+ gtk_widget_queue_draw (day_view->main_canvas);
return FALSE;
}
@@ -1036,9 +1061,6 @@ e_day_view_focus_out (GtkWidget *widget, GdkEventFocus *event)
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
- /* Get rid of selection. */
- day_view->selection_start_col = -1;
-
gtk_widget_queue_draw (day_view->top_canvas);
gtk_widget_queue_draw (day_view->main_canvas);
@@ -1058,11 +1080,23 @@ e_day_view_set_calendar (EDayView *day_view,
}
+/* This reloads all calendar events. */
void
-e_day_view_update_event (EDayView *day_view,
- iCalObject *ico,
- int flags)
+e_day_view_update_all_events (EDayView *day_view)
{
+ e_day_view_reload_events (day_view);
+}
+
+
+/* This is called when one event has been added or updated. */
+void
+e_day_view_update_event (EDayView *day_view,
+ const gchar *uid)
+{
+ EDayViewEvent *event;
+ gchar *obj_string;
+ iCalObject *ico;
+ CalObjFindStatus status;
gint day, event_num;
g_return_if_fail (E_IS_DAY_VIEW (day_view));
@@ -1071,48 +1105,199 @@ e_day_view_update_event (EDayView *day_view,
g_print ("In e_day_view_update_event\n");
#endif
- /* If our time hasn't been set yet, just return. */
- if (day_view->lower == 0 && day_view->upper == 0)
+ /* If our calendar or time hasn't been set yet, just return. */
+ if (!day_view->calendar
+ || (day_view->lower == 0 && day_view->upper == 0))
return;
+ /* Get the event from the server. */
+ obj_string = cal_client_get_object (day_view->calendar->client, uid);
+ status = ical_object_find_in_string (uid, obj_string, &ico);
+
+ switch (status) {
+ case CAL_OBJ_FIND_SUCCESS:
+ /* Fall through. */
+ break;
+ case CAL_OBJ_FIND_SYNTAX_ERROR:
+ g_warning ("syntax error uid=%s\n", uid);
+ return;
+ case CAL_OBJ_FIND_NOT_FOUND:
+ g_warning ("obj not found uid=%s\n", uid);
+ return;
+ }
+
/* We only care about events. */
if (ico && ico->type != ICAL_EVENT)
return;
- /* If one non-recurring event was added, we can just add it. */
- if (flags == CHANGE_NEW && ico && !ico->recur) {
- if (ico->dtstart < day_view->upper
- && ico->dtend > day_view->lower) {
- e_day_view_add_event (ico, ico->dtstart, ico->dtend,
- day_view);
- e_day_view_check_layout (day_view);
+ /* 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_day_view_find_event_from_uid (day_view, uid, &day, &event_num)) {
+ if (day == E_DAY_VIEW_LONG_EVENT)
+ event = &g_array_index (day_view->long_events,
+ EDayViewEvent, event_num);
+ else
+ event = &g_array_index (day_view->events[day],
+ EDayViewEvent, event_num);
+ if (ical_object_compare_dates (event->ico, ico)) {
+ e_day_view_foreach_event_with_uid (day_view, uid, e_day_view_update_event_cb, ico);
gtk_widget_queue_draw (day_view->top_canvas);
gtk_widget_queue_draw (day_view->main_canvas);
+ return;
}
- return;
- /* If only the summary changed, we can update that easily. */
- } else if (!(flags & ~CHANGE_SUMMARY)) {
- if (e_day_view_find_event_from_ico (day_view, ico,
- &day, &event_num)) {
- if (day == E_DAY_VIEW_LONG_EVENT) {
- e_day_view_update_long_event_label (day_view,
- event_num);
- /* For long events we also have to reshape it
- as the text is centered. */
- e_day_view_reshape_long_event (day_view,
- event_num);
- } else {
- e_day_view_update_event_label (day_view, day,
- event_num);
+ /* The dates have changed, so we need to remove the
+ old occurrrences before adding the new ones. */
+ e_day_view_foreach_event_with_uid (day_view, uid,
+ e_day_view_remove_event_cb,
+ NULL);
+ }
+
+ /* Add the occurrences of the event. */
+ ical_object_generate_events (ico, day_view->lower, day_view->upper,
+ e_day_view_add_event, day_view);
+
+ e_day_view_check_layout (day_view);
+
+ gtk_widget_queue_draw (day_view->top_canvas);
+ gtk_widget_queue_draw (day_view->main_canvas);
+}
+
+
+static gboolean
+e_day_view_update_event_cb (EDayView *day_view,
+ gint day,
+ gint event_num,
+ gpointer data)
+{
+ EDayViewEvent *event;
+ iCalObject *ico;
+
+ ico = data;
+
+ /* FIXME: When do ico's get freed? */
+ if (day == E_DAY_VIEW_LONG_EVENT) {
+ event = &g_array_index (day_view->long_events, EDayViewEvent,
+ event_num);
+ event->ico = ico;
+ } else {
+ event = &g_array_index (day_view->events[day], EDayViewEvent,
+ event_num);
+ event->ico = ico;
+ }
+
+ /* If we are editing an event which we have just created, we will get
+ an update_event callback from the server. But we need to ignore it
+ or we will lose the text the user has already typed in. */
+ if (day_view->editing_new_event
+ && day_view->editing_event_day == day
+ && day_view->editing_event_num == event_num) {
+ return TRUE;
+ }
+
+ if (day == E_DAY_VIEW_LONG_EVENT) {
+ e_day_view_update_long_event_label (day_view, event_num);
+ e_day_view_reshape_long_event (day_view, event_num);
+ } else {
+ e_day_view_update_event_label (day_view, day, event_num);
+ e_day_view_reshape_day_event (day_view, day, event_num);
+ }
+ return TRUE;
+}
+
+
+/* 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
+ step backwards through the arrays). */
+static void
+e_day_view_foreach_event_with_uid (EDayView *day_view,
+ const gchar *uid,
+ EDayViewForeachEventCallback callback,
+ gpointer data)
+{
+ EDayViewEvent *event;
+ gint day, event_num;
+
+ for (day = 0; day < day_view->days_shown; day++) {
+ for (event_num = day_view->events[day]->len - 1;
+ event_num >= 0;
+ event_num--) {
+ event = &g_array_index (day_view->events[day],
+ EDayViewEvent, event_num);
+ if (event->ico && event->ico->uid
+ && !strcmp (uid, event->ico->uid)) {
+ if (!(*callback) (day_view, day, event_num,
+ data))
+ return;
}
+ }
+ }
- return;
+ for (event_num = day_view->long_events->len - 1;
+ event_num >= 0;
+ event_num--) {
+ event = &g_array_index (day_view->long_events,
+ EDayViewEvent, event_num);
+ if (event->ico && event->ico->uid
+ && !strcmp (uid, event->ico->uid)) {
+ if (!(*callback) (day_view, day, event_num, data))
+ return;
}
}
+}
- e_day_view_reload_events (day_view);
+
+/* This removes all the events associated with the given uid. Note that for
+ recurring events there may be more than one. If any events are found and
+ removed we need to layout the events again. */
+void
+e_day_view_remove_event (EDayView *day_view,
+ const gchar *uid)
+{
+ g_return_if_fail (E_IS_DAY_VIEW (day_view));
+
+ e_day_view_foreach_event_with_uid (day_view, uid,
+ e_day_view_remove_event_cb, NULL);
+
+ e_day_view_check_layout (day_view);
+ gtk_widget_queue_draw (day_view->top_canvas);
+ gtk_widget_queue_draw (day_view->main_canvas);
+}
+
+
+static gboolean
+e_day_view_remove_event_cb (EDayView *day_view,
+ gint day,
+ gint event_num,
+ gpointer data)
+{
+ EDayViewEvent *event;
+
+ if (day == E_DAY_VIEW_LONG_EVENT)
+ event = &g_array_index (day_view->long_events,
+ EDayViewEvent, event_num);
+ else
+ event = &g_array_index (day_view->events[day],
+ EDayViewEvent, event_num);
+
+ /* We set the event's uid to NULL so we don't try to update it in
+ on_editing_stopped(). */
+ g_free (event->ico->uid);
+ event->ico->uid = NULL;
+
+ if (event->canvas_item)
+ gtk_object_destroy (GTK_OBJECT (event->canvas_item));
+
+ if (day == E_DAY_VIEW_LONG_EVENT) {
+ g_array_remove_index (day_view->long_events, event_num);
+ day_view->long_events_need_layout = TRUE;
+ } else {
+ g_array_remove_index (day_view->events[day], event_num);
+ day_view->need_layout[day] = TRUE;
+ }
+ return TRUE;
}
@@ -1221,8 +1406,8 @@ e_day_view_find_event_from_item (EDayView *day_view,
If is is a long event, E_DAY_VIEW_LONG_EVENT is returned as the day.
Returns TRUE if the event was found. */
static gboolean
-e_day_view_find_event_from_ico (EDayView *day_view,
- iCalObject *ico,
+e_day_view_find_event_from_uid (EDayView *day_view,
+ const gchar *uid,
gint *day_return,
gint *event_num_return)
{
@@ -1234,10 +1419,8 @@ e_day_view_find_event_from_ico (EDayView *day_view,
event_num++) {
event = &g_array_index (day_view->events[day],
EDayViewEvent, event_num);
- //if (event->ico == ico) {
- if (ico && ico->uid &&
- event && event->ico && event->ico->uid &&
- (strcmp (ico->uid, event->ico->uid) == 0)) {
+ if (event->ico && event->ico->uid
+ && !strcmp (uid, event->ico->uid)) {
*day_return = day;
*event_num_return = event_num;
return TRUE;
@@ -1249,7 +1432,8 @@ e_day_view_find_event_from_ico (EDayView *day_view,
event_num++) {
event = &g_array_index (day_view->long_events,
EDayViewEvent, event_num);
- if (event->ico == ico) {
+ if (event->ico && event->ico->uid
+ && !strcmp (uid, event->ico->uid)) {
*day_return = E_DAY_VIEW_LONG_EVENT;
*event_num_return = event_num;
return TRUE;
@@ -2015,7 +2199,8 @@ e_day_view_on_event_right_click (EDayView *day_view,
{ N_("New appointment..."), (GtkSignalFunc) e_day_view_on_new_appointment, NULL, TRUE }
};
- have_selection = (day_view->selection_start_col != -1);
+ have_selection = GTK_WIDGET_HAS_FOCUS (day_view)
+ && day_view->selection_start_col != -1;
if (event_num == -1) {
items = 1;
@@ -2648,7 +2833,10 @@ e_day_view_reload_events (EDayView *day_view)
day_view->pressed_event_day = -1;
day_view->drag_event_day = -1;
- if (day_view->calendar) {
+ /* If both lower & upper are 0, then the time range hasn't been set,
+ so we don't try to load any events. */
+ if (day_view->calendar
+ && (day_view->lower != 0 || day_view->upper != 0)) {
calendar_iterate (day_view->calendar,
day_view->lower,
day_view->upper,
@@ -3512,17 +3700,26 @@ e_day_view_key_press (GtkWidget *widget, GdkEventKey *event)
e_day_view_get_selection_range (day_view, &ico->dtstart, &ico->dtend);
- gnome_calendar_add_object (day_view->calendar, ico);
+ /* We add the event locally and start editing it. When we get the
+ "update_event" callback from the server, we basically ignore it.
+ If we were to wait for the "update_event" callback it wouldn't be
+ as responsive and we may lose a few keystrokes. */
+ e_day_view_add_event (ico, ico->dtstart, ico->dtend, day_view);
+ e_day_view_check_layout (day_view);
+ gtk_widget_queue_draw (day_view->top_canvas);
+ gtk_widget_queue_draw (day_view->main_canvas);
- /* gnome_calendar_add_object() should have resulted in a call to
- e_day_view_update_event(), so the new event should now be layed out.
- So we try to find it so we can start editing it. */
- if (e_day_view_find_event_from_ico (day_view, ico, &day, &event_num)) {
- /* Start editing the new event. */
+ if (e_day_view_find_event_from_uid (day_view, ico->uid,
+ &day, &event_num)) {
e_day_view_start_editing_event (day_view, day, event_num,
initial_text);
+ day_view->editing_new_event = TRUE;
+ } else {
+ g_warning ("Couldn't find event to start editing.\n");
}
+ gnome_calendar_add_object (day_view->calendar, ico);
+
return TRUE;
}
@@ -3702,10 +3899,15 @@ e_day_view_on_editing_stopped (EDayView *day_view,
/* Reset the edit fields. */
day_view->editing_event_day = -1;
day_view->editing_event_num = -1;
+ day_view->editing_new_event = FALSE;
day_view->resize_bars_event_day = -1;
day_view->resize_bars_event_num = -1;
+ /* Check that the event is still valid. */
+ if (!event->ico->uid)
+ return;
+
gtk_object_get (GTK_OBJECT (event->canvas_item),
"text", &text,
NULL);
diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h
index ac967f030c..ea49fff0ee 100644
--- a/calendar/gui/e-day-view.h
+++ b/calendar/gui/e-day-view.h
@@ -314,6 +314,11 @@ struct _EDayView
gint editing_event_day;
gint editing_event_num;
+ /* This is TRUE if we are editing an event which we have just created.
+ We ignore the "update_event" callback which we will get from the
+ server when the event is added. */
+ gboolean editing_new_event;
+
/* This is a GnomeCanvasRect which is placed around an item while it
is being resized, so we can raise it above all other EText items. */
GnomeCanvasItem *resize_long_event_rect_item;
@@ -414,15 +419,18 @@ void e_day_view_set_selected_time_range (EDayView *day_view,
time_t start_time,
time_t end_time);
+/* This reloads all calendar events. */
+void e_day_view_update_all_events (EDayView *day_view);
-/* This is called when one or more events have been updated, either within the
- EDayView itself, or via another calendar view or application. If only one
- event has changed, it is passed in the ico argument and the flags indicate
- the change - whether it is a new event, or just the summary has changed. */
+/* This is called when one event has been added or updated. */
void e_day_view_update_event (EDayView *day_view,
- iCalObject *ico,
- int flags);
+ const gchar *uid);
+/* This removes all the events associated with the given uid. Note that for
+ recurring events there may be more than one. If any events are found and
+ removed we need to layout the events again. */
+void e_day_view_remove_event (EDayView *day_view,
+ const gchar *uid);
/* The number of days shown in the EDayView, from 1 to 7. This is normally
either 1 or 5 (for the Work-Week view). */
diff --git a/calendar/gui/e-week-view-event-item.c b/calendar/gui/e-week-view-event-item.c
index e22fd944bf..3bacdc68f9 100644
--- a/calendar/gui/e-week-view-event-item.c
+++ b/calendar/gui/e-week-view-event-item.c
@@ -637,18 +637,20 @@ e_week_view_event_item_button_press (EWeekViewEventItem *wveitem,
span = &g_array_index (week_view->spans, EWeekViewEventSpan,
event->spans_index + wveitem->span_num);
-#if 0
+#if 1
g_print ("In e_week_view_event_item_button_press\n");
#endif
pos = e_week_view_event_item_get_position (wveitem, bevent->button.x,
bevent->button.y);
+ if (pos == E_WEEK_VIEW_POS_NONE)
+ return FALSE;
/* Ignore clicks on the event while editing. */
- if (pos == E_WEEK_VIEW_POS_EVENT && E_TEXT (span->text_item)->editing)
+ if (E_TEXT (span->text_item)->editing)
return FALSE;
- if (pos == E_WEEK_VIEW_POS_EVENT) {
+ if (bevent->button.button == 1) {
/* Remember the item clicked and the mouse position,
so we can start a drag if the mouse moves. */
week_view->pressed_event_num = wveitem->event_num;
@@ -659,9 +661,15 @@ e_week_view_event_item_button_press (EWeekViewEventItem *wveitem,
/* FIXME: Remember the day offset from the start of the event.
*/
+ } else if (bevent->button.button == 3) {
+ e_week_view_show_popup_menu (week_view,
+ (GdkEventButton*) bevent,
+ wveitem->event_num);
+ gtk_signal_emit_stop_by_name (GTK_OBJECT (item->canvas),
+ "button_press_event");
}
- return FALSE;
+ return TRUE;
}
diff --git a/calendar/gui/e-week-view-main-item.c b/calendar/gui/e-week-view-main-item.c
index 7101cbef46..49c2ca3d7d 100644
--- a/calendar/gui/e-week-view-main-item.c
+++ b/calendar/gui/e-week-view-main-item.c
@@ -277,7 +277,8 @@ e_week_view_main_item_draw_day (EWeekViewMainItem *wvmitem,
/* If the day is selected, draw the blue background. */
selected = TRUE;
- if (week_view->selection_start_day == -1
+ if (!GTK_WIDGET_HAS_FOCUS (week_view)
+ || week_view->selection_start_day == -1
|| week_view->selection_start_day > day
|| week_view->selection_end_day < day)
selected = FALSE;
diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c
index 51a292041e..7f6e1c0c9c 100644
--- a/calendar/gui/e-week-view.c
+++ b/calendar/gui/e-week-view.c
@@ -125,18 +125,38 @@ static gboolean e_week_view_find_event_from_item (EWeekView *week_view,
GnomeCanvasItem *item,
gint *event_num,
gint *span_num);
-static gboolean e_week_view_find_event_from_ico (EWeekView *week_view,
- iCalObject *ico,
+static gboolean e_week_view_find_event_from_uid (EWeekView *week_view,
+ const gchar *uid,
gint *event_num_return);
+typedef gboolean (* EWeekViewForeachEventCallback) (EWeekView *week_view,
+ gint event_num,
+ gpointer data);
+
+static void e_week_view_foreach_event_with_uid (EWeekView *week_view,
+ const gchar *uid,
+ EWeekViewForeachEventCallback callback,
+ gpointer data);
static gboolean e_week_view_on_text_item_event (GnomeCanvasItem *item,
GdkEvent *event,
EWeekView *week_view);
static gint e_week_view_key_press (GtkWidget *widget, GdkEventKey *event);
-static void e_week_view_show_popup_menu (EWeekView *week_view,
- GdkEventButton *event,
- gint day);
static void e_week_view_on_new_appointment (GtkWidget *widget,
gpointer data);
+static void e_week_view_on_edit_appointment (GtkWidget *widget,
+ gpointer data);
+static void e_week_view_on_delete_occurance (GtkWidget *widget,
+ gpointer data);
+static void e_week_view_on_delete_appointment (GtkWidget *widget,
+ gpointer data);
+static void e_week_view_on_unrecur_appointment (GtkWidget *widget,
+ gpointer data);
+
+static gboolean e_week_view_update_event_cb (EWeekView *week_view,
+ gint event_num,
+ gpointer data);
+static gboolean e_week_view_remove_event_cb (EWeekView *week_view,
+ gint event_num,
+ gpointer data);
static GtkTableClass *parent_class;
@@ -230,6 +250,7 @@ e_week_view_init (EWeekView *week_view)
week_view->pressed_event_num = -1;
week_view->editing_event_num = -1;
+ week_view->editing_new_event = FALSE;
/* Create the small font. */
week_view->use_small_font = TRUE;
@@ -620,12 +641,19 @@ e_week_view_recalc_cell_sizes (EWeekView *week_view)
static gint
e_week_view_focus_in (GtkWidget *widget, GdkEventFocus *event)
{
+ EWeekView *week_view;
+
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (E_IS_WEEK_VIEW (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
+ g_print ("In e_week_view_focus_in\n");
+
+ week_view = E_WEEK_VIEW (widget);
+
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
- gtk_widget_draw_focus (widget);
+
+ gtk_widget_queue_draw (week_view->main_canvas);
return FALSE;
}
@@ -640,13 +668,12 @@ e_week_view_focus_out (GtkWidget *widget, GdkEventFocus *event)
g_return_val_if_fail (E_IS_WEEK_VIEW (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
+ g_print ("In e_week_view_focus_out\n");
+
week_view = E_WEEK_VIEW (widget);
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
- /* Get rid of selection. */
- week_view->selection_start_day = -1;
-
gtk_widget_queue_draw (week_view->main_canvas);
return FALSE;
@@ -905,69 +932,212 @@ e_week_view_set_compress_weekend (EWeekView *week_view,
}
+/* This reloads all calendar events. */
+void
+e_week_view_update_all_events (EWeekView *week_view)
+{
+ e_week_view_reload_events (week_view);
+}
+
+
+/* This is called when one event has been added or updated. */
void
-e_week_view_update_event (EWeekView *week_view,
- iCalObject *ico,
- int flags)
+e_week_view_update_event (EWeekView *week_view,
+ const gchar *uid)
{
EWeekViewEvent *event;
- EWeekViewEventSpan *span;
- gint event_num, num_days, span_num;
- gboolean one_day_event;
+ gint event_num, num_days;
+ gchar *obj_string;
+ iCalObject *ico;
+ CalObjFindStatus status;
g_return_if_fail (E_IS_WEEK_VIEW (week_view));
+#if 0
+ g_print ("In e_week_view_update_event\n");
+#endif
+
+ /* If we don't have a calendar or valid date set yet, just return. */
+ if (!week_view->calendar
+ || !g_date_valid (&week_view->first_day_shown))
+ return;
+
+ /* Get the event from the server. */
+ obj_string = cal_client_get_object (week_view->calendar->client, uid);
+ status = ical_object_find_in_string (uid, obj_string, &ico);
+
+ switch (status) {
+ case CAL_OBJ_FIND_SUCCESS:
+ /* Fall through. */
+ break;
+ case CAL_OBJ_FIND_SYNTAX_ERROR:
+ g_warning ("syntax error uid=%s\n", uid);
+ return;
+ case CAL_OBJ_FIND_NOT_FOUND:
+ g_warning ("obj not found uid=%s\n", uid);
+ return;
+ }
+
/* We only care about events. */
if (ico && ico->type != ICAL_EVENT)
return;
- /* If we don't have a valid date set yet, just return. */
- if (!g_date_valid (&week_view->first_day_shown))
- return;
+ /* 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)) {
+ event = &g_array_index (week_view->events, EWeekViewEvent,
+ event_num);
- /* If one non-recurring event was added, we can just add it. */
- if (flags == CHANGE_NEW && ico && !ico->recur) {
- num_days = week_view->display_month
- ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7;
- if (ico->dtstart < week_view->day_starts[num_days]
- && ico->dtend > week_view->day_starts[0]) {
- e_week_view_add_event (ico, ico->dtstart, ico->dtend,
- week_view);
- e_week_view_check_layout (week_view);
+ if (ical_object_compare_dates (event->ico, ico)) {
+ e_week_view_foreach_event_with_uid (week_view, uid, e_week_view_update_event_cb, ico);
gtk_widget_queue_draw (week_view->main_canvas);
+ return;
}
- return;
- /* If only the summary changed, we can update that easily.
- Though we have to update all spans of the event. */
- } else if (!(flags & ~CHANGE_SUMMARY)) {
- if (e_week_view_find_event_from_ico (week_view, ico,
- &event_num)) {
- event = &g_array_index (week_view->events,
- EWeekViewEvent, event_num);
- one_day_event = e_week_view_is_one_day_event (week_view, event_num);
- for (span_num = 0; span_num < event->num_spans;
- span_num++) {
- span = &g_array_index (week_view->spans,
- EWeekViewEventSpan,
- event->spans_index
- + span_num);
-
- if (span->text_item) {
- gnome_canvas_item_set (span->text_item,
- "text", ico->summary ? ico->summary : "",
- NULL);
-
- if (!one_day_event)
- e_week_view_reshape_event_span (week_view, event_num, span_num);
- }
- }
+ /* The dates have changed, so we need to remove the
+ old occurrrences before adding the new ones. */
+ e_week_view_foreach_event_with_uid (week_view, uid,
+ e_week_view_remove_event_cb,
+ NULL);
+ }
- return;
+ /* Add the occurrences of the event. */
+ num_days = week_view->display_month ? E_WEEK_VIEW_MAX_WEEKS * 7 : 7;
+ ical_object_generate_events (ico,
+ week_view->day_starts[0],
+ week_view->day_starts[num_days],
+ e_week_view_add_event,
+ week_view);
+
+ e_week_view_check_layout (week_view);
+
+ gtk_widget_queue_draw (week_view->main_canvas);
+}
+
+
+static gboolean
+e_week_view_update_event_cb (EWeekView *week_view,
+ gint event_num,
+ gpointer data)
+{
+ EWeekViewEvent *event;
+ EWeekViewEventSpan *span;
+ gint span_num;
+ gchar *text;
+ iCalObject *ico;
+
+ ico = data;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent, event_num);
+ /* FIXME: When do ico's get freed? */
+ event->ico = ico;
+
+ /* If we are editing an event which we have just created, we will get
+ an update_event callback from the server. But we need to ignore it
+ or we will lose the text the user has already typed in. */
+ if (week_view->editing_new_event
+ && week_view->editing_event_num == event_num) {
+ return TRUE;
+ }
+
+ for (span_num = 0; span_num < event->num_spans; span_num++) {
+ span = &g_array_index (week_view->spans, EWeekViewEventSpan,
+ event->spans_index + span_num);
+
+ if (span->text_item) {
+ text = event->ico->summary;
+ gnome_canvas_item_set (span->text_item,
+ "text", text ? text : "",
+ NULL);
+
+ e_week_view_reshape_event_span (week_view, event_num,
+ span_num);
}
}
- e_week_view_reload_events (week_view);
+ return TRUE;
+}
+
+
+/* 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
+ step backwards through the arrays). */
+static void
+e_week_view_foreach_event_with_uid (EWeekView *week_view,
+ const gchar *uid,
+ 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 (event->ico && event->ico->uid
+ && !strcmp (uid, event->ico->uid)) {
+ if (!(*callback) (week_view, event_num, data))
+ return;
+ }
+ }
+}
+
+
+/* This removes all the events associated with the given uid. Note that for
+ recurring events there may be more than one. If any events are found and
+ removed we need to layout the events again. */
+void
+e_week_view_remove_event (EWeekView *week_view,
+ const gchar *uid)
+{
+ g_return_if_fail (E_IS_WEEK_VIEW (week_view));
+
+ e_week_view_foreach_event_with_uid (week_view, uid,
+ e_week_view_remove_event_cb, NULL);
+
+ e_week_view_check_layout (week_view);
+ gtk_widget_queue_draw (week_view->main_canvas);
+}
+
+
+static gboolean
+e_week_view_remove_event_cb (EWeekView *week_view,
+ gint event_num,
+ gpointer data)
+{
+ EWeekViewEvent *event;
+ EWeekViewEventSpan *span;
+ gint span_num;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent, event_num);
+
+ /* We set the event's uid to NULL so we don't try to update it in
+ on_editing_stopped(). */
+ g_free (event->ico->uid);
+ event->ico->uid = NULL;
+
+ /* We leave the span elements in the array, but set the canvas item
+ pointers to NULL. */
+ for (span_num = 0; span_num < event->num_spans; span_num++) {
+ span = &g_array_index (week_view->spans, EWeekViewEventSpan,
+ event->spans_index + span_num);
+
+ if (span->text_item) {
+ gtk_object_destroy (GTK_OBJECT (span->text_item));
+ span->text_item = NULL;
+ }
+ if (span->background_item) {
+ gtk_object_destroy (GTK_OBJECT (span->background_item));
+ span->background_item = NULL;
+ }
+ }
+ g_array_remove_index (week_view->events, event_num);
+ week_view->events_need_layout = TRUE;
+
+ return TRUE;
}
@@ -1152,7 +1322,7 @@ e_week_view_on_button_press (GtkWidget *widget,
gtk_widget_queue_draw (week_view->main_canvas);
}
} else if (event->button == 3) {
- e_week_view_show_popup_menu (week_view, event, day);
+ e_week_view_show_popup_menu (week_view, event, -1);
}
return FALSE;
@@ -1989,19 +2159,74 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item,
GdkEvent *event,
EWeekView *week_view)
{
+ gint event_num, span_num;
+
switch (event->type) {
case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
+ if (!e_week_view_find_event_from_item (week_view, item,
+ &event_num, &span_num))
+ return FALSE;
+
+ if (event->button.button == 3) {
+ e_week_view_show_popup_menu (week_view,
+ (GdkEventButton*) event,
+ event_num);
+ gtk_signal_emit_stop_by_name (GTK_OBJECT (item->canvas),
+ "button_press_event");
+ return TRUE;
+ }
+
/* Only let the EText handle the event while editing. */
- if (!E_TEXT (item)->editing)
+ if (!E_TEXT (item)->editing) {
+ gtk_signal_emit_stop_by_name (GTK_OBJECT (item),
+ "event");
+
+
+ week_view->pressed_event_num = event_num;
+ week_view->pressed_span_num = span_num;
+
+ if (event) {
+ week_view->drag_event_x = event->button.x;
+ week_view->drag_event_y = event->button.y;
+ } else
+ g_warning ("No GdkEvent");
+
+ /* FIXME: Remember the day offset from the start of
+ the event. */
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (!E_TEXT (item)->editing) {
gtk_signal_emit_stop_by_name (GTK_OBJECT (item),
"event");
+
+ if (!e_week_view_find_event_from_item (week_view,
+ item,
+ &event_num,
+ &span_num))
+ return FALSE;
+
+ if (week_view->pressed_event_num != -1
+ && week_view->pressed_event_num == event_num
+ && week_view->pressed_span_num == span_num) {
+ e_week_view_start_editing_event (week_view,
+ event_num,
+ span_num,
+ NULL);
+ week_view->pressed_event_num = -1;
+ return TRUE;
+ }
+ }
+ week_view->pressed_event_num = -1;
break;
case GDK_FOCUS_CHANGE:
- if (event->focus_change.in)
+ if (event->focus_change.in) {
+ g_print ("Item got keyboard focus\n");
e_week_view_on_editing_started (week_view, item);
- else
+ } else {
+ g_print ("Item lost keyboard focus\n");
e_week_view_on_editing_stopped (week_view, item);
+ }
return FALSE;
default:
@@ -2059,6 +2284,11 @@ e_week_view_on_editing_stopped (EWeekView *week_view,
/* Reset the edit fields. */
week_view->editing_event_num = -1;
+ week_view->editing_new_event = FALSE;
+
+ /* Check that the event is still valid. */
+ if (!event->ico->uid)
+ return;
gtk_object_get (GTK_OBJECT (span->text_item),
"text", &text,
@@ -2117,8 +2347,8 @@ e_week_view_find_event_from_item (EWeekView *week_view,
static gboolean
-e_week_view_find_event_from_ico (EWeekView *week_view,
- iCalObject *ico,
+e_week_view_find_event_from_uid (EWeekView *week_view,
+ const gchar *uid,
gint *event_num_return)
{
EWeekViewEvent *event;
@@ -2128,7 +2358,8 @@ e_week_view_find_event_from_ico (EWeekView *week_view,
for (event_num = 0; event_num < num_events; event_num++) {
event = &g_array_index (week_view->events, EWeekViewEvent,
event_num);
- if (event->ico == ico) {
+ if (event->ico && event->ico->uid
+ && !strcmp (uid, event->ico->uid)) {
*event_num_return = event_num;
return TRUE;
}
@@ -2212,35 +2443,93 @@ e_week_view_key_press (GtkWidget *widget, GdkEventKey *event)
ico->dtstart = week_view->day_starts[week_view->selection_start_day];
ico->dtend = week_view->day_starts[week_view->selection_end_day + 1];
- gnome_calendar_add_object (week_view->calendar, ico);
+ /* We add the event locally and start editing it. When we get the
+ "update_event" callback from the server, we basically ignore it.
+ If we were to wait for the "update_event" callback it wouldn't be
+ as responsive and we may lose a few keystrokes. */
+ e_week_view_add_event (ico, ico->dtstart, ico->dtend, week_view);
+ e_week_view_check_layout (week_view);
+ gtk_widget_queue_draw (week_view->main_canvas);
- /* gnome_calendar_add_object() should have resulted in a call to
- e_week_view_update_event(), so the new event should now be layed
- out. So we try to find it so we can start editing it. */
- if (e_week_view_find_event_from_ico (week_view, ico, &event_num)) {
- /* Start editing the new event. */
+ if (e_week_view_find_event_from_uid (week_view, ico->uid,
+ &event_num)) {
e_week_view_start_editing_event (week_view, event_num, 0,
initial_text);
+ week_view->editing_new_event = TRUE;
+ } else {
+ g_warning ("Couldn't find event to start editing.\n");
}
+ gnome_calendar_add_object (week_view->calendar, ico);
+
return TRUE;
}
-static void
-e_week_view_show_popup_menu (EWeekView *week_view,
- GdkEventButton *event,
- gint day)
+void
+e_week_view_show_popup_menu (EWeekView *week_view,
+ GdkEventButton *bevent,
+ gint event_num)
{
+ EWeekViewEvent *event;
+ int have_selection, not_being_edited, num_items, i;
+ struct menu_item *context_menu;
+
static struct menu_item items[] = {
{ N_("New appointment..."), (GtkSignalFunc) e_week_view_on_new_appointment, NULL, TRUE }
};
- items[0].data = week_view;
+ static struct menu_item child_items[] = {
+ { N_("Edit this appointment..."), (GtkSignalFunc) e_week_view_on_edit_appointment, NULL, TRUE },
+ { N_("Delete this appointment"), (GtkSignalFunc) e_week_view_on_delete_appointment, NULL, TRUE },
+ { NULL, NULL, NULL, TRUE },
+ { N_("New appointment..."), (GtkSignalFunc) e_week_view_on_new_appointment, NULL, TRUE }
+ };
+
+ static struct menu_item recur_child_items[] = {
+ { N_("Make this appointment movable"), (GtkSignalFunc) e_week_view_on_unrecur_appointment, NULL, TRUE },
+ { N_("Edit this appointment..."), (GtkSignalFunc) e_week_view_on_edit_appointment, NULL, TRUE },
+ { N_("Delete this occurance"), (GtkSignalFunc) e_week_view_on_delete_occurance, NULL, TRUE },
+ { N_("Delete all occurances"), (GtkSignalFunc) e_week_view_on_delete_appointment, NULL, TRUE },
+ { NULL, NULL, NULL, TRUE },
+ { N_("New appointment..."), (GtkSignalFunc) e_week_view_on_new_appointment, NULL, TRUE }
+ };
+
+ have_selection = GTK_WIDGET_HAS_FOCUS (week_view)
+ && week_view->selection_start_day != -1;
+
+ if (event_num == -1) {
+ num_items = 1;
+ context_menu = &items[0];
+ context_menu[0].sensitive = have_selection;
+ } else {
+ event = &g_array_index (week_view->events,
+ EWeekViewEvent, event_num);
+
+ /* Check if the event is being edited in the event editor. */
+ not_being_edited = (event->ico->user_data == NULL);
+
+ if (event->ico->recur) {
+ num_items = 6;
+ context_menu = &recur_child_items[0];
+ context_menu[3].sensitive = not_being_edited;
+ context_menu[5].sensitive = have_selection;
+ } else {
+ num_items = 4;
+ context_menu = &child_items[0];
+ context_menu[3].sensitive = have_selection;
+ }
+ /* These settings are common for each context sensitive menu */
+ context_menu[0].sensitive = not_being_edited;
+ context_menu[1].sensitive = not_being_edited;
+ context_menu[2].sensitive = not_being_edited;
+ }
+
+ for (i = 0; i < num_items; i++)
+ context_menu[i].data = week_view;
- week_view->popup_event_day = day;
- week_view->popup_event_num = -1;
- popup_menu (items, 1, event);
+ week_view->popup_event_num = event_num;
+ popup_menu (context_menu, num_items, bevent);
}
@@ -2255,11 +2544,97 @@ e_week_view_on_new_appointment (GtkWidget *widget, gpointer data)
ico = ical_new ("", user_name, "");
ico->new = 1;
- ico->dtstart = week_view->day_starts[week_view->popup_event_day];
- ico->dtend = week_view->day_starts[week_view->popup_event_day + 1];
+ ico->dtstart = week_view->day_starts[week_view->selection_start_day];
+ ico->dtend = week_view->day_starts[week_view->selection_end_day + 1];
event_editor = event_editor_new (week_view->calendar, ico);
gtk_widget_show (event_editor);
}
+static void
+e_week_view_on_edit_appointment (GtkWidget *widget, gpointer data)
+{
+ EWeekView *week_view;
+ EWeekViewEvent *event;
+ GtkWidget *event_editor;
+
+ week_view = E_WEEK_VIEW (data);
+
+ if (week_view->popup_event_num == -1)
+ return;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent,
+ week_view->popup_event_num);
+
+ event_editor = event_editor_new (week_view->calendar, event->ico);
+ gtk_widget_show (event_editor);
+}
+
+
+static void
+e_week_view_on_delete_occurance (GtkWidget *widget, gpointer data)
+{
+ EWeekView *week_view;
+ EWeekViewEvent *event;
+
+ week_view = E_WEEK_VIEW (data);
+
+ if (week_view->popup_event_num == -1)
+ return;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent,
+ week_view->popup_event_num);
+
+ ical_object_add_exdate (event->ico, event->start);
+ gnome_calendar_object_changed (week_view->calendar, event->ico,
+ CHANGE_DATES);
+}
+
+
+static void
+e_week_view_on_delete_appointment (GtkWidget *widget, gpointer data)
+{
+ EWeekView *week_view;
+ EWeekViewEvent *event;
+
+ week_view = E_WEEK_VIEW (data);
+
+ if (week_view->popup_event_num == -1)
+ return;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent,
+ week_view->popup_event_num);
+
+ gnome_calendar_remove_object (week_view->calendar, event->ico);
+}
+
+
+static void
+e_week_view_on_unrecur_appointment (GtkWidget *widget, gpointer data)
+{
+ EWeekView *week_view;
+ EWeekViewEvent *event;
+ iCalObject *ico;
+
+ week_view = E_WEEK_VIEW (data);
+
+ if (week_view->popup_event_num == -1)
+ return;
+
+ event = &g_array_index (week_view->events, EWeekViewEvent,
+ week_view->popup_event_num);
+
+ /* New object */
+ ico = ical_object_duplicate (event->ico);
+ g_free (ico->recur);
+ ico->recur = 0;
+ ico->dtstart = event->start;
+ ico->dtend = event->end;
+
+ /* Duplicate, and eliminate the recurrency fields */
+ ical_object_add_exdate (event->ico, event->start);
+ gnome_calendar_object_changed (week_view->calendar, event->ico,
+ CHANGE_ALL);
+ gnome_calendar_add_object (week_view->calendar, ico);
+}
diff --git a/calendar/gui/e-week-view.h b/calendar/gui/e-week-view.h
index eac23565c2..c940f736d4 100644
--- a/calendar/gui/e-week-view.h
+++ b/calendar/gui/e-week-view.h
@@ -279,8 +279,12 @@ struct _EWeekView
gint editing_event_num;
gint editing_span_num;
- /* The day or event that the context menu is for. */
- gint popup_event_day;
+ /* This is TRUE if we are editing an event which we have just created.
+ We ignore the "update_event" callback which we will get from the
+ server when the event is added. */
+ gboolean editing_new_event;
+
+ /* The event that the context menu is for. */
gint popup_event_num;
/* The last mouse position when dragging, in the entire canvas. */
@@ -318,13 +322,18 @@ gboolean e_week_view_get_compress_weekend (EWeekView *week_view);
void e_week_view_set_compress_weekend (EWeekView *week_view,
gboolean compress);
-/* This is called when one or more events have been updated, either within the
- EWeekView itself, or via another calendar view or application. If only one
- event has changed, it is passed in the ico argument and the flags indicate
- the change - whether it is a new event, or just the summary has changed. */
+/* This reloads all calendar events. */
+void e_week_view_update_all_events (EWeekView *week_view);
+
+/* This is called when one event has been added or updated. */
void e_week_view_update_event (EWeekView *week_view,
- iCalObject *ico,
- int flags);
+ const gchar *uid);
+
+/* This removes all the events associated with the given uid. Note that for
+ recurring events there may be more than one. If any events are found and
+ removed we need to layout the events again. */
+void e_week_view_remove_event (EWeekView *week_view,
+ const gchar *uid);
/*
@@ -350,6 +359,10 @@ void e_week_view_start_editing_event (EWeekView *week_view,
gchar *initial_text);
void e_week_view_stop_editing_event (EWeekView *week_view);
+void e_week_view_show_popup_menu (EWeekView *week_view,
+ GdkEventButton *event,
+ gint event_num);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c
index 763fd5eac4..cb37240ba4 100644
--- a/calendar/gui/gnome-cal.c
+++ b/calendar/gui/gnome-cal.c
@@ -385,20 +385,20 @@ gnome_calendar_set_view (GnomeCalendar *gcal, char *page_name)
}
+/* This tells all components to reload all calendar objects. */
static void
gnome_calendar_update_all (GnomeCalendar *cal, iCalObject *object, int flags)
{
- e_day_view_update_event (E_DAY_VIEW (cal->day_view),
- object, flags);
- e_day_view_update_event (E_DAY_VIEW (cal->work_week_view),
- object, flags);
- e_week_view_update_event (E_WEEK_VIEW (cal->week_view),
- object, flags);
- e_week_view_update_event (E_WEEK_VIEW (cal->month_view),
- object, flags);
- year_view_update (YEAR_VIEW (cal->year_view), object, flags);
-
- gncal_todo_update (GNCAL_TODO (cal->todo), object, flags);
+ e_day_view_update_all_events (E_DAY_VIEW (cal->day_view));
+ e_day_view_update_all_events (E_DAY_VIEW (cal->work_week_view));
+ e_week_view_update_all_events (E_WEEK_VIEW (cal->week_view));
+ e_week_view_update_all_events (E_WEEK_VIEW (cal->month_view));
+
+#if 0
+ year_view_update (YEAR_VIEW (cal->year_view), NULL, TRUE);
+#endif
+
+ gncal_todo_update (GNCAL_TODO (cal->todo), NULL, TRUE);
gnome_calendar_tag_calendar (cal, cal->gtk_calendar);
}
@@ -410,7 +410,22 @@ gnome_calendar_object_updated_cb (GtkWidget *cal_client,
{
printf ("gnome-cal: got object changed_cb, uid='%s'\n",
uid?uid:"<NULL>");
- gnome_calendar_update_all (gcal, NULL, CHANGE_NEW);
+
+ /* FIXME: do we really want each view to reload the event itself?
+ Maybe we should keep track of events globally, maybe with ref
+ counts. We also need to sort out where they get freed. */
+ e_day_view_update_event (E_DAY_VIEW (gcal->day_view), uid);
+ e_day_view_update_event (E_DAY_VIEW (gcal->work_week_view), uid);
+ e_week_view_update_event (E_WEEK_VIEW (gcal->week_view), uid);
+ e_week_view_update_event (E_WEEK_VIEW (gcal->month_view), uid);
+
+ /* FIXME: optimize these? */
+#if 0
+ year_view_update (YEAR_VIEW (gcal->year_view), NULL, TRUE);
+#endif
+
+ gncal_todo_update (GNCAL_TODO (gcal->todo), NULL, TRUE);
+ gnome_calendar_tag_calendar (gcal, gcal->gtk_calendar);
}
@@ -421,7 +436,18 @@ gnome_calendar_object_removed_cb (GtkWidget *cal_client,
{
printf ("gnome-cal: got object removed _cb, uid='%s'\n",
uid?uid:"<NULL>");
- gnome_calendar_update_all (gcal, NULL, CHANGE_ALL);
+
+ e_day_view_remove_event (E_DAY_VIEW (gcal->day_view), uid);
+ e_day_view_remove_event (E_DAY_VIEW (gcal->work_week_view), uid);
+ e_week_view_remove_event (E_WEEK_VIEW (gcal->week_view), uid);
+ e_week_view_remove_event (E_WEEK_VIEW (gcal->month_view), uid);
+
+ /* FIXME: optimize these? */
+#if 0
+ year_view_update (YEAR_VIEW (gcal->year_view), NULL, CHANGE_ALL);
+#endif
+ gncal_todo_update (GNCAL_TODO (gcal->todo), NULL, CHANGE_ALL);
+ gnome_calendar_tag_calendar (gcal, gcal->gtk_calendar);
}
@@ -794,20 +820,23 @@ static int
mark_gtk_calendar_day (iCalObject *obj, time_t start, time_t end, void *c)
{
GtkCalendar *gtk_cal = c;
- struct tm tm_s;
- time_t t, day_end;
+ struct tm tm_s, tm_e;
+ gint start_day, end_day, day;
tm_s = *localtime (&start);
- day_end = time_day_end (end);
+ tm_e = *localtime (&end);
- for (t = start; t <= day_end; t += 60*60*24){
- time_t new = mktime (&tm_s);
- struct tm tm_day;
+ start_day = tm_s.tm_mday;
+ end_day = tm_e.tm_mday;
+
+ /* If the event ends at midnight then really it ends on the previous
+ day (unless it started at the same time). */
+ if (start != end && tm_e.tm_hour == 0 && tm_e.tm_min == 0)
+ end_day--;
+
+ for (day = start_day; day <= end_day; day++)
+ gtk_calendar_mark_day (gtk_cal, day);
- tm_day = *localtime (&new);
- gtk_calendar_mark_day (gtk_cal, tm_day.tm_mday);
- tm_s.tm_mday++;
- }
return TRUE;
}