[california/wip/first-of-week] First pass



commit 7ac962384d5757faa7b2158c381cf970257211bc
Author: Jim Nelson <jim yorba org>
Date:   Thu Jun 12 19:33:48 2014 -0700

    First pass

 data/org.yorba.california.gschema.xml    |    8 ++++
 src/application/california-settings.vala |   66 ++++++++++++++++++++++++++++++
 src/calendar/calendar-first-of-week.vala |   10 ++++-
 src/host/host-main-window.vala           |    9 ----
 src/toolkit/toolkit-stack-model.vala     |    8 ++++
 src/view/month/month-cell.vala           |    8 ++--
 src/view/month/month-controller.vala     |   30 +++++++------
 src/view/month/month-grid.vala           |   23 ++--------
 src/view/view-controllable.vala          |    6 ---
 src/view/week/week-all-day-cell.vala     |    8 +++-
 src/view/week/week-controller.vala       |   28 +++++--------
 11 files changed, 134 insertions(+), 70 deletions(-)
---
diff --git a/data/org.yorba.california.gschema.xml b/data/org.yorba.california.gschema.xml
index d7eda5f..5dfd453 100644
--- a/data/org.yorba.california.gschema.xml
+++ b/data/org.yorba.california.gschema.xml
@@ -46,6 +46,14 @@
         <description>
         </description>
     </key>
+    
+    <key name="first-of-week" type="s">
+        <default>"sunday"</default>
+        <summary>The first day of the week</summary>
+        <description>
+            For now, the only two respected values are "sunday" and "monday".
+        </description>
+    </key>
 </schema>
 
 </schemalist>
diff --git a/src/application/california-settings.vala b/src/application/california-settings.vala
index 59fe41b..91856d2 100644
--- a/src/application/california-settings.vala
+++ b/src/application/california-settings.vala
@@ -17,6 +17,7 @@ public class Settings : BaseObject {
     public const string PROP_WINDOW_WIDTH = "window-width";
     public const string PROP_WINDOW_HEIGHT = "window-height";
     public const string PROP_WINDOW_MAXIMIZED = "window-maximized";
+    public const string PROP_FIRST_OF_WEEK = "first-of-week";
     
     // GSettings schema identifier.
     private const string SCHEMA_ID = "org.yorba.california";
@@ -29,6 +30,10 @@ public class Settings : BaseObject {
     private const string KEY_WINDOW_WIDTH = "window-width";
     private const string KEY_WINDOW_HEIGHT = "window-height";
     private const string KEY_WINDOW_MAXIMIZED = "window-maximized";
+    private const string KEY_FIRST_OF_WEEK = "first-of-week";
+    
+    private const string VALUE_FIRST_OF_WEEK_SUNDAY = "sunday";
+    private const string VALUE_FIRST_OF_WEEK_MONDAY = "monday";
     
     public static Settings instance { get; private set; }
     
@@ -106,6 +111,11 @@ public class Settings : BaseObject {
      */
     public bool window_maximized { get; set; }
     
+    /**
+     * Configured first day of the week.
+     */
+    public Calendar.FirstOfWeek first_of_week { get; set; }
+    
     private GLib.Settings settings;
     
     private Settings() {
@@ -116,6 +126,13 @@ public class Settings : BaseObject {
         // themselves (with a bit more type safety)
         settings.bind(KEY_CALENDAR_VIEW, this, PROP_CALENDAR_VIEW, SettingsBindFlags.DEFAULT);
         settings.bind(KEY_WINDOW_MAXIMIZED, this, PROP_WINDOW_MAXIMIZED, SettingsBindFlags.DEFAULT);
+        
+        // bind_mapping() isn't well-bound in the VAPI, so do some of these transformations manually
+        settings.changed.connect(on_setting_changed);
+        notify[PROP_FIRST_OF_WEEK].connect(on_property_first_of_week_changed);
+        
+        // initialize these unbound values
+        on_setting_changed(KEY_FIRST_OF_WEEK);
     }
     
     internal static void init() throws Error {
@@ -135,6 +152,55 @@ public class Settings : BaseObject {
         instance = null;
     }
     
+    private void on_setting_changed(string key) {
+        switch (key.casefold()) {
+            case KEY_FIRST_OF_WEEK:
+                on_setting_first_of_week_changed(settings.get_string(KEY_FIRST_OF_WEEK));
+            break;
+        }
+    }
+    
+    private void on_setting_first_of_week_changed(string value) {
+        Calendar.FirstOfWeek to_set;
+        switch (value.casefold()) {
+            case VALUE_FIRST_OF_WEEK_MONDAY:
+                to_set = Calendar.FirstOfWeek.MONDAY;
+            break;
+            
+            case VALUE_FIRST_OF_WEEK_SUNDAY:
+                to_set = Calendar.FirstOfWeek.SUNDAY;
+            break;
+            
+            default:
+                to_set = Calendar.FirstOfWeek.DEFAULT;
+            break;
+        }
+        
+        // to avoid unnecessary notifications
+        if (first_of_week != to_set)
+            first_of_week = to_set;
+    }
+    
+    private void on_property_first_of_week_changed() {
+        string value;
+        switch (first_of_week) {
+            case Calendar.FirstOfWeek.MONDAY:
+                value = VALUE_FIRST_OF_WEEK_MONDAY;
+            break;
+            
+            case Calendar.FirstOfWeek.SUNDAY:
+                value = VALUE_FIRST_OF_WEEK_SUNDAY;
+            break;
+            
+            default:
+                assert_not_reached();
+        }
+        
+        // prevent costly writes
+        if (settings.get_string(KEY_FIRST_OF_WEEK).casefold() != value)
+            settings.set_string(KEY_FIRST_OF_WEEK, value);
+    }
+    
     public override string to_string() {
         return get_class().get_type().name();
     }
diff --git a/src/calendar/calendar-first-of-week.vala b/src/calendar/calendar-first-of-week.vala
index aacb2d4..ed87f5e 100644
--- a/src/calendar/calendar-first-of-week.vala
+++ b/src/calendar/calendar-first-of-week.vala
@@ -12,8 +12,16 @@ namespace California.Calendar {
 
 public enum FirstOfWeek {
     MONDAY,
-    SUNDAY;
+    SUNDAY,
     
+    /**
+     * Default { link FirstOfWeek}.
+     */
+    DEFAULT = SUNDAY;
+    
+    /**
+     * Converts the { link FirstOfWeek} into an actual { link DayOfWeek}.
+     */
     public DayOfWeek as_day_of_week() {
         switch (this) {
             case MONDAY:
diff --git a/src/host/host-main-window.vala b/src/host/host-main-window.vala
index f542eee..8cd4f2c 100644
--- a/src/host/host-main-window.vala
+++ b/src/host/host-main-window.vala
@@ -35,8 +35,6 @@ public class MainWindow : Gtk.ApplicationWindow {
      */
     public const int DEFAULT_HEIGHT = 768;
     
-    private const string PROP_FIRST_OF_WEEK = "first-of-week";
-    
     private const string DETAILED_ACTION_QUICK_CREATE_EVENT = "win.quick-create-event";
     private const string ACTION_QUICK_CREATE_EVENT = "quick-create-event";
     private const string ACCEL_QUICK_CREATE_EVENT = "<Primary>n";
@@ -85,9 +83,6 @@ public class MainWindow : Gtk.ApplicationWindow {
         { ACTION_RESET_FONT, on_reset_font }
     };
     
-    // Set as a property so it can be bound to the current View.Controllable
-    public Calendar.FirstOfWeek first_of_week { get; set; }
-    
     private Gtk.Button quick_add_button;
     private View.Palette palette;
     private View.Controllable month_view;
@@ -333,10 +328,6 @@ public class MainWindow : Gtk.ApplicationWindow {
             binding = current_controller.bind_property(View.Controllable.PROP_IS_VIEWING_TODAY, today,
                 "sensitive", BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
             current_bindings.add(binding);
-            
-            binding = current_controller.bind_property(View.Controllable.PROP_FIRST_OF_WEEK, this,
-                PROP_FIRST_OF_WEEK, BindingFlags.BIDIRECTIONAL);
-            current_bindings.add(binding);
         }
     }
     
diff --git a/src/toolkit/toolkit-stack-model.vala b/src/toolkit/toolkit-stack-model.vala
index cbd72be..fe9c02d 100644
--- a/src/toolkit/toolkit-stack-model.vala
+++ b/src/toolkit/toolkit-stack-model.vala
@@ -188,6 +188,14 @@ public class StackModel<G> : BaseObject {
     }
     
     /**
+     * Clear all items from the { link StackModel}.
+     */
+    public void clear() {
+        foreach (G item in items.keys.to_array())
+            remove(item);
+    }
+    
+    /**
      * Show the item using the specified transition.
      *
      * If the item was not already present in { link StackModel}, it will be added.
diff --git a/src/view/month/month-cell.vala b/src/view/month/month-cell.vala
index 1c788aa..d4242d1 100644
--- a/src/view/month/month-cell.vala
+++ b/src/view/month/month-cell.vala
@@ -18,7 +18,7 @@ internal class Cell : Common.EventsCell {
     public int col { get; private set; }
     
     public Cell(Grid owner, Calendar.Date date, int row, int col) {
-        base (owner.owner.palette, date, date.week_of(owner.first_of_week).to_date_span());
+        base (owner.owner.palette, date, date.week_of(Settings.instance.first_of_week).to_date_span());
         
         this.owner = owner;
         this.row = row;
@@ -26,13 +26,13 @@ internal class Cell : Common.EventsCell {
         
         notify[PROP_DATE].connect(update_top_line);
         
-        owner.notify[Grid.PROP_FIRST_OF_WEEK].connect(on_first_of_week_changed);
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].connect(on_first_of_week_changed);
         
         update_top_line();
     }
     
     ~Cell() {
-        owner.notify[Grid.PROP_FIRST_OF_WEEK].disconnect(on_first_of_week_changed);
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].disconnect(on_first_of_week_changed);
     }
     
     protected override Common.EventsCell? get_cell_for_date(Calendar.Date cell_date) {
@@ -40,7 +40,7 @@ internal class Cell : Common.EventsCell {
     }
     
     private void on_first_of_week_changed() {
-        change_date_and_neighbors(date, date.week_of(owner.first_of_week).to_date_span());
+        change_date_and_neighbors(date, date.week_of(Settings.instance.first_of_week).to_date_span());
     }
     
     protected override void draw_borders(Cairo.Context ctx) {
diff --git a/src/view/month/month-controller.vala b/src/view/month/month-controller.vala
index f1b4b54..268078a 100644
--- a/src/view/month/month-controller.vala
+++ b/src/view/month/month-controller.vala
@@ -43,11 +43,6 @@ public class Controller : BaseObject, View.Controllable {
     /**
      * @inheritDoc
      */
-    public Calendar.FirstOfWeek first_of_week { get; set; }
-    
-    /**
-     * @inheritDoc
-     */
     public string id { get { return VIEW_ID; } }
     
     /**
@@ -78,6 +73,7 @@ public class Controller : BaseObject, View.Controllable {
     private MasterGrid master_grid;
     private Gtk.Stack stack = new Gtk.Stack();
     private Toolkit.StackModel<Calendar.MonthOfYear> stack_model;
+    private Gee.HashMap<int, Gtk.Label> dow_labels = new Gee.HashMap<int, Gtk.Label>();
     private Calendar.MonthSpan cache_span;
     
     public Controller(View.Palette palette) {
@@ -101,13 +97,10 @@ public class Controller : BaseObject, View.Controllable {
             Gtk.Label dow_label = new Gtk.Label(null);
             dow_label.margin_top = 2;
             dow_label.margin_bottom = 2;
+            dow_label.label = Calendar.DayOfWeek.for_checked(col + 1,
+                Settings.instance.first_of_week).abbrev_name;
             
-            // update label if first-of-week changes
-            int dow_col = col + Calendar.DayOfWeek.MIN;
-            notify[PROP_FIRST_OF_WEEK].connect(() => {
-                Calendar.DayOfWeek dow = Calendar.DayOfWeek.for_checked(dow_col, first_of_week);
-                dow_label.label = dow.abbrev_name;
-            });
+            dow_labels.set(col, dow_label);
             
             master_grid.attach(dow_label, col, 0, 1, 1);
         }
@@ -118,15 +111,15 @@ public class Controller : BaseObject, View.Controllable {
         
         notify[PROP_MONTH_OF_YEAR].connect(on_month_of_year_changed);
         Calendar.System.instance.today_changed.connect(on_today_changed);
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].connect(on_first_of_week_changed);
         
-        // update now that signal handlers are in place ... do first_of_week first since more heavy
-        // processing is done when month_of_year changes
-        first_of_week = Calendar.FirstOfWeek.SUNDAY;
+        // update now that signal handlers are in place
         month_of_year = Calendar.System.today.month_of_year();
     }
     
     ~Controller() {
         Calendar.System.instance.today_changed.disconnect(on_today_changed);
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].disconnect(on_first_of_week_changed);
     }
     
     private Gtk.Widget model_presentation(Calendar.MonthOfYear moy, out string? id) {
@@ -209,6 +202,15 @@ public class Controller : BaseObject, View.Controllable {
         update_is_viewing_today();
     }
     
+    private void on_first_of_week_changed() {
+        Gee.MapIterator<int, Gtk.Label> iter = dow_labels.map_iterator();
+        while (iter.next()) {
+            Calendar.DayOfWeek dow = Calendar.DayOfWeek.for_checked(iter.get_key() + 1,
+                Settings.instance.first_of_week);
+            iter.get_value().label = dow.abbrev_name;
+        }
+    }
+    
     private void on_month_of_year_changed() {
         current_label = month_of_year.full_name;
         update_is_viewing_today();
diff --git a/src/view/month/month-grid.vala b/src/view/month/month-grid.vala
index 8203f62..624e563 100644
--- a/src/view/month/month-grid.vala
+++ b/src/view/month/month-grid.vala
@@ -13,7 +13,6 @@ namespace California.View.Month {
 private class Grid : Gtk.Grid {
     public const string PROP_MONTH_OF_YEAR = "month-of-year";
     public const string PROP_WINDOW = "window";
-    public const string PROP_FIRST_OF_WEEK = "first-of-week";
     
     // days of the week
     public const int COLS = Calendar.DayOfWeek.COUNT;
@@ -36,11 +35,6 @@ private class Grid : Gtk.Grid {
     public Calendar.MonthOfYear month_of_year { get; private set; }
     
     /**
-     * The first day of the week, as defined by this { link Grid}'s { link Controller}.
-     */
-    public Calendar.FirstOfWeek first_of_week { get; private set; }
-    
-    /**
      * The span of dates being displayed.
      */
     public Calendar.DateSpan window { get; private set; }
@@ -60,7 +54,6 @@ private class Grid : Gtk.Grid {
     public Grid(Controller owner, Calendar.MonthOfYear month_of_year) {
         this.owner = owner;
         this.month_of_year = month_of_year;
-        first_of_week = owner.first_of_week;
         
         column_homogeneous = true;
         column_spacing = 0;
@@ -96,12 +89,12 @@ private class Grid : Gtk.Grid {
         update_subscriptions();
         
         owner.notify[Controller.PROP_MONTH_OF_YEAR].connect(on_controller_month_of_year_changed);
-        owner.notify[View.Controllable.PROP_FIRST_OF_WEEK].connect(update_first_of_week);
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].connect(update_first_of_week);
     }
     
     ~Grid() {
         owner.notify[Controller.PROP_MONTH_OF_YEAR].disconnect(on_controller_month_of_year_changed);
-        owner.notify[View.Controllable.PROP_FIRST_OF_WEEK].disconnect(update_first_of_week);
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].disconnect(update_first_of_week);
     }
     
     private Cell get_cell(int row, int col) {
@@ -157,7 +150,7 @@ private class Grid : Gtk.Grid {
     private void update_week(int row, Calendar.Week week) {
         Calendar.DateSpan week_as_date_span = week.to_date_span();
         foreach (Calendar.Date date in week) {
-            int col = date.day_of_week.ordinal(owner.first_of_week) - 1;
+            int col = date.day_of_week.ordinal(Settings.instance.first_of_week) - 1;
             
             Cell cell = get_cell(row, col);
             cell.change_date_and_neighbors(date, week_as_date_span);
@@ -173,8 +166,8 @@ private class Grid : Gtk.Grid {
         
         // create a WeekSpan for the first week of the month to the last displayed week (not all
         // months will fill all displayed weeks, but some will)
-        Calendar.WeekSpan span = new 
Calendar.WeekSpan.count(month_of_year.to_week_span(owner.first_of_week).first,
-            ROWS - 1);
+        Calendar.WeekSpan span = new Calendar.WeekSpan.count(
+            month_of_year.to_week_span(Settings.instance.first_of_week).first, ROWS - 1);
         
         // fill in weeks of the displayed month
         int row = 0;
@@ -234,12 +227,6 @@ private class Grid : Gtk.Grid {
     }
     
     private void update_first_of_week() {
-        // avoid some extra work
-        if (first_of_week == owner.first_of_week)
-            return;
-        
-        first_of_week = owner.first_of_week;
-        
         // requires updating all the cells as well, since all dates have to be shifted
         update_cells();
         update_subscriptions();
diff --git a/src/view/view-controllable.vala b/src/view/view-controllable.vala
index d004fb0..0251c9c 100644
--- a/src/view/view-controllable.vala
+++ b/src/view/view-controllable.vala
@@ -18,7 +18,6 @@ public interface Controllable : Object {
     public const string PROP_CURRENT_LABEL = "current-label";
     public const string PROP_IS_VIEWING_TODAY = "is-viewing-today";
     public const string PROP_DEFAULT_DATE = "default-date";
-    public const string PROP_FIRST_OF_WEEK = "first-of-week";
     
     /**
      * A short string uniquely identifying this view.
@@ -47,11 +46,6 @@ public interface Controllable : Object {
     public abstract bool is_viewing_today { get; protected set; }
     
     /**
-     * The first day of the week.
-     */
-    public abstract Calendar.FirstOfWeek first_of_week { get; set; }
-    
-    /**
      * Signal from the { link Controllable} that a DATE-TIME { link Component.Event} should be
      * created with the specified initial parameters.
      */
diff --git a/src/view/week/week-all-day-cell.vala b/src/view/week/week-all-day-cell.vala
index 66f242a..7f48d53 100644
--- a/src/view/week/week-all-day-cell.vala
+++ b/src/view/week/week-all-day-cell.vala
@@ -20,10 +20,11 @@ internal class AllDayCell : Common.EventsCell {
     public Grid owner { get; private set; }
     
     public AllDayCell(Grid owner, Calendar.Date date) {
-        base (owner.owner.palette, date, date.week_of(owner.owner.first_of_week).to_date_span());
+        base (owner.owner.palette, date, date.week_of(Settings.instance.first_of_week).to_date_span());
         
         this.owner = owner;
         
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].connect(on_first_of_week_changed);
         palette.palette_changed.connect(on_palette_changed);
         
         // use for initialization
@@ -31,6 +32,7 @@ internal class AllDayCell : Common.EventsCell {
     }
     
     ~AllDayCell() {
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].disconnect(on_first_of_week_changed);
         palette.palette_changed.disconnect(on_palette_changed);
     }
     
@@ -43,6 +45,10 @@ internal class AllDayCell : Common.EventsCell {
         set_size_request(-1, (palette.small_font_height_px + Palette.LINE_PADDING_PX) * LINES_SHOWN);
     }
     
+    private void on_first_of_week_changed() {
+        change_date_and_neighbors(date, date.week_of(Settings.instance.first_of_week).to_date_span());
+    }
+    
     protected override void draw_borders(Cairo.Context ctx) {
         int width = get_allocated_width();
         int height = get_allocated_height();
diff --git a/src/view/week/week-controller.vala b/src/view/week/week-controller.vala
index 7802306..fd636a1 100644
--- a/src/view/week/week-controller.vala
+++ b/src/view/week/week-controller.vala
@@ -52,11 +52,6 @@ public class Controller : BaseObject, View.Controllable {
     public bool is_viewing_today { get; protected set; }
     
     /**
-     * @inheritDoc
-     */
-    public Calendar.FirstOfWeek first_of_week { get; set; }
-    
-    /**
      * { link View.Palette} for the entire hosted view.
      */
     public View.Palette palette { get; private set; }
@@ -76,16 +71,16 @@ public class Controller : BaseObject, View.Controllable {
             Toolkit.StackModel.OrderedTransitionType.SLIDE_LEFT_RIGHT, model_presentation,
             trim_presentation_from_cache, ensure_presentation_in_cache);
         
-        // set this before signal handlers are in place (week and first_of_week are very closely
-        // tied in this view)
-        first_of_week = Calendar.FirstOfWeek.SUNDAY;
-        
         // changing these properties drives a lot of the what the view displays
-        notify[View.Controllable.PROP_FIRST_OF_WEEK].connect(on_first_of_week_changed);
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].connect(on_first_of_week_changed);
         notify[PROP_WEEK].connect(on_week_changed);
         
         // set this now that signal handlers are in place
-        week = Calendar.System.today.week_of(first_of_week);
+        week = Calendar.System.today.week_of(Settings.instance.first_of_week);
+    }
+    
+    ~Controller() {
+        Settings.instance.notify[Settings.PROP_FIRST_OF_WEEK].disconnect(on_first_of_week_changed);
     }
     
     /**
@@ -113,7 +108,7 @@ public class Controller : BaseObject, View.Controllable {
      * @inheritDoc
      */
     public void today() {
-        Calendar.Week this_week = Calendar.System.today.week_of(first_of_week);
+        Calendar.Week this_week = Calendar.System.today.week_of(Settings.instance.first_of_week);
         if (!week.equal_to(this_week))
             week = this_week;
     }
@@ -140,7 +135,7 @@ public class Controller : BaseObject, View.Controllable {
     
     private bool trim_presentation_from_cache(Calendar.Week week, Calendar.Week? visible_week) {
         // always keep today's week in cache
-        if (week.equal_to(Calendar.System.today.week_of(first_of_week)))
+        if (week.equal_to(Calendar.System.today.week_of(Settings.instance.first_of_week)))
             return false;
         
         // otherwise only keep weeks that are in the current cache span
@@ -152,15 +147,14 @@ public class Controller : BaseObject, View.Controllable {
         Gee.List<Calendar.Week> weeks = cache_span.as_list();
         
         // add today's week to the mix
-        weeks.add(Calendar.System.today.week_of(first_of_week));
+        weeks.add(Calendar.System.today.week_of(Settings.instance.first_of_week));
         
         return weeks;
     }
     
     private void on_first_of_week_changed() {
-        // update week to reflect this change, but only if necessary
-        if (first_of_week != week.first_of_week)
-            week = week.start_date.week_of(first_of_week);
+        stack_model.clear();
+        week = week.start_date.week_of(Settings.instance.first_of_week);
     }
     
     private void on_week_changed() {


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