[california/wip/725787-remove-recurring] Improvements



commit 0ef789a0c33bebd92294d55f9da26b9e4df456f1
Author: Jim Nelson <jim yorba org>
Date:   Wed Jul 2 19:27:57 2014 -0700

    Improvements

 src/backing/eds/backing-eds-calendar-source.vala |  119 ++++++++++++++++------
 src/component/component-date-time.vala           |    2 +-
 src/host/host-show-event.vala                    |    2 +
 vapi/libecal-1.2.vapi                            |    3 +-
 vapi/libecal-1.2/libecal-1.2.metadata            |    7 +-
 vapi/libical.vapi                                |    6 +-
 6 files changed, 101 insertions(+), 38 deletions(-)
---
diff --git a/src/backing/eds/backing-eds-calendar-source.vala 
b/src/backing/eds/backing-eds-calendar-source.vala
index 292359e..f68da03 100644
--- a/src/backing/eds/backing-eds-calendar-source.vala
+++ b/src/backing/eds/backing-eds-calendar-source.vala
@@ -118,31 +118,6 @@ 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());
@@ -191,15 +166,95 @@ internal class EdsCalendarSource : CalendarSource {
         CalendarSource.AffectedInstances affected, Cancellable? cancellable = null) throws Error {
         check_open();
         
-        E.CalObjModType mod_type = convert_to_obj_mod_type(affected);
+        // Note that E.CalObjModType.ONLY_THIS is *never* used ... 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.
+        switch (affected) {
+            case CalendarSource.AffectedInstances.THIS:
+                yield client.remove_object(uid.value, rid.value, E.CalObjModType.THIS, cancellable);
+            break;
+            
+            case CalendarSource.AffectedInstances.THIS_AND_FUTURE:
+                yield remove_future_async(uid, rid, cancellable);
+            break;
+            
+            case CalendarSource.AffectedInstances.THIS_AND_PRIOR:
+                yield remove_prior_async(uid, rid, cancellable);
+            break;
+            
+            case CalendarSource.AffectedInstances.ALL:
+                yield remove_all_instances_async(uid, cancellable);
+            break;
+            
+            default:
+                assert_not_reached();
+        }
+    }
+    
+    private async void remove_future_async(Component.UID uid, Component.DateTime rid,
+        Cancellable? cancellable) throws Error {
+        // get the master instance ... remember that the Backing.CalendarSource only stores generated
+        // instances
+        iCal.icalcomponent ical_component;
+        yield client.get_object(uid.value, null, cancellable, out ical_component);
+        
+        // change the RRULE's UNTIL indicating the end of the recurring set (which is, handily enough,
+        // the RID)
+        unowned iCal.icalproperty? rrule_property = ical_component.get_first_property(
+            iCal.icalproperty_kind.RRULE_PROPERTY);
+        if (rrule_property == null)
+            return;
+        
+        iCal.icalrecurrencetype rrule = rrule_property.get_rrule();
+        
+        // In order to be inclusive, need to set UNTIL one tick earlier to ensure the supplied RID
+        // is now excluded
+        if (rid.is_date) {
+            Component.date_to_ical(rid.to_date().previous(), &rrule.until);
+        } else {
+            Component.exact_time_to_ical(rid.to_exact_time().adjust_time(-1, Calendar.TimeUnit.SECOND),
+                &rrule.until);
+        }
+        
+        // COUNT and UNTIL are mutually exclusive in an RRULE ... COUNT can be reliably reset
+        // because the RID enforces a new de facto COUNT (assuming the RID originated from the UID's
+        // recurring instance; if not, the user has screwed up)
+        rrule.count = 0;
+        
+        rrule_property.set_rrule(rrule);
+        
+        // write it out ... essentially, this style of remove is actually an update
+        yield client.modify_object(ical_component, E.CalObjModType.THIS, cancellable);
+    }
+    
+    private async void remove_prior_async(Component.UID uid, Component.DateTime rid,
+        Cancellable? cancellable) throws Error {
+        // get the master instance ... remember that the Backing.CalendarSource only stores generated
+        // instances
+        iCal.icalcomponent ical_component;
+        yield client.get_object(uid.value, null, cancellable, out ical_component);
+        
+        // like remove_future_async(), need to set DTSTART one tick forward to ensure the supplied
+        // RID is now excluded
+        //
+        // TODO: DTSTART needs to be synchronized with recurrences, so this is a no-go
+        iCal.icaltimetype dtstart = {};
+        if (rid.is_date) {
+            Component.date_to_ical(rid.to_date().next(), &dtstart);
+        } else {
+            Component.exact_time_to_ical(rid.to_exact_time().adjust_time(1, Calendar.TimeUnit.SECOND),
+                &dtstart);
+        }
         
-        debug("remove_instances_async: UID=%s RID=%s MOD_TYPE=%Xh", uid.value, rid.value, mod_type);
+        // change the DTSTART indicating the start of the recurring set (which is, handily enough,
+        // the RID)
+        ical_component.set_dtstart(dtstart);
         
-        // 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);
+        // write it out ... essentially, this style of remove is actually an update
+        yield client.modify_object(ical_component, E.CalObjModType.THIS, 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 0a64cbc..d52bd00 100644
--- a/src/component/component-date-time.vala
+++ b/src/component/component-date-time.vala
@@ -169,7 +169,7 @@ public class DateTime : BaseObject, Gee.Hashable<DateTime>, Gee.Comparable<DateT
      *
      * Returns null if { link is_date} is true.
      */
-    public Calendar.ExactTime? to_exact_time() throws CalendarError{
+    public Calendar.ExactTime? to_exact_time() throws CalendarError {
         if (is_date)
             return null;
         
diff --git a/src/host/host-show-event.vala b/src/host/host-show-event.vala
index 142a402..deced98 100644
--- a/src/host/host-show-event.vala
+++ b/src/host/host-show-event.vala
@@ -69,6 +69,8 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
     }
     
     private void build_display() {
+        debug("%s\n", event.source);
+        
         // summary
         set_label(null, summary_text, event.summary);
         
diff --git a/vapi/libecal-1.2.vapi b/vapi/libecal-1.2.vapi
index 54894e7..4d9a21a 100644
--- a/vapi/libecal-1.2.vapi
+++ b/vapi/libecal-1.2.vapi
@@ -51,7 +51,8 @@ namespace E {
                public async bool get_free_busy (ulong start, ulong end, GLib.SList users, GLib.Cancellable? 
cancellable) throws GLib.Error;
                public bool get_free_busy_sync (ulong start, ulong end, GLib.SList users, GLib.Cancellable? 
cancellable) throws GLib.Error;
                public unowned string get_local_attachment_store ();
-               public async bool get_object (string uid, string rid, GLib.Cancellable? cancellable, out 
unowned iCal.icalcomponent out_icalcomp) throws GLib.Error;
+               [CCode (finish_name = "e_cal_client_get_object_finish")]
+               public async void get_object (string uid, string? rid, GLib.Cancellable? cancellable, out 
iCal.icalcomponent out_icalcomp) throws GLib.Error;
                public async bool get_object_list (string sexp, GLib.Cancellable? cancellable) throws 
GLib.Error;
                public async bool get_object_list_as_comps (string sexp, GLib.Cancellable? cancellable) 
throws GLib.Error;
                public bool get_object_list_as_comps_sync (string sexp, GLib.SList out_ecalcomps, 
GLib.Cancellable? cancellable) throws GLib.Error;
diff --git a/vapi/libecal-1.2/libecal-1.2.metadata b/vapi/libecal-1.2/libecal-1.2.metadata
index 951af62..e93a428 100644
--- a/vapi/libecal-1.2/libecal-1.2.metadata
+++ b/vapi/libecal-1.2/libecal-1.2.metadata
@@ -82,9 +82,12 @@ e_cal_client_get_free_busy async="1"
 e_cal_client_get_free_busy.cancellable nullable="1"
 e_cal_client_get_free_busy_sync.cancellable nullable="1"
 
-e_cal_client_get_object async="1"
+e_cal_client_get_object async="1" finish_name="e_cal_client_get_object_finish"
+e_cal_client_get_object.rid nullable="1"
 e_cal_client_get_object.cancellable nullable="1"
-e_cal_client_get_object_finish.icalcomp is_out="1" value_owned="1"
+
+e_cal_client_get_object_finish type_name="void"
+e_cal_client_get_object_finish.out_icalcomp is_out="1" transfer_ownership="1"
 
 e_cal_client_get_object_list async="1"
 e_cal_client_get_object_list.cancellable nullable="1"
diff --git a/vapi/libical.vapi b/vapi/libical.vapi
index 2bf00a2..9b50119 100644
--- a/vapi/libical.vapi
+++ b/vapi/libical.vapi
@@ -1678,7 +1678,8 @@ namespace iCal {
        [Compact]
        public class sspm_minor_type {
        }
-       [CCode (cheader_filename = "libical/ical.h")]
+       [CCode (cheader_filename = "libical/ical.h", cname="struct icaldatetimeperiodtype")]
+       [SimpleType]
        public struct icaldatetimeperiodtype {
                public iCal.icaltimetype time;
                public iCal.icalperiodtype period;
@@ -1688,7 +1689,8 @@ namespace iCal {
                public float lat;
                public float lon;
        }
-       [CCode (cheader_filename = "libical/ical.h")]
+       [CCode (cheader_filename = "libical/ical.h", cname="struct icalperiodtype")]
+       [SimpleType]
        public struct icalperiodtype {
                public iCal.icaltimetype start;
                public iCal.icaltimetype end;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]