def __init__(self, model, controller): self.model = model self.controller = controller cancel = cancel_btn(_("Cancel"), on_press=self.cancel) disks = [] for disk in self.model.all_disks(): label = "%-42s %s" % (disk.label, humanize_size(disk.size).rjust(9)) if disk.size >= model.lower_size_limit: disk_btn = forward_btn(label, on_press=self.choose_disk, user_arg=disk) else: disk_btn = Color.info_minor(Text(" "+label)) disks.append(disk_btn) body = Pile([ ('pack', Text("")), ('pack', Padding.center_70( Text(_("Choose the disk to install to:")))), ('pack', Text("")), Padding.center_70(ListBox(disks)), ('pack', Text("")), ('pack', button_pile([cancel])), ('pack', Text("")), ]) super().__init__(body)
def _build_disk_selection(self): log.debug('raid: _build_disk_selection') items = [Text("DISK SELECTION")] # raid can use empty whole disks, or empty partitions avail_disks = self.model.get_empty_disk_names() avail_parts = self.model.get_empty_partition_names() avail_devs = sorted(avail_disks + avail_parts) if len(avail_devs) == 0: return items.append( [Color.info_minor(Text("No available disks."))]) for dname in avail_devs: device = self.model.get_disk(dname) if device.path != dname: # we've got a partition raiddev = device.get_partition(dname) else: raiddev = device disk_sz = _humanize_size(raiddev.size) disk_string = "{} {}, {}".format(dname, disk_sz, device.model) log.debug('raid: disk_string={}'.format(disk_string)) self.selected_disks.append(CheckBox(disk_string)) items += self.selected_disks return Pile(items)
def __init__(self, model, controller, name): self.model = model self.controller = controller self.dev = self.model.get_netdev_by_name(name) self.form = WLANForm() connect_signal(self.form, 'submit', self.done) connect_signal(self.form, 'cancel', self.cancel) if self.dev.configured_ssid is not None: self.form.ssid.value = self.dev.configured_ssid if self.dev.configured_wifi_psk is not None: self.form.psk.value = self.dev.configured_wifi_psk self.ssid_row = self.form.ssid.as_row(self, self.form.longest_caption) self.psk_row = self.form.psk.as_row(self, self.form.longest_caption) self.inputs = Pile(self._build_iface_inputs()) self.error = Text("") self.body = Pile([ ('pack', Text("")), ListBox([Padding.center_79(self.inputs)]), ('pack', Pile([ ('pack', Text("")), Padding.center_79(Color.info_error(self.error)), self.form.buttons, ('pack', Text("")), ])), ]) self.orig_w = None super().__init__(self.body)
def __init__(self, parent, device): self.parent = parent self.device = device title = _("Network interface {} WIFI configuration").format( device.name) self.form = WLANForm() connect_signal(self.form, 'submit', self.done) connect_signal(self.form, 'cancel', self.cancel) if self.device.configured_ssid is not None: self.form.ssid.value = self.device.configured_ssid if self.device.configured_wifi_psk is not None: self.form.psk.value = self.device.configured_wifi_psk self.ssid_row = self.form.ssid._table self.psk_row = self.form.psk._table self.ssid_row.bind(self.psk_row) self.inputs = Pile(self._build_iface_inputs()) self.error = Text("") widgets = [ self.inputs, Padding.center_79(Color.info_error(self.error)), self.form.buttons, ] super().__init__(title, widgets, 0, 0)
def make_main_screen(self, snap_list): self.snap_boxes = {} body = [] preinstalled = self.get_preinstalled_snaps() for snap in snap_list: if snap.name in preinstalled: log.debug("not offering preseeded snap %r", snap.name) continue box = self.snap_boxes[snap.name] = SnapCheckBox(self, snap) row = [ box, Text(snap.publisher), Text(snap.summary, wrap='clip'), ] body.append(Color.menu_button(TableRow(row))) table = NoTabCyclingTableListBox(body, colspecs={ 1: ColSpec(omittable=True), 2: ColSpec(pack=False, min_width=40), }) ok = ok_btn(label=_("Done"), on_press=self.done) cancel = cancel_btn(label=_("Back"), on_press=self.cancel) self._main_screen = screen( table, [ok, cancel], focus_buttons=False, excerpt=_( "These are popular snaps in server environments. Select or " "deselect with SPACE, press ENTER to see more details of the " "package, publisher and versions available."))
def make_main_screen(self, snap_list): self.snap_boxes = {} body = [] for snap in snap_list: box = self.snap_boxes[snap.name] = SnapCheckBox(self, snap) row = [ box, Text(snap.publisher), Text(snap.summary, wrap='clip'), ] body.append(Color.menu_button(TableRow(row))) table = NoTabCyclingTableListBox(body, colspecs={ 1: ColSpec(omittable=True), 2: ColSpec(pack=False, min_width=40), }) ok = ok_btn(label=_("OK"), on_press=self.done) self._main_screen = screen( table, [ok], focus_buttons=False, excerpt=_( "These are popular snaps in server environments. Select or " "deselect with SPACE, press ENTER to see more details of the " "package, publisher and versions available."))
def __init__(self, parent, setting): self.parent = parent self.setting = setting self.selector = Selector(toggle_options) self.selector.value = 'alt_shift_toggle' if self.parent.model.setting.toggle: try: self.selector.value = self.parent.model.setting.toggle except AttributeError: pass widgets = [ Text(_(toggle_text)), Text(""), Padding.center_79( Columns([ ('pack', Text(_("Shortcut: "))), Color.string_input(self.selector), ])), Text(""), button_pile([ ok_btn(label=_("OK"), on_press=self.ok), cancel_btn(label=_("Cancel"), on_press=self.cancel), ]), ] super().__init__(_("Select layout toggle"), widgets, stretchy_index=0, focus_index=4)
def summarize_device(device, part_filter=lambda p: True): """Return content for a table summarizing device. This (obj, cells) where obj is either device itself, a partition of device or None and cells is part of an argument to TableRow that will span 4 columns that describes device or a partition of device. This sounds a bit strange but hopefully you can figure it out by looking at the uses of this function. """ label = device.label if device.annotations: label = "{} ({})".format(label, ", ".join(device.annotations)) rows = [(device, [ (2, Text(label)), Text(device.desc()), Text(humanize_size(device.size), align="right"), ])] partitions = device.partitions() if partitions: for part in device.partitions(): if not part_filter(part): continue details = ", ".join(part.annotations + part.usage_labels()) rows.append((part, [ Text(part.short_label), (2, Text(details)), Text(humanize_size(part.size), align="right"), ])) else: rows.append((None, [ (4, Color.info_minor(Text(", ".join(device.usage_labels())))) ])) return rows
def show_network_error(self, action, info=None): self.error_showing = True self.bottom.contents[0:0] = [ (Color.info_error(self.error), self.bottom.options()), (Text(""), self.bottom.options()), ] if action == 'stop-networkd': exc = info[0] self.error.set_text("Stopping systemd-networkd-failed: %r" % (exc.stderr, )) elif action == 'apply': self.error.set_text("Network configuration could not be applied; " "please verify your settings.") elif action == 'timeout': self.error.set_text("Network configuration timed out; " "please verify your settings.") elif action == 'down': self.error.set_text("Downing network interfaces failed.") elif action == 'add-vlan': self.error.set_text("Failed to add a VLAN tag.") elif action == 'rm-dev': self.error.set_text("Failed to delete a virtual interface.") else: self.error.set_text("An unexpected error has occurred; " "please verify your settings.")
def _action_menu_for_device(self, device): device_actions = [] for action in device.supported_actions: label = _(action.value) if action == DeviceAction.REMOVE and device.constructed_device(): cd = device.constructed_device() label = _("Remove from {}").format(cd.desc()) enabled, whynot = device.action_possible(action) if whynot: assert not enabled enabled = True label += " *" meth = _whynot_shower(self.parent, action, whynot) else: meth_name = '_{}_{}'.format(device.type, action.name) meth = getattr(self, meth_name) if not whynot and action == DeviceAction.DELETE: label = Color.danger_button(ActionMenuOpenButton(label)) device_actions.append(Action( label=label, enabled=enabled, value=(action, meth), opens_dialog=getattr(meth, 'opens_dialog', False))) menu = ActionMenu(device_actions) connect_signal(menu, 'action', self._action, device) return menu
def _build_model_inputs(self): netdevs = self.model.get_all_netdevs() ifname_width = 8 # default padding if netdevs: ifname_width += max(map(lambda dev: len(dev.name), netdevs)) if ifname_width > 20: ifname_width = 20 iface_menus = [] # Display each interface -- name in first column, then configured IPs # in the second. log.debug('interfaces: {}'.format(netdevs)) for dev in netdevs: col_1 = [] col_2 = [] col_1.append( Color.menu_button( menu_btn(label=dev.name, on_press=self.on_net_dev_press))) if dev.type == 'wlan': col_2.extend(_build_wifi_info(dev)) if len(dev.actual_ip_addresses) == 0 and dev.type == 'eth' and not dev.is_connected: col_2.append(Color.info_primary(Text("Not connected"))) col_2.extend(_build_gateway_ip_info_for_version(dev, 4)) col_2.extend(_build_gateway_ip_info_for_version(dev, 6)) # Other device info (MAC, vendor/model, speed) template = '' if dev.hwaddr: template += '{} '.format(dev.hwaddr) if dev.is_bond_slave: template += '(Bonded) ' if not dev.vendor.lower().startswith('unknown'): vendor = textwrap.wrap(dev.vendor, 15)[0] template += '{} '.format(vendor) if not dev.model.lower().startswith('unknown'): model = textwrap.wrap(dev.model, 20)[0] template += '{} '.format(model) if dev.speed: template += '({})'.format(dev.speed) col_2.append(Color.info_minor(Text(template))) iface_menus.append(Columns([(ifname_width, Pile(col_1)), Pile(col_2)], 2)) return iface_menus
def __init__(self, parent, snap, cur_channel): self.parent = parent self.snap = snap self.channels = [] self.needs_focus = True channel_width = (max(len(csi.channel_name) for csi in snap.channels) + StarRadioButton.reserve_columns + 1) max_version = max(len(csi.version) for csi in snap.channels) max_revision = max(len(str(csi.revision)) for csi in snap.channels) + 2 max_size = max(len(humanize_size(csi.size)) for csi in snap.channels) self.description = Text(snap.description.replace('\r', '').strip()) self.lb_description = ListBox([self.description]) radio_group = [] for csi in snap.channels: notes = '-' if csi.confinement != "strict": notes = csi.confinement btn = StarRadioButton(radio_group, "{}:".format(csi.channel_name), state=csi.channel_name == cur_channel, on_state_change=self.state_change, user_data=SnapSelection( channel=csi.channel_name, is_classic=csi.confinement == "classic")) self.channels.append( Color.menu_button( Columns([ (channel_width, btn), (max_version, Text(csi.version)), (max_revision, Text("({})".format(csi.revision))), (max_size, Text(humanize_size(csi.size))), ('pack', Text(notes)), ], dividechars=1))) self.lb_channels = NoTabCyclingListBox(self.channels) title = Columns([ Text(snap.name), ('pack', Text(_("Publisher: {}").format(snap.publisher), align='right')), ], dividechars=1) contents = [ ('pack', title), ('pack', Text("")), ('pack', Text(snap.summary)), ('pack', Text("")), self.lb_description, # overwritten in render() ('pack', Text("")), ('weight', 1, self.lb_channels), ] self.description_index = contents.index(self.lb_description) self.pile = Pile(contents) super().__init__(self.pile)
def _build_model_inputs(self): sl = [] for lang in self.model.get_menu(): sl.append( Color.menu_button(menu_btn(label=lang, on_press=self.confirm), focus_map="menu_button focus")) return BoxAdapter(SimpleList(sl), height=len(sl))
def _build_additional_options(self): labels = [] netdevs = self.model.get_all_netdevs() # Display default route status if self.model.default_v4_gateway is not None: v4_route_source = "via " + self.model.default_v4_gateway default_v4_route_w = Color.info_minor( Text(" IPv4 default route " + v4_route_source + ".")) labels.append(default_v4_route_w) if self.model.default_v6_gateway is not None: v6_route_source = "via " + self.model.default_v6_gateway default_v6_route_w = Color.info_minor( Text(" IPv6 default route " + v6_route_source + ".")) labels.append(default_v6_route_w) max_btn_len = 0 buttons = [] for opt, sig in self.model.get_menu(): if ':set-default-route' in sig: if len(netdevs) < 2: log.debug('Skipping default route menu option' ' (only one nic)') continue if ':bond-interfaces' in sig: not_bonded = [dev for dev in netdevs if not dev.is_bonded] if len(not_bonded) < 2: log.debug('Skipping bonding menu option' ' (not enough available nics)') continue if len(opt) > max_btn_len: max_btn_len = len(opt) buttons.append( Color.menu_button( menu_btn(label=opt, on_press=self.additional_menu_select, user_data=sig))) from urwid import Padding buttons = [ Padding(button, align='left', width=max_btn_len + 6) for button in buttons ] return labels + buttons
def show_edit_default_route(self, btn): log.debug("Re-rendering specify default route") self.default_gateway_w = StringEditor( caption="Default gateway will be ") self.gateway_options.contents[-1] = (Padding.center_50( Color.string_input(self.default_gateway_w, focus_map="string_input focus")), self.gateway_options.options())
def _build_ipv6_method_buttons(self): button_padding = 70 buttons = [] btn = menu_btn(label="Use a static IPv6 configuration", on_press=self.show_ipv6_configuration) buttons.append(Color.menu_button(btn)) btn = menu_btn(label="Use DHCPv6 on this interface", on_press=self.enable_dhcp6) buttons.append(Color.menu_button(btn)) btn = menu_btn(label="Do not use", on_press=self.clear_ipv6) buttons.append(Color.menu_button(btn)) padding = getattr(Padding, 'left_{}'.format(button_padding)) buttons = [padding(button) for button in buttons] return buttons
def _build_model_inputs(self): rows = [] rows.append(TableRow([ Color.info_minor(Text(header)) for header in ["", "NAME", "TYPE", "NOTES / ADDRESSES", ""]])) for dev in self.model.get_all_netdevs(): rows.extend(self._rows_for_device(dev)) return rows
def set_bound_form_field(self, bff): super().set_bound_form_field(bff) self.all_rows = [] for kind, device in bff.form.all_devices: if kind == LABEL: self.all_rows.append(TableRow([ Text(" " + device.label), Text(humanize_size(device.size), align='right') ])) self.no_selector_rows.append(self.all_rows[-1]) self.all_rows.append(TableRow([ (2, Color.info_minor(Text(" " + device.desc()))) ])) self.no_selector_rows.append(self.all_rows[-1]) else: if kind == DEVICE: label = device.label prefix = " " elif kind == PART: label = _(" partition {}").format(device._number) prefix = " " else: raise Exception("unexpected kind {}".format(kind)) box = CheckBox( label, on_state_change=self._state_change_device, user_data=device) self.device_to_checkbox[device] = box size = Text(humanize_size(device.size), align='right') self.all_rows.append(Color.menu_button(TableRow([box, size]))) self.no_selector_rows.append(self.all_rows[-1]) selector = Selector(['active', 'spare']) connect_signal( selector, 'select', self._select_active_spare, device) selector = Toggleable( UrwidPadding( Color.menu_button(selector), left=len(prefix))) selector.disable() self.device_to_selector[device] = selector self.all_rows.append(TableRow([(2, selector)])) # Do not append that one to no_selector_rows! self.all_rows.append(self._summarize(prefix, device)) self.no_selector_rows.append(self.all_rows[-1]) self.table.set_contents(self.all_rows) log.debug("%s", self.table._w.focus_position)
def __init__(self): choices = [ (_("No"), True, None), (_("from Github"), True, "gh"), (_("from Launchpad"), True, "lp"), (_("from Ubuntu One account"), True, "sso"), ] self.selector = Selector(choices) connect_signal(self.selector, 'select', self._select) self.username = UsernameEditor() self.email = EmailEditor() connect_signal(self.username, 'change', self._change) self.cols = Columns([ self.selector, (1, Text("")), (2, Color.body(Text(""))), Color.body(Text("")) ]) super().__init__(self.cols)
def __init__(self): self.header = Header("", self.right_icon) self.pile = Pile([ ('pack', self.header), ListBox([Text("")]), ]) self.pile.focus_position = 1 super().__init__(Color.body(self.pile))
def __init__(self): self.header = Header("") self.body = Body() self.footer = Footer("", 0, 1) self.frame = Frame(self.body, header=self.header, footer=self.footer) self.progress_current = 0 self.progress_completion = 0 super().__init__(Color.body(self.frame))
def _build_model_inputs(self): sl = Padding.center_79( Columns([ ("weight", 0.2, Text("Email address:", align="right")), ("weight", 0.3, Color.string_input(self.email)), ], dividechars=4)) return sl
def __init__(self, title, right_icon): if isinstance(title, str): title = Text(title) title = HeaderColumns([ Text(""), title, right_icon, Text(""), ]) super().__init__( Pile([ (1, Color.frame_header_fringe(SolidFill("\N{lower half block}"))), Color.frame_header(title), (1, Color.frame_header_fringe(SolidFill("\N{upper half block}"))), ]))
def __init__(self, title): super().__init__( Color.frame_header( Pile([ Text(""), Padding.center_79(Text(title)), Text(""), ])))
def _build_model_inputs(self): items = [ Columns([("weight", 0.2, Text("iSCSI Server Host", align="right")), ("weight", 0.3, Color.string_input(self.iscsi_host))], dividechars=4), Columns( [("weight", 0.2, Text("Connect anonymously", align="right")), ("weight", 0.3, Color.string_input(Pile(self.connect_anon.group)))], dividechars=4), Columns( [("weight", 0.2, Text("Connect as user", align="right")), ("weight", 0.3, Color.string_input(self.connect_username))], dividechars=4), Columns( [("weight", 0.2, Text("Password", align="right")), ("weight", 0.3, Color.string_input(self.connect_password))], dividechars=4), Columns( [("weight", 0.2, Text("Require server auth", align="right")), ("weight", 0.3, Color.string_input(Pile(self.server_auth.group)))], dividechars=4), Columns( [("weight", 0.2, Text("Server identity", align="right")), ("weight", 0.3, Color.string_input(self.server_username))], dividechars=4), Columns( [("weight", 0.2, Text("Server password", align="right")), ("weight", 0.3, Color.string_input(self.server_password))], dividechars=4) ] return Pile(items)
def make_body(self): self.error_text = Text("", align="center") return Pile([ Text(_("Please press one of the following keys:")), Text(""), Columns([Text(s, align="center") for s in self.step.symbols], dividechars=1), Text(""), Color.info_error(self.error_text), ])
def _build_lvm_configuration(self): log.debug('lvm: _build_lvm_config') items = [ Text("LVM VOLUMEGROUP CONFIGURATION"), Columns([("weight", 0.2, Text("VolumeGroup Name", align="right")), ("weight", 0.3, Color.string_input(self.volgroup))], dividechars=4), ] return Pile(items)
def _build_buttons(self): log.debug('FileSystemView: building buttons') buttons = [] # don't enable done botton if we can't install if self.model.installable(): buttons.append( Color.button(done_btn(on_press=self.done), focus_map='button focus')) buttons.append( Color.button(reset_btn(on_press=self.reset), focus_map='button focus')) buttons.append( Color.button(cancel_btn(on_press=self.cancel), focus_map='button focus')) return Pile(buttons)
def _create(self): # Create the widget for a nic. This consists of a Pile containing a # table, an info line and a blank line. The first row of the table is # the one that can be focused and has a menu for manipulating the nic, # the other rows summarize its address config. # [ name type notes ▸ ] \ # address info | <- table # more address info / # mac / vendor info / model info # <blank line> actions = [] for action in NetDevAction: meth = getattr(self.parent, '_action_' + action.name) opens_dialog = getattr(meth, 'opens_dialog', False) if action in self.dev_info.enabled_actions: actions.append( (action.str(), True, (action, meth), opens_dialog)) menu = ActionMenu(actions) connect_signal(menu, 'action', self.parent._action, self) trows = [ make_action_menu_row([ Text("["), Text(self.dev_info.name), Text(self.dev_info.type), Text(self._notes(), wrap='clip'), menu, Text("]"), ], menu) ] + self._address_rows() self.table = TablePile(trows, colspecs=self.parent.device_colspecs, spacing=2) self.table.bind(self.parent.heading_table) if self.dev_info.type == "vlan": info = _("VLAN {id} on interface {link}").format( id=self.dev_info.vlan.id, link=self.dev_info.vlan.link) elif self.dev_info.type == "bond": info = _("bond master for {interfaces}").format( interfaces=', '.join(self.dev_info.bond.interfaces)) else: info = " / ".join([ self.dev_info.hwaddr, self.dev_info.vendor, self.dev_info.model, ]) return Pile([ ('pack', self.table), ('pack', Color.info_minor(Text(" " + info))), ('pack', Text("")), ])
def __init__(self, controller, netdev_infos): self.controller = controller self.dev_name_to_table = {} self.cur_netdev_names = [] self.error = Text("", align='center') self.device_colspecs = { 0: ColSpec(rpad=1), 3: ColSpec(min_width=15), 4: ColSpec(can_shrink=True, rpad=1), } self.heading_table = TablePile([ TableRow([ Color.info_minor(Text(header)) for header in [ "", "NAME", "TYPE", "NOTES", "", ] ]) ], spacing=2, colspecs=self.device_colspecs) self.device_pile = Pile([self.heading_table]) for dev_info in netdev_infos: self.new_link(dev_info) self._create_bond_btn = menu_btn(_("Create bond"), on_press=self._create_bond) bp = button_pile([self._create_bond_btn]) bp.align = 'left' rows = [ self.device_pile, bp, ] self.buttons = button_pile([ done_btn("TBD", on_press=self.done), # See _route_watcher back_btn(_("Back"), on_press=self.cancel), ]) self.bottom = Pile([ ('pack', self.buttons), ]) self.error_showing = False super().__init__( screen(rows=rows, buttons=self.bottom, focus_buttons=True, excerpt=_(self.excerpt)))