Commit de92610a authored by Jim Nelson's avatar Jim Nelson

Basic plumbing and conversion set up

parent 406a149a
......@@ -133,6 +133,7 @@ california_RC = \
rc/google-login.ui \
rc/show-event.ui \
rc/webcal-subscribe.ui \
rc/windowsZones.xml \
......@@ -116,7 +116,7 @@ public class Application : Gtk.Application {
add_action_entries(action_entries, this);
set_app_menu(Resource.load<MenuModel>("app-menu.interface", "app-menu"));
set_app_menu(Resource.load_object<MenuModel>("app-menu.interface", "app-menu"));
// This method is invoked when the main loop terminates on the primary instance.
......@@ -5,21 +5,41 @@
* Utility methods to facilitiate loading Resources and converting them into useful objects.
* Utility methods to facilitiate loading Resources.
* These methods assume that the resource must be present for proper operation and so treat hard
* failures as cause for application termination.
namespace California.Resource {
public const string DEFAULT_PATH = "/org/yorba/california/rc";
private string create_fullpath(string path, string resource) {
return "%s%s%s".printf(path, path.has_suffix("/") ? "" : "/", resource);
* Loads the resource and returns it as Bytes.
public Bytes load_bytes(string resource_name, string path = DEFAULT_PATH) {
string fullpath = create_fullpath(path, resource_name);
try {
return resources_lookup_data(fullpath, ResourceLookupFlags.NONE);
} catch (Error err) {
error("Unable to load resource %s: %s", fullpath, err.message);
* Loads the resource and returns it as a casted object.
* Loads the resource, parses it with Gtk.Builder, and returns it as a casted object.
* Any load error will cause the application to panic. This generally indicates the resource
* was not compiled in or that the path is malformed.
public T load<T>(string resource, string object_name, string path = DEFAULT_PATH) {
string fullpath = "%s%s%s".printf(path, path.has_suffix("/") ? "" : "/", resource);
public T load_object<T>(string resource_name, string object_name, string path = DEFAULT_PATH) {
string fullpath = create_fullpath(path, resource_name);
Gtk.Builder builder = new Gtk.Builder();
try {
......@@ -12,8 +12,8 @@ namespace California.Calendar {
* An Olson name is in the form of "Area/Location". This class merely encapsulates this string
* and gives it some type-ness; actual time zone calculations is left to {@link Timezone}.
* In particular, little error-checking is performed by this class. It also does no processing
* or consideration for zone aliases ("links"), which is why it does not implement Gee.Hashable or
* Gee.Comparable.
* or consideration for zone aliases ("links"). It is Gee.Hashable, but that is purely based on
* string comparisons with no other logic involved.
* This class is immutable.
......@@ -22,9 +22,11 @@ namespace California.Calendar {
* The IANA database of Olson zones and related information is located at
* [[]]
* @see WindowsZone
public class OlsonZone : BaseObject {
public class OlsonZone : BaseObject, Gee.Hashable<OlsonZone> {
* The string value this class uses if an empty string is passed to the constructor.
......@@ -46,16 +48,111 @@ public class OlsonZone : BaseObject {
public string value { get; private set; }
private static Gee.HashMap<string, OlsonZone>? windows_to_olson = null;
public OlsonZone(string area_location) {
value = !String.is_empty(area_location) ? area_location : UTC;
string stripped = area_location.strip();
value = !String.is_empty(stripped) ? stripped : UTC;
internal static void init() {
utc = new OlsonZone(UTC);
// Load Windows -> Olson conversion table
internal static void load_conversions() throws Error {
windows_to_olson = new Gee.HashMap<string, OlsonZone>(String.stri_hash, String.stri_equal);
// to conserve resident objects, as these will stick around the lifetime of the application
Gee.HashMap<string, OlsonZone> name_to_olson = new Gee.HashMap<string, OlsonZone>(
String.stri_hash, String.stri_equal);
// Yes, we should be doing this with a proper XML DOM library, but (a) libxml2 is kind of
// messy to work with, (b) it doesn't guarantee to be compiled with XPath support, which
// would sure make our lives easier here, and (c) we're in complete control of the data being
// parsed, and so XML validation and correct traversal is less important
char[] windows_buf = new char[4096];
char[] territory_buf = new char[4096];
char[] olson_buf = new char[4096];
DataInputStream dins = new DataInputStream(
new MemoryInputStream.from_bytes(Resource.load_bytes("windowsZones.xml")));
for (;;) {
string? line = dins.read_line();
if (line == null)
line = line.strip();
if (String.is_empty(line))
// Note that the width specifier matches the size of the character arrays above
int count = line.scanf("<mapZone other=\"%4096[^\"]\" territory=\"%4096[^\"]\" type=\"%4096[^\"]\"/>",
windows_buf, territory_buf, olson_buf);
if (count != 3)
// only interested in territory "001", the primary territory, which is how the conversion
// is made
string territory = ((string) territory_buf).strip();
if (territory != "001")
string windows = ((string) windows_buf).strip();
string olson = ((string) olson_buf).strip();
// unlike other entries, 001 is always a single Olson code, otherwise the value would
// need to be tokenized
assert(!olson.contains(" "));
// conserve Olson zone objects (one can be assigned to many Windows zone names)
OlsonZone? olson_zone = name_to_olson.get(olson);
if (olson_zone == null) {
olson_zone = new OlsonZone(olson);
name_to_olson.set(olson_zone.value, olson_zone);
windows_to_olson.set(windows, olson_zone);
internal static void terminate() {
utc = null;
windows_to_olson = null;
* Returns the {@link OlsonZone}, if any, for a Windows zone name.
* Windows time zone names tend to be a single descriptive string, such as "Pacific Standard Time".
* There are often variations of the same time zone with different names depending on political
* and national bounaries. They are always transmitted in English.
* For more information, see
* [[]]
public OlsonZone? for_windows_zone(string name) {
assert(windows_to_olson != null);
return windows_to_olson.get(name.strip());
* See the class notes for stipulations about object equality.
public uint hash() {
return String.stri_hash(value);
* See the class notes for stipulations about object equality.
public bool equal_to(OlsonZone other) {
return (this != other) ? String.stri_equal(value, other.value) : true;
public override string to_string() {
......@@ -19,25 +19,25 @@ namespace California.Calendar {
private int init_count = 0;
private static unowned string FMT_MONTH_YEAR_FULL;
private static unowned string FMT_MONTH_YEAR_ABBREV;
private static unowned string FMT_MONTH_FULL;
private static unowned string FMT_MONTH_ABBREV;
private static unowned string FMT_DAY_OF_WEEK_FULL;
private static unowned string FMT_DAY_OF_WEEK_ABBREV;
private static unowned string FMT_FULL_DATE;
private static unowned string FMT_PRETTY_DATE;
private static unowned string FMT_PRETTY_DATE_NO_YEAR;
private static unowned string FMT_PRETTY_DATE_ABBREV;
private static unowned string FMT_PRETTY_DATE_ABBREV_NO_YEAR;
private static unowned string FMT_AM;
private static unowned string FMT_BRIEF_AM;
private static unowned string FMT_PM;
private static unowned string FMT_BRIEF_PM;
private static unowned string FMT_12HOUR_MIN_MERIDIEM;
private static unowned string FMT_12HOUR_MIN_SEC_MERIDIEM;
private static unowned string FMT_24HOUR_MIN;
private static unowned string FMT_24HOUR_MIN_SEC;
private unowned string FMT_MONTH_YEAR_FULL;
private unowned string FMT_MONTH_YEAR_ABBREV;
private unowned string FMT_MONTH_FULL;
private unowned string FMT_MONTH_ABBREV;
private unowned string FMT_DAY_OF_WEEK_FULL;
private unowned string FMT_DAY_OF_WEEK_ABBREV;
private unowned string FMT_FULL_DATE;
private unowned string FMT_PRETTY_DATE;
private unowned string FMT_PRETTY_DATE_NO_YEAR;
private unowned string FMT_PRETTY_DATE_ABBREV;
private unowned string FMT_PRETTY_DATE_ABBREV_NO_YEAR;
private unowned string FMT_AM;
private unowned string FMT_BRIEF_AM;
private unowned string FMT_PM;
private unowned string FMT_BRIEF_PM;
private unowned string FMT_12HOUR_MIN_MERIDIEM;
private unowned string FMT_12HOUR_MIN_SEC_MERIDIEM;
private unowned string FMT_24HOUR_MIN;
private unowned string FMT_24HOUR_MIN_SEC;
public void init() throws Error {
if (!California.Unit.do_init(ref init_count))
......@@ -149,6 +149,9 @@ public void init() throws Error {
// this needs to be peformed after the rest of the namespace is initialized
public void terminate() {
......@@ -36,5 +36,8 @@
<gresource prefix="/org/yorba/california">
<file compressed="true">rc/webcal-subscribe.ui</file>
<gresource prefix="/org/yorba/california">
<file compressed="true">rc/windowsZones.xml</file>
This diff is collapsed.
......@@ -16,6 +16,14 @@ public int stricmp(string a, string b) {
return strcmp(a.casefold(), b.casefold());
public uint stri_hash(string str) {
return str.down().hash();
public bool stri_equal(string a, string b) {
return stricmp(a, b) == 0;
* Removes redundant whitespace (including tabs and newlines) and strips whitespace from beginning
* and end of string.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment