[libgweather/ebassi/issue-161] location: Add getter for time zone name




commit d84d9614b12fa628d5fafdeaaf9f723effcd8bd1
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Jan 13 02:41:02 2022 +0000

    location: Add getter for time zone name
    
    When I removed GWeatherTimezone I inadvertedly missed the only
    functionality that the type provided on top of GTimeZone, and that
    is: the ability to retrieve the human readable, localised name of the
    time zone bound to a location. That information does not exist in the
    time zone database as parsed by GLib, but it is available in GWeather's
    location database. This means we need to retrieve the time zone reference
    from the location's database, just like we do for
    gweather_location_get_timezone(), and from that reference we retrieve the
    localised string with the time zone name.
    
    The old GWeather-3 API allowed retrieving the name for any given
    GWeatherTimezone, but since all time zones are bound to a location, we can
    skip that particular aspect of the API.
    
    Fixes: #161

 libgweather/gweather-location.c | 103 ++++++++++++++++++++++++++++++++++++++++
 libgweather/gweather-location.h |   3 ++
 libgweather/tests/timezones.c   |  49 +++++++++++++++++++
 3 files changed, 155 insertions(+)
---
diff --git a/libgweather/gweather-location.c b/libgweather/gweather-location.c
index 0ad5adcf..51375092 100644
--- a/libgweather/gweather-location.c
+++ b/libgweather/gweather-location.c
@@ -1063,6 +1063,109 @@ gweather_location_get_timezone_str (GWeatherLocation *loc)
     return NULL;
 }
 
+static const char *
+timezone_ref_get_name (GWeatherDb *db,
+                       guint16 idx)
+{
+    DbWorldTimezonesEntryRef entry_ref =
+        db_world_timezones_get_at (db->timezones_ref, idx);
+
+    DbTimezoneRef tz_ref = db_world_timezones_entry_get_value (entry_ref);
+    DbI18nRef tz_name = db_timezone_get_name (tz_ref);
+
+    const char *name = EMPTY_TO_NULL (db_i18n_get_str (tz_name));
+    const char *msgctxt = EMPTY_TO_NULL (db_i18n_get_msgctxt (tz_name));
+
+    if (name != NULL) {
+        if (msgctxt != NULL) {
+            return g_dpgettext2 (LOCATIONS_GETTEXT_PACKAGE, msgctxt, name);
+        } else {
+            return g_dgettext (LOCATIONS_GETTEXT_PACKAGE, name);
+        }
+    }
+
+    return NULL;
+}
+
+static void
+add_timezones_name (GWeatherLocation *self,
+                    const char *identifier,
+                    GPtrArray *names)
+{
+    /* NOTE: Only DB backed locations can have timezones */
+    if (self->db && IDX_VALID (self->db_idx)) {
+        DbArrayofuint16Ref ref;
+        gsize len;
+
+        ref = db_location_get_timezones (self->ref);
+        len = db_arrayofuint16_get_length (ref);
+        for (gsize i = 0; i < len; i++) {
+            guint16 tz_idx = db_arrayofuint16_get_at (ref, i);
+
+            g_autoptr (GTimeZone) tz = timezone_ref_for_idx (self->db, tz_idx);
+            const char *tz_id = g_time_zone_get_identifier (tz);
+
+            if (identifier == NULL || g_strcmp0 (identifier, tz_id) == 0) {
+                g_ptr_array_add (names, (gpointer) timezone_ref_get_name (self->db, tz_idx));
+            }
+        }
+    }
+
+    /* Collect regions and world */
+    if (self->level < GWEATHER_LOCATION_COUNTRY) {
+        g_autoptr (GWeatherLocation) child = NULL;
+
+        while ((child = gweather_location_next_child (self, child)))
+            add_timezones_name (child, identifier, names);
+    }
+}
+
+/**
+ * gweather_location_get_timezone_name:
+ * @loc: the location to query
+ * @tzid: (nullable): the identifier of a timezone
+ *
+ * Retrieves the human readable, localized name of the timezone available
+ * at the given location, if any.
+ *
+ * If @tzid is omitted then the returned name will be the one of the first
+ * available timezone.
+ *
+ * If @loc is `GWEATHER_LOCATION_WORLD` and @tzid is `NULL` then this
+ * function will return the localized name for the Coordinated Universal
+ * Time (UTC).
+ *
+ * Returns: (transfer none) (nullable): the human readable name of the
+ *   location's timezone
+ */
+const char *
+gweather_location_get_timezone_name (GWeatherLocation *loc,
+                                     const char *tzid)
+{
+    g_autoptr (GWeatherLocation) s = NULL;
+
+    g_return_val_if_fail (GWEATHER_IS_LOCATION (loc), NULL);
+
+    /* We need to special-case UTC, because that's what the old libgweather-3
+     * used to do
+     */
+    if (loc->level == GWEATHER_LOCATION_WORLD && tzid == NULL) {
+        return _ ("Coordinated Universal Time (UTC)");
+    }
+
+    /* The names are constant strings inside the translation catalogue */
+    g_autoptr (GPtrArray) names = g_ptr_array_new ();
+
+    add_timezones_name (loc, tzid, names);
+
+    /* No name found */
+    if (names->len == 0)
+        return NULL;
+
+    /* The first item is always the result */
+    return g_ptr_array_index (names, 0);
+}
+
 static void
 add_timezones (GWeatherLocation *loc,
                GPtrArray *zones)
diff --git a/libgweather/gweather-location.h b/libgweather/gweather-location.h
index 4e33a108..bddfd9bf 100644
--- a/libgweather/gweather-location.h
+++ b/libgweather/gweather-location.h
@@ -147,6 +147,9 @@ GTimeZone *             gweather_location_get_timezone          (GWeatherLocatio
 GWEATHER_AVAILABLE_IN_ALL
 const char *            gweather_location_get_timezone_str      (GWeatherLocation  *loc);
 GWEATHER_AVAILABLE_IN_ALL
+const char *            gweather_location_get_timezone_name     (GWeatherLocation  *loc,
+                                                                 const char        *tzid);
+GWEATHER_AVAILABLE_IN_ALL
 GTimeZone **            gweather_location_get_timezones         (GWeatherLocation  *loc);
 GWEATHER_AVAILABLE_IN_ALL
 void                    gweather_location_free_timezones        (GWeatherLocation  *loc,
diff --git a/libgweather/tests/timezones.c b/libgweather/tests/timezones.c
index 5475c223..41c134f2 100644
--- a/libgweather/tests/timezones.c
+++ b/libgweather/tests/timezones.c
@@ -147,6 +147,19 @@ test_timezone (GWeatherLocation *location)
         tzs = gweather_location_get_timezones (location);
         g_assert_nonnull (tzs);
 
+        for (int i = 0; tzs[i] != NULL; i++) {
+            GTimeZone *tz = tzs[i];
+
+            const char *tz_id = g_time_zone_get_identifier (tz);
+            const char *tz_name = gweather_location_get_timezone_name (location, tz_id);
+            g_test_message ("Location '%s': timezone (%s) = '%s'",
+                            gweather_location_get_name (location),
+                            tz_id,
+                            tz_name);
+
+            g_assert_nonnull (tz_name);
+        }
+
         /* Only countries should have multiple timezones associated */
         if ((tzs[0] == NULL && gweather_location_get_level (location) < GWEATHER_LOCATION_WEATHER_STATION) &&
             gweather_location_get_level (location) >= GWEATHER_LOCATION_COUNTRY) {
@@ -194,6 +207,41 @@ test_timezones (void)
     gweather_test_reset_world ();
 }
 
+static void
+test_utc_name (void)
+{
+    g_autoptr (GWeatherLocation) world = NULL;
+
+    world = gweather_location_get_world ();
+    g_assert_nonnull (world);
+
+    g_test_message ("Root location has no direct timezones");
+    GTimeZone *utc_tz = gweather_location_get_timezone (world);
+    g_assert_null (utc_tz);
+
+    g_test_message ("Root location has a default timezone name of UTC");
+    const char *utc_name = gweather_location_get_timezone_name (world, NULL);
+    g_assert_nonnull (utc_name);
+
+    GTimeZone **world_tzs = gweather_location_get_timezones (world);
+
+    for (int i = 0; world_tzs[i] != NULL; i++) {
+        GTimeZone *tz = world_tzs[i];
+        const char *tz_id = g_time_zone_get_identifier (tz);
+        const char *tz_name = gweather_location_get_timezone_name (world, tz_id);
+
+        g_test_message ("World: timezone (%s) = '%s'",
+                        tz_id,
+                        tz_name);
+    }
+
+    gweather_location_free_timezones (world, world_tzs);
+
+    g_clear_object (&world);
+
+    gweather_test_reset_world ();
+}
+
 int
 main (int argc,
       char *argv[])
@@ -208,6 +256,7 @@ main (int argc,
     g_test_add_func ("/weather/named-timezones", test_named_timezones);
     g_test_add_func ("/weather/named-timezones-deserialized", test_named_timezones_deserialized);
     g_test_add_func ("/weather/timezones", test_timezones);
+    g_test_add_func ("/weather/utc-name", test_utc_name);
 
     int res = g_test_run ();
 


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