[california/wip/725792-quick-add: 2/2] Started parser



commit 340ab2b0e4f080d180d4455f1776368d0601b175
Author: Jim Nelson <jim yorba org>
Date:   Wed Apr 16 20:03:00 2014 -0700

    Started parser

 src/calendar/calendar-date.vala        |   14 +++++
 src/calendar/calendar-day-of-week.vala |   18 +++++++
 src/calendar/calendar-wall-time.vala   |   61 ++++++++++++++++++++++
 src/host/host-quick-create-event.vala  |   88 ++++++++++++++++++++++++++++++++
 src/util/util-string.vala              |   17 ++++++
 5 files changed, 198 insertions(+), 0 deletions(-)
---
diff --git a/src/calendar/calendar-date.vala b/src/calendar/calendar-date.vala
index c9166b0..5ba97ba 100644
--- a/src/calendar/calendar-date.vala
+++ b/src/calendar/calendar-date.vala
@@ -250,6 +250,20 @@ 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-day-of-week.vala b/src/calendar/calendar-day-of-week.vala
index e5d6f2f..56698a4 100644
--- a/src/calendar/calendar-day-of-week.vala
+++ b/src/calendar/calendar-day-of-week.vala
@@ -180,6 +180,24 @@ public class DayOfWeek : BaseObject, Gee.Hashable<DayOfWeek> {
     }
     
     /**
+     * Parses the string looking for a match with any of the { link DayOfWeek}'s { link abbrev_name}
+     * or { link full_name}.
+     */
+    public static DayOfWeek? parse(string str) {
+        string token = str.strip().down();
+        
+        foreach (DayOfWeek dow in days_of_week_monday) {
+            if (dow.abbrev_name.down() == token)
+                return dow;
+            
+            if (dow.full_name.down() == token)
+                return dow;
+        }
+        
+        return null;
+    }
+    
+    /**
      * The one-based ordinal value of the day of the week, depended on what the definition of
      * the first day of the week.
      */
diff --git a/src/calendar/calendar-wall-time.vala b/src/calendar/calendar-wall-time.vala
index 7eecb7b..9b05a16 100644
--- a/src/calendar/calendar-wall-time.vala
+++ b/src/calendar/calendar-wall-time.vala
@@ -92,6 +92,8 @@ public class WallTime : BaseObject, Gee.Comparable<WallTime>, Gee.Hashable<WallT
     /**
      * Generate a new { link WallTime} object with the specified values.
      *
+     * Note that hour must be in 24-hour time.
+     *
      * Values will be clamped to create a valid time.
      */
     public WallTime(int hour, int minute, int second) {
@@ -134,6 +136,65 @@ public class WallTime : BaseObject, Gee.Comparable<WallTime>, Gee.Hashable<WallT
     }
     
     /**
+     * Attempt to convert a string into { link WallTime}.
+     */
+    public static WallTime? parse(string str) {
+        string token = str.strip().down();
+        if (String.is_empty(token))
+            return null;
+        
+        // look for meridiem tacked on to end
+        bool pm = false;
+        bool meridiem_unknown = false;
+        if (token.has_suffix(FMT_AM)) {
+            token = token.slice(0, token.length - FMT_AM.length);
+        } else if (token.has_suffix(FMT_BRIEF_AM)) {
+            token = token.slice(0, token.length - FMT_BRIEF_AM.length);
+        } else if (token.has_suffix(FMT_PM)) {
+            token = token.slice(0, token.length - FMT_PM.length);
+            pm = true;
+        } else if (token.has_suffix(FMT_BRIEF_PM)) {
+            token = token.slice(0, token.length - FMT_BRIEF_PM.length);
+            pm = true;
+        } else {
+            meridiem_unknown = true;
+        }
+        
+        // remove colon (can be present for 12- or 24-hour time)
+        token = token.replace(":", "");
+        int length = token.length;
+        
+        // rest of string better be numeric and under the common lengths for specifying time
+        if (!String.is_numeric(token) || length == 0 || length > 4)
+            return null;
+        
+        // look for 24-hour time or a fully-detailed 12-hour time
+        if ((length == 3 || length == 4)) {
+            int h, m;
+            if (length == 3) {
+                h = int.parse(token.slice(0, 1));
+                m = int.parse(token.slice(1, 3));
+            } else {
+                h = int.parse(token.slice(0, 2));
+                m = int.parse(token.slice(2, 4));
+            }
+            
+            if (!meridiem_unknown && pm)
+                h += 12;
+            
+            return new WallTime(h, m, 0);
+        }
+        
+        // otherwise, treat as short-form 12-hour time (even if meridiem is unknown, i.e. "8" is
+        // treated as "8:00am"
+        int h = int.parse(token);
+        if (!meridiem_unknown && pm)
+            h += 12;
+        
+        return new WallTime(h, 0, 0);
+    }
+    
+    /**
      * Returns { link WallTime} adjusted before or after this one.
      *
      * To subtract time, use a negative value.
diff --git a/src/host/host-quick-create-event.vala b/src/host/host-quick-create-event.vala
index d004422..b750b4c 100644
--- a/src/host/host-quick-create-event.vala
+++ b/src/host/host-quick-create-event.vala
@@ -35,6 +35,7 @@ public class QuickCreateEvent : Gtk.Grid, Toolkit.Card {
     [GtkCallback]
     private void on_details_entry_icon_release(Gtk.Entry entry, Gtk.EntryIconPosition icon,
         Gdk.Event event) {
+        // check for clear icon being pressed
         if (icon == Gtk.EntryIconPosition.SECONDARY)
             details_entry.text = "";
     }
@@ -46,9 +47,96 @@ public class QuickCreateEvent : Gtk.Grid, Toolkit.Card {
     
     [GtkCallback]
     private void on_create_button_clicked() {
+        parse(details_entry.text);
+        
         completed();
         dismissed(true);
     }
+    
+    // TODO: Temporary.  This logic should be moved out of the UI layer
+    private Component.Event? parse(string details) {
+        StringBuilder title = new StringBuilder();
+        Calendar.WallTime? start_time = null;
+        Calendar.WallTime? end_time = null;
+        Calendar.Date? start_date = null;
+        Calendar.Date? end_date = null;
+        
+        string[] tokens = String.reduce_whitespace(details).split(" ");
+        for (int ctr = 0; ctr < tokens.length; ctr++) {
+            string token = tokens[ctr].down();
+            
+            Calendar.WallTime? wall_time = Calendar.WallTime.parse(token);
+            if (wall_time != null) {
+                if (start_time == null) {
+                    start_time = wall_time;
+                    
+                    continue;
+                }
+                
+                if (end_time == null) {
+                    end_time = wall_time;
+                    
+                    continue;
+                }
+            }
+            
+            // TODO: use internationalized strings
+            Calendar.Date? date = null;
+            switch (token) {
+                case "today":
+                    date = Calendar.System.today;
+                break;
+                
+                case "tomorrow":
+                    date = Calendar.System.today.next();
+                break;
+                
+                case "yesterday":
+                    date = Calendar.System.today.previous();
+                break;
+            }
+            
+            if (date == null) {
+                Calendar.DayOfWeek? dow = Calendar.DayOfWeek.parse(token);
+                if (dow != null) {
+                    Calendar.Date upcoming = Calendar.System.today;
+                    Calendar.Date next_week = upcoming.adjust(1, Calendar.DateUnit.WEEK);
+                    do {
+                        if (upcoming.day_of_week.equal_to(dow))
+                            date = upcoming;
+                        else
+                            upcoming = upcoming.next();
+                    } while (date == null && !upcoming.equal_to(next_week));
+                }
+            }
+            
+            if (date != null) {
+                if (start_date == null) {
+                    start_date = date;
+                    
+                    continue;
+                }
+                
+                if (end_date == null) {
+                    end_date = date;
+                    
+                    continue;
+                }
+            }
+            
+            if (!String.is_empty(title.str))
+                title.append_unichar(' ');
+            title.append(tokens[ctr]);
+        }
+        
+        debug("start time: %s", (start_time != null) ? start_time.to_string() : "(null)");
+        debug("end time: %s", (end_time != null) ? end_time.to_string() : "(null)");
+        debug("start date: %s", (start_date != null) ? start_date.to_string() : "(null)");
+        debug("end date: %s", (end_date != null) ? end_date.to_string() : "(null)");
+        debug("title: \"%s\"", title.str);
+        
+        return null;
+    }
 }
 
 }
diff --git a/src/util/util-string.vala b/src/util/util-string.vala
index 693cb11..781b236 100644
--- a/src/util/util-string.vala
+++ b/src/util/util-string.vala
@@ -44,5 +44,22 @@ public string reduce_whitespace(string str) {
     return builder.str;
 }
 
+/**
+ * Returns true if every character in the string is a numeric digit.
+ */
+public bool is_numeric(string? str) {
+    if (is_empty(str))
+        return false;
+    
+    unichar ch;
+    int index = 0;
+    while (str.get_next_char(ref index, out ch)) {
+        if (!ch.isdigit())
+            return false;
+    }
+    
+    return true;
+}
+
 }
 


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