Exemple #1
0
class ResultTreeView(HintedTreeView, MultiDragTreeView):
    """The result treeview"""

    def __init__(self, album):
        self.album = album
        self._release = None
        self.model = ObjectStore()
        self.model.append_many(album)

        super(ResultTreeView, self).__init__(self.model)
        self.set_headers_clickable(True)
        self.set_rules_hint(True)
        self.set_reorderable(True)
        self.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)

        mode = Pango.EllipsizeMode
        cols = [
                (_('Filename'), self.__name_datafunc, True, mode.MIDDLE),
                (_('Disc'), self.__disc_datafunc, False, mode.END),
                (_('Track'), self.__track_datafunc, False, mode.END),
                (_('Title'), self.__title_datafunc, True, mode.END),
                (_('Artist'), self.__artist_datafunc, True, mode.END),
            ]

        for title, func, resize, mode in cols:
            render = Gtk.CellRendererText()
            render.set_property('ellipsize', mode)
            col = Gtk.TreeViewColumn(title, render)
            col.set_cell_data_func(render, func)
            col.set_resizable(resize)
            col.set_expand(resize)
            self.append_column(col)

    def iter_tracks(self):
        """Yields tuples of (release, track, song) combinations as they
        are shown in the list.
        """

        tracks = self._tracks
        for idx, (song, ) in enumerate(self.model):
            if song is None:
                continue
            if idx >= len(tracks):
                continue
            track = tracks[idx]
            yield (self._release, track, song)

    def update_release(self, full_release):
        """Updates the TreeView, handling results with a different number of
        tracks than the album being tagged.

        Passing in None will reset the list.
        """

        if full_release is not None:
            tracks = full_release.tracks
        else:
            tracks = []

        for i in range(len(self.model), len(tracks)):
            self.model.append((None, ))
        for i in range(len(self.model), len(tracks), -1):
            if self.model[-1][0] is not None:
                break
            itr = self.model.get_iter_from_string(str(len(self.model) - 1))
            self.model.remove(itr)

        self._release = full_release

        for row in self.model:
            self.model.row_changed(row.path, row.iter)

        # Only show artists if we have any
        has_artists = bool(filter(lambda t: t.artists, tracks))
        col = self.get_column(4)
        col.set_visible(has_artists)

        # Only show discs column if we have more than one disc
        col = self.get_column(1)
        col.set_visible(
            bool(full_release) and bool(full_release.disc_count > 1))

        self.columns_autosize()

    @property
    def _tracks(self):
        if self._release is None:
            return []
        return self._release.tracks

    def __name_datafunc(self, col, cell, model, itr, data):
        song = model[itr][0]
        if song:
            cell.set_property('text', path.fsdecode(song("~basename")))
        else:
            cell.set_property('text', '')

    def __track_datafunc(self, col, cell, model, itr, data):
        idx = model.get_path(itr)[0]
        if idx >= len(self._tracks):
            cell.set_property('text', '')
        else:
            cell.set_property('text', self._tracks[idx].tracknumber)

    def __disc_datafunc(self, col, cell, model, itr, data):
        idx = model.get_path(itr)[0]
        if idx >= len(self._tracks):
            cell.set_property('text', '')
        else:
            cell.set_property('text', self._tracks[idx].discnumber)

    def __title_datafunc(self, col, cell, model, itr, data):
        idx = model.get_path(itr)[0]
        if idx >= len(self._tracks):
            cell.set_property('text', '')
        else:
            cell.set_property('text', self._tracks[idx].title)

    def __artist_datafunc(self, col, cell, model, itr, data):
        idx = model.get_path(itr)[0]
        if idx >= len(self._tracks):
            cell.set_property('text', '')
        else:
            names = [a.name for a in self._tracks[idx].artists]
            cell.set_property('text', ", ".join(names))
Exemple #2
0
class ResultTreeView(HintedTreeView, MultiDragTreeView):
    """The result treeview"""
    def __init__(self, album):
        self.album = album
        self._release = None
        self.model = ObjectStore()
        self.model.append_many(album)

        super(ResultTreeView, self).__init__(self.model)
        self.set_headers_clickable(True)
        self.set_rules_hint(True)
        self.set_reorderable(True)
        self.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)

        mode = Pango.EllipsizeMode
        cols = [
            (_('Filename'), self.__name_datafunc, True, mode.MIDDLE),
            (_('Disc'), self.__disc_datafunc, False, mode.END),
            (_('Track'), self.__track_datafunc, False, mode.END),
            (_('Title'), self.__title_datafunc, True, mode.END),
            (_('Artist'), self.__artist_datafunc, True, mode.END),
        ]

        for title, func, resize, mode in cols:
            render = Gtk.CellRendererText()
            render.set_property('ellipsize', mode)
            col = Gtk.TreeViewColumn(title, render)
            col.set_cell_data_func(render, func)
            col.set_resizable(resize)
            col.set_expand(resize)
            self.append_column(col)

    def iter_tracks(self):
        """Yields tuples of (release, track, song) combinations as they
        are shown in the list.
        """

        tracks = self._tracks
        for idx, (song, ) in enumerate(self.model):
            if song is None:
                continue
            if idx >= len(tracks):
                continue
            track = tracks[idx]
            yield (self._release, track, song)

    def update_release(self, full_release):
        """Updates the TreeView, handling results with a different number of
        tracks than the album being tagged.

        Passing in None will reset the list.
        """

        if full_release is not None:
            tracks = full_release.tracks
        else:
            tracks = []

        for i in range(len(self.model), len(tracks)):
            self.model.append((None, ))
        for i in range(len(self.model), len(tracks), -1):
            if self.model[-1][0] is not None:
                break
            itr = self.model.get_iter_from_string(str(len(self.model) - 1))
            self.model.remove(itr)

        self._release = full_release

        for row in self.model:
            self.model.row_changed(row.path, row.iter)

        # Only show artists if we have any
        has_artists = bool(filter(lambda t: t.artists, tracks))
        col = self.get_column(4)
        col.set_visible(has_artists)

        # Only show discs column if we have more than one disc
        col = self.get_column(1)
        col.set_visible(
            bool(full_release) and bool(full_release.disc_count > 1))

        self.columns_autosize()

    @property
    def _tracks(self):
        if self._release is None:
            return []
        return self._release.tracks

    def __name_datafunc(self, col, cell, model, itr, data):
        song = model[itr][0]
        if song:
            cell.set_property('text', fsn2text(song("~basename")))
        else:
            cell.set_property('text', '')

    def __track_datafunc(self, col, cell, model, itr, data):
        idx = model.get_path(itr)[0]
        if idx >= len(self._tracks):
            cell.set_property('text', '')
        else:
            cell.set_property('text', self._tracks[idx].tracknumber)

    def __disc_datafunc(self, col, cell, model, itr, data):
        idx = model.get_path(itr)[0]
        if idx >= len(self._tracks):
            cell.set_property('text', '')
        else:
            cell.set_property('text', self._tracks[idx].discnumber)

    def __title_datafunc(self, col, cell, model, itr, data):
        idx = model.get_path(itr)[0]
        if idx >= len(self._tracks):
            cell.set_property('text', '')
        else:
            cell.set_property('text', self._tracks[idx].title)

    def __artist_datafunc(self, col, cell, model, itr, data):
        idx = model.get_path(itr)[0]
        if idx >= len(self._tracks):
            cell.set_property('text', '')
        else:
            names = [a.name for a in self._tracks[idx].artists]
            cell.set_property('text', ", ".join(names))
Exemple #3
0
class MatchListsTreeView(HintedTreeView, Generic[T]):
    _b_order: List[Optional[int]]

    def __init__(self, a_items: List[T], b_items: List[T],
                 columns: List[ColumnSpec[T]]):
        self.model = ObjectStore()
        self.model.append_many(a_items)
        self._b_items = b_items

        super().__init__(self.model)
        self.set_headers_clickable(False)
        self.set_rules_hint(True)
        self.set_reorderable(False)
        self.get_selection().set_mode(Gtk.SelectionMode.NONE)

        def show_id(col, cell, model, itr, data):
            idx = model.get_path(itr)[0]
            imp_idx = self._b_order[idx]
            num = '_' if imp_idx is None else imp_idx + 1
            cell.set_property('markup', f'<span weight="bold">{num}</span>')

        def df_for_a_items(a_attr_getter):
            def data_func(col, cell, model, itr, data):
                a_item = model[itr][0]
                text = ''
                if a_item is not None:
                    text = a_attr_getter(a_item)
                cell.set_property('text', text)

            return data_func

        def df_for_b_items(b_attr_getter):
            def data_func(col, cell, model, itr, data):
                self._set_text(model, itr, cell, b_attr_getter)

            return data_func

        for c in columns:
            self._add_col(c.title, df_for_a_items(c.cell_text_getter),
                          c.is_resizable)

        self._add_col('#', show_id, False)

        for c in columns:
            self._add_col(c.title, df_for_b_items(c.cell_text_getter),
                          c.is_resizable)

        self._b_order = []  # Initialize the backing field of b_order
        self.b_order = list(range(len(b_items)))  # Update it and rows

        self.update_b_items(b_items)

    def _add_col(self, title, func, resize):
        render = Gtk.CellRendererText()
        render.set_property('ellipsize', Pango.EllipsizeMode.END)
        col = Gtk.TreeViewColumn(title, render)
        col.set_cell_data_func(render, func)
        col.set_resizable(resize)
        col.set_expand(resize)
        self.append_column(col)

    def _set_text(self, model, itr, cell, get_attr):
        idx = model.get_path(itr)[0]
        text = ''
        if idx < len(self._b_order):
            it_idx = self._b_order[idx]
            if it_idx is not None:
                text = get_attr(self._b_items[it_idx])
        cell.set_property('text', text)

    def update_b_items(self, b_items: List[T]):
        """
        Updates the TreeView, handling results with a different number of b_items than
        there are a_items.
        """
        self._b_items = b_items

        for i in range(len(self.model), len(b_items)):
            self.model.append((None, ))

        for i in range(len(self.model), len(b_items), -1):
            if self.model[-1][0] is not None:
                break
            itr = self.model.get_iter_from_string(str(len(self.model) - 1))
            self.model.remove(itr)

        self._rows_changed()
        self.columns_autosize()

    def _rows_changed(self):
        for row in self.model:
            self.model.row_changed(row.path, row.iter)

    @property
    def b_order(self) -> List[Optional[int]]:
        return list(self._b_order)

    @b_order.setter
    def b_order(self, order: List[Optional[int]]):
        """
        Supports a partial order list. For example, if there are 5 elements in the
        b_items list, you could supply [4, 1, 2]. This will result in an ascending order
        for the last 2 rows, so [0, 3].
        """
        if order == self._b_order:
            return

        b_len = len(self._b_items)
        if len(order) < b_len:
            # add missing indices
            for i in range(b_len):
                if i not in order:
                    order.append(i)

        while len(order) < len(self.model):
            order.append(None)

        self._b_order = order
        self._rows_changed()