Gone is a utility that locks a terminal with a password chosen by the user. Gone will prompt the user for a password (unless the -p option is given, then gone will use the system password), then print the gone banner, then drop into the gone shell. From this shell, only a restricted set of commands can be run. Gone will also disallow messages by removing permissions on the parent tty. After the timeout period (10 minutes by default), gone will automatically log the user out. -Joe marcus@marcuscom.com 13-evolution' title='gsoc2013-evolution Git repository'/>
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.gz
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;
}