PATCH 1/3 fixes a potential issue that probably cannot be hit. PATCH 2/3 is needed for the PATCH 3/3 that changes the flow of the data when the timezone information is updated. Instead of selecting timezone on the map and relying on the signals it emits to update the other UI elements, it sets the timezone in the comboboxes and relies on their signals to propagate the change. The result is more robust because the indication on the map is more like an optional feature that may do internally anything with the data it gets and may even fail safely if we want to allow users set timezone that is not supported by the map (e.g. "Etc/UTC"). It also fixes bug #953311 that was caused by the map reporting America/SOMETHING (synonyms) for US/SOMETHING timezones selected.
Vratislav Podzimek (3): Sensitivity of the date&time settings doesn't depend on timezone Allow setting timezone on the map without signal Streamline DatetimeSpoke's timezone updating (#953311)
pyanaconda/ui/gui/spokes/datetime_spoke.py | 74 +++++++++++++++++------------- widgets/python/AnacondaWidgets.py | 7 +++ widgets/src/TimezoneMap.c | 19 +++++--- widgets/src/TimezoneMap.h | 5 +- 4 files changed, 64 insertions(+), 41 deletions(-)
It depends only on whether we can do changes to the system or not.
Signed-off-by: Vratislav Podzimek vpodzime@redhat.com --- pyanaconda/ui/gui/spokes/datetime_spoke.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.py b/pyanaconda/ui/gui/spokes/datetime_spoke.py index b760346..33dc4f4 100644 --- a/pyanaconda/ui/gui/spokes/datetime_spoke.py +++ b/pyanaconda/ui/gui/spokes/datetime_spoke.py @@ -376,9 +376,8 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): self._tzmap.set_timezone(DEFAULT_TZ) self.data.timezone.timezone = DEFAULT_TZ
- if self.data.timezone.timezone: - if not flags.can_touch_runtime_system("modify system time and date"): - self._set_date_time_setting_sensitive(False) + if not flags.can_touch_runtime_system("modify system time and date"): + self._set_date_time_setting_sensitive(False)
self._config_dialog = NTPconfigDialog(self.data) self._config_dialog.initialize()
This simplifies the code that now doesn't have to do any magic preventing infinite loops caused by signals and UI elements updating.
Signed-off-by: Vratislav Podzimek vpodzime@redhat.com --- widgets/python/AnacondaWidgets.py | 7 +++++++ widgets/src/TimezoneMap.c | 19 ++++++++++++------- widgets/src/TimezoneMap.h | 5 +++-- 3 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/widgets/python/AnacondaWidgets.py b/widgets/python/AnacondaWidgets.py index edb9f35..6e8570d 100644 --- a/widgets/python/AnacondaWidgets.py +++ b/widgets/python/AnacondaWidgets.py @@ -75,3 +75,10 @@ class DiskOverview(Anaconda.DiskOverview):
DiskOverview = override(DiskOverview) __all__.append('DiskOverview') + +class TimezoneMap(Anaconda.TimezoneMap): + def set_timezone(self, timezone, no_signal=False): + Anaconda.TimezoneMap.set_timezone(self, timezone, no_signal) + +TimezoneMap = override(TimezoneMap) +__all__.append('TimezoneMap') diff --git a/widgets/src/TimezoneMap.c b/widgets/src/TimezoneMap.c index a494e70..a939c3c 100644 --- a/widgets/src/TimezoneMap.c +++ b/widgets/src/TimezoneMap.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Red Hat, Inc +/* Copyright (C) 2012-2013 Red Hat, Inc * * Heavily based on the code from gnome-control-center, Copyright (C) 2010 Intel, Inc. * Written by Thomas Wood thomas.wood@intel.com @@ -437,7 +437,8 @@ sort_locations (TzLocation *a, static void set_location (AnacondaTimezoneMap *map, TzLocation *location, - gboolean no_city) { + gboolean no_city, + gboolean no_signal) { AnacondaTimezoneMapPrivate *priv = map->priv; TzInfo *info;
@@ -448,11 +449,13 @@ set_location (AnacondaTimezoneMap *map,
if (no_city) { priv->location = NULL; - g_signal_emit (map, signals[TIMEZONE_CHANGED], 0, ""); + if (!no_signal) + g_signal_emit (map, signals[TIMEZONE_CHANGED], 0, ""); } else { priv->location = location; - g_signal_emit (map, signals[TIMEZONE_CHANGED], 0, priv->location->zone); + if (!no_signal) + g_signal_emit (map, signals[TIMEZONE_CHANGED], 0, priv->location->zone); }
tz_info_free (info); @@ -520,7 +523,7 @@ button_press_event (GtkWidget *widget, distances = g_list_sort (distances, (GCompareFunc) sort_locations);
- set_location (ANACONDA_TIMEZONE_MAP (widget), (TzLocation*) distances->data, FALSE); + set_location (ANACONDA_TIMEZONE_MAP (widget), (TzLocation*) distances->data, FALSE, FALSE);
g_list_free (distances);
@@ -565,6 +568,7 @@ anaconda_timezone_map_init (AnacondaTimezoneMap *self) { * anaconda_timezone_map_set_timezone: * @map: an #AnacondaTimezoneMap * @timezone: timezone name + * @no_signal: whether the timezone-changed signal should be emitted or not * * Modifies the map to show @timezone as selected. Also modifies the internal * data of the @map. @@ -573,7 +577,8 @@ anaconda_timezone_map_init (AnacondaTimezoneMap *self) { */ gboolean anaconda_timezone_map_set_timezone (AnacondaTimezoneMap *map, - const gchar *timezone) { + const gchar *timezone, + gboolean no_signal) { GPtrArray *locations; guint i; char *real_tz; @@ -596,7 +601,7 @@ anaconda_timezone_map_set_timezone (AnacondaTimezoneMap *map, TzLocation *loc = locations->pdata[i];
if (!g_strcmp0 (loc->zone, real_tz ? real_tz : timezone)) { - set_location (map, loc, no_city); + set_location (map, loc, no_city, no_signal); ret = TRUE; break; } diff --git a/widgets/src/TimezoneMap.h b/widgets/src/TimezoneMap.h index 0018266..3a857bd 100644 --- a/widgets/src/TimezoneMap.h +++ b/widgets/src/TimezoneMap.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Red Hat, Inc + * Copyright (C) 2012-2013 Red Hat, Inc * * Heavily based on the gnome-control-center code, * Copyright (c) 2010 Intel, Inc @@ -74,7 +74,8 @@ GType anaconda_timezone_map_get_type (void) G_GNUC_CONST; GtkWidget *anaconda_timezone_map_new (void);
gboolean anaconda_timezone_map_set_timezone (AnacondaTimezoneMap *map, - const gchar *timezone); + const gchar *timezone, + gboolean no_signal);
gchar *anaconda_timezone_map_get_timezone (AnacondaTimezoneMap *map);
Without this patch the final word about the selected timezone was on the TimezoneMap which brought bugs and complicated things because the map doesn't store the timezone it was asked to select and when queried, it returns the value it calculates from the currently selected timezone. Thus when selecting e.g. US/Central, the map selected it correctly (visually), but when queried with get_timezone afterwards it returned America/Chicago.
All in all we shouldn't rely on the map having the best data when it does some transformations on its own and does not necessary support all timezones we want to set (now or in the future).
Signed-off-by: Vratislav Podzimek vpodzime@redhat.com --- pyanaconda/ui/gui/spokes/datetime_spoke.py | 69 +++++++++++++++++------------- 1 file changed, 40 insertions(+), 29 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.py b/pyanaconda/ui/gui/spokes/datetime_spoke.py index 33dc4f4..ad1ae64 100644 --- a/pyanaconda/ui/gui/spokes/datetime_spoke.py +++ b/pyanaconda/ui/gui/spokes/datetime_spoke.py @@ -1,6 +1,6 @@ # Datetime configuration spoke class # -# Copyright (C) 2012 Red Hat, Inc. +# Copyright (C) 2012-2013 Red Hat, Inc. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of @@ -369,11 +369,11 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
self._update_datetime_timer_id = None if timezone.is_valid_timezone(self.data.timezone.timezone): - self._tzmap.set_timezone(self.data.timezone.timezone) + self._set_timezone(self.data.timezone.timezone) elif not flags.flags.automatedInstall: log.warning("%s is not a valid timezone, falling back to default "\ "(%s)" % (self.data.timezone.timezone, DEFAULT_TZ)) - self._tzmap.set_timezone(DEFAULT_TZ) + self._set_timezone(DEFAULT_TZ) self.data.timezone.timezone = DEFAULT_TZ
if not flags.can_touch_runtime_system("modify system time and date"): @@ -436,7 +436,7 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): self._start_updating_timer_id = None
if timezone.is_valid_timezone(self.data.timezone.timezone): - self._tzmap.set_timezone(self.data.timezone.timezone) + self._set_timezone(self.data.timezone.timezone)
self._update_datetime()
@@ -454,6 +454,28 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
self._ntpSwitch.set_active(ntp_working)
+ def _set_timezone(self, timezone): + """ + Sets timezone to the city/region comboboxes and the timezone map. + + :param timezone: timezone to set + :type timezone: str + :return: if successfully set or not + :rtype: bool + + """ + + parts = timezone.split("/", 1) + if len(parts) != 2: + # invalid timezone cannot be set + return False + + region, city = parts + self._set_combo_selection(self._regionCombo, region) + self._set_combo_selection(self._cityCombo, city) + + return True + @gtk_action_nowait def add_to_store(self, store, item): store.append([item]) @@ -666,8 +688,7 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): def _restore_old_city_region(self): """Restore stored "old" (or last valid) values."""
- self._set_combo_selection(self._regionCombo, self._old_region) - self._set_combo_selection(self._cityCombo, self._old_city) + self._set_timezone(self._old_region + "/" + self._old_city)
def on_up_hours_clicked(self, *args): self._stop_and_maybe_start_time_updating() @@ -741,6 +762,7 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): """
region = self._get_active_region() + if not region or region == self._old_region: # region entry being edited or old_value chosen, no action needed # @see: on_city_changed @@ -779,18 +801,17 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
if city and region: timezone = region + "/" + city + else: + # both city and region are needed to form a valid timezone + return
- if timezone is not None and region == "Etc": + if region == "Etc": # Etc timezones cannot be displayed on the map, so let's set the map # to "" which sets it to "Europe/London" (UTC) without a city pin - self._tzmap.set_timezone("") - - # Change to Etc/XXXXX emits timezone-changed with "" as timezone, - # so let's help it a bit. - self._tzmap.emit("timezone-changed", timezone) - - elif timezone and (self._tzmap.get_timezone() != timezone): - self._tzmap.set_timezone(timezone) + self._tzmap.set_timezone("", no_signal=True) + else: + # we don't want the timezone-changed signal to be emitted + self._tzmap.set_timezone(timezone, no_signal=True)
# update "old" values self._old_city = city @@ -838,20 +859,10 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke): self._daysFilter.refilter()
def on_timezone_changed(self, tz_map, timezone): - fields = timezone.split("/", 1) - if len(fields) == 1: - # timezone may be "" - return - - region, city = fields - if region != "Etc": - # If region is "Etc", TimezoneMap returns "" from get_timezone - # and changing comboboxes here would create an endless loop. - self._set_combo_selection(self._regionCombo, region) - self._set_combo_selection(self._cityCombo, city) - - os.environ["TZ"] = timezone - self._update_datetime() + if self._set_timezone(timezone): + # timezone successfully set + os.environ["TZ"] = timezone + self._update_datetime()
def on_timeformat_changed(self, button24h, *args): hours = int(self._hoursLabel.get_text())
pyanaconda/ui/gui/spokes/datetime_spoke.py | 74 +++++++++++++++++------------- widgets/python/AnacondaWidgets.py | 7 +++ widgets/src/TimezoneMap.c | 19 +++++--- widgets/src/TimezoneMap.h | 5 +- 4 files changed, 64 insertions(+), 41 deletions(-)
These look fine.
- Chris
anaconda-patches@lists.fedorahosted.org