You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qubes-installer-qubes-os/anaconda/pyanaconda/ui/gui/spokes/welcome.py

336 lines
14 KiB

# Welcome 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.
#
import sys
import re
import os
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from pyanaconda.ui.gui.hubs.summary import SummaryHub
from pyanaconda.ui.gui.spokes import StandaloneSpoke
from pyanaconda.ui.gui.utils import setup_gtk_direction, escape_markup, gtk_action_wait
from pyanaconda.ui.gui.xkl_wrapper import XklWrapper
from pyanaconda.ui.gui.spokes.lib.lang_locale_handler import LangLocaleHandler
from pyanaconda import localization
from pyanaconda.product import distributionText, isFinal, productName, productVersion
from pyanaconda import flags
from pyanaconda import geoloc
from pyanaconda.i18n import _, C_
from pyanaconda.iutil import is_unsupported_hw, ipmi_abort
from pyanaconda.constants import DEFAULT_LANG, WINDOW_TITLE_TEXT
import logging
log = logging.getLogger("anaconda")
__all__ = ["WelcomeLanguageSpoke"]
class WelcomeLanguageSpoke(LangLocaleHandler, StandaloneSpoke):
"""
.. inheritance-diagram:: WelcomeLanguageSpoke
:parts: 3
"""
mainWidgetName = "welcomeWindow"
focusWidgetName = "languageEntry"
uiFile = "spokes/welcome.glade"
helpFile = "WelcomeSpoke.xml"
builderObjects = ["languageStore", "languageStoreFilter", "localeStore",
"welcomeWindow", "betaWarnDialog", "unsupportedHardwareDialog"]
preForHub = SummaryHub
priority = 0
def __init__(self, *args, **kwargs):
StandaloneSpoke.__init__(self, *args, **kwargs)
LangLocaleHandler.__init__(self)
self._xklwrapper = XklWrapper.get_instance()
self._origStrings = {}
def apply(self):
(store, itr) = self._localeSelection.get_selected()
locale = store[itr][1]
locale = localization.setup_locale(locale, self.data.lang, text_mode=False)
self._set_lang(locale)
# Skip timezone and keyboard default setting for kickstart installs.
# The user may have provided these values via kickstart and if not, we
# need to prompt for them.
if flags.flags.automatedInstall:
return
geoloc_timezone = geoloc.get_timezone()
loc_timezones = localization.get_locale_timezones(self.data.lang.lang)
if geoloc_timezone:
# (the geolocation module makes sure that the returned timezone is
# either a valid timezone or None)
self.data.timezone.timezone = geoloc_timezone
elif loc_timezones and not self.data.timezone.timezone:
# no data is provided by Geolocation, try to get timezone from the
# current language
self.data.timezone.timezone = loc_timezones[0]
@property
def completed(self):
# Skip the welcome screen if we are in single language mode
# If language has not been set the default language (en_US)
# will be used for the installation and for the installed system.
if flags.flags.singlelang:
return True
if flags.flags.automatedInstall and self.data.lang.seen:
return self.data.lang.lang and self.data.lang.lang != ""
else:
return False
def _row_is_separator(self, model, itr, *args):
return model[itr][3]
def initialize(self):
self._languageStore = self.builder.get_object("languageStore")
self._languageStoreFilter = self.builder.get_object("languageStoreFilter")
self._languageEntry = self.builder.get_object("languageEntry")
self._langSelection = self.builder.get_object("languageViewSelection")
self._langSelectedRenderer = self.builder.get_object("langSelectedRenderer")
self._langSelectedColumn = self.builder.get_object("langSelectedColumn")
self._langView = self.builder.get_object("languageView")
self._localeView = self.builder.get_object("localeView")
self._localeStore = self.builder.get_object("localeStore")
self._localeSelection = self.builder.get_object("localeViewSelection")
LangLocaleHandler.initialize(self)
# We need to tell the view whether something is a separator or not.
self._langView.set_row_separator_func(self._row_is_separator, None)
# We can use the territory from geolocation here
# to preselect the translation, when it's available.
territory = geoloc.get_territory_code(wait=True)
# bootopts and kickstart have priority over geoip
if self.data.lang.lang and self.data.lang.seen:
locales = [self.data.lang.lang]
else:
locales = localization.get_territory_locales(territory) or [DEFAULT_LANG]
# get the data models
filter_store = self._languageStoreFilter
store = filter_store.get_model()
# get language codes for the locales
langs = [localization.parse_langcode(locale)['language'] for locale in locales]
# check which of the geolocated languages have translations
# and store the iterators for those languages in a dictionary
langs_with_translations = {}
itr = store.get_iter_first()
while itr:
row_lang = store[itr][2]
if row_lang in langs:
langs_with_translations[row_lang] = itr
itr = store.iter_next(itr)
# if there are no translations for the given locales,
# use default
if not langs_with_translations:
self._set_lang(DEFAULT_LANG)
localization.setup_locale(DEFAULT_LANG, self.data.lang, text_mode=False)
lang_itr, _locale_itr = self._select_locale(self.data.lang.lang)
langs_with_translations[DEFAULT_LANG] = lang_itr
locales = [DEFAULT_LANG]
# go over all geolocated languages in reverse order
# and move those we have translation for to the top of the
# list, above the separator
for lang in reversed(langs):
itr = langs_with_translations.get(lang)
if itr:
store.move_after(itr, None)
else:
# we don't have translation for this language,
# so dump all locales for it
locales = [l for l in locales
if localization.parse_langcode(l)['language'] != lang]
# And then we add a separator after the selected best language
# and any additional languages (that have translations) from geoip
newItr = store.insert(len(langs_with_translations))
store.set(newItr, 0, "", 1, "", 2, "", 3, True)
# setup the "best" locale
locale = localization.setup_locale(locales[0], self.data.lang)
self._set_lang(locale)
self._select_locale(self.data.lang.lang)
def _retranslate_one(self, widgetName, context=None):
widget = self.builder.get_object(widgetName)
if not widget:
return
if not widget in self._origStrings:
self._origStrings[widget] = widget.get_label()
before = self._origStrings[widget]
if context is not None:
widget.set_label(C_(context, before))
else:
widget.set_label(_(before))
def retranslate(self):
# Change the translations on labels and buttons that do not have
# substitution text.
for name in ["pickLanguageLabel", "betaWarnTitle", "betaWarnDesc"]:
self._retranslate_one(name)
# It would be nice to be able to read the translation context from the
# widget, but we live in an imperfect world.
# See also: https://bugzilla.gnome.org/show_bug.cgi?id=729066
for name in ["quitButton", "continueButton"]:
self._retranslate_one(name, "GUI|Welcome|Beta Warn Dialog")
# The welcome label is special - it has text that needs to be
# substituted.
welcomeLabel = self.builder.get_object("welcomeLabel")
welcomeLabel.set_text(_("WELCOME TO %(name)s %(version)s.") %
{"name" : productName.upper(), "version" : productVersion}) # pylint: disable=no-member
# Retranslate the language (filtering) entry's placeholder text
languageEntry = self.builder.get_object("languageEntry")
if not languageEntry in self._origStrings:
self._origStrings[languageEntry] = languageEntry.get_placeholder_text()
languageEntry.set_placeholder_text(_(self._origStrings[languageEntry]))
# And of course, don't forget the underlying window.
self.window.set_property("distribution", distributionText().upper())
self.window.retranslate()
# Retranslate the window title text
# - it looks like that the main window object is not yet
# properly initialized during the first run of the
# retranslate method (it is always triggered at startup)
# so make sure the object is actually what we think it is
# - ignoring this run is OK as the initial title is
# already translated to the initial language
if isinstance(self.main_window, Gtk.Window):
self.main_window.set_title(_(WINDOW_TITLE_TEXT))
# Correct the language attributes for labels
self.main_window.reapply_language()
def refresh(self):
self._select_locale(self.data.lang.lang)
self._languageEntry.set_text("")
self._languageStoreFilter.refilter()
def _add_language(self, store, native, english, lang):
native_span = '<span lang="%s">%s</span>' % \
(escape_markup(lang),
escape_markup(native))
store.append([native_span, english, lang, False])
def _add_locale(self, store, native, locale):
native_span = '<span lang="%s">%s</span>' % \
(escape_markup(re.sub(r'\..*', '', locale)),
escape_markup(native))
store.append([native_span, locale])
# Signal handlers.
def on_lang_selection_changed(self, selection):
(_store, selected) = selection.get_selected_rows()
LangLocaleHandler.on_lang_selection_changed(self, selection)
if not selected and hasattr(self.window, "set_may_continue"):
self.window.set_may_continue(False)
def on_locale_selection_changed(self, selection):
(store, selected) = selection.get_selected_rows()
if hasattr(self.window, "set_may_continue"):
self.window.set_may_continue(len(selected) > 0)
if selected:
lang = store[selected[0]][1]
lang = localization.setup_locale(lang)
self._set_lang(lang)
self.retranslate()
# Reset the text direction
setup_gtk_direction()
# Redraw the window to reset the sidebar to where it needs to be
self.window.queue_draw()
# Override the default in StandaloneSpoke so we can display the beta
# warning dialog first.
def _on_continue_clicked(self, window, user_data=None):
# Don't display the betanag dialog if this is the final release or
# when autostep has been requested as betanag breaks the autostep logic.
if not isFinal and not self.data.autostep.seen:
dlg = self.builder.get_object("betaWarnDialog")
with self.main_window.enlightbox(dlg):
rc = dlg.run()
dlg.hide()
if rc != 1:
ipmi_abort(scripts=self.data.scripts)
sys.exit(0)
# pylint: disable=no-member
unsupported_status = is_unsupported_hw()
if unsupported_status:
# Fedora kickstart do not have unsupported_hardware option:
# and not self.data.unsupportedhardware.unsupported_hardware:
dlg = self.builder.get_object("unsupportedHardwareDialog")
msg = self.builder.get_object("unsupportedHardwareDesc")
msg.set_text(_(msg.get_text()) % {'features': unsupported_status})
with self.main_window.enlightbox(dlg):
rc = dlg.run()
dlg.destroy()
if rc != 1:
ipmi_abort(scripts=self.data.scripts)
sys.exit(0)
StandaloneSpoke._on_continue_clicked(self, window, user_data)
@gtk_action_wait
def _set_lang(self, lang):
# This is *hopefully* safe. The only threads that might be running
# outside of the GIL are those doing file operations, the Gio dbus
# proxy thread, and calls from the Gtk main loop. The file operations
# won't be doing things that may access the environment, fingers
# crossed, the GDbus thread shouldn't be doing anything weird since all
# of our dbus calls are from python and synchronous. Using
# gtk_action_wait ensures that this is Gtk main loop thread, and it's
# holding the GIL.
#
# There is a lot of uncertainty and weasliness in those statements.
# This is not good code.
#
# We cannot get around setting $LANG. Python's gettext implementation
# differs from C in that consults only the environment for the current
# language and not the data set via setlocale. If we want translations
# from python modules to work, something needs to be set in the
# environment when the language changes.
# pylint: disable=environment-modify
os.environ["LANG"] = lang