diff --git a/bin/subscription-manager-gui b/bin/subscription-manager-gui index a7c2ca2..e6bf56e 100755 --- a/bin/subscription-manager-gui +++ b/bin/subscription-manager-gui @@ -108,10 +108,10 @@ if _LIBPATH not in sys.path: from subscription_manager import ga_loader ga_loader.init_ga() -from subscription_manager.ga import GObject as ga_GObject from subscription_manager.ga import Gtk as ga_Gtk +from subscription_manager.ga import gtk_compat -ga_GObject.threads_init() +gtk_compat.threads_init() # quick check to see if you are a super-user. if os.getuid() != 0: diff --git a/rel-eng/packages/subscription-manager b/rel-eng/packages/subscription-manager index 8181efc..c569df4 100644 --- a/rel-eng/packages/subscription-manager +++ b/rel-eng/packages/subscription-manager @@ -1 +1 @@ -1.15.9-2 ./ +1.15.9-3 ./ diff --git a/src/daemons/rhsm_d.py b/src/daemons/rhsm_d.py index 2a5b57c..2ca9125 100755 --- a/src/daemons/rhsm_d.py +++ b/src/daemons/rhsm_d.py @@ -66,7 +66,6 @@ def excepthook_logging(exc_type, exc_value, exc_traceback): sys.excepthook = excepthook_logging from subscription_manager.ga import GObject as ga_GObject -from subscription_manager.ga import GLib as ga_GLib from subscription_manager.injectioninit import init_dep_injection init_dep_injection() @@ -157,7 +156,7 @@ class StatusChecker(dbus.service.Object): #certain parts of that are async def watchdog(self): if not self.keep_alive: - ga_GLib.idle_add(check_if_ran_once, self, self.loop) + ga_GObject.idle_add(check_if_ran_once, self, self.loop) @dbus.service.method( dbus_interface="com.redhat.SubscriptionManager.EntitlementStatus", diff --git a/src/subscription_manager/async.py b/src/subscription_manager/async.py index c86a873..05433f9 100644 --- a/src/subscription_manager/async.py +++ b/src/subscription_manager/async.py @@ -111,3 +111,76 @@ class AsyncBind(object): def unbind(self, serial, selection, callback, except_callback): threading.Thread(target=self._run_unbind, args=(serial, selection, callback, except_callback)).start() + + +class AsyncRepoOverridesUpdate(object): + + def __init__(self, overrides_api): + self.overrides_api = overrides_api + self.identity = require(IDENTITY) + + def _load_data(self, success_callback, except_callback): + try: + # pull the latest overrides from the cache which will be the ones from the server. + current_overrides = self.overrides_api.get_overrides(self.identity.uuid) or [] + + # Fetch the repositories from repolib without any overrides applied. + # We do this so that we can tell if anything has been modified by + # overrides. + current_repos = self.overrides_api.repo_lib.get_repos(apply_overrides=False) + + self._process_callback(success_callback, current_overrides, current_repos) + except Exception, e: + self._process_callback(except_callback, e) + + def _update(self, to_add, to_remove, success_callback, except_callback): + ''' + Processes the override mapping and sends the overrides to the server for addition/removal. + ''' + try: + # TODO: At some point we should look into providing a single API call that can handle + # additions and removals in the same call (currently not supported by server). + current_overrides = None + if len(to_add) > 0: + current_overrides = self.overrides_api.add_overrides(self.identity.uuid, to_add) + + if len(to_remove) > 0: + current_overrides = self.overrides_api.remove_overrides(self.identity.uuid, to_remove) + + if current_overrides: + self.overrides_api.update(current_overrides) + + # Fetch the repositories from repolib without any overrides applied. + # We do this so that we can tell if anything has been modified by + # overrides. + current_repos = self.overrides_api.repo_lib.get_repos(apply_overrides=False) + + self._process_callback(success_callback, current_overrides, current_repos) + except Exception, e: + self._process_callback(except_callback, e) + + def _remove_all(self, repo_ids, success_callback, except_callback): + try: + current_overrides = self.overrides_api.remove_all_overrides(self.identity.uuid, repo_ids) + self.overrides_api.update(current_overrides) + + # Fetch the repositories from repolib without any overrides applied. + # We do this so that we can tell if anything has been modified by + # overrides. + current_repos = self.overrides_api.repo_lib.get_repos(apply_overrides=False) + + self._process_callback(success_callback, current_overrides, current_repos) + except Exception, e: + self._process_callback(except_callback, e) + + def _process_callback(self, callback, *args): + ga_GObject.idle_add(callback, *args) + + def load_data(self, success_callback, failure_callback): + threading.Thread(target=self._load_data, args=(success_callback, failure_callback)).start() + + def update_overrides(self, to_add, to_remove, success_callback, except_callback): + threading.Thread(target=self._update, args=(to_add, to_remove, success_callback, except_callback)).start() + + def remove_all_overrides(self, repo_ids, success_callback, except_callback): + threading.Thread(target=self._remove_all, args=(repo_ids, success_callback, except_callback)).start() diff --git a/src/subscription_manager/ga_impls/ga_gtk2/GObject.py b/src/subscription_manager/ga_impls/ga_gtk2/GObject.py index dee1c34..3783ce7 100644 --- a/src/subscription_manager/ga_impls/ga_gtk2/GObject.py +++ b/src/subscription_manager/ga_impls/ga_gtk2/GObject.py @@ -1,6 +1,4 @@ -# To get gtk.gdk.threads_init -import gtk # objects from gobject import GObject @@ -14,11 +12,6 @@ from gobject import markup_escape_text from gobject import SIGNAL_RUN_LAST from gobject import TYPE_BOOLEAN, TYPE_PYOBJECT, PARAM_READWRITE -# These are not exact replacements, but for our purposes they -# are used in the same places in the same way. A purely GObject -# app with no gui may want to distinquish. -threads_init = gtk.gdk.threads_init - class SignalFlags(object): RUN_LAST = SIGNAL_RUN_LAST @@ -26,7 +19,7 @@ class SignalFlags(object): constants = [TYPE_BOOLEAN, TYPE_PYOBJECT, PARAM_READWRITE] methods = [add_emission_hook, idle_add, markup_escape_text, - source_remove, threads_init, timeout_add] + 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 7ec7a01..d009019 100644 --- a/src/subscription_manager/ga_impls/ga_gtk2/Gtk.py +++ b/src/subscription_manager/ga_impls/ga_gtk2/Gtk.py @@ -9,8 +9,9 @@ from gtk import CellRendererProgress, CellRendererSpin, CellRendererText from gtk import CellRendererToggle, Entry from gtk import FileChooserDialog, FileFilter, Frame, HBox, HButtonBox, Image from gtk import Label, ListStore, MessageDialog, RadioButton, SpinButton -from gtk import TextBuffer, TreeRowReference +from gtk import TextBuffer from gtk import TreeStore, TreeView, TreeViewColumn, VBox, Viewport +from gtk import Window # enums from gtk import BUTTONBOX_END @@ -112,13 +113,6 @@ class GaImage(Image): Image = GaImage -# Gtk2's TreeRowReference is a class, while Gtk3's TreeRowReference is -# non-callable class that has to be constructed with it's .new() method. -# Provide a helper method that provides a compatible interface. snake_case -# naming used to distinquish it from the "real" TreeRowReference. -def tree_row_reference(model, path): - return TreeRowReference(model, path) - # Attempt to keep the list of faux Gtk 3 names we are # providing to a min. constants = [STOCK_APPLY, STOCK_CANCEL, STOCK_REMOVE, STOCK_YES] @@ -133,7 +127,7 @@ widgets = [AboutDialog, Adjustment, Builder, Button, Calendar, CellRendererPixbu Entry, FileChooserDialog, FileFilter, Frame, HBox, HButtonBox, Image, Label, ListStore, MessageDialog, RadioButton, SpinButton, TextBuffer, TreeStore, TreeView, TreeViewColumn, - VBox, Viewport] + VBox, Viewport, Window] methods = [check_version, main, main_quit] diff --git a/src/subscription_manager/ga_impls/ga_gtk2/__init__.py b/src/subscription_manager/ga_impls/ga_gtk2/__init__.py index 00c3418..e810ef1 100644 --- a/src/subscription_manager/ga_impls/ga_gtk2/__init__.py +++ b/src/subscription_manager/ga_impls/ga_gtk2/__init__.py @@ -1,7 +1,5 @@ import os -# so ga.gtk_compat.tree_row_reference finds it -from Gtk import tree_row_reference # ../../gui/data/glade/ ourfile = __file__ @@ -9,6 +7,7 @@ GTK_BUILDER_FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "../../gui/data/glade/")) GTK_BUILDER_FILES_SUFFIX = "glade" +GTK_COMPAT_VERSION = "2" + __all__ = [GTK_BUILDER_FILES_DIR, - GTK_BUILDER_FILES_SUFFIX, - tree_row_reference] + GTK_BUILDER_FILES_SUFFIX] diff --git a/src/subscription_manager/ga_impls/ga_gtk2/gtk_compat.py b/src/subscription_manager/ga_impls/ga_gtk2/gtk_compat.py new file mode 100644 index 0000000..113a2a1 --- /dev/null +++ b/src/subscription_manager/ga_impls/ga_gtk2/gtk_compat.py @@ -0,0 +1,30 @@ + +import os + +from gtk import TreeRowReference +from gtk.gdk import threads_init + + +# Gtk2's TreeRowReference is a class, while Gtk3's TreeRowReference is +# non-callable class that has to be constructed with it's .new() method. +# Provide a helper method that provides a compatible interface. snake_case +# naming used to distinquish it from the "real" TreeRowReference. +def tree_row_reference(model, path): + return TreeRowReference(model, path) + + +# These are not exact replacements, but for our purposes they +# are used in the same places in the same way. A purely GObject +# app with no gui may want to distinquish. +threads_init = threads_init + +# ../../gui/data/glade/ +ourfile = __file__ +GTK_BUILDER_FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), + "../../gui/data/glade/")) +GTK_BUILDER_FILES_SUFFIX = "glade" + +GTK_COMPAT_VERSION = "2" + +__all__ = [GTK_BUILDER_FILES_DIR, + GTK_BUILDER_FILES_SUFFIX] diff --git a/src/subscription_manager/ga_impls/ga_gtk3.py b/src/subscription_manager/ga_impls/ga_gtk3.py index f378067..1588d6c 100644 --- a/src/subscription_manager/ga_impls/ga_gtk3.py +++ b/src/subscription_manager/ga_impls/ga_gtk3.py @@ -1,6 +1,7 @@ import os from gi.repository import Gtk +from gi.repository import GObject # ../../gui/data/glade/ ourfile = __file__ @@ -8,8 +9,12 @@ GTK_BUILDER_FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "../gui/data/ui/")) GTK_BUILDER_FILES_SUFFIX = "ui" +GTK_COMPAT_VERSION = "3" + # gtk3 requires constructing with .new(), where # gtk2 does not have a .new() def tree_row_reference(model, path): return Gtk.TreeRowReference.new(model, path) + +threads_init = GObject.threads_init diff --git a/src/subscription_manager/ga_loader.py b/src/subscription_manager/ga_loader.py index 8a3c38e..59a00f6 100644 --- a/src/subscription_manager/ga_loader.py +++ b/src/subscription_manager/ga_loader.py @@ -179,8 +179,8 @@ class GaImporterGtk3(GaImporter): class GaImporterGtk2(GaImporter): virtual_modules = {'subscription_manager.ga': None, - 'subscription_manager.ga.gtk_compat': ['subscription_manager.ga_impls', - 'ga_gtk2'], + 'subscription_manager.ga.gtk_compat': ['subscription_manager.ga_impls.ga_gtk2', + 'gtk_compat'], 'subscription_manager.ga.GObject': ['subscription_manager.ga_impls.ga_gtk2', 'GObject'], 'subscription_manager.ga.Gdk': ['subscription_manager.ga_impls.ga_gtk2', diff --git a/src/subscription_manager/gui/data/glade/repositories.glade b/src/subscription_manager/gui/data/glade/repositories.glade index 30868b9..e45fc29 100644 --- a/src/subscription_manager/gui/data/glade/repositories.glade +++ b/src/subscription_manager/gui/data/glade/repositories.glade @@ -1,105 +1,55 @@ - + - - Manage the repositories your subscriptions grant you access to by enabling, disabling and overriding certain fields. - - + False 5 Manage Repositories True center-on-parent - 600 - 400 + 800 + 600 True subscription-manager dialog False - - + + + manage_repositories_dialog + + + True False 2 - - + + True False - edge - - - Remove All Overrides - True - True - True - 0.45 - - - - - remove_all_overrides_button - - - - - False - False - 0 - - - - - Close - True - True - True - - - - - close_button - - - - - False - False - 1 - - + 0 + 0 + 10 + Manage the repositories your subscriptions grant you access to by enabling, disabling and overriding certain fields. + True + word-char + + + False False - end 0 - + True False - - True - False - True - False - word - textbuffer1 - - - False - True - 6 - 0 - - - True True @@ -109,7 +59,7 @@ True True - 1 + 0 @@ -117,184 +67,144 @@ True False - + True False 0 - 3 + 0 + 6 <b>Repository Details</b> True False - False + True 0 - - 96 + True False - 0 - none + 3 + 2 + + + True + False + 0 + 0 + <b>Name:</b> + True + + + GTK_FILL + GTK_FILL + 4 + 4 + + + + + True + False + 0 + 0 + <b>Base URL:</b> + True + + + 1 + 2 + GTK_FILL + GTK_FILL + 4 + 4 + + - + True False + 0 + 0 + <b>Other Overrides:</b> + True + + + 2 + 3 + GTK_FILL + GTK_FILL + 4 + 4 + + + + + True + False + 0 + 0 + True + word-char + True + + + 1 + 2 + + + + + True + False + 0 + 0 + True + word-char + True + + + 1 + 2 + 1 + 2 + + + + + 120 + True + True + automatic + automatic - + True True - automatic - automatic - in - - - True - False - queue - 0 0 1 0.10000000000000001 0.90000000000000002 1 - none - - - True - False - 2 - 3 - 3 - - - True - False - 0 - <b>Name:</b> - True - - - GTK_FILL - GTK_FILL - 4 - 4 - - - - - True - False - True - 5 - False - 10 - False - - - - Subscription Text - - - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 0 - <b>Base URL:</b> - True - - - 1 - 2 - GTK_FILL - GTK_FILL - 4 - 4 - - - - - True - False - True - 5 - False - none - 10 - False - - - - SKU Text - - - - - 1 - 2 - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 0 - 0 - <b>Other Overrides:</b> - True - - - 2 - 3 - GTK_FILL - GTK_FILL - 4 - 4 - - - - - True - True - True - False - 0 - False - - - - Other Overrides Table - - - - - 1 - 2 - 2 - 3 - - - - + True + False + 0 + False + + + Other Overrides Table + + 1 + 2 + 2 + 3 + - True + False True 1 @@ -302,8 +212,8 @@ False - False - 2 + True + 1 @@ -313,12 +223,81 @@ 1 + + + True + False + end + + + Remove All Overrides + True + True + True + 0.44999998807907104 + + + remove_all_overrides_button + + + + + + False + False + end + 0 + + + + + Apply + True + True + True + + + + False + False + end + 1 + + + + + Close + True + True + True + + + close_button + + + + + + False + False + end + 2 + + + + + False + True + end + 2 + + - - - manage_repositories_dialog - - + + close_button + apply_button + reset_button + diff --git a/src/subscription_manager/gui/data/ui/activation_key.ui b/src/subscription_manager/gui/data/ui/activation_key.ui index 47af425..ad96278 100644 --- a/src/subscription_manager/gui/data/ui/activation_key.ui +++ b/src/subscription_manager/gui/data/ui/activation_key.ui @@ -10,10 +10,11 @@ True False - 0 - 0.10000000149011612 + 8 <b>Please enter the following for this system:</b> True + 0 + 0.10000000149011612 False @@ -22,22 +23,21 @@ - + True False - 3 - 2 + 4 True False Organization: + end + 0 - GTK_FILL - GTK_FILL - 15 - 15 + 0 + 0 @@ -45,14 +45,11 @@ True False Activation Key: + 0 + 0 1 - 2 - GTK_FILL - GTK_FILL - 15 - 15 @@ -60,14 +57,11 @@ True False System Name: + 0 + 0 2 - 3 - GTK_FILL - GTK_FILL - 15 - 15 @@ -75,6 +69,8 @@ True True This must be the organization key, not the name. + 8 + True @@ -84,7 +80,7 @@ 1 - 2 + 0 @@ -92,6 +88,8 @@ True True Multiple Activation Keys can be entered by separating them with a comma or a space. + 8 + True @@ -101,15 +99,15 @@ 1 - 2 1 - 2 True True + 8 + True @@ -119,16 +117,13 @@ 1 - 2 2 - 3 False - False - 5 + True 1 diff --git a/src/subscription_manager/gui/data/ui/contract_selection.ui b/src/subscription_manager/gui/data/ui/contract_selection.ui index cab5140..75ce373 100644 --- a/src/subscription_manager/gui/data/ui/contract_selection.ui +++ b/src/subscription_manager/gui/data/ui/contract_selection.ui @@ -1,33 +1,38 @@ - + + - - + + False Contract Selection True center-on-parent 580 True + subscription-manager dialog - subscription-manager - vertical True + False + True 4 + vertical 3 - vertical True + False 6 + vertical 3 True - 0 + False <b>Choose the specific contract to use:</b> True + 0 False @@ -37,153 +42,169 @@ - horizontal True + False False + True 1 - + True - 16 + False + 16 + True + vertical + 3 - - vertical + True - 3 + False + 4 - + True - 2 - 2 - 5 - 3 - - - True - 1 - 0 - <b>Subscription:</b> - True - - - GTK_FILL - GTK_FILL - 10 - - - - - True - 1 - <b>Total Contracts:</b> - True - - - 1 - 2 - GTK_FILL - GTK_FILL - 10 - 4 - - - - - True - 0 - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - 0 - - - 1 - 2 - 1 - 2 - - + False + <b>Subscription:</b> + True + 1 + 0 - False - 0 + 0 + 0 - - horizontal + True - - - True - 1 - 1 - * Click to Change Quantity - True - - - 0 - - + False + <b>Total Contracts:</b> + True + True + word-char + 1 + + + 0 + 1 + + + + + True + False + 16 + True + True + word-char + 0 - 1 + 1 + 0 - + + True + False + 16 + True + 0 + + + 1 + 1 + + + + + False + True + 0 + + + + + True + False + + + True + False + * Click to Change Quantity + True + 1 + 1 + + + False + True + end + 0 + + + + + False + True + 1 + + + + + True + True + True + True + etched-in + + + 450 + 200 True True - automatic - automatic - etched-in - - - 450 - 200 - True - True - True - - - SLA Selection Table - - + True + True + + + + + + SLA Selection Table - - 2 - + + True + True + 2 + + False + True 2 + False + True 0 - horizontal True + False 6 5 end @@ -194,7 +215,7 @@ False False True - + False @@ -208,7 +229,7 @@ True True False - + False @@ -219,6 +240,8 @@ False + True + end 1 diff --git a/src/subscription_manager/gui/data/ui/done_box.ui b/src/subscription_manager/gui/data/ui/done_box.ui index eb5f679..6fdf405 100644 --- a/src/subscription_manager/gui/data/ui/done_box.ui +++ b/src/subscription_manager/gui/data/ui/done_box.ui @@ -10,10 +10,13 @@ True False - Done! + Registration with Red Hat Subscription Management is Done! + + + - False + True True 0 diff --git a/src/subscription_manager/gui/data/ui/factsdialog.ui b/src/subscription_manager/gui/data/ui/factsdialog.ui index 886a026..c1a2f3a 100644 --- a/src/subscription_manager/gui/data/ui/factsdialog.ui +++ b/src/subscription_manager/gui/data/ui/factsdialog.ui @@ -1,7 +1,7 @@ + - - + 500 400 @@ -14,39 +14,42 @@ - vertical True False + vertical 2 - vertical True False + vertical - + True False - 3 - 2 True False - 0 10 System Identity: + 0 + + + - GTK_FILL + 0 + 0 True False - 0 + True True + 0 System Identity Value @@ -55,29 +58,33 @@ 1 - 2 + 0 True False - 0 10 Organization: + 0 + + + + 0 1 - 2 - GTK_FILL True False - 0 + True True + end + 0 Organization Value @@ -86,31 +93,32 @@ 1 - 2 1 - 2 True False - 0 10 Environment: + 0 + + + + 0 2 - 3 - GTK_FILL True False - 0 + True True + 0 Environment @@ -119,29 +127,24 @@ 1 - 2 2 - 3 False - False + True 0 - horizontal True False True True - automatic - automatic etched-in @@ -149,6 +152,9 @@ True True True + + + facts_view @@ -184,21 +190,24 @@ - horizontal True False + vertical - vertical True False + 8 True False - 0 10 Last Update: + 0 + + + False @@ -210,8 +219,8 @@ True False - 0 10 + 0 Update Time @@ -226,48 +235,49 @@ - True + False True 0 - horizontal True False - - Update Facts + + Close True True True - + + + + close_button + + False False 3 + end 0 - - Close + + Update Facts True True True - - - close_button - - - + False False 3 + end 1 @@ -283,7 +293,6 @@ False True - 12 1 diff --git a/src/subscription_manager/gui/data/ui/filters.ui b/src/subscription_manager/gui/data/ui/filters.ui index 0a7989a..a6529e8 100644 --- a/src/subscription_manager/gui/data/ui/filters.ui +++ b/src/subscription_manager/gui/data/ui/filters.ui @@ -5,7 +5,7 @@ Filter Options subscription-manager - menu + dialog diff --git a/src/subscription_manager/gui/data/ui/installed.ui b/src/subscription_manager/gui/data/ui/installed.ui index 28d0104..a38737c 100644 --- a/src/subscription_manager/gui/data/ui/installed.ui +++ b/src/subscription_manager/gui/data/ui/installed.ui @@ -2,6 +2,23 @@ + + + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + False subscription-manager @@ -191,8 +208,8 @@ True True - 0 0 396 39.600000000000001 356.40000000000003 396 - 37 0 116 7.9000000000000004 71.100000000000009 79 + scrolled_window_3_h_adjustment + scrolled_window_3_v_adjustment automatic automatic in diff --git a/src/subscription_manager/gui/data/ui/networkConfig.ui b/src/subscription_manager/gui/data/ui/networkConfig.ui index f50531a..d88b97a 100644 --- a/src/subscription_manager/gui/data/ui/networkConfig.ui +++ b/src/subscription_manager/gui/data/ui/networkConfig.ui @@ -1,30 +1,104 @@ - + + - - + + False Proxy Configuration True center-on-parent True + subscription-manager dialog - subscription-manager - vertical True + False + vertical + + + True + False + end + + + _Test Connection + True + True + True + True + + + Test Connection Button + + + + + False + False + 1 + + + + + _Cancel + True + True + True + True + + + Cancel Button + + + + + False + False + 2 + + + + + _Save + True + True + False + True + + + Save Button + + + + + False + False + 2 + + + + + False + False + end + 0 + + - vertical True + False 10 + vertical 10 True - 0 + False <b>HTTP Proxy</b> True + 0 False @@ -33,317 +107,246 @@ - + True - 20 + False + vertical + 10 - - vertical + + I would like to connect via an _HTTP proxy. True - 10 + True + False + True + 0 + True + + + Proxy Checkbox + + + + + False + True + 0 + + + + + True + False + 24 + 8 - - I would like to connect via an _HTTP proxy. + True - True - False + False + _Proxy Location: True - True + proxyEntry + 0 + + + 0 + 0 + + + + + True + False + True + Enter in the format hostname(:port) + True - - Proxy Checkbox + + Proxy Location Text - False - 0 + 1 + 0 - + True - 22 + False + 5 + + + True + False + gtk-info + + + False + True + 0 + + - + True - 2 - 2 - 6 - 6 - - - horizontal - True - 5 - - - True - gtk-info - - - False - 0 - - - - - True - 0 - <small><b>Example:</b> proxy.example.com:3128</small> - True - - - 1 - - - - - 1 - 2 - 1 - 2 - - - - - True - 0 - _Proxy Location: - True - proxyEntry - - - GTK_FILL - GTK_FILL - - - - - True - False - True - Enter in the format hostname(:port) - - - Proxy Location Text - - - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - + False + <small><b>Example:</b> proxy.example.com:3128</small> + True + 0 + + False + True + 1 + - 1 + 1 + 1 - - Use Au_thentication with HTTP Proxy: + + + + + False + True + 1 + + + + + Use Au_thentication with HTTP Proxy: + True + True + False + True + 0 + True + + + Authentication Checkbox + + + + + False + True + 2 + + + + + True + False + 24 + 8 + + True - True - False + False + False + Proxy _Username: + True + proxyUserEntry + 0 + + + 0 + 0 + + + + + True + False + Proxy P_assword: True - True + proxyPasswordEntry + 0 + + + 0 + 1 + + + + + True + False + True + 8 + True - - Authentication Checkbox + + Username Text - False - 2 + 1 + 0 - + True - 22 - - - True - 2 - 2 - 6 - 6 - - - True - False - 0 - Proxy _Username: - True - proxyUserEntry - - - GTK_FILL - GTK_FILL - - - - - True - 0 - Proxy P_assword: - True - proxyPasswordEntry - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - True - - - Username Text - - - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - True - False - - - - Password Text - - - - - 1 - 2 - 1 - 2 - GTK_FILL - - + True + 8 + True + False + + + + Password Text - 3 + 1 + 1 + + False + True + 3 + False + True 1 + False + True 1 True + False + 8 - + connectionStatusLabel - 3 - - - - - horizontal - True - end - - - _Cancel - True - True - True - True - - - Cancel Button - - - - - False - False - 2 - - - - - _Save - True - True - False - True - - - Save Button - - - - - False - False - 2 - - - - - _Test Connection - True - True - True - True - - - Test Connection Button - - - - - False - False - 1 - - - - False - end - 0 + True + 3 diff --git a/src/subscription_manager/gui/data/ui/organization.ui b/src/subscription_manager/gui/data/ui/organization.ui index 2ece2a7..06dd501 100644 --- a/src/subscription_manager/gui/data/ui/organization.ui +++ b/src/subscription_manager/gui/data/ui/organization.ui @@ -5,7 +5,7 @@ True False - start + True 25 vertical 7 @@ -13,9 +13,9 @@ True False - 0 <b>Organization Selection</b> True + 0 org_selection_label @@ -38,8 +38,8 @@ True True - start True + True diff --git a/src/subscription_manager/gui/data/ui/registration.ui b/src/subscription_manager/gui/data/ui/registration.ui index 7c7bcf5..31baac9 100644 --- a/src/subscription_manager/gui/data/ui/registration.ui +++ b/src/subscription_manager/gui/data/ui/registration.ui @@ -18,13 +18,15 @@ True False + baseline + start vertical 2 - horizontal True False + start end @@ -79,7 +81,6 @@ False False - end 0 @@ -87,22 +88,23 @@ True True + start False False - vertical True False 25 + vertical 7 True False - 0 <b>Registering</b> True + 0 progress_label @@ -128,7 +130,7 @@ False - True + False 1 @@ -136,8 +138,8 @@ True False - 0 True + 0 register_details_label @@ -146,11 +148,14 @@ False - True + False 2 + + False + @@ -164,13 +169,13 @@ - True - True + False + False 1 - + register_dialog_main_vbox diff --git a/src/subscription_manager/gui/data/ui/repositories.ui b/src/subscription_manager/gui/data/ui/repositories.ui index cf624ed..5e39274 100644 --- a/src/subscription_manager/gui/data/ui/repositories.ui +++ b/src/subscription_manager/gui/data/ui/repositories.ui @@ -1,45 +1,44 @@ - + + - - Manage the repositories your subscriptions grant you access to by enabling, disabling and overriding certain fields. - - - + False 5 Manage Repositories True center-on-parent - 600 - 400 + 800 + 600 True subscription-manager dialog False - + - vertical True False + vertical 2 - horizontal True False - edge + end + 12 + True + end Remove All Overrides True True True - 0.45 - + 0.44999998807907104 + - + remove_all_overrides_button @@ -51,14 +50,35 @@ + + Apply + True + True + True + + + + apply_button + + + + + False + False + 8 + end + 1 + + + Close True True True - + - + close_button @@ -66,44 +86,50 @@ False False - 1 + end + 2 False - False + True end 0 - - vertical + + main_content_container True False + True + vertical - + True - False - True - False - word - textbuffer1 + False + 12 + Manage the repositories your subscriptions grant you access to by enabling, disabling and overriding certain fields. + True + 0 + + + False True - 6 0 + -1 True True - automatic - automatic + True + True True @@ -113,185 +139,153 @@ - vertical True False + vertical True False - 0 + 6 3 <b>Repository Details</b> True + start + 0 False - False + True 0 - - 96 + True False - 0 - none + end + False - + True False + <b>Name:</b> + True + 0 + 0 + + + 0 + 0 + + + + + True + False + <b>Base URL:</b> + True + 0 + 0 + + + 0 + 1 + + + + + True + False + <b>Other Overrides:</b> + True + 0 + 0 + + + 0 + 2 + + + + + 116 + True + True + 6 + 3 + 3 + in - + + 80 True True - automatic - automatic - in - - - True - False - queue - 0 0 1 0.10000000000000001 0.90000000000000002 1 - none - - - True - False - 2 - 3 - 3 - - - True - False - 0 - <b>Name:</b> - True - - - GTK_FILL - GTK_FILL - 4 - 4 - - - - - True - False - True - 5 - False - 10 - False - - - Subscription Text - - - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 0 - <b>Base URL:</b> - True - - - 1 - 2 - GTK_FILL - GTK_FILL - 4 - 4 - - - - - True - False - True - 5 - False - none - 10 - False - - - SKU Text - - - - - 1 - 2 - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 0 - 0 - <b>Other Overrides:</b> - True - - - 2 - 3 - GTK_FILL - GTK_FILL - 4 - 4 - - - - - True - True - True - False - 0 - False - - - Other Overrides Table - - - - - 1 - 2 - 2 - 3 - - - - + 3 + 3 + True + False + True + False + 0 + False + + + + + + Other Overrides Table + + 1 + 2 + + + + + True + False + 6 + 3 + 3 + True + True + word-char + True + 0 + 0 + + + 1 + 0 + + + + + True + False + 6 + 3 + 3 + True + True + word-char + True + 0 + 0 + + + 1 + 1 + - True + False True 1 @@ -299,8 +293,8 @@ False - False - 2 + True + 3 @@ -313,9 +307,12 @@ - + manage_repositories_dialog + + Manage the repositories your subscriptions grant you access to by enabling, disabling and overriding certain fields. + diff --git a/src/subscription_manager/gui/data/ui/subdetails.ui b/src/subscription_manager/gui/data/ui/subdetails.ui index 96ecd56..25a949e 100644 --- a/src/subscription_manager/gui/data/ui/subdetails.ui +++ b/src/subscription_manager/gui/data/ui/subdetails.ui @@ -2,6 +2,14 @@ + + 0 + 0 + 0 + 0 + 0 + 0 + False subscription-manager @@ -47,7 +55,7 @@ True False queue - 0 0 206 20.600000000000001 185.40000000000001 206 + viewport_2_v_adjustment none diff --git a/src/subscription_manager/gui/managergui.py b/src/subscription_manager/gui/managergui.py index 6b641d1..67e9b36 100644 --- a/src/subscription_manager/gui/managergui.py +++ b/src/subscription_manager/gui/managergui.py @@ -429,6 +429,7 @@ class MainWindow(widgets.SubmanBaseWidget): autobind_wizard = registergui.AutobindWizard(self.backend, self.facts, self._get_window()) + autobind_wizard.initialize() autobind_wizard.show() def _redeem_item_clicked(self, widget): diff --git a/src/subscription_manager/gui/preferences.py b/src/subscription_manager/gui/preferences.py index 55f6ede..7ebf2db 100644 --- a/src/subscription_manager/gui/preferences.py +++ b/src/subscription_manager/gui/preferences.py @@ -63,6 +63,13 @@ class PreferencesDialog(widgets.SubmanBaseWidget): self.release_combobox.set_model(self.release_model) self.sla_combobox.set_model(self.sla_model) + cell_renderer = ga_Gtk.CellRendererText() + self.release_combobox.pack_start(cell_renderer, True) + self.release_combobox.add_attribute(cell_renderer, "text", 0) + + self.sla_combobox.pack_start(cell_renderer, True) + self.sla_combobox.add_attribute(cell_renderer, "text", 0) + self.close_button.connect("clicked", self._close_button_clicked) self.sla_combobox.connect("changed", self._sla_changed) self.release_combobox.connect("changed", self._release_changed) diff --git a/src/subscription_manager/gui/progress.py b/src/subscription_manager/gui/progress.py index ddc8f7d..61b2b2d 100644 --- a/src/subscription_manager/gui/progress.py +++ b/src/subscription_manager/gui/progress.py @@ -24,7 +24,7 @@ class Progress(widgets.SubmanBaseWidget): widget_names = ['progressWindow', 'progressLabel', 'progressBar', 'statusLabel'] gui_file = "progress" - def __init__(self, title, label): + def __init__(self, title, label, support_markup=False): super(Progress, self).__init__() self.progressWindow.connect("delete-event", self._on_delete_event) @@ -34,7 +34,7 @@ class Progress(widgets.SubmanBaseWidget): self.lastProgress = 0.0 self.set_title(title) - self.set_label(label) + self.set_label(label, support_markup) def hide(self): self.progressWindow.hide() @@ -43,8 +43,11 @@ class Progress(widgets.SubmanBaseWidget): def set_title(self, text): self.progressWindow.set_title(text) - def set_label(self, text): - self.progressLabel.set_text(text) + def set_label(self, text, markup=False): + if markup: + self.progressLabel.set_markup(text) + else: + self.progressLabel.set_text(text) def pulse(self): """ diff --git a/src/subscription_manager/gui/registergui.py b/src/subscription_manager/gui/registergui.py index c422e89..c56ec5b 100644 --- a/src/subscription_manager/gui/registergui.py +++ b/src/subscription_manager/gui/registergui.py @@ -469,6 +469,9 @@ class AutobindWizard(RegisterScreen): super(AutobindWizard, self).show() self._run_pre(SELECT_SLA_PAGE) + def _get_initial_screen(self): + return SELECT_SLA_PAGE + class Screen(widgets.SubmanBaseWidget): widget_names = ['container'] diff --git a/src/subscription_manager/gui/reposgui.py b/src/subscription_manager/gui/reposgui.py index 6ddfccc..2b6a391 100644 --- a/src/subscription_manager/gui/reposgui.py +++ b/src/subscription_manager/gui/reposgui.py @@ -17,12 +17,16 @@ import gettext import logging from subscription_manager.ga import Gtk as ga_Gtk +from subscription_manager.ga import gtk_compat +from subscription_manager.ga import GObject as ga_GObject from subscription_manager.ga import GdkPixbuf as ga_GdkPixbuf import rhsm.config from subscription_manager.gui.utils import handle_gui_exception from subscription_manager.gui import widgets +from subscription_manager.gui import progress +from subscription_manager.async import AsyncRepoOverridesUpdate from subscription_manager.injection import IDENTITY, ENT_DIR, require from subscription_manager.gui.storage import MappedListStore from subscription_manager.gui.widgets import TextTreeViewColumn, CheckBoxColumn,\ @@ -41,9 +45,10 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): """ GTK dialog for managing repositories and their overrides. """ - widget_names = ['main_window', 'reset_button', 'close_button', + widget_names = ['main_window', 'reset_button', 'close_button', 'apply_button', 'name_text', 'baseurl_text', 'scrolledwindow', - 'other_overrides_view'] + 'other_overrides_view', 'details_vbox', 'main_content_container', + 'description_text'] gui_file = "repositories" ENTS_PROVIDE_NO_REPOS = _("Attached subscriptions do not provide any repositories.") @@ -53,6 +58,21 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): def __init__(self, backend, parent): super(RepositoriesDialog, self).__init__() + # Label wrapping on resize does not work very well on GTK2+ + # so we resize on the fly. + if gtk_compat.GTK_COMPAT_VERSION == "2": + # 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. + self.description_text.set_line_wrap(True) + self.description_text.connect('size-allocate', lambda label, size: label.set_size_request(size.width - 1, -1)) + + self.name_text.set_line_wrap(True) + self.name_text.connect('size-allocate', lambda label, size: label.set_size_request(size.width - 1, -1)) + + self.baseurl_text.set_line_wrap(True) + self.baseurl_text.connect('size-allocate', lambda label, size: label.set_size_request(size.width - 1, -1)) + # Set up dynamic elements self.overrides_treeview = ga_Gtk.TreeView() # Add at-spi because we no longer create this widget from glade @@ -67,11 +87,13 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): # FIXME: We really shouldn't have to worry about our connection info # changing out from under us. self.backend = backend + self.async_update = AsyncRepoOverridesUpdate(self.backend.overrides) self.identity = require(IDENTITY) self.ent_dir = require(ENT_DIR) self.connect_signals({"on_dialog_delete_event": self._on_close, "on_close_button_clicked": self._on_close, + "on_apply_button_clicked": self._on_apply_request, "on_reset_button_clicked": self._on_reset_repo}) self.overrides_store = MappedListStore({ @@ -127,6 +149,11 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): self.overrides_treeview.get_selection().connect('changed', self._on_selection) self.overrides_treeview.set_rules_hint(True) + # Progress bar + self.pb = None + self.timer = 0 + + self.parent = parent self.main_window.set_transient_for(parent) def hide(self): @@ -134,16 +161,25 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): def show(self): self._load_data() - self.main_window.present() def _load_data(self): - # pull the latest overrides from the cache which will be the ones from the server. - current_overrides = self.backend.overrides.get_overrides(self.identity.uuid) or [] - self._refresh(current_overrides) - # By default sort by repo_id + self._show_progress_bar(_("Loading Repository Data"), _("Retrieving repository data from server."), self.parent) + self.async_update.load_data(self._on_async_load_data_success, self._on_async_load_data_failure) + + def _on_async_load_data_success(self, current_overrides, current_repos): self.overrides_store.set_sort_column_id(0, ga_Gtk.SortType.ASCENDING) + self._refresh(current_overrides, current_repos) + self._clear_progress_bar() + self.main_window.present() + # By default sort by repo_id - def _refresh(self, current_overrides, repo_id_to_select=None): + def _on_async_load_data_failure(self, e): + self._clear_progress_bar() + handle_gui_exception(e, _("Unable to load repository data."), + self._get_dialog_widget()) + + def _refresh(self, current_overrides, current_repos, repo_id_to_select=None): + # Current overrides from server overrides_per_repo = {} for override in current_overrides: @@ -151,12 +187,17 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): overrides_per_repo.setdefault(repo_id, {}) overrides_per_repo[repo_id][override.name] = override.value + self.apply_button.set_sensitive(False) + self.overrides_store.clear() self.other_overrides.clear() + self.main_content_container.remove(self.details_vbox) - current_repos = self.backend.overrides.repo_lib.get_repos(apply_overrides=False) + # Switch the dialog view depending on content availability if (current_repos): self.widget_switcher.set_active(1) + self.main_content_container.add(self.details_vbox) + #self.details_vbox.set_visible(True) else: ent_count = len(self.ent_dir.list_valid()) no_repos_message = self.ENTS_PROVIDE_NO_REPOS @@ -168,29 +209,16 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): no_repos_message = self.REPOS_DISABLED_BY_CFG self.no_repos_label.set_markup("%s" % no_repos_message) + +# self.details_vbox.set_visible(False) self.widget_switcher.set_active(0) - # Fetch the repositories from repolib without any overrides applied. - # We do this so that we can tell if anything has been modified by - # overrides. + self.main_content_container.show_all() + + # Update the table model from our gathered override/repo data for repo in current_repos: overrides = overrides_per_repo.get(repo.id, None) - modified = not overrides is None - enabled = self._get_boolean(self._get_model_value(repo, overrides, 'enabled')[0]) - gpgcheck, gpgcheck_modified = self._get_model_value(repo, overrides, 'gpgcheck') - gpgcheck = self._get_boolean(gpgcheck) - self.overrides_store.add_map({ - 'enabled': bool(int(enabled)), - 'repo_id': repo.id, - 'modified': modified, - 'modified-icon': self._get_modified_icon(modified), - 'name': repo['name'], - 'baseurl': repo['baseurl'], - 'gpgcheck': gpgcheck, - 'gpgcheck_modified': gpgcheck_modified, - 'repo_data': repo, - 'override_data': overrides - }) + self.overrides_store.add_map(self._build_table_row_data(repo, overrides)) first_row_iter = self.overrides_store.get_iter_first() if not first_row_iter: @@ -200,6 +228,37 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): else: self.overrides_treeview.get_selection().select_iter(first_row_iter) + def _build_table_row_data(self, repo_data, repo_overrides): + modified = not repo_overrides is None + enabled = self._get_boolean(self._get_model_value(repo_data, repo_overrides, 'enabled')[0]) + gpgcheck, gpgcheck_modified = self._get_model_value(repo_data, repo_overrides, 'gpgcheck') + gpgcheck = self._get_boolean(gpgcheck) + + return { + 'enabled': bool(int(enabled)), + 'repo_id': repo_data.id, + 'modified': modified, + 'modified-icon': self._get_modified_icon(modified), + 'name': repo_data['name'], + 'baseurl': repo_data['baseurl'], + 'gpgcheck': gpgcheck, + 'gpgcheck_modified': gpgcheck_modified, + 'repo_data': repo_data, + 'override_data': repo_overrides + } + + def _show_progress_bar(self, title, label, progress_parent=None): + self.pb = progress.Progress(title, label, True) + self.timer = ga_GObject.timeout_add(100, self.pb.pulse) + self.pb.set_parent_window(progress_parent or self._get_dialog_widget()) + + def _clear_progress_bar(self): + if self.pb: + self.pb.hide() + ga_GObject.source_remove(self.timer) + self.timer = 0 + self.pb = None + def _get_modified_icon(self, modified): icon = None if modified: @@ -208,8 +267,7 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): def _get_selected_repo_id(self): selected = None - override_selection = SelectionWrapper(self.overrides_treeview.get_selection(), - self.overrides_store) + override_selection = SelectionWrapper(self.overrides_treeview.get_selection(), self.overrides_store) if override_selection.is_valid(): selected = override_selection['repo_id'] return selected @@ -269,52 +327,167 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): repo_id = selection['repo_id'] - try: - self._delete_all_overrides(repo_id) - except Exception, e: - handle_gui_exception(e, _("Unable to reset repository overrides."), - self._get_dialog_widget()) + self._show_progress_bar(_("Removing Repository Overrides"), _("Removing all overrides for repository %s") % repo_id) + self.async_update.remove_all_overrides([repo_id], self._on_async_delete_all_overrides_success, + self._on_async_delete_all_overrides_failure) + + def _on_async_delete_all_overrides_success(self, current_overrides, current_repos): + selection = SelectionWrapper(self.overrides_treeview.get_selection(), + self.overrides_store) + + repo_id = selection['repo_id'] + repo_data = None + for repo in current_repos: + if repo_id == repo.id: + repo_data = repo + break + + if repo_data: + override_data = None + for override in current_overrides: + if repo_id == override.repo_id: + override_data = override + break + + row_data = self._build_table_row_data(repo_data, override_data) + self.overrides_store.update_map(selection.tree_iter, row_data) + + # Update the UI based on the current selection as no selection change is + # triggered, but data may enable/disable different widgets based on data + # change. + self._on_selection(self.overrides_treeview.get_selection()) + + self._clear_progress_bar() + + def _on_async_delete_all_overrides_failure(self, e): + self._clear_progress_bar() + handle_gui_exception(e, _("Unable to reset repository overrides."), + self._get_dialog_widget()) def _on_selection(self, tree_selection): selection = SelectionWrapper(tree_selection, self.overrides_store) self.other_overrides.clear() - self.reset_button.set_sensitive(selection.is_valid() and selection['modified']) + reset_enabled = False if selection.is_valid(): - self.name_text.get_buffer().set_text(selection['name']) - self.baseurl_text.get_buffer().set_text(selection['baseurl']) + overrides = selection['override_data'] + reset_enabled = overrides is not None and len(overrides) > 0 + + self.name_text.set_text(selection['name']) + self.baseurl_text.set_text(selection['baseurl']) for key, value in (selection['override_data'] or {}).items(): if key not in ['gpgcheck', 'enabled']: self.other_overrides.add_override(key, value) + self.reset_button.set_sensitive(reset_enabled) + + def _get_changed_overrides(self): + override_mapping = { + 'to_add': [], + 'to_remove': [] + } + + # Process each row in the model and build up a mapping of overrides. + self.overrides_store.foreach(self._get_overrides_for_row, override_mapping) + return override_mapping + + def _on_apply_request(self, button, event=None): + override_mapping = self._get_changed_overrides() + self._apply_override_changes(override_mapping, self._on_update_success) + + def _apply_override_changes(self, override_mapping, success_handler): + self._show_progress_bar(_("Updating Repository Overrides"), _("Applying override changes to repositories.")) + self.async_update.update_overrides(override_mapping['to_add'], override_mapping['to_remove'], + success_handler, self._on_update_failure) + + def _on_update_success(self, current_overrides, current_repos): + self._refresh(current_overrides, current_repos, self._get_selected_repo_id()) + self._clear_progress_bar() + + def _on_update_failure(self, e): + handle_gui_exception(e, _("Unable to update overrides."), self._get_dialog_widget()) + def _on_close(self, button, event=None): + override_mapping = self._get_changed_overrides() + if (len(override_mapping["to_add"]) == 0 and len(override_mapping["to_remove"]) == 0): + self.close_dialog() + return True + + # There are changes pending, check if the user would like to save changes. + confirm = YesNoDialog(_("Repositories have changes. Save changes?"), + self._get_dialog_widget(), _("Save Changes")) + confirm.connect("response", self._on_apply_changes_on_close_response, override_mapping) + + def _on_apply_changes_on_close_response(self, dialog, response, override_mapping): + if not response: + self.close_dialog() + return + self._apply_override_changes(override_mapping, self._on_async_close_request) + + def _on_async_close_request(self, current_overrides, current_repos): + self.close_dialog() + + def close_dialog(self): + self._clear_progress_bar() self.hide() - return True + + def _get_overrides_for_row(self, model, path, iter, override_mapping): + self._update_override_mapping("gpgcheck", model, path, iter, override_mapping) + self._update_override_mapping("enabled", model, path, iter, override_mapping) + + def _update_override_mapping(self, attribute, model, path, iter, override_mapping): + ''' + Process a single model row and determine if an override should be added/removed. + ''' + repo = model.get_value(iter, model['repo_data']) + remote_overrides = model.get_value(iter, model['override_data']) + + repo_attribute_value = self._get_boolean(repo[attribute]) + model_attribute_value = self._get_boolean(model.get_value(iter, model[attribute])) + has_remote_override = remote_overrides and attribute in remote_overrides + + if not has_remote_override and model_attribute_value != repo_attribute_value: + override_mapping["to_add"].append(Override(repo.id, attribute, str(int(model_attribute_value)))) + elif has_remote_override and model_attribute_value == repo_attribute_value: + override_mapping["to_remove"].append(Override(repo.id, attribute)) def _on_toggle_changed(self, override_model_iter, enabled, key): + ''' + Update the gui based on check box change. + ''' repo = self.overrides_store.get_value(override_model_iter, self.overrides_store['repo_data']) overrides = self.overrides_store.get_value(override_model_iter, self.overrides_store['override_data']) - value = repo[key] - has_active_override = overrides and key in overrides + current_gpg_check = self._get_boolean(self.overrides_store.get_value(override_model_iter, + self.overrides_store['gpgcheck'])) + repo_gpg_check = self._get_boolean(repo['gpgcheck']) - try: - if not has_active_override and enabled != int(value): - # We get True/False from the model, convert to int so that - # the override gets the correct value. - self._add_override(repo.id, key, int(enabled)) - - elif has_active_override and overrides[key] != value: - self._delete_override(repo.id, key) - else: - # Should only ever be one path here, else we have a UI logic error. - self._add_override(repo.id, key, int(enabled)) - except Exception, e: - handle_gui_exception(e, _("Unable to update %s override.") % key, - self._get_dialog_widget()) + current_enabled = self._get_boolean(self.overrides_store.get_value(override_model_iter, + self.overrides_store['enabled'])) + repo_enabled = self._get_boolean(repo['enabled']) + + has_extra = self._has_extra_overrides(overrides) + + mark_modified = has_extra or repo_gpg_check != current_gpg_check or repo_enabled != current_enabled + enable_reset = overrides is not None and len(overrides) > 0 + + self.reset_button.set_sensitive(enable_reset) + self.overrides_store.set_value(override_model_iter, self.overrides_store['modified'], mark_modified) + self.overrides_store.set_value(override_model_iter, self.overrides_store['modified-icon'], + self._get_modified_icon(mark_modified)) + + changed = self._get_changed_overrides() + activate_apply_button = len(changed["to_add"]) != 0 or len(changed["to_remove"]) != 0 + self.apply_button.set_sensitive(activate_apply_button) + + def _has_extra_overrides(self, override_data): + for key, value in (override_data or {}).items(): + if key not in ['gpgcheck', 'enabled']: + return True + return False def _on_enable_repo_toggle(self, override_model_iter, enabled): return self._on_toggle_changed(override_model_iter, enabled, 'enabled') @@ -322,22 +495,5 @@ class RepositoriesDialog(widgets.SubmanBaseWidget, HasSortableWidget): def _on_gpgcheck_toggle_changed(self, override_model_iter, enabled): return self._on_toggle_changed(override_model_iter, enabled, 'gpgcheck') - def _add_override(self, repo, name, value): - to_add = Override(repo, name, value) - current_overrides = self.backend.overrides.add_overrides(self.identity.uuid, [to_add]) - self.backend.overrides.update(current_overrides) - self._refresh(current_overrides, self._get_selected_repo_id()) - - def _delete_override(self, repo, name): - to_delete = Override(repo, name) - current_overrides = self.backend.overrides.remove_overrides(self.identity.uuid, [to_delete]) - self.backend.overrides.update(current_overrides) - self._refresh(current_overrides, self._get_selected_repo_id()) - - def _delete_all_overrides(self, repo_id): - current_overrides = self.backend.overrides.remove_all_overrides(self.identity.uuid, [repo_id]) - self.backend.overrides.update(current_overrides) - self._refresh(current_overrides, self._get_selected_repo_id()) - def _get_dialog_widget(self): return self.main_window diff --git a/src/subscription_manager/gui/storage.py b/src/subscription_manager/gui/storage.py index 818dbb2..296d1d0 100644 --- a/src/subscription_manager/gui/storage.py +++ b/src/subscription_manager/gui/storage.py @@ -80,6 +80,10 @@ class MappedListStore(MappedStore, ga_Gtk.ListStore): """ self.append(self._create_initial_entry(item_map)) + def update_map(self, iter, item_map): + for key, value in item_map.iteritems(): + self.set_value(iter, self[key], value) + class MappedTreeStore(MappedStore, ga_Gtk.TreeStore): def __init__(self, type_map): diff --git a/src/subscription_manager/gui/widgets.py b/src/subscription_manager/gui/widgets.py index d09743b..e50b7ae 100644 --- a/src/subscription_manager/gui/widgets.py +++ b/src/subscription_manager/gui/widgets.py @@ -79,7 +79,6 @@ class FileBasedGui(object): "%s.%s" % (self.gui_file, self.gui_file_suffix)) - log.debug("loading gui file %s", gui_file_full_path) return gui_file_full_path @@ -150,7 +149,13 @@ class SubmanBaseWidget(object): """ for name in widget_names: - setattr(self, name, file_based_gui.get_object(name)) + obj = file_based_gui.get_object(name) + # Builder doesn't set the name of the widget to the id in + # xml ui file as libglade did, so set it here so widget.get_name() + # returns that id ('proxyButton' vs 'Gtk.CheckButton', for ex) + if obj: + obj.set_name(name) + setattr(self, name, obj) def connect_signals(self, signals): return self.gui.connect_signals(signals) @@ -722,8 +727,6 @@ class DatePicker(ga_Gtk.HBox): self._calendar_window.set_type_hint(ga_Gdk.WindowTypeHint.DIALOG) self._calendar_window.set_modal(True) self._calendar_window.set_title(_("Date Selection")) - self._calendar_window.set_transient_for( - self.get_parent()) self._calendar.select_month(self._date.month - 1, self._date.year) self._calendar.select_day(self._date.day) diff --git a/subscription-manager.spec b/subscription-manager.spec index de5695b..a44c4db 100644 --- a/subscription-manager.spec +++ b/subscription-manager.spec @@ -37,7 +37,7 @@ Name: subscription-manager Version: 1.15.9 -Release: 2%{?dist} +Release: 3%{?dist} Summary: Tools and libraries for subscription and repository management Group: System Environment/Base License: GPLv2 @@ -114,6 +114,7 @@ Group: System Environment/Base Requires: pygobject3-base # plugin needs a slightly newer version of python-iniparse for 'tidy' Requires: python-iniparse >= 0.4 +Requires: %{name} = %{version}-%{release} %description -n subscription-manager-plugin-ostree Enables handling of content of type 'ostree' in any certificates @@ -130,6 +131,7 @@ the remote in the currently deployed .origin file. %package -n subscription-manager-plugin-container Summary: A plugin for handling container content. Group: System Environment/Base +Requires: %{name} = %{version}-%{release} %description -n subscription-manager-plugin-container Enables handling of content of type 'containerImage' in any certificates @@ -527,6 +529,29 @@ fi %endif %changelog +* Fri Jul 31 2015 Chris Rog 1.15.9-3 +- 1248746: Fix layout of contract dialog (GTK3) (mstead@redhat.com) +- 1248821: Add Gtk.Window to ga_gtk2.Gtk (alikins@redhat.com) +- 1248821: All subs date picker was failing. (alikins@redhat.com) +- 1249053: Fixed layout/blank button issues on owner selection dialog + (mstead@redhat.com) +- 1248729: All subs filter dialog was not focused. (alikins@redhat.com) +- 1248664: Fix GtkAdjustment related warnings (alikins@redhat.com) +- 1248546: Slightly better looking done screen. (alikins@redhat.com) +- 1245557: Fix release and service level preferences (alikins@redhat.com) +- Add GTK_COMPAT_VERSION to ga_gtk2/gtk_compat (alikins@redhat.com) +- 1248773: Fixed proxy dialog layout (GTK3) (mstead@redhat.com) +- 1248771: Fixing activation key dialog layout (GTK3) (mstead@redhat.com) +- 1247723: Fixed layout issues in Facts dialog (GTK3) (mstead@redhat.com) +- 1245283: Properly initialize AutobindWizard when auto-attach is clicked + (mstead@redhat.com) +- 1248546: Refine the aesthics of register dialog. (alikins@redhat.com) +- 1243260: Make proxy config dialog work. (alikins@redhat.com) +- 1161157,1155954: Improve performance of Repository Dialog (mstead@redhat.com) +- 1165771: make content plugins require subman (alikins@redhat.com) +- Move gtk_compat features to sub ga module. (alikins@redhat.com) +- Use idle_add from ga_Object for 6.x (alikins@redhat.com) + * Mon Jul 27 2015 Chris Rog 1.15.9-2 - Updated initial-setup-addon package requirement to initial-setup-gui (crog@redhat.com) diff --git a/test/test_repogui.py b/test/test_repogui.py index dcae508..b1b1907 100644 --- a/test/test_repogui.py +++ b/test/test_repogui.py @@ -14,6 +14,7 @@ from mock import Mock from fixture import SubManFixture +from subscription_manager.async import AsyncRepoOverridesUpdate from subscription_manager.gui.reposgui import RepositoriesDialog from subscription_manager.repolib import Repo from subscription_manager.overrides import Override @@ -37,6 +38,7 @@ class TestReposGui(SubManFixture): self.dialog = RepositoriesDialog(backend, None) self.dialog.overrides_mock = self.overrides_mock + self.dialog.async_update = TestingOverridesAsync(self.overrides_mock) def test_show_dialog_with_no_overrides(self): repo = self._create_repo("my_repo", [('enabled', '0'), ('gpgcheck', '0')]) @@ -68,10 +70,10 @@ class TestReposGui(SubManFixture): self.assertEquals(repo, store.get_value(tree_iter, store['repo_data'])) # Check that the details view is populated correctly - name = self._get_text(self.dialog.name_text) + name = self.dialog.name_text.get_text() self.assertEquals("MY_REPO", name) - baseurl = self._get_text(self.dialog.baseurl_text) + baseurl = self.dialog.baseurl_text.get_text() self.assertEquals("http://foo.bar", baseurl) def test_show_dialog_with_overrides(self): @@ -114,10 +116,10 @@ class TestReposGui(SubManFixture): self.assertEquals(repo, store.get_value(tree_iter, store['repo_data'])) # Check that the details view is populated correctly - name = self._get_text(self.dialog.name_text) + name = self.dialog.name_text.get_text() self.assertEquals("MY_REPO", name) - baseurl = self._get_text(self.dialog.baseurl_text) + baseurl = self.dialog.baseurl_text.get_text() self.assertEquals("http://foo.bar", baseurl) def test_remove_all_button_disabled_when_repo_has_no_modifications(self): @@ -157,11 +159,21 @@ class TestReposGui(SubManFixture): attrs.extend(attribute_tuple_list) return Repo(repo_id, attrs) - def _get_text(self, text_view): - start, end = text_view.get_buffer().get_bounds() - return text_view.get_buffer().get_text(start, end, - include_hidden_chars=False) - def _get_combo_box_value(self, combo_box): column = combo_box.get_active() return combo_box.get_model()[column][1] + + +class TestingOverridesAsync(AsyncRepoOverridesUpdate): + + def _process_callback(self, callback, *args): + callback(*args) + + def load_data(self, success_callback, except_callback): + self._load_data(success_callback, except_callback) + + def update_overrides(self, to_add, to_remove, success_callback, except_callback): + self._update(to_add, to_remove, success_callback, except_callback) + + def remove_all_overrides(self, repo_ids, success_callback, except_callback): + self._remove_all(repo_ids, success_callback, except_callback)