[PATCH 3/3] EULA agreement spoke (#1000409)

Vratislav Podzimek vpodzime at redhat.com
Fri Sep 20 18:08:38 UTC 2013


Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 initial-setup.spec                          |   2 +
 initial_setup/__main__.py                   |   1 +
 initial_setup/gui/hubs/initial_setup_hub.py |  22 +++++
 initial_setup/gui/spokes/eula.glade         | 132 ++++++++++++++++++++++++++++
 initial_setup/gui/spokes/eula.py            |  72 +++++++++++++++
 initial_setup/product.py                    |  44 ++++++++++
 6 files changed, 273 insertions(+)
 create mode 100644 initial_setup/gui/spokes/eula.glade
 create mode 100644 initial_setup/gui/spokes/eula.py

diff --git a/initial-setup.spec b/initial-setup.spec
index 793af05..329af92 100644
--- a/initial-setup.spec
+++ b/initial-setup.spec
@@ -26,10 +26,12 @@ BuildRequires: gobject-introspection-devel
 BuildRequires: glade-devel
 BuildRequires: pygobject3
 BuildRequires: anaconda >= 19.13
+BuildRequires: pykickstart >= 1.99.35.5-1
 BuildRequires: python-di
 Requires: gtk3
 Requires: python
 Requires: anaconda >= 19.13
+Requires: pykickstart >= 1.99.35.5-1
 Requires(post): systemd
 Requires(preun): systemd
 Requires(postun): systemd
diff --git a/initial_setup/__main__.py b/initial_setup/__main__.py
index 55cce93..ffe5db6 100644
--- a/initial_setup/__main__.py
+++ b/initial_setup/__main__.py
@@ -51,6 +51,7 @@ from pyanaconda import kickstart
 
 # Construct a commandMap with the supported Anaconda's commands only
 kickstart_commands = ["user",
+                      "eula",
                       "group",
                       "keyboard",
                       "lang",
diff --git a/initial_setup/gui/hubs/initial_setup_hub.py b/initial_setup/gui/hubs/initial_setup_hub.py
index d9e798b..20ec0ae 100644
--- a/initial_setup/gui/hubs/initial_setup_hub.py
+++ b/initial_setup/gui/hubs/initial_setup_hub.py
@@ -2,7 +2,9 @@ from pyanaconda.constants import FIRSTBOOT_ENVIRON
 from pyanaconda.ui.gui.hubs import Hub
 from pyanaconda.ui.gui.spokes import Spoke
 from pyanaconda.ui.common import collect
+from initial_setup import product
 import os
+import sys
 
 __all__ = ["InitialSetupMainHub"]
 
@@ -62,3 +64,23 @@ class InitialSetupMainHub(Hub):
     @property
     def quitButton(self):
         return self.builder.get_object("quitButton")
+
+    def register_event_cb(self, event, cb):
+        if event == "continue" and self.continueButton:
+            self.continueButton.connect("clicked", lambda *args: cb())
+        elif event == "quit" and self.quitButton:
+            self.quitButton.connect("clicked", lambda *args: self._on_quit_clicked(cb))
+
+    def _on_quit_clicked(self, cb):
+        try:
+            cb()
+        except SystemExit:
+            # user wants to exit, check if EULA is available and accepted and do
+            # proper action
+            license_file = product.get_license_file_name()
+            if not license_file or self.data.eula.agreed:
+                # agreed, just exit
+                sys.exit(0)
+            else:
+                # not agreed, reboot the system and leave Initial Setup enabled
+                os.system("reboot")
diff --git a/initial_setup/gui/spokes/eula.glade b/initial_setup/gui/spokes/eula.glade
new file mode 100644
index 0000000..ea29652
--- /dev/null
+++ b/initial_setup/gui/spokes/eula.glade
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.6 -->
+  <!-- interface-requires AnacondaWidgets 1.0 -->
+  <object class="GtkTextBuffer" id="eulaBuffer">
+    <property name="text" translatable="yes">The license will go here</property>
+  </object>
+  <object class="AnacondaSpokeWindow" id="eulaWindow">
+    <property name="startup_id">filler</property>
+    <property name="can_focus">False</property>
+    <property name="hexpand">True</property>
+    <property name="vexpand">True</property>
+    <property name="startup_id">filler</property>
+    <property name="window_name" translatable="yes">LICENSE INFORMATION</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="xscale">0.80000001192092896</property>
+            <property name="yscale">0.80000001192092896</property>
+            <child internal-child="action_area">
+              <object class="GtkBox" id="mainBox">
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="licenseAgreementLabel">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">start</property>
+                    <property name="margin_top">24</property>
+                    <property name="margin_bottom">6</property>
+                    <property name="label" translatable="yes">License Agreement:</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox" id="eulaBox">
+                    <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="GtkTextView" id="eulaView">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="margin_bottom">18</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="vscroll_policy">natural</property>
+                        <property name="pixels_above_lines">12</property>
+                        <property name="editable">False</property>
+                        <property name="wrap_mode">word</property>
+                        <property name="left_margin">12</property>
+                        <property name="right_margin">12</property>
+                        <property name="cursor_visible">False</property>
+                        <property name="buffer">eulaBuffer</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="agreeCheckButton">
+                        <property name="label" translatable="yes">I _accept the license agreement.</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="on_check_button_toggled" 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">False</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/initial_setup/gui/spokes/eula.py b/initial_setup/gui/spokes/eula.py
new file mode 100644
index 0000000..0704477
--- /dev/null
+++ b/initial_setup/gui/spokes/eula.py
@@ -0,0 +1,72 @@
+"""EULA spoke for the Initial Setup"""
+
+import gettext
+
+from gi.repository import Pango
+from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
+from pyanaconda.ui.gui.spokes import NormalSpoke
+from pyanaconda.ui.gui.categories.localization import LocalizationCategory
+from pyanaconda.constants import FIRSTBOOT_ENVIRON
+
+from initial_setup.product import get_license_file_name
+
+_ = lambda x: gettext.ldgettext("initial-setup", x)
+N_ = lambda x: x
+
+__all__ = ["EULAspoke"]
+
+class EULAspoke(FirstbootOnlySpokeMixIn, NormalSpoke):
+    """The EULA spoke"""
+
+    builderObjects = ["eulaBuffer", "eulaWindow"]
+    mainWidgetName = "eulaWindow"
+    uiFile = "eula.glade"
+
+    icon = "application-certificate-symbolic"
+    title = N_("_LICENSE INFORMATION")
+    category = LocalizationCategory
+
+    def initialize(self):
+        NormalSpoke.initialize(self)
+
+        self._have_eula = True
+        self._eula_buffer = self.builder.get_object("eulaBuffer")
+        self._agree_check_button = self.builder.get_object("agreeCheckButton")
+        self._agree_label = self._agree_check_button.get_child()
+        self._agree_text = self._agree_label.get_text()
+
+        itr = self._eula_buffer.get_iter_at_offset(0)
+        license_file = get_license_file_name()
+        if not license_file:
+            self._have_eula = False
+            self._eula_buffer.set_text(_("No license found. Please report this "
+                                         "at http://bugzilla.redhat.com"))
+            return
+
+        with open(license_file, "r") as fobj:
+            for line in fobj:
+                self._eula_buffer.insert(itr, line)
+
+    def refresh(self):
+        self._agree_check_button.set_sensitive(self._have_eula)
+        self._agree_check_button.set_active(self.data.eula.agreed)
+
+    def apply(self):
+        self.data.eula.agreed = self._agree_check_button.get_active()
+
+    @property
+    def completed(self):
+        return not self._have_eula or self.data.eula.agreed
+
+    @property
+    def status(self):
+        if not self._have_eula:
+            return _("No license found")
+
+        return _("License agreed") if self.data.eula.agreed else _("License not agreed")
+
+    def on_check_button_toggled(self, checkbutton, *args):
+        if self._agree_check_button.get_active():
+            self._agree_label.set_markup("<b>%s</b>" % self._agree_text)
+        else:
+            self._agree_label.set_markup(self._agree_text)
diff --git a/initial_setup/product.py b/initial_setup/product.py
index 82f9b0f..aa9bda3 100644
--- a/initial_setup/product.py
+++ b/initial_setup/product.py
@@ -1,6 +1,12 @@
 """Module providing information about the installed product."""
 
+from pyanaconda.localization import find_best_locale_match
+from pyanaconda.constants import DEFAULT_LANG
+import os
+import glob
+
 RELEASE_STRING_FILE = "/etc/os-release"
+LICENSE_FILE_GLOB = "/usr/share/doc/redhat-release*/EULA*"
 
 def product_title():
     """
@@ -34,3 +40,41 @@ def is_final():
 
     # doesn't really matter for the Initial Setup
     return True
+
+def get_license_file_name():
+    """
+    Get filename of the license file best matching current localization settings.
+
+    :return: filename of the license file or None if no license file found
+    :rtype: str or None
+
+    """
+
+    all_eulas = glob.glob(LICENSE_FILE_GLOB)
+    non_localized_eulas = []
+    langs = set()
+    for eula in all_eulas:
+        if "EULA_" in eula:
+            # license file for a specific locale
+            lang = eula.rsplit("EULA_", 1)[1]
+            if lang:
+                langs.add(lang)
+        else:
+            non_localized_eulas.append(eula)
+
+    best_lang = find_best_locale_match(os.environ["LANG"], langs)
+    if not best_lang:
+        # nothing found for the current language, try the default one
+        best_lang = find_best_locale_match(DEFAULT_LANG, langs)
+
+    if not best_lang:
+        # nothing found even for the default language, use non-localized or None
+        if non_localized_eulas:
+            best_eula = non_localized_eulas[0]
+        else:
+            return None
+    else:
+        # use first of the best-matching EULA files (there should be only one)
+        best_eula = glob.glob(LICENSE_FILE_GLOB + ("_%s" % best_lang))[0]
+
+    return best_eula
-- 
1.7.11.7



More information about the anaconda-patches mailing list