Beispiel #1
0
 def test_main(self):
     TreeViewColumn(title="foo")
     area = Gtk.CellAreaBox()
     tvc = TreeViewColumn(cell_area=area)
     self.assertEqual(tvc.get_area(), area)
Beispiel #2
0
    def __init__(self, initial=None, filter=filesel_filter, folders=None):
        """
        initial -- a path to a file which should be shown initially
        filter -- a function which filters paths shown in the file list
        folders -- list of shown folders in the directory tree
        """

        super().__init__(orientation=Gtk.Orientation.VERTICAL)
        self.__filter = filter

        if initial is not None:
            assert isinstance(initial, fsnative)

        if initial and os.path.isfile(initial):
            initial = os.path.dirname(initial)
        dirlist = DirectoryTree(initial, folders=folders)

        model = ObjectStore()
        filelist = AllTreeView(model=model)
        filelist.connect("draw", self.__restore_scroll_pos_on_draw)

        column = TreeViewColumn(title=_("Songs"))
        column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        render = Gtk.CellRendererPixbuf()
        render.props.xpad = 3

        def cell_icon(column, cell, model, iter_, userdata):
            value = model.get_value(iter_)
            if is_image(value):
                cell.set_property('icon-name', Icons.IMAGE_X_GENERIC)
            else:
                cell.set_property('icon-name', Icons.AUDIO_X_GENERIC)

        column.set_cell_data_func(render, cell_icon)

        column.pack_start(render, False)
        render = Gtk.CellRendererText()
        if filelist.supports_hints():
            render.set_property('ellipsize', Pango.EllipsizeMode.END)
        column.pack_start(render, True)

        def cell_data(column, cell, model, iter_, userdata):
            value = model.get_value(iter_)
            cell.set_property('text', fsn2text(os.path.basename(value)))

        column.set_cell_data_func(render, cell_data)

        filelist.append_column(column)
        filelist.set_rules_hint(True)
        filelist.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        filelist.set_search_equal_func(search_func, False)
        filelist.set_search_column(0)

        self.__sig = filelist.get_selection().connect('changed',
                                                      self.__changed)

        dirlist.get_selection().connect('changed',
                                        self.__dir_selection_changed, filelist)
        dirlist.get_selection().emit('changed')

        def select_all_files(view, path, col, fileselection):
            view.expand_row(path, False)
            fileselection.select_all()

        dirlist.connect('row-activated', select_all_files,
                        filelist.get_selection())

        sw = ScrolledWindow()
        sw.add(dirlist)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.pack1(sw, resize=True)

        sw = ScrolledWindow()
        sw.add(filelist)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.pack2(sw, resize=True)
Beispiel #3
0
    def __init__(self, initial=None, folders=None):
        """
        initial -- the path to select/scroll to
        folders -- a list of paths to show in the tree view, None
                   will result in a separator.
        """

        model = ObjectTreeStore()
        super().__init__(model=model)

        if initial is not None:
            assert isinstance(initial, fsnative)

        column = TreeViewColumn(title=_("Folders"))
        column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        render = Gtk.CellRendererPixbuf()
        render.set_property('icon-name', Icons.FOLDER)
        render.props.xpad = 3
        column.pack_start(render, False)
        render = Gtk.CellRendererText()
        if self.supports_hints():
            render.set_property('ellipsize', Pango.EllipsizeMode.END)
        column.pack_start(render, True)

        def cell_data(column, cell, model, iter_, userdata):
            value = model.get_value(iter_)
            if value is not None:
                text = fsn2text(os.path.basename(value) or value)
                cell.set_property('text', text)

        column.set_cell_data_func(render, cell_data)

        self.append_column(column)
        self.set_search_equal_func(search_func, True)
        self.set_search_column(0)

        if folders is None:
            folders = []

        for path in folders:
            niter = model.append(None, [path])
            if path is not None:
                assert isinstance(path, fsnative)
                model.append(niter, [fsnative(u"dummy")])

        self.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        self.connect('test-expand-row', DirectoryTree.__expanded, model)

        self.set_row_separator_func(
            lambda model, iter_, data: model.get_value(iter_) is None, None)

        if initial:
            self.go_to(initial)

        menu = self._create_menu()
        connect_obj(self, 'popup-menu', self._popup_menu, menu)

        # Allow to drag and drop files from outside
        targets = [("text/uri-list", 0, 42)]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]
        self.drag_dest_set(Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY)
        self.connect('drag-data-received', self.__drag_data_received)
Beispiel #4
0
    def __init__(self, parent, library):
        super(EditTags, self).__init__(spacing=12)
        self.title = _("Edit Tags")
        self.set_border_width(12)

        model = ObjectStore()
        view = RCMHintedTreeView(model=model)
        self._view = view
        selection = view.get_selection()
        render = Gtk.CellRendererPixbuf()
        column = TreeViewColumn()
        column.pack_start(render, True)
        column.set_fixed_width(24)
        column.set_expand(False)

        def cdf_write(col, rend, model, iter_, *args):
            entry = model.get_value(iter_)
            rend.set_property('sensitive', entry.edited or entry.deleted)
            if entry.canedit or entry.deleted:
                if entry.deleted:
                    rend.set_property('icon-name', Icons.EDIT_DELETE)
                else:
                    rend.set_property('icon-name', Icons.EDIT)
            else:
                rend.set_property('icon-name', Icons.CHANGES_PREVENT)

        column.set_cell_data_func(render, cdf_write)
        view.append_column(column)

        render = Gtk.CellRendererText()
        column = TreeViewColumn(title=_('Tag'))
        column.pack_start(render, True)

        def cell_data_tag(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.tag)
            cell.set_property("strikethrough", entry.deleted)

        column.set_cell_data_func(render, cell_data_tag)

        column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        render.set_property('editable', True)
        render.connect('edited', self.__edit_tag_name, model)
        render.connect('editing-started', self.__tag_editing_started, model,
                       library)
        view.append_column(column)

        render = Gtk.CellRendererText()
        render.set_property('ellipsize', Pango.EllipsizeMode.END)
        render.set_property('editable', True)
        render.connect('edited', self.__edit_tag, model)
        render.connect('editing-started', self.__value_editing_started, model,
                       library)
        column = TreeViewColumn(title=_('Value'))
        column.pack_start(render, True)

        def cell_data_value(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            markup = entry.value.get_markup()
            cell.markup = markup
            cell.set_property("markup", markup)
            cell.set_property("editable", entry.canedit)
            cell.set_property("strikethrough", entry.deleted)

        column.set_cell_data_func(render, cell_data_value)

        column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        view.append_column(column)

        sw = Gtk.ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.IN)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.add(view)
        self.pack_start(sw, True, True, 0)

        cb = ConfigCheckButton(
            _("Show _programmatic tags"),
            'editing',
            'alltags',
            populate=True,
            tooltip=_("Access all tags, including machine-generated "
                      "ones e.g. MusicBrainz or Replay Gain tags"))
        cb.connect('toggled', self.__all_tags_toggled)
        self.pack_start(cb, False, True, 0)

        # Add and Remove [tags] buttons
        buttonbox = Gtk.HBox(spacing=18)
        bbox1 = Gtk.HButtonBox()
        bbox1.set_spacing(6)
        bbox1.set_layout(Gtk.ButtonBoxStyle.START)
        add = qltk.Button(_("_Add"), Icons.LIST_ADD)
        add.set_focus_on_click(False)
        self._add = add
        add.connect('clicked', self.__add_tag, model, library)
        bbox1.pack_start(add, True, True, 0)
        # Remove button
        remove = qltk.Button(_("_Remove"), Icons.LIST_REMOVE)
        remove.set_focus_on_click(False)
        remove.connect('clicked', self.__remove_tag, view)
        remove.set_sensitive(False)
        self._remove = remove

        bbox1.pack_start(remove, True, True, 0)

        # Revert and save buttons
        # Both can have customised translated text (and thus accels)
        bbox2 = Gtk.HButtonBox()
        bbox2.set_spacing(6)
        bbox2.set_layout(Gtk.ButtonBoxStyle.END)
        # Translators: Revert button in the tag editor
        revert = Button(C_("edittags", "_Revert"), Icons.DOCUMENT_REVERT)

        self._revert = revert
        revert.set_sensitive(False)
        # Translators: Save button in the tag editor
        save = Button(C_("edittags", "_Save"), Icons.DOCUMENT_SAVE)
        save.set_sensitive(False)
        self._save = save
        bbox2.pack_start(revert, True, True, 0)
        bbox2.pack_start(save, True, True, 0)

        buttonbox.pack_start(bbox1, True, True, 0)
        buttonbox.pack_start(bbox2, True, True, 0)
        self.pack_start(buttonbox, False, True, 0)
        self._buttonbox = buttonbox

        parent.connect('changed', self.__parent_changed)
        revert.connect('clicked', lambda *x: self._update())
        connect_obj(revert, 'clicked', parent.set_pending, None)

        save.connect('clicked', self.__save_files, revert, model, library)
        connect_obj(save, 'clicked', parent.set_pending, None)
        for sig in ['row-inserted', 'row-deleted', 'row-changed']:
            model.connect(sig, self.__enable_save, [save, revert])
            connect_obj(model, sig, parent.set_pending, save)

        view.connect('popup-menu', self.__popup_menu, parent)
        view.connect('button-press-event', self.__button_press)
        view.connect('key-press-event', self.__view_key_press_event)
        selection.connect('changed', self.__tag_select, remove)
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)

        self._parent = parent

        for child in self.get_children():
            child.show_all()
Beispiel #5
0
    def __init__(self, prop, library):
        super(TrackNumbers, self).__init__(spacing=6)
        self.title = _("Track Numbers")
        self.set_border_width(12)

        label_start = Gtk.Label(label=_("Start fro_m:"), halign=Gtk.Align.END)
        label_start.set_use_underline(True)
        spin_start = Gtk.SpinButton()
        spin_start.set_range(0, 999)
        spin_start.set_increments(1, 10)
        spin_start.set_value(1)
        label_start.set_mnemonic_widget(spin_start)

        label_total = Gtk.Label(label=_("_Total tracks:"),
                                halign=Gtk.Align.END)
        label_total.set_use_underline(True)
        spin_total = Gtk.SpinButton()
        spin_total.set_range(0, 999)
        spin_total.set_increments(1, 10)
        label_total.set_mnemonic_widget(spin_total)

        preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)

        grid = Gtk.Grid(row_spacing=4, column_spacing=4)
        grid.add(label_start)
        grid.attach_next_to(spin_start, label_start, Gtk.PositionType.RIGHT, 1,
                            1)
        grid.attach_next_to(label_total, label_start, Gtk.PositionType.BOTTOM,
                            1, 1)
        grid.attach_next_to(spin_total, label_total, Gtk.PositionType.RIGHT, 1,
                            1)
        grid.attach_next_to(Align(preview, halign=Gtk.Align.END), spin_start,
                            Gtk.PositionType.RIGHT, 1, 1)
        preview.props.hexpand = True

        model = ObjectStore()
        view = HintedTreeView(model=model)

        self.pack_start(grid, False, True, 0)

        render = Gtk.CellRendererText()
        column = TreeViewColumn(title=_('File'))
        column.pack_start(render, True)
        column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)

        def cell_data_file(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.name)

        column.set_cell_data_func(render, cell_data_file)

        view.append_column(column)
        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(title=_('Track'))
        column.pack_start(render, True)
        column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)

        def cell_data_track(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.tracknumber)

        column.set_cell_data_func(render, cell_data_track)

        view.append_column(column)
        view.set_reorderable(True)
        w = Gtk.ScrolledWindow()
        w.set_shadow_type(Gtk.ShadowType.IN)
        w.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        w.add(view)
        self.pack_start(w, True, True, 0)

        bbox = Gtk.HButtonBox()
        bbox.set_spacing(6)
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save = save
        connect_obj(save, 'clicked', self.__save_files, prop, model, library)
        revert = Button(_("_Revert"), Icons.DOCUMENT_REVERT)
        self.revert = revert
        bbox.pack_start(revert, True, True, 0)
        bbox.pack_start(save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

        preview_args = [spin_start, spin_total, model, save, revert]
        preview.connect('clicked', self.__preview_tracks, *preview_args)
        connect_obj(revert, 'clicked', self.__update, None, *preview_args[1:])
        spin_total.connect('value-changed', self.__preview_tracks,
                           *preview_args)
        spin_start.connect('value-changed', self.__preview_tracks,
                           *preview_args)
        connect_obj(view, 'drag-end', self.__class__.__preview_tracks, self,
                    *preview_args)
        render.connect('edited', self.__row_edited, model, preview, save)

        connect_obj(prop, 'changed', self.__class__.__update, self, spin_total,
                    model, save, revert)

        for child in self.get_children():
            child.show_all()
Beispiel #6
0
    def __preview(self, songs):
        if songs is None:
            songs = [row[0].song for row in (self.view.get_model() or [])]

        if songs:
            pattern_text = gdecode(self.combo.get_child().get_text())
        else:
            pattern_text = ""
        try:
            pattern = TagsFromPattern(pattern_text)
        except re.error:
            qltk.ErrorMessage(
                self, _("Invalid pattern"),
                _("The pattern\n\t<b>%s</b>\nis invalid. "
                  "Possibly it contains the same tag twice or "
                  "it has unbalanced brackets (&lt; / &gt;).") % (
                util.escape(pattern_text))).run()
            return
        else:
            if pattern_text:
                self.combo.prepend_text(pattern_text)
                self.combo.write(TBP)

        invalid = []

        for header in pattern.headers:
            if not min([song.can_change(header) for song in songs]):
                invalid.append(header)
        if len(invalid) and songs:
            if len(invalid) == 1:
                title = _("Invalid tag")
                msg = _("Invalid tag <b>%s</b>\n\nThe files currently"
                        " selected do not support editing this tag.")
            else:
                title = _("Invalid tags")
                msg = _("Invalid tags <b>%s</b>\n\nThe files currently"
                        " selected do not support editing these tags.")
            qltk.ErrorMessage(
                self, title, msg % ", ".join(invalid)).run()
            pattern = TagsFromPattern("")

        self.view.set_model(None)
        model = ObjectStore()
        for col in self.view.get_columns():
            self.view.remove_column(col)

        render = Gtk.CellRendererText()
        col = TreeViewColumn(title=_('File'))
        col.pack_start(render, True)
        col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)

        def cell_data_file(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.name)

        col.set_cell_data_func(render, cell_data_file)

        def cell_data_header(column, cell, model, iter_, header):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.get_match(header))

        self.view.append_column(col)
        for i, header in enumerate(pattern.headers):
            render = Gtk.CellRendererText()
            render.set_property('editable', True)
            render.connect('edited', self.__row_edited, model, header)
            escaped_title = header.replace("_", "__")
            col = Gtk.TreeViewColumn(escaped_title, render)
            col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
            col.set_cell_data_func(render, cell_data_header, header)
            self.view.append_column(col)

        for song in songs:
            entry = ListEntry(song)
            match = pattern.match(song)
            for h in pattern.headers:
                text = match.get(h, '')
                for f in self.filter_box.filters:
                    if f.active:
                        text = f.filter(h, text)
                if not song.can_multiple_values(h):
                    text = u", ".join(text.split("\n"))
                entry.matches[h] = text
            model.append([entry])

        # save for last to potentially save time
        if songs:
            self.view.set_model(model)
        self.preview.set_sensitive(False)
        self.save.set_sensitive(len(pattern.headers) > 0)