diff --git a/subiquity/core.py b/subiquity/core.py index b45fc0dc..fe782f44 100644 --- a/subiquity/core.py +++ b/subiquity/core.py @@ -35,6 +35,7 @@ from subiquitycore.async_helpers import ( ) from subiquitycore.controller import Skip from subiquitycore.core import Application +from subiquitycore.view import BaseView from subiquity.controllers.error import ( ErrorReportKind, @@ -128,7 +129,7 @@ class Subiquity(Application): ["subiquity"], self.subiquity_event, seek=True) super().__init__(opts) self.install_lock_file = Lockfile(self.state_path("installing")) - self.install_running = None + self.global_overlays = [] self.block_log_dir = block_log_dir self.kernel_cmdline = shlex.split(opts.kernel_cmdline) if opts.snaps_from_examples: @@ -168,16 +169,15 @@ class Subiquity(Application): InstallRunning, ) tty = self.install_lock_file.read_content() - self.install_running = InstallRunning(self.ui.body, self, tty) - self.ui.body.show_stretchy_overlay(self.install_running) - schedule_task(self._hide_install_running()) + install_running = InstallRunning(self.ui.body, self, tty) + self.add_global_overlay(install_running) + schedule_task(self._hide_install_running(install_running)) - async def _hide_install_running(self): + async def _hide_install_running(self, install_running): # Wait until the install has completed... async with self.install_lock_file.shared(): # And remove the overlay. - self.install_running = None - self.ui.body.remove_overlay() + self.remove_global_overlay(install_running) def restart(self, remove_last_screen=True): if remove_last_screen: @@ -343,7 +343,7 @@ class Subiquity(Application): InstallConfirmation, ) self._cancel_show_progress() - self.ui.body.show_stretchy_overlay( + self.add_global_overlay( InstallConfirmation(self.ui.body, self)) else: yes = _('yes') @@ -371,12 +371,22 @@ class Subiquity(Application): return True return bool(self.autoinstall_config.get('interactive-sections')) + def add_global_overlay(self, overlay): + self.global_overlays.append(overlay) + if isinstance(self.ui.body, BaseView): + self.ui.body.show_stretchy_overlay(overlay) + + def remove_global_overlay(self, overlay): + self.global_overlays.remove(overlay) + if isinstance(self.ui.body, BaseView): + self.ui.body.remove_overlay(overlay) + def select_initial_screen(self, index): - super().select_initial_screen(index) for report in self.controllers.Error.reports: if report.kind == ErrorReportKind.UI and not report.seen: - self.report_to_show = report - return + self.show_error_report(report) + break + super().select_initial_screen(index) def select_screen(self, new): if new.interactive(): @@ -390,12 +400,6 @@ class Subiquity(Application): return self.progress_showing = False super().select_screen(new) - if self.report_to_show is not None: - log.debug("showing new error %r", self.report_to_show.base) - self.show_error_report(self.report_to_show) - self.report_to_show = None - if self.install_running is not None: - self.ui.body.show_stretchy_overlay(self.install_running) elif self.autoinstall_config and not new.autoinstall_applied: if self.interactive() and self.show_progress_handle is None: self.ui.block_input = True @@ -520,12 +524,12 @@ class Subiquity(Application): def show_error_report(self, report): log.debug("show_error_report %r", report.base) - w = getattr(self.ui.body._w, 'top_w', None) - if isinstance(w, ErrorReportStretchy): - # Don't show an error if already looking at one. - return - self.ui.body.show_stretchy_overlay( - ErrorReportStretchy(self, self.ui.body, report)) + if isinstance(self.ui.body, BaseView): + w = getattr(self.ui.body._w, 'stretchy', None) + if isinstance(w, ErrorReportStretchy): + # Don't show an error if already looking at one. + return + self.add_global_overlay(ErrorReportStretchy(self, report)) def make_autoinstall(self): config = {} diff --git a/subiquity/ui/frame.py b/subiquity/ui/frame.py index b5ed1bd3..7771b20a 100644 --- a/subiquity/ui/frame.py +++ b/subiquity/ui/frame.py @@ -16,6 +16,7 @@ import logging from subiquitycore.ui.frame import SubiquityCoreUI +from subiquitycore.view import BaseView from subiquity.ui.views.help import HelpButton @@ -28,9 +29,16 @@ class SubiquityUI(SubiquityCoreUI): block_input = False def __init__(self, app): + self.app = app self.right_icon = HelpButton(app) super().__init__() def keypress(self, size, key): if not self.block_input: return super().keypress(size, key) + + def set_body(self, widget): + super().set_body(widget) + if isinstance(widget, BaseView): + for overlay in self.app.global_overlays: + widget.show_stretchy_overlay(overlay) diff --git a/subiquity/ui/views/error.py b/subiquity/ui/views/error.py index 670a2cba..677462a4 100644 --- a/subiquity/ui/views/error.py +++ b/subiquity/ui/views/error.py @@ -54,10 +54,12 @@ from subiquity.controllers.error import ( log = logging.getLogger('subiquity.ui.error') -def close_btn(parent, label=None): +def close_btn(stretchy, label=None): if label is None: label = _("Close") - return other_btn(label, on_press=lambda sender: parent.remove_overlay()) + return other_btn( + label, + on_press=lambda sender: stretchy.app.remove_global_overlay(stretchy)) error_report_intros = { @@ -129,17 +131,16 @@ If you want to help improve the installer, you can send an error report. class ErrorReportStretchy(Stretchy): - def __init__(self, app, parent, report, interrupting=True): + def __init__(self, app, report, interrupting=True): self.app = app self.report = report - self.parent = parent self.interrupting = interrupting self.btns = { 'cancel': other_btn( _("Cancel upload"), on_press=self.cancel_upload), - 'close': close_btn(parent, _("Close report")), - 'continue': close_btn(parent, _("Continue")), + 'close': close_btn(self, _("Close report")), + 'continue': close_btn(self, _("Continue")), 'debug_shell': other_btn( _("Switch to a shell"), on_press=self.debug_shell), 'restart': other_btn( @@ -247,7 +248,7 @@ class ErrorReportStretchy(Stretchy): self.pile.focus_position += 1 def debug_shell(self, sender): - self.parent.remove_overlay() + self.app.debug_shell() def restart(self, sender): self.app.restart() @@ -273,9 +274,8 @@ class ErrorReportStretchy(Stretchy): class ErrorReportListStretchy(Stretchy): - def __init__(self, app, parent): + def __init__(self, app): self.app = app - self.parent = parent rows = [ TableRow([ Text(""), @@ -295,13 +295,13 @@ class ErrorReportListStretchy(Stretchy): Text(""), self.table, Text(""), - button_pile([close_btn(parent)]), + button_pile([close_btn(self)]), ] super().__init__("", widgets, 2, 2) def open_report(self, sender, report): - self.parent.show_stretchy_overlay( - ErrorReportStretchy(self.app, self.parent, report, False)) + self.app.add_global_overlay( + ErrorReportStretchy(self.app, report, False)) def state_for_report(self, report): if report.seen: diff --git a/subiquity/ui/views/help.py b/subiquity/ui/views/help.py index 8ed7746c..aec7b8dd 100644 --- a/subiquity/ui/views/help.py +++ b/subiquity/ui/views/help.py @@ -61,9 +61,10 @@ from subiquity.ui.views.error import ErrorReportListStretchy log = logging.getLogger('subiquity.ui.help') -def close_btn(parent): +def close_btn(app, stretchy): return other_btn( - _("Close"), on_press=lambda sender: parent.remove_overlay()) + _("Close"), + on_press=lambda sender: app.remove_global_overlay(stretchy)) ABOUT_INSTALLER = _(""" @@ -154,7 +155,7 @@ def ssh_help_texts(ips, password): class SimpleTextStretchy(Stretchy): - def __init__(self, parent, title, *texts): + def __init__(self, app, title, *texts): widgets = [] for text in texts: @@ -164,7 +165,7 @@ class SimpleTextStretchy(Stretchy): widgets.extend([ Text(""), - button_pile([close_btn(parent)]), + button_pile([close_btn(app, self)]), ]) super().__init__(title, widgets, 0, len(widgets)-1) @@ -191,7 +192,7 @@ DRY_RUN_KEYS = ( class GlobalKeyStretchy(Stretchy): - def __init__(self, app, parent): + def __init__(self, app): rows = [] for key, text in GLOBAL_KEYS: rows.append(TableRow([Text(_(key)), Text(_(text))])) @@ -210,7 +211,7 @@ class GlobalKeyStretchy(Stretchy): ('pack', table), ]), Text(""), - button_pile([close_btn(parent)]), + button_pile([close_btn(app, self)]), ] super().__init__(_("Shortcut Keys"), widgets, 0, 2) @@ -339,18 +340,18 @@ class HelpMenu(WidgetWrap): # We don't let help dialogs pile up: if one is already # showing, remove it before showing the new one. - if self.parent.showing_something: - ui.body.remove_overlay() - self.parent.showing_something = True + if self.parent.current_help: + self.parent.app.remove_global_overlay(self.parent.current_help) + self.parent.current_help = stretchy fp, ui.pile.focus_position = ui.pile.focus_position, 1 def on_close(): - self.parent.showing_something = False + self.parent.current_help = None ui.pile.focus_position = fp connect_signal(stretchy, 'closed', on_close) - ui.body.show_stretchy_overlay(stretchy) + self.parent.app.add_global_overlay(stretchy) def _about(self, sender=None): info = lsb_release() @@ -364,7 +365,7 @@ class HelpMenu(WidgetWrap): }) self._show_overlay( SimpleTextStretchy( - self.parent.app.ui.body, + self.parent.app, _("About the installer"), template.format(**info))) @@ -382,7 +383,7 @@ class HelpMenu(WidgetWrap): self._show_overlay( SimpleTextStretchy( - self.parent.app.ui.body, + self.parent.app, _("Help on SSH access"), *texts, )) @@ -392,16 +393,13 @@ class HelpMenu(WidgetWrap): def cb(sender=None): self._show_overlay( SimpleTextStretchy( - self.parent.app.ui.body, + self.parent.app, local_title, local_doc)) return cb def _shortcuts(self, sender): - self._show_overlay( - GlobalKeyStretchy( - self.parent.app, - self.parent.app.ui.body)) + self._show_overlay(GlobalKeyStretchy(self.parent.app)) def _debug_shell(self, sender): self.parent.app.debug_shell() @@ -410,10 +408,7 @@ class HelpMenu(WidgetWrap): self.parent.app.toggle_color() def _show_errors(self, sender): - self._show_overlay( - ErrorReportListStretchy( - self.parent.app, - self.parent.app.ui.body)) + self._show_overlay(ErrorReportListStretchy(self.parent.app)) def get_installer_password(dry_run=False): @@ -439,7 +434,7 @@ class HelpButton(PopUpLauncher): self.app = app self.btn = header_btn(_("Help"), on_press=self._open) self.ssh_password = None - self.showing_something = False + self.current_help = None super().__init__(self.btn) def _open(self, sender):