--- pyanaconda/ui/gui/spokes/langsupport.glade | 201 +++++++++++++++++++++++++++++ pyanaconda/ui/gui/spokes/langsupport.py | 195 ++++++++++++++++++++++++++++ 2 files changed, 396 insertions(+) create mode 100644 pyanaconda/ui/gui/spokes/langsupport.glade create mode 100644 pyanaconda/ui/gui/spokes/langsupport.py
diff --git a/pyanaconda/ui/gui/spokes/langsupport.glade b/pyanaconda/ui/gui/spokes/langsupport.glade new file mode 100644 index 0000000..b7ef1ce --- /dev/null +++ b/pyanaconda/ui/gui/spokes/langsupport.glade @@ -0,0 +1,201 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 3.0 --> + <!-- interface-requires AnacondaWidgets 1.0 --> + <object class="GtkListStore" id="langsupportStore"> + <columns> + <!-- column-name nativeName --> + <column type="gchararray"/> + <!-- column-name englishName --> + <column type="gchararray"/> + <!-- column-name langSetting --> + <column type="gchararray"/> + <!-- column-name langSupportSelected --> + <column type="gboolean"/> + <!-- column-name isAdditional --> + <column type="gboolean"/> + </columns> + </object> + <object class="GtkTreeModelFilter" id="langsupportStoreFilter"> + <property name="child_model">langsupportStore</property> + </object> + <object class="AnacondaSpokeWindow" id="langsupportWindow"> + <property name="startup_id">filler</property> + <property name="can_focus">False</property> + <property name="startup_id">filler</property> + <property name="window_name" translatable="yes">LANGUAGE SUPPORT</property> + <signal name="button-clicked" handler="on_back_clicked" swapped="no"/> + <child internal-child="main_box"> + <object class="GtkBox" id="AnacondaSpokeWindow-main_box1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child internal-child="nav_box"> + <object class="GtkEventBox" id="AnacondaSpokeWindow-nav_box1"> + <property name="app_paintable">True</property> + <property name="can_focus">False</property> + <child internal-child="nav_area"> + <object class="GtkGrid" id="AnacondaSpokeWindow-nav_area1"> + <property name="can_focus">False</property> + <property name="margin_left">6</property> + <property name="margin_right">6</property> + <property name="margin_top">6</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child internal-child="alignment"> + <object class="GtkAlignment" id="AnacondaSpokeWindow-alignment1"> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="top_padding">12</property> + <property name="bottom_padding">48</property> + <property name="left_padding">24</property> + <property name="right_padding">24</property> + <child internal-child="action_area"> + <object class="GtkBox" id="AnacondaSpokeWindow-action_area1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="selectLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Select additional language support to be installed</property> + <attributes> + <attribute name="font-desc" value="Cantarell 12"/> + <attribute name="weight" value="normal"/> + <attribute name="scale" value="1"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkScrolledWindow" id="langsupportScrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="langsupportView"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">langsupportStoreFilter</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + <property name="search_column">0</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="langsupportViewSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="langsupportSelectedCol"> + <property name="title" translatable="yes">column</property> + <signal name="clicked" handler="on_langsupport_toggled" swapped="no"/> + <child> + <object class="GtkCellRendererToggle" id="langsupportSelectedRenderer"> + <signal name="toggled" handler="on_langsupport_toggled" swapped="no"/> + </object> + <attributes> + <attribute name="sensitive">4</attribute> + <attribute name="activatable">4</attribute> + <attribute name="active">3</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="nativeNameCol"> + <property name="title" translatable="yes">column</property> + <property name="expand">True</property> + <child> + <object class="GtkCellRendererText" id="nativeNameRenderer"/> + <attributes> + <attribute name="markup">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="englishNameCol"> + <property name="title" translatable="yes">column</property> + <property name="expand">True</property> + <child> + <object class="GtkCellRendererText" id="englishNameRenderer"/> + <attributes> + <attribute name="markup">1</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="langsupportEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="valign">start</property> + <property name="margin_top">6</property> + <property name="hexpand">True</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + <property name="secondary_icon_name">edit-clear-symbolic</property> + <signal name="changed" handler="on_entry_changed" swapped="no"/> + <signal name="icon-release" handler="on_clear_icon_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + </child> + </object> +</interface> diff --git a/pyanaconda/ui/gui/spokes/langsupport.py b/pyanaconda/ui/gui/spokes/langsupport.py new file mode 100644 index 0000000..c586346 --- /dev/null +++ b/pyanaconda/ui/gui/spokes/langsupport.py @@ -0,0 +1,195 @@ +# Language support selection spoke classes +# +# Copyright (C) 2011-2012 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 +# the GNU General Public License v.2, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY expressed or implied, including the implied warranties of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the +# GNU General Public License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the +# source code or documentation are not subject to the GNU General Public +# License and may only be used or replicated with the express permission of +# Red Hat, Inc. +# +# Red Hat Author(s): Radek Vykydal rvykydal@redhat.com +# + +import gettext +_ = lambda x: gettext.ldgettext("anaconda", x) +N_ = lambda x: x + +from gi.repository import Gtk, Pango +from pyanaconda.flags import flags +from pyanaconda.ui.gui.spokes import NormalSpoke +from pyanaconda.ui.gui.categories.localization import LocalizationCategory +from pyanaconda.localization import Language, LOCALE_PREFERENCES, expand_langs + +import re + +import logging +log = logging.getLogger("anaconda") + +__all__ = ["LangsupportSpoke"] + +COL_NATIVE_NAME = 0 +COL_ENGLISH_NAME = 1 +COL_LANG_SETTING = 2 +COL_SELECTED = 3 +COL_IS_ADDITIONAL = 4 + +class LangsupportSpoke(NormalSpoke): + builderObjects = ["langsupportStore", "langsupportStoreFilter", "langsupportWindow"] + mainWidgetName = "langsupportWindow" + uiFile = "spokes/langsupport.glade" + + category = LocalizationCategory + + icon = "accessories-character-map-symbolic" + title = N_("_LANGUAGE SUPPORT") + + def __init__(self, *args, **kwargs): + NormalSpoke.__init__(self, *args, **kwargs) + + def initialize(self): + self._langsupportStore = self.builder.get_object("langsupportStore") + self._langsupportEntry = self.builder.get_object("langsupportEntry") + self._langsupportStoreFilter = self.builder.get_object("langsupportStoreFilter") + self._langsupportStoreFilter.set_visible_func(self._matches_entry, None) + + # mark selected items in language list bold + for col, rend, idx in (("englishNameCol", "englishNameRenderer", COL_ENGLISH_NAME), + ("nativeNameCol", "nativeNameRenderer", COL_NATIVE_NAME)): + column = self.builder.get_object(col) + renderer = self.builder.get_object(rend) + column.set_cell_data_func(renderer, self._mark_selected_bold, idx) + + language = Language(LOCALE_PREFERENCES, territory=None) + # source of lang code <-> UI name mapping + self.locale_infos_for_data = language.translations + self.locale_infos_for_ui = language.translations + + for code, info in sorted(self.locale_infos_for_ui.items()): + self._add_language(self._langsupportStore, info.display_name, + info.english_name, info.short_name, + False, True) + + self._select_language(self._langsupportStore, self.data.lang.lang) + + def apply(self): + self.data.lang.addsupport = [row[COL_LANG_SETTING] + for row in self._langsupportStore + if row[COL_SELECTED] and row[COL_IS_ADDITIONAL]] + + def refresh(self): + lang_infos = self._find_localeinfos_for_code(self.data.lang.lang, self.locale_infos_for_ui) + lang_short_names = [info.short_name for info in lang_infos] + if len(lang_short_names) > 1: + log.warning("Found multiple locales for lang %s: %s, picking first" % + (self.data.lang.lang, lang_short_names)) + # Just take the first found + # TODO - for corner cases choose the one that is common prefix + lang_short_names = lang_short_names[:1] + + addsupp_short_names = [] + for code in self.data.lang.addsupport: + code_infos = self._find_localeinfos_for_code(code, self.locale_infos_for_ui) + addsupp_short_names.extend(info.short_name for info in code_infos) + + for row in self._langsupportStore: + if row[COL_LANG_SETTING] in addsupp_short_names: + row[COL_SELECTED] = True + if row[COL_LANG_SETTING] in lang_short_names: + row[COL_SELECTED] = True + row[COL_IS_ADDITIONAL] = False + + @property + def showable(self): + return not flags.livecdInstall + + @property + def status(self): + # TODO: translate + infos = set(self._find_localeinfos_for_code(self.data.lang.lang, self.locale_infos_for_data)[:1]) + for code in self.data.lang.addsupport: + infos.update(self._find_localeinfos_for_code(code, self.locale_infos_for_data)) + return ", ".join(info.english_name for info in infos) + + @property + def mandatory(self): + return False + + @property + def completed(self): + return True + + def _find_localeinfos_for_code(self, code, infos): + try: + retval = [infos[code]] + except KeyError: + retval = [info for _code, info in infos.items() + if code in expand_langs(_code)] + log.debug("locale info found for %s: %s" % (code, retval)) + return retval + + def _add_language(self, store, native, english, setting, selected, additional): + store.append(['<span lang="%s">%s</span>' % (re.sub('..*', '', setting), native), + english, setting, selected, additional]) + + def _select_language(self, store, language): + itr = store.get_iter_first() + while itr and language not in expand_langs(store[itr][COL_LANG_SETTING]): + itr = store.iter_next(itr) + + # If we were provided with an unsupported language, just use the default. + if not itr: + return + + treeview = self.builder.get_object("langsupportView") + selection = treeview.get_selection() + selection.select_iter(itr) + path = store.get_path(itr) + treeview.scroll_to_cell(path) + + def _matches_entry(self, model, itr, *args): + # Need to strip out the pango markup before attempting to match. + # Otherwise, starting to type "span" for "spanish" will match everything + # due to the enclosing span tag. + (success, attrs, native, accel) = Pango.parse_markup(model[itr][COL_NATIVE_NAME], -1, "_") + english = model[itr][COL_ENGLISH_NAME] + entry = self._langsupportEntry.get_text().strip() + + # Nothing in the text entry? Display everything. + if not entry: + return True + + # Otherwise, filter the list showing only what is matched by the + # text entry. Either the English or native names can match. + lowered = entry.lower() + if lowered in native.lower() or lowered in english.lower(): + return True + else: + return False + + def _mark_selected_bold(self, column, renderer, model, itr, idx): + value = model[itr][idx] + if model[itr][COL_SELECTED]: + value = "<b>%s</b>" % value + renderer.set_property("markup", value) + + def on_langsupport_toggled(self, renderer, path): + selected = not self._langsupportStoreFilter[path][COL_SELECTED] + itr = self._langsupportStoreFilter.get_iter(path) + itr = self._langsupportStoreFilter.convert_iter_to_child_iter(itr) + self._langsupportStore[itr][COL_SELECTED] = selected + + def on_clear_icon_clicked(self, entry, icon_pos, event): + if icon_pos == Gtk.EntryIconPosition.SECONDARY: + entry.set_text("") + + def on_entry_changed(self, *args): + self._langsupportStoreFilter.refilter()