diff --git a/.gitignore b/.gitignore
index 1dd9fde6..fd412777 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,3 +58,4 @@ target/
# subiquity installer images
installer/*.img
+logs/*
diff --git a/bin/subiquity b/bin/subiquity
index 8e4ad3d3..fd38eda3 100755
--- a/bin/subiquity
+++ b/bin/subiquity
@@ -16,10 +16,11 @@
import argparse
import sys
-import urwid
-import urwid.curses_display
-from subiquity.palette import STYLES, STYLES_MONO
-from subiquity.controllers.welcome import WelcomeController
+import logging
+from subiquity.log import setup_logger
+from subiquity import __version__ as VERSION
+from subiquity.controllers import BaseController as Subiquity
+from subiquity.ui.frame import SubiquityUI
def parse_options(argv):
@@ -34,20 +35,15 @@ def parse_options(argv):
def main():
opts = parse_options(sys.argv[1:])
- if opts.run_on_serial:
- screen = urwid.curses_display.Screen()
- screen.register_palette(STYLES_MONO)
- else:
- screen = urwid.raw_display.Screen()
- screen.set_mouse_tracking(False)
- screen.set_terminal_properties(256)
- screen.register_palette(STYLES)
+ setup_logger()
+ logger = logging.getLogger('subiquity')
+ logger.info("Starting SUbiquity v{}".format(VERSION))
+ logger.info("Arguments passed: {}".format(sys.argv))
- def unhandled_input(key):
- if key in ('Q', 'q', 'esc'):
- raise urwid.ExitMainLoop()
- urwid.MainLoop(WelcomeController().show(), screen=screen,
- unhandled_input=unhandled_input).run()
+ ui = SubiquityUI()
+
+ subiquity_interface = Subiquity(ui, opts)
+ subiquity_interface.run()
if __name__ == '__main__':
main()
diff --git a/subiquity/controllers/__init__.py b/subiquity/controllers/__init__.py
index 87f3306d..9ee58b5f 100644
--- a/subiquity/controllers/__init__.py
+++ b/subiquity/controllers/__init__.py
@@ -13,31 +13,93 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from abc import ABCMeta, abstractmethod
+import logging
+import urwid
+import urwid.curses_display
+from subiquity.routes import Routes
+from subiquity.palette import STYLES, STYLES_MONO
-class BaseController(metaclass=ABCMeta):
- controller_name = None
+log = logging.getLogger('subiquity.controller')
- @classmethod
- def name(cls):
- if cls.controller_name:
- return cls.controller_name
- return cls.__name__.lower()
- @abstractmethod
- def show(self):
- """ Implements show action for the controller
+class BaseControllerError(Exception):
+ """ Basecontroller exception """
+ pass
- Renders the View for controller.
- """
- pass
- @abstractmethod
- def finish(self):
- """ Implements finish action for controller.
+class BaseController:
+ def __init__(self, ui, opts):
+ self.ui = ui
+ self.opts = opts
- This handles any callback data/procedures required
- to move to the next controller or end the install.
- """
- pass
+ def next_controller(self, *args, **kwds):
+ controller = Routes.next()
+ controller(self).show(*args, **kwds)
+
+ def prev_controller(self, *args, **kwds):
+ controller = Routes.prev()
+ controller(self).show(*args, **kwds)
+
+ def redraw_screen(self):
+ if hasattr(self, 'loop'):
+ try:
+ self.loop.draw_screen()
+ except AssertionError as e:
+ log.critical(e)
+
+ def set_alarm_in(self, interval, cb):
+ self.loop.set_alarm_in(interval, cb)
+ return
+
+ def update(self, *args, **kwds):
+ route = Routes.current_idx()
+ if route == 0:
+ self.begin()
+ self.set_alarm_in(1, self.update)
+
+ def exit(self):
+ raise urwid.ExitMainLoop()
+
+ def header_hotkeys(self, key):
+ if key in ['q', 'Q']:
+ self.exit()
+
+ def set_body(self, w):
+ self.ui.set_body(w)
+ self.redraw_screen()
+
+ def set_header(self, title, excerpt):
+ self.ui.set_header(title, excerpt)
+ self.redraw_screen()
+
+ def set_footer(self, message):
+ self.ui.set_footer(message)
+ self.redraw_screen()
+
+ def run(self):
+ if not hasattr(self, 'loop'):
+ if self.opts.run_on_serial:
+ screen = urwid.raw_display.Screen()
+ screen.register_palette(STYLES_MONO)
+ else:
+ screen = urwid.raw_display.Screen()
+ screen.set_mouse_tracking(False)
+ screen.set_terminal_properties(256)
+ screen.register_palette(STYLES)
+
+ self.loop = urwid.MainLoop(self.ui, screen=screen,
+ unhandled_input=self.header_hotkeys)
+
+ try:
+ self.begin()
+ self.loop.run()
+ except:
+ log.exception("Exception in controller.run():")
+ raise
+
+ def begin(self):
+ """ Initializes the first controller for installation """
+ Routes.reset()
+ initial_controller = Routes.first()
+ initial_controller(self).show()
diff --git a/subiquity/controllers/installpath.py b/subiquity/controllers/installpath.py
index c8b3f086..985ccb8d 100644
--- a/subiquity/controllers/installpath.py
+++ b/subiquity/controllers/installpath.py
@@ -13,18 +13,36 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from subiquity.controllers import BaseController
+from subiquity.controllers.policy import ControllerPolicy
from subiquity.views.installpath import InstallpathView
-from subiquity.models.welcome import InstallpathModel
+from subiquity.models.installpath import InstallpathModel
+import logging
+import subprocess
+
+log = logging.getLogger('subiquity.installpath')
-class InstallpathController(BaseController):
+class InstallpathController(ControllerPolicy):
"""InstallpathController"""
- controller_name = "Ubuntu Install selection"
- def show(self):
+ title = "15.10"
+ excerpt = ("Welcome to Ubuntu! The world’s favourite platform "
+ "for clouds, clusters and amazing internet things. "
+ "This is the installer for Ubuntu on servers and "
+ "internet devices.")
+ footer = ("Use UP, DOWN arrow keys, and ENTER, to "
+ "navigate options")
+
+ def show(self, *args, **kwds):
+ log.debug("Loading install path controller")
+ self.ui.set_header(self.title, self.excerpt)
+ self.ui.set_footer(self.footer)
model = InstallpathModel()
- return InstallpathView(model, self.finish)
+ self.ui.set_body(InstallpathView(model, self.finish))
+ return
- def finish(self, install_selection):
- raise SystemExit("Install selection: {}".format(install_selection))
+ def finish(self, install_selection=None):
+ # subprocess.check_call("/usr/local/bin/curtin_wrap.sh")
+ return self.ui.next_controller()
+
+__controller_class__ = InstallpathController
diff --git a/subiquity/controllers/network.py b/subiquity/controllers/network.py
new file mode 100644
index 00000000..dc289de4
--- /dev/null
+++ b/subiquity/controllers/network.py
@@ -0,0 +1,45 @@
+# 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 .
+
+from subiquity.controllers.policy import ControllerPolicy
+from subiquity.views.network import NetworkView
+from subiquity.models.network import NetworkModel
+import logging
+
+log = logging.getLogger('subiquity.network')
+
+
+class NetworkController(ControllerPolicy):
+ """InstallpathController"""
+
+ title = "Network connections"
+ excerpt = ("Configure at least the main interface this server will "
+ "use to talk to other machines, and preferably provide "
+ "sufficient access for updates.")
+
+ footer = ("Additional networking info here")
+
+ def show(self, *args, **kwds):
+ self.ui.set_header(self.title, self.excerpt)
+ self.ui.set_footer(self.footer)
+ model = NetworkModel()
+ self.ui.set_body(NetworkView(model, self.finish))
+ return
+
+ def finish(self, interface=None):
+ log.info("Network Interface choosen: {}".format(interface))
+ return self.ui.exit()
+
+__controller_class__ = NetworkController
diff --git a/subiquity/controllers/policy.py b/subiquity/controllers/policy.py
new file mode 100644
index 00000000..a77da196
--- /dev/null
+++ b/subiquity/controllers/policy.py
@@ -0,0 +1,41 @@
+# 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 .
+
+""" Controller policy """
+
+from abc import ABCMeta, abstractmethod
+
+
+class ControllerPolicy(metaclass=ABCMeta):
+
+ def __init__(self, ui):
+ self.ui = ui
+
+ @abstractmethod
+ def show(self, *args, **kwds):
+ """ Implements show action for the controller
+
+ Renders the View for controller.
+ """
+ pass
+
+ @abstractmethod
+ def finish(self):
+ """ Implements finish action for controller.
+
+ This handles any callback data/procedures required
+ to move to the next controller or end the install.
+ """
+ pass
diff --git a/subiquity/controllers/welcome.py b/subiquity/controllers/welcome.py
index 0fb4bb88..8e1d2119 100644
--- a/subiquity/controllers/welcome.py
+++ b/subiquity/controllers/welcome.py
@@ -13,20 +13,34 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from subiquity.controllers import BaseController
+from subiquity.controllers.policy import ControllerPolicy
from subiquity.views.welcome import WelcomeView
from subiquity.models.welcome import WelcomeModel
-import subprocess
+import logging
-class WelcomeController(BaseController):
+log = logging.getLogger('subiquity.controllers.welcome')
+
+
+class WelcomeController(ControllerPolicy):
"""WelcomeController"""
- controller_name = "Welcome to Ubuntu"
+ title = "Wilkommen! Bienvenue! Welcome! Zdrastvutie! Welkom!"
+ excerpt = "Please choose your preferred language"
+ footer = ("Use UP, DOWN arrow keys, and ENTER, to "
+ "select your language.")
- def show(self):
- model = WelcomeModel()
- return WelcomeView(model, self.finish)
+ def show(self, *args, **kwds):
+ self.ui.set_header(self.title, self.excerpt)
+ self.ui.set_footer(self.footer)
+ self.ui.set_body(WelcomeView(WelcomeModel, self.finish))
+ return
- def finish(self, code, val):
- subprocess.check_call("/usr/local/bin/curtin_wrap.sh")
- raise SystemExit("Saw res: {}, val: {}".format(code, val))
+ def finish(self, language=None):
+ if language is None:
+ raise SystemExit("No language selected, exiting as there are no "
+ "more previous controllers to render.")
+ WelcomeModel.selected_language = language
+ log.debug("Welcome Model: {}".format(WelcomeModel()))
+ return self.ui.next_controller()
+
+__controller_class__ = WelcomeController
diff --git a/subiquity/log.py b/subiquity/log.py
new file mode 100644
index 00000000..e70d648e
--- /dev/null
+++ b/subiquity/log.py
@@ -0,0 +1,41 @@
+# 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 .
+
+import logging
+import os
+from logging.handlers import TimedRotatingFileHandler
+
+
+def setup_logger(name=__name__):
+ LOGDIR = "logs"
+ LOGFILE = os.path.join(LOGDIR, "debug.log")
+ if not os.path.isdir(LOGDIR):
+ os.makedirs(LOGDIR)
+ log = TimedRotatingFileHandler(LOGFILE,
+ when='D',
+ interval=1,
+ backupCount=7)
+ log.setLevel('DEBUG')
+ log.setFormatter(logging.Formatter(
+ "%(asctime)s "
+ "%(name)s:%(lineno)d %(message)s",
+ datefmt='%m/%d %H:%M'))
+ log_filter = logging.Filter(name='subiquity')
+ log.addFilter(log_filter)
+
+ logger = logging.getLogger('')
+ logger.setLevel('DEBUG')
+ logger.addHandler(log)
+ return logger
diff --git a/subiquity/models/filesystem.py b/subiquity/models/filesystem.py
new file mode 100644
index 00000000..6b892840
--- /dev/null
+++ b/subiquity/models/filesystem.py
@@ -0,0 +1,40 @@
+# 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 .
+
+""" Filesystem Model
+
+Provides storage device selection and additional storage
+configuration.
+
+"""
+
+from subiquity import models
+
+
+class FilesystemModel(models.Model):
+ """ Model representing storage options
+ """
+
+ available_disks = ['/dev/sda',
+ '/dev/sdb',
+ '/dev/sdc',
+ '/dev/sdd',
+ '/dev/sde']
+
+ additional_options = ['Connecti iSCSI network disk',
+ 'Connect Ceph network disk',
+ 'Create volume group (LVM2)',
+ 'Create software RAID (MD)',
+ 'Setup hierarchichal storage (bcache)']
diff --git a/subiquity/models/network.py b/subiquity/models/network.py
new file mode 100644
index 00000000..5c203c0c
--- /dev/null
+++ b/subiquity/models/network.py
@@ -0,0 +1,35 @@
+# 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 .
+
+""" Network Model
+
+Provides network device listings and extended network information
+
+"""
+
+from subiquity import models
+
+
+class NetworkModel(models.Model):
+ """ Model representing network interfaces
+ """
+
+ interfaces = ['em1',
+ 'em2',
+ 'bond0']
+
+ additional_options = ['Set default route',
+ 'Bond interfaces',
+ 'Install network driver']
diff --git a/subiquity/models/welcome.py b/subiquity/models/welcome.py
index 0e3e2a9e..67c6460c 100644
--- a/subiquity/models/welcome.py
+++ b/subiquity/models/welcome.py
@@ -28,3 +28,6 @@ class WelcomeModel(models.Model):
supported_languages = ['English', 'Belgian', 'German', 'Italian']
selected_language = None
+
+ def __repr__(self):
+ return "".format(self.selected_language)
diff --git a/subiquity/routes.py b/subiquity/routes.py
new file mode 100644
index 00000000..e0f5a38b
--- /dev/null
+++ b/subiquity/routes.py
@@ -0,0 +1,74 @@
+# 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 .
+
+from subiquity.controllers.welcome import WelcomeController
+from subiquity.controllers.installpath import InstallpathController
+from subiquity.controllers.network import NetworkController
+
+
+class RoutesError(Exception):
+ """ Error in routes """
+ pass
+
+
+class Routes:
+ """ Defines application routes and maps to their controller
+
+ Routes are inserted top down from start to finish. Maintaining
+ this order is required for routing to work.
+ """
+ routes = [WelcomeController,
+ InstallpathController,
+ NetworkController]
+ current_route_idx = 0
+
+ @classmethod
+ def route(cls, idx):
+ """ Include route listing in controllers """
+ try:
+ _route = cls.routes[idx]
+ except IndexError:
+ raise RoutesError("Failed to load Route at index: {}".format(idx))
+ return _route
+
+ @classmethod
+ def current_idx(cls):
+ """ Returns current route index """
+ return cls.current_route_idx
+
+ @classmethod
+ def reset(cls):
+ """ Resets current route """
+ cls.current_route_idx = 0
+
+ @classmethod
+ def first(cls):
+ """ first controller/start of install """
+ return cls.route(0)
+
+ @classmethod
+ def last(cls):
+ """ end of install, last controller """
+ return cls.route(-1)
+
+ @classmethod
+ def next(cls):
+ cls.current_route_idx = cls.current_route_idx + 1
+ return cls.route(cls.current_route_idx)
+
+ @classmethod
+ def prev(cls):
+ cls.current_route_idx = cls.current_route_idx - 1
+ return cls.route(cls.current_route_idx)
diff --git a/subiquity/ui/anchors.py b/subiquity/ui/anchors.py
index 0158aa69..785fd5e4 100644
--- a/subiquity/ui/anchors.py
+++ b/subiquity/ui/anchors.py
@@ -15,6 +15,7 @@
from urwid import WidgetWrap, Pile, Text
from subiquity.ui.utils import Padding, Color
+from subiquity.ui.lists import SimpleList
class Header(WidgetWrap):
@@ -26,12 +27,9 @@ class Header(WidgetWrap):
:returns: Header()
"""
- title = "Ubuntu Server Installer"
- excerpt = ""
-
- def __init__(self):
- title_widget = Padding.push_10(Color.body(Text(self.title)))
- excerpt_widget = Padding.push_10(Color.body(Text(self.excerpt)))
+ def __init__(self, title="Ubuntu Server Installer", excerpt=""):
+ title_widget = Padding.center_79(Color.body(Text(title)))
+ excerpt_widget = Padding.center_79(Color.body(Text(excerpt)))
pile = Pile([Text(""),
title_widget,
Text(""),
@@ -47,20 +45,23 @@ class Footer(WidgetWrap):
"""
- message = ""
-
- def __init__(self):
- border = Text("")
- message_widget = Padding.push_10(Color.body(Text(self.message)))
- status = Pile([border, message_widget])
+ def __init__(self, message=""):
+ message_widget = Padding.center_79(Color.body(Text(message)))
+ status = Pile([Padding.line_break(""), message_widget])
super().__init__(status)
class Body(WidgetWrap):
""" Body widget
"""
+
def __init__(self):
- self.text = [
- Text("Welcome to the Ubuntu Server Installation", align="center")
+ text = [
+ Padding.line_break(""),
+ Padding.center_79(
+ Text("Welcome to the Ubuntu Server Installation",
+ align="center")),
+ Padding.line_break("")
]
- super().__init__(Pile(self.text))
+ w = (SimpleList(text))
+ super().__init__(w)
diff --git a/subiquity/ui/frame.py b/subiquity/ui/frame.py
index 914c38e3..3a17373f 100644
--- a/subiquity/ui/frame.py
+++ b/subiquity/ui/frame.py
@@ -17,11 +17,25 @@
from urwid import Frame, WidgetWrap
from subiquity.ui.anchors import Header, Footer, Body
+import logging
-class BaseFrame(WidgetWrap):
- def __init__(self):
- _frame = Frame(Body(),
- Header(),
- Footer())
- super().__init__(_frame)
+log = logging.getLogger('subiquity.ui.frame')
+
+
+class SubiquityUI(WidgetWrap):
+ def __init__(self, header=None, body=None, footer=None):
+ self.header = header if header else Header()
+ self.body = body if body else Body()
+ self.footer = footer if footer else Footer()
+ self.frame = Frame(self.body, header=self.header, footer=self.footer)
+ super().__init__(self.frame)
+
+ def set_header(self, title, excerpt):
+ self.frame.header = Header(title, excerpt)
+
+ def set_footer(self, message):
+ self.frame.footer = Footer(message)
+
+ def set_body(self, widget):
+ self.frame.body = widget
diff --git a/subiquity/ui/lists.py b/subiquity/ui/lists.py
index fed370b7..6220aa1d 100644
--- a/subiquity/ui/lists.py
+++ b/subiquity/ui/lists.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from urwid import ListBox, SimpleListWalker, WidgetWrap, Button
+from urwid import ListBox, SimpleListWalker, WidgetWrap
class SimpleList(WidgetWrap):
@@ -22,6 +22,6 @@ class SimpleList(WidgetWrap):
super().__init__(self._build_widget())
def _build_widget(self):
- lw = SimpleListWalker([Button(x) for x in self.contents])
+ lw = SimpleListWalker([x for x in self.contents])
return ListBox(lw)
diff --git a/subiquity/ui/utils.py b/subiquity/ui/utils.py
index 4d6ae326..27b70227 100644
--- a/subiquity/ui/utils.py
+++ b/subiquity/ui/utils.py
@@ -16,7 +16,7 @@
""" UI utilities """
from urwid import Padding as _Padding
-from urwid import AttrMap
+from urwid import AttrMap, Text
from functools import partialmethod
from subiquity.palette import STYLES
@@ -108,7 +108,7 @@ class Padding:
"width of 10 columns"))
"""
- pass
+ line_break = partialmethod(Text)
def apply_style_map(cls):
diff --git a/subiquity/views/installpath.py b/subiquity/views/installpath.py
index eed50af4..fd681cb4 100644
--- a/subiquity/views/installpath.py
+++ b/subiquity/views/installpath.py
@@ -13,32 +13,28 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import logging
from urwid import (WidgetWrap, ListBox, Pile, BoxAdapter)
from subiquity.ui.lists import SimpleList
-from subiquity.ui.anchors import Header, Footer, Body # NOQA
-from subiquity.ui.buttons import cancel_btn
+from subiquity.ui.buttons import confirm_btn, cancel_btn
from subiquity.ui.utils import Padding, Color
+log = logging.getLogger('subiquity.installpathView')
+
+
class InstallpathView(WidgetWrap):
- def __init__(self, model, cb=None):
- Header.title = "15.10"
- Header.excerpt = ("Welcome to Ubuntu! The world’s favourite platform "
- "for clouds, clusters and amazing internet things. "
- "This is the installer for Ubuntu on servers and "
- "internet devices.")
- Footer.message = ("Use UP, DOWN arrow keys, and ENTER, to "
- "navigate options..")
+ def __init__(self, model, cb):
+ log.debug("In install path view")
self.model = model
self.cb = cb
self.items = []
- self.layout = [
- Header(),
+ self.body = [
Padding.center_79(self._build_model_inputs()),
+ Padding.line_break(""),
Padding.center_20(self._build_buttons()),
- Footer()
]
- super().__init__(ListBox(self.layout))
+ super().__init__(ListBox(self.body))
def _build_buttons(self):
self.buttons = [
@@ -48,16 +44,17 @@ class InstallpathView(WidgetWrap):
return Pile(self.buttons)
def _build_model_inputs(self):
- sl = SimpleList(self.model.install_paths)
- return BoxAdapter(sl,
- height=len(self.model.install_paths))
+ sl = []
+ for ipath in self.model.install_paths:
+ sl.append(Color.button_primary(confirm_btn(label=ipath,
+ on_press=self.confirm),
+ focus_map='button_primary focus'))
+
+ return BoxAdapter(SimpleList(sl),
+ height=len(sl))
def confirm(self, button):
- if self.cb is not None:
- return self.cb(True, 'Moving to next controller.')
+ return self.cb(button.label)
def cancel(self, button):
- if self.cb is None:
- raise SystemExit('Cancelled.')
- else:
- return self.cb(False, 'Cancelled with callback.')
+ return self.cb(None)
diff --git a/subiquity/views/network.py b/subiquity/views/network.py
new file mode 100644
index 00000000..e5f9b311
--- /dev/null
+++ b/subiquity/views/network.py
@@ -0,0 +1,71 @@
+# 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 .
+
+import logging
+from urwid import (WidgetWrap, ListBox, Pile, BoxAdapter, Text)
+from subiquity.ui.lists import SimpleList
+from subiquity.ui.buttons import confirm_btn, cancel_btn
+from subiquity.ui.utils import Padding, Color
+
+
+log = logging.getLogger('subiquity.networkView')
+
+
+class NetworkView(WidgetWrap):
+ def __init__(self, model, cb):
+ self.model = model
+ self.cb = cb
+ self.items = []
+ self.body = [
+ Padding.center_79(self._build_model_inputs()),
+ Padding.line_break(""),
+ Padding.center_79(self._build_additional_options()),
+ Padding.line_break(""),
+ Padding.center_20(self._build_buttons()),
+ ]
+ super().__init__(ListBox(self.body))
+
+ def _build_buttons(self):
+ buttons = [
+ Color.button_secondary(cancel_btn(on_press=self.cancel),
+ focus_map='button_secondary focus'),
+ ]
+ return Pile(buttons)
+
+ def _build_model_inputs(self):
+ sl = []
+ for iface in self.model.interfaces:
+ sl.append(Color.button_primary(confirm_btn(label=iface,
+ on_press=self.confirm),
+ focus_map='button_primary focus'))
+ sl.append(Padding.push_10(Text("Adapter info")))
+
+ return BoxAdapter(SimpleList(sl),
+ height=len(sl))
+
+ def _build_additional_options(self):
+ opts = []
+ for opt in self.model.additional_options:
+ opts.append(
+ Color.button_secondary(confirm_btn(label=opt,
+ on_press=self.confirm),
+ focus_map='button_secondary focus'))
+ return Pile(opts)
+
+ def confirm(self, button):
+ return self.cb(button.label)
+
+ def cancel(self, button):
+ return self.cb(None)
diff --git a/subiquity/views/welcome.py b/subiquity/views/welcome.py
index d8161f21..c1b1c7eb 100644
--- a/subiquity/views/welcome.py
+++ b/subiquity/views/welcome.py
@@ -15,48 +15,41 @@
from urwid import (WidgetWrap, ListBox, Pile, BoxAdapter)
from subiquity.ui.lists import SimpleList
-from subiquity.ui.anchors import Header, Footer, Body # NOQA
from subiquity.ui.buttons import confirm_btn, cancel_btn
from subiquity.ui.utils import Padding, Color
class WelcomeView(WidgetWrap):
- def __init__(self, model, cb=None):
- Header.title = "Wilkommen! Bienvenue! Welcome! Zdrastvutie! Welkom!"
- Header.excerpt = "Please choose your preferred language"
- Footer.message = ("Use UP, DOWN arrow keys, and ENTER, to "
- "select your language.")
+ def __init__(self, model, cb):
self.model = model
self.cb = cb
self.items = []
- self.layout = [
- Header(),
+ self.body = [
Padding.center_79(self._build_model_inputs()),
+ Padding.line_break(""),
Padding.center_20(self._build_buttons()),
- Footer()
]
- super().__init__(ListBox(self.layout))
+ super().__init__(ListBox(self.body))
def _build_buttons(self):
self.buttons = [
- Color.button_primary(confirm_btn(on_press=self.confirm),
- focus_map='button_primary focus'),
Color.button_secondary(cancel_btn(on_press=self.cancel),
focus_map='button_secondary focus'),
]
return Pile(self.buttons)
def _build_model_inputs(self):
- sl = SimpleList(self.model.supported_languages)
- return BoxAdapter(sl,
- height=len(self.model.supported_languages))
+ sl = []
+ for lang in self.model.supported_languages:
+ sl.append(Color.button_primary(
+ confirm_btn(label=lang, on_press=self.confirm),
+ focus_map="button_primary focus"))
+
+ return BoxAdapter(SimpleList(sl),
+ height=len(sl))
def confirm(self, button):
- if self.cb is not None:
- return self.cb(True, 'Moving to next controller.')
+ return self.cb(button.label)
def cancel(self, button):
- if self.cb is None:
- raise SystemExit('Cancelled.')
- else:
- return self.cb(False, 'Cancelled with callback.')
+ return self.cb(None)