diff --git a/Makefile b/Makefile
index fb0d2eb..ee36a1f 100644
--- a/Makefile
+++ b/Makefile
@@ -487,12 +487,19 @@ coverage-jenkins:
#
# gettext, po files, etc
#
-
po/POTFILES.in:
# generate the POTFILES.in file expected by intltool. it wants one
# file per line, but we're lazy.
find $(SRC_DIR)/ $(RCT_SRC_DIR) $(RD_SRC_DIR) $(DAEMONS_SRC_DIR) $(YUM_PLUGINS_SRC_DIR) -name "*.py" > po/POTFILES.in
- find $(SRC_DIR)/gui/data/ -name "*.glade" >> po/POTFILES.in
+ find $(SRC_DIR)/gui/data/glade/ -name "*.glade" >> po/POTFILES.in
+ # intltool-update doesn't recognize .ui as glade files, so
+ # build a dir of .glade symlinks to the .ui files and add to POTFILES.in
+ mkdir -p po/tmp_ui_links
+ for ui_file in ./$(SRC_DIR)/gui/data/ui/*.ui ; do \
+ ui_base=$$(basename "$$ui_file") ; \
+ ln -f -s "../../$$ui_file" "po/tmp_ui_links/$$ui_base.glade" ; \
+ done ;
+ find po/tmp_ui_links/ -name "*.glade" >> po/POTFILES.in
find $(BIN_DIR) -name "*-to-rhsm" >> po/POTFILES.in
find $(BIN_DIR) -name "subscription-manager*" >> po/POTFILES.in
find $(BIN_DIR) -name "rct" >> po/POTFILES.in
diff --git a/man/rhsm.conf.5 b/man/rhsm.conf.5
index 04e9aca..29349b2 100644
--- a/man/rhsm.conf.5
+++ b/man/rhsm.conf.5
@@ -51,7 +51,7 @@ The port which the subscription service is listening on\&.
.PP
insecure
.RS 4
-This flag enables or disables certification verification using the certificate authorities which are installed in /etc/rhsm/ca\&.
+This flag enables or disables entitlement server certification verification using the certificate authorities which are installed in /etc/rhsm/ca\&.
.RE
.PP
ssl_verify_depth
diff --git a/rel-eng/packages/subscription-manager b/rel-eng/packages/subscription-manager
index 6f399f3..9f6984a 100644
--- a/rel-eng/packages/subscription-manager
+++ b/rel-eng/packages/subscription-manager
@@ -1 +1 @@
-1.15.9-7 ./
+1.15.9-8 ./
diff --git a/src/initial-setup/com_redhat_subscription_manager/gui/spokes/rhsm_gui.py b/src/initial-setup/com_redhat_subscription_manager/gui/spokes/rhsm_gui.py
index 09ca0b6..43b6947 100644
--- a/src/initial-setup/com_redhat_subscription_manager/gui/spokes/rhsm_gui.py
+++ b/src/initial-setup/com_redhat_subscription_manager/gui/spokes/rhsm_gui.py
@@ -22,6 +22,7 @@ import sys
from pyanaconda.ui.gui.spokes import NormalSpoke
from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
from pyanaconda.ui.categories.system import SystemCategory
+from pyanaconda.ui.gui.utils import really_hide
log = logging.getLogger(__name__)
@@ -38,6 +39,7 @@ from subscription_manager.gui import managergui
from subscription_manager.injectioninit import init_dep_injection
from subscription_manager import injection as inj
from subscription_manager.gui import registergui
+from subscription_manager.gui import utils
ga_GObject.threads_init()
@@ -45,7 +47,7 @@ __all__ = ["RHSMSpoke"]
class RHSMSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
- buildrObjects = ["RHSMSpokeWindow", "RHSMSpokeWindow-action_area1"]
+ buildrObjects = ["RHSMSpokeWindow"]
mainWidgetName = "RHSMSpokeWindow"
@@ -67,68 +69,113 @@ class RHSMSpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
init_dep_injection()
facts = inj.require(inj.FACTS)
+
backend = managergui.Backend()
- self._registergui = registergui.RegisterScreen(backend, facts,
- callbacks=[self.finished])
- self._action_area = self.builder.get_object("RHSMSpokeWindow-action_area1")
- self._register_box = self._registergui.dialog_vbox6
-
- # FIXME: close_window handling is kind of a mess. Standlone subman gui,
- # the firstboot screens, and initial-setup need it to do different
- # things. Potentially a 'Im done with this window now' signal, with
- # each attaching different handlers.
- self._registergui.close_window_callback = self._close_window_callback
-
- self._registergui._error_screen = registergui.CHOOSE_SERVER_PAGE
-
- # we have a ref to _register_box, but need to remove it from
- # the regustergui.window (a GtkDialog), and add it to the main
- # box in the action area of our initial-setup screen.
- self._registergui.window.remove(self._register_box)
- self._action_area.pack_end(self._register_box, True, True, 0)
- self._action_area.show()
- self._register_box.show_all()
- self._registergui.initialize()
-
- def _close_window_callback(self):
- self._registergui.goto_error_screen()
-
- def finished(self):
- self._registergui.done()
- self._registergui.cancel_button.hide()
- self._registergui.register_button.hide()
+ self.register_widget = registergui.RegisterWidget(backend, facts,
+ parent_window=self.main_window)
+
+ self.register_box = self.builder.get_object("register_box")
+ self.button_box = self.builder.get_object('navigation_button_box')
+ self.proceed_button = self.builder.get_object('proceed_button')
+ self.cancel_button = self.builder.get_object('cancel_button')
+
+ self.register_box.pack_start(self.register_widget.register_widget,
+ True, True, 0)
+
+ # Hook up the nav buttons in the gui
+ # TODO: add a 'start over'?
+ self.proceed_button.connect('clicked', self._on_register_button_clicked)
+ self.cancel_button.connect('clicked', self.cancel)
+
+ # initial-setup will likely
+ self.register_widget.connect('finished', self.finished)
+ self.register_widget.connect('register-finished', self.register_finished)
+ self.register_widget.connect('register-error', self._on_register_error)
+
+ # update the 'next/register button on page change'
+ self.register_widget.connect('notify::register-button-label',
+ self._on_register_button_label_change)
+
+ self.register_box.show_all()
+ self.register_widget.initialize()
+
+ # handler for RegisterWidgets 'finished' signal
+ def finished(self, obj):
+ self._done = True
+ really_hide(self.button_box)
+
+ # If we completed registration, that's close enough to consider
+ # completed.
+ def register_finished(self, obj):
self._done = True
# Update gui widgets to reflect state of self.data
+ # This could also be used to pre populate partial answers from a ks
+ # or answer file
def refresh(self):
log.debug("data.addons.com_redhat_subscription_manager %s",
self.data.addons.com_redhat_subscription_manager)
-
pass
+ # take info from the gui widgets and set into the self.data
def apply(self):
self.data.addons.com_redhat_subscription_manager.text = \
"System is registered to Red Hat Subscription Management."
+ # when the spoke is left, this can run anything that happens
def execute(self):
pass
+ def cancel(self, button):
+ # TODO: clear out settings and restart?
+ # TODO: attempt to undo the REST api calls we've made?
+ self.register_widget.set_initial_screen()
+ self.register_widget.clear_screens()
+
+ # A property indicating the spoke is ready to be visited. This
+ # could depend on other modules or waiting for internal state to be setup.
@property
def ready(self):
return True
+ # Indicate if all the mandatory actions are completed
@property
def completed(self):
+ # TODO: tie into register_widget.info.register-state
return self._done
+ # indicate if the module has to be completed before initial-setup is done.
@property
def mandatory(self):
return False
+ # A user facing string showing a summary of the status. This is displayed
+ # under the spokes name on it's hub.
@property
def status(self):
if self._done:
+ # TODO: add consumer uuid, products, etc?
return "System is registered to RHSM."
else:
return "System is not registered to RHSM."
+
+ def _on_register_button_clicked(self, button):
+ # unset any error info
+ self.clear_info()
+
+ self.register_widget.emit('proceed')
+
+ def _on_register_error(self, widget, msg, exc_info):
+ if exc_info:
+ formatted_msg = utils.format_exception(exc_info, msg)
+ self.set_error(formatted_msg)
+ else:
+ log.error(msg)
+ self.set_error(msg)
+
+ def _on_register_button_label_change(self, obj, value):
+ register_label = obj.get_property('register-button-label')
+
+ if register_label:
+ self.proceed_button.set_label(register_label)
diff --git a/src/initial-setup/com_redhat_subscription_manager/gui/spokes/rhsm_gui.ui b/src/initial-setup/com_redhat_subscription_manager/gui/spokes/rhsm_gui.ui
index ea465a3..3a5f64f 100644
--- a/src/initial-setup/com_redhat_subscription_manager/gui/spokes/rhsm_gui.ui
+++ b/src/initial-setup/com_redhat_subscription_manager/gui/spokes/rhsm_gui.ui
@@ -39,10 +39,60 @@
<child internal-child="action_area">
<object class="GtkBox" id="RHSMSpokeWindow-action_area1">
<property name="can_focus">False</property>
+ <property name="valign">start</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
- <placeholder/>
+ <object class="GtkButtonBox" id="navigation_button_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label" translatable="yes">Cancel</property>
+ <property name="visible">True</property>
+ <property name="yalign">0.43999999761581421</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="proceed_button">
+ <property name="label" translatable="yes">Register</property>
+ <property name="visible">True</property>
+ <property name="yalign">0.56999999284744263</property>
+ </object>
+ <packing>
+ <property name="expand">True</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">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="register_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
</child>
diff --git a/src/subscription_manager/ga_impls/ga_gtk2/GObject.py b/src/subscription_manager/ga_impls/ga_gtk2/GObject.py
index 3783ce7..d77a280 100644
--- a/src/subscription_manager/ga_impls/ga_gtk2/GObject.py
+++ b/src/subscription_manager/ga_impls/ga_gtk2/GObject.py
@@ -5,21 +5,22 @@ from gobject import GObject
from gobject import MainLoop
# methods
-from gobject import add_emission_hook, idle_add, source_remove, timeout_add
+from gobject import add_emission_hook, idle_add, property
+from gobject import source_remove, timeout_add
from gobject import markup_escape_text
# enums
-from gobject import SIGNAL_RUN_LAST
+from gobject import SIGNAL_RUN_FIRST, SIGNAL_RUN_LAST
from gobject import TYPE_BOOLEAN, TYPE_PYOBJECT, PARAM_READWRITE
class SignalFlags(object):
+ RUN_FIRST = SIGNAL_RUN_FIRST
RUN_LAST = SIGNAL_RUN_LAST
-
constants = [TYPE_BOOLEAN, TYPE_PYOBJECT, PARAM_READWRITE]
methods = [add_emission_hook, idle_add, markup_escape_text,
- source_remove, timeout_add]
+ property, source_remove, timeout_add]
enums = [SignalFlags]
objects = [GObject, MainLoop]
__all__ = objects + methods + constants + enums
diff --git a/src/subscription_manager/ga_impls/ga_gtk2/Gtk.py b/src/subscription_manager/ga_impls/ga_gtk2/Gtk.py
index d009019..3d04bbc 100644
--- a/src/subscription_manager/ga_impls/ga_gtk2/Gtk.py
+++ b/src/subscription_manager/ga_impls/ga_gtk2/Gtk.py
@@ -26,11 +26,13 @@ from gtk import SORT_ASCENDING
from gtk import SELECTION_NONE
from gtk import STATE_NORMAL
from gtk import WINDOW_TOPLEVEL
-from gtk import WIN_POS_MOUSE, WIN_POS_CENTER_ON_PARENT
+from gtk import WIN_POS_MOUSE, WIN_POS_CENTER, WIN_POS_CENTER_ON_PARENT
# methods
from gtk import image_new_from_icon_name
+from gtk import events_pending
from gtk import main
+from gtk import main_iteration
from gtk import main_quit
from gtk import check_version
@@ -98,6 +100,7 @@ class WindowType(object):
class WindowPosition(object):
MOUSE = WIN_POS_MOUSE
+ CENTER = WIN_POS_CENTER
CENTER_ON_PARENT = WIN_POS_CENTER_ON_PARENT
@@ -129,6 +132,6 @@ widgets = [AboutDialog, Adjustment, Builder, Button, Calendar, CellRendererPixbu
RadioButton, SpinButton, TextBuffer, TreeStore, TreeView, TreeViewColumn,
VBox, Viewport, Window]
-methods = [check_version, main, main_quit]
+methods = [check_version, events_pending, main, main_iteration, main_quit]
__all__ = widgets + constants + methods + enums
diff --git a/src/subscription_manager/gui/autobind.py b/src/subscription_manager/gui/autobind.py
index 8d55cf4..f863f0c 100644
--- a/src/subscription_manager/gui/autobind.py
+++ b/src/subscription_manager/gui/autobind.py
@@ -47,7 +47,6 @@ class DryRunResult(object):
# The products that would be covered if we did this autobind:
autobind_products = set()
- log.debug("Unentitled products: %s" % required_products)
for pool_quantity in self.json:
pool = pool_quantity['pool']
# This is usually the MKT product and has no content, but it
diff --git a/src/subscription_manager/gui/data/glade/choose_server.glade b/src/subscription_manager/gui/data/glade/choose_server.glade
index 622e4fc..e67b428 100644
--- a/src/subscription_manager/gui/data/glade/choose_server.glade
+++ b/src/subscription_manager/gui/data/glade/choose_server.glade
@@ -114,7 +114,6 @@
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<accessibility/>
- <signal handler="on_server_entry_changed" name="changed"/>
<child internal-child="accessible">
<object class="AtkObject" id="a11y-server_entry1">
<property name="AtkObject::accessible-name" translatable="yes">server_entry</property>
diff --git a/src/subscription_manager/gui/data/glade/register_dialog.glade b/src/subscription_manager/gui/data/glade/register_dialog.glade
new file mode 100644
index 0000000..fe76ce1
--- /dev/null
+++ b/src/subscription_manager/gui/data/glade/register_dialog.glade
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="2.24"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="register_dialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">System Registration</property>
+ <property name="icon_name">subscription-manager</property>
+ <property name="type_hint">splashscreen</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="register_dialog_main_vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ <property name="image_position">right</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="cancel_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">cancel_button</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="register_button">
+ <property name="label" translatable="yes">Register</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="image_position">right</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="register_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_button</property>
+ <property name="AtkObject::accessible-description" translatable="yes">register_button</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">cancel_button</action-widget>
+ <action-widget response="0">register_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/src/subscription_manager/gui/data/glade/registration.glade b/src/subscription_manager/gui/data/glade/registration.glade
index 02a9e61..b42f510 100644
--- a/src/subscription_manager/gui/data/glade/registration.glade
+++ b/src/subscription_manager/gui/data/glade/registration.glade
@@ -1,192 +1,103 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 2.10 -->
- <!--
- interface-naming-policy project-wide -->
- <object class="GtkDialog" id="register_dialog">
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkVBox" id="register_widget">
+ <property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="border_width">5</property>
- <property name="title" translatable="yes">System Registration</property>
- <property name="resizable">False</property>
- <property name="modal">True</property>
- <property name="window_position">center-on-parent</property>
- <property name="destroy_with_parent">True</property>
- <property name="icon_name">subscription-manager</property>
- <property name="type_hint">dialog</property>
- <property name="deletable">False</property>
- <accessibility/>
- <signal handler="on_register_dialog_delete_event" name="delete_event"/>
- <child internal-child="vbox">
- <object class="GtkVBox" id="dialog-vbox6">
+ <property name="spacing">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="register_widget-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_widget_main_vbox</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="register_notebook">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="spacing">2</property>
- <accessibility/>
- <child internal-child="action_area">
- <object class="GtkHButtonBox" id="dialog-action_area6">
+ <property name="show_tabs">False</property>
+ <property name="show_border">False</property>
+ <child>
+ <object class="GtkVBox" id="progressVbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="layout_style">end</property>
- <accessibility/>
+ <property name="border_width">25</property>
+ <property name="spacing">7</property>
<child>
- <object class="GtkButton" id="cancel_button">
- <property name="label">gtk-cancel</property>
+ <object class="GtkLabel" id="progress_label">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- <property name="image_position">right</property>
- <accessibility/>
- <signal handler="on_register_cancel_button_clicked" name="clicked"/>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><b>Registering</b></property>
+ <property name="use_markup">True</property>
<child internal-child="accessible">
- <object class="AtkObject" id="a11y-cancel_button1">
- <property name="AtkObject::accessible-name">cancel_button</property>
+ <object class="AtkObject" id="progress_label-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">progress_label</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="padding">8</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="register_button">
- <property name="label" translatable="yes">Register</property>
+ <object class="GtkProgressBar" id="register_progressbar">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="receives_default">True</property>
- <property name="image_position">right</property>
- <accessibility/>
- <signal handler="on_register_button_clicked" name="clicked"/>
+ <property name="can_focus">False</property>
+ <property name="activity_mode">True</property>
+ <property name="pulse_step">0.25</property>
<child internal-child="accessible">
- <object class="AtkObject" id="a11y-register_button1">
- <property name="AtkObject::accessible-name" translatable="yes">register_button</property>
- <property name="AtkObject::accessible-description">register_button</property>
+ <object class="AtkObject" id="register_progressbar-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_progressbar</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-dialog-action_area61">
- <property name="AtkObject::accessible-name" translatable="yes">registration_dialog_action_area</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="pack_type">end</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkNotebook" id="register_notebook">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="show_tabs">False</property>
- <property name="show_border">False</property>
<child>
- <object class="GtkVBox" id="progressVbox">
+ <object class="GtkLabel" id="register_details_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="border_width">25</property>
- <property name="spacing">7</property>
- <child>
- <object class="GtkLabel" id="progress_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Registering</b></property>
- <property name="use_markup">True</property>
- <accessibility/>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-progress_label1">
- <property name="AtkObject::accessible-name" translatable="yes">progress_label</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="padding">8</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkProgressBar" id="register_progressbar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="activity_mode">True</property>
- <accessibility/>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-register_progressbar1">
- <property name="AtkObject::accessible-name" translatable="yes">register_progressbar</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="register_details_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="use_markup">True</property>
- <accessibility/>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-register_details_label1">
- <property name="AtkObject::accessible-name" translatable="yes">register_details_label</property>
- </object>
- </child>
+ <property name="xalign">0</property>
+ <property name="use_markup">True</property>
+ <property name="single_line_mode">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="register_details_label-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_details_label</property>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
</child>
</object>
- </child>
- <child type="tab">
- <object class="GtkLabel" id="label2">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">page 2</property>
- </object>
<packing>
- <property name="tab_fill">False</property>
+ <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>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-dialog-vbox61">
- <property name="AtkObject::accessible-name" translatable="yes">register_dialog_main_vbox</property>
+ <child type="tab">
+ <object class="GtkLabel" id="tab_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Progress Page</property>
</object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
</child>
</object>
- </child>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-register_dialog1">
- <property name="AtkObject::accessible-name">register_dialog</property>
- </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
</child>
</object>
</interface>
diff --git a/src/subscription_manager/gui/data/glade/repositories.glade b/src/subscription_manager/gui/data/glade/repositories.glade
index e45fc29..944db9a 100644
--- a/src/subscription_manager/gui/data/glade/repositories.glade
+++ b/src/subscription_manager/gui/data/glade/repositories.glade
@@ -19,7 +19,7 @@
<property name="AtkObject::accessible-name" translatable="yes">manage_repositories_dialog</property>
</object>
</child>
- <signal name="delete-event" handler="on_dialog_delete_event" swapped="no"/>
+ <signal name="delete-event" handler="on_dialog_delete_event" />
<child internal-child="vbox">
<object class="GtkVBox" id="main_container">
<property name="visible">True</property>
@@ -240,7 +240,7 @@
<property name="AtkObject::accessible-name" translatable="yes">remove_all_overrides_button</property>
</object>
</child>
- <signal name="clicked" handler="on_reset_button_clicked" swapped="no"/>
+ <signal name="clicked" handler="on_reset_button_clicked" />
</object>
<packing>
<property name="expand">False</property>
@@ -255,7 +255,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_apply_button_clicked" swapped="no"/>
+ <signal name="clicked" handler="on_apply_button_clicked" />
</object>
<packing>
<property name="expand">False</property>
@@ -275,7 +275,7 @@
<property name="AtkObject::accessible-name" translatable="yes">close_button</property>
</object>
</child>
- <signal name="clicked" handler="on_close_button_clicked" swapped="no"/>
+ <signal name="clicked" handler="on_close_button_clicked" />
</object>
<packing>
<property name="expand">False</property>
diff --git a/src/subscription_manager/gui/data/ui/choose_server.ui b/src/subscription_manager/gui/data/ui/choose_server.ui
index 5bd3e6b..8684f07 100644
--- a/src/subscription_manager/gui/data/ui/choose_server.ui
+++ b/src/subscription_manager/gui/data/ui/choose_server.ui
@@ -114,7 +114,6 @@
<property name="width_chars">30</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
- <signal name="changed" handler="on_server_entry_changed" swapped="no"/>
<child internal-child="accessible">
<object class="AtkObject" id="server_entry-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">server_entry</property>
diff --git a/src/subscription_manager/gui/data/ui/credentials.ui b/src/subscription_manager/gui/data/ui/credentials.ui
index 219d32a..283a410 100644
--- a/src/subscription_manager/gui/data/ui/credentials.ui
+++ b/src/subscription_manager/gui/data/ui/credentials.ui
@@ -53,9 +53,11 @@
<object class="GtkBox" id="forgot_info_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="valign">start</property>
<child>
<object class="GtkImage" id="tip_icon_hosted">
<property name="visible">True</property>
+ <property name="valign">center</property>
<property name="can_focus">False</property>
<property name="yalign">0</property>
<property name="stock">gtk-info</property>
@@ -75,11 +77,13 @@
<object class="GtkLabel" id="registration_tip_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
+ <property name="valign">start</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">middle</property>
<property name="xpad">1</property>
<property name="ypad">2</property>
<property name="use_markup">True</property>
+ <property name="lines">1</property>
<property name="wrap">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="registration_tip_label-atkobject">
diff --git a/src/subscription_manager/gui/data/ui/register_dialog.ui b/src/subscription_manager/gui/data/ui/register_dialog.ui
new file mode 100644
index 0000000..ed83845
--- /dev/null
+++ b/src/subscription_manager/gui/data/ui/register_dialog.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <object class="GtkDialog" id="register_dialog">
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">end</property>
+ <property name="title" translatable="yes">System Registration</property>
+ <property name="resizable">False</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="icon_name">subscription-manager</property>
+ <property name="type_hint">dialog</property>
+ <property name="deletable">False</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="register_dialog_main_vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">end</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ <property name="image_position">right</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="cancel_button-atkobject">
+ <property name="AtkObject::accessible-name">cancel_button</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="register_button">
+ <property name="label" translatable="yes">Register</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="image_position">right</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="register_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_button</property>
+ <property name="AtkObject::accessible-description">register_button</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="dialog-action_area3-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">registration_dialog_action_area</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="register_dialog_main_vbox_atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_dialog_main_vbox</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="register_dialog-atkobject">
+ <property name="AtkObject::accessible-name">register_dialog</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/src/subscription_manager/gui/data/ui/registration.ui b/src/subscription_manager/gui/data/ui/registration.ui
index 31baac9..3bf3d1a 100644
--- a/src/subscription_manager/gui/data/ui/registration.ui
+++ b/src/subscription_manager/gui/data/ui/registration.ui
@@ -2,188 +2,107 @@
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.0"/>
- <object class="GtkDialog" id="register_dialog">
+ <object class="GtkBox" id="register_widget">
+ <property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="border_width">5</property>
- <property name="title" translatable="yes">System Registration</property>
- <property name="resizable">False</property>
- <property name="modal">True</property>
- <property name="window_position">center-on-parent</property>
- <property name="destroy_with_parent">True</property>
- <property name="icon_name">subscription-manager</property>
- <property name="type_hint">dialog</property>
- <property name="deletable">False</property>
- <signal name="delete-event" handler="on_register_dialog_delete_event" swapped="no"/>
- <child internal-child="vbox">
- <object class="GtkBox" id="dialog_vbox6">
+ <property name="valign">start</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkNotebook" id="register_notebook">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">baseline</property>
- <property name="valign">start</property>
- <property name="orientation">vertical</property>
- <property name="spacing">2</property>
- <child internal-child="action_area">
- <object class="GtkButtonBox" id="dialog-action_area6">
+ <property name="show_tabs">False</property>
+ <property name="show_border">False</property>
+ <child>
+ <object class="GtkBox" id="progressVbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="valign">start</property>
- <property name="layout_style">end</property>
+ <property name="border_width">25</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">7</property>
<child>
- <object class="GtkButton" id="cancel_button">
- <property name="label">gtk-cancel</property>
+ <object class="GtkLabel" id="progress_label">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- <property name="image_position">right</property>
- <signal name="clicked" handler="on_register_cancel_button_clicked" swapped="no"/>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes"><b>Registering</b></property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
<child internal-child="accessible">
- <object class="AtkObject" id="cancel_button-atkobject">
- <property name="AtkObject::accessible-name">cancel_button</property>
+ <object class="AtkObject" id="progress_label-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">progress_label</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="padding">8</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="register_button">
- <property name="label" translatable="yes">Register</property>
+ <object class="GtkProgressBar" id="register_progressbar">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="receives_default">True</property>
- <property name="image_position">right</property>
- <signal name="clicked" handler="on_register_button_clicked" swapped="no"/>
+ <property name="can_focus">False</property>
+ <property name="pulse_step">0.1</property>
<child internal-child="accessible">
- <object class="AtkObject" id="register_button-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">register_button</property>
- <property name="AtkObject::accessible-description">register_button</property>
+ <object class="AtkObject" id="register_progressbar-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_progressbar</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
- <child internal-child="accessible">
- <object class="AtkObject" id="dialog-action_area6-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">registration_dialog_action_area</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkNotebook" id="register_notebook">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="valign">start</property>
- <property name="show_tabs">False</property>
- <property name="show_border">False</property>
<child>
- <object class="GtkBox" id="progressVbox">
+ <object class="GtkLabel" id="register_details_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="border_width">25</property>
- <property name="orientation">vertical</property>
- <property name="spacing">7</property>
- <child>
- <object class="GtkLabel" id="progress_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes"><b>Registering</b></property>
- <property name="use_markup">True</property>
- <property name="xalign">0</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="progress_label-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">progress_label</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="padding">8</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkProgressBar" id="register_progressbar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="register_progressbar-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">register_progressbar</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="register_details_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="use_markup">True</property>
- <property name="xalign">0</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="register_details_label-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">register_details_label</property>
- </object>
- </child>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="register_details_label-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_details_label</property>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
</child>
</object>
<packing>
- <property name="tab_fill">False</property>
- </packing>
- </child>
- <child type="tab">
- <object class="GtkLabel" id="label2">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">page 2</property>
- </object>
- <packing>
- <property name="tab_fill">False</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="tab_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Progress Page</property>
+ </object>
<packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
+ <property name="tab_fill">False</property>
</packing>
</child>
<child internal-child="accessible">
- <object class="AtkObject" id="dialog_vbox6-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">register_dialog_main_vbox</property>
+ <object class="AtkObject" id="register_notebook-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_notebook</property>
</object>
</child>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
</child>
<child internal-child="accessible">
- <object class="AtkObject" id="register_dialog-atkobject">
- <property name="AtkObject::accessible-name">register_dialog</property>
+ <object class="AtkObject" id="register_widget-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">register_widget_main_vbox</property>
</object>
</child>
</object>
diff --git a/src/subscription_manager/gui/firstboot/rhsm_login.py b/src/subscription_manager/gui/firstboot/rhsm_login.py
index 7c06f19..3aea9a6 100644
--- a/src/subscription_manager/gui/firstboot/rhsm_login.py
+++ b/src/subscription_manager/gui/firstboot/rhsm_login.py
@@ -1,14 +1,18 @@
import gettext
-import socket
import sys
import logging
_ = lambda x: gettext.ldgettext("rhsm", x)
-import gtk
-gtk.gdk.threads_init()
+from subscription_manager import ga_loader
+ga_loader.init_ga()
+
+from subscription_manager.ga import Gtk as ga_Gtk
+from subscription_manager.ga import gtk_compat
+
+gtk_compat.threads_init()
import rhsm
@@ -26,20 +30,21 @@ running_as_firstboot()
from subscription_manager.injectioninit import init_dep_injection
init_dep_injection()
-from subscription_manager.injection import PLUGIN_MANAGER, IDENTITY, require
+
+from subscription_manager import injection as inj
from subscription_manager.facts import Facts
from subscription_manager.hwprobe import Hardware
-from subscription_manager.gui.firstboot_base import RhsmFirstbootModule
from subscription_manager.gui import managergui
from subscription_manager.gui import registergui
-from subscription_manager.gui.utils import handle_gui_exception
-from subscription_manager.gui.autobind import \
- ServiceLevelNotSupportedException, NoProductsException, \
- AllProductsCoveredException
-from subscription_manager import managerlib
+from subscription_manager.gui.utils import format_exception
+from subscription_manager.i18n import configure_i18n
+
+from firstboot import module
+from firstboot import constants
+
+configure_i18n(with_glade=True)
-from rhsm.connection import RestlibException
from rhsm.utils import remove_scheme
sys.path.append("/usr/share/rhn")
@@ -50,179 +55,36 @@ try:
except ImportError:
log.debug("no rhn-client-tools modules could be imported")
-MANUALLY_SUBSCRIBE_PAGE = 11
-
-
-class SelectSLAScreen(registergui.SelectSLAScreen):
- """
- override the default SelectSLAScreen to jump to the manual subscribe page.
- """
- def _on_get_service_levels_cb(self, result, error=None):
- if error is not None:
- if isinstance(error[1], ServiceLevelNotSupportedException):
- message = _("Unable to auto-attach, server does not support "
- "service levels. Please run 'Subscription Manager' "
- "to manually attach a subscription.")
- self._parent.manual_message = message
- self._parent.pre_done(MANUALLY_SUBSCRIBE_PAGE)
- elif isinstance(error[1], NoProductsException):
- message = _("No installed products on system. No need to "
- "update subscriptions at this time.")
- self._parent.manual_message = message
- self._parent.pre_done(MANUALLY_SUBSCRIBE_PAGE)
- elif isinstance(error[1], AllProductsCoveredException):
- message = _("All installed products are fully subscribed.")
- self._parent.manual_message = message
- self._parent.pre_done(MANUALLY_SUBSCRIBE_PAGE)
- else:
- handle_gui_exception(error, _("Error subscribing"),
- self._parent.window)
- self._parent.finish_registration(failed=True)
- return
-
- (current_sla, unentitled_products, sla_data_map) = result
-
- self._parent.current_sla = current_sla
- if len(sla_data_map) == 1:
- # If system already had a service level, we can hit this point
- # when we cannot fix any unentitled products:
- if current_sla is not None and \
- not self._can_add_more_subs(current_sla, sla_data_map):
- message = _("Unable to attach any additional subscriptions at "
- "current service level: %s") % current_sla
- self._parent.manual_message = message
- self._parent.pre_done(MANUALLY_SUBSCRIBE_PAGE)
- return
-
- self._dry_run_result = sla_data_map.values()[0]
- self._parent.pre_done(registergui.CONFIRM_SUBS_PAGE)
- elif len(sla_data_map) > 1:
- self._sla_data_map = sla_data_map
- self.set_model(unentitled_products, sla_data_map)
- self._parent.pre_done(registergui.DONT_CHANGE)
- else:
- message = _("No service levels will cover all installed products. "
- "Please run 'Subscription Manager' to manually "
- "attach subscriptions.")
- self._parent.manual_message = message
- self._parent.pre_done(MANUALLY_SUBSCRIBE_PAGE)
-
-
-class PerformRegisterScreen(registergui.PerformRegisterScreen):
-
- def _on_registration_finished_cb(self, new_account, error=None):
- if error is not None:
- handle_gui_exception(error, registergui.REGISTER_ERROR,
- self._parent.window)
- self._parent.finish_registration(failed=True)
- return
-
- try:
- managerlib.persist_consumer_cert(new_account)
- self._parent.backend.cs.force_cert_check() # Ensure there isn't much wait time
-
- if self._parent.activation_keys:
- self._parent.pre_done(registergui.REFRESH_SUBSCRIPTIONS_PAGE)
- elif self._parent.skip_auto_bind:
- message = _("You have opted to skip auto-attach.")
- self._parent.manual_message = message
- self._parent.pre_done(MANUALLY_SUBSCRIBE_PAGE)
- else:
- self._parent.pre_done(registergui.SELECT_SLA_PAGE)
-
- # If we get errors related to consumer name on register,
- # go back to the credentials screen where we set the
- # consumer name. See bz#865954
- except RestlibException, e:
- handle_gui_exception(e, registergui.REGISTER_ERROR,
- self._parent.window)
- if e.code == 404 and self._parent.activation_keys:
- self._parent.pre_done(registergui.ACTIVATION_KEY_PAGE)
- if e.code == 400:
- self._parent.pre_done(registergui.CREDENTIALS_PAGE)
-
- except Exception, e:
- handle_gui_exception(e, registergui.REGISTER_ERROR,
- self._parent.window)
- self._parent.finish_registration(failed=True)
-
- def pre(self):
- # TODO: this looks like it needs updating now that we run
- # firstboot without rhn client tools.
-
- # Because the RHN client tools check if certs exist and bypass our
- # firstboot module if so, we know that if we reach this point and
- # identity certs exist, someone must have hit the back button.
- # TODO: i'd like this call to be inside the async progress stuff,
- # since it does take some time
- identity = require(IDENTITY)
- if identity.is_valid():
- try:
- managerlib.unregister(self._parent.backend.cp_provider.get_consumer_auth_cp(),
- self._parent.identity.uuid)
- except socket.error, e:
- handle_gui_exception(e, e, self._parent.window)
- self._parent._registration_finished = False
-
- return registergui.PerformRegisterScreen.pre(self)
-
-class ManuallySubscribeScreen(registergui.Screen):
- widget_names = registergui.Screen.widget_names + ['title']
- gui_file = "manually_subscribe"
-
- def __init__(self, parent, backend):
- super(ManuallySubscribeScreen, self).__init__(parent, backend)
-
- self.button_label = _("Finish")
-
- def apply(self):
- return registergui.FINISH
-
- def pre(self):
- if self._parent.manual_message:
- self.title.set_label(self._parent.manual_message)
- # XXX set message here.
- return False
-
-
-class moduleClass(RhsmFirstbootModule, registergui.RegisterScreen):
+class moduleClass(module.Module, object):
def __init__(self):
"""
Create a new firstboot Module for the 'register' screen.
"""
- RhsmFirstbootModule.__init__(self, # Firstboot module title
- # Note: translated title needs to be unique across all
- # firstboot modules, not just the rhsm ones. See bz #828042
- _("Subscription Management Registration"),
- _("Subscription Registration"),
- 200.1, 109.10)
+ super(moduleClass, self).__init__()
- backend = managergui.Backend()
- self.plugin_manager = require(PLUGIN_MANAGER)
- registergui.RegisterScreen.__init__(self, backend, Facts())
+ self.mode = constants.MODE_REGULAR
+ self.title = _("Subscription Management Registration")
+ self.sidebarTitle = _("Subscription Registration")
+ self.priority = 200.1
- #insert our new screens
- screen = SelectSLAScreen(self, backend)
- screen.index = self._screens[registergui.SELECT_SLA_PAGE].index
- self._screens[registergui.SELECT_SLA_PAGE] = screen
- self.register_notebook.remove_page(screen.index)
- self.register_notebook.insert_page(screen.container,
- position=screen.index)
+ # NOTE: all of this is copied form former firstboot_base module
+ # and may no longer be needed
+ # set this so subclasses can override behaviour if needed
+ self._is_compat = False
- screen = PerformRegisterScreen(self, backend)
- self._screens[registergui.PERFORM_REGISTER_PAGE] = screen
-
- screen = ManuallySubscribeScreen(self, backend)
- self._screens.append(screen)
- screen.index = self.register_notebook.append_page(screen.container)
+ reg_info = registergui.RegisterInfo()
+ backend = managergui.Backend()
+ self.plugin_manager = inj.require(inj.PLUGIN_MANAGER)
+ self.register_widget = registergui.RegisterWidget(backend, Facts(), reg_info)
# Will be False if we are on an older RHEL version where
# rhn-client-tools already does some things so we don't have to.
self.standalone = True
distribution = Hardware().get_distribution()
log.debug("Distribution: %s" % str(distribution))
+
try:
dist_version = float(distribution[1])
# We run this for Fedora as well, but all we really care about here
@@ -243,7 +105,141 @@ class moduleClass(RhsmFirstbootModule, registergui.RegisterScreen):
self.interface = None
self.proxies_were_enabled_from_gui = None
- self._apply_result = self._RESULT_FAILURE
+ self._apply_result = constants.RESULT_FAILURE
+
+ self.page_status = constants.RESULT_FAILURE
+
+ def apply(self, interface, testing=False):
+ """
+ 'Next' button has been clicked - try to register with the
+ provided user credentials and return the appropriate result
+ value.
+ """
+ self.interface = interface
+
+ self.register_widget.emit('proceed')
+
+ # This is always "fail" until we get to the done screen
+ return self.page_status
+
+ def createScreen(self):
+ """
+ Create a new instance of gtk.VBox, pulling in child widgets from the
+ glade file.
+ """
+ self.vbox = ga_Gtk.VBox()
+ # self.vbox.pack_start(self.get_widget("register_widget"), False, False, 0)
+ self.vbox.pack_start(self.register_widget.register_widget, False, False, 0)
+
+ self.register_widget.connect('finished', self.on_finished)
+ self.register_widget.connect('register-error', self.on_register_error)
+
+ # In firstboot, we leverage the RHN setup proxy settings already
+ # presented to the user, so hide the choose server screen's proxy
+ # text and button. But, if we are standalone, show our versions.
+ if not self.standalone and False:
+ screen = self._screens[registergui.CHOOSE_SERVER_PAGE]
+ screen.proxy_frame.destroy()
+
+ def focus(self):
+ """
+ Focus the initial UI element on the page, in this case the
+ login name field.
+ """
+ # FIXME: This is currently broken
+ # login_text = self.glade.get_widget("account_login")
+ # login_text.grab_focus()
+
+ def initializeUI(self):
+ log.debug("initializeUi %s", self)
+ # Need to make sure that each time the UI is initialized we reset back
+ # to the main register screen.
+
+ # Note, even if we are standalone firstboot mode (no rhn modules),
+ # we may still have RHN installed, and possibly configured.
+ self._read_rhn_proxy_settings()
+
+ self.register_widget.initialize()
+
+ def needsNetwork(self):
+ """
+ This lets firstboot know that networking is required, in order to
+ talk to hosted UEP.
+ """
+ return True
+
+ def needsReboot(self):
+ return False
+
+ # TODO: verify this doesnt break anything
+ def not_renderModule(self, interface):
+ #ParentClass.renderModule(self, interface)
+
+ # firstboot module class docs state to not override renderModule,
+ # so this is breaking the law.
+ #
+ # This is to set line wrapping on the title label to resize
+ # correctly with our long titles and their even longer translations
+ super(moduleClass, self).renderModule(interface)
+
+ # FIXME: likely all of this should be behind a try/except, since it's
+ # likely to break, and it is just to fix cosmetic issues.
+ # Walk down widget tree to find the title label
+ label_container = self.vbox.get_children()[0]
+ title_label = label_container.get_children()[0]
+
+ # Set the title to wrap and connect to size-allocate to
+ # properly resize the label so that it takes up the most
+ # space it can.
+ title_label.set_line_wrap(True)
+ title_label.connect('size-allocate',
+ lambda label, size: label.set_size_request(size.width - 1, -1))
+
+ def shouldAppear(self):
+ """
+ Indicates to firstboot whether to show this screen. In this case
+ we want to skip over this screen if there is already an identity
+ certificate on the machine (most likely laid down in a kickstart).
+ """
+ identity = inj.require(inj.IDENTITY)
+ return not identity.is_valid()
+
+ def on_register_error(self, obj, msg, exc_list):
+ self.page_status = constants.RESULT_FAILURE
+
+ # TODO: we can add the register state, error type (error or exc)
+ if exc_list:
+ self.handle_register_exception(obj, msg, exc_list)
+ else:
+ self.handle_register_error(obj, msg)
+ return True
+
+ def on_finished(self, obj):
+ self.finished = True
+ self.page_status = constants.RESULT_SUCCESS
+ return False
+
+ def handle_register_error(self, obj, msg):
+ self.error_dialog(msg)
+
+ def handle_register_exception(self, obj, msg, exc_info):
+ message = format_exception(exc_info, msg)
+ self.error_dialog(message)
+
+ def error_dialog(self, text):
+ dlg = ga_Gtk.MessageDialog(None, 0, ga_Gtk.MessageType.ERROR,
+ ga_Gtk.ButtonsType.OK, text)
+ dlg.set_markup(text)
+ dlg.set_skip_taskbar_hint(True)
+ dlg.set_skip_pager_hint(True)
+ dlg.set_position(ga_Gtk.WindowPosition.CENTER)
+
+ def response_handler(obj, response_id):
+ obj.destroy()
+
+ dlg.connect('response', response_handler)
+ dlg.set_modal(True)
+ dlg.show()
def _get_initial_screen(self):
"""
@@ -310,47 +306,6 @@ class moduleClass(RhsmFirstbootModule, registergui.RegisterScreen):
self.backend.cp_provider.set_connection_info()
- def apply(self, interface, testing=False):
- """
- 'Next' button has been clicked - try to register with the
- provided user credentials and return the appropriate result
- value.
- """
-
- # on el5 we can't just move to another page, we have to set the next
- # page then do an apply. since we've already done our work async, skip
- # this time through
- if self._skip_apply_for_page_jump:
- self._skip_apply_for_page_jump = False
- # Reset back to first screen in our module in case the user hits back.
- # The firstboot register screen subclass will handle unregistering
- # if necessary when it runs again.
- self.show()
- return self._RESULT_SUCCESS
-
- self.interface = interface
-
- # bad proxy settings can cause socket.error or friends here
- # see bz #810363
- try:
- valid_registration = self.register()
-
- except socket.error, e:
- handle_gui_exception(e, e, self.window)
- return self._RESULT_FAILURE
-
- # run main_iteration till we have no events, like idle
- # loop sources, aka, the thread watchers are finished.
- while gtk.events_pending():
- gtk.main_iteration()
-
- if valid_registration:
- self._cached_credentials = self._get_credentials_hash()
-
- # finish_registration/skip_remaining_screens should set
- # __apply_result to RESULT_JUMP
- return self._apply_result
-
def close_window(self):
"""
Overridden from RegisterScreen - we want to bypass the default behavior
@@ -365,49 +320,6 @@ class moduleClass(RhsmFirstbootModule, registergui.RegisterScreen):
"""
pass
- def createScreen(self):
- """
- Create a new instance of gtk.VBox, pulling in child widgets from the
- glade file.
- """
- self.vbox = gtk.VBox(spacing=10)
- self.register_dialog = self.get_widget("dialog-vbox6")
- self.register_dialog.reparent(self.vbox)
-
- # Get rid of the 'register' and 'cancel' buttons, as we are going to
- # use the 'forward' and 'back' buttons provided by the firsboot module
- # to drive the same functionality
- self._destroy_widget('register_button')
- self._destroy_widget('cancel_button')
-
- # In firstboot, we leverage the RHN setup proxy settings already
- # presented to the user, so hide the choose server screen's proxy
- # text and button. But, if we are standalone, show our versions.
- if not self.standalone:
- screen = self._screens[registergui.CHOOSE_SERVER_PAGE]
- screen.proxy_frame.destroy()
-
- def initializeUI(self):
- # Need to make sure that each time the UI is initialized we reset back
- # to the main register screen.
-
- # Note, even if we are standalone firstboot mode (no rhn modules),
- # we may still have RHN installed, and possibly configured.
- self._read_rhn_proxy_settings()
-
- # NOTE: On EL5 this does not appear to be called when the user
- # presses Back, only when they go through the first time.
- self.show()
-
- def focus(self):
- """
- Focus the initial UI element on the page, in this case the
- login name field.
- """
- # FIXME: This is currently broken
- # login_text = self.glade.get_widget("account_login")
- # login_text.grab_focus()
-
def _destroy_widget(self, widget_name):
"""
Destroy a widget by name.
@@ -489,6 +401,3 @@ class moduleClass(RhsmFirstbootModule, registergui.RegisterScreen):
else:
self._apply_result = self._RESULT_SUCCESS
return
-
-# for el5
-childWindow = moduleClass
diff --git a/src/subscription_manager/gui/firstboot_base.py b/src/subscription_manager/gui/firstboot_base.py
deleted file mode 100644
index 1a7b507..0000000
--- a/src/subscription_manager/gui/firstboot_base.py
+++ /dev/null
@@ -1,122 +0,0 @@
-#
-# Copyright (c) 2012 Red Hat, Inc.
-#
-# This software is licensed to you under the GNU General Public License,
-# version 2 (GPLv2). There is NO WARRANTY for this software, express or
-# implied, including the implied warranties of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
-# along with this software; if not, see
-# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
-#
-# Red Hat trademarks are not licensed under GPLv2. No permission is
-# granted to use or replicate Red Hat trademarks that are incorporated
-# in this software or its documentation.
-#
-
-import sys
-
-sys.path.append("/usr/share/rhsm")
-
-# rhsm_login init the injector before we are loaded
-from subscription_manager import injection as inj
-
-from subscription_manager.i18n import configure_i18n
-
-configure_i18n(with_glade=True)
-
-# Number of total RHSM firstboot screens, used to skip past to whatever's
-# next in a couple places.
-NUM_RHSM_SCREENS = 4
-
-try:
- _version = "el6"
- from firstboot.constants import RESULT_SUCCESS, RESULT_FAILURE, RESULT_JUMP
- from firstboot.module import Module
-except Exception:
- # we must be on el5
- _version = "el5"
- from firstboot_module_window import FirstbootModuleWindow
-
-
-if _version == "el5":
- ParentClass = FirstbootModuleWindow
-else:
- ParentClass = Module
-
-
-class RhsmFirstbootModule(ParentClass):
-
- def __init__(self, title, sidebar_title, priority, compat_priority):
- ParentClass.__init__(self)
-
- if _version == "el6":
- # set this so subclasses can override behaviour if needed
- self._is_compat = False
- self._RESULT_SUCCESS = RESULT_SUCCESS
- self._RESULT_FAILURE = RESULT_FAILURE
- self._RESULT_JUMP = RESULT_JUMP
- else:
- self._is_compat = True
- self._RESULT_SUCCESS = True
- self._RESULT_FAILURE = None
- self._RESULT_JUMP = True
-
- # this value is relative to when you want to load the screen
- # so check other modules before setting
- self.priority = priority
- self.sidebarTitle = sidebar_title
- self.title = title
-
- # el5 values
- self.runPriority = compat_priority
- self.moduleName = self.sidebarTitle
- self.windowTitle = self.moduleName
- self.shortMessage = self.title
- self.noSidebar = True
-
- # el5 value to get access to parent object for page jumping
- self.needsparent = 1
-
- def renderModule(self, interface):
- ParentClass.renderModule(self, interface)
- label_container = self.vbox.get_children()[0]
- title_label = label_container.get_children()[0]
-
- # Set the title to wrap and connect to size-allocate to
- # properly resize the label so that it takes up the most
- # space it can.
- title_label.set_line_wrap(True)
- title_label.connect('size-allocate', lambda label, size: label.set_size_request(size.width - 1, -1))
-
- def needsNetwork(self):
- """
- This lets firstboot know that networking is required, in order to
- talk to hosted UEP.
- """
- return True
-
- def shouldAppear(self):
- """
- Indicates to firstboot whether to show this screen. In this case
- we want to skip over this screen if there is already an identity
- certificate on the machine (most likely laid down in a kickstart).
- """
- identity = inj.require(inj.IDENTITY)
- return not identity.is_valid()
-
- ##############################
- # el5 compat functions follow
- ##############################
-
- def launch(self, doDebug=None):
- self.createScreen()
- return self.vbox, self.icon, self.windowTitle
-
- def passInParent(self, parent):
- self.compat_parent = parent
-
- self.register_button = parent.nextButton
- self.cancel_button = parent.backButton
-
- def grabFocus(self):
- self.initializeUI()
diff --git a/src/subscription_manager/gui/managergui.py b/src/subscription_manager/gui/managergui.py
index 2aae80e..cb2cec9 100644
--- a/src/subscription_manager/gui/managergui.py
+++ b/src/subscription_manager/gui/managergui.py
@@ -158,6 +158,7 @@ class MainWindow(widgets.SubmanBaseWidget):
log.debug("Server Versions: %s " % get_server_versions(self.backend.cp_provider.get_consumer_auth_cp()))
settings = self.main_window.get_settings()
+
# prevent gtk from trying to save a list of recently used files, which
# as root, causes gtk warning:
# "Attempting to set the permissions of `/root/.local/share/recently-used.xbel'
@@ -171,8 +172,7 @@ class MainWindow(widgets.SubmanBaseWidget):
self.system_facts_dialog = factsgui.SystemFactsDialog(self.facts)
- self.registration_dialog = registergui.RegisterScreen(self.backend, self.facts,
- self._get_window())
+ self.registration_dialog = registergui.RegisterDialog(self.backend, self.facts)
self.preferences_dialog = PreferencesDialog(self.backend,
self._get_window())
@@ -360,7 +360,6 @@ class MainWindow(widgets.SubmanBaseWidget):
self.redeem_menu_item.set_sensitive(False)
def _register_item_clicked(self, widget):
- self.log.debug("_register_item_clicked widget=%s", widget)
self.registration_dialog.initialize()
self.registration_dialog.show()
@@ -427,9 +426,8 @@ class MainWindow(widgets.SubmanBaseWidget):
self.import_sub_dialog.show()
def _update_certificates_button_clicked(self, widget):
- autobind_wizard = registergui.AutobindWizard(self.backend,
- self.facts,
- self._get_window())
+ autobind_wizard = registergui.AutobindWizardDialog(self.backend,
+ self.facts)
autobind_wizard.initialize()
autobind_wizard.show()
diff --git a/src/subscription_manager/gui/registergui.py b/src/subscription_manager/gui/registergui.py
index 123c783..3ba0fff 100644
--- a/src/subscription_manager/gui/registergui.py
+++ b/src/subscription_manager/gui/registergui.py
@@ -23,7 +23,6 @@ import socket
import sys
import threading
-
from subscription_manager.ga import Gtk as ga_Gtk
from subscription_manager.ga import GObject as ga_GObject
@@ -41,21 +40,16 @@ from subscription_manager import managerlib
from subscription_manager.utils import is_valid_server_info, MissingCaCertException, \
parse_server_info, restart_virt_who
-from subscription_manager.gui.utils import handle_gui_exception, show_error_window
+from subscription_manager.gui.utils import format_exception, show_error_window
from subscription_manager.gui.autobind import DryRunResult, \
ServiceLevelNotSupportedException, AllProductsCoveredException, \
NoProductsException
-from subscription_manager.gui.messageWindow import InfoDialog, OkDialog
from subscription_manager.jsonwrapper import PoolWrapper
_ = lambda x: gettext.ldgettext("rhsm", x)
gettext.textdomain("rhsm")
-#Gtk.glade.bindtextdomain("rhsm")
-
-#Gtk.glade.textdomain("rhsm")
-
log = logging.getLogger('rhsm-app.' + __name__)
CFG = config.initConfig()
@@ -74,6 +68,7 @@ def set_state(new_state):
global state
state = new_state
+ERROR_SCREEN = -3
DONT_CHANGE = -2
PROGRESS_PAGE = -1
CHOOSE_SERVER_PAGE = 0
@@ -122,388 +117,545 @@ def reset_resolver():
pass
-class RegistrationBox(widgets.SubmanBaseWidget):
- gui_file = "registration_box"
-
-
-class RegisterScreen(widgets.SubmanBaseWidget):
- """
- Registration Widget Screen
-
- RegisterScreen is the parent widget of registration screens, and
- also the base class of the firstboot rhsm_module.
-
- RegisterScreen has a list of Screen subclasses.
+class RegisterInfo(ga_GObject.GObject):
- Screen subclasses can be Screen, NonGuiScreen, or GuiScreen
- classes. Only GuiScreen classes are user visible. NonGuiScreen
- and subclasses are used for state transitions (a between screens
- check for pools, for example)
+ username = ga_GObject.property(type=str, default='')
+ password = ga_GObject.property(type=str, default='')
- The rhsmModule.apply() runs RegisterScreen.register().
- RegisterScreen.register runs the current screens .apply().
+ # server info
+ hostname = ga_GObject.property(type=str, default='')
+ port = ga_GObject.property(type=str, default='')
+ prefix = ga_GObject.property(type=str, default='')
- A Screen.apply() will return the index of the next screen that
- should be invoked (which may be a different screen, the same screen,
- or the special numbers for DONT_CHANGE and FINISH.)
+ # rhsm model info
+ environment = ga_GObject.property(type=str, default='')
+ consumername = ga_GObject.property(type=str, default='')
+ owner_key = ga_GObject.property(type=ga_GObject.TYPE_PYOBJECT, default=None)
+ activation_keys = ga_GObject.property(type=ga_GObject.TYPE_PYOBJECT, default=None)
- In firstboot, calling the firstboot modules .apply() results in calling
- rhsm_module.moduleClass.apply() which calls the first Screen.apply()
- (also self._current_screen).
+ # split into AttachInfo or FindSlaInfo?
+ current_sla = ga_GObject.property(type=ga_GObject.TYPE_PYOBJECT, default=None)
+ dry_run_result = ga_GObject.property(type=ga_GObject.TYPE_PYOBJECT, default=None)
- After the Screen.apply(), RegisterScreen.register checks it's return
- for DONT_CHANGE or FINISH.
+ # registergui states
+ skip_auto_bind = ga_GObject.property(type=bool, default=False)
+ details_label_txt = ga_GObject.property(type=str, default='')
+ register_state = ga_GObject.property(type=int, default=REGISTERING)
- If the apply returns a screen index, then the Screen.post() is called.
- The return value is ignored.
-
- The RegisterScreen.register calls RegisterScreen.run_pre() on the
- screen index that the current_screen .apply() returned(i.e. the
- next screen).
-
- run_pre() checks that it's arg (the result of above apply(), what
- is still currently the next screen) is not DONT_CHANGE/FINISH.
+ # TODO: make a gobj prop as well, with custom set/get, so we can be notified
+ @property
+ def identity(self):
+ id = require(IDENTITY)
+ return id
- If not, then it calls self._set_screen() which updates
- self._current_screen to point to the next screen.
+ def __init__(self):
+ ga_GObject.GObject.__init__(self)
- run_pre() then calls the new current_screens's .pre()
- .register()
- next_screen = current_screen.apply()
- current_screen.post()
- RegisterScreen.run_pre(next_screen)
- RegisterScreen._set_screen(next_screen)
- current_screen = next_screen
+class RegisterWidget(widgets.SubmanBaseWidget):
+ gui_file = "registration"
+ widget_names = ['register_widget', 'register_notebook',
+ 'register_details_label', 'register_progressbar',
+ 'progress_label']
+
+ __gsignals__ = {'proceed': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'register-warning': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, (ga_GObject.TYPE_PYOBJECT,)),
+ 'register-error': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, (ga_GObject.TYPE_PYOBJECT,
+ ga_GObject.TYPE_PYOBJECT)),
+ 'finished': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'attach-finished': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'register-finished': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, [])}
+
+ initial_screen = CHOOSE_SERVER_PAGE
+
+ register_button_label = ga_GObject.property(type=str, default=_('Register'))
+ # TODO: a prop equilivent to initial-setups 'completed' and 'status' props
+
+ def __init__(self, backend, facts, reg_info=None, parent_window=None):
+ super(RegisterWidget, self).__init__()
- Then if current_screen is a gui screen, the visible
- gui will update with the new widgets.
+ self.backend = backend
+ self.identity = require(IDENTITY)
+ self.facts = facts
- The new current_screen has its pre() method invoked. pre()
- methods may return an async representing that a request
- has been called and a callback registered. If that's the case,
- then RegisterScreen._set_screen() sets the current screen
- to a progress screen.
+ self.async = AsyncBackend(self.backend)
- The return value of RegisterScreen.run_pre() is ignored, and
- RegisterScreen.register() returns False.
+ # TODO: should be able to get rid of this soon, the
+ # only thing that uses it is the NetworkConfigDialog in
+ # chooseServerScreen and we can replace that with an embedded
+ # widget
+ self.parent_window = parent_window
+
+ self.info = reg_info or RegisterInfo()
+
+ self.progress_timer = None
+
+ # TODO: move these handlers into their own class
+ self.info.connect("notify::username",
+ self._on_username_password_change)
+ self.info.connect("notify::password",
+ self._on_username_password_change)
+ self.info.connect("notify::hostname",
+ self._on_connection_info_change)
+ self.info.connect("notify::port",
+ self._on_connection_info_change)
+ self.info.connect("notify::prefix",
+ self._on_connection_info_change)
+ self.info.connect("notify::activation-keys",
+ self._on_activation_keys_change)
+ self.info.connect('notify::details-label-txt',
+ self._on_details_label_txt_change)
+ self.info.connect('notify::register-state',
+ self._on_register_state_change)
+
+ # expect this to be driving from the parent dialog
+ self.connect('proceed',
+ self._on_proceed)
+
+ # FIXME: change glade name
+ self.details_label = self.register_details_label
+
+ # To update the 'next/register' button in the parent dialog based on the new page
+ self.register_notebook.connect('switch-page',
+ self._on_switch_page)
- This returns to rhsm_login.apply(), where valid_registration is
- set to the return value. valid_registration=True indicates a
- succesful registration
+ screen_classes = [ChooseServerScreen, ActivationKeyScreen,
+ CredentialsScreen, OrganizationScreen,
+ EnvironmentScreen, PerformRegisterScreen,
+ SelectSLAScreen, ConfirmSubscriptionsScreen,
+ PerformSubscribeScreen, RefreshSubscriptionsScreen,
+ InfoScreen, DoneScreen]
+ self._screens = []
- If valid_registration=True, we are basically done with registeration.
- But rhsm_login can't return from apply() yet, since that could
- potential lead to firstboot ending if it's the last or only module.
+ # TODO: current_screen as a gobject property
+ for idx, screen_class in enumerate(screen_classes):
+ self.add_screen(idx, screen_class)
- gtk main loop iterations are run, mostly to let any threads finish
- up and any idle loop thread watchers to dry up.
+ self._current_screen = None
- The return value of rhsm_login.apply() at this point is actualy
- the _apply_result instance variable. Register Screens() are expected
- to set this by calling their finish_registration() method. For
- subscription-manager-gui that means RegisterScreen.finish_registration,
- usually access as a Screens() self._parent.finish_registration.
+ # Track screens we "show" so we can choose a reasonable error screen
+ self.screen_history = []
- For firstboot screens, self._parent will be rhsm_module.moduleClass
- (also a subclass of RegisterScreen).
+ # FIXME: modify property instead
+ self.callbacks = []
- rhsm_module.finish_registration() will check the "failed" boolean,
- and either return to a Screen() (CredentialsPage, atm). Or if
- failed=True, it will also call RegisterScreen.finish_registration(),
- that closes the gui window.
+ self.register_widget.show()
- The UI flow is a result of the order of RegisterScreen._screens,
- and the screen indexes returned by Screen.apply().
+ def add_screen(self, idx, screen_class):
+ screen = screen_class(reg_info=self.info,
+ async_backend=self.async,
+ facts=self.facts,
+ parent_window=self.parent_window)
- But, between the Screen activity call also change the flow, most
- notably the results of any async calls and callbacks invoked from
- the screens .pre()
+ # add the index of the screen in self._screens to the class itself
+ screen.screens_index = idx
- A common case is the async callbacks error handling calling
- self._parent.finish_registration(failed=True)
+ # connect handlers to various screen signals. The screens are
+ # Gobjects not gtk widgets, so they can't propagate normally.
+ screen.connect('move-to-screen', self._on_move_to_screen)
+ screen.connect('stay-on-screen', self._on_stay_on_screen)
+ screen.connect('register-error', self._on_screen_register_error)
+ screen.connect('register-finished',
+ self._on_screen_register_finished)
+ screen.connect('attach-finished',
+ self._on_screen_attach_finished)
- The async callback can also call RegisterScreen.pre_done() to send the
- UI to a different screen. RHSM api call results that indicate multiple
- choices for a sub would send flow to a chooseSub GuiScreen vs a
- NonGuiScreen for attaching a sub, for example.
+ self._screens.append(screen)
- RegisterScreen.run_pre schedules async jobs, they get queued, and
- wait for their callbacks. The callbacks then can use pre_done()
- to finish the tasks the run_pre started. Typicaly the UI will
- see the Progress screens in the meantime.
+ # Some screens have no gui controls, they just use the
+ # PROGRESS_PAGE, so the indexes to the register_notebook's pages and
+ # to self._screen differ
+ if screen.needs_gui:
+ # screen.index is the screens index in self.register_notebook
+ screen.index = self.register_notebook.append_page(screen.container,
+ tab_label=None)
- If going to screen requires an async task, run_pre starts it by
- calling the new screens pre(), setting that screen to current (_set_screen),
- and then setting the GuiScreen to the progress screens. Screen
- transitions that don't need async tasks just return nothing from
- their pre() and go to the next screen in the order in self._screens.
+ def initialize(self):
+ self.set_initial_screen()
+ self.clear_screens()
+ # TODO: move this so it's only running when a progress bar is "active"
+ self.register_widget.show_all()
+
+ def start_progress_timer(self):
+ if not self.progress_timer:
+ self.progress_timer = ga_GObject.timeout_add(100, self._timeout_callback)
+
+ def stop_progress_timer(self):
+ if self.progress_timer:
+ ga_GObject.source_remove(self.progress_timer)
+ self.progress_timer = None
+
+ def set_initial_screen(self):
+ self._set_screen(self.initial_screen)
+ self._current_screen = self.initial_screen
+ self.screen_history = [self.initial_screen]
+
+ # switch-page should be after the current screen is reset
+ def _on_switch_page(self, notebook, page, page_num):
+ current_screen = self._screens[self._current_screen]
+ # NonGuiScreens have a None button label
+ if current_screen.button_label:
+ self.set_property('register-button-label', current_screen.button_label)
+
+ # HMMM: If the connect/backend/async, and the auth info is composited into
+ # the same GObject, these could be class closure handlers
+ def _on_username_password_change(self, *args):
+ self.async.set_user_pass(self.info.username, self.info.password)
+
+ def _on_connection_info_change(self, *args):
+ self.async.update()
+
+ def _on_activation_keys_change(self, obj, param):
+ activation_keys = obj.get_property('activation-keys')
+
+ # Unset backend from attempting to use basic auth
+ if activation_keys:
+ self.async.cp_provider.set_user_pass()
+ self.async.update()
+
+ def _on_details_label_txt_change(self, obj, value):
+ """Update the label under the progress bar on progress page."""
+ self.details_label.set_label("<small>%s</small>" %
+ obj.get_property('details-label-txt'))
+
+ def _on_register_state_change(self, obj, value):
+ """Handler for the signal indicating we moved from registering to attaching.
+
+ (the 'register-state' property changed), so update the
+ related label on progress page."""
+ state = obj.get_property('register-state')
+ if state == REGISTERING:
+ self.progress_label.set_markup(_("<b>Registering</b>"))
+ elif state == SUBSCRIBING:
+ self.progress_label.set_markup(_("<b>Attaching</b>"))
- Note the the flow of firstboot through multiple modules is driven
- by the return value of rhsm_login.apply(). firstboot itself maintains
- a list of modules and a an ordered list of them. True goes to the
- next screen, False stays. Except for RHEL6, where it is the opposite.
+ def do_register_error(self, msg, exc_info):
+ """Class closure signal handler for 'register-error'.
- As of RHEL7.0+, none of that matters much, since rhsm_login is the
- only module in firstboot.
+ This should always get run first, when this widget emits a
+ 'register-error', then it's emitted to other handlers (set up by
+ any parent dialogs for example)."""
+ # return to the last gui screen we showed.
- """
+ self._set_screen(self.screen_history[-1])
- widget_names = ['register_dialog', 'register_notebook',
- 'register_progressbar', 'register_details_label',
- 'cancel_button', 'register_button', 'progress_label',
- 'dialog_vbox6']
- gui_file = "registration"
- __gtype_name__ = 'RegisterScreen'
+ def _on_screen_register_error(self, obj, msg, exc_info):
+ """Handler for 'register-error' signals emitted from the Screens.
- def __init__(self, backend, facts=None, parent=None, callbacks=None):
- """
- Callbacks will be executed when registration status changes.
- """
- super(RegisterScreen, self).__init__()
+ Then emit one ourselves. Now emit a new signal for parent widget and
+ self.do_register_error() to handle"""
- self.backend = backend
- self.identity = require(IDENTITY)
- self.facts = facts
- self.parent = parent
- self.callbacks = callbacks or []
+ self.emit('register-error', msg, exc_info)
- self.async = AsyncBackend(self.backend)
+ # do_register_error handles it for this widget, so stop emission
+ return False
- callbacks = {"on_register_cancel_button_clicked": self.cancel,
- "on_register_button_clicked": self._on_register_button_clicked,
- "hide": self.cancel,
- "on_register_dialog_delete_event": self._delete_event}
- self.connect_signals(callbacks)
+ def _on_stay_on_screen(self, current_screen):
+ """A 'stay-on-screen' handler, for errors that need to be corrected before proceeding.
- self.window = self.register_dialog
- self.register_dialog.set_transient_for(self.parent)
+ A screen has been shown, and error handling emits this to indicate the
+ widget should not move to a different screen.
- screen_classes = [ChooseServerScreen, ActivationKeyScreen,
- CredentialsScreen, OrganizationScreen,
- EnvironmentScreen, PerformRegisterScreen,
- SelectSLAScreen, ConfirmSubscriptionsScreen,
- PerformSubscribeScreen, RefreshSubscriptionsScreen,
- InfoScreen, DoneScreen]
- self._screens = []
- for screen_class in screen_classes:
- screen = screen_class(self, self.backend)
- self._screens.append(screen)
- if screen.needs_gui:
- screen.index = self.register_notebook.append_page(
- screen.container, tab_label=None)
-
- self._current_screen = CHOOSE_SERVER_PAGE
- self._error_screen = DONT_CHANGE
-
- # values that will be set by the screens
- self.username = None
- self.consumername = None
- self.activation_keys = None
- self.owner_key = None
- self.environment = None
- self.current_sla = None
- self.dry_run_result = None
- self.skip_auto_bind = False
-
- # XXX needed by firstboot
- self.password = None
+ This also represents screens that allow the user to potentially correct
+ an error, so we track the history of these screens so errors can go to
+ a useful screen."""
+ self.screen_history.append(current_screen.screens_index)
+ self._set_screen(self._current_screen)
- # FIXME: a 'done' signal maybe?
- # initial_setup needs to be able to make this empty
- self.close_window_callback = self._close_window_callback
+ # TODO: replace most of the gui flow logic in the Screen subclasses with
+ # some state machine that drives them, possibly driving via signals
+ # indicating each state
- def initialize(self):
- # Ensure that we start on the first page and that
- # all widgets are cleared.
- self._set_initial_screen()
+ def _on_move_to_screen(self, current_screen, next_screen_id):
+ """Handler for the 'move-to-screen' signal, indicating a jump to another screen.
- self._set_navigation_sensitive(True)
- self._clear_registration_widgets()
- self.timer = ga_GObject.timeout_add(100, self._timeout_callback)
+ This can be used to send the UI to any other screen, including the next screen.
+ For example, to skip SLA selection if there is only one SLA."""
+ self.change_screen(next_screen_id)
- def show(self):
- # initial-setup module skips this, since it results in a
- # new top level window that isn't reparented to the initial-setup
- # screen.
- self.register_dialog.show()
+ def change_screen(self, next_screen_id):
+ """Move to the next screen and call the next screens .pre().
- def _set_initial_screen(self):
- target = self._get_initial_screen()
- self._set_screen(target)
+ If next_screen.pre() indicates it is async (by returning True)and is spinning
+ off a thread and we should wait for a callback, then move the screen to the
+ PROGRESS_PAGE. The callback passed to AsyncBackend in pre() is then responsible
+ for sending the user to the right screen via 'move-to-screen' signal."""
+ next_screen = self._screens[next_screen_id]
- def _get_initial_screen(self):
- return CHOOSE_SERVER_PAGE
+ self._set_screen(next_screen_id)
- # for subman gui, we don't need to switch screens on error
- # but for firstboot, we will go back to the info screen if
- # we have it.
- @property
- def error_screen(self):
- return self._error_screen
-
- def goto_error_screen(self):
- self._set_navigation_sensitive(True)
- self._set_screen(self.error_screen)
-
- # FIXME: This exists because standalone gui needs to update the nav
- # buttons in it's own top level window, while firstboot needs to
- # update the buttons in the main firstboot window. Firstboot version
- # has additional logic for rhel5/rhel6 differences.
- # FIXME: just split this into a registerWidget and a registerDialog
- def _set_navigation_sensitive(self, sensitive):
- # We could unsens the cancel button here, but since we use it as
- # a 'do over' button that sends the dialog back to the start, just
- # leave it enabled, to avoid leaving un unsens after an async error
- # handler.
- self.register_button.set_sensitive(sensitive)
+ async = next_screen.pre()
+ if async:
+ self.start_progress_timer()
+ next_screen.emit('move-to-screen', PROGRESS_PAGE)
def _set_screen(self, screen):
+ """Handle both updating self._current_screen, and updating register_notebook."""
+ next_notebook_page = screen
+
if screen > PROGRESS_PAGE:
self._current_screen = screen
+ # FIXME: If we just add ProgressPage in the screen order, we
+ # shouldn't need this bookeeping
if self._screens[screen].needs_gui:
- self._set_register_label(screen)
- self.register_notebook.set_current_page(self._screens[screen].index)
+ next_notebook_page = self._screens[screen].index
else:
- self.register_notebook.set_current_page(screen + 1)
+ # TODO: replace with a generator
+ next_notebook_page = screen + 1
+
+ # set_current_page changes the gui, and also results in the
+ # 'switch-page' attribute of the gtk notebook being emitted,
+ # indicating the gui has switched to that page.
+ self.register_notebook.set_current_page(next_notebook_page)
+
+ # FIXME: figure out to determine we are on first screen, then this
+ # could just be 'move-to-screen', next screen
+ # Go to the next screen/state
+ def _on_proceed(self, obj):
+ self.apply_current_screen()
+
+ def apply_current_screen(self):
+ """Extract any info from the widgets and call the screens apply()."""
+ self._screens[self._current_screen].apply()
+
+ def _on_screen_register_finished(self, obj):
+ """Handler for 'register-finished' signal, indicating register is finished.
+
+ The 'register-finished' signal indicates that we are finished with
+ registration (either completly, or because it's not needed, etc).
+ RegisterWidget then emits it's own 'register-finished' for any parent
+ dialogs to handle. Note: 'register-finished' only means the registration
+ steps are finished, and not neccasarily that the gui should be close.
+ It may need to auto attach, etc. The 'finished' signal indicates register
+ and attach are finished, while 'register-finished' is just the first part."""
+
+ self.emit('register-finished')
+
+ # We are done if there is auto bind is being skipped ("Manually attach
+ # to subscriptions" is clicked in the gui)
+ if self.info.get_property('skip-auto-bind'):
+ self.emit('finished')
+
+ def _on_screen_attach_finished(self, obj):
+ """Handler for 'attach-finished' signal from our Screens.
+
+ One of our Screens has indicated that subscription attachment is done.
+ Note: This doesn't neccasarily indicate success, just that the gui has
+ done all the attaching it can. RegisterWidget emits it's own
+ 'attach-finished' for parent widgets to handle. Again, note that
+ attach-finished is not the same as 'finished', even though at the moment,
+ 'finished' does immediately follow 'attach-finished'"""
+
+ self.emit('attach-finished')
+
+ # If attach is finished, we are done.
+ # let RegisterWidget's self.do_finished() handle any self specific
+ # shutdown (like detaching self.timer) first.
+ self.emit('finished')
+
+ def do_finished(self):
+ """Class closure signal handler for the 'finished' signal.
+
+ Ran first before the any other signal handlers attach to 'finished'"""
+ if self.progress_timer:
+ ga_GObject.source_remove(self.progress_timer)
+
+ # Switch to the 'done' screen before telling other signal handlers we
+ # are done. This way, parent widgets like initial-setup that don't just
+ # close the window have something to display.
+ self.done()
- if get_state() == REGISTERING:
- # aka, if this is firstboot
- if not isinstance(self.register_dialog, ga_Gtk.VBox):
- self.register_dialog.set_title(_("System Registration"))
- self.progress_label.set_markup(_("<b>Registering</b>"))
- elif get_state() == SUBSCRIBING:
- if not isinstance(self.register_dialog, ga_Gtk.VBox):
- self.register_dialog.set_title(_("Subscription Attachment"))
- self.progress_label.set_markup(_("<b>Attaching</b>"))
-
- def _set_register_label(self, screen):
- button_label = self._screens[screen].button_label
- self.register_button.set_label(button_label)
+ def done(self):
+ self.change_screen(DONE_PAGE)
- def _delete_event(self, event, data=None):
- return self.close_window()
+ def clear_screens(self):
+ for screen in self._screens:
+ screen.clear()
- def cancel(self, button):
- self.close_window()
+ def _timeout_callback(self):
+ """Callback used to drive the progress bar 'pulse'."""
+ self.register_progressbar.pulse()
+ # return true to keep it pulsing
+ return True
- # callback needs the extra arg, so just a wrapper here
- def _on_register_button_clicked(self, button):
- self.register()
- def register(self):
+class RegisterDialog(widgets.SubmanBaseWidget):
- result = self._screens[self._current_screen].apply()
+ widget_names = ['register_dialog', 'register_dialog_main_vbox',
+ 'register_details_label',
+ 'cancel_button', 'register_button', 'progress_label',
+ 'dialog_vbox6']
- if result == FINISH:
- self.finish_registration()
- return True
- elif result == DONT_CHANGE:
- return False
+ gui_file = "register_dialog"
+ __gtype_name__ = 'RegisterDialog'
- self._screens[self._current_screen].post()
+ def __init__(self, backend, facts=None, callbacks=None):
+ """
+ Callbacks will be executed when registration status changes.
+ """
+ super(RegisterDialog, self).__init__()
- self._run_pre(result)
- return False
+ # dialog
+ callbacks = {"on_register_cancel_button_clicked": self.cancel,
+ "on_register_button_clicked": self._on_register_button_clicked,
+ "hide": self.cancel,
+ "on_register_dialog_delete_event": self.cancel}
+ self.connect_signals(callbacks)
- def _run_pre(self, screen):
- # XXX move this into the button handling somehow?
- if screen == FINISH:
- self.finish_registration()
- return
+ self.reg_info = RegisterInfo()
+ # FIXME: Need better error handling in general, but it's kind of
+ # annoying to have to pass the top level widget all over the place
+ self.register_widget = RegisterWidget(backend, facts,
+ reg_info=self.reg_info,
+ parent_window=self.register_dialog)
- self._set_screen(screen)
- async = self._screens[self._current_screen].pre()
- if async:
- self._set_navigation_sensitive(False)
- self._set_screen(PROGRESS_PAGE)
- self._set_register_details_label(
- self._screens[self._current_screen].pre_message)
+ # Ensure that we start on the first page and that
+ # all widgets are cleared.
+ self.register_widget.initialize()
- def _timeout_callback(self):
- self.register_progressbar.pulse()
- # return true to keep it pulsing
- return True
+ self.register_dialog_main_vbox.pack_start(self.register_widget.register_widget,
+ True, True, 0)
- def finish_registration(self, failed=False):
- # failed is used by the firstboot subclasses to decide if they should
- # advance the screen or not.
- # XXX it would be cool here to do some async spinning while the
- # main window gui refreshes itself
+ self.register_button.connect('clicked', self._on_register_button_clicked)
+ self.cancel_button.connect('clicked', self.cancel)
- if failed:
- self.goto_error_screen()
- return
+ # initial-setup will likely handle these itself
+ self.register_widget.connect('finished', self.cancel)
+ self.register_widget.connect('register-error', self.on_register_error)
- # FIXME: subman-gui needs this but initial-setup doesnt
- self.close_window_callback()
+ # update window title on register state changes
+ self.register_widget.info.connect('notify::register-state',
+ self._on_register_state_change)
- self.emit_consumer_signal()
+ # update the 'next/register button on page change'
+ self.register_widget.connect('notify::register-button-label',
+ self._on_register_button_label_change)
- ga_GObject.source_remove(self.timer)
+ self.window = self.register_dialog
- def emit_consumer_signal(self):
- for method in self.callbacks:
- method()
+ # FIXME: needed by firstboot
+ self.password = None
- def done(self):
- self._set_screen(DONE_PAGE)
+ def initialize(self):
+ self.register_widget.clear_screens()
+ # self.register_widget.initialize()
- def close_window(self):
- if self.close_window_callback:
- self.close_window_callback()
+ def show(self):
+ # initial-setup module skips this, since it results in a
+ # new top level window that isn't reparented to the initial-setup
+ # screen.
+ self.register_dialog.show()
- def _close_window_callback(self):
- set_state(REGISTERING)
+ def cancel(self, button):
self.register_dialog.hide()
return True
- def _set_register_details_label(self, details):
- self.register_details_label.set_label("<small>%s</small>" % details)
+ def on_register_error(self, obj, msg, exc_list):
+ # TODO: we can add the register state, error type (error or exc)
+ if exc_list:
+ self.handle_register_exception(obj, msg, exc_list)
+ else:
+ self.handle_register_error(obj, msg)
+ return True
- def _clear_registration_widgets(self):
- for screen in self._screens:
- screen.clear()
+ def handle_register_error(self, obj, msg):
+ log.error("registration error: %s", msg)
+ self.error_dialog(obj, msg)
- def pre_done(self, next_screen):
- self._set_navigation_sensitive(True)
- if next_screen == DONT_CHANGE:
- self._set_screen(self._current_screen)
- else:
- self._screens[self._current_screen].post()
- self._run_pre(next_screen)
+ # RegisterWidget.do_register_error() will take care of changing screens
+
+ def handle_register_exception(self, obj, msg, exc_info):
+ # format_exception ends up logging the exception as well
+ message = format_exception(exc_info, msg)
+ self.error_dialog(obj, message)
+ def error_dialog(self, obj, msg):
+ show_error_window(msg)
-class AutobindWizard(RegisterScreen):
+ def _on_register_button_clicked(self, button):
+ self.register_widget.emit('proceed')
- def __init__(self, backend, facts, parent):
- super(AutobindWizard, self).__init__(backend, facts, parent)
+ def _on_register_state_change(self, obj, value):
+ state = obj.get_property('register-state')
+ if state == REGISTERING:
+ self.register_dialog.set_title(_("System Registration"))
+ elif state == SUBSCRIBING:
+ self.register_dialog.set_title(_("Subscription Attachment"))
- def show(self):
- super(AutobindWizard, self).show()
- self._run_pre(SELECT_SLA_PAGE)
+ def _on_register_button_label_change(self, obj, value):
+ register_label = obj.get_property('register-button-label')
+ # FIXME: button_label can be None for NonGuiScreens. Seems like
+ #
+ if register_label:
+ self.register_button.set_label(register_label)
- def _get_initial_screen(self):
- return SELECT_SLA_PAGE
+class AutobindWizardDialog(RegisterDialog):
+ __gtype_name__ = "AutobindWizard"
+
+ initial_screen = SELECT_SLA_PAGE
+
+ def __init__(self, backend, facts):
+ super(AutobindWizardDialog, self).__init__(backend, facts)
+
+ def show(self):
+ super(AutobindWizardDialog, self).show()
+ self.register_widget.change_screen(SELECT_SLA_PAGE)
+
+# TODO: Screen could be a container widget, that has the rest of the gui as
+# a child. That way, we could add the Screen class to the
+# register_notebook directly, and follow up to the parent the normal
+# way. Then we could stop passing 'parent' around. And RegisterInfo
+# could be on the parent register_notebook. I think the various GtkDialogs
+# for error handling (handle_gui_exception, etc) would also find it by
+# default.
class Screen(widgets.SubmanBaseWidget):
widget_names = ['container']
gui_file = None
-
- def __init__(self, parent, backend):
+ screen_enum = None
+
+ # TODO: replace page int with class enum
+ __gsignals__ = {'stay-on-screen': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'register-finished': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'attach-finished': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'register-error': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, (ga_GObject.TYPE_PYOBJECT,
+ ga_GObject.TYPE_PYOBJECT)),
+ 'move-to-screen': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, (int,))}
+
+ def __init__(self, reg_info, async_backend, facts, parent_window):
super(Screen, self).__init__()
self.pre_message = ""
self.button_label = _("Register")
self.needs_gui = True
self.index = -1
- self._parent = parent
- self._backend = backend
+ # REMOVE self._error_screen = self.index
+
+ self.parent_window = parent_window
+ self.info = reg_info
+ self.async = async_backend
+ self.facts = facts
+
+ def stay(self):
+ self.emit('stay-on-screen')
def pre(self):
return False
+ # do whatever the screen indicates, and emit any signals indicating where
+ # to move to next. apply() should not return anything.
def apply(self):
pass
@@ -514,19 +666,45 @@ class Screen(widgets.SubmanBaseWidget):
pass
-class NoGuiScreen(object):
+class NoGuiScreen(ga_GObject.GObject):
+ screen_enum = None
+
+ __gsignals__ = {'identity-updated': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'move-to-screen': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, (int,)),
+ 'stay-on-screen': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'register-finished': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'attach-finished': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, []),
+ 'register-error': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, (ga_GObject.TYPE_PYOBJECT,
+ ga_GObject.TYPE_PYOBJECT)),
+ 'certs-updated': (ga_GObject.SignalFlags.RUN_FIRST,
+ None, [])}
+
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ ga_GObject.GObject.__init__(self)
+
+ self.parent_window = parent_window
+ self.info = reg_info
+ self.async = async_backend
+ self.facts = facts
- def __init__(self, parent, backend):
- self._parent = parent
- self._backend = backend
self.button_label = None
self.needs_gui = False
+ self.pre_message = "Default Pre Message"
+
+ # FIXME: a do_register_error could be used for logging?
+ # Otherwise it's up to the parent dialog to do the logging.
def pre(self):
return True
def apply(self):
- return 1
+ self.emit('move-to-screen')
def post(self):
pass
@@ -536,82 +714,99 @@ class NoGuiScreen(object):
class PerformRegisterScreen(NoGuiScreen):
+ screen_enum = PERFORM_REGISTER_PAGE
- def __init__(self, parent, backend):
- super(PerformRegisterScreen, self).__init__(parent, backend)
- self.pre_message = _("Registering your system")
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(PerformRegisterScreen, self).__init__(reg_info, async_backend, facts, parent_window)
def _on_registration_finished_cb(self, new_account, error=None):
if error is not None:
- handle_gui_exception(error, REGISTER_ERROR, self._parent.parent)
- self._parent.finish_registration(failed=True)
+ self.emit('register-error',
+ REGISTER_ERROR,
+ error)
+ # TODO: register state
return
try:
managerlib.persist_consumer_cert(new_account)
- self._parent.backend.cs.force_cert_check() # Ensure there isn't much wait time
-
- if self._parent.activation_keys:
- self._parent.pre_done(REFRESH_SUBSCRIPTIONS_PAGE)
- elif self._parent.skip_auto_bind:
- self._parent.pre_done(FINISH)
- else:
- self._parent.pre_done(SELECT_SLA_PAGE)
except Exception, e:
- handle_gui_exception(e, REGISTER_ERROR, self._parent.parent)
- self._parent.finish_registration(failed=True)
+ # hint: register error, back to creds?
+ self.emit('register-error', REGISTER_ERROR, e)
+ return
+
+ # trigger a id cert reload
+ self.emit('identity-updated')
+
+ # Force all the cert dir backends to update, but mostly
+ # force the identity cert monitor to run, which will
+ # also update Backend. It also blocks until the new
+ # identity is reloaded, so we don't start the selectSLA
+ # screen before it.
+ self.async.backend.cs.force_cert_check()
+
+ # Done with the registration stuff, now on to attach
+ self.emit('register-finished')
+
+ if self.info.get_property('activation-keys'):
+ self.emit('move-to-screen', REFRESH_SUBSCRIPTIONS_PAGE)
+ return
+ elif self.info.get_property('skip-auto-bind'):
+ return
+ else:
+ self.emit('move-to-screen', SELECT_SLA_PAGE)
+ return
def pre(self):
log.info("Registering to owner: %s environment: %s" %
- (self._parent.owner_key, self._parent.environment))
+ (self.info.get_property('owner-key'),
+ self.info.get_property('environment')))
- self._parent.async.register_consumer(self._parent.consumername,
- self._parent.facts,
- self._parent.owner_key,
- self._parent.environment,
- self._parent.activation_keys,
- self._on_registration_finished_cb)
+ self.async.register_consumer(self.info.get_property('consumername'),
+ self.facts,
+ self.info.get_property('owner-key'),
+ self.info.get_property('environment'),
+ self.info.get_property('activation-keys'),
+ self._on_registration_finished_cb)
return True
class PerformSubscribeScreen(NoGuiScreen):
+ screen_enum = PERFORM_SUBSCRIBE_PAGE
- def __init__(self, parent, backend):
- super(PerformSubscribeScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(PerformSubscribeScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.pre_message = _("Attaching subscriptions")
def _on_subscribing_finished_cb(self, unused, error=None):
if error is not None:
- handle_gui_exception(error, _("Error subscribing: %s"),
- self._parent.parent)
- self._parent.finish_registration(failed=True)
+ message = _("Error subscribing: %s")
+ self.emit('register-error', message, error)
return
- self._parent.pre_done(FINISH)
- self._parent.backend.cs.force_cert_check()
+ self.emit('certs-updated')
+ self.emit('attach-finished')
def pre(self):
- self._parent.async.subscribe(self._parent.identity.uuid,
- self._parent.current_sla,
- self._parent.dry_run_result,
- self._on_subscribing_finished_cb)
+ self.info.set_property('details-label-txt', self.pre_message)
+ self.async.subscribe(self.info.identity.uuid,
+ self.info.get_property('current-sla'),
+ self.info.get_property('dry-run-result'),
+ self._on_subscribing_finished_cb)
return True
class ConfirmSubscriptionsScreen(Screen):
""" Confirm Subscriptions GUI Window """
-
+ screen_enum = CONFIRM_SUBS_PAGE
widget_names = Screen.widget_names + ['subs_treeview', 'back_button',
'sla_label']
gui_file = "confirmsubs"
- def __init__(self, parent, backend):
-
- super(ConfirmSubscriptionsScreen, self).__init__(parent,
- backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(ConfirmSubscriptionsScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.button_label = _("Attach")
self.store = ga_Gtk.ListStore(str, bool, str)
@@ -636,18 +831,22 @@ class ConfirmSubscriptionsScreen(Screen):
return column
def apply(self):
- return PERFORM_SUBSCRIBE_PAGE
+ self.emit('move-to-screen', PERFORM_SUBSCRIBE_PAGE)
def set_model(self):
- self._dry_run_result = self._parent.dry_run_result
+ dry_run_result = self.info.get_property('dry-run-result')
# Make sure that the store is cleared each time
# the data is loaded into the screen.
self.store.clear()
- self.sla_label.set_markup("<b>" + self._dry_run_result.service_level +
+
+ if not dry_run_result:
+ return
+
+ self.sla_label.set_markup("<b>" + dry_run_result.service_level +
"</b>")
- for pool_quantity in self._dry_run_result.json:
+ for pool_quantity in dry_run_result.json:
self.store.append([pool_quantity['pool']['productName'],
PoolWrapper(pool_quantity['pool']).is_virt_only(),
str(pool_quantity['quantity'])])
@@ -662,19 +861,18 @@ class SelectSLAScreen(Screen):
An wizard screen that displays the available
SLAs that are provided by the installed products.
"""
+ screen_enum = SELECT_SLA_PAGE
widget_names = Screen.widget_names + ['product_list_label',
'sla_radio_container',
'owner_treeview']
gui_file = "selectsla"
- def __init__(self, parent, backend):
- super(SelectSLAScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(SelectSLAScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.pre_message = _("Finding suitable service levels")
self.button_label = _("Next")
- self._dry_run_result = None
-
def set_model(self, unentitled_prod_certs, sla_data_map):
self.product_list_label.set_text(
self._format_prods(unentitled_prod_certs))
@@ -684,7 +882,9 @@ class SelectSLAScreen(Screen):
# of the screen.
for sla in reversed(sla_data_map.keys()):
radio = ga_Gtk.RadioButton(group=group, label=sla)
- radio.connect("toggled", self._radio_clicked, sla)
+ radio.connect("toggled",
+ self._radio_clicked,
+ (sla, sla_data_map))
self.sla_radio_container.pack_start(radio, expand=False,
fill=False, padding=0)
radio.show()
@@ -694,19 +894,19 @@ class SelectSLAScreen(Screen):
group.set_active(True)
def apply(self):
- return CONFIRM_SUBS_PAGE
-
- def post(self):
- self._parent.dry_run_result = self._dry_run_result
+ self.emit('move-to-screen', CONFIRM_SUBS_PAGE)
def clear(self):
child_widgets = self.sla_radio_container.get_children()
for child in child_widgets:
self.sla_radio_container.remove(child)
- def _radio_clicked(self, button, service_level):
+ def _radio_clicked(self, button, data):
+ sla, sla_data_map = data
+
if button.get_active():
- self._dry_run_result = self._sla_data_map[service_level]
+ self.info.set_property('dry-run-result',
+ sla_data_map[sla])
def _format_prods(self, prod_certs):
prod_str = ""
@@ -718,71 +918,89 @@ class SelectSLAScreen(Screen):
return prod_str
# so much for service level simplifying things
+ # FIXME: this could be split into 'on_get_all_service_levels_cb' and
+ # and 'on_get_service_levels_cb'
def _on_get_service_levels_cb(self, result, error=None):
- # The parent for the dialogs is set to the grandparent window
- # (which is MainWindow) because the parent window is closed
- # by finish_registration() after displaying the dialogs. See
- # BZ #855762.
if error is not None:
if isinstance(error[1], ServiceLevelNotSupportedException):
- OkDialog(_("Unable to auto-attach, server does not support service levels."),
- parent=self._parent.parent)
+ msg = _("Unable to auto-attach, server does not support service levels.")
+ self.emit('register-error', msg, None)
+ # HMM: if we make the ok a register-error as well, we may get
+ # wacky ordering if the register-error is followed immed by a
+ # register-finished?
+ self.emit('attach-finished')
+ return
elif isinstance(error[1], NoProductsException):
- InfoDialog(_("No installed products on system. No need to attach subscriptions at this time."),
- parent=self._parent.parent)
+ msg = _("No installed products on system. No need to attach subscriptions at this time.")
+ self.emit('register-error', msg, None)
+ self.emit('attach-finished')
+ return
elif isinstance(error[1], AllProductsCoveredException):
- InfoDialog(_("All installed products are covered by valid entitlements. No need to attach subscriptions at this time."),
- parent=self._parent.parent)
+ msg = _("All installed products are covered by valid entitlements. "
+ "No need to attach subscriptions at this time.")
+ self.emit('register-error', msg, None)
+ self.emit('attach-finished')
+ return
elif isinstance(error[1], GoneException):
- InfoDialog(_("Consumer has been deleted."), parent=self._parent.parent)
+ # FIXME: shoudl we log here about deleted consumer or
+ # did we do that when we created GoneException?
+ msg = _("Consumer has been deleted.")
+ self.emit('register-error', msg, None)
+ return
+ # TODO: where we should go from here?
else:
log.exception(error)
- handle_gui_exception(error, _("Error subscribing"),
- self._parent.parent)
- self._parent.finish_registration(failed=True)
- return
+ self.emit('register-error',
+ _("Error subscribing"),
+ error)
+ return
(current_sla, unentitled_products, sla_data_map) = result
- self._parent.current_sla = current_sla
+ self.info.set_property('current-sla', current_sla)
+
if len(sla_data_map) == 1:
# If system already had a service level, we can hit this point
# when we cannot fix any unentitled products:
if current_sla is not None and \
not self._can_add_more_subs(current_sla, sla_data_map):
- handle_gui_exception(None,
- _("No available subscriptions at "
- "the current service level: %s. "
- "Please use the \"All Available "
- "Subscriptions\" tab to manually "
- "attach subscriptions.") % current_sla,
- self._parent.parent)
- self._parent.finish_registration(failed=True)
+ msg = _("No available subscriptions at "
+ "the current service level: %s. "
+ "Please use the \"All Available "
+ "Subscriptions\" tab to manually "
+ "attach subscriptions.") % current_sla
+ # TODO: add 'attach' state
+ self.emit('register-error', msg, None)
+ self.emit('attach-finished')
return
- self._dry_run_result = sla_data_map.values()[0]
- self._parent.pre_done(CONFIRM_SUBS_PAGE)
+ self.info.set_property('dry-run-result',
+ sla_data_map.values()[0])
+ self.emit('move-to-screen', CONFIRM_SUBS_PAGE)
+ return
elif len(sla_data_map) > 1:
- self._sla_data_map = sla_data_map
self.set_model(unentitled_products, sla_data_map)
- self._parent.pre_done(DONT_CHANGE)
+ self.stay()
+ return
else:
log.info("No suitable service levels found.")
- handle_gui_exception(None,
- _("No service level will cover all "
- "installed products. Please manually "
- "subscribe using multiple service levels "
- "via the \"All Available Subscriptions\" "
- "tab or purchase additional subscriptions."),
- parent=self._parent.parent)
- self._parent.finish_registration(failed=True)
+ msg = _("No service level will cover all "
+ "installed products. Please manually "
+ "subscribe using multiple service levels "
+ "via the \"All Available Subscriptions\" "
+ "tab or purchase additional subscriptions.")
+ # TODO: add 'registering/attaching' state info
+ self.emit('register-error', msg, None)
+ self.emit('attach-finished')
def pre(self):
- set_state(SUBSCRIBING)
- self._parent.identity.reload()
- self._parent.async.find_service_levels(self._parent.identity.uuid,
- self._parent.facts,
- self._on_get_service_levels_cb)
+ self.info.set_property('details-label-txt', self.pre_message)
+ self.info.set_property('register-state', SUBSCRIBING)
+ self.info.identity.reload()
+
+ self.async.find_service_levels(self.info.identity.uuid,
+ self.facts,
+ self._on_get_service_levels_cb)
return True
def _can_add_more_subs(self, current_sla, sla_data_map):
@@ -800,8 +1018,8 @@ class EnvironmentScreen(Screen):
widget_names = Screen.widget_names + ['environment_treeview']
gui_file = "environment"
- def __init__(self, parent, backend):
- super(EnvironmentScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(EnvironmentScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.pre_message = _("Fetching list of possible environments")
renderer = ga_Gtk.CellRendererText()
@@ -812,35 +1030,39 @@ class EnvironmentScreen(Screen):
def _on_get_environment_list_cb(self, result_tuple, error=None):
environments = result_tuple
if error is not None:
- handle_gui_exception(error, REGISTER_ERROR, self._parent.parent)
- self._parent.finish_registration(failed=True)
+ # TODO: registering state
+ self.emit('register-error', REGISTER_ERROR, error)
return
if not environments:
- self._environment = None
- self._parent.pre_done(PERFORM_REGISTER_PAGE)
+ self.set_environment(None)
+ self.emit('move-to-screen', PERFORM_REGISTER_PAGE)
return
envs = [(env['id'], env['name']) for env in environments]
if len(envs) == 1:
- self._environment = envs[0][0]
- self._parent.pre_done(PERFORM_REGISTER_PAGE)
+ self.set_environement(envs[0][0])
+ self.emit('move-to-screen', PERFORM_REGISTER_PAGE)
+ return
+
else:
self.set_model(envs)
- self._parent.pre_done(DONT_CHANGE)
+ self.stay()
+ return
def pre(self):
- self._parent.async.get_environment_list(self._parent.owner_key,
- self._on_get_environment_list_cb)
+ self.info.set_property('details-label-txt', self.pre_message)
+ self.async.get_environment_list(self.info.get_property('owner-key'),
+ self._on_get_environment_list_cb)
return True
def apply(self):
model, tree_iter = self.environment_treeview.get_selection().get_selected()
- self._environment = model.get_value(tree_iter, 0)
- return PERFORM_REGISTER_PAGE
+ self.set_environment(model.get_value(tree_iter, 0))
+ self.emit('move-to-screen', PERFORM_REGISTER_PAGE)
- def post(self):
- self._parent.environment = self._environment
+ def set_environment(self, environment):
+ self.info.set_property('environment', environment)
def set_model(self, envs):
environment_model = ga_Gtk.ListStore(str, str)
@@ -857,8 +1079,8 @@ class OrganizationScreen(Screen):
widget_names = Screen.widget_names + ['owner_treeview']
gui_file = "organization"
- def __init__(self, parent, backend):
- super(OrganizationScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(OrganizationScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.pre_message = _("Fetching list of possible organizations")
@@ -867,13 +1089,9 @@ class OrganizationScreen(Screen):
self.owner_treeview.set_property("headers-visible", False)
self.owner_treeview.append_column(column)
- self._owner_key = None
-
def _on_get_owner_list_cb(self, owners, error=None):
if error is not None:
- handle_gui_exception(error, REGISTER_ERROR,
- self._parent.window)
- self._parent.finish_registration(failed=True)
+ self.emit('register-error', REGISTER_ERROR, error)
return
owners = [(owner['key'], owner['displayName']) for owner in owners]
@@ -881,32 +1099,35 @@ class OrganizationScreen(Screen):
owners = sorted(owners, key=lambda item: item[1])
if len(owners) == 0:
- handle_gui_exception(None,
- _("<b>User %s is not able to register with any orgs.</b>") %
- (self._parent.username),
- self._parent.parent)
- self._parent.finish_registration(failed=True)
+ msg = _("<b>User %s is not able to register with any orgs.</b>") % \
+ self.info.get_property('username')
+ self.emit('register-error', msg, None)
return
if len(owners) == 1:
- self._owner_key = owners[0][0]
- self._parent.pre_done(ENVIRONMENT_SELECT_PAGE)
+ owner_key = owners[0][0]
+ self.info.set_property('owner-key', owner_key)
+ # only one org, use it and skip the org selection screen
+ self.emit('move-to-screen', ENVIRONMENT_SELECT_PAGE)
+ return
+
else:
self.set_model(owners)
- self._parent.pre_done(DONT_CHANGE)
+ self.stay()
+ return
def pre(self):
- self._parent.async.get_owner_list(self._parent.username,
- self._on_get_owner_list_cb)
+ self.info.set_property('details-label-txt', self.pre_message)
+ self.async.get_owner_list(self.info.get_property('username'),
+ self._on_get_owner_list_cb)
return True
def apply(self):
+ # check for selection exists
model, tree_iter = self.owner_treeview.get_selection().get_selected()
- self._owner_key = model.get_value(tree_iter, 0)
- return ENVIRONMENT_SELECT_PAGE
-
- def post(self):
- self._parent.owner_key = self._owner_key
+ owner_key = model.get_value(tree_iter, 0)
+ self.info.set_property('owner-key', owner_key)
+ self.emit('move-to-screen', ENVIRONMENT_SELECT_PAGE)
def set_model(self, owners):
owner_model = ga_Gtk.ListStore(str, str)
@@ -927,11 +1148,10 @@ class CredentialsScreen(Screen):
gui_file = "credentials"
- def __init__(self, parent, backend):
- super(CredentialsScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(CredentialsScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self._initialize_consumer_name()
-
self.registration_tip_label.set_label("<small>%s</small>" %
get_branding().GUI_FORGOT_LOGIN_TIP)
@@ -944,7 +1164,11 @@ class CredentialsScreen(Screen):
def _validate_consumername(self, consumername):
if not consumername:
- show_error_window(_("You must enter a system name."), self._parent.window)
+ # TODO: register state to signal
+ self.emit('register-error',
+ _("You must enter a system name."),
+ None)
+
self.consumer_name.grab_focus()
return False
return True
@@ -952,42 +1176,46 @@ class CredentialsScreen(Screen):
def _validate_account(self):
# validate / check user name
if self.account_login.get_text().strip() == "":
- show_error_window(_("You must enter a login."), self._parent.window)
+ self.emit('register-error',
+ _("You must enter a login."),
+ None)
+
self.account_login.grab_focus()
return False
if self.account_password.get_text().strip() == "":
- show_error_window(_("You must enter a password."), self._parent.window)
+ self.emit('register-error',
+ _("You must enter a password."),
+ None)
+
self.account_password.grab_focus()
return False
return True
def pre(self):
+ self.info.set_property('details-label-txt', self.pre_message)
self.account_login.grab_focus()
return False
def apply(self):
- self._username = self.account_login.get_text().strip()
- self._password = self.account_password.get_text().strip()
- self._consumername = self.consumer_name.get_text()
- self._skip_auto_bind = self.skip_auto_bind.get_active()
+ self.stay()
+ username = self.account_login.get_text().strip()
+ password = self.account_password.get_text().strip()
+ consumername = self.consumer_name.get_text()
+ skip_auto_bind = self.skip_auto_bind.get_active()
- if not self._validate_consumername(self._consumername):
- return DONT_CHANGE
+ if not self._validate_consumername(consumername):
+ return
if not self._validate_account():
- return DONT_CHANGE
+ return
- self._backend.cp_provider.set_user_pass(self._username, self._password)
+ self.info.set_property('username', username)
+ self.info.set_property('password', password)
+ self.info.set_property('skip-auto-bind', skip_auto_bind)
+ self.info.set_property('consumername', consumername)
- return OWNER_SELECT_PAGE
-
- def post(self):
- self._parent.username = self._username
- self._parent.password = self._password
- self._parent.consumername = self._consumername
- self._parent.skip_auto_bind = self._skip_auto_bind
- self._parent.activation_keys = None
+ self.emit('move-to-screen', OWNER_SELECT_PAGE)
def clear(self):
self.account_login.set_text("")
@@ -1005,8 +1233,8 @@ class ActivationKeyScreen(Screen):
]
gui_file = "activation_key"
- def __init__(self, parent, backend):
- super(ActivationKeyScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(ActivationKeyScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self._initialize_consumer_name()
def _initialize_consumer_name(self):
@@ -1014,21 +1242,26 @@ class ActivationKeyScreen(Screen):
self.consumer_entry.set_text(socket.gethostname())
def apply(self):
- self._activation_keys = self._split_activation_keys(
+ self.stay()
+ activation_keys = self._split_activation_keys(
self.activation_key_entry.get_text().strip())
- self._owner_key = self.organization_entry.get_text().strip()
- self._consumername = self.consumer_entry.get_text().strip()
+ owner_key = self.organization_entry.get_text().strip()
+ consumername = self.consumer_entry.get_text().strip()
+
+ if not self._validate_owner_key(owner_key):
+ return
- if not self._validate_owner_key(self._owner_key):
- return DONT_CHANGE
+ if not self._validate_activation_keys(activation_keys):
+ return
- if not self._validate_activation_keys(self._activation_keys):
- return DONT_CHANGE
+ if not self._validate_consumername(consumername):
+ return
- if not self._validate_consumername(self._consumername):
- return DONT_CHANGE
+ self.info.set_property('consumername', consumername)
+ self.info.set_property('owner-key', owner_key)
+ self.info.set_property('activation-keys', activation_keys)
- return PERFORM_REGISTER_PAGE
+ self.emit('move-to-screen', PERFORM_REGISTER_PAGE)
def _split_activation_keys(self, entry):
keys = re.split(',\s*|\s+', entry)
@@ -1036,56 +1269,59 @@ class ActivationKeyScreen(Screen):
def _validate_owner_key(self, owner_key):
if not owner_key:
- show_error_window(_("You must enter an organization."), self._parent.window)
+ self.emit('register-error',
+ _("You must enter an organization."),
+ None)
+
self.organization_entry.grab_focus()
return False
return True
def _validate_activation_keys(self, activation_keys):
if not activation_keys:
- show_error_window(_("You must enter an activation key."), self._parent.window)
+ self.emit('register-error',
+ _("You must enter an activation key."),
+ None)
+
self.activation_key_entry.grab_focus()
return False
return True
def _validate_consumername(self, consumername):
if not consumername:
- show_error_window(_("You must enter a system name."), self._parent.window)
+ self.emit('register-error',
+ _("You must enter a system name."),
+ None)
+
self.consumer_entry.grab_focus()
return False
return True
def pre(self):
+ self.info.set_property('details-label-txt', self.pre_message)
self.organization_entry.grab_focus()
return False
- def post(self):
- self._parent.activation_keys = self._activation_keys
- self._parent.owner_key = self._owner_key
- self._parent.consumername = self._consumername
- # Environments aren't used with activation keys so clear any
- # cached value.
- self._parent.environment = None
- self._backend.cp_provider.set_user_pass()
-
class RefreshSubscriptionsScreen(NoGuiScreen):
- def __init__(self, parent, backend):
- super(RefreshSubscriptionsScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(RefreshSubscriptionsScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.pre_message = _("Attaching subscriptions")
def _on_refresh_cb(self, error=None):
if error is not None:
- handle_gui_exception(error, _("Error subscribing: %s"),
- self._parent.parent)
- self._parent.finish_registration(failed=True)
+ self.emit('register-error',
+ _("Error subscribing: %s"),
+ error)
+ # TODO: register state
return
- self._parent.pre_done(FINISH)
+ self.emit('attach-finished')
def pre(self):
- self._parent.async.refresh(self._on_refresh_cb)
+ self.info.set_property('details-label-txt', self.pre_message)
+ self.async.refresh(self._on_refresh_cb)
return True
@@ -1095,16 +1331,14 @@ class ChooseServerScreen(Screen):
'activation_key_checkbox']
gui_file = "choose_server"
- def __init__(self, parent, backend):
-
- super(ChooseServerScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(ChooseServerScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.button_label = _("Next")
callbacks = {
"on_default_button_clicked": self._on_default_button_clicked,
"on_proxy_button_clicked": self._on_proxy_button_clicked,
- "on_server_entry_changed": self._on_server_entry_changed,
}
self.connect_signals(callbacks)
@@ -1121,29 +1355,8 @@ class ChooseServerScreen(Screen):
# bump the resolver as well.
self.reset_resolver()
- self.network_config_dialog.set_parent_window(self._parent.window)
self.network_config_dialog.show()
- def _on_server_entry_changed(self, widget):
- """
- Disable the activation key checkbox if the user is registering
- to hosted.
- """
- server = self.server_entry.get_text()
- try:
- (hostname, port, prefix) = parse_server_info(server)
- if re.search('subscription\.rhn\.(.*\.)*redhat\.com', hostname):
- sensitive = False
- self.activation_key_checkbox.set_active(False)
- else:
- sensitive = True
- self.activation_key_checkbox.set_sensitive(sensitive)
- except ServerUrlParseError:
- # This may seem like it should be False, but we don't want
- # the checkbox blinking on and off as the user types a value
- # that is first unparseable and then later parseable.
- self.activation_key_checkbox.set_sensitive(True)
-
def reset_resolver(self):
try:
reset_resolver()
@@ -1151,7 +1364,11 @@ class ChooseServerScreen(Screen):
log.warn("Error from reset_resolver: %s", e)
def apply(self):
+ self.stay()
server = self.server_entry.get_text()
+
+ # TODO: test the values before saving, then update
+ # self.info and cfg if it works
try:
(hostname, port, prefix) = parse_server_info(server)
CFG.set('server', 'hostname', hostname)
@@ -1162,27 +1379,38 @@ class ChooseServerScreen(Screen):
try:
if not is_valid_server_info(hostname, port, prefix):
- show_error_window(_("Unable to reach the server at %s:%s%s") %
- (hostname, port, prefix),
- self._parent.window)
- return self._parent.error_screen
+ self.emit('register-error',
+ _("Unable to reach the server at %s:%s%s") %
+ (hostname, port, prefix),
+ None)
+ return
except MissingCaCertException:
- show_error_window(_("CA certificate for subscription service has not been installed."),
- self._parent.window)
- return self._parent.error_screen
+ self.emit('register-error',
+ _("CA certificate for subscription service has not been installed."),
+ None)
+ return
except ServerUrlParseError:
- show_error_window(_("Please provide a hostname with optional port and/or prefix: hostname[:port][/prefix]"),
- self._parent.window)
- return self._parent.error_screen
+ self.emit('register-error',
+ _("Please provide a hostname with optional port and/or prefix: "
+ "hostname[:port][/prefix]"),
+ None)
+ return
log.debug("Writing server data to rhsm.conf")
CFG.save()
- self._backend.update()
+
+ self.info.set_property('hostname', hostname)
+ self.info.set_property('port', port)
+ self.info.set_property('prefix', prefix)
+
if self.activation_key_checkbox.get_active():
- return ACTIVATION_KEY_PAGE
+ self.emit('move-to-screen', ACTIVATION_KEY_PAGE)
+ return
+
else:
- return CREDENTIALS_PAGE
+ self.emit('move-to-screen', CREDENTIALS_PAGE)
+ return
def clear(self):
# Load the current server values from rhsm.conf:
@@ -1205,6 +1433,28 @@ class AsyncBackend(object):
self.plugin_manager = require(PLUGIN_MANAGER)
self.queue = Queue.Queue()
+ def update(self):
+ self.backend.update()
+
+ def set_user_pass(self, username, password):
+ self.backend.cp_provider.set_user_pass(username, password)
+ self.backend.update()
+
+ def _watch_thread(self):
+ """
+ glib idle method to watch for thread completion.
+ runs the provided callback method in the main thread.
+ """
+ try:
+ (callback, retval, error) = self.queue.get(block=False)
+ if error:
+ callback(retval, error=error)
+ else:
+ callback(retval)
+ return False
+ except Queue.Empty:
+ return True
+
def _get_owner_list(self, username, callback):
"""
method run in the worker thread.
@@ -1243,14 +1493,20 @@ class AsyncBackend(object):
try:
installed_mgr = require(INSTALLED_PRODUCTS_MANAGER)
+ # TODO: not sure why we pass in a facts.Facts, and call it's
+ # get_facts() three times. The two bracketing plugin calls
+ # are meant to be able to enhance/tweak facts
self.plugin_manager.run("pre_register_consumer", name=name,
- facts=facts.get_facts())
- retval = self.backend.cp_provider.get_basic_auth_cp().registerConsumer(name=name,
- facts=facts.get_facts(), owner=owner, environment=env,
- keys=activation_keys,
- installed_products=installed_mgr.format_for_server())
+ facts=facts.get_facts())
+
+ cp = self.backend.cp_provider.get_basic_auth_cp()
+ retval = cp.registerConsumer(name=name, facts=facts.get_facts(),
+ owner=owner, environment=env,
+ keys=activation_keys,
+ installed_products=installed_mgr.format_for_server())
+
self.plugin_manager.run("post_register_consumer", consumer=retval,
- facts=facts.get_facts())
+ facts=facts.get_facts())
require(IDENTITY).reload()
# Facts and installed products went out with the registration
@@ -1288,6 +1544,7 @@ class AsyncBackend(object):
try:
if not current_sla:
log.debug("Saving selected service level for this system.")
+
self.backend.cp_provider.get_consumer_auth_cp().updateConsumer(uuid,
service_level=dry_run_result.service_level)
@@ -1301,10 +1558,12 @@ class AsyncBackend(object):
pool_id=pool_id, quantity=quantity)
ents = self.backend.cp_provider.get_consumer_auth_cp().bindByEntitlementPool(uuid, pool_id, quantity)
self.plugin_manager.run("post_subscribe", consumer_uuid=uuid, entitlement_data=ents)
+ # FIXME: this should be a different asyncBackend task
managerlib.fetch_certificates(self.backend.certlib)
except Exception:
# Going to try to update certificates just in case we errored out
# mid-way through a bunch of binds:
+ # FIXME: emit update-ent-certs signal
try:
managerlib.fetch_certificates(self.backend.certlib)
except Exception, cert_update_ex:
@@ -1316,6 +1575,16 @@ class AsyncBackend(object):
# This guy is really ugly to run in a thread, can we run it
# in the main thread with just the network stuff threaded?
+
+ # get_consumer
+ # get_service_level_list
+ # update_consumer
+ # action_client
+ # update_installed_products
+ # update_facts
+ # update_other_action_client_stuff
+ # for sla in available_slas:
+ # get_dry_run_bind for sla
def _find_suitable_service_levels(self, consumer_uuid, facts):
# FIXME:
@@ -1356,7 +1625,14 @@ class AsyncBackend(object):
action_client.update()
for sla in available_slas:
+
+ # TODO: what kind of madness would happen if we did a couple of
+ # these in parallel in seperate threads?
dry_run_json = self.backend.cp_provider.get_consumer_auth_cp().dryRunBind(consumer_uuid, sla)
+
+ # FIXME: are we modifying cert_sorter (self.backend.cs) state here?
+ # FIXME: it's only to get the unentitled products list, can pass
+ # that in
dry_run = DryRunResult(sla, dry_run_json, self.backend.cs)
# If we have a current SLA for this system, we do not need
@@ -1364,6 +1640,8 @@ class AsyncBackend(object):
# this wizard:
if current_sla or dry_run.covers_required_products():
suitable_slas[sla] = dry_run
+
+ # why do we call cert_sorter stuff in the return?
return (current_sla, self.backend.cs.unentitled_products.values(), suitable_slas)
def _find_service_levels(self, consumer_uuid, facts, callback):
@@ -1383,21 +1661,6 @@ class AsyncBackend(object):
except Exception:
self.queue.put((callback, None, sys.exc_info()))
- def _watch_thread(self):
- """
- glib idle method to watch for thread completion.
- runs the provided callback method in the main thread.
- """
- try:
- (callback, retval, error) = self.queue.get(block=False)
- if error:
- callback(retval, error=error)
- else:
- callback(retval)
- return False
- except Queue.Empty:
- return True
-
def get_owner_list(self, username, callback):
ga_GObject.idle_add(self._watch_thread)
threading.Thread(target=self._get_owner_list,
@@ -1440,11 +1703,12 @@ class AsyncBackend(object):
args=(callback,)).start()
+# TODO: make this a more informative 'summary' page.
class DoneScreen(Screen):
gui_file = "done_box"
- def __init__(self, parent, backend):
- super(DoneScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(DoneScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.pre_message = "We are done."
@@ -1463,32 +1727,30 @@ class InfoScreen(Screen):
]
gui_file = "registration_info"
- def __init__(self, parent, backend):
- super(InfoScreen, self).__init__(parent, backend)
+ def __init__(self, reg_info, async_backend, facts, parent_window):
+ super(InfoScreen, self).__init__(reg_info, async_backend, facts, parent_window)
self.button_label = _("Next")
- callbacks = {
- "on_why_register_button_clicked":
- self._on_why_register_button_clicked,
- "on_back_to_reg_button_clicked":
- self._on_back_to_reg_button_clicked
- }
+ callbacks = {"on_why_register_button_clicked":
+ self._on_why_register_button_clicked,
+ "on_back_to_reg_button_clicked":
+ self._on_back_to_reg_button_clicked
+ }
- # FIXME: self.conntect_signals to wrap self.gui.connect_signals
self.connect_signals(callbacks)
def pre(self):
return False
def apply(self):
+ self.stay()
if self.register_radio.get_active():
log.debug("Proceeding with registration.")
- return CHOOSE_SERVER_PAGE
+ self.emit('move-to-screen', CHOOSE_SERVER_PAGE)
+ return
+
else:
log.debug("Skipping registration.")
- return FINISH
-
- def post(self):
- pass
+ self.emit('move-to-screen', FINISH)
def _on_why_register_button_clicked(self, button):
self.why_register_dialog.show()
diff --git a/src/subscription_manager/gui/utils.py b/src/subscription_manager/gui/utils.py
index 6c77ff7..9b8a52e 100644
--- a/src/subscription_manager/gui/utils.py
+++ b/src/subscription_manager/gui/utils.py
@@ -103,6 +103,52 @@ def handle_gui_exception(e, msg, parent, format_msg=True, log_msg=None):
show_error_window(msg, parent=parent)
+def format_mapped_message(e, msg, mapped_message, format_msg=True):
+ message = None
+ if isinstance(e, connection.RestlibException):
+ # If this exception's code is in the 200 range (such as 202 ACCEPTED)
+ # we're going to ignore the message we were given and just display
+ # the message from the server as an info dialog. (not an error)
+ if 200 < int(e.code) < 300:
+ message = linkify(mapped_message)
+ else:
+ try:
+ if format_msg:
+ message = msg % linkify(mapped_message)
+ else:
+ message = linkify(mapped_message)
+ except Exception:
+ message = msg
+ return message
+
+
+def format_interpolated_message(e, msg, mapped_message, format_msg=True):
+ message = None
+ #catch-all, try to interpolate and if it doesn't work out, just display the message
+ try:
+ interpolated_str = msg % e
+ message = interpolated_str
+ except Exception:
+ message = msg
+ return message
+
+
+def format_exception(e, msg, format_msg=True, log_msg=None):
+ if isinstance(e, tuple):
+ log.error(log_msg, exc_info=e)
+ # Get the class instance of the exception
+ e = e[1]
+ message = None
+ exception_mapper = ExceptionMapper()
+ mapped_message = exception_mapper.get_message(e)
+ if mapped_message:
+ message = format_mapped_message(e, msg, mapped_message, format_msg=format_msg)
+ else:
+ message = format_interpolated_message(e, msg, mapped_message, format_msg=format_msg)
+
+ return message
+
+
def show_error_window(message, parent=None):
messageWindow.ErrorDialog(messageWindow.wrap_text(message),
parent)
diff --git a/src/subscription_manager/gui/widgets.py b/src/subscription_manager/gui/widgets.py
index 57d400d..c1615a2 100644
--- a/src/subscription_manager/gui/widgets.py
+++ b/src/subscription_manager/gui/widgets.py
@@ -96,7 +96,7 @@ class BuilderFileBasedWidget(FileBasedGui):
builder_based_widget = cls()
builder_based_widget.gui_file = builder_file
- #print "ga", ga.GTK_BUILDER_FILES_DIR
+ builder_based_widget.builder.set_translation_domain('rhsm')
builder_based_widget.gui_file_suffix = ga_gtk_compat.GTK_BUILDER_FILES_SUFFIX
builder_based_widget.file_dir = ga_gtk_compat.GTK_BUILDER_FILES_DIR
@@ -126,11 +126,12 @@ class BuilderFileBasedWidget(FileBasedGui):
# FIXME: not actually a widget, just an object that has a widget
-class SubmanBaseWidget(object):
+class SubmanBaseWidget(ga_GObject.GObject):
widget_names = []
gui_file = None
def __init__(self):
+ ga_GObject.GObject.__init__(self)
self.gui = self._gui_factory()
self.pull_widgets(self.gui, self.widget_names)
self.log = logging.getLogger('rhsm-app.' + __name__ +
diff --git a/src/subscription_manager/managercli.py b/src/subscription_manager/managercli.py
index 1b50b67..3933c30 100644
--- a/src/subscription_manager/managercli.py
+++ b/src/subscription_manager/managercli.py
@@ -305,7 +305,7 @@ class CliCommand(AbstractCLICommand):
self.parser.add_option("--serverurl", dest="server_url",
default=None, help=_("server URL in the form of https://hostname:port/prefix"))
self.parser.add_option("--insecure", action="store_true",
- default=False, help=_("do not check the server SSL certificate against available certificate authorities"))
+ default=False, help=_("do not check the entitlement server SSL certificate against available certificate authorities"))
def _add_proxy_options(self):
""" Add proxy options that apply to sub-commands that require network connections. """
@@ -534,8 +534,6 @@ class UserPassCommand(CliCommand):
@property
def username(self):
if not self._username:
- print _("Registering to: %s:%s%s") % \
- (cfg.get("server", "hostname"), cfg.get("server", "port"), cfg.get("server", "prefix"))
(self._username, self._password) = self._get_username_and_password(
self.options.username, self.options.password)
return self._username
@@ -1041,6 +1039,8 @@ class RegisterCommand(UserPassCommand):
# Proceed with new registration:
try:
if not self.options.activation_keys:
+ print _("Registering to: %s:%s%s") % \
+ (cfg.get("server", "hostname"), cfg.get("server", "port"), cfg.get("server", "prefix"))
self.cp_provider.set_user_pass(self.username, self.password)
admin_cp = self.cp_provider.get_basic_auth_cp()
else:
diff --git a/subscription-manager.spec b/subscription-manager.spec
index 1d4b9a4..e6d4b1d 100644
--- a/subscription-manager.spec
+++ b/subscription-manager.spec
@@ -49,7 +49,7 @@
Name: subscription-manager
Version: 1.15.9
-Release: 7%{?dist}
+Release: 8%{?dist}
Summary: Tools and libraries for subscription and repository management
Group: System Environment/Base
License: GPLv2
@@ -542,6 +542,13 @@ fi
%endif
%changelog
+* Wed Sep 02 2015 Chris Rog <crog@redhat.com> 1.15.9-8
+- 884288: Better registergui for initial-setup (alikins@redhat.com)
+- Fix 'make gladelint' errors in repositories.glade (alikins@redhat.com)
+- 1254349: Move registering to message (vrjain@redhat.com)
+- 1257460: Set text domain on Gtk.Builder widgets (alikins@redhat.com)
+- 1207247: Insecure parameter needs more explanation (wpoteat@redhat.com)
+
* Wed Aug 19 2015 Chris Rog <crog@redhat.com> 1.15.9-7
- search-disabled-repos: ignore failed temporarily enabled repos
(vmukhame@redhat.com)
diff --git a/test/stubs.py b/test/stubs.py
index 5704cca..36c8888 100644
--- a/test/stubs.py
+++ b/test/stubs.py
@@ -468,15 +468,9 @@ class StubBackend(object):
self.overrides = None
self.certlib = None
- def monitor_certs(self, callback):
+ def on_cert_check_timer(self):
pass
- def monitor_identity(self, callback):
- pass
-
- def create_admin_uep(self, username, password):
- return StubUEP(username, password)
-
def update(self):
pass
diff --git a/test/test_managergui.py b/test/test_managergui.py
index af78f9e..150a2f0 100644
--- a/test/test_managergui.py
+++ b/test/test_managergui.py
@@ -12,9 +12,6 @@ from subscription_manager.injection import provide, \
class TestManagerGuiMainWindow(SubManFixture):
def test_main_window(self):
- managergui.Backend = stubs.StubBackend
- managergui.Facts = stubs.StubFacts()
-
provide(PROD_DIR, stubs.StubProductDirectory([]))
provide(PRODUCT_DATE_RANGE_CALCULATOR, mock.Mock())
@@ -25,8 +22,11 @@ class TestManagerGuiMainWindow(SubManFixture):
class TestRegisterScreen(unittest.TestCase):
def test_register_screen(self):
- registergui.RegisterScreen(stubs.StubBackend())
+ registergui.RegisterDialog(stubs.StubBackend())
def test_register_screen_register(self):
- rs = registergui.RegisterScreen(stubs.StubBackend())
- rs.register()
+ rd = registergui.RegisterDialog(stubs.StubBackend())
+ #rs.initialize()
+ rd.show()
+ rd.register_dialog.hide()
+ #rs.cancel()
diff --git a/test/test_migration.py b/test/test_migration.py
index 7286b3e..019b2f9 100644
--- a/test/test_migration.py
+++ b/test/test_migration.py
@@ -26,8 +26,14 @@ from fixture import Capture, SubManFixture, temp_file
from optparse import OptionParser
from textwrap import dedent
+from nose import SkipTest
+
from subscription_manager import injection as inj
-from subscription_manager.migrate import migrate
+try:
+ from subscription_manager.migrate import migrate
+except ImportError:
+ raise SkipTest("Couldn't import rhn modules for migration tests")
+
from subscription_manager.certdirectory import ProductDirectory
diff --git a/test/test_registrationgui.py b/test/test_registrationgui.py
index 9610c33..9374325 100644
--- a/test/test_registrationgui.py
+++ b/test/test_registrationgui.py
@@ -4,14 +4,17 @@ from mock import Mock
from fixture import SubManFixture
from stubs import StubBackend, StubFacts
-from subscription_manager.gui.registergui import RegisterScreen, \
- CredentialsScreen, ActivationKeyScreen, ChooseServerScreen, \
- CREDENTIALS_PAGE, CHOOSE_SERVER_PAGE
+from subscription_manager.gui.registergui import RegisterWidget, \
+ CredentialsScreen, ActivationKeyScreen, ChooseServerScreen, \
+ CREDENTIALS_PAGE, CHOOSE_SERVER_PAGE
+from subscription_manager.ga import GObject as ga_GObject
+from subscription_manager.ga import Gtk as ga_Gtk
-class RegisterScreenTests(SubManFixture):
+
+class RegisterWidgetTests(SubManFixture):
def setUp(self):
- super(RegisterScreenTests, self).setUp()
+ super(RegisterWidgetTests, self).setUp()
self.backend = StubBackend()
expected_facts = {'fact1': 'one',
'fact2': 'two',
@@ -19,7 +22,7 @@ class RegisterScreenTests(SubManFixture):
'system.uuid': 'MOCKUUID'}
self.facts = StubFacts(fact_dict=expected_facts)
- self.rs = RegisterScreen(self.backend, self.facts)
+ self.rs = RegisterWidget(self.backend, self.facts)
self.rs._screens[CHOOSE_SERVER_PAGE] = Mock()
self.rs._screens[CHOOSE_SERVER_PAGE].index = 0
@@ -29,29 +32,77 @@ class RegisterScreenTests(SubManFixture):
def test_show(self):
self.rs.initialize()
- self.rs.show()
- def test_show_registration_returns_to_choose_server_screen(self):
- self.rs.initialize()
- self.rs.show()
- self.rs.register()
- self.assertEquals(CREDENTIALS_PAGE,
- self.rs.register_notebook.get_current_page() - 1)
- self.rs.cancel(self.rs.cancel_button)
+ # FIXME: unit tests for gtk is a weird universe
+ def test_registration_error_returns_to_page(self):
self.rs.initialize()
- self.rs.show()
- self.assertEquals(CHOOSE_SERVER_PAGE,
- self.rs.register_notebook.get_current_page())
+
+ self.correct_page = None
+
+ def error_handler(obj, msg, exc_info):
+ page_after = self.rs.register_notebook.get_current_page()
+
+ # NOTE: these exceptions are not in the nost test context,
+ # so they don't actually fail nose
+ self.assertEquals(page_after, 0)
+ self.correct_page = True
+ self.quit()
+
+ def emit_proceed():
+ self.rs.emit('proceed')
+ return False
+
+ def emit_error():
+ self.rs.emit('register-error', 'Some register error', None)
+ return False
+
+ self.rs.connect('register-error', error_handler)
+
+ ga_GObject.timeout_add(250, self.quit)
+ ga_GObject.idle_add(emit_proceed)
+ ga_GObject.idle_add(emit_error)
+
+ # run till quit or timeout
+ # if we get to the state we want we can call quit
+ ga_Gtk.main()
+
+ # verify class scope self.correct_page got set correct in error handler
+ self.assertTrue(self.correct_page)
+
+ def quit(self):
+ ga_Gtk.main_quit()
+
+
+def mock_parent():
+ parent = Mock()
+ backend = StubBackend()
+ parent.backend = backend
+ parent.async = Mock()
+
+
+class StubReg(object):
+ def __init__(self):
+ self.parent_window = Mock()
+ self.backend = StubBackend()
+ self.async = Mock()
+ self.reg_info = Mock()
+ self.expected_facts = {'fact1': 'one',
+ 'fact2': 'two',
+ 'system': '',
+ 'system.uuid': 'MOCKUUID'}
+ self.facts = StubFacts(fact_dict=self.expected_facts)
class CredentialsScreenTests(SubManFixture):
def setUp(self):
super(CredentialsScreenTests, self).setUp()
- self.backend = StubBackend()
- self.parent = Mock()
- self.screen = CredentialsScreen(self.backend, self.parent)
+ stub_reg = StubReg()
+ self.screen = CredentialsScreen(reg_info=stub_reg.reg_info,
+ async_backend=stub_reg.async,
+ facts=stub_reg.facts,
+ parent_window=stub_reg.parent_window)
def test_clear_credentials_dialog(self):
# Pull initial value here since it will be different per machine.
@@ -71,9 +122,11 @@ class CredentialsScreenTests(SubManFixture):
class ActivationKeyScreenTests(SubManFixture):
def setUp(self):
super(ActivationKeyScreenTests, self).setUp()
- self.backend = StubBackend()
- self.parent = Mock()
- self.screen = ActivationKeyScreen(self.backend, self.parent)
+ stub_reg = StubReg()
+ self.screen = ActivationKeyScreen(reg_info=stub_reg.reg_info,
+ async_backend=stub_reg.async,
+ facts=stub_reg.facts,
+ parent_window=stub_reg.parent_window)
def test_split_activation_keys(self):
expected = ['hello', 'world', 'how', 'are', 'you']
@@ -85,21 +138,23 @@ class ActivationKeyScreenTests(SubManFixture):
class ChooseServerScreenTests(SubManFixture):
def setUp(self):
super(ChooseServerScreenTests, self).setUp()
- self.backend = StubBackend()
- self.parent = Mock()
- self.screen = ChooseServerScreen(self.backend, self.parent)
+ stub_reg = StubReg()
+ self.screen = ChooseServerScreen(reg_info=stub_reg.reg_info,
+ async_backend=stub_reg.async,
+ facts=stub_reg.facts,
+ parent_window=stub_reg.parent_window)
def test_activation_key_checkbox_sensitive(self):
self.screen.server_entry.set_text("foo.bar:443/baz")
self.assertTrue(self.screen.activation_key_checkbox.get_property('sensitive'))
- def test_activation_key_checkbox_insensitive(self):
+ def test_activation_key_checkbox_prod_sensitive(self):
self.screen.server_entry.set_text("subscription.rhn.redhat.com:443/baz")
- self.assertFalse(self.screen.activation_key_checkbox.get_property('sensitive'))
+ self.assertTrue(self.screen.activation_key_checkbox.get_property('sensitive'))
def test_activation_key_checkbox_inactive_when_insensitive(self):
self.screen.server_entry.set_text("foo.bar:443/baz")
self.screen.activation_key_checkbox.set_active(True)
self.screen.server_entry.set_text("subscription.rhn.redhat.com:443/baz")
- self.assertFalse(self.screen.activation_key_checkbox.get_property('sensitive'))
- self.assertFalse(self.screen.activation_key_checkbox.get_property('active'))
+ self.assertTrue(self.screen.activation_key_checkbox.get_property('sensitive'))
+ self.assertTrue(self.screen.activation_key_checkbox.get_property('active'))