subiquity/console_conf/ui/views/chooser.py

221 lines
7.0 KiB
Python

# 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 <http://www.gnu.org/licenses/>.
""" 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()