예제 #1
0
    def _device_widget(self, dev, netdev_i=None):
        # 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>
        if netdev_i is None:
            netdev_i = len(self.cur_netdevs)
        self.cur_netdevs[netdev_i:netdev_i] = [dev]

        actions = []
        for action in NetDevAction:
            meth = getattr(self, '_action_' + action.name)
            opens_dialog = getattr(meth, 'opens_dialog', False)
            if dev.supports_action(action):
                actions.append(
                    (_(action.value), True, (action, meth), opens_dialog))

        menu = ActionMenu(actions)
        connect_signal(menu, 'action', self._action, dev)

        trows = [
            make_action_menu_row([
                Text("["),
                Text(dev.name),
                Text(dev.type),
                Text(self._notes_for_device(dev), wrap='clip'),
                menu,
                Text("]"),
            ], menu)
        ] + self._address_rows_for_device(dev)

        table = TablePile(trows, colspecs=self.device_colspecs, spacing=2)
        self.dev_to_table[dev] = table
        table.bind(self.heading_table)

        if dev.type == "vlan":
            info = _("VLAN {id} on interface {link}").format(**dev.config)
        elif dev.type == "bond":
            info = _("bond master for {interfaces}").format(
                interfaces=', '.join(dev.config['interfaces']))
        else:
            info = " / ".join(
                [dev.info.hwaddr, dev.info.vendor, dev.info.model])

        return Pile([
            ('pack', table),
            ('pack', Color.info_minor(Text("  " + info))),
            ('pack', Text("")),
        ])
예제 #2
0
    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))
예제 #3
0
    def __init__(self, parent, snap, cur_channel):
        self.parent = parent
        self.snap = snap
        self.needs_focus = True

        self.description = Text(snap.description.replace('\r', '').strip())
        self.lb_description = ListBox([self.description])

        latest_update = datetime.datetime.min
        radio_group = []
        channel_rows = []
        for csi in snap.channels:
            latest_update = max(latest_update, csi.released_at)
            btn = StarRadioButton(radio_group,
                                  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"))
            channel_rows.append(
                Color.menu_button(
                    TableRow([
                        btn,
                        Text(csi.version),
                        Text("(" + csi.revision + ")"),
                        Text(humanize_size(csi.size)),
                        Text(format_datetime(csi.released_at)),
                        Text(csi.confinement),
                    ])))

        first_info_row = TableRow([
            (3, Text([
                ('info_minor', "LICENSE: "),
                snap.license,
            ],
                     wrap='clip')),
            (3,
             Text([
                 ('info_minor', "LAST UPDATED: "),
                 format_datetime(latest_update),
             ])),
        ])
        heading_row = Color.info_minor(
            TableRow([
                Text("CHANNEL"),
                (2, Text("VERSION")),
                Text("SIZE"),
                Text("PUBLISHED"),
                Text("CONFINEMENT"),
            ]))
        colspecs = {
            1: ColSpec(can_shrink=True),
        }
        info_table = TablePile([
            first_info_row,
            TableRow([Text("")]),
            heading_row,
        ],
                               spacing=2,
                               colspecs=colspecs)
        self.lb_channels = NoTabCyclingTableListBox(channel_rows,
                                                    spacing=2,
                                                    colspecs=colspecs)
        info_table.bind(self.lb_channels)
        self.info_padding = Padding.pull_1(info_table)

        publisher = [('info_minor header', "by: "), snap.publisher]
        if snap.verified:
            publisher.append(('verified header', ' \N{check mark}'))

        self.title = Columns([
            Text(snap.name),
            ('pack', Text(publisher, align='right')),
        ],
                             dividechars=1)

        contents = [
            ('pack', Text(snap.summary)),
            ('pack', Text("")),
            self.lb_description,  # overwritten in render()
            ('pack', Text("")),
            ('pack', self.info_padding),
            ('pack', Text("")),
            ('weight', 1, self.lb_channels),
        ]
        self.description_index = contents.index(self.lb_description)
        self.pile = Pile(contents)
        super().__init__(self.pile)
예제 #4
0
class NetworkDeviceTable(WidgetWrap):
    def __init__(self, parent, dev_info):
        self.parent = parent
        self.dev_info = dev_info
        super().__init__(self._create())

    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 _notes(self):
        notes = []
        if self.dev_info.type == "wlan":
            config = self.dev_info.wlan.config
            if config.ssid is not None:
                notes.append(_("ssid: {ssid}".format(ssid=config.ssid)))
            else:
                notes.append(_("not connected"))
        if not self.dev_info.is_connected:
            notes.append(_("not connected"))
        if self.dev_info.bond_master:
            notes.append(
                _("enslaved to {device}").format(
                    device=self.dev_info.bond_master))
        if notes:
            notes = ", ".join(notes)
        else:
            notes = '-'
        return notes

    def _address_rows(self):
        address_info = []
        for v, dhcp_status, static_config in (
            (4, self.dev_info.dhcp4, self.dev_info.static4),
            (6, self.dev_info.dhcp6, self.dev_info.static6),
        ):
            if dhcp_status.enabled:
                label = Text("DHCPv{v}".format(v=v))
                addrs = dhcp_status.addresses
                if addrs:
                    address_info.extend([(label, Text(addr))
                                         for addr in addrs])
                elif dhcp_status.state == DHCPState.PENDING:
                    s = Spinner(self.parent.controller.app.aio_loop,
                                align='left')
                    s.rate = 0.3
                    s.start()
                    address_info.append((label, s))
                elif dhcp_status.state == DHCPState.TIMED_OUT:
                    address_info.append((label, Text(_("timed out"))))
                elif dhcp_status.state == DHCPState.RECONFIGURE:
                    address_info.append((label, Text("-")))
            elif static_config.addresses:
                address_info.append((
                    Text(_('static')),
                    Text(', '.join(static_config.addresses)),
                ))
        if len(address_info) == 0 and not self.dev_info.is_used:
            reason = self.dev_info.disabled_reason
            if reason is None:
                reason = ""
            address_info.append((Text(_("disabled")), Text(reason)))
        rows = []
        for label, value in address_info:
            rows.append(TableRow([Text(""), label, (2, value)]))
        return rows

    def update(self, dev_info):
        # Update the display of dev to represent the current state.
        #
        # The easiest way of doing this would be to just create a new table
        # widget for the device and replace the current one with it. But that
        # is jarring if the menu for the current device is open, so instead we
        # overwrite the contents of the first (menu) row of the table, and
        # replace all other rows of the with new content (which is OK as they
        # cannot be focused).
        self.dev_info = dev_info
        first_row = self.table.table_rows[0].base_widget
        first_row.cells[1][1].set_text(dev_info.name)
        first_row.cells[2][1].set_text(dev_info.type)
        first_row.cells[3][1].set_text(self._notes())
        self.table.remove_rows(1, len(self.table.table_rows))
        self.table.insert_rows(1, self._address_rows())