# Copyright 2015 Canonical, Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """ Chooser Chooser provides a view with recovery chooser actions. """ import logging from urwid import Text, connect_signal from subiquitycore.ui.actionmenu import Action, ActionMenu from subiquitycore.ui.buttons import back_btn, danger_btn, forward_btn from subiquitycore.ui.container import ListBox, Pile from subiquitycore.ui.table import TablePile, TableRow from subiquitycore.ui.utils import Color, button_pile, make_action_menu_row, screen from subiquitycore.view import BaseView log = logging.getLogger("console_conf.ui.views.chooser") class ChooserBaseView(BaseView): title = "Ubuntu Core" def __init__(self, current, scr): super().__init__(scr) if current is not None: self.title = current.model.display_name def by_preferred_action_type(action): """Order action entries by having the 'run' mode first, then 'recover', then 'install', the rest is ordered alphabetically.""" priority = {"run": 0, "recover": 1, "install": 2} return (priority.get(action.mode, 100), action.title.lower()) class ChooserCurrentSystemView(ChooserBaseView): excerpt = "Select action:" def __init__(self, controller, current, has_more=False): self.controller = controller log.debug("more systems available: %s", has_more) log.debug("current system: %s", current) actions = [] for action in sorted(current.actions, key=by_preferred_action_type): actions.append( forward_btn( label=action.title.capitalize(), on_press=self._current_system_action, user_arg=(current, action), ) ) if has_more: # add a button to show the other systems actions.append(Text("")) actions.append( forward_btn( label="Show all available systems", on_press=self._more_options ) ) lb = ListBox(actions) super().__init__(current, screen(lb, narrow_rows=True, excerpt=self.excerpt)) def _current_system_action(self, sender, arg): current, action = arg self.controller.select(current, action) def _more_options(self, sender): self.controller.more_options() def back(self, result): self.controller.back() class ChooserView(ChooserBaseView): excerpt = ( "Select one of available recovery systems and a desired action to execute." ) def __init__(self, controller, systems): self.controller = controller heading_table = TablePile( [ TableRow( [ Color.info_minor(Text(header)) for header in ["LABEL", "MODEL", "PUBLISHER", ""] ] ) ], spacing=2, ) trows = [] systems = sorted( systems, key=lambda s: ( s.brand.display_name, s.model.display_name, s.current, s.label, ), ) for s in systems: actions = [] log.debug("actions: %s", s.actions) for act in sorted(s.actions, key=by_preferred_action_type): actions.append( Action(label=act.title.capitalize(), value=act, enabled=True) ) menu = ActionMenu(actions) connect_signal(menu, "action", self._system_action, s) srow = make_action_menu_row( [ Text(s.label), Text(s.model.display_name), Text(s.brand.display_name), Text("(installed)" if s.current else ""), menu, ], menu, ) trows.append(srow) systems_table = TablePile(trows, spacing=2) systems_table.bind(heading_table) rows = [ Pile([heading_table, systems_table]), ] buttons = [] if controller.model.current is not None: # back to options of current system buttons.append(back_btn("BACK", on_press=self.back)) super().__init__( controller.model.current, screen( rows=rows, buttons=button_pile(buttons), focus_buttons=False, excerpt=self.excerpt, ), ) def _system_action(self, sender, action, system): self.controller.select(system, action) def back(self, result): self.controller.back() class ChooserConfirmView(ChooserBaseView): canned_summary = { "run": "Continue running the system without any changes.", "recover": "You have requested to reboot the system into recovery mode.", "install": ( "You are about to {action_lower} the system version " "{version} for {model} from {publisher}.\n\n" "This will remove all existing user data on the " "device.\n\n" "The system will reboot in the process." ), } default_summary = ( 'You are about to execute action "{action}" using ' "system version {version} for device {model} from " "{publisher}.\n\n" "Make sure you understand the consequences of " "performing this action." ) def __init__(self, controller, selection): self.controller = controller buttons = [ danger_btn("CONFIRM", on_press=self.confirm), back_btn("BACK", on_press=self.back), ] fmt = self.canned_summary.get(selection.action.mode, self.default_summary) summary = fmt.format( action=selection.action.title, action_lower=selection.action.title.lower(), model=selection.system.model.display_name, publisher=selection.system.brand.display_name, version=selection.system.label, ) rows = [ Text(summary), ] super().__init__( controller.model.current, screen(rows=rows, buttons=button_pile(buttons), focus_buttons=False), ) def confirm(self, result): self.controller.confirm() def back(self, result): self.controller.back()