[california/wip/732930-explain] All potential text in place, now add to UI



commit eec72be48929d3716cda6b79d984464c1653643d
Author: Jim Nelson <jim yorba org>
Date:   Fri Sep 5 12:38:42 2014 -0700

    All potential text in place, now add to UI

 src/calendar/calendar-day-of-week.vala       |   21 ++++
 src/component/component-recurrence-rule.vala |  160 ++++++++++++++++++++++----
 src/host/host-create-update-recurring.vala   |    8 +-
 3 files changed, 166 insertions(+), 23 deletions(-)
---
diff --git a/src/calendar/calendar-day-of-week.vala b/src/calendar/calendar-day-of-week.vala
index 4fc8500..0ace8c3 100644
--- a/src/calendar/calendar-day-of-week.vala
+++ b/src/calendar/calendar-day-of-week.vala
@@ -277,6 +277,27 @@ public class DayOfWeek : BaseObject, Gee.Hashable<DayOfWeek> {
         return new DayOfWeekIterator(first_of_week);
     }
     
+    public static CompareDataFunc<DayOfWeek> get_comparator_for_first_of_week(FirstOfWeek fow) {
+        switch (fow) {
+            case FirstOfWeek.MONDAY:
+                return monday_comparator;
+            
+            case FirstOfWeek.SUNDAY:
+                return sunday_comparator;
+            
+            default:
+                assert_not_reached();
+        }
+    }
+    
+    private static int monday_comparator(DayOfWeek a, DayOfWeek b) {
+        return a.value_monday - b.value_monday;
+    }
+    
+    private static int sunday_comparator(DayOfWeek a, DayOfWeek b) {
+        return a.value_sunday - b.value_sunday;
+    }
+    
     public bool equal_to(DayOfWeek other) {
         return this == other;
     }
diff --git a/src/component/component-recurrence-rule.vala b/src/component/component-recurrence-rule.vala
index 16774cb..8a72ce2 100644
--- a/src/component/component-recurrence-rule.vala
+++ b/src/component/component-recurrence-rule.vala
@@ -354,9 +354,7 @@ public class RecurrenceRule : BaseObject {
      * Encode a Gee.Map of { link Calendar.DayOfWeek} and its position into a value for
      * { link set_by_rule} when using { link ByRule.DAY}.
      *
-     * Use null for DayOfWeek and zero for position to mean "any" or "every".
-     *
-     * @see encode_day
+     * See { link encode_day} for more information about how encoding works.
      */
     public static Gee.Collection<int> encode_days(Gee.Map<Calendar.DayOfWeek?, int>? day_values) {
         if (day_values == null || day_values.size == 0)
@@ -432,6 +430,9 @@ public class RecurrenceRule : BaseObject {
     /**
      * Returns a read-only sorted set of BY rule settings for the specified { link ByRule}.
      *
+     * Note that because BYDAY rules are bit-encoded, their sorting has no relationship to their
+     * decoded values.  Callers should decode each value and sort them according to their needs.
+     *
      * See [[https://tools.ietf.org/html/rfc5545#section-3.3.10]] for information how these values
      * operate according to their associated ByRule and this RRULE's { link freq}.
      */
@@ -615,11 +616,11 @@ public class RecurrenceRule : BaseObject {
         
     }
     
-    private string explain_simple(string unit) {
+    private string explain_simple(string units) {
         if (count > 0) {
             // As in, "Repeats every day, 2 times"
             return _("Repeats every %s, %s").printf(units,
-                ngettext("%d time", "%d times").printf(count)
+                ngettext("%d time", "%d times", count).printf(count)
             );
         }
         
@@ -642,15 +643,11 @@ public class RecurrenceRule : BaseObject {
         return _("Repeats every %s").printf(units);
     }
     
-    private string? explain_weekly(string unit) {
-        // can only explain BYDAY rules
-        Gee.Set<ByRule> active = get_active_by_rules();
-        if (!active.contains(ByRule.DAY) || active.size == 0)
-            return null;
-        
-        // Gather all the DayOfWeeks in the WEEKLY RRULE into a sorted set
-        // TODO: Need start-of-week comparator
-        Gee.TreeSet<Calendar.DayOfWeek> dows = new Gee.TreeSet<Calendar.DayOfWeek>();
+    // Use only with WEEKLY RRULEs
+    private string? explain_days_of_the_week() {
+        // Gather all the DayOfWeeks amd sort by start of week
+        Gee.TreeSet<Calendar.DayOfWeek> dows = new Gee.TreeSet<Calendar.DayOfWeek>(
+            Calendar.DayOfWeek.get_comparator_for_first_of_week(Calendar.System.first_of_week));
         foreach (int day in get_by_rule(ByRule.DAY)) {
             Calendar.DayOfWeek dow;
             if (!decode_day(day, out dow, null))
@@ -663,7 +660,7 @@ public class RecurrenceRule : BaseObject {
         if (dows.size == 0)
             return null;
         
-        // assemble a list of days
+        // assemble a text list of days
         StringBuilder days_of_the_week = new StringBuilder();
         bool first = true;
         foreach (Calendar.DayOfWeek dow in dows) {
@@ -676,36 +673,155 @@ public class RecurrenceRule : BaseObject {
             first = false;
         }
         
+        return days_of_the_week.str;
+    }
+    
+    private string? explain_weekly(string units) {
+        // can only explain BYDAY rules
+        Gee.Set<ByRule> active = get_active_by_rules();
+        if (!active.contains(ByRule.DAY) || active.size == 0)
+            return null;
+        
+        string? days_of_the_week = explain_days_of_the_week();
+        if (String.is_empty(days_of_the_week))
+            return null;
+        
         if (count > 0) {
             // As in, "Repeats every week on Monday, Tuesday, 3 times"
-            return _("Repeats every %s on %s, %s").printf(units, days_of_the_week.str,
-                ngettext("%d time", "%d times").printf(count)
+            return _("Repeats every %s on %s, %s").printf(units, days_of_the_week,
+                ngettext("%d time", "%d times", count).printf(count)
             );
         }
         
         if (until_date != null) {
             // As in, "Repeats every week on Thursday until Sept. 2, 2014"
-            return _("Repeats every %s on %s until %s").printf(units, days_of_the_week.str,
+            return _("Repeats every %s on %s until %s").printf(units, days_of_the_week,
                 until_date.to_pretty_string(Calendar.Date.PrettyFlag.INCLUDE_YEAR)
             );
         }
         
         if (until_exact_time != null) {
             // As in, "Repeats every week on Friday, Saturday until Sept. 2, 2014, 8:00pm"
-            return _("Repeats every %s on %s until %s, %s").printf(units, days_of_the_week.str,
+            return _("Repeats every %s on %s until %s, %s").printf(units, days_of_the_week,
                 until_exact_time.to_pretty_date_string(Calendar.Date.PrettyFlag.INCLUDE_YEAR),
                 until_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE)
             );
         }
         
         // As in, "Repeats every week on Monday, Wednesday, Friday"
-        return _("Repeats every %s on %s").printf(units, days_of_the_week.str);
+        return _("Repeats every %s on %s").printf(units, days_of_the_week);
     }
     
-    private string? explain_monthly_byday(string unit) {
+    private string? explain_monthly_byday(string units) {
+        // only support one day of the week for BYMONTHDAT RRULEs
+        Gee.Set<int> byday = get_by_rule(ByRule.DAY);
+        if (byday.size != 1)
+            return null;
+        
+        Calendar.DayOfWeek? dow;
+        int position;
+        if (!decode_day(traverse<int>(byday).first(), out dow, out position))
+            return null;
+        
+        // only support a small set of possibilites here
+        if (dow == null)
+            return null;
+        
+        string day;
+        switch (position) {
+            case 1:
+                // As in, "first Thursday of the month"
+                day = _("first %s").printf(dow.full_name);
+            break;
+            
+            case 2:
+                // As in, "second Thursday of the month"
+                day = _("second %s").printf(dow.full_name);
+            break;
+            
+            case 3:
+                // As in, "third Thursday of the month"
+                day = _("third %s").printf(dow.full_name);
+            break;
+            
+            case 4:
+                // As in, "fourth Thursday of the month"
+                day = _("fourth %s").printf(dow.full_name);
+            break;
+            
+            case 5:
+                // As in, "fifth Thursday of the month"
+                day = _("fifth %s").printf(dow.full_name);
+            break;
+            
+            case -1:
+                // As in, "last Thursday of the month"
+                day = _("last %s").printf(dow.full_name);
+            break;
+            
+            default:
+                return null;
+        }
+        
+        if (count > 0) {
+            // As in, "Repeats every month on the first Tuesday, 3 times"
+            return _("Repeats every %s on the %s, %s").printf(units, day,
+                ngettext("%d time", "%d times", count).printf(count)
+            );
+        }
+        
+        if (until_date != null) {
+            // As in, "Repeats every month on the second Monday until Sept. 2, 2014"
+            return _("Repeats every %s on the %s until %s").printf(units, day,
+                until_date.to_pretty_string(Calendar.Date.PrettyFlag.INCLUDE_YEAR)
+            );
+        }
+        
+        if (until_exact_time != null) {
+            // As in, "Repeats every month on the last Friday until Sept. 2, 2014, 8:00pm"
+            return _("Repeats every %s on the %s until %s, %s").printf(units, day,
+                until_exact_time.to_pretty_date_string(Calendar.Date.PrettyFlag.INCLUDE_YEAR),
+                until_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE)
+            );
+        }
+        
+        // As in, "Repeats every month on the third Tuesday"
+        return _("Repeats every %s on the %s").printf(units, day);
     }
     
-    private string? explain_monthly_bymonthday(string unit) {
+    private string? explain_monthly_bymonthday(string units) {
+        // currently only support one monthday (generally, the same as DTSTART)
+        Gee.Set<int> monthdays = get_by_rule(ByRule.MONTH_DAY);
+        if (monthdays.size != 1)
+            return null;
+        
+        // As in, "Repeats on day 4 of the month"
+        string day = "day %d".printf(traverse<int>(monthdays).first());
+        
+        if (count > 0) {
+            // As in, "Repeats every month on day 4, 3 times"
+            return _("Repeats every %s on %s, %s").printf(units, day,
+                ngettext("%d time", "%d times", count).printf(count)
+            );
+        }
+        
+        if (until_date != null) {
+            // As in, "Repeats every month on day 21 until Sept. 2, 2014"
+            return _("Repeats every %s on %s until %s").printf(units, day,
+                until_date.to_pretty_string(Calendar.Date.PrettyFlag.INCLUDE_YEAR)
+            );
+        }
+        
+        if (until_exact_time != null) {
+            // As in, "Repeats every month on day 20 until Sept. 2, 2014, 8:00pm"
+            return _("Repeats every %s on %s until %s, %s").printf(units, day,
+                until_exact_time.to_pretty_date_string(Calendar.Date.PrettyFlag.INCLUDE_YEAR),
+                until_exact_time.to_pretty_time_string(Calendar.WallTime.PrettyFlag.NONE)
+            );
+        }
+        
+        // As in, "Repeats every month on day 5"
+        return _("Repeats every %s on %s").printf(units, day);
     }
     
     public override string to_string() {
diff --git a/src/host/host-create-update-recurring.vala b/src/host/host-create-update-recurring.vala
index 8d9fb7f..3e202ac 100644
--- a/src/host/host-create-update-recurring.vala
+++ b/src/host/host-create-update-recurring.vala
@@ -539,8 +539,14 @@ public class CreateUpdateRecurring : Gtk.Grid, Toolkit.Card {
         
         if (rrule.is_monthly) {
             if (repeats_combobox.active == Repeats.DAY_OF_THE_WEEK) {
+                // if > 4th week of month, use last week position indicator, since many months don't
+                // have more than 4 weeks
+                int position = start_date.week_of(Calendar.System.first_of_week).week_of_month;
+                if (position > 4)
+                    position = -1;
+                
                 Gee.HashMap<Calendar.DayOfWeek?, int> by_day = new Gee.HashMap<Calendar.DayOfWeek?, int>();
-                by_day[start_date.day_of_week] = 
start_date.week_of(Calendar.System.first_of_week).week_of_month;
+                by_day[start_date.day_of_week] = position;
                 rrule.set_by_rule(Component.RecurrenceRule.ByRule.DAY,
                     Component.RecurrenceRule.encode_days(by_day));
             } else {


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