From 6b919e5046fe307b6d93dbb868f21f4bb86d8941 Mon Sep 17 00:00:00 2001 From: Vratislav Podzimek Date: Mon, 13 Aug 2012 08:47:58 +0200 Subject: Add entries with completions to the comboboxes (DatetimeSpoke) Some regions have so many timezones (cities), that the combobox doesn't fit in the screen and is hard to search through. This patch modifies the city and region comboboxes to have text entry, that can be used to choose timezone. There are five ways of choosing timezone: 1) click on the map 2) popup comboboxes and choose region and city 3) type to the region and city comboboxes and choose from the completions 4) type a whole region or city name to the combobox and hit ENTER 5) type a whole region or city name to the combobox and click somewhere else or hit TAB --- pyanaconda/ui/gui/spokes/datetime_spoke.glade | 152 +++++++++++++------------- pyanaconda/ui/gui/spokes/datetime_spoke.py | 87 +++++++++++++-- 2 files changed, 155 insertions(+), 84 deletions(-) (limited to 'pyanaconda/ui') diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.glade b/pyanaconda/ui/gui/spokes/datetime_spoke.glade index d2b9825f3..393f88661 100644 --- a/pyanaconda/ui/gui/spokes/datetime_spoke.glade +++ b/pyanaconda/ui/gui/spokes/datetime_spoke.glade @@ -2,28 +2,36 @@ + + True + False + list-add-symbolic + + + True + False + system-run-symbolic + + + days + + + citiesSort + 0 + + cities citiesFilter - - True - False - system-run-symbolic - - - True - False - list-add-symbolic - filler False @@ -35,18 +43,9 @@ False vertical 6 - - - - - False - 6 - 6 - 6 - 2 - 2 - - + + + False False @@ -100,12 +99,19 @@ True False regions - - - - - 0 - + True + 0 + + + + True + GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK + 20 + regionCompletion + + + + @@ -135,12 +141,19 @@ True False citiesSort - - - - - 0 - + True + 0 + + + + True + GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK + 20 + cityCompletion + + + + @@ -182,7 +195,6 @@ True end start - False @@ -197,7 +209,6 @@ True True True - False configImage @@ -309,7 +320,6 @@ True True True - False upImage @@ -325,7 +335,6 @@ True True True - False downImage @@ -341,7 +350,6 @@ True True True - False upImage1 @@ -357,7 +365,6 @@ True True True - False upImage2 @@ -373,7 +380,6 @@ True True True - False downImage1 @@ -389,7 +395,6 @@ True True True - False downImage2 @@ -623,8 +628,37 @@ - - days + + True + False + go-down-symbolic + + + True + False + go-down-symbolic + + + True + False + go-down-symbolic + + + + + + + + + regions + 0 + + + + + + + False @@ -694,7 +728,6 @@ True True True - False addImage @@ -815,7 +848,6 @@ True True True - False True @@ -830,7 +862,6 @@ True True True - False True @@ -854,33 +885,6 @@ okButton - - True - False - go-down-symbolic - - - True - False - go-down-symbolic - - - True - False - go-down-symbolic - - - - - - - - - - - - - diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.py b/pyanaconda/ui/gui/spokes/datetime_spoke.py index b9b59bb86..5746ce75b 100644 --- a/pyanaconda/ui/gui/spokes/datetime_spoke.py +++ b/pyanaconda/ui/gui/spokes/datetime_spoke.py @@ -27,7 +27,7 @@ import logging log = logging.getLogger("anaconda") # pylint: disable-msg=E0611 -from gi.repository import AnacondaWidgets, GLib, Gtk +from gi.repository import AnacondaWidgets, GLib, Gtk, Gdk from pyanaconda.ui.gui import GUIObject from pyanaconda.ui.gui.spokes import NormalSpoke @@ -285,6 +285,7 @@ class DatetimeSpoke(NormalSpoke): "upImage", "upImage1", "upImage2", "downImage", "downImage1", "downImage2", "downImage3", "configImage", "citiesFilter", "daysFilter", "citiesSort", "regionsSort", + "cityCompletion", "regionCompletion", ] mainWidgetName = "datetimeWindow" @@ -328,6 +329,10 @@ class DatetimeSpoke(NormalSpoke): for city in self._regions_zones[region]: self.add_to_store(self._citiesStore, city) + # we need to know it the new value is the same as previous or not + self._old_region = None + self._old_city = None + self._regionCombo = self.builder.get_object("regionCombobox") self._cityCombo = self.builder.get_object("cityCombobox") self._monthCombo = self.builder.get_object("monthCombobox") @@ -428,8 +433,8 @@ class DatetimeSpoke(NormalSpoke): @property def mandatory(self): - return True - + return True + def refresh(self): #update the displayed time self._update_datetime_timer_id = GLib.timeout_add_seconds(1, @@ -663,6 +668,11 @@ class DatetimeSpoke(NormalSpoke): return model[itr][0] + 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) def on_up_hours_clicked(self, *args): self._stop_and_maybe_start_time_updating() @@ -729,27 +739,49 @@ class DatetimeSpoke(NormalSpoke): else: self._amPmLabel.set_text("AM") - def on_region_changed(self, *args): - self._citiesFilter.refilter() + def on_region_changed(self, combo, *args): + """ + @see: on_city_changed + + """ - # Attempt to set the city to the first one available in this newly - # selected region. region = self._get_active_region() - if not region: + if not region or region == self._old_region: + # region entry being edited or old_value chosen, no action needed + # @see: on_city_changed return + self._citiesFilter.refilter() + + # Set the city to the first one available in this newly selected region. zone = self._regions_zones[region] firstCity = sorted(list(zone))[0] self._set_combo_selection(self._cityCombo, firstCity) - self._cityCombo.emit("changed") + self._old_region = region + self._old_city = firstCity + + def on_city_changed(self, combo, *args): + """ + ComboBox emits ::changed signal not only when something is selected, but + also when its entry's text is changed. We need to distinguish between + those two cases ('London' typed in the entry => no action until ENTER is + hit etc.; 'London' chosen in the expanded combobox => update timezone + map and do all necessary actions). Fortunately when entry is being + edited, self._get_active_city returns None. + + """ - def on_city_changed(self, *args): timezone = None region = self._get_active_region() city = self._get_active_city() + if not region or not city or (region == self._old_region and + city == self._old_city): + # entry being edited or no change, no actions needed + return + if city and region: timezone = region + "/" + city @@ -765,6 +797,41 @@ class DatetimeSpoke(NormalSpoke): elif timezone and (self._tzmap.get_timezone() != timezone): self._tzmap.set_timezone(timezone) + # update "old" values + self._old_city = city + print "Storing %s" % city + + def on_entry_left(self, entry, *args): + # user clicked somewhere else or hit TAB => finished editing + entry.emit("activate") + + def on_city_region_key_released(self, entry, event, *args): + if event.type == Gdk.EventType.KEY_RELEASE and \ + event.keyval == Gdk.KEY_Escape: + # editing canceled + self._restore_old_city_region() + + def on_completion_match_selected(self, combo, model, itr): + item = None + if model and itr: + item = model[itr][0] + if item: + self._set_combo_selection(combo, item) + + def on_city_region_text_entry_activated(self, entry): + combo = entry.get_parent() + model = combo.get_model() + itr = model.get_iter_first() + entry_text = entry.get_text().lower() + + for row in model: + if entry_text == row[0].lower(): + self._set_combo_selection(combo, row[0]) + return + + # non-matching value entered, reset to old values + self._restore_old_city_region() + def on_month_changed(self, *args): self._stop_and_maybe_start_time_updating(interval=5) self._daysFilter.refilter() -- cgit