diff --git a/subiquity/controllers/filesystem.py b/subiquity/controllers/filesystem.py index 682d0267..c59bb814 100644 --- a/subiquity/controllers/filesystem.py +++ b/subiquity/controllers/filesystem.py @@ -32,6 +32,8 @@ from subiquity.ui.views import ( DiskPartitionView, FilesystemView, FormatEntireView, + GuidedDiskSelectionView, + GuidedFilesystemView, LVMVolumeGroupView, PartitionView, RaidView, @@ -59,13 +61,29 @@ class FilesystemController(BaseController): if reset: log.info("Resetting Filesystem model") self.model.reset() + if self.model.any_configuration_done(): + self.manual() + else: + title = "Filesystem setup" + footer = ("Choose guided or manual partitioning") + self.ui.set_header(title) + self.ui.set_footer(footer, 30) + self.ui.set_body(GuidedFilesystemView(self.model, self)) + def manual(self): title = "Filesystem setup" footer = ("Select available disks to format and mount") self.ui.set_header(title) self.ui.set_footer(footer, 30) self.ui.set_body(FilesystemView(self.model, self)) + def guided(self): + title = "Filesystem setup" + footer = ("Choose the installation target") + self.ui.set_header(title) + self.ui.set_footer(footer, 30) + self.ui.set_body(GuidedDiskSelectionView(self.model, self)) + def reset(self): log.info("Resetting Filesystem model") self.model.reset() diff --git a/subiquity/models/filesystem.py b/subiquity/models/filesystem.py index 8068a2d2..b59db17c 100644 --- a/subiquity/models/filesystem.py +++ b/subiquity/models/filesystem.py @@ -370,6 +370,9 @@ class FilesystemModel(object): r[m.path] = m.device.volume.path return r + def any_configuration_done(self): + return len(self._disks) > 0 + def can_install(self): # Do we need to check that there is a disk with the boot flag? return '/' in self.get_mountpoint_to_devpath_mapping() and self.bootable() diff --git a/subiquity/ui/views/__init__.py b/subiquity/ui/views/__init__.py index ef66d2aa..cf8f9a31 100644 --- a/subiquity/ui/views/__init__.py +++ b/subiquity/ui/views/__init__.py @@ -17,7 +17,9 @@ from .filesystem import (FilesystemView, # NOQA PartitionView, FormatEntireView, DiskPartitionView, - DiskInfoView) + DiskInfoView, + GuidedDiskSelectionView, + GuidedFilesystemView) from .bcache import BcacheView # NOQA from .raid import RaidView # NOQA from .ceph import CephDiskView # NOQA diff --git a/subiquity/ui/views/filesystem/__init__.py b/subiquity/ui/views/filesystem/__init__.py index d9398645..a5d44fc2 100644 --- a/subiquity/ui/views/filesystem/__init__.py +++ b/subiquity/ui/views/filesystem/__init__.py @@ -23,4 +23,5 @@ configuration. from .disk_info import DiskInfoView from .disk_partition import DiskPartitionView from .filesystem import FilesystemView +from .guided import GuidedDiskSelectionView, GuidedFilesystemView from .partition import FormatEntireView, PartitionView diff --git a/subiquity/ui/views/filesystem/filesystem.py b/subiquity/ui/views/filesystem/filesystem.py index 5ecb25ff..3e64fbb8 100644 --- a/subiquity/ui/views/filesystem/filesystem.py +++ b/subiquity/ui/views/filesystem/filesystem.py @@ -94,7 +94,10 @@ class FilesystemView(BaseView): #Text(""), Padding.fixed_10(self._build_buttons()), ] - super().__init__(Padding.center_95(ListBox(self.body))) + w = ListBox(self.body) + if self.model.can_install(): + w.set_focus_path([len(self.body)-1, 0]) + super().__init__(Padding.center_95(w)) log.debug('FileSystemView init complete()') def _build_used_disks(self): diff --git a/subiquity/ui/views/filesystem/guided.py b/subiquity/ui/views/filesystem/guided.py new file mode 100644 index 00000000..33725f31 --- /dev/null +++ b/subiquity/ui/views/filesystem/guided.py @@ -0,0 +1,91 @@ +# Copyright 2017 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 . + +from urwid import ( + connect_signal, + Text, + ) + +from subiquitycore.ui.utils import Padding, Color + +from subiquitycore.ui.buttons import ( + menu_btn, + PlainButton, + ) +from subiquitycore.ui.container import ListBox, Pile +from subiquitycore.view import BaseView + +from subiquity.models.filesystem import humanize_size + + +text = """The installer can guide you through partitioning a disk or, if \ +you prefer, you can do it manually. If you choose guided partitioning you \ +will still have a chance to review and modify the results.""" + + +class GuidedFilesystemView(BaseView): + + def __init__(self, model, controller): + self.controller = controller + guided = PlainButton(label="Guided") + connect_signal(guided, 'click', self.guided) + manual = PlainButton(label="Manual") + connect_signal(manual, 'click', self.manual) + lb = ListBox([ + Padding.center_70(Text(text)), + Padding.center_70(Text("")), + Padding.fixed_10(Color.button(guided)), + Padding.fixed_10(Color.button(manual))]) + super().__init__(lb) + + def manual(self, btn): + self.controller.manual() + + def guided(self, btn): + self.controller.guided() + +class GuidedDiskSelectionView(BaseView): + + def __init__(self, model, controller): + self.model = model + self.controller = controller + cancel = PlainButton(label="Cancel") + connect_signal(cancel, 'click', self.cancel) + disks = [] + for disk in self.model.all_disks(): + if disk.available: + disk_btn = menu_btn("%-40s %s"%(disk.serial, humanize_size(disk.size).rjust(9))) + connect_signal(disk_btn, 'click', self.choose_disk, disk) + disks.append(Color.menu_button(disk_btn)) + lb = ListBox([ + Padding.center_70(Text("Choose the disk to install to:")), + Padding.center_70(Text("")), + Padding.center_70(Pile(disks)), + Padding.center_70(Text("")), + Padding.fixed_10(Color.button(cancel))]) + super().__init__(lb) + + def cancel(self, btn): + self.controller.default() + + def choose_disk(self, btn, disk): + result = { + "partnum": 1, + "size": disk.free, + "fstype": self.model.fs_by_name["ext4"], + "mount": "/", + } + self.controller.partition_disk_handler(disk, None, result) + self.controller.manual() diff --git a/subiquitycore/ui/views/network.py b/subiquitycore/ui/views/network.py index 13204395..b22abb12 100644 --- a/subiquitycore/ui/views/network.py +++ b/subiquitycore/ui/views/network.py @@ -125,7 +125,7 @@ class NetworkView(BaseView): ] # FIXME determine which UX widget should have focus self.lb = ListBox(self.body) - self.lb.set_focus(4) # _build_buttons + self.lb.set_focus_path([6, 0]) # _build_buttons super().__init__(self.lb) def _build_buttons(self):