From 4c87463e3b663b413c3be899bb15891aa7f0ee43 Mon Sep 17 00:00:00 2001 From: David Shea Date: Tue, 28 Jun 2016 13:49:14 -0400 Subject: [PATCH 18/24] Improve the location selected when setting the timezone by name. When setting the timezone from a name (e.g., Australia/Brisbane), try to find the city that matches the timezone name. That way, in our example, the pin will appear on Brisbane and not just some random city in eastern Australia. In addition, when cc_timezone_map_set_timezone is called for an unknown timezone, set the offset highlight based on glib's view of timezones (since this may be a low-population timezone without city data) and unset the location. --- src/cc-timezone-map.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/src/cc-timezone-map.c b/src/cc-timezone-map.c index 11b14ea..5e4c210 100644 --- a/src/cc-timezone-map.c +++ b/src/cc-timezone-map.c @@ -28,6 +28,7 @@ #include #include "tz.h" #include +#include G_DEFINE_TYPE (CcTimezoneMap, cc_timezone_map, GTK_TYPE_WIDGET) @@ -817,10 +818,42 @@ cc_timezone_map_set_timezone (CcTimezoneMap *map, const gchar *timezone) { GPtrArray *locations; + GList *zone_locations = NULL; + GList *location_node = NULL; guint i; - char *real_tz; + const char *real_tz; + const char *tz_city_start; + char *tz_city; + char *tmp; + gboolean found_location = FALSE; real_tz = g_hash_table_lookup (map->priv->alias_db, timezone); + if (!real_tz) + real_tz = timezone; + + tz_city_start = strrchr (timezone, '/'); + if (tz_city_start) + { + /* Move to the first character after the / */ + tz_city_start++; + } + else + { + tz_city_start = real_tz; + } + + tz_city = g_strdup(tz_city_start); + + /* Replace the underscores with spaces */ + tmp = tz_city; + while (*tmp != '\0') + { + if (*tmp == '_') + { + *tmp = ' '; + } + tmp++; + } locations = tz_get_locations (map->priv->tzdb); @@ -828,12 +861,76 @@ cc_timezone_map_set_timezone (CcTimezoneMap *map, { CcTimezoneLocation *loc = locations->pdata[i]; - if (!g_strcmp0 (cc_timezone_location_get_zone(loc), real_tz ? real_tz : timezone)) + if (!g_strcmp0 (cc_timezone_location_get_zone (loc), real_tz)) { - set_location (map, loc); + zone_locations = g_list_prepend (zone_locations, loc); + } + } + + /* No location found. Use GLib to set the highlight. g_time_zone_new always + * returns a GTimeZone, so invalid zones will just be offset 0. + */ + if (zone_locations == NULL) + { + CcTimezoneLocation *test_location = cc_timezone_location_new (); + gdouble offset; + + cc_timezone_location_set_zone (test_location, real_tz); + offset = get_location_offset (test_location); + g_object_unref (test_location); + + set_location (map, NULL); + cc_timezone_map_set_selected_offset (map, offset); + + return; + } + + /* Look for a location with a name that either starts or ends with the name + * of the zone + */ + location_node = zone_locations; + while (location_node != NULL) + { + const gchar *name = cc_timezone_location_get_en_name (location_node->data); + if (!strncmp (name, tz_city, strlen (tz_city)) || + ((strlen(name) > strlen(tz_city)) && + !strncmp (name + (strlen(name) - strlen(tz_city)), tz_city, strlen (tz_city)))) + { + set_location (map, location_node->data); + found_location = TRUE; break; } + + location_node = location_node->next; } + + /* If that didn't work, try by state */ + if (!found_location) + { + location_node = zone_locations; + while (location_node != NULL) + { + const gchar *state = cc_timezone_location_get_state (location_node->data); + + if ((state != NULL) && + !strncmp (state, tz_city, strlen (tz_city))) + { + set_location (map, location_node->data); + found_location = TRUE; + break; + } + + location_node = location_node->next; + } + } + + /* If nothing matched, just use the first location */ + if (!found_location) + { + set_location (map, zone_locations->data); + } + + g_list_free (zone_locations); } void -- 2.5.5