Exemplo n.º 1
0
class SnapInfoView(WidgetWrap):

    # This is mostly like a Pile but it tries to be a bit smart about
    # how to distribute space between the description and channel list
    # (which can both be arbitrarily long or short). If both are long,
    # the channel list is given a third of the space. If there is
    # space for both, they are packed into the upper part of the view.

    def __init__(self, parent, snap, cur_channel):
        self.parent = parent
        self.snap = snap
        self.channels = []
        self.needs_focus = True

        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(
                    TableRow([
                        btn,
                        Text(csi.version),
                        Text("({})".format(csi.revision)),
                        Text(humanize_size(csi.size)),
                        Text(notes),
                    ])))

        self.lb_channels = NoTabCyclingTableListBox(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 state_change(self, sender, state, selection):
        if state:
            self.parent.snap_boxes[self.snap.name].set_state(True)
            self.parent.to_install[self.snap.name] = selection

    def render(self, size, focus):
        maxcol, maxrow = size

        rows_available = maxrow
        pack_option = self.pile.options('pack')
        for w, o in self.pile.contents:
            if o == pack_option:
                rows_available -= w.rows((maxcol, ), focus)

        rows_wanted_description = self.description.rows((maxcol, ), False)
        rows_wanted_channels = len(self.channels)

        if rows_wanted_channels + rows_wanted_description <= rows_available:
            description_rows = rows_wanted_description
        else:
            if rows_wanted_description < 2 * rows_available / 3:
                description_rows = rows_wanted_description
            else:
                channel_rows = min(rows_wanted_channels,
                                   int(rows_available / 3))
                description_rows = rows_available - channel_rows

        self.pile.contents[self.description_index] = (self.lb_description,
                                                      self.pile.options(
                                                          'given',
                                                          description_rows))
        if description_rows >= rows_wanted_description:
            self.lb_description.base_widget._selectable = False
        else:
            self.lb_description.base_widget._selectable = True
        if self.needs_focus:
            self.pile._select_first_selectable()
            self.needs_focus = False
        return self.pile.render(size, focus)
Exemplo n.º 2
0
class SnapInfoView(WidgetWrap):

    # This is mostly like a Pile but it tries to be a bit smart about
    # how to distribute space between the description and channel list
    # (which can both be arbitrarily long or short). If both are long,
    # the channel list is given a third of the space. If there is
    # space for both, they are packed into the upper part of the view.

    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)

    def state_change(self, sender, state, selection):
        if state:
            self.parent.snap_boxes[self.snap.name].set_state(True)
            self.parent.to_install[self.snap.name] = selection

    def render(self, size, focus):
        maxcol, maxrow = size

        rows_available = maxrow
        pack_option = self.pile.options('pack')
        for w, o in self.pile.contents:
            if o == pack_option:
                rows_available -= w.rows((maxcol, ), focus)

        rows_wanted_description = self.description.rows((maxcol - 1, ), False)
        rows_wanted_channels = 0
        for row in self.lb_channels._w.original_widget.body:
            rows_wanted_channels += row.rows((maxcol, ), False)

        log.debug('rows_available %s', rows_available)
        log.debug('rows_wanted_description %s rows_wanted_channels %s',
                  rows_wanted_description, rows_wanted_channels)

        if rows_wanted_channels + rows_wanted_description <= rows_available:
            description_rows = rows_wanted_description
            channel_rows = rows_wanted_channels
        else:
            if rows_wanted_description < 2 * rows_available / 3:
                description_rows = rows_wanted_description
                channel_rows = rows_available - description_rows
            else:
                channel_rows = max(
                    min(rows_wanted_channels, int(rows_available / 3)), 3)
                log.debug('channel_rows %s', channel_rows)
                description_rows = rows_available - channel_rows

        self.pile.contents[self.description_index] = (self.lb_description,
                                                      self.pile.options(
                                                          'given',
                                                          description_rows))
        if description_rows >= rows_wanted_description:
            self.lb_description.base_widget._selectable = False
        else:
            self.lb_description.base_widget._selectable = True
        if channel_rows >= rows_wanted_channels:
            self.info_padding.right = 0
        else:
            self.info_padding.right = 1
        if self.needs_focus:
            self.pile._select_first_selectable()
            self.needs_focus = False
        return self.pile.render(size, focus)