[california/wip/725787-remove-recurring: 8/8] API development
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california/wip/725787-remove-recurring: 8/8] API development
- Date: Wed, 2 Jul 2014 19:45:47 +0000 (UTC)
commit b0f83bacd42f8a2c235d5446ee100e2a7bdb2f01
Author: Jim Nelson <jim yorba org>
Date: Wed Jul 2 12:44:40 2014 -0700
API development
Examining Evolution, need to re-think how signals from ClientView are
handled in relation to how instances are handled internally.
.../backing-calendar-source-subscription.vala | 7 +++
src/backing/backing-calendar-source.vala | 54 +++++++++++++++++--
src/backing/eds/backing-eds-calendar-source.vala | 44 +++++++++++++++-
src/component/component-date-time.vala | 6 ++-
src/host/host-show-event.vala | 37 ++++++++++----
vapi/libecal-1.2.vapi | 21 ++++----
vapi/libecal-1.2/libecal-1.2.metadata | 4 +-
7 files changed, 142 insertions(+), 31 deletions(-)
---
diff --git a/src/backing/backing-calendar-source-subscription.vala
b/src/backing/backing-calendar-source-subscription.vala
index 71216fd..12a1342 100644
--- a/src/backing/backing-calendar-source-subscription.vala
+++ b/src/backing/backing-calendar-source-subscription.vala
@@ -9,6 +9,13 @@ namespace California.Backing {
/**
* A subscription to an active timespan of interest of a calendar.
*
+ * CalendarSourceSubscription generates { link Component.Instance}s of the various events in a
+ * window of time in a calendar. Note that for recurring events, there is no interface to directly
+ * edit or remove the "original" iCalendar source. Rather, the caller should update or remove
+ * generated instances of that recurring event with flags to indicate how the original is to be
+ * altered to match these changes. See { link CalendarSource} for the interface to make these
+ * alterations.
+ *
* The subscription can notify of calendar event updates and list a complete or partial collections
* of the same.
*/
diff --git a/src/backing/backing-calendar-source.vala b/src/backing/backing-calendar-source.vala
index 1cd6cde..4286b67 100644
--- a/src/backing/backing-calendar-source.vala
+++ b/src/backing/backing-calendar-source.vala
@@ -9,11 +9,40 @@ namespace California.Backing {
/**
* An abstract representation of a backing source of calendar information.
*
+ * CalendarSource provides information about the calendar and an interface for operating on
+ * { link Component.Instance}s in the calendar. Use { link CalendarSourceSubscription} to generate
+ * those instances for specific windows of time.
+ *
* @see Manager
* @see Source
*/
public abstract class CalendarSource : Source {
+ /**
+ * The affected range of a modification or removal operation.
+ *
+ * Note that zero (0) does ''not'' mean "none", it means { link AffectedInstances.THIS}. The
+ * additional enums merely expand the scope of the default, which is the supplied instance.
+ */
+ public enum AffectedInstances {
+ /**
+ * Include the supplied { link Component.Instance} in the affected instances.
+ */
+ THIS = 0,
+ /**
+ * Include all prior { link Component.Instance}s in the affected instances.
+ */
+ THIS_AND_PRIOR,
+ /**
+ * Include all future { link Component.Instance}s in the affected instances.
+ */
+ THIS_AND_FUTURE,
+ /**
+ * Indicating all { link Component.Instance}s should be affected.
+ */
+ ALL
+ }
+
protected CalendarSource(string id, string title) {
base (id, title);
}
@@ -28,9 +57,10 @@ public abstract class CalendarSource : Source {
* Creates a new { link Component} instance on the backing { link CalendarSource}.
*
* Outstanding { link CalendarSourceSubscriptions} will eventually report the generated
- * instance when it's available.
+ * instance when it's available. If the supplied instance includes an RRULE (i.e.
+ * { link Component.Instance.rrule}), one or more instances will be generated.
*
- * @returns The { link Component.UID}.of the generated instance, if available.
+ * @returns The { link Component.UID}.keyed to all instances, if available.
*/
public abstract async Component.UID? create_component_async(Component.Instance instance,
Cancellable? cancellable = null) throws Error;
@@ -45,15 +75,27 @@ public abstract class CalendarSource : Source {
Cancellable? cancellable = null) throws Error;
/**
- * Destroys (removes) a { link Component} instance on the backing { link CalendarSource}.
+ * Destroys (removes) all { link Component.Instance}s on the backing { link CalendarSource}
+ * keyed to the supplied { link Component.UID}.
*
- * Outstanding { link CalendarSourceSubscriptions} will eventually report the instance as
- * removed.
+ * Outstanding { link CalendarSourceSubscriptions} will eventually report all affected instances
+ * as removed.
*/
- public abstract async void remove_component_async(Component.UID uid,
+ public abstract async void remove_all_instances_async(Component.UID uid,
Cancellable? cancellable = null) throws Error;
/**
+ * Destroys (removes) some or all { link Component.Instance}s on the backing
+ * { link CalendarSource} keyed to the supplied { link Component.UID}, the supplied RID,
+ * and the { link AffectedInstances}.
+ *
+ * Outstanding { link CalendarSourceSubscriptions} will eventually report all affected instances
+ * as removed.
+ */
+ public abstract async void remove_instances_async(Component.UID uid, Component.DateTime rid,
+ AffectedInstances affected, Cancellable? cancellable = null) throws Error;
+
+ /**
* Imports a { link Component.iCalendar} into the { link CalendarSource}.
*/
public abstract async void import_icalendar_async(Component.iCalendar ical, Cancellable? cancellable =
null)
diff --git a/src/backing/eds/backing-eds-calendar-source.vala
b/src/backing/eds/backing-eds-calendar-source.vala
index 984f778..292359e 100644
--- a/src/backing/eds/backing-eds-calendar-source.vala
+++ b/src/backing/eds/backing-eds-calendar-source.vala
@@ -118,6 +118,31 @@ internal class EdsCalendarSource : CalendarSource {
read_only = true;
}
+ // Note that E.CalObjModType.ONLY_THIS is *never* returned ... examining EDS source code,
+ // it appears in e-cal-backend-file.c that ONLY_THIS merely removes the instance but does not
+ // include an EXDATE in the original iCal source ... I don't quite understand the benefit of
+ // this, as this suggests (a) other calendar clients won't learn of the removal and (b) the
+ // instance will be re-generated the next time the user runs an EDS calendar client. In either
+ // case, ONLY maps to our desired effect by adding an EXDATE to the iCal source.
+ private E.CalObjModType convert_to_obj_mod_type(CalendarSource.AffectedInstances affected) {
+ switch (affected) {
+ case CalendarSource.AffectedInstances.THIS:
+ return E.CalObjModType.THIS;
+
+ case CalendarSource.AffectedInstances.THIS_AND_FUTURE:
+ return E.CalObjModType.THIS_AND_FUTURE;
+
+ case CalendarSource.AffectedInstances.THIS_AND_PRIOR:
+ return E.CalObjModType.THIS_AND_PRIOR;
+
+ case CalendarSource.AffectedInstances.ALL:
+ return E.CalObjModType.ALL;
+
+ default:
+ assert_not_reached();
+ }
+ }
+
private void check_open() throws BackingError {
if (client == null)
throw new BackingError.UNAVAILABLE("%s has been removed", to_string());
@@ -155,11 +180,26 @@ internal class EdsCalendarSource : CalendarSource {
yield client.modify_object(instance.ical_component, E.CalObjModType.THIS, cancellable);
}
- public override async void remove_component_async(Component.UID uid,
+ public override async void remove_all_instances_async(Component.UID uid,
Cancellable? cancellable = null) throws Error {
check_open();
- yield client.remove_object(uid.value, null, E.CalObjModType.THIS, cancellable);
+ yield client.remove_object(uid.value, null, E.CalObjModType.ALL, cancellable);
+ }
+
+ public override async void remove_instances_async(Component.UID uid, Component.DateTime rid,
+ CalendarSource.AffectedInstances affected, Cancellable? cancellable = null) throws Error {
+ check_open();
+
+ E.CalObjModType mod_type = convert_to_obj_mod_type(affected);
+
+ debug("remove_instances_async: UID=%s RID=%s MOD_TYPE=%Xh", uid.value, rid.value, mod_type);
+
+ // special-case ALL
+ if (mod_type == E.CalObjModType.ALL)
+ yield remove_all_instances_async(uid, cancellable);
+ else
+ yield client.remove_object(uid.value, rid.value, mod_type, cancellable);
}
public override async void import_icalendar_async(Component.iCalendar ical, Cancellable? cancellable =
null)
diff --git a/src/component/component-date-time.vala b/src/component/component-date-time.vala
index 685949c..0a64cbc 100644
--- a/src/component/component-date-time.vala
+++ b/src/component/component-date-time.vala
@@ -46,8 +46,10 @@ public class DateTime : BaseObject, Gee.Hashable<DateTime>, Gee.Comparable<DateT
/**
* Returns the original iCalendar string representing the DATE/DATE-TIME property value.
+ *
+ * This does not include the iCal key string preceding the value, i.e. "DTSTAMP:"
*/
- public string value_as_ical_string { get; private set; }
+ public string value { get; private set; }
/**
* The DATE-TIME for the iCal component and property kind.
@@ -119,7 +121,7 @@ public class DateTime : BaseObject, Gee.Hashable<DateTime>, Gee.Comparable<DateT
}
kind = ical_prop_kind;
- value_as_ical_string = prop.get_value_as_string();
+ value = prop.get_value_as_string();
}
/**
diff --git a/src/host/host-show-event.vala b/src/host/host-show-event.vala
index 5cdc044..142a402 100644
--- a/src/host/host-show-event.vala
+++ b/src/host/host-show-event.vala
@@ -83,7 +83,7 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
// If recurring (and so this is a generated instance of the VEVENT, not the VEVENT itself),
// use a popup menu to ask how to remove this event
- if (event.is_recurring_generated) {
+ if (event.is_recurring) {
remove_recurring_menu = new Gtk.Menu();
Gtk.MenuItem remove_all = new Gtk.MenuItem.with_mnemonic(_("Remove _All Events"));
@@ -98,13 +98,18 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
_("Remove This and All _Following Events"));
remove_following.activate.connect(on_remove_recurring_this_and_following);
remove_recurring_menu.append(remove_following);
+
+ Gtk.MenuItem remove_prior = new Gtk.MenuItem.with_mnemonic(
+ _("Remove This and All _Prior Events"));
+ remove_prior.activate.connect(on_remove_recurring_this_and_prior);
+ remove_recurring_menu.append(remove_prior);
}
// don't current support updating or removing recurring events properly; see
// https://bugzilla.gnome.org/show_bug.cgi?id=725786
bool read_only = event.calendar_source != null && event.calendar_source.read_only;
- bool updatable = !event.is_recurring_generated && !read_only;
+ bool updatable = !event.is_recurring && !read_only;
update_button.visible = updatable;
update_button.no_show_all = updatable;
@@ -151,7 +156,7 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
[GtkCallback]
private void on_remove_button_clicked() {
- if (event.is_recurring_generated) {
+ if (event.is_recurring) {
assert(remove_recurring_menu != null);
remove_recurring_menu.popup(null, null, null, 0, Gtk.get_current_event_time());
@@ -160,7 +165,7 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
return;
}
- remove_event_async.begin();
+ remove_events_async.begin(null, Backing.CalendarSource.AffectedInstances.ALL);
}
[GtkCallback]
@@ -173,32 +178,44 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
notify_user_closed();
}
- private async void remove_event_async() {
+ private async void remove_events_async(Component.DateTime? rid,
+ Backing.CalendarSource.AffectedInstances affected) {
Gdk.Cursor? cursor = Toolkit.set_busy(this);
Error? remove_err = null;
try {
- yield event.calendar_source.remove_component_async(event.uid, null);
+ if (rid == null || affected == Backing.CalendarSource.AffectedInstances.ALL)
+ yield event.calendar_source.remove_all_instances_async(event.uid, null);
+ else
+ yield event.calendar_source.remove_instances_async(event.uid, rid, affected, null);
} catch (Error err) {
remove_err = err;
}
Toolkit.set_unbusy(this, cursor);
- if (remove_err == null)
+ if (remove_err == null) {
notify_success();
- else
- notify_failure(_("Unable to remove event: %s").printf(remove_err.message));
+ } else {
+ notify_failure(ngettext("Unable to remove event: %s", "Unable to remove events: %s",
+ rid == null ? 1 : 2).printf(remove_err.message));
+ }
}
private void on_remove_recurring_all() {
- remove_event_async.begin();
+ remove_events_async.begin(null, Backing.CalendarSource.AffectedInstances.ALL);
}
private void on_remove_recurring_this() {
+ remove_events_async.begin(event.rid, Backing.CalendarSource.AffectedInstances.THIS);
}
private void on_remove_recurring_this_and_following() {
+ remove_events_async.begin(event.rid, Backing.CalendarSource.AffectedInstances.THIS_AND_FUTURE);
+ }
+
+ private void on_remove_recurring_this_and_prior() {
+ remove_events_async.begin(event.rid, Backing.CalendarSource.AffectedInstances.THIS_AND_PRIOR);
}
}
diff --git a/vapi/libecal-1.2.vapi b/vapi/libecal-1.2.vapi
index e414c46..7952301 100644
--- a/vapi/libecal-1.2.vapi
+++ b/vapi/libecal-1.2.vapi
@@ -248,6 +248,17 @@ namespace E {
public void set_repeat (E.CalComponentAlarmRepeat repeat);
public void set_trigger (E.CalComponentAlarmTrigger trigger);
}
+ [CCode (cheader_filename = "libecal/libecal.h", copy_function = "e_cal_component_id_copy",
free_function = "e_cal_component_free_id")]
+ [Compact]
+ public class CalComponentId {
+ public weak string rid;
+ public weak string uid;
+ [CCode (has_construct_function = false)]
+ public CalComponentId (string uid, string rid);
+ public E.CalComponentId copy ();
+ public bool equal (E.CalComponentId id2);
+ public uint hash ();
+ }
[CCode (cheader_filename = "libecal/libecal.h")]
public interface TimezoneCache : GLib.Object {
public abstract unowned GLib.List list_timezones ();
@@ -301,16 +312,6 @@ namespace E {
public weak string tzid;
}
[CCode (cheader_filename = "libecal/libecal.h")]
- public struct CalComponentId {
- public weak string uid;
- public weak string rid;
- [CCode (has_construct_function = false)]
- public CalComponentId (string uid, string rid);
- public E.CalComponentId copy ();
- public bool equal (E.CalComponentId id2);
- public uint hash ();
- }
- [CCode (cheader_filename = "libecal/libecal.h")]
public struct CalComponentOrganizer {
public weak string value;
public weak string sentby;
diff --git a/vapi/libecal-1.2/libecal-1.2.metadata b/vapi/libecal-1.2/libecal-1.2.metadata
index 0d82150..951af62 100644
--- a/vapi/libecal-1.2/libecal-1.2.metadata
+++ b/vapi/libecal-1.2/libecal-1.2.metadata
@@ -234,7 +234,9 @@ ECalComponentAttendee is_value_type="1"
ECalComponentDateTime is_value_type="1" has_destroy_function="0"
ECalComponentDateTime.value type_name="iCal.icaltimetype*"
-ECalComponentId is_value_type="1"
+ECalComponentId is_value_type="0" free_function="e_cal_component_free_id"
+e_cal_component_id_copy transfer_ownership="1"
+
ECalComponentOrganizer is_value_type="1"
ECalComponentPeriod is_value_type="1"
ECalComponentPeriod.start type_name="iCal.icaltimetype"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]