[california/wip/calendar-spans: 2/2] Rethinking Span vs. DateSpan for DiscreteUnit



commit 5c756df2ee140c398762d440b68d8625bbe2f849
Author: Jim Nelson <jim yorba org>
Date:   Thu May 1 17:40:32 2014 -0700

    Rethinking Span vs. DateSpan for DiscreteUnit

 src/calendar/calendar-date-span.vala        |    6 +-
 src/calendar/calendar-date.vala             |  104 ++++++++++++++++++++++-----
 src/calendar/calendar-month-of-year.vala    |   31 +++------
 src/calendar/calendar-span.vala             |    2 +-
 src/calendar/calendar-unit.vala             |   97 +++++++++++++++++++++++++
 src/calendar/calendar-week.vala             |   35 +++++++--
 src/component/component-date-time.vala      |    2 +-
 src/component/component-details-parser.vala |    4 +-
 src/component/component-instance.vala       |    2 +-
 src/host/host-main-window.vala              |    2 +-
 src/tests/tests-calendar-date.vala          |    2 +-
 src/tests/tests-calendar-month-span.vala    |    4 +-
 src/tests/tests-quick-add.vala              |    2 +-
 src/view/month/month-controller.vala        |    5 --
 14 files changed, 234 insertions(+), 64 deletions(-)
---
diff --git a/src/calendar/calendar-date-span.vala b/src/calendar/calendar-date-span.vala
index b9794bd..3725fa6 100644
--- a/src/calendar/calendar-date-span.vala
+++ b/src/calendar/calendar-date-span.vala
@@ -33,7 +33,7 @@ public class DateSpan : BaseObject, Collection.SimpleIterable<Date>, Span<Date>,
             if (current == null)
                 current = first;
             else if (current.compare_to(last) < 0)
-                current = current.adjust(1, DateUnit.DAY);
+                current = current.next();
             else
                 return false;
             
@@ -167,7 +167,7 @@ public class DateSpan : BaseObject, Collection.SimpleIterable<Date>, Span<Date>,
     public DateSpan adjust_start_date(Calendar.Date new_start_date) {
         int diff = start_date.difference(end_date);
         
-        return new DateSpan(new_start_date, new_start_date.adjust(diff, DateUnit.DAY));
+        return new DateSpan(new_start_date, new_start_date.adjust(diff));
     }
     
     /**
@@ -182,7 +182,7 @@ public class DateSpan : BaseObject, Collection.SimpleIterable<Date>, Span<Date>,
     public DateSpan adjust_end_date(Calendar.Date new_end_date) {
         int diff = end_date.difference(start_date);
         
-        return new DateSpan(new_end_date.adjust(diff, DateUnit.DAY), new_end_date);
+        return new DateSpan(new_end_date.adjust(diff), new_end_date);
     }
     
     /**
diff --git a/src/calendar/calendar-date.vala b/src/calendar/calendar-date.vala
index 5ba97ba..96e8219 100644
--- a/src/calendar/calendar-date.vala
+++ b/src/calendar/calendar-date.vala
@@ -20,7 +20,8 @@ namespace California.Calendar {
  * issues.
  */
 
-public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
+public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, DiscreteUnit<Date>,
+    Gee.Comparable<Date>, Gee.Hashable<Date> {
     /**
      * Options for { link to_pretty_string}.
      */
@@ -42,11 +43,52 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
         NO_TODAY
     }
     
+    private class DateIterator : BaseObject, Collection.SimpleIterator<Date> {
+        private Date date;
+        
+        public DateIterator(Date date) {
+            this.date = date;
+        }
+        
+        /**
+         * @inheritDoc
+         */
+        public bool next() {
+            return false;
+        }
+        
+        /**
+         * @inheritDoc
+         */
+        public new Date get() {
+            return date;
+        }
+        
+        public override string to_string() {
+            return "DateIterator:%s".printf(date.to_string());
+        }
+    }
+    
     public DayOfWeek day_of_week { get; private set; }
     public DayOfMonth day_of_month { get; private set; }
     public Month month { get; private set; }
     public Year year { get; private set; }
     
+    /**
+     * @inheritDoc
+     */
+    public DateUnit date_unit { get { return DateUnit.DAY; } }
+    
+    /**
+     * @inheritDoc
+     */
+    public Date start_date { owned get { return this; } }
+    
+    /**
+     * @inheritDoc
+     */
+    public Date end_date { owned get { return this; } }
+    
     private GLib.Date gdate;
     
     /**
@@ -101,6 +143,34 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
     }
     
     /**
+     * @inheritDoc
+     */
+    public Date start() {
+        return this;
+    }
+    
+    /**
+     * @inheritDoc
+     */
+    public Date end() {
+        return this;
+    }
+    
+    /**
+     * @inheritDoc
+     */
+    public bool contains(Date date) {
+        return equal_to(date);
+    }
+    
+    /**
+     * @inheritDoc
+     */
+    public bool has(Date date) {
+        return equal_to(date);
+    }
+    
+    /**
      * Returns the { link Week} the { link Date} falls in.
      */
     public Week week_of(FirstOfWeek first) {
@@ -118,7 +188,7 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
         }
         
         // add six days and that's the last day of the week
-        Date end = start.adjust(DayOfWeek.COUNT - 1, DateUnit.DAY);
+        Date end = start.adjust_by(DayOfWeek.COUNT - 1, DateUnit.DAY);
         
         // get the numeric week of the year of this date
         int week_of_year;
@@ -186,11 +256,18 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
     }
     
     /**
+     * @inheritDoc
+     */
+    public Date adjust(int quantity) {
+        return adjust_by(quantity, DateUnit.DAY);
+    }
+    
+    /**
      * Returns a new { link Date} adjusted from this Date by the specifed quantity of time.
      *
      * Subtraction (adjusting to a past date) is acheived by using a negative quantity.
      */
-    public Date adjust(int quantity, DateUnit unit) {
+    public Date adjust_by(int quantity, DateUnit unit) {
         if (quantity == 0)
             return this;
         
@@ -241,6 +318,13 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
     }
     
     /**
+     * @inheritDoc
+     */
+    public Collection.SimpleIterator<Date> iterator() {
+        return new DateIterator(this);
+    }
+    
+    /**
      * Returns a { link Date} clamped between the two supplied Dates, inclusive.
      */
     public Date clamp(Date min, Date max) {
@@ -250,20 +334,6 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
         return new Date.from_gdate(clone);
     }
     
-    /**
-     * Returns the next date;
-     */
-    public Date next() {
-        return adjust(1, DateUnit.DAY);
-    }
-    
-    /**
-     * Returns the previous date.
-     */
-    public Date previous() {
-        return adjust(-1, DateUnit.DAY);
-    }
-    
     public int compare_to(Date other) {
         return (this != other) ? gdate.compare(other.gdate) : 0;
     }
diff --git a/src/calendar/calendar-month-of-year.vala b/src/calendar/calendar-month-of-year.vala
index 7425e3b..5d429fd 100644
--- a/src/calendar/calendar-month-of-year.vala
+++ b/src/calendar/calendar-month-of-year.vala
@@ -10,7 +10,12 @@ namespace California.Calendar {
  * An immutable representation of a { link Month} of a { link Year}.
  */
 
-public class MonthOfYear : DateSpan {
+public class MonthOfYear : DiscreteUnit<MonthOfYear>, DateSpan {
+    /**
+     * @inheritDoc
+     */
+    public DateUnit date_unit { get { return DateUnit.MONTH; } }
+    
     /**
      * The { link Month} of the associated { link Year}.
      */
@@ -76,18 +81,14 @@ public class MonthOfYear : DateSpan {
     }
     
     /**
-     * Returns a { link MonthOfYear} adjusted a quantity of months from this one.
-     *
-     * Subtraction (adjusting to a past date) is acheived by using a negative quantity.
+     * @inheritDoc
      */
     public MonthOfYear adjust(int quantity) {
-        return start_date.adjust(quantity, DateUnit.MONTH).month_of_year();
+        return start_date.adjust_by(quantity, DateUnit.MONTH).month_of_year();
     }
     
     /**
-     * Returns the number of months between the two { link MonthOfYear}s.
-     *
-     * If the supplied MonthOfYear is earlier than this one, a negative value is returned.
+     * @inheritDoc
      */
     public int difference(MonthOfYear other) {
         int compare = compare_to(other);
@@ -106,20 +107,6 @@ public class MonthOfYear : DateSpan {
         }
     }
     
-    /**
-     * Returns the chronological next { link MonthOfYear}.
-     */
-    public MonthOfYear next() {
-        return adjust(1);
-    }
-    
-    /**
-     * Returns the chronological prior { link MonthOfYear}.
-     */
-    public MonthOfYear previous() {
-        return adjust(-1);
-    }
-    
     public override string to_string() {
         return "%s %s".printf(month.to_string(), year.to_string());
     }
diff --git a/src/calendar/calendar-span.vala b/src/calendar/calendar-span.vala
index 416ecad..2f8b0d3 100644
--- a/src/calendar/calendar-span.vala
+++ b/src/calendar/calendar-span.vala
@@ -10,7 +10,7 @@ namespace California.Calendar {
  * An immutable generic span or range of consecutive calendar dates.
  *
  * The Span is delineated by specific lengths of time (such as { link Date}, { link Week}, or
- * { link Month} and is required to be Traversable and Iterable by the same.
+ * { link Month} and is required to be a { link SimpleIterable}.
  *
  * Since the start and end Date of a Span may fall within the larger delineated unit of time,
  * the contract is that partial units will always be returned.  If the caller wants to only deal
diff --git a/src/calendar/calendar-unit.vala b/src/calendar/calendar-unit.vala
index 7411685..30c2424 100644
--- a/src/calendar/calendar-unit.vala
+++ b/src/calendar/calendar-unit.vala
@@ -22,10 +22,107 @@ public enum DateUnit {
  *
  * @see WallTime
  */
+
 public enum TimeUnit {
     SECOND,
     MINUTE,
     HOUR
 }
 
+/**
+ * An immutable, discrete, well-recognized unit of calendar dates.
+ *
+ * This interface indicates the { link Calendar.Span} represents a discrete unit of time (each of
+ * which may not contain the same number of days, such as { link Year}s, while some might, such as
+ * { link Week}s.
+ *
+ * Note that this different than a { link WeekSpan} or { link MonthSpan} which are designed to hold
+ * an arbitrary consecutive number of their date units.  DiscreteUnits represent a single unit of
+ * time.
+ *
+ * DiscreteUnit is not designed to work with discrete { link ExactTime} or { link WallTime} units.
+ *
+ * @see Date
+ * @see Week
+ * @see MonthOfYear
+ * @see Year
+ */
+
+public interface DiscreteUnit<G> : Span<G> {
+    private class DiscreteUnitIterator<G> : BaseObject, Collection.SimpleIterator<G> {
+        private G unit;
+        private DateUnit date_unit;
+        private bool finished = false;
+        
+        public DiscreteUnitIterator(G unit, DateUnit date_unit) {
+            this.unit = unit;
+            this.date_unit = date_unit;
+        }
+        
+        /**
+         * @inheritDoc
+         */
+        public bool next() {
+            if (!finished) {
+                finished = true;
+                
+                return true;
+            }
+            
+            return false;
+        }
+        
+        /**
+         * @inheritDoc
+         */
+        public new G get() {
+            return unit;
+        }
+        
+        public override string to_string() {
+            return "DiscreteUnitIterator:%s".printf(date_unit.to_string());
+        }
+    }
+    
+    /**
+     * Returns the { link DateUnit} this { link DiscreteUnit} represents.
+     */
+    public abstract DateUnit date_unit { get; }
+    
+    /**
+     * The next chronological discrete unit of time.
+     */
+    public G next() {
+        return adjust(1);
+    }
+    
+    /**
+     * The previous chronological discrete unit of time.
+     */
+    public G previous() {
+        return adjust(-1);
+    }
+    
+    /**
+     * @inheritDoc
+     */
+    public Collection.SimpleIterator<G> iterator() {
+        return new DiscreteUnitIterator<G>(this, date_unit);
+    }
+    
+    /**
+     * Returns the { link DiscreteUnit} adjusted a quantity of months from this one.
+     *
+     * Subtraction (adjusting to a past date) is acheived by using a negative quantity.
+     */
+    public abstract G adjust(int quantity);
+    
+    /**
+     * Returns the number of { link DiscreteUnit}s between the two.
+     *
+     * If the supplied DiscreteUnit is earlier than this one, a negative value is returned.
+     */
+    public abstract int difference(G other);
+}
+
 }
diff --git a/src/calendar/calendar-week.vala b/src/calendar/calendar-week.vala
index 565d1a3..b80ebe4 100644
--- a/src/calendar/calendar-week.vala
+++ b/src/calendar/calendar-week.vala
@@ -18,7 +18,12 @@ namespace California.Calendar {
  * { link Date.week_of} to obtain a Week for a particular calendar day.
  */
 
-public class Week : DateSpan {
+public class Week : DateSpan, DiscreteUnit<Week> {
+    /**
+     * @inheritDoc
+     */
+    public DateUnit date_unit { get { return DateUnit.MONTH; } }
+    
     /**
      * The one-based week of the month (1 to 6).
      */
@@ -61,14 +66,30 @@ public class Week : DateSpan {
     }
     
     /**
-     * Returns a { link Week} adjusted a quantity of weeks from this one.
-     *
-     * The first day of the week is preserved in the new Week.
-     *
-     * Subtraction (adjusting to a past date) is acheived by using a negative quantity.
+     * @inheritDoc
      */
     public Week adjust(int quantity) {
-        return start_date.adjust(quantity, DateUnit.WEEK).week_of(first_of_week);
+        return start_date.adjust_by(quantity, DateUnit.WEEK).week_of(first_of_week);
+    }
+    
+    /**
+     * @inheritDoc
+     */
+    public int difference(Week other) {
+        int compare = compare_to(other);
+        if (compare == 0)
+            return 0;
+        
+        // TODO: Iterating sucks, but it will have to suffice for now.
+        int count = 0;
+        Week current = this;
+        for (;;) {
+            current = (compare > 0) ? current.previous() : current.next();
+            count += (compare > 0) ? -1 : 1;
+            
+            if (current.equal_to(other))
+                return count;
+        }
     }
     
     public override string to_string() {
diff --git a/src/component/component-date-time.vala b/src/component/component-date-time.vala
index 3795a69..f8121a5 100644
--- a/src/component/component-date-time.vala
+++ b/src/component/component-date-time.vala
@@ -213,7 +213,7 @@ public class DateTime : BaseObject, Gee.Hashable<DateTime>, Gee.Comparable<DateT
         
         // if exclusive, drop back one day
         if (!dtend_inclusive)
-            end_date = end_date.adjust(-1, Calendar.DateUnit.DAY);
+            end_date = end_date.previous();
         
         date_span = new Calendar.DateSpan(start_date, end_date);
         exact_time_span = null;
diff --git a/src/component/component-details-parser.vala b/src/component/component-details-parser.vala
index c396141..ff27110 100644
--- a/src/component/component-details-parser.vala
+++ b/src/component/component-details-parser.vala
@@ -186,7 +186,7 @@ public class DetailsParser : BaseObject {
         // if no end date was describe, assume ends today as well (unless midnight was crossed
         // due to duration)
         if (start_date != null && end_date == null)
-            end_date = midnight_crossed ? start_date.adjust(1, Calendar.DateUnit.DAY) : start_date;
+            end_date = midnight_crossed ? start_date.next() : start_date;
         
         // Event start/end time, if specified
         if (start_time != null && end_time != null) {
@@ -349,7 +349,7 @@ public class DetailsParser : BaseObject {
         // find a Date for day of the week ... starting today, move forward up to one
         // week
         Calendar.Date upcoming = Calendar.System.today;
-        Calendar.Date next_week = upcoming.adjust(1, Calendar.DateUnit.WEEK);
+        Calendar.Date next_week = upcoming.adjust_by(1, Calendar.DateUnit.WEEK);
         do {
             if (upcoming.day_of_week.equal_to(dow))
                 return upcoming;
diff --git a/src/component/component-instance.vala b/src/component/component-instance.vala
index 40cb7e8..16a9977 100644
--- a/src/component/component-instance.vala
+++ b/src/component/component-instance.vala
@@ -325,7 +325,7 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
     protected static void date_span_to_ical(Calendar.DateSpan date_span, bool dtend_inclusive,
         iCal.icaltimetype *ical_dtstart, iCal.icaltimetype *ical_dtend) {
         date_to_ical(date_span.start_date, ical_dtstart);
-        date_to_ical(date_span.end_date.adjust(dtend_inclusive ? 0 : 1, Calendar.DateUnit.DAY),
+        date_to_ical(date_span.end_date.adjust_by(dtend_inclusive ? 0 : 1, Calendar.DateUnit.DAY),
             ical_dtend);
     }
     
diff --git a/src/host/host-main-window.vala b/src/host/host-main-window.vala
index aa8459c..4ad6801 100644
--- a/src/host/host-main-window.vala
+++ b/src/host/host-main-window.vala
@@ -171,7 +171,7 @@ public class MainWindow : Gtk.ApplicationWindow {
     }
     
     private void on_previous() {
-        current_view.prev();
+        current_view.previous();
     }
     
     private void on_request_create_timed_event(Calendar.ExactTimeSpan initial, Gtk.Widget relative_to,
diff --git a/src/tests/tests-calendar-date.vala b/src/tests/tests-calendar-date.vala
index 2620dd9..82d8374 100644
--- a/src/tests/tests-calendar-date.vala
+++ b/src/tests/tests-calendar-date.vala
@@ -23,7 +23,7 @@ private class CalendarDate : UnitTest.Harness {
     }
     
     private Calendar.Date from_today(int days) {
-        return Calendar.System.today.adjust(days, Calendar.DateUnit.DAY);
+        return Calendar.System.today.adjust(days);
     }
     
     private Calendar.DateSpan span_from_today(int start_days, int end_days) {
diff --git a/src/tests/tests-calendar-month-span.vala b/src/tests/tests-calendar-month-span.vala
index 5f200d3..5a9e72d 100644
--- a/src/tests/tests-calendar-month-span.vala
+++ b/src/tests/tests-calendar-month-span.vala
@@ -23,7 +23,7 @@ private class CalendarMonthSpan : UnitTest.Harness {
     }
     
     private Calendar.Date from_today(int days) {
-        return Calendar.System.today.adjust(days, Calendar.DateUnit.DAY);
+        return Calendar.System.today.adjust(days);
     }
     
     private bool todays_month() throws Error {
@@ -39,7 +39,7 @@ private class CalendarMonthSpan : UnitTest.Harness {
         Calendar.Date last = new Calendar.Date(Calendar.DayOfMonth.for_checked(30), Calendar.Month.JAN, new 
Calendar.Year(2014));
         Calendar.MonthSpan span = new Calendar.MonthSpan(new Calendar.DateSpan(first, last));
         
-        return span.contains(first.adjust(15, Calendar.DateUnit.DAY));
+        return span.contains(first.adjust(15));
     }
     
     private bool has_month() throws Error {
diff --git a/src/tests/tests-quick-add.vala b/src/tests/tests-quick-add.vala
index 57ff4c2..d4b3314 100644
--- a/src/tests/tests-quick-add.vala
+++ b/src/tests/tests-quick-add.vala
@@ -160,7 +160,7 @@ private class QuickAdd : UnitTest.Harness {
         
         Calendar.ExactTime start = new Calendar.ExactTime(Calendar.Timezone.local, Calendar.System.today,
             new Calendar.WallTime(23, 0, 0));
-        Calendar.ExactTime end = new Calendar.ExactTime(Calendar.Timezone.local, 
Calendar.System.today.adjust(1, Calendar.DateUnit.DAY),
+        Calendar.ExactTime end = new Calendar.ExactTime(Calendar.Timezone.local, 
Calendar.System.today.next(),
             new Calendar.WallTime(0, 0, 0));
         
         return parser.event.summary == "Dinner"
diff --git a/src/view/month/month-controller.vala b/src/view/month/month-controller.vala
index 7197655..62d6f55 100644
--- a/src/view/month/month-controller.vala
+++ b/src/view/month/month-controller.vala
@@ -51,11 +51,6 @@ public class Controller : BaseObject, View.Controllable {
      */
     public bool is_viewing_today { get; protected set; }
     
-    /**
-     * @inheritDoc
-     */
-    public Calendar.Date default_date { get; protected set; }
-    
     private Gtk.Grid master_grid = new Gtk.Grid();
     private Gtk.Stack stack = new Gtk.Stack();
     private Gee.HashMap<Calendar.MonthOfYear, Grid> month_grids = new Gee.HashMap<Calendar.MonthOfYear, 
Grid>();


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