[PATCH 2/2] Make the date format locale-dependent in our GUI (#1044233)

Vratislav Podzimek vpodzime at redhat.com
Tue Oct 7 16:32:37 UTC 2014


The y/m/d order varies among locales and so do the delimiters between the date
fields.

Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 pyanaconda/ui/gui/spokes/datetime_spoke.glade | 159 ++++++++++----------------
 pyanaconda/ui/gui/spokes/datetime_spoke.py    | 102 +++++++++++------
 2 files changed, 129 insertions(+), 132 deletions(-)

diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.glade b/pyanaconda/ui/gui/spokes/datetime_spoke.glade
index 5a390ae..a9d8933 100644
--- a/pyanaconda/ui/gui/spokes/datetime_spoke.glade
+++ b/pyanaconda/ui/gui/spokes/datetime_spoke.glade
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.18.1 -->
+<!-- Generated with glade 3.18.3 -->
 <interface>
   <requires lib="gtk+" version="3.2"/>
   <requires lib="AnacondaWidgets" version="1.0"/>
@@ -33,8 +33,10 @@
   </object>
   <object class="GtkListStore" id="days">
     <columns>
-      <!-- column-name number -->
+      <!-- column-name idx -->
       <column type="guint"/>
+      <!-- column-name day -->
+      <column type="gchararray"/>
     </columns>
   </object>
   <object class="GtkTreeModelFilter" id="daysFilter">
@@ -57,6 +59,8 @@
   </object>
   <object class="GtkListStore" id="months">
     <columns>
+      <!-- column-name idx -->
+      <column type="guint"/>
       <!-- column-name name -->
       <column type="gchararray"/>
     </columns>
@@ -95,6 +99,46 @@
         <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
         <property name="spacing">6</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="cancelButton">
+                <property name="label" translatable="yes" context="GUI|Date and Time|NTP">_Cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="okButton">
+                <property name="label" translatable="yes" context="GUI|Date and Time|NTP">_OK</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
         <child>
           <object class="GtkLabel" id="configHeadingLabel">
             <property name="visible">True</property>
@@ -221,46 +265,6 @@
             <property name="position">2</property>
           </packing>
         </child>
-        <child internal-child="action_area">
-          <object class="GtkButtonBox" id="dialog-action_area1">
-            <property name="can_focus">False</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="cancelButton">
-                <property name="label" translatable="yes" context="GUI|Date and Time|NTP">_Cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_underline">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="okButton">
-                <property name="label" translatable="yes" context="GUI|Date and Time|NTP">_OK</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_underline">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="pack_type">end</property>
-            <property name="position">4</property>
-          </packing>
-        </child>
       </object>
     </child>
     <action-widgets>
@@ -288,12 +292,6 @@
     <property name="can_focus">False</property>
     <property name="icon_name">go-up-symbolic</property>
   </object>
-  <object class="GtkListStore" id="years">
-    <columns>
-      <!-- column-name number -->
-      <column type="guint"/>
-    </columns>
-  </object>
   <object class="AnacondaSpokeWindow" id="datetimeWindow">
     <property name="can_focus">False</property>
     <property name="window_name" translatable="yes">DATE &amp; TIME</property>
@@ -818,66 +816,19 @@
                                 <property name="yscale">0.20000000298023224</property>
                                 <property name="right_padding">24</property>
                                 <child>
-                                  <object class="GtkBox" id="box5">
+                                  <object class="GtkBox" id="dateBox">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
                                     <property name="halign">end</property>
+                                    <property name="spacing">3</property>
                                     <child>
-                                      <object class="GtkComboBox" id="monthCombobox">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">False</property>
-                                        <property name="model">months</property>
-                                        <signal name="changed" handler="on_month_changed" swapped="no"/>
-                                        <child>
-                                          <object class="GtkCellRendererText" id="monthsComboRenderer"/>
-                                          <attributes>
-                                            <attribute name="text">0</attribute>
-                                          </attributes>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">True</property>
-                                        <property name="position">0</property>
-                                      </packing>
+                                      <placeholder/>
                                     </child>
                                     <child>
-                                      <object class="GtkComboBox" id="dayCombobox">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">False</property>
-                                        <property name="model">daysFilter</property>
-                                        <signal name="changed" handler="on_day_changed" swapped="no"/>
-                                        <child>
-                                          <object class="GtkCellRendererText" id="daysComboRenderer"/>
-                                          <attributes>
-                                            <attribute name="text">0</attribute>
-                                          </attributes>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">True</property>
-                                        <property name="position">1</property>
-                                      </packing>
+                                      <placeholder/>
                                     </child>
                                     <child>
-                                      <object class="GtkComboBox" id="yearCombobox">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">False</property>
-                                        <property name="model">years</property>
-                                        <signal name="changed" handler="on_year_changed" swapped="no"/>
-                                        <child>
-                                          <object class="GtkCellRendererText" id="yearsComboRenderer"/>
-                                          <attributes>
-                                            <attribute name="text">0</attribute>
-                                          </attributes>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">True</property>
-                                        <property name="position">2</property>
-                                      </packing>
+                                      <placeholder/>
                                     </child>
                                   </object>
                                 </child>
@@ -929,4 +880,12 @@
       </object>
     </child>
   </object>
+  <object class="GtkListStore" id="years">
+    <columns>
+      <!-- column-name idx -->
+      <column type="guint"/>
+      <!-- column-name year -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
 </interface>
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.py b/pyanaconda/ui/gui/spokes/datetime_spoke.py
index 69000f8..6abc43b 100644
--- a/pyanaconda/ui/gui/spokes/datetime_spoke.py
+++ b/pyanaconda/ui/gui/spokes/datetime_spoke.py
@@ -22,7 +22,7 @@
 import logging
 log = logging.getLogger("anaconda")
 
-from gi.repository import GLib, Gdk, TimezoneMap
+from gi.repository import GLib, Gdk, Gtk, TimezoneMap
 
 from pyanaconda.ui.communication import hubQ
 from pyanaconda.ui.common import FirstbootSpokeMixIn
@@ -35,7 +35,7 @@ from pyanaconda.ui.helpers import InputCheck
 
 from pyanaconda.i18n import _, CN_
 from pyanaconda.timezone import NTP_SERVICE, get_all_regions_and_timezones, is_valid_timezone
-from pyanaconda.localization import get_xlated_timezone
+from pyanaconda.localization import get_xlated_timezone, resolve_date_format
 from pyanaconda import iutil
 from pyanaconda import isys
 from pyanaconda import network
@@ -113,6 +113,27 @@ def _compare_cities(city_xlated1, city_xlated2):
         # compare prefixes
         return locale_mod.strcoll(prefix1, prefix2)
 
+def _new_date_field_box(store):
+    """
+    Creates new date field box (a combobox and a label in a horizontal box) for
+    a given store.
+
+    """
+
+    box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
+    suffix_label = Gtk.Label()
+    renderer = Gtk.CellRendererText()
+    combo = Gtk.ComboBox(model=store)
+    combo.pack_start(renderer, False)
+
+    # idx is column 0, string we want to show is 1
+    combo.add_attribute(renderer, "text", 1)
+
+    box.pack_start(combo, False, False, 0)
+    box.pack_start(suffix_label, False, False, 0)
+
+    return (box, combo, suffix_label)
+
 class NTPconfigDialog(GUIObject, GUIDialogInputCheckHandler):
     builderObjects = ["ntpConfigDialog", "addImage", "serversStore"]
     mainWidgetName = "ntpConfigDialog"
@@ -392,6 +413,7 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
         self._regionsStore = self.builder.get_object("regions")
         self._citiesStore = self.builder.get_object("cities")
         self._tzmap = self.builder.get_object("tzmap")
+        self._dateBox = self.builder.get_object("dateBox")
 
         # we need to know it the new value is the same as previous or not
         self._old_region = None
@@ -399,9 +421,6 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
 
         self._regionCombo = self.builder.get_object("regionCombobox")
         self._cityCombo = self.builder.get_object("cityCombobox")
-        self._monthCombo = self.builder.get_object("monthCombobox")
-        self._dayCombo = self.builder.get_object("dayCombobox")
-        self._yearCombo = self.builder.get_object("yearCombobox")
 
         self._daysFilter = self.builder.get_object("daysFilter")
         self._daysFilter.set_visible_func(self.existing_date, None)
@@ -416,11 +435,31 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
         self._amPmLabel = self.builder.get_object("amPmLabel")
         self._radioButton24h = self.builder.get_object("timeFormatRB")
 
+        # create widgets for displaying/configuring date
+        day_box, self._dayCombo, day_label = _new_date_field_box(self._daysFilter)
+        month_box, self._monthCombo, month_label = _new_date_field_box(self._monthsStore)
+        year_box, self._yearCombo, year_label = _new_date_field_box(self._yearsStore)
+
+        # get the right order for date widgets and respective formats and put
+        # widgets in place
+        widgets, formats = resolve_date_format(year_box, month_box, day_box)
+        for widget in widgets:
+            self._dateBox.pack_start(widget, False, False, 0)
+
+        self._day_format, suffix = formats[widgets.index(day_box)]
+        day_label.set_text(suffix)
+        self._month_format, suffix = formats[widgets.index(month_box)]
+        month_label.set_text(suffix)
+        self._year_format, suffix = formats[widgets.index(year_box)]
+        year_label.set_text(suffix)
+
         self._ntpSwitch = self.builder.get_object("networkTimeSwitch")
 
         self._regions_zones = get_all_regions_and_timezones()
 
+        self._days_nums = dict()
         self._months_nums = dict()
+        self._years_nums = dict()
 
         # Set the initial sensitivity of the AM/PM toggle based on the time-type selected
         self._radioButton24h.emit("toggled")
@@ -435,18 +474,18 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
                                      target=self._initialize))
 
     def _initialize(self):
-        for day in xrange(1, 32):
-            self.add_to_store(self._daysStore, day)
+        # a bit hacky way, but should return the translated strings
+        for i in range(1, 32):
+            day = datetime.date(2000, 1, i).strftime(self._day_format)
+            self.add_to_store_idx(self._daysStore, i, day)
 
-        for i in xrange(1, 13):
-            #a bit hacky way, but should return the translated string
-            #TODO: how to handle language change? Clear and populate again?
-            month = datetime.date(2000, i, 1).strftime('%B')
-            self.add_to_store(self._monthsStore, month)
-            self._months_nums[month] = i
+        for i in range(1, 13):
+            month = datetime.date(2000, i, 1).strftime(self._month_format)
+            self.add_to_store_idx(self._monthsStore, i, month)
 
-        for year in xrange(1990, 2051):
-            self.add_to_store(self._yearsStore, year)
+        for i in range(1990, 2051):
+            year = datetime.date(i, 1, 1).strftime(self._year_format)
+            self.add_to_store_idx(self._yearsStore, i, year)
 
         cities = set()
         xlated_regions = ((region, get_xlated_timezone(region))
@@ -590,10 +629,14 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
     def add_to_store(self, store, item):
         store.append([item])
 
-    def existing_date(self, model, itr, user_data=None):
-        if not itr:
+    @gtk_action_nowait
+    def add_to_store_idx(self, store, idx, item):
+        store.append([idx, item])
+
+    def existing_date(self, days_model, days_iter, user_data=None):
+        if not days_iter:
             return False
-        day = model[itr][0]
+        day = days_model[days_iter][0]
 
         #days 1-28 are in every month every year
         if day < 29:
@@ -603,16 +646,15 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
         months_iter = self._monthCombo.get_active_iter()
         if not months_iter:
             return True
-        month = months_model[months_iter][0]
 
         years_model = self._yearCombo.get_model()
         years_iter = self._yearCombo.get_active_iter()
         if not years_iter:
             return True
-        year = years_model[years_iter][0]
 
         try:
-            datetime.date(year, self._months_nums[month], day)
+            datetime.date(years_model[years_iter][0],
+                          months_model[months_iter][0], day)
             return True
         except ValueError:
             return False
@@ -682,8 +724,7 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
         self._minutesLabel.set_text("%0.2d" % now.minute)
 
         self._set_combo_selection(self._dayCombo, now.day)
-        self._set_combo_selection(self._monthCombo,
-                            datetime.date(2000, now.month, 1).strftime('%B'))
+        self._set_combo_selection(self._monthCombo, now.month)
         self._set_combo_selection(self._yearCombo, now.year)
 
         #GLib's timer is driven by the return value of the function.
@@ -701,15 +742,13 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
         if not flags.can_touch_runtime_system("save system time"):
             return False
 
-        month = self._get_combo_selection(self._monthCombo)
+        month, month_str = self._get_combo_selection(self._monthCombo)
         if not month:
             return False
-        month = self._months_nums[month]
 
-        year_str = self._get_combo_selection(self._yearCombo)
-        if not year_str:
+        year, year_str = self._get_combo_selection(self._yearCombo)
+        if not year:
             return False
-        year = int(year_str)
 
         hours = int(self._hoursLabel.get_text())
         if not self._radioButton24h.get_active():
@@ -717,10 +756,9 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
 
         minutes = int(self._minutesLabel.get_text())
 
-        day = self._get_combo_selection(self._dayCombo)
+        day, day_str = self._get_combo_selection(self._dayCombo)
         #day may be None if there is no such in the selected year and month
         if day:
-            day = int(day)
             isys.set_system_date_time(year, month, day, hours, minutes)
 
         #start the timer only when the spoke is shown
@@ -789,9 +827,9 @@ class DatetimeSpoke(FirstbootSpokeMixIn, NormalSpoke):
         model = combo.get_model()
         itr = combo.get_active_iter()
         if not itr or not model:
-            return None
+            return None, None
 
-        return model[itr][0]
+        return model[itr][0], model[itr][1]
 
     def _restore_old_city_region(self):
         """Restore stored "old" (or last valid) values."""
-- 
1.9.3



More information about the anaconda-patches mailing list