Esempio n. 1
0
    def __init__(self, parent, default="", **kwargs):
        if self.is_not_unique():
            return
        super(TextEdit, self).__init__()
        self.set_title(_("Edit Display"))
        self.set_transient_for(qltk.get_top_parent(parent))
        self.set_border_width(12)
        self.set_default_size(420, 190)

        vbox = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        self.box = box = self.Box(default, **kwargs)
        vbox.pack_start(box, True, True, 0)
        self.use_header_bar()
        if not self.has_close_button():
            vbox.pack_start(b, False, True, 0)

        self.add(vbox)
        self.apply = box.apply
        self.revert = box.revert

        close.grab_focus()
        self.get_child().show_all()
Esempio n. 2
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Playlist Browser Preferences"))
        self.set_default_size(420, 240)
        self.set_transient_for(qltk.get_top_parent(browser))

        box = Gtk.VBox(spacing=6)
        edit_frame = self.edit_display_pane(browser, _("Playlist display"))
        box.pack_start(edit_frame, False, True, 12)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Esempio n. 3
0
    def __init__(self, count=0, text="", initial={}, limit=3):
        """count: the total amount of items expected, 0 for unknown/indefinite
        text: text to display in the label; may contain % formats
        initial: initial values for % formats (text % initial)
        limit: count must be greater than limit (or 0) for pause/stop to appear

        The current iteration of the counter can be gotten as
        self.current. count can be gotten as self.count.
        """

        super().__init__()

        self._label = Gtk.Label()
        self._label.set_use_markup(True)

        self._progress = Gtk.ProgressBar()
        self._progress.set_pulse_step(0.08)
        self.pulse = self._progress.pulse
        self.set_fraction = self._progress.set_fraction
        self.set_text = self._label.set_markup

        self.setup(count, text, initial)

        if self.count > limit or self.count == 0:
            # Add stop/pause buttons. count = 0 means an indefinite
            # number of steps.
            self._cancel_button = Button(_("_Stop"), Icons.PROCESS_STOP)
            self._pause_button = ToggleButton(_("P_ause"),
                                              Icons.MEDIA_PLAYBACK_PAUSE)
            self._cancel_button.connect('clicked', self.__cancel_clicked)
            self._pause_button.connect('clicked', self.__pause_clicked)
        else:
            self._cancel_button = None
            self._pause_button = None
Esempio n. 4
0
    def PluginPreferences(self, win):
        box = Gtk.VBox(spacing=12)

        # api key section
        def key_changed(entry, *args):
            config.set("plugins", "fingerprint_acoustid_api_key",
                entry.get_text())

        button = Button(_("Request API key"), Icons.NETWORK_WORKGROUP)
        button.connect("clicked",
            lambda s: util.website("https://acoustid.org/api-key"))
        key_box = Gtk.HBox(spacing=6)
        entry = UndoEntry()
        entry.set_text(get_api_key())
        entry.connect("changed", key_changed)
        label = Gtk.Label(label=_("API _key:"))
        label.set_use_underline(True)
        label.set_mnemonic_widget(entry)
        key_box.pack_start(label, False, True, 0)
        key_box.pack_start(entry, True, True, 0)
        key_box.pack_start(button, False, True, 0)

        box.pack_start(Frame(_("AcoustID Web Service"),
                       child=key_box), True, True, 0)

        return box
Esempio n. 5
0
    def enabled(self):
        self.scrolled_window = Gtk.ScrolledWindow()
        self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
                                        Gtk.PolicyType.AUTOMATIC)
        self.adjustment = self.scrolled_window.get_vadjustment()

        self.textview = Gtk.TextView()
        self.textbuffer = self.textview.get_buffer()
        self._italics = self.textbuffer.create_tag("italic",
                                                   style="italic",
                                                   foreground="grey")
        self.textview.set_editable(False)
        self.textview.set_cursor_visible(False)
        self.textview.set_wrap_mode(Gtk.WrapMode.WORD)
        self.textview.set_justification(Gtk.Justification.CENTER)
        self.textview.connect('key-press-event', self.key_press_event_cb)
        add_css(self.textview, "* { padding: 6px; }")
        vbox = Gtk.VBox()
        vbox.pack_start(self.textview, True, True, 0)
        self._edit_button = Button("Edit Lyrics", Icons.EDIT)
        hbox = Gtk.HBox()
        hbox.pack_end(self._edit_button, False, False, 3)
        vbox.pack_start(hbox, False, False, 3)
        self.scrolled_window.add(vbox)
        self.textview.show()

        self.scrolled_window.show()
        self._sig = None
        cur = app.player.info
        if cur is not None:
            cur = SongWrapper(cur)
        self.plugin_on_song_started(cur)
Esempio n. 6
0
    def PluginPreferences(self, win):
        box = Gtk.VBox(spacing=12)

        # api key section
        def key_changed(entry, *args):
            config.set("plugins", "fingerprint_acoustid_api_key",
                       entry.get_text())

        button = Button(_("Request API key"), Gtk.STOCK_NETWORK)
        button.connect("clicked",
                       lambda s: util.website("https://acoustid.org/api-key"))
        key_box = Gtk.HBox(spacing=6)
        entry = UndoEntry()
        entry.set_text(get_api_key())
        entry.connect("changed", key_changed)
        label = Gtk.Label(label=_("API _key:"))
        label.set_use_underline(True)
        label.set_mnemonic_widget(entry)
        key_box.pack_start(label, False, True, 0)
        key_box.pack_start(entry, True, True, 0)
        key_box.pack_start(button, False, True, 0)

        box.pack_start(Frame(_("Acoustid Web Service"), child=key_box), True,
                       True, 0)

        return box
Esempio n. 7
0
    def enabled(self):
        self.scrolled_window = Gtk.ScrolledWindow()
        self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
                                        Gtk.PolicyType.AUTOMATIC)
        self.adjustment = self.scrolled_window.get_vadjustment()

        self.textview = Gtk.TextView()
        self.textbuffer = self.textview.get_buffer()
        self._italics = self.textbuffer.create_tag("italic", style="italic",
                                                   foreground="grey")
        self.textview.set_editable(False)
        self.textview.set_cursor_visible(False)
        self.textview.set_wrap_mode(Gtk.WrapMode.WORD)
        self.textview.set_justification(Gtk.Justification.CENTER)
        self.textview.connect('key-press-event', self.key_press_event_cb)
        add_css(self.textview, "* { padding: 6px; }")
        vbox = Gtk.VBox()
        vbox.pack_start(self.textview, True, True, 0)
        self._edit_button = Button("Edit Lyrics", Icons.EDIT)
        hbox = Gtk.HBox()
        hbox.pack_end(self._edit_button, False, False, 3)
        vbox.pack_start(hbox, False, False, 3)
        self.scrolled_window.add(vbox)
        self.textview.show()

        self.scrolled_window.show()
        self._sig = None
        cur = app.player.info
        if cur is not None:
            cur = SongWrapper(cur)
        self.plugin_on_song_started(cur)
Esempio n. 8
0
    def __init__(self, count=0, text="", initial={}, limit=3):
        """count: the total amount of items expected, 0 for unknown/indefinite
        text: text to display in the label; may contain % formats
        initial: initial values for % formats (text % initial)
        limit: count must be greater than limit (or 0) for pause/stop to appear

        The current iteration of the counter can be gotten as
        self.current. count can be gotten as self.count.
        """

        super(WaitLoadBase, self).__init__()

        self._label = Gtk.Label()
        self._label.set_use_markup(True)

        self._progress = Gtk.ProgressBar()
        self._progress.set_pulse_step(0.08)
        self.pulse = self._progress.pulse
        self.set_fraction = self._progress.set_fraction
        self.set_text = self._label.set_markup

        self.setup(count, text, initial)

        if self.count > limit or self.count == 0:
            # Add stop/pause buttons. count = 0 means an indefinite
            # number of steps.
            self._cancel_button = Button(_("_Stop"), Icons.PROCESS_STOP)
            self._pause_button = ToggleButton(_("P_ause"),
                                              Icons.MEDIA_PLAYBACK_PAUSE)
            self._cancel_button.connect('clicked', self.__cancel_clicked)
            self._pause_button.connect('clicked', self.__pause_clicked)
        else:
            self._cancel_button = None
            self._pause_button = None
Esempio n. 9
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Album List Preferences"))
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._PREVIEW_ITEM["~rating"] = format_rating(0.75)

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(
            _("Show album _covers"), "browsers", "album_covers")
        cb.set_active(config.getboolean("browsers", "album_covers"))
        cb.connect('toggled', lambda s: browser.toggle_covers())
        vbox.pack_start(cb, False, True, 0)

        cb = ConfigCheckButton(
            _("Inline _search includes people"),
            "browsers", "album_substrings")
        cb.set_active(config.getboolean("browsers", "album_substrings"))
        vbox.pack_start(cb, False, True, 0)
        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        display_frame = self.edit_display_pane(browser, _("Album Display"))
        box.pack_start(display_frame, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Esempio n. 10
0
    def __init__(self, default=""):
        super(TextEditBox, self).__init__(spacing=6)

        sw = Gtk.ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.IN)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.add(TextView(buffer=TextBuffer()))
        self.pack_start(sw, True, True, 0)
        self.buffer = sw.get_child().get_buffer()

        box = Gtk.VBox(spacing=6)
        rev = Button(_("_Revert"), Icons.DOCUMENT_REVERT)
        app = Button(_("_Apply"))
        box.pack_start(rev, False, True, 0)
        box.pack_start(app, False, True, 0)
        self.pack_start(box, False, True, 0)
        connect_obj(rev, 'clicked', self.buffer.set_text, default)
        self.revert = rev
        self.apply = app
Esempio n. 11
0
    def __init__(self, filters, browser, parent=None):
        super(SelectionWindow, self).__init__()
        self.set_border_width(10)
        self.set_title(FilterAll.PLUGIN_NAME)
        self.set_default_size(200, 250)
        self.set_transient_for(parent)

        model = Gtk.ListStore(bool, str, str)
        for key, value in sorted(filters.items()):
            model.append(row=[False, key, value])

        toggle = Gtk.CellRendererToggle()
        toggle.connect("toggled", self.__toggeled, model, browser)
        text = Gtk.CellRendererText()

        toggle_column = Gtk.TreeViewColumn("", toggle, active=0)
        column = Gtk.TreeViewColumn(_("Tag"), text, text=1)

        view = Gtk.TreeView(model)
        view.append_column(toggle_column)
        view.append_column(column)

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

        buttons = Gtk.HButtonBox()
        buttons.set_spacing(6)
        buttons.set_layout(Gtk.ButtonBoxStyle.END)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        buttons.pack_start(close, True, True, 0)

        box = Gtk.VBox(spacing=12)
        box.pack_start(sw, True, True, 0)
        box.pack_start(buttons, False, True, 0)

        self.add(box)

        self.show_all()
Esempio n. 12
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Playlist Browser Preferences"))
        self.set_default_size(420, 240)
        self.set_transient_for(qltk.get_top_parent(browser))

        box = Gtk.VBox(spacing=6)
        edit_frame = self.edit_display_pane(browser, _("Playlist display"))
        box.pack_start(edit_frame, False, True, 12)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Esempio n. 13
0
    def __init__(self, parent, default="", **kwargs):
        if self.is_not_unique():
            return
        super(TextEdit, self).__init__()
        self.set_title(_("Edit Display"))
        self.set_transient_for(qltk.get_top_parent(parent))
        self.set_border_width(12)
        self.set_default_size(420, 190)

        vbox = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        self.box = box = self.Box(default, **kwargs)
        vbox.pack_start(box, True, True, 0)
        self.use_header_bar()
        if not self.has_close_button():
            vbox.pack_start(b, False, True, 0)

        self.add(vbox)
        self.apply = box.apply
        self.revert = box.revert

        close.grab_focus()
        self.get_child().show_all()
Esempio n. 14
0
    def PluginPreferences(self, *args):
        vbox = Gtk.VBox(spacing=12)

        label = Gtk.Label(label=_("Visualiser executable:"))

        def edited(widget):
            self.executable = widget.get_text()
        entry = UndoEntry()
        entry.connect('changed', edited)
        entry.set_text(self.executable)
        hbox = Gtk.HBox(spacing=6)
        hbox.pack_start(label, False, False, 0)
        hbox.pack_start(entry, True, True, 0)
        vbox.pack_start(hbox, True, True, 0)

        def refresh_clicked(widget):
            self.disabled()
            self.enabled()
        refresh_button = Button(_("Reload"), Icons.VIEW_REFRESH)
        refresh_button.connect('clicked', refresh_clicked)
        vbox.pack_start(refresh_button, False, False, 0)
        return vbox
Esempio n. 15
0
    def PluginPreferences(self, *args):
        vbox = Gtk.VBox(spacing=12)

        label = Gtk.Label(label=_("Visualiser executable:"))

        def edited(widget):
            self.executable = widget.get_text()

        entry = UndoEntry()
        entry.connect('changed', edited)
        entry.set_text(self.executable)
        hbox = Gtk.HBox(spacing=6)
        hbox.pack_start(label, False, False, 0)
        hbox.pack_start(entry, True, True, 0)
        vbox.pack_start(hbox, True, True, 0)

        def refresh_clicked(widget):
            self.disabled()
            self.enabled()

        refresh_button = Button(_("Reload"), Icons.VIEW_REFRESH)
        refresh_button.connect('clicked', refresh_clicked)
        vbox.pack_start(refresh_button, False, False, 0)
        return vbox
Esempio n. 16
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()

        self._browser = browser

        self.set_transient_for(qltk.get_top_parent(browser))
        self.set_default_size(350, 225)
        self.set_border_width(12)

        self.set_title(_("Album Collection Preferences"))

        vbox = Gtk.VBox(spacing=12)

        editor = PatternEditor()
        editor.headers = get_headers()

        apply = Button(_("_Apply"))
        connect_obj(apply, "clicked", self.__apply, editor, False)

        cancel = Button(_("_Cancel"))
        cancel.connect("clicked", lambda x: self.destroy())

        box = Gtk.HButtonBox()
        box.set_spacing(6)
        box.set_layout(Gtk.ButtonBoxStyle.END)
        box.pack_start(apply, True, True, 0)
        self.use_header_bar()
        if not self.has_close_button():
            box.pack_start(cancel, True, True, 0)

        vbox.pack_start(editor, True, True, 0)
        vbox.pack_start(box, False, True, 0)

        self.add(vbox)

        apply.grab_focus()
        self.show_all()
Esempio n. 17
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Album List Preferences"))
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._PREVIEW_ITEM["~rating"] = format_rating(0.75)

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(
            _("Show album _covers"), "browsers", "album_covers")
        cb.set_active(config.getboolean("browsers", "album_covers"))
        cb.connect('toggled', lambda s: browser.toggle_covers())
        vbox.pack_start(cb, False, True, 0)

        cb = ConfigCheckButton(
            _("Inline _search includes people"),
            "browsers", "album_substrings")
        cb.set_active(config.getboolean("browsers", "album_substrings"))
        vbox.pack_start(cb, False, True, 0)
        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        display_frame = self.edit_display_pane(browser, _("Album Display"))
        box.pack_start(display_frame, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Esempio n. 18
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()

        self._browser = browser

        self.set_transient_for(qltk.get_top_parent(browser))
        self.set_default_size(350, 225)
        self.set_border_width(12)

        self.set_title(_("Album Collection Preferences"))

        vbox = Gtk.VBox(spacing=12)

        editor = PatternEditor()
        editor.headers = get_headers()

        apply = Button(_("_Apply"))
        connect_obj(apply, "clicked", self.__apply, editor, False)

        cancel = Button(_("_Cancel"))
        cancel.connect("clicked", lambda x: self.destroy())

        box = Gtk.HButtonBox()
        box.set_spacing(6)
        box.set_layout(Gtk.ButtonBoxStyle.END)
        box.pack_start(apply, True, True, 0)
        self.use_header_bar()
        if not self.has_close_button():
            box.pack_start(cancel, True, True, 0)

        vbox.pack_start(editor, True, True, 0)
        vbox.pack_start(box, False, True, 0)

        self.add(vbox)

        apply.grab_focus()
        self.show_all()
Esempio n. 19
0
    def __init__(self, model):
        songs_text = numeric_phrase("%d duplicate group",
                                    "%d duplicate groups",
                                    len(model))
        super(DuplicateDialog, self).__init__()
        self.set_destroy_with_parent(True)
        self.set_title("Quod Libet - %s (%s)" % (Duplicates.PLUGIN_NAME,
                                                 songs_text))
        self.finished = False
        self.set_default_size(960, 480)
        self.set_border_width(6)
        swin = Gtk.ScrolledWindow()
        swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        swin.set_shadow_type(Gtk.ShadowType.IN)
        # Set up the browser view
        view = DuplicateSongsView(model)

        def cell_text(column, cell, model, iter_, index):
            text = model[iter_][index]
            cell.markup = text
            cell.set_property("markup", text)

        # Set up the columns
        for i, (tag, f) in enumerate(DuplicatesTreeModel.TAG_MAP):
            e = (Pango.EllipsizeMode.START if tag == '~filename'
                else Pango.EllipsizeMode.END)
            render = Gtk.CellRendererText()
            render.set_property("ellipsize", e)
            col = Gtk.TreeViewColumn(util.tag(tag), render)
            # Numeric columns are better smaller here.
            if tag.startswith("~#"):
                col.set_fixed_width(80)
                col.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
            else:
                col.set_expand(True)
                col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
            col.set_resizable(True)
            col.set_cell_data_func(render, cell_text, i + 1)
            view.append_column(col)

        view.connect('popup-menu', self.__songs_popup_menu)
        swin.add(view)
        # A basic information area
        hbox = Gtk.HBox(spacing=6)

        def expand_all(*args):
            model = view.get_model()
            for row in model:
                if view.row_expanded(row.path):
                    view.collapse_row(row.path)
            else:
                for row in model:
                    view.expand_row(row.path, False)

        expand = Gtk.Button(_("Collapse / Expand all"))
        connect_obj(expand, "clicked", expand_all, view)
        hbox.pack_start(expand, False, True, 0)

        label = Gtk.Label(label=_("Duplicate key expression is '%s'") %
                Duplicates.get_key_expression())
        hbox.pack_start(label, True, True, 0)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', self.__quit)
        hbox.pack_start(close, False, True, 0)

        vbox = Gtk.VBox(spacing=6)
        vbox.pack_start(swin, True, True, 0)
        vbox.pack_start(hbox, False, True, 0)
        self.add(vbox)
        self.show_all()
Esempio n. 20
0
    def __init__(self, parent, library):
        super(RenameFiles, self).__init__(spacing=6)
        self.set_border_width(12)

        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = NBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(NBP, cbes_defaults,
            title=_("Path Patterns"),
            edit_title=_(u"Edit saved patterns…"))
        self.combo.show_all()
        hbox.pack_start(self.combo, True, True, 0)
        self.preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)
        self.preview.show()
        hbox.pack_start(self.preview, False, True, 0)
        self.pack_start(hbox, False, True, 0)
        self.combo.get_child().connect('changed', self._changed)

        model = ObjectStore()
        self.view = Gtk.TreeView(model=model)
        self.view.show()

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

        self.pack_start(Gtk.VBox(), False, True, 0)

        filter_box = FilterPluginBox(self.handler, self.FILTERS)
        filter_box.connect("preview", self.__filter_preview)
        filter_box.connect("changed", self.__filter_changed)
        self.filter_box = filter_box
        self.pack_start(filter_box, False, True, 0)

        # Save button
        self.save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save.show()
        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.pack_start(self.save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

        render = Gtk.CellRendererText()
        column = TreeViewColumn(_('File'), render)

        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)

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

        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(_('New Name'), render)

        def cell_data_new_name(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.new_name or u"")
        column.set_cell_data_func(render, cell_data_new_name)

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

        connect_obj(self.preview, 'clicked', self.__preview, None)

        connect_obj(parent, 'changed', self.__class__.__preview, self)
        connect_obj(self.save, 'clicked', self.__rename, library)

        render.connect('edited', self.__row_edited)

        for child in self.get_children():
            child.show()
Esempio n. 21
0
class RenameFiles(Gtk.VBox):
    title = _("Rename Files")
    FILTERS = [SpacesToUnderscores, StripWindowsIncompat, StripDiacriticals,
               StripNonASCII, Lowercase]
    handler = RenameFilesPluginHandler()

    @classmethod
    def init_plugins(cls):
        PluginManager.instance.register_handler(cls.handler)

    def __init__(self, parent, library):
        super(RenameFiles, self).__init__(spacing=6)
        self.set_border_width(12)

        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = NBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(NBP, cbes_defaults,
            title=_("Path Patterns"),
            edit_title=_(u"Edit saved patterns…"))
        self.combo.show_all()
        hbox.pack_start(self.combo, True, True, 0)
        self.preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)
        self.preview.show()
        hbox.pack_start(self.preview, False, True, 0)
        self.pack_start(hbox, False, True, 0)
        self.combo.get_child().connect('changed', self._changed)

        model = ObjectStore()
        self.view = Gtk.TreeView(model=model)
        self.view.show()

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

        self.pack_start(Gtk.VBox(), False, True, 0)

        filter_box = FilterPluginBox(self.handler, self.FILTERS)
        filter_box.connect("preview", self.__filter_preview)
        filter_box.connect("changed", self.__filter_changed)
        self.filter_box = filter_box
        self.pack_start(filter_box, False, True, 0)

        # Save button
        self.save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save.show()
        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.pack_start(self.save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

        render = Gtk.CellRendererText()
        column = TreeViewColumn(_('File'), render)

        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)

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

        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(_('New Name'), render)

        def cell_data_new_name(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.new_name or u"")
        column.set_cell_data_func(render, cell_data_new_name)

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

        connect_obj(self.preview, 'clicked', self.__preview, None)

        connect_obj(parent, 'changed', self.__class__.__preview, self)
        connect_obj(self.save, 'clicked', self.__rename, library)

        render.connect('edited', self.__row_edited)

        for child in self.get_children():
            child.show()

    def __filter_preview(self, *args):
        Gtk.Button.clicked(self.preview)

    def __filter_changed(self, *args):
        self._changed(self.combo.get_child())

    def _changed(self, entry):
        self.save.set_sensitive(False)
        self.preview.set_sensitive(bool(entry.get_text()))

    def __row_edited(self, renderer, path, new):
        path = Gtk.TreePath.new_from_string(path)
        model = self.view.get_model()
        entry = model[path][0]
        new = gdecode(new)
        if entry.new_name != new:
            entry.new_name = new
            self.preview.set_sensitive(True)
            self.save.set_sensitive(True)
            model.path_changed(path)

    def __rename(self, library):
        model = self.view.get_model()
        win = WritingWindow(self, len(model))
        win.show()
        was_changed = set()
        skip_all = False
        self.view.freeze_child_notify()

        for entry in model.itervalues():
            song = entry.song
            new_name = entry.new_name
            old_name = entry.name
            if new_name is None:
                continue

            try:
                library.rename(song, fsnative(new_name), changed=was_changed)
            except Exception:
                util.print_exc()
                if skip_all:
                    continue
                RESPONSE_SKIP_ALL = 1
                msg = qltk.Message(
                    Gtk.MessageType.ERROR, win, _("Unable to rename file"),
                    _("Renaming <b>%(old-name)s</b> to <b>%(new-name)s</b> "
                      "failed. Possibly the target file already exists, "
                      "or you do not have permission to make the "
                      "new file or remove the old one.") % {
                        "old-name": util.escape(old_name),
                        "new-name": util.escape(new_name),
                      },
                    buttons=Gtk.ButtonsType.NONE)
                msg.add_button(_("Ignore _All Errors"), RESPONSE_SKIP_ALL)
                msg.add_icon_button(_("_Stop"), Icons.PROCESS_STOP,
                                    Gtk.ResponseType.CANCEL)
                msg.add_button(_("_Continue"), Gtk.ResponseType.OK)
                msg.set_default_response(Gtk.ResponseType.OK)
                resp = msg.run()
                skip_all |= (resp == RESPONSE_SKIP_ALL)
                # Preserve old behavior: shift-click is Ignore All
                mods = Gdk.Display.get_default().get_pointer()[3]
                skip_all |= mods & Gdk.ModifierType.SHIFT_MASK
                library.reload(song, changed=was_changed)
                if resp != Gtk.ResponseType.OK and resp != RESPONSE_SKIP_ALL:
                    break
            if win.step():
                break

        self.view.thaw_child_notify()
        win.destroy()
        library.changed(was_changed)
        self.save.set_sensitive(False)

    def __preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [e.song for e in model.itervalues()]

        pattern_text = gdecode(self.combo.get_child().get_text())

        try:
            pattern = FileFromPattern(pattern_text)
        except ValueError:
            qltk.ErrorMessage(
                self, _("Path is not absolute"),
                _("The pattern\n\t<b>%s</b>\ncontains / but "
                  "does not start from root. To avoid misnamed "
                  "folders, root your pattern by starting "
                  "it with / or ~/.") % (
                util.escape(pattern))).run()
            return
        else:
            if pattern:
                self.combo.prepend_text(pattern_text)
                self.combo.write(NBP)

        # native paths
        orignames = [song["~filename"] for song in songs]
        newnames = [pattern.format(song) for song in songs]
        for f in self.filter_box.filters:
            if f.active:
                newnames = f.filter_list(orignames, newnames)

        model.clear()
        for song, newname in zip(songs, newnames):
            entry = Entry(song)
            entry.new_name = fsdecode(newname)
            model.append(row=[entry])

        self.preview.set_sensitive(False)
        self.save.set_sensitive(bool(pattern_text))
        for song in songs:
            if not song.is_file:
                self.set_sensitive(False)
                break
        else:
            self.set_sensitive(True)
Esempio n. 22
0
    def __init__(self, parent, library):
        super(RenameFiles, self).__init__(spacing=6)
        self.__skip_interactive = False
        self.set_border_width(12)

        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = NBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(NBP, cbes_defaults,
            title=_("Path Patterns"),
            edit_title=_(u"Edit saved patterns…"))
        self.combo.show_all()
        hbox.pack_start(self.combo, True, True, 0)
        self.preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)
        self.preview.show()
        hbox.pack_start(self.preview, False, True, 0)
        self.pack_start(hbox, False, True, 0)
        self.combo.get_child().connect('changed', self._changed)

        model = ObjectStore()
        self.view = Gtk.TreeView(model=model)
        self.view.show()

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

        self.pack_start(Gtk.VBox(), False, True, 0)

        # rename options
        rename_options = Gtk.HBox()

        # file name options
        filter_box = FilterPluginBox(self.handler, self.FILTERS)
        filter_box.connect("preview", self.__filter_preview)
        filter_box.connect("changed", self.__filter_changed)
        self.filter_box = filter_box

        frame_filename_options = Frame(_("File names"), filter_box)
        frame_filename_options.show_all()
        rename_options.pack_start(frame_filename_options, False, True, 0)

        # album art options
        albumart_box = Gtk.VBox()

        # move art
        moveart_box = Gtk.VBox()
        self.moveart = ConfigCheckButton(
             _('_Move album art'),
             "rename", "move_art", populate=True)
        self.moveart.set_tooltip_text(
             _("See '[albumart] filenames' config entry " +
               "for image search strings"))
        self.moveart.show()
        moveart_box.pack_start(self.moveart, False, True, 0)
        self.moveart_overwrite = ConfigCheckButton(
             _('_Overwrite album art at target'),
             "rename", "move_art_overwrite", populate=True)
        self.moveart_overwrite.show()
        moveart_box.pack_start(self.moveart_overwrite, False, True, 0)
        albumart_box.pack_start(moveart_box, False, True, 0)
        # remove empty
        removeemptydirs_box = Gtk.VBox()
        self.removeemptydirs = ConfigCheckButton(
             _('_Remove empty directories'),
             "rename", "remove_empty_dirs", populate=True)
        self.removeemptydirs.show()
        removeemptydirs_box.pack_start(self.removeemptydirs, False, True, 0)
        albumart_box.pack_start(removeemptydirs_box, False, True, 0)

        frame_albumart_options = Frame(_("Album art"), albumart_box)
        frame_albumart_options.show_all()
        rename_options.pack_start(frame_albumart_options, False, True, 0)

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

        # Save button
        self.save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save.show()
        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.pack_start(self.save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

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

        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)

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

        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(title=_('New Name'))
        column.pack_start(render, True)

        def cell_data_new_name(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.new_name or u"")
        column.set_cell_data_func(render, cell_data_new_name)

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

        connect_obj(self.preview, 'clicked', self._preview, None)

        connect_obj(parent, 'changed', self.__class__._preview, self)
        connect_obj(self.save, 'clicked', self._rename, library)

        render.connect('edited', self.__row_edited)

        for child in self.get_children():
            child.show()
Esempio n. 23
0
    def __init__(self):
        super(PatternEditor, self).__init__(spacing=12)

        self.__headers = headers = {}
        buttons = []

        group = None
        for tags in self.PRESETS:
            tied = "~" + "~".join([t[0] for t in tags])
            group = Gtk.RadioButton(group=group,
                                    label="_" + util.tag(tied),
                                    use_underline=True)
            headers[group] = tags
            buttons.append(group)

        group = Gtk.RadioButton(group=group,
                                label=_("_Custom"),
                                use_underline=True)
        self.__custom = group
        headers[group] = []
        buttons.append(group)

        button_box = Gtk.HBox(spacing=6)
        self.__model = model = Gtk.ListStore(str, bool)

        radio_box = Gtk.VBox(spacing=6)
        for button in buttons:
            radio_box.pack_start(button, False, True, 0)
            button.connect('toggled', self.__toggled, button_box, model)

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

        cb = TagsComboBoxEntry(self.COMPLETION)

        view = BaseView(model=model)
        view.set_reorderable(True)
        view.set_headers_visible(True)

        ctrl_box = Gtk.VBox(spacing=6)

        add = Button(_("_Add"), Icons.LIST_ADD)
        ctrl_box.pack_start(add, False, True, 0)
        add.connect('clicked', self.__add, model, cb)

        remove = Button(_("_Remove"), Icons.LIST_REMOVE)
        ctrl_box.pack_start(remove, False, True, 0)
        remove.connect('clicked', self.__remove, view)

        selection = view.get_selection()
        selection.connect('changed', self.__selection_changed, remove)
        selection.emit('changed')

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

        edit_box = Gtk.VBox(spacing=6)
        edit_box.pack_start(cb, False, True, 0)
        edit_box.pack_start(sw, True, True, 0)

        button_box.pack_start(edit_box, True, True, 0)
        button_box.pack_start(ctrl_box, False, True, 0)
        self.pack_start(button_box, True, True, 0)

        render = Gtk.CellRendererText()
        render.set_property("editable", True)

        def edited_cb(render, path, text, model):
            model[path][0] = text

        render.connect("edited", edited_cb, model)

        column = Gtk.TreeViewColumn(_("Tag"), render, text=0)
        column.set_expand(True)
        view.append_column(column)

        toggle = Gtk.CellRendererToggle()
        toggle.connect("toggled", self.__toggeled, model)
        toggle_column = Gtk.TreeViewColumn(_("Merge"), toggle, active=1)
        view.append_column(toggle_column)
Esempio n. 24
0
class WaitLoadBase(object):
    """Abstract class providing a label, a progressbar, pause/stop buttons,
    and the stepping logic."""

    def __init__(self, count=0, text="", initial={}, limit=3):
        """count: the total amount of items expected, 0 for unknown/indefinite
        text: text to display in the label; may contain % formats
        initial: initial values for % formats (text % initial)
        limit: count must be greater than limit (or 0) for pause/stop to appear

        The current iteration of the counter can be gotten as
        self.current. count can be gotten as self.count.
        """

        super(WaitLoadBase, self).__init__()

        self._label = Gtk.Label()
        self._label.set_use_markup(True)

        self._progress = Gtk.ProgressBar()
        self._progress.set_pulse_step(0.08)
        self.pulse = self._progress.pulse
        self.set_fraction = self._progress.set_fraction
        self.set_text = self._label.set_markup

        self.setup(count, text, initial)

        if self.count > limit or self.count == 0:
            # Add stop/pause buttons. count = 0 means an indefinite
            # number of steps.
            self._cancel_button = Button(_("_Stop"), Icons.PROCESS_STOP)
            self._pause_button = ToggleButton(_("P_ause"),
                                              Icons.MEDIA_PLAYBACK_PAUSE)
            self._cancel_button.connect('clicked', self.__cancel_clicked)
            self._pause_button.connect('clicked', self.__pause_clicked)
        else:
            self._cancel_button = None
            self._pause_button = None

    def setup(self, count=0, text="", initial=None):
        self.current = 0
        self.count = count
        self._text = text
        self.paused = False
        self.quit = False
        self._start_time = time.time()
        initial = initial or {}

        initial.setdefault("total", self.count)
        initial.setdefault("current", self.current)
        initial.setdefault("remaining", _("Unknown"))

        def localeify(k, v):
            foo = '%(' + k + ')d'
            if foo in self._text:
                self._text = self._text.replace(foo, '%(' + k + ')s')
                return k, format_int_locale(int(v))
            return k, v

        localed = dict([localeify(k, v) for k, v in iteritems(initial)])
        self._label.set_markup(self._text % localed)
        self._progress.set_fraction(0.0)

    def __pause_clicked(self, button):
        self.paused = button.get_active()

    def __cancel_clicked(self, button):
        self.quit = True

    def step(self, **values):
        """Advance the counter by one. Arguments are applied to the
        originally-supplied text as a format string.

        This function doesn't return if the dialog is paused (though
        the GTK main loop will still run), and returns True if stop
        was pressed.
        """

        if self.count:
            self.current += 1
            self._progress.set_fraction(
                max(0, min(1, self.current / float(self.count))))
        else:
            self._progress.pulse()
        values.setdefault("total", format_int_locale(self.count))
        values.setdefault("current", format_int_locale(self.current))
        if self.count:
            t = (time.time() - self._start_time) / self.current
            remaining = math.ceil((self.count - self.current) * t)
            values.setdefault("remaining", format_time_display(remaining))
        self._label.set_markup(self._text % values)

        while not self.quit and (self.paused or Gtk.events_pending()):
            Gtk.main_iteration()
        return self.quit
Esempio n. 25
0
class ViewLyrics(EventPlugin, UserInterfacePlugin):
    """The plugin for viewing lyrics in the main window."""

    PLUGIN_ID = 'View Lyrics'
    PLUGIN_NAME = _('View Lyrics')
    PLUGIN_DESC = _('Automatically displays tag or file-based lyrics '
                    'in a sidebar.')
    PLUGIN_ICON = Icons.FORMAT_JUSTIFY_FILL

    def enabled(self):
        self.scrolled_window = Gtk.ScrolledWindow()
        self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
                                        Gtk.PolicyType.AUTOMATIC)
        self.adjustment = self.scrolled_window.get_vadjustment()

        self.textview = Gtk.TextView()
        self.textbuffer = self.textview.get_buffer()
        self._italics = self.textbuffer.create_tag("italic",
                                                   style="italic",
                                                   foreground="grey")
        self.textview.set_editable(False)
        self.textview.set_cursor_visible(False)
        self.textview.set_wrap_mode(Gtk.WrapMode.WORD)
        self.textview.set_justification(Gtk.Justification.CENTER)
        self.textview.connect('key-press-event', self.key_press_event_cb)
        add_css(self.textview, "* { padding: 6px; }")
        vbox = Gtk.VBox()
        vbox.pack_start(self.textview, True, True, 0)
        self._edit_button = Button("Edit Lyrics", Icons.EDIT)
        hbox = Gtk.HBox()
        hbox.pack_end(self._edit_button, False, False, 3)
        vbox.pack_start(hbox, False, False, 3)
        self.scrolled_window.add(vbox)
        self.textview.show()

        self.scrolled_window.show()
        self._sig = None
        cur = app.player.info
        if cur is not None:
            cur = SongWrapper(cur)
        self.plugin_on_song_started(cur)

    def create_sidebar(self):
        vbox = Gtk.VBox(margin=0)
        vbox.pack_start(self.scrolled_window, True, True, 0)
        vbox.show_all()
        return vbox

    def disabled(self):
        self.textview.destroy()
        self.scrolled_window.destroy()

    def plugin_on_song_started(self, song):
        """Called when a song is started. Loads the lyrics.

        If there are lyrics associated with `song`, load them into the
        lyrics viewer. Otherwise, hides the lyrics viewer.
        """
        lyrics = None
        if song is not None:
            print_d("Looking for lyrics for %s" % song("~filename"))
            lyrics = song("~lyrics")
            if lyrics:
                self.textbuffer.set_text(lyrics)
                self.adjustment.set_value(0)  # Scroll to the top.
                self.textview.show()
            else:
                title = _("No lyrics found for\n %s") % song("~basename")
                self._set_italicised(title)

            def edit(widget):
                print_d("Launching lyrics editor for %s" % song("~filename"))
                assert isinstance(song, SongWrapper)
                information = Information(app.librarian, [song._song])
                information.get_child()._switch_to_lyrics()
                information.show()

            if self._sig:
                self._edit_button.disconnect(self._sig)
            self._sig = self._edit_button.connect('clicked', edit)

    def _set_italicised(self, title):
        self.textbuffer.set_text(title)
        start = self.textbuffer.get_start_iter()
        end = self.textbuffer.get_end_iter()
        self.textbuffer.remove_all_tags(start, end)
        self.textbuffer.apply_tag(self._italics, start, end)

    def plugin_on_changed(self, songs):
        cur = app.player.info
        if cur:
            fn = cur("~filename")
            for s in songs:
                if s("~filename") == fn:
                    print_d("Active song changed, reloading lyrics")
                    self.plugin_on_song_started(SongWrapper(cur))
        else:
            self._set_italicised(_("No active song"))

    def key_press_event_cb(self, widget, event):
        """Handles up/down "key-press-event" in the lyrics view."""
        adj = self.scrolled_window.get_vadjustment().props
        if event.keyval == Gdk.KEY_Up:
            adj.value = max(adj.value - adj.step_increment, adj.lower)
        elif event.keyval == Gdk.KEY_Down:
            adj.value = min(adj.value + adj.step_increment,
                            adj.upper - adj.page_size)
        elif event.keyval == Gdk.KEY_Page_Up:
            adj.value = max(adj.value - adj.page_increment, adj.lower)
        elif event.keyval == Gdk.KEY_Page_Down:
            adj.value = min(adj.value + adj.page_increment,
                            adj.upper - adj.page_size)
        elif event.keyval == Gdk.KEY_Home:
            adj.value = adj.lower
        elif event.keyval == Gdk.KEY_End:
            adj.value = adj.upper - adj.page_size
        else:
            return False
        return True
Esempio n. 26
0
    def PluginPreferences(self, win):
        vb = Gtk.VBox(spacing=6)
        if not self.player_has_eq:
            l = Gtk.Label()
            l.set_markup(
                _('The current backend does not support equalization.'))
            vb.pack_start(l, False, True, 0)
            return vb

        def format_hertz(band):
            if band >= 1000:
                return _('%.1f kHz') % (band / 1000.)
            return _('%d Hz') % band

        bands = [format_hertz(band) for band in app.player.eq_bands]
        levels = get_config() + [0.] * len(bands)

        table = Gtk.Table(rows=len(bands), columns=3)
        table.set_col_spacings(6)

        def set_band(adj, idx):
            rounded = int(adj.get_value() * 2) / 2.0
            adj.set_value(rounded)
            levels[idx] = rounded
            config.set('plugins', 'equalizer_levels',
                       ','.join(str(lv) for lv in levels))
            self.apply()

        adjustments = []

        for i, band in enumerate(bands):
            # align numbers and suffixes in separate rows for great justice
            lbl = Gtk.Label(label=band.split()[0])
            lbl.set_alignment(1, 0.5)
            lbl.set_padding(0, 4)
            table.attach(lbl, 0, 1, i, i + 1, xoptions=Gtk.AttachOptions.FILL)
            lbl = Gtk.Label(label=band.split()[1])
            lbl.set_alignment(1, 0.5)
            table.attach(lbl, 1, 2, i, i + 1, xoptions=Gtk.AttachOptions.FILL)
            adj = Gtk.Adjustment.new(levels[i], -24., 12., 0.5, 3, 0)
            adj.connect('value-changed', set_band, i)
            adjustments.append(adj)
            hs = Gtk.HScale(adjustment=adj)
            hs.connect('button-press-event', self.__rightclick)
            hs.set_draw_value(True)
            hs.set_value_pos(Gtk.PositionType.RIGHT)
            hs.connect('format-value', lambda s, v: _('%.1f dB') % v)
            table.attach(hs, 2, 3, i, i + 1)
        vb.pack_start(table, True, True, 0)

        def clicked_cb(button):
            [adj.set_value(0) for adj in adjustments]

        sorted_presets = sorted(PRESETS.items())

        def combo_changed(combo):
            # custom, skip
            if not combo.get_active():
                return
            gain = sorted_presets[combo.get_active() - 1][1][1]
            gain = interp_bands(PRESET_BANDS, app.player.eq_bands, gain)
            for (g, a) in zip(gain, adjustments):
                a.set_value(g)

        combo = Gtk.ComboBoxText()
        combo.append_text(_("Custom"))
        combo.set_active(0)
        for key, (name, gain) in sorted_presets:
            combo.append_text(name)
        combo.connect("changed", combo_changed)

        bbox = Gtk.HButtonBox()
        clear = Button(_("_Clear"), Icons.EDIT_CLEAR)
        clear.connect('clicked', clicked_cb)
        bbox.pack_start(combo, True, True, 0)
        bbox.pack_start(clear, True, True, 0)
        vb.pack_start(bbox, True, True, 0)
        return vb
Esempio n. 27
0
    def __init__(self):
        super(PatternEditor, self).__init__(spacing=12)

        self.__headers = headers = {}
        buttons = []

        group = None
        for tags in self.PRESETS:
            tied = "~" + "~".join([t[0] for t in tags])
            group = Gtk.RadioButton(group=group, label="_" + util.tag(tied),
                                    use_underline=True)
            headers[group] = tags
            buttons.append(group)

        group = Gtk.RadioButton(group=group, label=_("_Custom"),
                                use_underline=True)
        self.__custom = group
        headers[group] = []
        buttons.append(group)

        button_box = Gtk.HBox(spacing=6)
        self.__model = model = Gtk.ListStore(str, bool)

        radio_box = Gtk.VBox(spacing=6)
        for button in buttons:
            radio_box.pack_start(button, False, True, 0)
            button.connect('toggled', self.__toggled, button_box, model)

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

        cb = TagsComboBoxEntry(self.COMPLETION)

        view = BaseView(model=model)
        view.set_reorderable(True)
        view.set_headers_visible(True)

        ctrl_box = Gtk.VBox(spacing=6)

        add = Button(_("_Add"), Icons.LIST_ADD)
        ctrl_box.pack_start(add, False, True, 0)
        add.connect('clicked', self.__add, model, cb)

        remove = Button(_("_Remove"), Icons.LIST_REMOVE)
        ctrl_box.pack_start(remove, False, True, 0)
        remove.connect('clicked', self.__remove, view)

        selection = view.get_selection()
        selection.connect('changed', self.__selection_changed, remove)
        selection.emit('changed')

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

        edit_box = Gtk.VBox(spacing=6)
        edit_box.pack_start(cb, False, True, 0)
        edit_box.pack_start(sw, True, True, 0)

        button_box.pack_start(edit_box, True, True, 0)
        button_box.pack_start(ctrl_box, False, True, 0)
        self.pack_start(button_box, True, True, 0)

        render = Gtk.CellRendererText()
        render.set_property("editable", True)

        def edited_cb(render, path, text, model):
            model[path][0] = text
        render.connect("edited", edited_cb, model)

        column = Gtk.TreeViewColumn(_("Tag"), render, text=0)
        column.set_expand(True)
        view.append_column(column)

        toggle = Gtk.CellRendererToggle()
        toggle.connect("toggled", self.__toggeled, model)
        toggle_column = Gtk.TreeViewColumn(_("Merge"), toggle, active=1)
        view.append_column(toggle_column)
Esempio n. 28
0
    def __init__(self, parent, library):
        super(RenameFiles, self).__init__(spacing=6)
        self.set_border_width(12)

        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = NBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(NBP,
                                       cbes_defaults,
                                       title=_("Path Patterns"),
                                       edit_title=_(u"Edit saved patterns…"))
        self.combo.show_all()
        hbox.pack_start(self.combo, True, True, 0)
        self.preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)
        self.preview.show()
        hbox.pack_start(self.preview, False, True, 0)
        self.pack_start(hbox, False, True, 0)
        self.combo.get_child().connect('changed', self._changed)

        model = ObjectStore()
        self.view = Gtk.TreeView(model=model)
        self.view.show()

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

        self.pack_start(Gtk.VBox(), False, True, 0)

        filter_box = FilterPluginBox(self.handler, self.FILTERS)
        filter_box.connect("preview", self.__filter_preview)
        filter_box.connect("changed", self.__filter_changed)
        self.filter_box = filter_box
        self.pack_start(filter_box, False, True, 0)

        # Save button
        self.save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save.show()
        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.pack_start(self.save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

        render = Gtk.CellRendererText()
        column = TreeViewColumn(_('File'), render)

        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)

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

        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(_('New Name'), render)

        def cell_data_new_name(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.new_name or u"")

        column.set_cell_data_func(render, cell_data_new_name)

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

        connect_obj(self.preview, 'clicked', self.__preview, None)

        connect_obj(parent, 'changed', self.__class__.__preview, self)
        connect_obj(self.save, 'clicked', self.__rename, library)

        render.connect('edited', self.__row_edited)

        for child in self.get_children():
            child.show()
Esempio n. 29
0
class ViewLyrics(EventPlugin, UserInterfacePlugin):
    """The plugin for viewing lyrics in the main window."""

    PLUGIN_ID = 'View Lyrics'
    PLUGIN_NAME = _('View Lyrics')
    PLUGIN_DESC = _('Automatically displays tag or file-based lyrics '
                    'in a sidebar.')
    PLUGIN_ICON = Icons.FORMAT_JUSTIFY_FILL

    def enabled(self):
        self.scrolled_window = Gtk.ScrolledWindow()
        self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
                                        Gtk.PolicyType.AUTOMATIC)
        self.adjustment = self.scrolled_window.get_vadjustment()

        self.textview = Gtk.TextView()
        self.textbuffer = self.textview.get_buffer()
        self._italics = self.textbuffer.create_tag("italic", style="italic",
                                                   foreground="grey")
        self.textview.set_editable(False)
        self.textview.set_cursor_visible(False)
        self.textview.set_wrap_mode(Gtk.WrapMode.WORD)
        self.textview.set_justification(Gtk.Justification.CENTER)
        self.textview.connect('key-press-event', self.key_press_event_cb)
        add_css(self.textview, "* { padding: 6px; }")
        vbox = Gtk.VBox()
        vbox.pack_start(self.textview, True, True, 0)
        self._edit_button = Button("Edit Lyrics", Icons.EDIT)
        hbox = Gtk.HBox()
        hbox.pack_end(self._edit_button, False, False, 3)
        vbox.pack_start(hbox, False, False, 3)
        self.scrolled_window.add(vbox)
        self.textview.show()

        self.scrolled_window.show()
        self._sig = None
        cur = app.player.info
        if cur is not None:
            cur = SongWrapper(cur)
        self.plugin_on_song_started(cur)

    def create_sidebar(self):
        vbox = Gtk.VBox(margin=0)
        vbox.pack_start(self.scrolled_window, True, True, 0)
        vbox.show_all()
        return vbox

    def disabled(self):
        self.textview.destroy()
        self.scrolled_window.destroy()

    def plugin_on_song_started(self, song):
        """Called when a song is started. Loads the lyrics.

        If there are lyrics associated with `song`, load them into the
        lyrics viewer. Otherwise, hides the lyrics viewer.
        """
        lyrics = None
        if song is not None:
            print_d("Looking for lyrics for %s" % song("~filename"))
            lyrics = song("~lyrics")
            if lyrics:
                self.textbuffer.set_text(lyrics)
                self.adjustment.set_value(0)    # Scroll to the top.
                self.textview.show()
            else:
                title = _("No lyrics found for\n %s") % song("~basename")
                self._set_italicised(title)

            def edit(widget):
                print_d("Launching lyrics editor for %s" % song("~filename"))
                assert isinstance(song, SongWrapper)
                information = Information(app.librarian, [song._song])
                information.get_child()._switch_to_lyrics()
                information.show()

            if self._sig:
                self._edit_button.disconnect(self._sig)
            self._sig = self._edit_button.connect('clicked', edit)

    def _set_italicised(self, title):
        self.textbuffer.set_text(title)
        start = self.textbuffer.get_start_iter()
        end = self.textbuffer.get_end_iter()
        self.textbuffer.remove_all_tags(start, end)
        self.textbuffer.apply_tag(self._italics, start, end)

    def plugin_on_changed(self, songs):
        cur = app.player.info
        if cur:
            fn = cur("~filename")
            for s in songs:
                if s("~filename") == fn:
                    print_d("Active song changed, reloading lyrics")
                    self.plugin_on_song_started(SongWrapper(cur))
        else:
            self._set_italicised(_("No active song"))

    def key_press_event_cb(self, widget, event):
        """Handles up/down "key-press-event" in the lyrics view."""
        adj = self.scrolled_window.get_vadjustment().props
        if event.keyval == Gdk.KEY_Up:
            adj.value = max(adj.value - adj.step_increment, adj.lower)
        elif event.keyval == Gdk.KEY_Down:
            adj.value = min(adj.value + adj.step_increment,
                            adj.upper - adj.page_size)
        elif event.keyval == Gdk.KEY_Page_Up:
            adj.value = max(adj.value - adj.page_increment, adj.lower)
        elif event.keyval == Gdk.KEY_Page_Down:
            adj.value = min(adj.value + adj.page_increment,
                            adj.upper - adj.page_size)
        elif event.keyval == Gdk.KEY_Home:
            adj.value = adj.lower
        elif event.keyval == Gdk.KEY_End:
            adj.value = adj.upper - adj.page_size
        else:
            return False
        return True
Esempio n. 30
0
    def __init__(self, model):
        songs_text = numeric_phrase("%d duplicate group",
                                    "%d duplicate groups",
                                    len(model))
        super(DuplicateDialog, self).__init__()
        self.set_destroy_with_parent(True)
        self.set_title("Quod Libet - %s (%s)" % (Duplicates.PLUGIN_NAME,
                                                 songs_text))
        self.finished = False
        self.set_default_size(960, 480)
        self.set_border_width(6)
        swin = Gtk.ScrolledWindow()
        swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        swin.set_shadow_type(Gtk.ShadowType.IN)
        # Set up the browser view
        view = DuplicateSongsView(model)

        def cell_text(column, cell, model, iter_, index):
            text = model[iter_][index]
            cell.markup = text
            cell.set_property("markup", text)

        # Set up the columns
        for i, (tag, f) in enumerate(DuplicatesTreeModel.TAG_MAP):
            e = (Pango.EllipsizeMode.START if tag == '~filename'
                else Pango.EllipsizeMode.END)
            render = Gtk.CellRendererText()
            render.set_property("ellipsize", e)
            col = Gtk.TreeViewColumn(util.tag(tag), render)
            # Numeric columns are better smaller here.
            if tag.startswith("~#"):
                col.set_fixed_width(80)
                col.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
            else:
                col.set_expand(True)
                col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
            col.set_resizable(True)
            col.set_cell_data_func(render, cell_text, i + 1)
            view.append_column(col)

        view.connect('popup-menu', self.__songs_popup_menu)
        swin.add(view)
        # A basic information area
        hbox = Gtk.HBox(spacing=6)

        def expand_all(*args):
            model = view.get_model()
            for row in model:
                if view.row_expanded(row.path):
                    view.collapse_row(row.path)
            else:
                for row in model:
                    view.expand_row(row.path, False)

        expand = Gtk.Button(_("Collapse / Expand all"))
        connect_obj(expand, "clicked", expand_all, view)
        hbox.pack_start(expand, False, True, 0)

        label = Gtk.Label(label=_("Duplicate key expression is '%s'") %
                Duplicates.get_key_expression())
        hbox.pack_start(label, True, True, 0)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', self.__quit)
        hbox.pack_start(close, False, True, 0)

        vbox = Gtk.VBox(spacing=6)
        vbox.pack_start(swin, True, True, 0)
        vbox.pack_start(hbox, False, True, 0)
        self.add(vbox)
        self.show_all()
Esempio n. 31
0
    def __init__(self, songs, title=None):
        super().__init__(
            default_width=800, default_height=400, border_width=12,
            title=title)

        self._thread = AcoustidLookupThread(self.__lookup_cb)

        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)

        model = ObjectStore()
        self.view = view = ResultView()
        view.set_model(model)
        self.model = model

        self._iter_map = {}
        for song in songs:
            iter_ = self.model.append([SearchEntry(song)])
            self._iter_map[song] = iter_

        sw.add(view)

        self.pool = pool = FingerPrintPool()
        pool.connect('fingerprint-done', self.__fp_done_cb)
        pool.connect('fingerprint-error', self.__fp_error_cb)
        pool.connect('fingerprint-started', self.__fp_started_cb)
        for song in songs:
            pool.push(song)

        outer_box = Gtk.VBox(spacing=12)

        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.set_spacing(6)
        self.__save = save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        save.connect("clicked", self.__on_save)
        save.set_sensitive(False)
        cancel = Button(_("_Cancel"))
        cancel.connect("clicked", lambda *x: self.destroy())
        bbox.pack_start(save, True, True, 0)
        bbox.pack_start(cancel, True, True, 0)

        inner_box = Gtk.VBox(spacing=6)
        inner_box.pack_start(sw, True, True, 0)

        ccb = ConfigCheckButton(
            _("Write MusicBrainz tags"),
            "plugins", "fingerprint_write_mb_tags")
        ccb.set_active(get_write_mb_tags())
        inner_box.pack_start(ccb, False, True, 0)

        ccb = ConfigCheckButton(
            _("Group by directory"),
            "plugins", "fingerprint_group_by_dir")
        ccb.set_active(get_group_by_dir())
        ccb.connect("toggled", self.__group_toggled)
        self._group_ccb = ccb

        outer_box.pack_start(inner_box, True, True, 0)

        bottom_box = Gtk.HBox(spacing=12)
        mode_button = Gtk.ToggleButton(label=_("Album Mode"))
        mode_button.set_tooltip_text(
            _("Write album related tags and try to "
              "reduce the number of different album releases"))
        mode_button.set_active(True)
        mode_button.connect("toggled", self.__mode_toggle)
        bottom_box.pack_start(mode_button, False, True, 0)
        bottom_box.pack_start(self._group_ccb, False, True, 0)
        bottom_box.pack_start(bbox, True, True, 0)

        outer_box.pack_start(bottom_box, False, True, 0)

        outer_box.show_all()
        self.add(outer_box)

        self.__album_mode = True
        self.__group_by_dir = True
        self._release_scores = {}
        self._directory_scores = {}
        self.__done = 0

        self.connect("destroy", self.__destroy)
Esempio n. 32
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Cover Grid Preferences"))
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._PREVIEW_ITEM["~rating"] = format_rating(0.75)
        self.mag_lock = False

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(
            _("Show album _text"), "browsers", "album_text")
        cb.set_active(config.getboolean("browsers", "album_text"))
        cb.connect('toggled',
                   lambda s: browser.toggle_text())
        vbox.pack_start(cb, False, True, 0)

        cb2 = ConfigCheckButton(
            _("Show \"All Albums\" Item"), "browsers", "covergrid_all")
        cb2.set_active(config.getboolean("browsers", "covergrid_all", False))
        cb2.connect('toggled',
                   lambda s: browser.view.get_model().refilter())
        vbox.pack_start(cb2, False, True, 0)

        cb3 = ConfigCheckButton(
            _("Wide Mode"), "browsers", "covergrid_wide")
        cb3.set_active(config.getboolean("browsers",
            "covergrid_wide", False))
        cb3.connect('toggled',
                   lambda s: browser.toggle_wide())
        vbox.pack_start(cb3, False, True, 0)

        # Redraws the covers only when the user releases the slider
        def mag_button_press(*_):
            self.mag_lock = True

        def mag_button_release(mag, _):
            self.mag_lock = False
            mag_changed(mag)

        def mag_changed(mag):
            if self.mag_lock:
                return
            newmag = mag.get_value()
            oldmag = config.getfloat("browsers", "covergrid_magnification", 3.)
            if newmag == oldmag:
                print_d("Covergrid magnification haven't changed: {0}"
                        .format(newmag))
                return
            print_d('Covergrid magnification update from {0} to {1}'
                    .format(oldmag, newmag))
            config.set("browsers", "covergrid_magnification", mag.get_value())
            browser.update_mag()

        mag_scale = Gtk.HScale(
            adjustment=Gtk.Adjustment.new(config.getfloat("browsers",
                "covergrid_magnification", 3), 0., 10., .5, .5, 0))
        mag_scale.set_tooltip_text(_("Cover Magnification"))
        l = Gtk.Label(label=_("Cover Magnification"))
        mag_scale.set_value_pos(Gtk.PositionType.RIGHT)
        mag_scale.connect('button-press-event', mag_button_press)
        mag_scale.connect('button-release-event', mag_button_release)
        mag_scale.connect('value-changed', mag_changed)

        vbox.pack_start(l, False, True, 0)
        vbox.pack_start(mag_scale, False, True, 0)

        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        display_frame = self.edit_display_pane(browser, _("Album Display"))
        box.pack_start(display_frame, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Esempio n. 33
0
    def PluginPreferences(self, win):
        vb = Gtk.VBox(spacing=6)
        if not self.player_has_eq:
            l = Gtk.Label()
            l.set_markup(
                _('The current backend does not support equalization.'))
            vb.pack_start(l, False, True, 0)
            return vb

        def format_hertz(band):
            if band >= 1000:
                return _('%.1f kHz') % (band / 1000.)
            return _('%d Hz') % band

        bands = [format_hertz(band) for band in app.player.eq_bands]
        levels = get_config() + [0.] * len(bands)

        table = Gtk.Table(rows=len(bands), columns=3)
        table.set_col_spacings(6)

        def set_band(adj, idx):
            levels[idx] = adj.get_value()
            config.set('plugins', 'equalizer_levels',
                       ','.join(map(str, levels)))
            self.apply()

        adjustments = []

        for i, band in enumerate(bands):
            # align numbers and suffixes in separate rows for great justice
            lbl = Gtk.Label(label=band.split()[0])
            lbl.set_alignment(1, 0.5)
            lbl.set_padding(0, 4)
            table.attach(lbl, 0, 1, i, i + 1, xoptions=Gtk.AttachOptions.FILL)
            lbl = Gtk.Label(label=band.split()[1])
            lbl.set_alignment(1, 0.5)
            table.attach(lbl, 1, 2, i, i + 1, xoptions=Gtk.AttachOptions.FILL)
            adj = Gtk.Adjustment(levels[i], -24., 12., 0.1)
            adj.connect('value-changed', set_band, i)
            adjustments.append(adj)
            hs = Gtk.HScale(adjustment=adj)
            hs.set_draw_value(True)
            hs.set_value_pos(Gtk.PositionType.RIGHT)
            hs.connect('format-value', lambda s, v: _('%.1f dB') % v)
            table.attach(hs, 2, 3, i, i + 1)
        vb.pack_start(table, True, True, 0)

        def clicked_cb(button):
            [adj.set_value(0) for adj in adjustments]

        sorted_presets = sorted(PRESETS.iteritems())

        def combo_changed(combo):
            # custom, skip
            if not combo.get_active():
                return
            gain = sorted_presets[combo.get_active() - 1][1][1]
            gain = interp_bands(PRESET_BANDS, app.player.eq_bands, gain)
            for (g, a) in zip(gain, adjustments):
                a.set_value(g)

        combo = Gtk.ComboBoxText()
        combo.append_text(_("Custom"))
        combo.set_active(0)
        for key, (name, gain) in sorted_presets:
            combo.append_text(name)
        combo.connect("changed", combo_changed)

        bbox = Gtk.HButtonBox()
        clear = Button(_("_Clear"), Icons.EDIT_CLEAR)
        clear.connect('clicked', clicked_cb)
        bbox.pack_start(combo, True, True, 0)
        bbox.pack_start(clear, True, True, 0)
        vb.pack_start(bbox, True, True, 0)
        return vb
Esempio n. 34
0
class RenameFiles(Gtk.VBox):
    title = _("Rename Files")
    FILTERS = [
        SpacesToUnderscores, StripWindowsIncompat, StripDiacriticals,
        StripNonASCII, Lowercase
    ]
    handler = RenameFilesPluginHandler()

    @classmethod
    def init_plugins(cls):
        PluginManager.instance.register_handler(cls.handler)

    def __init__(self, parent, library):
        super(RenameFiles, self).__init__(spacing=6)
        self.set_border_width(12)

        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = NBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(NBP,
                                       cbes_defaults,
                                       title=_("Path Patterns"),
                                       edit_title=_(u"Edit saved patterns…"))
        self.combo.show_all()
        hbox.pack_start(self.combo, True, True, 0)
        self.preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)
        self.preview.show()
        hbox.pack_start(self.preview, False, True, 0)
        self.pack_start(hbox, False, True, 0)
        self.combo.get_child().connect('changed', self._changed)

        model = ObjectStore()
        self.view = Gtk.TreeView(model=model)
        self.view.show()

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

        self.pack_start(Gtk.VBox(), False, True, 0)

        filter_box = FilterPluginBox(self.handler, self.FILTERS)
        filter_box.connect("preview", self.__filter_preview)
        filter_box.connect("changed", self.__filter_changed)
        self.filter_box = filter_box
        self.pack_start(filter_box, False, True, 0)

        # Save button
        self.save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save.show()
        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.pack_start(self.save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

        render = Gtk.CellRendererText()
        column = TreeViewColumn(_('File'), render)

        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)

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

        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(_('New Name'), render)

        def cell_data_new_name(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.new_name or u"")

        column.set_cell_data_func(render, cell_data_new_name)

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

        connect_obj(self.preview, 'clicked', self.__preview, None)

        connect_obj(parent, 'changed', self.__class__.__preview, self)
        connect_obj(self.save, 'clicked', self.__rename, library)

        render.connect('edited', self.__row_edited)

        for child in self.get_children():
            child.show()

    def __filter_preview(self, *args):
        Gtk.Button.clicked(self.preview)

    def __filter_changed(self, *args):
        self._changed(self.combo.get_child())

    def _changed(self, entry):
        self.save.set_sensitive(False)
        self.preview.set_sensitive(bool(entry.get_text()))

    def __row_edited(self, renderer, path, new):
        path = Gtk.TreePath.new_from_string(path)
        model = self.view.get_model()
        entry = model[path][0]
        new = gdecode(new)
        if entry.new_name != new:
            entry.new_name = new
            self.preview.set_sensitive(True)
            self.save.set_sensitive(True)
            model.path_changed(path)

    def __rename(self, library):
        model = self.view.get_model()
        win = WritingWindow(self, len(model))
        win.show()
        was_changed = set()
        skip_all = False
        self.view.freeze_child_notify()

        for entry in model.itervalues():
            song = entry.song
            new_name = entry.new_name
            old_name = entry.name
            if new_name is None:
                continue

            try:
                library.rename(song, fsnative(new_name), changed=was_changed)
            except Exception:
                util.print_exc()
                if skip_all:
                    continue
                RESPONSE_SKIP_ALL = 1
                msg = qltk.Message(
                    Gtk.MessageType.ERROR,
                    win,
                    _("Unable to rename file"),
                    _("Renaming <b>%(old-name)s</b> to <b>%(new-name)s</b> "
                      "failed. Possibly the target file already exists, "
                      "or you do not have permission to make the "
                      "new file or remove the old one.") % {
                          "old-name": util.escape(old_name),
                          "new-name": util.escape(new_name),
                      },
                    buttons=Gtk.ButtonsType.NONE)
                msg.add_button(_("Ignore _All Errors"), RESPONSE_SKIP_ALL)
                msg.add_icon_button(_("_Stop"), Icons.PROCESS_STOP,
                                    Gtk.ResponseType.CANCEL)
                msg.add_button(_("_Continue"), Gtk.ResponseType.OK)
                msg.set_default_response(Gtk.ResponseType.OK)
                resp = msg.run()
                skip_all |= (resp == RESPONSE_SKIP_ALL)
                # Preserve old behavior: shift-click is Ignore All
                mods = Gdk.Display.get_default().get_pointer()[3]
                skip_all |= mods & Gdk.ModifierType.SHIFT_MASK
                library.reload(song, changed=was_changed)
                if resp != Gtk.ResponseType.OK and resp != RESPONSE_SKIP_ALL:
                    break
            if win.step():
                break

        self.view.thaw_child_notify()
        win.destroy()
        library.changed(was_changed)
        self.save.set_sensitive(False)

    def __preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [e.song for e in model.itervalues()]

        pattern_text = gdecode(self.combo.get_child().get_text())

        try:
            pattern = FileFromPattern(pattern_text)
        except ValueError:
            qltk.ErrorMessage(
                self, _("Path is not absolute"),
                _("The pattern\n\t<b>%s</b>\ncontains / but "
                  "does not start from root. To avoid misnamed "
                  "folders, root your pattern by starting "
                  "it with / or ~/.") % (util.escape(pattern))).run()
            return
        else:
            if pattern:
                self.combo.prepend_text(pattern_text)
                self.combo.write(NBP)

        # native paths
        orignames = [song["~filename"] for song in songs]
        newnames = [pattern.format(song) for song in songs]
        for f in self.filter_box.filters:
            if f.active:
                newnames = f.filter_list(orignames, newnames)

        model.clear()
        for song, newname in zip(songs, newnames):
            entry = Entry(song)
            entry.new_name = fsdecode(newname)
            model.append(row=[entry])

        self.preview.set_sensitive(False)
        self.save.set_sensitive(bool(pattern_text))
        for song in songs:
            if not song.is_file:
                self.set_sensitive(False)
                break
        else:
            self.set_sensitive(True)
Esempio n. 35
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super().__init__()
        self.set_border_width(12)
        self.set_title(_("Cover Grid Preferences"))
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._PREVIEW_ITEM["~rating"] = format_rating(0.75)
        self.mag_lock = False

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(_("Show album _text"), "browsers", "album_text")
        cb.set_active(config.getboolean("browsers", "album_text"))
        cb.connect('toggled', lambda s: browser.toggle_text())
        vbox.pack_start(cb, False, True, 0)

        cb2 = ConfigCheckButton(_("Show \"All Albums\" Item"), "browsers",
                                "covergrid_all")
        cb2.set_active(config.getboolean("browsers", "covergrid_all", True))

        def refilter(s):
            mod = browser.view.get_model()
            if mod:
                mod.refilter()

        cb2.connect('toggled', refilter)
        vbox.pack_start(cb2, False, True, 0)

        cb3 = ConfigCheckButton(_("Wide Mode"), "browsers", "covergrid_wide")
        cb3.set_active(config.getboolean("browsers", "covergrid_wide", False))
        cb3.connect('toggled', lambda s: browser.toggle_wide())
        vbox.pack_start(cb3, False, True, 0)

        # Redraws the covers only when the user releases the slider
        def mag_button_press(*_):
            self.mag_lock = True

        def mag_button_release(mag, _):
            self.mag_lock = False
            mag_changed(mag)

        def mag_changed(mag):
            if self.mag_lock:
                return
            newmag = mag.get_value()
            oldmag = config.getfloat("browsers", "covergrid_magnification", 3.)
            if newmag == oldmag:
                print_d("Covergrid magnification haven't changed: {0}".format(
                    newmag))
                return
            print_d('Covergrid magnification update from {0} to {1}'.format(
                oldmag, newmag))
            config.set("browsers", "covergrid_magnification", mag.get_value())
            browser.update_mag()

        mag_scale = Gtk.HScale(adjustment=Gtk.Adjustment.new(
            config.getfloat("browsers", "covergrid_magnification", 3), 0., 10.,
            .5, .5, 0))
        mag_scale.set_tooltip_text(_("Cover Magnification"))
        l = Gtk.Label(label=_("Cover Magnification"))
        mag_scale.set_value_pos(Gtk.PositionType.RIGHT)
        mag_scale.connect('button-press-event', mag_button_press)
        mag_scale.connect('button-release-event', mag_button_release)
        mag_scale.connect('value-changed', mag_changed)

        vbox.pack_start(l, False, True, 0)
        vbox.pack_start(mag_scale, False, True, 0)

        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        display_frame = self.edit_display_pane(browser, _("Album Display"))
        box.pack_start(display_frame, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Esempio n. 36
0
    def __init__(self, songs, title=None):
        super(SearchWindow, self).__init__(default_width=800, default_height=400, border_width=12, title=title)

        self._thread = AcoustidLookupThread(self.__lookup_cb)

        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)

        model = ObjectStore()
        self.view = view = ResultView()
        view.set_model(model)
        self.model = model

        self._iter_map = {}
        for song in songs:
            iter_ = self.model.append([SearchEntry(song)])
            self._iter_map[song] = iter_

        sw.add(view)

        self.pool = pool = FingerPrintPool()
        pool.connect("fingerprint-done", self.__fp_done_cb)
        pool.connect("fingerprint-error", self.__fp_error_cb)
        pool.connect("fingerprint-started", self.__fp_started_cb)
        for song in songs:
            pool.push(song)

        outer_box = Gtk.VBox(spacing=12)

        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.set_spacing(6)
        self.__save = save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        save.connect("clicked", self.__on_save)
        save.set_sensitive(False)
        cancel = Button(_("_Cancel"))
        cancel.connect("clicked", lambda *x: self.destroy())
        bbox.pack_start(save, True, True, 0)
        bbox.pack_start(cancel, True, True, 0)

        inner_box = Gtk.VBox(spacing=6)
        inner_box.pack_start(sw, True, True, 0)

        ccb = ConfigCheckButton(_("Write MusicBrainz tags"), "plugins", "fingerprint_write_mb_tags")
        ccb.set_active(get_write_mb_tags())
        inner_box.pack_start(ccb, False, True, 0)

        ccb = ConfigCheckButton(_("Group by directory"), "plugins", "fingerprint_group_by_dir")
        ccb.set_active(get_group_by_dir())
        ccb.connect("toggled", self.__group_toggled)
        self._group_ccb = ccb

        outer_box.pack_start(inner_box, True, True, 0)

        bottom_box = Gtk.HBox(spacing=12)
        mode_button = Gtk.ToggleButton(label=_("Album Mode"))
        mode_button.set_tooltip_text(
            _("Write album related tags and try to " "reduce the number of different album releases")
        )
        mode_button.set_active(True)
        mode_button.connect("toggled", self.__mode_toggle)
        bottom_box.pack_start(mode_button, False, True, 0)
        bottom_box.pack_start(self._group_ccb, False, True, 0)
        bottom_box.pack_start(bbox, True, True, 0)

        outer_box.pack_start(bottom_box, False, True, 0)

        outer_box.show_all()
        self.add(outer_box)

        self.__album_mode = True
        self.__group_by_dir = True
        self._release_scores = {}
        self._directory_scores = {}
        self.__done = 0

        self.connect("destroy", self.__destroy)
Esempio n. 37
0
class WaitLoadBase:
    """Abstract class providing a label, a progressbar, pause/stop buttons,
    and the stepping logic."""
    def __init__(self, count=0, text="", initial={}, limit=3):
        """count: the total amount of items expected, 0 for unknown/indefinite
        text: text to display in the label; may contain % formats
        initial: initial values for % formats (text % initial)
        limit: count must be greater than limit (or 0) for pause/stop to appear

        The current iteration of the counter can be gotten as
        self.current. count can be gotten as self.count.
        """

        super().__init__()

        self._label = Gtk.Label()
        self._label.set_use_markup(True)

        self._progress = Gtk.ProgressBar()
        self._progress.set_pulse_step(0.08)
        self.pulse = self._progress.pulse
        self.set_fraction = self._progress.set_fraction
        self.set_text = self._label.set_markup

        self.setup(count, text, initial)

        if self.count > limit or self.count == 0:
            # Add stop/pause buttons. count = 0 means an indefinite
            # number of steps.
            self._cancel_button = Button(_("_Stop"), Icons.PROCESS_STOP)
            self._pause_button = ToggleButton(_("P_ause"),
                                              Icons.MEDIA_PLAYBACK_PAUSE)
            self._cancel_button.connect('clicked', self.__cancel_clicked)
            self._pause_button.connect('clicked', self.__pause_clicked)
        else:
            self._cancel_button = None
            self._pause_button = None

    def setup(self, count=0, text="", initial=None):
        self.current = 0
        self.count = count
        self._text = text
        self.paused = False
        self.quit = False
        self._start_time = time.time()
        initial = initial or {}

        initial.setdefault("total", self.count)
        initial.setdefault("current", self.current)
        initial.setdefault("remaining", _("Unknown"))

        def localeify(k, v):
            foo = '%(' + k + ')d'
            if foo in self._text:
                self._text = self._text.replace(foo, '%(' + k + ')s')
                return k, format_int_locale(int(v))
            return k, v

        localed = dict([localeify(k, v) for k, v in initial.items()])
        self._label.set_markup(self._text % localed)
        self._progress.set_fraction(0.0)

    def __pause_clicked(self, button):
        self.paused = button.get_active()

    def __cancel_clicked(self, button):
        self.quit = True

    def step(self, **values):
        """Advance the counter by one. Arguments are applied to the
        originally-supplied text as a format string.

        This function doesn't return if the dialog is paused (though
        the GTK main loop will still run), and returns True if stop
        was pressed.
        """

        if self.count:
            self.current += 1
            self._progress.set_fraction(
                max(0, min(1, self.current / float(self.count))))
        else:
            self._progress.pulse()
        values.setdefault("total", format_int_locale(self.count))
        values.setdefault("current", format_int_locale(self.current))
        if self.count:
            t = (time.time() - self._start_time) / self.current
            remaining = math.ceil((self.count - self.current) * t)
            values.setdefault("remaining", format_time_display(remaining))
        self._label.set_markup(self._text % values)

        while not self.quit and (self.paused or Gtk.events_pending()):
            Gtk.main_iteration()
        return self.quit
Esempio n. 38
0
    def PluginPreferences(self, win):
        main_vbox = Gtk.VBox(spacing=12)
        if not self.player_has_eq:
            l = Gtk.Label()
            l.set_markup(
                _('The current backend does not support equalization.'))
            main_vbox.pack_start(l, False, True, 0)
            return main_vbox

        def format_hertz(band):
            if band >= 1000:
                return _('%.1f kHz') % (band / 1000.)
            return _('%d Hz') % band

        bands = [format_hertz(band) for band in app.player.eq_bands]
        self._config = get_config()
        levels = self._config["Current"]

        # This fixes possible old corrupt config files with extra level values.
        if len(levels) != len(bands):
            print_w("Number of bands didn't match current. Using flat EQ.")
            levels = [0.] * len(bands)

        table = Gtk.Table(rows=len(bands), columns=3)
        table.set_col_spacings(6)

        def set_band(adj, idx):
            rounded = int(adj.get_value() * 2) / 2.0
            adj.set_value(rounded)
            levels[idx] = rounded

            self._config["Current"] = levels
            config.set('plugins', 'equalizer_levels', str(self._config))
            self.apply()

        adjustments = []

        for i, band in enumerate(bands):
            # align numbers and suffixes in separate rows for great justice
            lbl = Gtk.Label(label=band.split()[0])
            lbl.set_alignment(1, 0.5)
            lbl.set_padding(0, 4)
            table.attach(lbl, 0, 1, i, i + 1, xoptions=Gtk.AttachOptions.FILL)
            lbl = Gtk.Label(label=band.split()[1])
            lbl.set_alignment(1, 0.5)
            table.attach(lbl, 1, 2, i, i + 1, xoptions=Gtk.AttachOptions.FILL)
            adj = Gtk.Adjustment.new(levels[i], -24., 12., 0.5, 3, 0)
            adj.connect('value-changed', set_band, i)
            adjustments.append(adj)
            hs = Gtk.HScale(adjustment=adj)
            hs.connect('button-press-event', self.__rightclick)
            hs.set_draw_value(True)
            hs.set_value_pos(Gtk.PositionType.RIGHT)
            hs.connect('format-value', lambda s, v: _('%.1f dB') % v)
            table.attach(hs, 2, 3, i, i + 1)
        main_vbox.pack_start(table, True, True, 0)

        # Reset EQ button
        def clicked_rb(button):
            [adj.set_value(0) for adj in adjustments]
            self._combo_default.set_active(0)
            self._combo_custom.set_active(0)

        # Delete custom preset button
        def clicked_db(button):
            selected_index = self._combo_custom.get_active()
            if selected_index < 1:
                return # Select…
            selected = self._combo_custom.get_active_text()
            self._combo_custom.set_active(0)
            self._combo_custom.remove(selected_index)
            del self._config[selected]
            config.set('plugins', 'equalizer_levels', str(self._config))

        # Save custom preset button
        def clicked_sb(button):
            name = self._preset_name_entry.get_text()
            is_new = not name in self._config.keys()

            levels = [adj.get_value() for adj in adjustments]
            self._config[name] = levels
            config.set('plugins', 'equalizer_levels', str(self._config))

            self._preset_name_entry.set_text("")
            if is_new:
                self._combo_custom.append_text(name)

            def find_iter(list_store, text):
                i = list_store.get_iter_first()
                while (i is not None):
                    if list_store.get_value(i, 0) == text:
                        return i
                    i = list_store.iter_next(i)
                return None

            itr = find_iter(self._combo_custom.get_model(), name)
            self._combo_custom.set_active_iter(itr)

        sorted_presets = sorted(PRESETS.items())

        def default_combo_changed(combo):
            if combo.get_active() < 1:
                return # Select…
            self._combo_custom.set_active(0)
            gain = sorted_presets[combo.get_active() - 1][1][1]
            gain = interp_bands(PRESET_BANDS, app.player.eq_bands, gain)
            for (g, a) in zip(gain, adjustments):
                a.set_value(g)

        def custom_combo_changed(combo):
            if combo.get_active() < 1:
                # Case: Select…
                self._delete_button.set_sensitive(False)
                return
            self._combo_default.set_active(0)
            self._delete_button.set_sensitive(True)
            gain = self._config[combo.get_active_text()]
            for (g, a) in zip(gain, adjustments):
                a.set_value(g)

        def save_name_changed(entry):
            name = entry.get_text()
            if not name or name == "Current" or name.isspace():
                self._save_button.set_sensitive(False)
            else:
                self._save_button.set_sensitive(True)

        frame = Gtk.Frame(label=_("Default presets"), label_xalign=0.5)
        main_middle_hbox = Gtk.HBox(spacing=6)

        # Default presets
        combo = Gtk.ComboBoxText()
        self._combo_default = combo
        combo.append_text(_("Select…"))
        combo.set_active(0)
        for key, (name, gain) in sorted_presets:
            combo.append_text(name)
        combo.connect("changed", default_combo_changed)

        # This block is just for padding.
        padboxv = Gtk.VBox()
        padboxv.pack_start(combo, True, True, 6)
        padboxh = Gtk.HBox()
        padboxh.pack_start(padboxv, True, True, 6)
        frame.add(padboxh)

        main_middle_hbox.pack_start(frame, True, True, 0)

        reset = Button(_("_Reset EQ"), Icons.EDIT_UNDO)
        reset.connect('clicked', clicked_rb)
        main_middle_hbox.pack_start(reset, False, False, 0)

        main_vbox.pack_start(main_middle_hbox, False, False, 0)

        frame = Gtk.Frame(label=_("Custom presets"), label_xalign=0.5)
        main_bottom_vbox = Gtk.VBox()

        # Custom presets
        combo = Gtk.ComboBoxText()
        self._combo_custom = combo
        combo.append_text(_("Select…"))
        combo.set_active(0)

        custom_presets = self._config.keys() - {"Current"}
        for key in custom_presets:
            combo.append_text(key)
        combo.connect("changed", custom_combo_changed)
        hb = Gtk.HBox(spacing=6)
        hb.pack_start(combo, True, True, 0)

        delete = Button(_("_Delete selected"), Icons.EDIT_DELETE)
        delete.connect('clicked', clicked_db)
        delete.set_sensitive(False)
        self._delete_button = delete
        hb.pack_start(delete, False, False, 0)

        main_bottom_vbox.pack_start(hb, True, True, 6)
        hs = Gtk.HSeparator()
        main_bottom_vbox.pack_start(hs, True, True, 6)

        hb = Gtk.HBox()
        l = Gtk.Label(label=_("Preset name for saving:"))
        hb.pack_start(l, False, False, 0)
        main_bottom_vbox.pack_start(hb, False, False, 0)

        e = Gtk.Entry()
        e.connect("changed", save_name_changed)
        self._preset_name_entry = e
        hb = Gtk.HBox(spacing=6)
        hb.pack_start(e, True, True, 0)

        save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        save.connect('clicked', clicked_sb)
        save.set_sensitive(False)
        self._save_button = save
        hb.pack_start(save, False, False, 0)

        main_bottom_vbox.pack_start(hb, True, True, 6)

        # This block is just for padding.
        padboxh = Gtk.HBox()
        padboxh.pack_start(main_bottom_vbox, True, True, 6)
        frame.add(padboxh)

        main_vbox.pack_start(frame, True, True, 0)
        return main_vbox
Esempio n. 39
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Album List Preferences") + " - Quod Libet")
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._EXAMPLE_ALBUM["~rating"] = format_rating(0.75)

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(
            _("Show album _covers"), "browsers", "album_covers")
        cb.set_active(config.getboolean("browsers", "album_covers"))
        cb.connect('toggled', lambda s: browser.toggle_covers())
        vbox.pack_start(cb, False, True, 0)

        cb = ConfigCheckButton(
            _("Inline _search includes people"),
            "browsers", "album_substrings")
        cb.set_active(config.getboolean("browsers", "album_substrings"))
        vbox.pack_start(cb, False, True, 0)
        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        vbox = Gtk.VBox(spacing=6)
        label = Gtk.Label()
        label.set_alignment(0.0, 0.5)
        label.set_padding(6, 6)
        eb = Gtk.EventBox()
        eb.get_style_context().add_class("entry")
        eb.add(label)

        edit = PatternEditBox(PATTERN)
        edit.text = browser._pattern_text
        edit.apply.connect('clicked', self.__set_pattern, edit, browser)
        connect_obj(
            edit.buffer, 'changed', self.__preview_pattern, edit, label)

        vbox.pack_start(eb, False, True, 3)
        vbox.pack_start(edit, True, True, 0)
        self.__preview_pattern(edit, label)
        f = qltk.Frame(_("Album Display"), child=vbox)
        box.pack_start(f, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Esempio n. 40
0
class RenameFiles(Gtk.VBox):
    title = _("Rename Files")
    FILTERS = [SpacesToUnderscores, StripWindowsIncompat, StripDiacriticals,
               StripNonASCII, Lowercase]
    handler = RenameFilesPluginHandler()
    IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'bmp']

    @classmethod
    def init_plugins(cls):
        PluginManager.instance.register_handler(cls.handler)

    def __init__(self, parent, library):
        super(RenameFiles, self).__init__(spacing=6)
        self.__skip_interactive = False
        self.set_border_width(12)

        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = NBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(NBP, cbes_defaults,
            title=_("Path Patterns"),
            edit_title=_(u"Edit saved patterns…"))
        self.combo.show_all()
        hbox.pack_start(self.combo, True, True, 0)
        self.preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)
        self.preview.show()
        hbox.pack_start(self.preview, False, True, 0)
        self.pack_start(hbox, False, True, 0)
        self.combo.get_child().connect('changed', self._changed)

        model = ObjectStore()
        self.view = Gtk.TreeView(model=model)
        self.view.show()

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

        self.pack_start(Gtk.VBox(), False, True, 0)

        # rename options
        rename_options = Gtk.HBox()

        # file name options
        filter_box = FilterPluginBox(self.handler, self.FILTERS)
        filter_box.connect("preview", self.__filter_preview)
        filter_box.connect("changed", self.__filter_changed)
        self.filter_box = filter_box

        frame_filename_options = Frame(_("File names"), filter_box)
        frame_filename_options.show_all()
        rename_options.pack_start(frame_filename_options, False, True, 0)

        # album art options
        albumart_box = Gtk.VBox()

        # move art
        moveart_box = Gtk.VBox()
        self.moveart = ConfigCheckButton(
             _('_Move album art'),
             "rename", "move_art", populate=True)
        self.moveart.set_tooltip_text(
             _("See '[albumart] filenames' config entry " +
               "for image search strings"))
        self.moveart.show()
        moveart_box.pack_start(self.moveart, False, True, 0)
        self.moveart_overwrite = ConfigCheckButton(
             _('_Overwrite album art at target'),
             "rename", "move_art_overwrite", populate=True)
        self.moveart_overwrite.show()
        moveart_box.pack_start(self.moveart_overwrite, False, True, 0)
        albumart_box.pack_start(moveart_box, False, True, 0)
        # remove empty
        removeemptydirs_box = Gtk.VBox()
        self.removeemptydirs = ConfigCheckButton(
             _('_Remove empty directories'),
             "rename", "remove_empty_dirs", populate=True)
        self.removeemptydirs.show()
        removeemptydirs_box.pack_start(self.removeemptydirs, False, True, 0)
        albumart_box.pack_start(removeemptydirs_box, False, True, 0)

        frame_albumart_options = Frame(_("Album art"), albumart_box)
        frame_albumart_options.show_all()
        rename_options.pack_start(frame_albumart_options, False, True, 0)

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

        # Save button
        self.save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save.show()
        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.pack_start(self.save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

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

        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)

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

        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(title=_('New Name'))
        column.pack_start(render, True)

        def cell_data_new_name(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.new_name or u"")
        column.set_cell_data_func(render, cell_data_new_name)

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

        connect_obj(self.preview, 'clicked', self._preview, None)

        connect_obj(parent, 'changed', self.__class__._preview, self)
        connect_obj(self.save, 'clicked', self._rename, library)

        render.connect('edited', self.__row_edited)

        for child in self.get_children():
            child.show()

    def __filter_preview(self, *args):
        Gtk.Button.clicked(self.preview)

    def __filter_changed(self, *args):
        self._changed(self.combo.get_child())

    def _changed(self, entry):
        self.save.set_sensitive(False)
        self.preview.set_sensitive(bool(entry.get_text()))

    def __row_edited(self, renderer, path, new):
        path = Gtk.TreePath.new_from_string(path)
        model = self.view.get_model()
        entry = model[path][0]
        if entry.new_name != new:
            entry.new_name = new
            self.preview.set_sensitive(True)
            self.save.set_sensitive(True)
            model.path_changed(path)

    def _rename(self, library):
        model = self.view.get_model()
        win = WritingWindow(self, len(model))
        win.show()
        was_changed = set()
        skip_all = self.__skip_interactive
        self.view.freeze_child_notify()
        should_move_art = config.getboolean("rename", "move_art")
        moveart_sets = {}
        remove_empty_dirs = config.getboolean("rename", "remove_empty_dirs")

        for entry in itervalues(model):
            if entry.new_name is None:
                continue
            song = entry.song
            old_name = entry.name
            old_pathfile = song['~filename']
            new_name = entry.new_name
            new_pathfile = ""
            # ensure target is a full path
            if os.path.abspath(new_name) != \
                   os.path.abspath(os.path.join(os.getcwd(), new_name)):
                new_pathfile = new_name
            else:
                # must be a relative pattern, so prefix the path
                new_pathfile = \
                    os.path.join(os.path.dirname(old_pathfile), new_name)

            try:
                library.rename(song, text2fsn(new_name), changed=was_changed)
            except Exception:
                util.print_exc()
                if skip_all:
                    continue
                RESPONSE_SKIP_ALL = 1
                msg = qltk.Message(
                    Gtk.MessageType.ERROR, win, _("Unable to rename file"),
                    _("Renaming <b>%(old-name)s</b> to <b>%(new-name)s</b> "
                      "failed. Possibly the target file already exists, "
                      "or you do not have permission to make the "
                      "new file or remove the old one.") % {
                        "old-name": util.escape(old_name),
                        "new-name": util.escape(new_name),
                      },
                    buttons=Gtk.ButtonsType.NONE)
                msg.add_button(_("Ignore _All Errors"), RESPONSE_SKIP_ALL)
                msg.add_icon_button(_("_Stop"), Icons.PROCESS_STOP,
                                    Gtk.ResponseType.CANCEL)
                msg.add_button(_("_Continue"), Gtk.ResponseType.OK)
                msg.set_default_response(Gtk.ResponseType.OK)
                resp = msg.run()
                skip_all |= (resp == RESPONSE_SKIP_ALL)
                # Preserve old behavior: shift-click is Ignore All
                mods = Gdk.Display.get_default().get_pointer()[3]
                skip_all |= mods & Gdk.ModifierType.SHIFT_MASK
                library.reload(song, changed=was_changed)
                if resp != Gtk.ResponseType.OK and resp != RESPONSE_SKIP_ALL:
                    break

            if should_move_art:
                self._moveart(moveart_sets, old_pathfile, new_pathfile, song)

            if remove_empty_dirs:
                path_old = os.path.dirname(old_pathfile)
                if not os.listdir(path_old):
                    try:
                        os.rmdir(path_old)
                        print_d("Removed empty directory: %r" % path_old, self)
                    except Exception:
                        util.print_exc()

            if win.step():
                break

        self.view.thaw_child_notify()
        win.destroy()
        library.changed(was_changed)
        self.save.set_sensitive(False)

    def _moveart(self, art_sets, pathfile_old, pathfile_new, song):

        path_old = os.path.dirname(os.path.realpath(pathfile_old))
        path_new = os.path.dirname(os.path.realpath(pathfile_new))
        if os.path.realpath(path_old) == os.path.realpath(path_new):
            return
        if (path_old in art_sets.keys() and not art_sets[path_old]):
            return

        # get art set for path
        images = []
        if path_old in art_sets.keys():
            images = art_sets[path_old]
        else:
            def glob_escape(s):
                for c in '[*?':
                    s = s.replace(c, '[' + c + ']')
                return s

            # generate art set for path
            art_sets[path_old] = images
            path_old_escaped = glob_escape(path_old)
            for suffix in self.IMAGE_EXTENSIONS:
                images.extend(glob.glob(os.path.join(path_old_escaped,
                                                     "*." + suffix)))
        if images:
            # set not empty yet, (re)process
            filenames = config.getstringlist("albumart", "search_filenames")
            moves = []
            for fn in filenames:
                fn = os.path.join(path_old, fn)
                if "<" in fn:
                    # resolve path
                    fnres = ArbitraryExtensionFileFromPattern(fn).format(song)
                    if fnres in images and fnres not in moves:
                        moves.append(fnres)
                elif "*" in fn:
                    moves.extend(f for f in glob.glob(fn)
                                     if f in images and f not in moves)
                elif fn in images and fn not in moves:
                    moves.append(fn)
            if len(moves) > 0:
                overwrite = config.getboolean("rename", "move_art_overwrite")
                for fnmove in moves:
                    try:
                        # existing files safeguarded until move successful,
                        # then deleted if overwrite set
                        fnmoveto = os.path.join(path_new,
                                                os.path.split(fnmove)[1])
                        fnmoveto_orig = ""
                        if os.path.exists(fnmoveto):
                            fnmoveto_orig = fnmoveto + ".orig"
                            if not os.path.exists(fnmoveto_orig):
                                os.rename(fnmoveto, fnmoveto_orig)
                            else:
                                suffix = 1
                                while os.path.exists(fnmoveto_orig +
                                                     "." + str(suffix)):
                                    suffix += 1
                                fnmoveto_orig = (fnmoveto_orig +
                                                 "." + str(suffix))
                                os.rename(fnmoveto, fnmoveto_orig)
                        print_d("Renaming image %r to %r" %
                                   (fnmove, fnmoveto), self)
                        shutil.move(fnmove, fnmoveto)
                        if overwrite and fnmoveto_orig:
                            os.remove(fnmoveto_orig)
                        images.remove(fnmove)
                    except Exception:
                        util.print_exc()

    def _preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [e.song for e in itervalues(model)]

        pattern_text = self.combo.get_child().get_text()

        try:
            pattern = FileFromPattern(pattern_text)
        except ValueError:
            qltk.ErrorMessage(
                self, _("Path is not absolute"),
                _("The pattern\n\t<b>%s</b>\ncontains / but "
                  "does not start from root. To avoid misnamed "
                  "folders, root your pattern by starting "
                  "it with / or ~/.") % (
                util.escape(pattern_text))).run()
            return
        else:
            if pattern:
                self.combo.prepend_text(pattern_text)
                self.combo.write(NBP)

        # native paths
        orignames = [song["~filename"] for song in songs]
        newnames = [fsn2text(pattern.format(song)) for song in songs]
        for f in self.filter_box.filters:
            if f.active:
                newnames = f.filter_list(orignames, newnames)

        model.clear()
        for song, newname in zip(songs, newnames):
            entry = Entry(song)
            entry.new_name = newname
            model.append(row=[entry])

        self.preview.set_sensitive(False)
        self.save.set_sensitive(bool(pattern_text))
        for song in songs:
            if not song.is_file:
                self.set_sensitive(False)
                break
        else:
            self.set_sensitive(True)

    @property
    def test_mode(self):
        return self.__skip_interactive

    @test_mode.setter
    def test_mode(self, value):
        self.__skip_interactive = value
Esempio n. 41
0
    def __init__(self, songs):
        super(FingerprintDialog, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Submit Acoustic Fingerprints"))
        self.set_default_size(300, 0)

        outer_box = Gtk.VBox(spacing=12)

        box = Gtk.VBox(spacing=6)

        self.__label = label = Gtk.Label()
        label.set_markup("<b>%s</b>" % _("Generating fingerprints:"))
        label.set_alignment(0, 0.5)
        box.pack_start(label, False, True, 0)

        self.__bar = bar = Gtk.ProgressBar()
        self.__set_fraction(0)
        box.pack_start(bar, False, True, 0)
        self.__label_song = label_song = Gtk.Label()
        label_song.set_alignment(0, 0.5)
        label_song.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
        box.pack_start(label_song, False, True, 0)

        self.__stats = stats = Gtk.Label()
        stats.set_alignment(0, 0.5)
        expand = Gtk.Expander.new_with_mnemonic(_("_Details"))
        align = Gtk.Alignment.new(0.0, 0.0, 1.0, 1.0)
        align.set_padding(6, 0, 6, 0)
        expand.add(align)
        align.add(stats)

        def expand_cb(expand, *args):
            self.resize(self.get_size()[0], 1)

        stats.connect("unmap", expand_cb)

        box.pack_start(expand, False, False, 0)

        self.__fp_results = {}
        self.__fp_done = 0
        self.__songs = songs
        self.__musicdns_thread = None
        self.__acoustid_thread = None

        self.__update_stats()

        pool = FingerPrintPool()

        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.set_spacing(6)
        self.__submit = submit = Button(_("_Submit"), Gtk.STOCK_APPLY)
        submit.set_sensitive(False)
        submit.connect('clicked', self.__submit_cb)
        cancel = Gtk.Button(stock=Gtk.STOCK_CANCEL)
        cancel.connect_object('clicked', self.__cancel_cb, pool)
        bbox.pack_start(submit, True, True, 0)
        bbox.pack_start(cancel, True, True, 0)

        outer_box.pack_start(box, False, True, 0)
        outer_box.pack_start(bbox, False, True, 0)

        pool.connect('fingerprint-done', self.__fp_done_cb)
        pool.connect('fingerprint-error', self.__fp_error_cb)
        pool.connect('fingerprint-started', self.__fp_started_cb)

        for song in songs:
            pool.push(song)

        self.connect_object('delete-event', self.__cancel_cb, pool)

        self.add(outer_box)
        self.show_all()
Esempio n. 42
0
class RenameFiles(Gtk.VBox):
    title = _("Rename Files")
    FILTERS = [
        SpacesToUnderscores, StripWindowsIncompat, StripDiacriticals,
        StripNonASCII, Lowercase
    ]
    handler = RenameFilesPluginHandler()
    IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'bmp']

    @classmethod
    def init_plugins(cls):
        PluginManager.instance.register_handler(cls.handler)

    def __init__(self, parent, library):
        super(RenameFiles, self).__init__(spacing=6)
        self.__skip_interactive = False
        self.set_border_width(12)

        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = NBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(NBP,
                                       cbes_defaults,
                                       title=_("Path Patterns"),
                                       edit_title=_(u"Edit saved patterns…"))
        self.combo.show_all()
        hbox.pack_start(self.combo, True, True, 0)
        self.preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)
        self.preview.show()
        hbox.pack_start(self.preview, False, True, 0)
        self.pack_start(hbox, False, True, 0)
        self.combo.get_child().connect('changed', self._changed)

        model = ObjectStore()
        self.view = Gtk.TreeView(model=model)
        self.view.show()

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

        self.pack_start(Gtk.VBox(), False, True, 0)

        # rename options
        rename_options = Gtk.HBox()

        # file name options
        filter_box = FilterPluginBox(self.handler, self.FILTERS)
        filter_box.connect("preview", self.__filter_preview)
        filter_box.connect("changed", self.__filter_changed)
        self.filter_box = filter_box

        frame_filename_options = Frame(_("File names"), filter_box)
        frame_filename_options.show_all()
        rename_options.pack_start(frame_filename_options, False, True, 0)

        # album art options
        albumart_box = Gtk.VBox()

        # move art
        moveart_box = Gtk.VBox()
        self.moveart = ConfigCheckButton(_('_Move album art'),
                                         "rename",
                                         "move_art",
                                         populate=True)
        self.moveart.set_tooltip_text(
            _("See '[albumart] filenames' config entry " +
              "for image search strings"))
        self.moveart.show()
        moveart_box.pack_start(self.moveart, False, True, 0)
        self.moveart_overwrite = ConfigCheckButton(
            _('_Overwrite album art at target'),
            "rename",
            "move_art_overwrite",
            populate=True)
        self.moveart_overwrite.show()
        moveart_box.pack_start(self.moveart_overwrite, False, True, 0)
        albumart_box.pack_start(moveart_box, False, True, 0)
        # remove empty
        removeemptydirs_box = Gtk.VBox()
        self.removeemptydirs = ConfigCheckButton(
            _('_Remove empty directories'),
            "rename",
            "remove_empty_dirs",
            populate=True)
        self.removeemptydirs.show()
        removeemptydirs_box.pack_start(self.removeemptydirs, False, True, 0)
        albumart_box.pack_start(removeemptydirs_box, False, True, 0)

        frame_albumart_options = Frame(_("Album art"), albumart_box)
        frame_albumart_options.show_all()
        rename_options.pack_start(frame_albumart_options, False, True, 0)

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

        # Save button
        self.save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save.show()
        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.pack_start(self.save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

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

        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)

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

        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(title=_('New Name'))
        column.pack_start(render, True)

        def cell_data_new_name(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.new_name or u"")

        column.set_cell_data_func(render, cell_data_new_name)

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

        connect_obj(self.preview, 'clicked', self._preview, None)

        connect_obj(parent, 'changed', self.__class__._preview, self)
        connect_obj(self.save, 'clicked', self._rename, library)

        render.connect('edited', self.__row_edited)

        for child in self.get_children():
            child.show()

    def __filter_preview(self, *args):
        Gtk.Button.clicked(self.preview)

    def __filter_changed(self, *args):
        self._changed(self.combo.get_child())

    def _changed(self, entry):
        self.save.set_sensitive(False)
        self.preview.set_sensitive(bool(entry.get_text()))

    def __row_edited(self, renderer, path, new):
        path = Gtk.TreePath.new_from_string(path)
        model = self.view.get_model()
        entry = model[path][0]
        new = gdecode(new)
        if entry.new_name != new:
            entry.new_name = new
            self.preview.set_sensitive(True)
            self.save.set_sensitive(True)
            model.path_changed(path)

    def _rename(self, library):
        model = self.view.get_model()
        win = WritingWindow(self, len(model))
        win.show()
        was_changed = set()
        skip_all = self.__skip_interactive
        self.view.freeze_child_notify()
        should_move_art = config.getboolean("rename", "move_art")
        moveart_sets = {}
        remove_empty_dirs = config.getboolean("rename", "remove_empty_dirs")

        for entry in itervalues(model):
            if entry.new_name is None:
                continue
            song = entry.song
            old_name = entry.name
            old_pathfile = song['~filename']
            new_name = entry.new_name
            new_pathfile = ""
            # ensure target is a full path
            if os.path.abspath(new_name) != \
                   os.path.abspath(os.path.join(os.getcwd(), new_name)):
                new_pathfile = new_name
            else:
                # must be a relative pattern, so prefix the path
                new_pathfile = \
                    os.path.join(os.path.dirname(old_pathfile), new_name)

            try:
                library.rename(song, text2fsn(new_name), changed=was_changed)
            except Exception:
                util.print_exc()
                if skip_all:
                    continue
                RESPONSE_SKIP_ALL = 1
                msg = qltk.Message(
                    Gtk.MessageType.ERROR,
                    win,
                    _("Unable to rename file"),
                    _("Renaming <b>%(old-name)s</b> to <b>%(new-name)s</b> "
                      "failed. Possibly the target file already exists, "
                      "or you do not have permission to make the "
                      "new file or remove the old one.") % {
                          "old-name": util.escape(old_name),
                          "new-name": util.escape(new_name),
                      },
                    buttons=Gtk.ButtonsType.NONE)
                msg.add_button(_("Ignore _All Errors"), RESPONSE_SKIP_ALL)
                msg.add_icon_button(_("_Stop"), Icons.PROCESS_STOP,
                                    Gtk.ResponseType.CANCEL)
                msg.add_button(_("_Continue"), Gtk.ResponseType.OK)
                msg.set_default_response(Gtk.ResponseType.OK)
                resp = msg.run()
                skip_all |= (resp == RESPONSE_SKIP_ALL)
                # Preserve old behavior: shift-click is Ignore All
                mods = Gdk.Display.get_default().get_pointer()[3]
                skip_all |= mods & Gdk.ModifierType.SHIFT_MASK
                library.reload(song, changed=was_changed)
                if resp != Gtk.ResponseType.OK and resp != RESPONSE_SKIP_ALL:
                    break

            if should_move_art:
                self._moveart(moveart_sets, old_pathfile, new_pathfile, song)

            if remove_empty_dirs:
                path_old = os.path.dirname(old_pathfile)
                if not os.listdir(path_old):
                    try:
                        os.rmdir(path_old)
                        print_d("Removed empty directory: %r" % path_old, self)
                    except Exception:
                        util.print_exc()

            if win.step():
                break

        self.view.thaw_child_notify()
        win.destroy()
        library.changed(was_changed)
        self.save.set_sensitive(False)

    def _moveart(self, art_sets, pathfile_old, pathfile_new, song):

        path_old = os.path.dirname(os.path.realpath(pathfile_old))
        path_new = os.path.dirname(os.path.realpath(pathfile_new))
        if os.path.realpath(path_old) == os.path.realpath(path_new):
            return
        if (path_old in art_sets.keys() and not art_sets[path_old]):
            return

        # get art set for path
        images = []
        if path_old in art_sets.keys():
            images = art_sets[path_old]
        else:

            def glob_escape(s):
                for c in '[*?':
                    s = s.replace(c, '[' + c + ']')
                return s

            # generate art set for path
            art_sets[path_old] = images
            path_old_escaped = glob_escape(path_old)
            for suffix in self.IMAGE_EXTENSIONS:
                images.extend(
                    glob.glob(os.path.join(path_old_escaped, "*." + suffix)))
        if images:
            # set not empty yet, (re)process
            filenames = config.getstringlist("albumart", "search_filenames")
            moves = []
            for fn in filenames:
                fn = os.path.join(path_old, fn)
                if "<" in fn:
                    # resolve path
                    fnres = ArbitraryExtensionFileFromPattern(fn).format(song)
                    if fnres in images and fnres not in moves:
                        moves.append(fnres)
                elif "*" in fn:
                    moves.extend(f for f in glob.glob(fn)
                                 if f in images and f not in moves)
                elif fn in images and fn not in moves:
                    moves.append(fn)
            if len(moves) > 0:
                overwrite = config.getboolean("rename", "move_art_overwrite")
                for fnmove in moves:
                    try:
                        # existing files safeguarded until move successful,
                        # then deleted if overwrite set
                        fnmoveto = os.path.join(path_new,
                                                os.path.split(fnmove)[1])
                        fnmoveto_orig = ""
                        if os.path.exists(fnmoveto):
                            fnmoveto_orig = fnmoveto + ".orig"
                            if not os.path.exists(fnmoveto_orig):
                                os.rename(fnmoveto, fnmoveto_orig)
                            else:
                                suffix = 1
                                while os.path.exists(fnmoveto_orig + "." +
                                                     str(suffix)):
                                    suffix += 1
                                fnmoveto_orig = (fnmoveto_orig + "." +
                                                 str(suffix))
                                os.rename(fnmoveto, fnmoveto_orig)
                        print_d("Renaming image %r to %r" % (fnmove, fnmoveto),
                                self)
                        shutil.move(fnmove, fnmoveto)
                        if overwrite and fnmoveto_orig:
                            os.remove(fnmoveto_orig)
                        images.remove(fnmove)
                    except Exception:
                        util.print_exc()

    def _preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [e.song for e in itervalues(model)]

        pattern_text = gdecode(self.combo.get_child().get_text())

        try:
            pattern = FileFromPattern(pattern_text)
        except ValueError:
            qltk.ErrorMessage(
                self, _("Path is not absolute"),
                _("The pattern\n\t<b>%s</b>\ncontains / but "
                  "does not start from root. To avoid misnamed "
                  "folders, root your pattern by starting "
                  "it with / or ~/.") % (util.escape(pattern_text))).run()
            return
        else:
            if pattern:
                self.combo.prepend_text(pattern_text)
                self.combo.write(NBP)

        # native paths
        orignames = [song["~filename"] for song in songs]
        newnames = [fsn2text(pattern.format(song)) for song in songs]
        for f in self.filter_box.filters:
            if f.active:
                newnames = f.filter_list(orignames, newnames)

        model.clear()
        for song, newname in zip(songs, newnames):
            entry = Entry(song)
            entry.new_name = newname
            model.append(row=[entry])

        self.preview.set_sensitive(False)
        self.save.set_sensitive(bool(pattern_text))
        for song in songs:
            if not song.is_file:
                self.set_sensitive(False)
                break
        else:
            self.set_sensitive(True)

    @property
    def test_mode(self):
        return self.__skip_interactive

    @test_mode.setter
    def test_mode(self, value):
        self.__skip_interactive = value
Esempio n. 43
0
    def __init__(self, parent, library):
        super(RenameFiles, self).__init__(spacing=6)
        self.__skip_interactive = False
        self.set_border_width(12)

        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = NBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(NBP,
                                       cbes_defaults,
                                       title=_("Path Patterns"),
                                       edit_title=_(u"Edit saved patterns…"))
        self.combo.show_all()
        hbox.pack_start(self.combo, True, True, 0)
        self.preview = qltk.Button(_("_Preview"), Icons.VIEW_REFRESH)
        self.preview.show()
        hbox.pack_start(self.preview, False, True, 0)
        self.pack_start(hbox, False, True, 0)
        self.combo.get_child().connect('changed', self._changed)

        model = ObjectStore()
        self.view = Gtk.TreeView(model=model)
        self.view.show()

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

        self.pack_start(Gtk.VBox(), False, True, 0)

        # rename options
        rename_options = Gtk.HBox()

        # file name options
        filter_box = FilterPluginBox(self.handler, self.FILTERS)
        filter_box.connect("preview", self.__filter_preview)
        filter_box.connect("changed", self.__filter_changed)
        self.filter_box = filter_box

        frame_filename_options = Frame(_("File names"), filter_box)
        frame_filename_options.show_all()
        rename_options.pack_start(frame_filename_options, False, True, 0)

        # album art options
        albumart_box = Gtk.VBox()

        # move art
        moveart_box = Gtk.VBox()
        self.moveart = ConfigCheckButton(_('_Move album art'),
                                         "rename",
                                         "move_art",
                                         populate=True)
        self.moveart.set_tooltip_text(
            _("See '[albumart] filenames' config entry " +
              "for image search strings"))
        self.moveart.show()
        moveart_box.pack_start(self.moveart, False, True, 0)
        self.moveart_overwrite = ConfigCheckButton(
            _('_Overwrite album art at target'),
            "rename",
            "move_art_overwrite",
            populate=True)
        self.moveart_overwrite.show()
        moveart_box.pack_start(self.moveart_overwrite, False, True, 0)
        albumart_box.pack_start(moveart_box, False, True, 0)
        # remove empty
        removeemptydirs_box = Gtk.VBox()
        self.removeemptydirs = ConfigCheckButton(
            _('_Remove empty directories'),
            "rename",
            "remove_empty_dirs",
            populate=True)
        self.removeemptydirs.show()
        removeemptydirs_box.pack_start(self.removeemptydirs, False, True, 0)
        albumart_box.pack_start(removeemptydirs_box, False, True, 0)

        frame_albumart_options = Frame(_("Album art"), albumart_box)
        frame_albumart_options.show_all()
        rename_options.pack_start(frame_albumart_options, False, True, 0)

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

        # Save button
        self.save = Button(_("_Save"), Icons.DOCUMENT_SAVE)
        self.save.show()
        bbox = Gtk.HButtonBox()
        bbox.set_layout(Gtk.ButtonBoxStyle.END)
        bbox.pack_start(self.save, True, True, 0)
        self.pack_start(bbox, False, True, 0)

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

        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)

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

        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        column = TreeViewColumn(title=_('New Name'))
        column.pack_start(render, True)

        def cell_data_new_name(column, cell, model, iter_, data):
            entry = model.get_value(iter_)
            cell.set_property("text", entry.new_name or u"")

        column.set_cell_data_func(render, cell_data_new_name)

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

        connect_obj(self.preview, 'clicked', self._preview, None)

        connect_obj(parent, 'changed', self.__class__._preview, self)
        connect_obj(self.save, 'clicked', self._rename, library)

        render.connect('edited', self.__row_edited)

        for child in self.get_children():
            child.show()
Esempio n. 44
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()
        self.set_border_width(12)
        self.set_title(_("Album List Preferences"))
        self.set_default_size(420, 380)
        self.set_transient_for(qltk.get_top_parent(browser))
        # Do this config-driven setup at instance-time
        self._EXAMPLE_ALBUM["~rating"] = format_rating(0.75)

        box = Gtk.VBox(spacing=6)
        vbox = Gtk.VBox(spacing=6)
        cb = ConfigCheckButton(_("Show album _covers"), "browsers",
                               "album_covers")
        cb.set_active(config.getboolean("browsers", "album_covers"))
        cb.connect('toggled', lambda s: browser.toggle_covers())
        vbox.pack_start(cb, False, True, 0)

        cb = ConfigCheckButton(_("Inline _search includes people"), "browsers",
                               "album_substrings")
        cb.set_active(config.getboolean("browsers", "album_substrings"))
        vbox.pack_start(cb, False, True, 0)
        f = qltk.Frame(_("Options"), child=vbox)
        box.pack_start(f, False, True, 12)

        vbox = Gtk.VBox(spacing=6)
        label = Gtk.Label()
        label.set_alignment(0.0, 0.5)
        label.set_padding(6, 6)
        eb = Gtk.EventBox()
        eb.get_style_context().add_class("entry")
        eb.add(label)

        edit = PatternEditBox(PATTERN)
        edit.text = browser._pattern_text
        edit.apply.connect('clicked', self.__set_pattern, edit, browser)
        connect_obj(edit.buffer, 'changed', self.__preview_pattern, edit,
                    label)

        vbox.pack_start(eb, False, True, 3)
        vbox.pack_start(edit, True, True, 0)
        self.__preview_pattern(edit, label)
        f = qltk.Frame(_("Album Display"), child=vbox)
        box.pack_start(f, True, True, 0)

        main_box = Gtk.VBox(spacing=12)
        close = Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = Gtk.HButtonBox()
        b.set_layout(Gtk.ButtonBoxStyle.END)
        b.pack_start(close, True, True, 0)

        main_box.pack_start(box, True, True, 0)
        self.use_header_bar()

        if not self.has_close_button():
            main_box.pack_start(b, False, True, 0)
        self.add(main_box)

        close.grab_focus()
        self.show_all()