[california/wip/725785-create-recurring: 11/11] Further cleanup of parser, handle yearly events



commit 6551c8705983fbe6a22c57d52327b91d88f2855b
Author: Jim Nelson <jim yorba org>
Date:   Fri Jun 13 16:20:33 2014 -0700

    Further cleanup of parser, handle yearly events

 src/calendar/calendar-date.vala              |   40 ++++++++++++--
 src/component/component-details-parser.vala  |   78 +++++++++++++++++++-------
 src/component/component-recurrence-rule.vala |   34 ++++++------
 src/component/component.vala                 |    4 +-
 4 files changed, 111 insertions(+), 45 deletions(-)
---
diff --git a/src/calendar/calendar-date.vala b/src/calendar/calendar-date.vala
index ce762f0..f01ccdc 100644
--- a/src/calendar/calendar-date.vala
+++ b/src/calendar/calendar-date.vala
@@ -68,6 +68,7 @@ public class Date : Unit<Date>, Gee.Comparable<Date>, Gee.Hashable<Date> {
     
     public DayOfWeek day_of_week { get; private set; }
     public DayOfMonth day_of_month { get; private set; }
+    public int day_of_year { get; private set; }
     public Month month { get; private set; }
     public Year year { get; private set; }
     
@@ -89,6 +90,7 @@ public class Date : Unit<Date>, Gee.Comparable<Date>, Gee.Hashable<Date> {
         
         day_of_week = DayOfWeek.from_gdate(gdate);
         this.day_of_month = day_of_month;
+        day_of_year = (int) gdate.get_day_of_year();
         this.month = month;
         this.year = year;
     }
@@ -108,6 +110,7 @@ public class Date : Unit<Date>, Gee.Comparable<Date>, Gee.Hashable<Date> {
         assert(gdate.valid());
         
         day_of_week = DayOfWeek.from_gdate(gdate);
+        day_of_year = (int) gdate.get_day_of_year();
     }
     
     /**
@@ -126,6 +129,7 @@ public class Date : Unit<Date>, Gee.Comparable<Date>, Gee.Hashable<Date> {
         
         day_of_week = DayOfWeek.from_gdate(gdate);
         day_of_month = DayOfMonth.from_gdate(gdate);
+        day_of_year = (int) gdate.get_day_of_year();
         month = Month.from_gdate(gdate);
         year = new Year.from_gdate(gdate);
     }
@@ -256,7 +260,20 @@ public class Date : Unit<Date>, Gee.Comparable<Date>, Gee.Hashable<Date> {
      * @see prior
      */
     public Date upcoming(DayOfWeek dow, bool includes_this_day) {
-        return upcoming_prior(dow, includes_this_day, 1);
+        return upcoming_prior(iterate<DayOfWeek>(dow).to_hash_set(), includes_this_day, 1);
+    }
+    
+    /**
+     * Returns the { link Date} of the upcoming (next chronological) { link DayOfWeek} from the
+     * set provided.
+     *
+     * Set { link includes_this_day} to true if this Date is to be considered "upcoming", that is,
+     * if it falls on the day of the week, it is returned.
+     *
+     * @see prior_in_set
+     */
+    public Date upcoming_in_set(Gee.Set<DayOfWeek> dow_set, bool includes_this_day) {
+        return upcoming_prior(dow_set, includes_this_day, 1);
     }
     
     /**
@@ -268,19 +285,32 @@ public class Date : Unit<Date>, Gee.Comparable<Date>, Gee.Hashable<Date> {
      * @see upcoming
      */
     public Date prior(DayOfWeek dow, bool includes_this_day) {
-        return upcoming_prior(dow, includes_this_day, -1);
+        return upcoming_prior(iterate<DayOfWeek>(dow).to_hash_set(), includes_this_day, -1);
+    }
+    
+    /**
+     * Returns the { link Date} of the prior (next chronological) { link DayOfWeek} from the
+     * set provided.
+     *
+     * Set { link includes_this_day} to true if this Date is to be considered "prior", that is,
+     * if it falls on the day of the week, it is returned.
+     *
+     * @see upcoming_in_set
+     */
+    public Date prior_in_set(Gee.Set<DayOfWeek> dow_set, bool includes_this_day) {
+        return upcoming_prior(dow_set, includes_this_day, -1);
     }
     
-    private Date upcoming_prior(DayOfWeek dow, bool includes_this_day, int adjustment) {
+    private Date upcoming_prior(Gee.Set<DayOfWeek> dow_set, bool includes_this_day, int adjustment) {
         // look for current date being the one
-        if (day_of_week.equal_to(dow) && includes_this_day)
+        if (dow_set.contains(day_of_week) && includes_this_day)
             return this;
         
         // find a Date for day of the week ... brute force isn't great, but it works
         Date upcoming_prior = this;
         for (;;) {
             upcoming_prior = upcoming_prior.adjust(adjustment);
-            if (upcoming_prior.day_of_week.equal_to(dow))
+            if (dow_set.contains(upcoming_prior.day_of_week))
                 return upcoming_prior;
         }
     }
diff --git a/src/component/component-details-parser.vala b/src/component/component-details-parser.vala
index a013892..ffeabda 100644
--- a/src/component/component-details-parser.vala
+++ b/src/component/component-details-parser.vala
@@ -351,57 +351,93 @@ public class DetailsParser : BaseObject {
         return true;
     }
     
-    private bool parse_recurring(Token? unit) {
-        // if a recurring rule has already been specified, another recurring cannot be made
-        if (unit == null || rrule != null)
+    private bool parse_recurring(Token? specifier) {
+        // if a recurring rule has already been specified, another recurring cannot be made and
+        // the current cannot be edited (yet)
+        if (specifier == null || rrule != null)
             return false;
         
         // a day of the week
-        Calendar.DayOfWeek? dow = Calendar.DayOfWeek.parse(unit.casefolded);
+        Calendar.DayOfWeek? dow = Calendar.DayOfWeek.parse(specifier.casefolded);
         if (dow != null) {
             start_date = Calendar.System.today.upcoming(dow, true);
             rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.WEEKLY_RECURRENCE);
+            rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
             
             return true;
         }
         
         // "day"
-        if (unit.casefolded == DAY) {
+        if (specifier.casefolded == DAY) {
             start_date = Calendar.System.today;
             rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.DAILY_RECURRENCE);
+            rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
             
             return true;
         }
         
         // "weekday"
-        if (unit.casefolded == WEEKDAY) {
-            start_date = Calendar.System.today;
-            rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.WEEKLY_RECURRENCE);
-            // TODO: Set start of week
-            Gee.Map<Calendar.DayOfWeek, int> map = new Gee.HashMap<Calendar.DayOfWeek, int>();
-            foreach (Calendar.DayOfWeek weekday in Calendar.DayOfWeek.weekdays)
-                map.set(weekday, 0);
-            rrule.set_by_rule(RecurrenceRule.ByRule.DAY, RecurrenceRule.encode_days(map));
+        if (specifier.casefolded == WEEKDAY) {
+            set_rrule_weekly(Calendar.DayOfWeek.weekdays);
             
             return true;
         }
         
         // "weekend"
-        if (unit.casefolded == WEEKEND) {
-            start_date = Calendar.System.today;
-            rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.WEEKLY_RECURRENCE);
-            // TODO: Set start of week
-            Gee.Map<Calendar.DayOfWeek, int> map = new Gee.HashMap<Calendar.DayOfWeek, int>();
-            foreach (Calendar.DayOfWeek weekend_day in Calendar.DayOfWeek.weekend_days)
-                map.set(weekend_day, 0);
-            rrule.set_by_rule(RecurrenceRule.ByRule.DAY, RecurrenceRule.encode_days(map));
+        if (specifier.casefolded == WEEKEND) {
+            set_rrule_weekly(Calendar.DayOfWeek.weekend_days);
             
             return true;
         }
         
+        // if no start date, then parse for start date, and if so, treat as yearly event
+        if (start_date == null) {
+            stack.mark();
+            {
+                Token? second = stack.pop();
+                if (second != null) {
+                    Calendar.Date? date = parse_day_month(specifier, second);
+                    if (date == null)
+                        date = parse_day_month(second, specifier);
+                    
+                    if (date != null) {
+                        set_rrule_yearly(date);
+                        
+                        return true;
+                    }
+                }
+            }
+            stack.restore();
+        }
+        
         return false;
     }
     
+    private void set_rrule_weekly(Calendar.DayOfWeek[]? by_days) {
+        Gee.Map<Calendar.DayOfWeek, int> map = new Gee.HashMap<Calendar.DayOfWeek, int>();
+        if (by_days != null) {
+            foreach (Calendar.DayOfWeek by_day in by_days)
+                map.set(by_day, 0);
+        }
+        
+        // start at the first day in the by_days
+        start_date = Calendar.System.today;
+        if (by_days != null)
+            start_date = start_date.upcoming_in_set(from_array<Calendar.DayOfWeek>(by_days).to_hash_set(), 
true);
+        
+        rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.WEEKLY_RECURRENCE);
+        rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
+        rrule.set_by_rule(RecurrenceRule.ByRule.DAY, RecurrenceRule.encode_days(map));
+    }
+    
+    private void set_rrule_yearly(Calendar.Date date) {
+        start_date = date;
+        
+        rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.YEARLY_RECURRENCE);
+        rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
+        rrule.set_by_rule(RecurrenceRule.ByRule.YEAR_DAY, iterate<int>(date.day_of_year).to_array_list());
+    }
+    
     // Adds the text to the summary and location field, if adding_location is set
     private void add_text(Token token) {
         // always add to summary
diff --git a/src/component/component-recurrence-rule.vala b/src/component/component-recurrence-rule.vala
index 4648ee9..12dd603 100644
--- a/src/component/component-recurrence-rule.vala
+++ b/src/component/component-recurrence-rule.vala
@@ -72,7 +72,7 @@ public class RecurrenceRule : BaseObject {
     /**
      * Start of work week (WKST).
      */
-    public Calendar.DayOfWeek? start_of_week { get; set; default = null; }
+    public Calendar.DayOfWeek? first_of_week { get; set; default = null; }
     
     private Gee.SortedSet<int> by_second = new Gee.TreeSet<int>();
     private Gee.SortedSet<int> by_minute = new Gee.TreeSet<int>();
@@ -114,36 +114,36 @@ public class RecurrenceRule : BaseObject {
         
         switch (rrule.week_start) {
             case iCal.icalrecurrencetype_weekday.SUNDAY_WEEKDAY:
-                start_of_week = Calendar.DayOfWeek.SUN;
+                first_of_week = Calendar.DayOfWeek.SUN;
             break;
             
             case iCal.icalrecurrencetype_weekday.MONDAY_WEEKDAY:
-                start_of_week = Calendar.DayOfWeek.MON;
+                first_of_week = Calendar.DayOfWeek.MON;
             break;
             
             case iCal.icalrecurrencetype_weekday.TUESDAY_WEEKDAY:
-                start_of_week = Calendar.DayOfWeek.TUE;
+                first_of_week = Calendar.DayOfWeek.TUE;
             break;
             
             case iCal.icalrecurrencetype_weekday.WEDNESDAY_WEEKDAY:
-                start_of_week = Calendar.DayOfWeek.WED;
+                first_of_week = Calendar.DayOfWeek.WED;
             break;
             
             case iCal.icalrecurrencetype_weekday.THURSDAY_WEEKDAY:
-                start_of_week = Calendar.DayOfWeek.THU;
+                first_of_week = Calendar.DayOfWeek.THU;
             break;
             
             case iCal.icalrecurrencetype_weekday.FRIDAY_WEEKDAY:
-                start_of_week = Calendar.DayOfWeek.FRI;
+                first_of_week = Calendar.DayOfWeek.FRI;
             break;
             
             case iCal.icalrecurrencetype_weekday.SATURDAY_WEEKDAY:
-                start_of_week = Calendar.DayOfWeek.SAT;
+                first_of_week = Calendar.DayOfWeek.SAT;
             break;
             
             case iCal.icalrecurrencetype_weekday.NO_WEEKDAY:
             default:
-                start_of_week = null;
+                first_of_week = null;
             break;
         }
         
@@ -331,21 +331,21 @@ public class RecurrenceRule : BaseObject {
         if (interval > 0)
             rrule.interval = interval;
         
-        if (start_of_week == null)
+        if (first_of_week == null)
             rrule.week_start = iCal.icalrecurrencetype_weekday.NO_WEEKDAY;
-        else if (start_of_week == Calendar.DayOfWeek.SUN)
+        else if (first_of_week == Calendar.DayOfWeek.SUN)
             rrule.week_start = iCal.icalrecurrencetype_weekday.SUNDAY_WEEKDAY;
-        else if (start_of_week == Calendar.DayOfWeek.MON)
+        else if (first_of_week == Calendar.DayOfWeek.MON)
             rrule.week_start = iCal.icalrecurrencetype_weekday.MONDAY_WEEKDAY;
-        else if (start_of_week == Calendar.DayOfWeek.TUE)
+        else if (first_of_week == Calendar.DayOfWeek.TUE)
             rrule.week_start = iCal.icalrecurrencetype_weekday.TUESDAY_WEEKDAY;
-        else if (start_of_week == Calendar.DayOfWeek.WED)
+        else if (first_of_week == Calendar.DayOfWeek.WED)
             rrule.week_start = iCal.icalrecurrencetype_weekday.WEDNESDAY_WEEKDAY;
-        else if (start_of_week == Calendar.DayOfWeek.THU)
+        else if (first_of_week == Calendar.DayOfWeek.THU)
             rrule.week_start = iCal.icalrecurrencetype_weekday.THURSDAY_WEEKDAY;
-        else if (start_of_week == Calendar.DayOfWeek.FRI)
+        else if (first_of_week == Calendar.DayOfWeek.FRI)
             rrule.week_start = iCal.icalrecurrencetype_weekday.FRIDAY_WEEKDAY;
-        else if (start_of_week == Calendar.DayOfWeek.SAT)
+        else if (first_of_week == Calendar.DayOfWeek.SAT)
             rrule.week_start = iCal.icalrecurrencetype_weekday.SATURDAY_WEEKDAY;
         else
             assert_not_reached();
diff --git a/src/component/component.vala b/src/component/component.vala
index 82b9975..c7be790 100644
--- a/src/component/component.vala
+++ b/src/component/component.vala
@@ -69,9 +69,9 @@ public void init() throws Error {
     // It's allowable for some or all of these words to
     // be duplicated in the location prepositions list (elsewhere) but not another time list.
     // The list can be empty, but that will limit the parser.
-    // Examples: "at 9am", "from 10pm to 11:30pm", "on monday"
+    // Examples: "at 9am", "from 10pm to 11:30pm", "on monday", "until June 3rd"
     // For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
-    TIME_PREPOSITIONS = _("at;from;to;on;").casefold().split(";");
+    TIME_PREPOSITIONS = _("at;from;to;on;until;").casefold().split(";");
     
     // Used by quick-add to determine if the word is a DURATION preposition (indicating a
     // a duration of time, not a specific time).  Each word must be separated by semi-colons.


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