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 \
$(NULL)
california_OPTIONAL_VALAFLAGS =
......
......@@ -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
* [[https://www.iana.org/time-zones]]
*
* @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")));
dins.set_newline_type(DataStreamNewlineType.ANY);
for (;;) {
string? line = dins.read_line();
if (line == null)
break;
line = line.strip();
if (String.is_empty(line))
continue;
// 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)
continue;
// only interested in territory "001", the primary territory, which is how the conversion
// is made
string territory = ((string) territory_buf).strip();
if (territory != "001")
continue;
string windows = ((string) windows_buf).strip();
assert(!String.is_empty(windows));
string olson = ((string) olson_buf).strip();
assert(!String.is_empty(olson));
// 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);
}
assert(!windows_to_olson.has_key(windows));
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
* [[http://technet.microsoft.com/en-us/library/cc749073%28v=ws.10%29.aspx]]
*/
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 {
WallTime.init();
System.init();
Timezone.init();
// this needs to be peformed after the rest of the namespace is initialized
OlsonZone.load_conversions();
}
public void terminate() {
......
......@@ -36,5 +36,8 @@
<gresource prefix="/org/yorba/california">
<file compressed="true">rc/webcal-subscribe.ui</file>
</gresource>
<gresource prefix="/org/yorba/california">
<file compressed="true">rc/windowsZones.xml</file>
</gresource>
</gresources>
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