Exemplo n.º 1
0
 def PluginPreferences(self, parent):
     box = Gtk.HBox()
     ccb = ConfigCheckButton(_("Hide main window on close"),
                             'plugins', 'mpris_window_hide')
     ccb.set_active(self.__do_hide())
     box.pack_start(qltk.Frame(_("Preferences"), child=ccb), True, True, 0)
     return box
Exemplo n.º 2
0
    def PluginPreferences(self, parent):
        prefer_lbl = _("Store cover into the directory of song")
        prefer_key = 'prefer_song_dir'

        grid = Gtk.Grid.new()
        prefer_cb = ConfigCheckButton(prefer_lbl, 'albumart', prefer_key)
        prefer_cb.set_active(config.getboolean('albumart', prefer_key, False))
        grid.attach(prefer_cb, 0, 0, 1, 1)

        return grid
Exemplo n.º 3
0
 def test_populate(self):
     # Assert that active state works
     config.set("memory", "bar", "on")
     c = ConfigCheckButton("dummy", "memory", "bar", populate=True)
     while gtk.events_pending(): gtk.main_iteration()
     self.failUnless(c.get_active())
     # ...and inactive
     config.set("memory", "bar", "off")
     c = ConfigCheckButton("dummy", "memory", "bar", populate=True)
     while gtk.events_pending(): gtk.main_iteration()
     self.failIf(c.get_active())
    def PluginPreferences(self, win):
        items = [
            ('split_disc', 'Split _disc from album', True),
            ('tesbtnlub', 'blbla_ sdfsadfsaf asdf', False),
#            ('year_only', 'Only use year for "date" tag', False),

        ]

        vb = gtk.VBox()
        vb.set_spacing(8)

        for key, label, default in items:
            ccb = ConfigCheckButton(label, 'plugins', 'discogs_' + key)
            ccb.set_active(config_get(key, default))
            vb.pack_start(ccb)

        return vb
Exemplo n.º 5
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super().__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()
Exemplo n.º 6
0
        def __init__(self):
            super(PreferencesWindow.Tagging, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Tags")

            vbox = gtk.VBox(spacing=6)

            cb = ConfigCheckButton(_("Auto-save tag changes"),
                                   'editing', 'auto_save_changes',
                                   populate=True)
            cb.set_tooltip_text(_("Save changes to tags without confirmation "
                                  "when editing multiple files"))
            vbox.pack_start(cb, expand=False)

            cb = ConfigCheckButton(_("Show _programmatic tags"),
                                   'editing', 'alltags', populate=True)
            cb.set_tooltip_text(
                    _("Access all tags, including machine-generated ones "
                      "e.g. MusicBrainz or Replay Gain tags"))
            vbox.pack_start(cb, expand=False)

            hb = gtk.HBox(spacing=6)
            e = UndoEntry()
            e.set_text(config.get("editing", "split_on"))
            e.connect('changed', self.__changed, 'editing', 'split_on')
            e.set_tooltip_text(
                    _("A list of separators to use when splitting tag values. "
                      "The list is space-separated"))
            l = gtk.Label(_("Split _on:"))
            l.set_use_underline(True)
            l.set_mnemonic_widget(e)
            hb.pack_start(l, expand=False)
            hb.pack_start(e)
            vbox.pack_start(hb, expand=False)

            vb2 = gtk.VBox(spacing=6)
            cb = ConfigCheckButton(_("Save ratings and play _counts"),
                                   "editing", "save_to_songs", populate=True)
            vb2.pack_start(cb)
            hb = gtk.HBox(spacing=6)
            lab = gtk.Label(_("_Email:"))
            entry = UndoEntry()
            entry.set_tooltip_text(_("Ratings and play counts will be set "
                                     "for this email address"))
            entry.set_text(config.get("editing", "save_email"))
            entry.connect('changed', self.__changed, 'editing', 'save_email')
            hb.pack_start(lab, expand=False)
            hb.pack_start(entry)
            lab.set_mnemonic_widget(entry)
            lab.set_use_underline(True)
            vb2.pack_start(hb)

            f = qltk.Frame(_("Tag Editing"), child=vbox)
            self.pack_start(f, expand=False)

            f = qltk.Frame(_("Ratings"), child=vb2)
            self.pack_start(f, expand=False)

            self.show_all()
Exemplo n.º 7
0
 def test_toggle(self):
     config.set("memory", "bar", "on")
     c = ConfigCheckButton("dummy", "memory", "bar")
     c.set_active(True)
     self.failUnless(config.getboolean("memory", "bar") and c.get_active())
     c.set_active(False)
     while gtk.events_pending(): gtk.main_iteration()
     self.failIf(config.getboolean("memory", "bar") or c.get_active())
    def __init__(self, parent):
        if self.is_not_unique():
            return
        super(PreferencesWindow, self).__init__()
        self.set_title(_("Ex Falso Preferences"))
        self.set_border_width(12)
        self.set_resizable(False)
        self.set_transient_for(parent)

        vbox = Gtk.VBox(spacing=6)
        hb = Gtk.HBox(spacing=6)
        e = UndoEntry()
        e.set_text(config.get("editing", "split_on"))
        e.connect('changed', self.__changed, 'editing', 'split_on')
        l = Gtk.Label(label=_("Split _on:"))
        l.set_use_underline(True)
        l.set_mnemonic_widget(e)
        hb.pack_start(l, False, True, 0)
        hb.pack_start(e, True, True, 0)
        cb = ConfigCheckButton(
            _("Show _programmatic tags"),
            'editing',
            'alltags',
            tooltip=_("Access all tags, including machine-generated "
                      "ones e.g. MusicBrainz or Replay Gain tags"))
        cb.set_active(config.getboolean("editing", 'alltags'))
        vbox.pack_start(hb, False, True, 0)
        vbox.pack_start(cb, False, True, 0)
        f = qltk.Frame(_("Tag Editing"), child=vbox)

        close = Gtk.Button(stock=Gtk.STOCK_CLOSE)
        close.connect_object('clicked', lambda x: x.destroy(), self)
        button_box = Gtk.HButtonBox()
        button_box.set_layout(Gtk.ButtonBoxStyle.END)
        button_box.pack_start(close, True, True, 0)

        main_vbox = Gtk.VBox(spacing=12)
        main_vbox.pack_start(f, True, True, 0)
        main_vbox.pack_start(button_box, False, True, 0)
        self.add(main_vbox)

        self.connect_object('destroy', PreferencesWindow.__destroy, self)
        self.get_child().show_all()
Exemplo n.º 9
0
    def PluginPreferences(cls, window):
        # Plugin Options
        toggles = [
            (cls._CFG_SEEKABLE_ONLY, _("Only Seekable Sources")),
        ]

        vb = Gtk.VBox(spacing=10)
        vb.set_border_width(0)
        vb2 = Gtk.VBox(spacing=6)
        for key, label in toggles:
            ccb = ConfigCheckButton(label, 'plugins', cls._config_key(key))
            ccb.set_active(cls.config_get_bool(key))
            vb2.pack_start(ccb, True, True, 0)

        frame = qltk.Frame(label=_("Plugin Options"), child=vb2)
        vb.pack_start(frame, False, True, 0)

        vb.show_all()
        return vb
Exemplo n.º 10
0
    def PluginPreferences(self, *args):
        self.__init_defaults()

        hb = Gtk.HBox(spacing=6)
        label = Gtk.Label(label=_("_Theme:"))
        combo = Gtk.ComboBoxText()

        theme = config.get("plugins", self.CONFIG_THEME, None)

        combo.append_text(_("Default Theme"))
        themes = self.__get_themes()
        select = 0
        for i, name in enumerate(sorted(themes)):
            combo.append_text(name)
            if name == theme:
                select = i + 1

        combo.set_active(select)
        combo.connect('changed', self.__changed)

        dark_button = ConfigCheckButton(_("Prefer dark theme version"),
                                        "plugins",
                                        self.CONFIG_DARK,
                                        populate=True,
                                        default=self.__get_dark())

        def dark_cb(button):
            self.__set_dark(button.get_active())

        dark_button.connect('toggled', dark_cb)

        hb_button = ConfigCheckButton(_("Use header bars"),
                                      "plugins",
                                      self.CONFIG_HEADER_BAR,
                                      populate=True,
                                      default=self.__get_header_bar())

        def hb_cb(button):
            self.__set_header_bar(button.get_active())

        hb_button.connect('toggled', hb_cb)

        label.set_mnemonic_widget(combo)
        label.set_use_underline(True)
        hb.pack_start(label, False, True, 0)
        hb.pack_start(combo, False, True, 0)

        vbox = Gtk.VBox(spacing=6)
        vbox.pack_start(hb, False, True, 0)
        vbox.pack_start(dark_button, False, True, 0)
        vbox.pack_start(hb_button, False, True, 0)

        return qltk.Frame(_("Preferences"), child=vbox)
Exemplo n.º 11
0
    def PluginPreferences(self, win):
        items = [
            ('split_disc', 'Split _disc from album', True),
            ('split_feat', 'Split _featured performers from track', False),
            ('year_only', 'Only use year for "date" tag', False),
            ('albumartist', 'Write "_albumartist" when needed', True),
            ('artist_sort', 'Write sort tags for artist names', False),
            ('standard', 'Write _standard MusicBrainz tags', True),
            ('labelid', 'Write _labelid tag (fixes multi-disc albums)', True),
        ]

        vb = Gtk.VBox()
        vb.set_spacing(8)

        for key, label, default in items:
            ccb = ConfigCheckButton(label, 'plugins', 'brainz_' + key)
            ccb.set_active(config_get(key, default))
            vb.pack_start(ccb, True, True, 0)

        return vb
Exemplo n.º 12
0
 def ConfigCheckButton(cls, label, name, default=False):
     """
     Create a new `ConfigCheckButton` for `name`, pre-populated correctly
     """
     option = cls._config_key(name)
     try:
         config.getboolean(PM.CONFIG_SECTION, option)
     except config.Error:
         cls.config_set(name, default)
     return ConfigCheckButton(label, PM.CONFIG_SECTION,
                              option, populate=True)
Exemplo n.º 13
0
    def PluginPreferences(cls, window):
        def key_changed(entry):
            cls.key_expression = None
            cls.config_set(cls._CFG_KEY_KEY, entry.get_text().strip())

        vb = Gtk.VBox(spacing=10)
        vb.set_border_width(0)
        hbox = Gtk.HBox(spacing=6)
        # TODO: construct a decent validator and use ValidatingEntry
        e = UndoEntry()
        e.set_text(cls.get_key_expression())
        e.connect("changed", key_changed)
        e.set_tooltip_markup(
            _("Accepts QL tag expressions like "
              "<tt>~artist~title</tt> or <tt>musicbrainz_track_id</tt>"))
        lbl = Gtk.Label(label=_("_Group duplicates by:"))
        lbl.set_mnemonic_widget(e)
        lbl.set_use_underline(True)
        hbox.pack_start(lbl, False, True, 0)
        hbox.pack_start(e, True, True, 0)
        frame = qltk.Frame(label=_("Duplicate Key"), child=hbox)
        vb.pack_start(frame, True, True, 0)

        # Matching Option
        toggles = [
            (cls._CFG_REMOVE_WHITESPACE, _("Remove _Whitespace")),
            (cls._CFG_REMOVE_DIACRITICS, _("Remove _Diacritics")),
            (cls._CFG_REMOVE_PUNCTUATION, _("Remove _Punctuation")),
            (cls._CFG_CASE_INSENSITIVE, _("Case _Insensitive")),
        ]
        vb2 = Gtk.VBox(spacing=6)
        for key, label in toggles:
            ccb = ConfigCheckButton(label, 'plugins', cls._config_key(key))
            ccb.set_active(cls.config_get_bool(key))
            vb2.pack_start(ccb, True, True, 0)

        frame = qltk.Frame(label=_("Matching options"), child=vb2)
        vb.pack_start(frame, False, True, 0)

        vb.show_all()
        return vb
Exemplo n.º 14
0
    def PluginPreferences(self, win):
        items = [
            ('split_disc', _('Split _disc from album'), True),
            ('split_feat', _('Split _featured performers from track'), False),
            ('year_only', _('Only use year for "date" tag'), False),
            ('albumartist', _('Write "_albumartist" when needed'), True),
            ('artist_sort', _('Write sort tags for artist names'), False),
            ('standard', _('Write _standard MusicBrainz tags'), True),
            ('labelid',
                _('Write _labelid tag (fixes multi-disc albums)'), True),
        ]

        vb = Gtk.VBox()
        vb.set_spacing(8)

        for key, label, default in items:
            ccb = ConfigCheckButton(label, 'plugins', 'brainz_' + key)
            ccb.set_active(config_get(key, default))
            vb.pack_start(ccb, True, True, 0)

        return vb
Exemplo n.º 15
0
    def PluginPreferences(cls, window):
        def key_changed(entry):
            cls.key_expression = None
            cls.config_set(cls._CFG_KEY_KEY, entry.get_text().strip())

        vb = Gtk.VBox(spacing=10)
        vb.set_border_width(0)
        hbox = Gtk.HBox(spacing=6)
        # TODO: construct a decent validator and use ValidatingEntry
        e = UndoEntry()
        e.set_text(cls.get_key_expression())
        e.connect("changed", key_changed)
        e.set_tooltip_markup(_("Accepts QL tag expressions like "
                "<tt>~artist~title</tt> or <tt>musicbrainz_track_id</tt>"))
        lbl = Gtk.Label(label=_("_Group duplicates by:"))
        lbl.set_mnemonic_widget(e)
        lbl.set_use_underline(True)
        hbox.pack_start(lbl, False, True, 0)
        hbox.pack_start(e, True, True, 0)
        frame = qltk.Frame(label=_("Duplicate Key"), child=hbox)
        vb.pack_start(frame, True, True, 0)

        # Matching Option
        toggles = [
            (cls._CFG_REMOVE_WHITESPACE, _("Remove _Whitespace")),
            (cls._CFG_REMOVE_DIACRITICS, _("Remove _Diacritics")),
            (cls._CFG_REMOVE_PUNCTUATION, _("Remove _Punctuation")),
            (cls._CFG_CASE_INSENSITIVE, _("Case _Insensitive")),
        ]
        vb2 = Gtk.VBox(spacing=6)
        for key, label in toggles:
            ccb = ConfigCheckButton(label, 'plugins', cls._config_key(key))
            ccb.set_active(cls.config_get_bool(key))
            vb2.pack_start(ccb, True, True, 0)

        frame = qltk.Frame(label=_("Matching options"), child=vb2)
        vb.pack_start(frame, False, True, 0)

        vb.show_all()
        return vb
Exemplo n.º 16
0
    def PluginPreferences(self, *args):
        self.__init_defaults()

        hb = Gtk.HBox(spacing=6)
        label = Gtk.Label(label=_("_Theme:"))
        combo = Gtk.ComboBoxText()

        theme = config.get("plugins", self.CONFIG_THEME, None)

        combo.append_text(_("Default Theme"))
        themes = self.__get_themes()
        select = 0
        for i, name in enumerate(sorted(themes)):
            combo.append_text(name)
            if name == theme:
                select = i + 1

        combo.set_active(select)
        combo.connect('changed', self.__changed)

        dark_button = ConfigCheckButton(
            _("Prefer dark theme version"),
            "plugins", self.CONFIG_DARK,
            populate=True, default=self.__get_dark())

        def dark_cb(button):
            self.__set_dark(button.get_active())

        dark_button.connect('toggled', dark_cb)

        label.set_mnemonic_widget(combo)
        label.set_use_underline(True)
        hb.pack_start(label, False, True, 0)
        hb.pack_start(combo, False, True, 0)

        vbox = Gtk.VBox(spacing=6)
        vbox.pack_start(hb, False, True, 0)
        vbox.pack_start(dark_button, False, True, 0)

        return qltk.Frame(_("Preferences"), child=vbox)
Exemplo n.º 17
0
    def __init__(self, parent):
        if self.is_not_unique(): return
        super(PreferencesWindow, self).__init__()
        self.set_title(_("Ex Falso Preferences"))
        self.set_border_width(12)
        self.set_resizable(False)
        self.set_transient_for(parent)

        vbox = gtk.VBox(spacing=6)
        hb = gtk.HBox(spacing=6)
        e = UndoEntry()
        e.set_text(config.get("editing", "split_on"))
        e.connect('changed', self.__changed, 'editing', 'split_on')
        l = gtk.Label(_("Split _on:"))
        l.set_use_underline(True)
        l.set_mnemonic_widget(e)
        hb.pack_start(l, expand=False)
        hb.pack_start(e)
        cb = ConfigCheckButton(
            _("Show _programmatic tags"), 'editing', 'alltags')
        cb.set_active(config.getboolean("editing", 'alltags'))
        vbox.pack_start(hb, expand=False)
        vbox.pack_start(cb, expand=False)
        f = qltk.Frame(_("Tag Editing"), child=vbox)

        close = gtk.Button(stock=gtk.STOCK_CLOSE)
        close.connect_object('clicked', lambda x: x.destroy(), self)
        button_box = gtk.HButtonBox()
        button_box.set_layout(gtk.BUTTONBOX_END)
        button_box.pack_start(close)

        main_vbox = gtk.VBox(spacing=12)
        main_vbox.pack_start(f)
        main_vbox.pack_start(button_box, expand=False)
        self.add(main_vbox)

        self.connect_object('destroy', PreferencesWindow.__destroy, self)
        self.show_all()
Exemplo n.º 18
0
    def __init__(self, browser):
        if self.is_not_unique():
            return
        super(Preferences, self).__init__()

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

        self.set_title(_("Paned Browser Preferences"))

        vbox = Gtk.VBox(spacing=12)

        column_modes = ColumnModes(browser)
        column_mode_frame = qltk.Frame(_("Column layout"), child=column_modes)

        editor = PatternEditor()
        editor.headers = get_headers()
        editor_frame = qltk.Frame(_("Column content"), child=editor)

        equal_width = ConfigCheckButton(_("Equal pane width"),
                                        "browsers",
                                        "equal_pane_width",
                                        populate=True)

        apply_ = Button(_("_Apply"))
        connect_obj(apply_, "clicked", self.__apply, editor, browser, False,
                    equal_width)

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

        box = Gtk.HButtonBox()
        box.set_spacing(6)
        box.set_layout(Gtk.ButtonBoxStyle.EDGE)
        box.pack_start(equal_width, True, True, 0)
        box.pack_start(apply_, False, False, 0)
        self.use_header_bar()
        if not self.has_close_button():
            box.pack_start(cancel, True, True, 0)

        vbox.pack_start(column_mode_frame, False, False, 0)
        vbox.pack_start(editor_frame, True, True, 0)
        vbox.pack_start(box, False, True, 0)

        self.add(vbox)

        cancel.grab_focus()
        self.get_child().show_all()
Exemplo n.º 19
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()
Exemplo n.º 20
0
 def test_populate(self):
     # Assert that active state works
     config.set("memory", "bar", "on")
     c = ConfigCheckButton("dummy", "memory", "bar", populate=True)
     run_gtk_loop()
     self.failUnless(c.get_active())
     # ...and inactive
     config.set("memory", "bar", "off")
     c = ConfigCheckButton("dummy", "memory", "bar", populate=True)
     run_gtk_loop()
     self.failIf(c.get_active())
 def test_populate(self):
     # Assert that active state works
     config.set("memory", "bar", "on")
     c = ConfigCheckButton("dummy", "memory", "bar", populate=True)
     while Gtk.events_pending():
         Gtk.main_iteration()
     self.failUnless(c.get_active())
     # ...and inactive
     config.set("memory", "bar", "off")
     c = ConfigCheckButton("dummy", "memory", "bar", populate=True)
     while Gtk.events_pending():
         Gtk.main_iteration()
     self.failIf(c.get_active())
Exemplo n.º 22
0
    def __init__(self, parent):
        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(400, 270)
        self.set_transient_for(qltk.get_top_parent(parent))

        box = gtk.VBox(spacing=6)

        cb = ConfigCheckButton(
            _("Show album _covers"), "browsers", "album_covers")
        cb.set_active(config.getboolean("browsers", "album_covers"))
        gobject_weak(cb.connect, 'toggled', lambda s: AlbumList.toggle_covers())
        box.pack_start(cb, expand=False)

        cb = ConfigCheckButton(
            _("Inline _search includes people"),
            "browsers", "album_substrings")
        cb.set_active(config.getboolean("browsers", "album_substrings"))
        box.pack_start(cb, expand=False)

        vbox = gtk.VBox(spacing=6)
        label = gtk.Label()
        label.set_alignment(0.0, 0.5)
        edit = PatternEditBox(PATTERN)
        edit.text = AlbumList._pattern_text
        gobject_weak(edit.apply.connect, 'clicked', self.__set_pattern, edit)
        gobject_weak(edit.buffer.connect_object, 'changed',
            self.__preview_pattern, edit, label, parent=edit)

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

        main_box = gtk.VBox(spacing=12)
        close = gtk.Button(stock=gtk.STOCK_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        b = gtk.HButtonBox()
        b.set_layout(gtk.BUTTONBOX_END)
        b.pack_start(close)

        main_box.pack_start(box)
        main_box.pack_start(b, expand=False)
        self.add(main_box)

        close.grab_focus()
        self.show_all()
Exemplo n.º 23
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()
Exemplo n.º 24
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()
Exemplo n.º 25
0
        def ratings_vbox(self):
            """Returns a new VBox containing all ratings widgets"""
            vb = Gtk.VBox(spacing=6)

            # Default Rating
            model = Gtk.ListStore(float)
            default_combo = Gtk.ComboBox(model=model)
            default_lab = Gtk.Label(label=_("_Default rating:"))
            default_lab.set_use_underline(True)
            default_lab.set_alignment(0, 0.5)

            def draw_rating(column, cell, model, it, data):
                num = model[it][0]
                text = "%0.2f: %s" % (num, util.format_rating(num))
                cell.set_property('text', text)

            def default_rating_changed(combo, model):
                it = combo.get_active_iter()
                if it is None:
                    return
                RATINGS.default = model[it][0]
                qltk.redraw_all_toplevels()

            def populate_default_rating_model(combo, num):
                model = combo.get_model()
                model.clear()
                deltas = []
                default = RATINGS.default
                precision = RATINGS.precision
                for i in range(0, num + 1):
                    r = i * precision
                    model.append(row=[r])
                    deltas.append((abs(default - r), i))
                active = sorted(deltas)[0][1]
                print_d("Choosing #%d (%.2f), closest to current %.2f"
                        % (active, precision * active, default))
                combo.set_active(active)

            cell = Gtk.CellRendererText()
            default_combo.pack_start(cell, True)
            default_combo.set_cell_data_func(cell, draw_rating, None)
            default_combo.connect('changed', default_rating_changed, model)
            default_lab.set_mnemonic_widget(default_combo)

            def refresh_default_combo(num):
                populate_default_rating_model(default_combo, num)

            # Rating Scale
            model = Gtk.ListStore(int)
            scale_combo = Gtk.ComboBox(model=model)
            scale_lab = Gtk.Label(label=_("Rating _scale:"))
            scale_lab.set_use_underline(True)
            scale_lab.set_mnemonic_widget(scale_combo)

            cell = Gtk.CellRendererText()
            scale_combo.pack_start(cell, False)
            num = RATINGS.number
            for i in [1, 2, 3, 4, 5, 6, 8, 10]:
                it = model.append(row=[i])
                if i == num:
                    scale_combo.set_active_iter(it)

            def draw_rating_scale(column, cell, model, it, data):
                num_stars = model[it][0]
                text = "%d: %s" % (num_stars, RATINGS.full_symbol * num_stars)
                cell.set_property('text', text)

            def rating_scale_changed(combo, model):
                it = combo.get_active_iter()
                if it is None:
                    return
                RATINGS.number = num = model[it][0]
                refresh_default_combo(num)

            refresh_default_combo(RATINGS.number)
            scale_combo.set_cell_data_func(cell, draw_rating_scale, None)
            scale_combo.connect('changed', rating_scale_changed, model)

            default_align = Align(halign=Gtk.Align.START)
            default_align.add(default_lab)
            scale_align = Align(halign=Gtk.Align.START)
            scale_align.add(scale_lab)

            grid = Gtk.Grid(column_spacing=6, row_spacing=6)
            grid.add(scale_align)
            grid.add(scale_combo)
            grid.attach(default_align, 0, 1, 1, 1)
            grid.attach(default_combo, 1, 1, 1, 1)
            vb.pack_start(grid, False, False, 6)

            # Bayesian Factor
            bayesian_factor = config.getfloat("settings",
                                              "bayesian_rating_factor", 0.0)
            adj = Gtk.Adjustment.new(bayesian_factor, 0.0, 10.0, 0.5, 0.5, 0.0)
            bayes_spin = Gtk.SpinButton(adjustment=adj, numeric=True)
            bayes_spin.set_digits(1)
            bayes_spin.connect('changed', self.__changed_and_signal_library,
                               'settings', 'bayesian_rating_factor')
            bayes_spin.set_tooltip_text(
                _("Bayesian Average factor (C) for aggregated ratings.\n"
                  "0 means a conventional average, higher values mean that "
                  "albums with few tracks will have less extreme ratings. "
                  "Changing this value triggers a re-calculation for all "
                  "albums."))
            bayes_label = Gtk.Label(label=_("_Bayesian averaging amount:"))
            bayes_label.set_use_underline(True)
            bayes_label.set_mnemonic_widget(bayes_spin)

            # Save Ratings
            hb = Gtk.HBox(spacing=6)
            hb.pack_start(bayes_label, False, True, 0)
            hb.pack_start(bayes_spin, False, True, 0)
            vb.pack_start(hb, True, True, 0)
            cb = CCB(_("Save ratings and play _counts in tags"),
                     "editing", "save_to_songs", populate=True)

            def update_entry(widget, email_entry):
                email_entry.set_sensitive(widget.get_active())

            vb.pack_start(cb, True, True, 0)
            hb = Gtk.HBox(spacing=6)
            lab = Gtk.Label(label=_("_Email:"))
            entry = UndoEntry()
            entry.set_tooltip_text(_("Ratings and play counts will be saved "
                                     "in tags for this email address"))
            entry.set_text(config.get("editing", "save_email"))
            entry.connect('changed', self.__changed, 'editing', 'save_email')

            # Disable the entry if not saving to tags
            cb.connect('clicked', update_entry, entry)
            update_entry(cb, entry)

            hb.pack_start(lab, False, True, 0)
            hb.pack_start(entry, True, True, 0)
            lab.set_mnemonic_widget(entry)
            lab.set_use_underline(True)
            vb.pack_start(hb, True, True, 0)

            return vb
Exemplo n.º 26
0
        def __init__(self):
            def create_display_frame():
                vbox = Gtk.VBox(spacing=6)
                model = Gtk.ListStore(str, str)

                def on_changed(combo):
                    it = combo.get_active_iter()
                    if it is None:
                        return
                    DURATION.format = model[it][0]
                    app.window.songlist.info.refresh()
                    app.window.qexpander.refresh()
                    # TODO: refresh info windows ideally too (but see #2019)

                def draw_duration(column, cell, model, it, data):
                    df, example = model[it]
                    cell.set_property('text', example)

                for df in sorted(DurationFormat.values):
                    # 4954s == longest ever CD, FWIW
                    model.append([df, format_time_preferred(4954, df)])
                duration = Gtk.ComboBox(model=model)
                cell = Gtk.CellRendererText()
                duration.pack_start(cell, True)
                duration.set_cell_data_func(cell, draw_duration, None)
                index = sorted(DurationFormat.values).index(DURATION.format)
                duration.set_active(index)
                duration.connect('changed', on_changed)
                hbox = Gtk.HBox(spacing=6)
                label = Gtk.Label(label=_("Duration totals") + ":",
                                  use_underline=True)
                label.set_mnemonic_widget(duration)
                hbox.pack_start(label, False, True, 0)
                hbox.pack_start(duration, False, True, 0)

                vbox.pack_start(hbox, False, True, 0)
                return qltk.Frame(_("Display"), child=vbox)

            def create_search_frame():
                vb = Gtk.VBox(spacing=6)
                hb = Gtk.HBox(spacing=6)
                l = Gtk.Label(label=_("_Global filter:"))
                l.set_use_underline(True)
                e = ValidatingEntry(Query.validator)
                e.set_text(config.get("browsers", "background"))
                e.connect('changed', self._entry, 'background', 'browsers')
                e.set_tooltip_text(
                    _("Apply this query in addition to all others"))
                l.set_mnemonic_widget(e)
                hb.pack_start(l, False, True, 0)
                hb.pack_start(e, True, True, 0)
                vb.pack_start(hb, False, True, 0)
                # Translators: The heading of the preference group, no action
                return qltk.Frame(C_("heading", "Search"), child=vb)

            super(PreferencesWindow.Browsers, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Browsers")
            self.pack_start(create_search_frame(), False, True, 0)
            self.pack_start(create_display_frame(), False, True, 0)

            # Ratings
            vb = Gtk.VBox(spacing=6)
            c1 = CCB(_("Confirm _multiple ratings"),
                     'browsers', 'rating_confirm_multiple', populate=True,
                     tooltip=_("Ask for confirmation before changing the "
                               "rating of multiple songs at once"))

            c2 = CCB(_("Enable _one-click ratings"),
                     'browsers', 'rating_click', populate=True,
                     tooltip=_("Enable rating by clicking on the rating "
                               "column in the song list"))

            vbox = Gtk.VBox(spacing=6)
            vbox.pack_start(c1, False, True, 0)
            vbox.pack_start(c2, False, True, 0)
            f = qltk.Frame(_("Ratings"), child=vbox)
            self.pack_start(f, False, True, 0)

            vb = Gtk.VBox(spacing=6)

            # Filename choice algorithm config
            cb = CCB(_("Prefer _embedded art"),
                     'albumart', 'prefer_embedded', populate=True,
                     tooltip=_("Choose to use artwork embedded in the audio "
                               "(where available) over other sources"))
            vb.pack_start(cb, False, True, 0)

            hb = Gtk.HBox(spacing=3)
            cb = CCB(_("_Fixed image filename:"),
                     'albumart', 'force_filename', populate=True,
                     tooltip=_("The single image filename to use if "
                               "selected"))
            hb.pack_start(cb, False, True, 0)

            entry = UndoEntry()
            entry.set_tooltip_text(
                    _("The album art image file to use when forced"))
            entry.set_text(config.get("albumart", "filename"))
            entry.connect('changed', self.__changed_text, 'filename')
            # Disable entry when not forcing
            entry.set_sensitive(cb.get_active())
            cb.connect('toggled', self.__toggled_force_filename, entry)
            hb.pack_start(entry, True, True, 0)
            vb.pack_start(hb, False, True, 0)

            f = qltk.Frame(_("Album Art"), child=vb)
            self.pack_start(f, False, True, 0)

            for child in self.get_children():
                child.show_all()
Exemplo n.º 27
0
    def __init__(self, menu, library, player):
        super(QueueExpander, self).__init__()
        sw = ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
        sw.set_shadow_type(gtk.SHADOW_IN)
        self.queue = PlayQueue(library, player)
        sw.add(self.queue)
        hb = gtk.HBox(spacing=12)

        hb2 = gtk.HBox(spacing=3)
        state = gtk.image_new_from_stock(
            gtk.STOCK_MEDIA_STOP, gtk.ICON_SIZE_MENU)
        hb2.pack_start(state)

        l = gtk.Label(_("_Queue"))
        hb2.pack_start(l)
        hb.pack_start(hb2)
        l.set_use_underline(True)

        clear = gtk.image_new_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU)
        b = gtk.Button()
        b.add(clear)
        b.set_tooltip_text(_("Remove all songs from the queue"))
        b.connect('clicked', self.__clear_queue)
        b.hide()
        b.set_relief(gtk.RELIEF_NONE)
        hb.pack_start(b, expand=False, fill=False)

        l2 = gtk.Label()
        hb.pack_start(l2)

        cb = ConfigCheckButton(
            _("_Random"), "memory", "shufflequeue")
        cb.connect('toggled', self.__queue_shuffle, self.queue.model)
        cb.set_active(config.getboolean("memory", "shufflequeue"))
        hb.pack_start(cb)

        self.set_label_widget(hb)
        self.add(sw)
        self.connect_object('notify::expanded', self.__expand, cb, b)

        targets = [("text/x-quodlibet-songs", gtk.TARGET_SAME_APP, 1),
                   ("text/uri-list", 0, 2)]
        self.drag_dest_set(gtk.DEST_DEFAULT_ALL, targets, gtk.gdk.ACTION_COPY)
        self.connect('drag-motion', self.__motion)
        self.connect('drag-data-received', self.__drag_data_received)

        self.model = self.queue.model
        self.show_all()

        self.queue.model.connect_after('row-inserted',
            util.DeferredSignal(self.__check_expand), l2)
        self.queue.model.connect_after('row-deleted',
            util.DeferredSignal(self.__update_count), l2)
        cb.hide()

        self.connect_object('notify::visible', self.__visible, cb, menu, b)
        self.__update_count(self.model, None, l2)

        player.connect('song-started', self.__update_state_icon, state)
        player.connect('paused', self.__update_state_icon_pause,
                        state, gtk.STOCK_MEDIA_PAUSE)
        player.connect('unpaused', self.__update_state_icon_pause,
                        state, gtk.STOCK_MEDIA_PLAY)

        # to make the children clickable if mapped
        # ....no idea why, but works
        def hack(expander):
            label = expander.get_label_widget()
            if label:
                label.unmap()
                label.map()
        self.connect("map", hack)
Exemplo n.º 28
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
Exemplo n.º 29
0
        def ratings_vbox(self):
            """Returns a new VBox containing all ratings widgets"""
            vb = Gtk.VBox(spacing=6)

            # Default Rating
            model = Gtk.ListStore(float)
            default_combo = Gtk.ComboBox(model=model)
            default_lab = Gtk.Label(label=_("_Default rating:"))
            default_lab.set_use_underline(True)
            default_lab.set_alignment(0, 0.5)

            def draw_rating(column, cell, model, it, data):
                num = model[it][0]
                text = "%0.2f: %s" % (num, util.format_rating(num))
                cell.set_property('text', text)

            def default_rating_changed(combo, model):
                it = combo.get_active_iter()
                if it is None:
                    return
                RATINGS.default = model[it][0]
                qltk.redraw_all_toplevels()

            def populate_default_rating_model(combo, num):
                model = combo.get_model()
                model.clear()
                deltas = []
                default = RATINGS.default
                precision = RATINGS.precision
                for i in range(0, num + 1):
                    r = i * precision
                    model.append(row=[r])
                    deltas.append((abs(default - r), i))
                active = sorted(deltas)[0][1]
                print_d("Choosing #%d (%.2f), closest to current %.2f"
                        % (active, precision * active, default))
                combo.set_active(active)

            cell = Gtk.CellRendererText()
            default_combo.pack_start(cell, True)
            default_combo.set_cell_data_func(cell, draw_rating, None)
            default_combo.connect('changed', default_rating_changed, model)
            default_lab.set_mnemonic_widget(default_combo)

            def refresh_default_combo(num):
                populate_default_rating_model(default_combo, num)

            # Rating Scale
            model = Gtk.ListStore(int)
            scale_combo = Gtk.ComboBox(model=model)
            scale_lab = Gtk.Label(label=_("Rating _scale:"))
            scale_lab.set_use_underline(True)
            scale_lab.set_mnemonic_widget(scale_combo)

            cell = Gtk.CellRendererText()
            scale_combo.pack_start(cell, False)
            num = RATINGS.number
            for i in [1, 2, 3, 4, 5, 6, 8, 10]:
                it = model.append(row=[i])
                if i == num:
                    scale_combo.set_active_iter(it)

            def draw_rating_scale(column, cell, model, it, data):
                num_stars = model[it][0]
                text = "%d: %s" % (num_stars, RATINGS.full_symbol * num_stars)
                cell.set_property('text', text)

            def rating_scale_changed(combo, model):
                it = combo.get_active_iter()
                if it is None:
                    return
                RATINGS.number = num = model[it][0]
                refresh_default_combo(num)

            refresh_default_combo(RATINGS.number)
            scale_combo.set_cell_data_func(cell, draw_rating_scale, None)
            scale_combo.connect('changed', rating_scale_changed, model)

            default_align = Align(halign=Gtk.Align.START)
            default_align.add(default_lab)
            scale_align = Align(halign=Gtk.Align.START)
            scale_align.add(scale_lab)

            grid = Gtk.Grid(column_spacing=6, row_spacing=6)
            grid.add(scale_align)
            grid.add(scale_combo)
            grid.attach(default_align, 0, 1, 1, 1)
            grid.attach(default_combo, 1, 1, 1, 1)
            vb.pack_start(grid, False, False, 6)

            # Bayesian Factor
            bayesian_factor = config.getfloat("settings",
                                              "bayesian_rating_factor", 0.0)
            adj = Gtk.Adjustment.new(bayesian_factor, 0.0, 10.0, 0.5, 0.5, 0.0)
            bayes_spin = Gtk.SpinButton(adjustment=adj, numeric=True)
            bayes_spin.set_digits(1)
            bayes_spin.connect('changed', self.__changed_and_signal_library,
                               'settings', 'bayesian_rating_factor')
            bayes_spin.set_tooltip_text(
                _("Bayesian Average factor (C) for aggregated ratings.\n"
                  "0 means a conventional average, higher values mean that "
                  "albums with few tracks will have less extreme ratings. "
                  "Changing this value triggers a re-calculation for all "
                  "albums."))
            bayes_label = Gtk.Label(label=_("_Bayesian averaging amount:"))
            bayes_label.set_use_underline(True)
            bayes_label.set_mnemonic_widget(bayes_spin)

            # Save Ratings
            hb = Gtk.HBox(spacing=6)
            hb.pack_start(bayes_label, False, True, 0)
            hb.pack_start(bayes_spin, False, True, 0)
            vb.pack_start(hb, True, True, 0)
            cb = CCB(_("Save ratings and play _counts in tags"),
                     "editing", "save_to_songs", populate=True)

            def update_entry(widget, email_entry):
                email_entry.set_sensitive(widget.get_active())

            vb.pack_start(cb, True, True, 0)
            hb = Gtk.HBox(spacing=6)
            lab = Gtk.Label(label=_("_Email:"))
            entry = UndoEntry()
            entry.set_tooltip_text(_("Ratings and play counts will be saved "
                                     "in tags for this email address"))
            entry.set_text(config.get("editing", "save_email"))
            entry.connect('changed', self.__changed, 'editing', 'save_email')

            # Disable the entry if not saving to tags
            cb.connect('clicked', update_entry, entry)
            update_entry(cb, entry)

            hb.pack_start(lab, False, True, 0)
            hb.pack_start(entry, True, True, 0)
            lab.set_mnemonic_widget(entry)
            lab.set_use_underline(True)
            vb.pack_start(hb, True, True, 0)

            return vb
Exemplo n.º 30
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 = Gtk.Button(stock=Gtk.STOCK_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()
Exemplo n.º 31
0
    def __init__(self, library, player):
        super(QueueExpander, self).__init__(spacing=3)
        sw = ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.queue = PlayQueue(library, player)
        self.queue.props.expand = True
        sw.add(self.queue)

        add_css(self, ".ql-expanded title { margin-bottom: 5px; }")

        outer = ExpandBoxHack(spacing=12)

        left = Gtk.HBox(spacing=12)

        hb2 = Gtk.HBox(spacing=3)
        state_icon = PlaybackStatusIcon()
        state_icon.stop()
        state_icon.show()
        hb2.pack_start(state_icon, True, True, 0)
        name_label = Gtk.Label(label=_("_Queue"), use_underline=True)
        hb2.pack_start(name_label, True, True, 0)
        left.pack_start(hb2, False, True, 0)

        b = SmallImageButton(
            image=SymbolicIconImage(Icons.EDIT_CLEAR, Gtk.IconSize.MENU))
        b.set_tooltip_text(_("Remove all songs from the queue"))
        b.connect('clicked', self.__clear_queue)
        b.set_no_show_all(True)
        b.set_relief(Gtk.ReliefStyle.NONE)
        left.pack_start(b, False, False, 0)

        self.count_label = count_label = Gtk.Label()
        left.pack_start(count_label, False, True, 0)

        outer.pack_start(left, True, True, 0)

        close_button = SmallImageButton(
            image=SymbolicIconImage("window-close", Gtk.IconSize.MENU),
            relief=Gtk.ReliefStyle.NONE)

        close_button.connect("clicked", lambda *x: self.hide())

        outer.pack_start(close_button, False, False, 6)
        self.set_label_fill(True)

        cb = ConfigCheckButton(
            _("_Random"), "memory", "shufflequeue")
        cb.connect('toggled', self.__queue_shuffle, self.queue.model)
        cb.set_active(config.getboolean("memory", "shufflequeue"))
        cb.set_no_show_all(True)
        left.pack_start(cb, False, True, 0)

        self.set_label_widget(outer)
        self.add(sw)
        connect_obj(self, 'notify::expanded', self.__expand, cb, b)

        targets = [
            ("text/x-quodlibet-songs", Gtk.TargetFlags.SAME_APP, DND_QL),
            ("text/uri-list", 0, DND_URI_LIST)
        ]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]

        self.drag_dest_set(Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY)
        self.connect('drag-motion', self.__motion)
        self.connect('drag-data-received', self.__drag_data_received)

        self.queue.model.connect_after('row-inserted',
            util.DeferredSignal(self.__check_expand), count_label)
        self.queue.model.connect_after('row-deleted',
            util.DeferredSignal(self.__update_count), count_label)

        connect_obj(self, 'notify::visible', self.__visible, cb, b)
        self.__update_count(self.model, None, count_label)

        connect_destroy(
            player, 'song-started', self.__update_state_icon, state_icon)
        connect_destroy(
            player, 'paused', self.__update_state_icon_pause,
            state_icon, True)
        connect_destroy(
            player, 'unpaused', self.__update_state_icon_pause,
            state_icon, False)

        # to make the children clickable if mapped
        # ....no idea why, but works
        def hack(expander):
            label = expander.get_label_widget()
            if label:
                label.unmap()
                label.map()
        self.connect("map", hack)

        self.set_expanded(config.getboolean("memory", "queue_expanded"))
        self.notify("expanded")

        for child in self.get_children():
            child.show_all()
Exemplo n.º 32
0
    def __init__(self, player, debug=False):
        super(GstPlayerPreferences, self).__init__(spacing=6)

        e = UndoEntry()
        e.set_tooltip_text(_("The GStreamer output pipeline used for "
                "playback. Leave blank for the default pipeline. "
                "In case the pipeline contains a sink, "
                "it will be used instead of the default one."))

        e.set_text(config.get('player', 'gst_pipeline'))

        def changed(entry):
            config.set('player', 'gst_pipeline', entry.get_text())
        e.connect('changed', changed)

        pipe_label = Gtk.Label(label=_('_Output pipeline:'))
        pipe_label.set_use_underline(True)
        pipe_label.set_mnemonic_widget(e)

        apply_button = Gtk.Button(stock=Gtk.STOCK_APPLY)

        def format_buffer(scale, value):
            return _("%.1f seconds") % value

        def scale_changed(scale):
            duration_msec = int(scale.get_value() * 1000)
            player._set_buffer_duration(duration_msec)

        duration = config.getfloat("player", "gst_buffer")
        scale = Gtk.HScale.new(
            Gtk.Adjustment(value=duration, lower=0.2, upper=10))
        scale.set_value_pos(Gtk.PositionType.RIGHT)
        scale.set_show_fill_level(True)
        scale.connect('format-value', format_buffer)
        scale.connect('value-changed', scale_changed)

        buffer_label = Gtk.Label(label=_('_Buffer duration:'))
        buffer_label.set_use_underline(True)
        buffer_label.set_mnemonic_widget(scale)

        def rebuild_pipeline(*args):
            player._rebuild_pipeline()
        apply_button.connect('clicked', rebuild_pipeline)

        gapless_button = ConfigCheckButton(
            _('Disable _gapless playback'),
            "player", "gst_disable_gapless", populate=True)
        gapless_button.set_alignment(0.0, 0.5)
        gapless_button.set_tooltip_text(
            _("Disabling gapless playback can avoid track changing problems "
              "with some GStreamer versions."))

        widgets = [(pipe_label, e, apply_button),
                   (buffer_label, scale, None),
        ]

        table = Gtk.Table(n_rows=len(widgets), n_columns=3)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        for i, (left, middle, right) in enumerate(widgets):
            left.set_alignment(0.0, 0.5)
            table.attach(left, 0, 1, i, i + 1,
                         xoptions=Gtk.AttachOptions.FILL |
                         Gtk.AttachOptions.SHRINK)
            if right:
                table.attach(middle, 1, 2, i, i + 1)
                table.attach(right, 2, 3, i, i + 1,
                             xoptions=Gtk.AttachOptions.FILL |
                             Gtk.AttachOptions.SHRINK)
            else:
                table.attach(middle, 1, 3, i, i + 1)

        table.attach(gapless_button, 0, 3, 2, 3)

        self.pack_start(table, True, True, 0)

        if debug:
            def print_bin(player):
                player._print_pipeline()

            b = Button("Print Pipeline", Gtk.STOCK_DIALOG_INFO)
            connect_obj(b, 'clicked', print_bin, player)
            self.pack_start(b, True, True, 0)
Exemplo n.º 33
0
        def __init__(self):
            super(PreferencesWindow.SongList, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Song List")

            # Behaviour
            vbox = gtk.VBox(spacing=6)
            c = ConfigCheckButton(_("_Jump to playing song automatically"),
                                  'settings', 'jump', populate=True)
            c.set_tooltip_text(_("When the playing song changes, "
                                 "scroll to it in the song list"))
            vbox.pack_start(c, expand=False)
            frame = qltk.Frame(_("Behavior"), child=vbox)
            self.pack_start(frame, expand=False)

            # Columns
            vbox = gtk.VBox(spacing=12)
            buttons = {}
            table = gtk.Table(3, 3)
            table.set_homogeneous(True)
            checks = config.get("settings", "headers").split()
            for j, l in enumerate(
                [[("~#disc", _("_Disc")),
                  ("album", _("Al_bum")),
                  ("~basename",_("_Filename"))],
                 [("~#track", _("_Track")),
                  ("artist", _("_Artist")),
                  ("~#rating", _("_Rating"))],
                 [("title", util.tag("title")),
                  ("date", _("_Date")),
                  ("~#length",_("_Length"))]]):
                for i, (k, t) in enumerate(l):
                    buttons[k] = gtk.CheckButton(t)
                    if k in checks:
                        buttons[k].set_active(True)
                        checks.remove(k)

                    table.attach(buttons[k], i, i + 1, j, j + 1)

            vbox.pack_start(table, expand=False)

            tiv = gtk.CheckButton(_("Title includes _version"))
            if "~title~version" in checks:
                buttons["title"].set_active(True)
                tiv.set_active(True)
                checks.remove("~title~version")
            aip = gtk.CheckButton(_("Album includes _disc subtitle"))
            if "~album~discsubtitle" in checks:
                buttons["album"].set_active(True)
                aip.set_active(True)
                checks.remove("~album~discsubtitle")
            fip = gtk.CheckButton(_("Filename includes _folder"))
            if "~filename" in checks:
                buttons["~basename"].set_active(True)
                fip.set_active(True)
                checks.remove("~filename")

            t = gtk.Table(2, 2)
            t.set_homogeneous(True)
            t.attach(tiv, 0, 1, 0, 1)
            t.attach(aip, 0, 1, 1, 2)
            t.attach(fip, 1, 2, 0, 1)
            vbox.pack_start(t, expand=False)

            hbox = gtk.HBox(spacing=6)
            l = gtk.Label(_("_Others:"))
            hbox.pack_start(l, expand=False)
            others = UndoEntry()
            if "~current" in checks: checks.remove("~current")
            others.set_text(" ".join(checks))
            others.set_tooltip_text(
                _("Other columns to display, separated by spaces"))
            l.set_mnemonic_widget(others)
            l.set_use_underline(True)
            hbox.pack_start(others)
            vbox.pack_start(hbox, expand=False)

            apply = gtk.Button(stock=gtk.STOCK_APPLY)
            apply.connect(
                'clicked', self.__apply, buttons, tiv, aip, fip, others)
            b = gtk.HButtonBox()
            b.set_layout(gtk.BUTTONBOX_END)
            b.pack_start(apply)
            vbox.pack_start(b)

            frame = qltk.Frame(_("Visible Columns"), child=vbox)
            self.pack_start(frame, expand=False)
            self.show_all()
Exemplo n.º 34
0
    def __init__(self, player, debug=False):
        super().__init__(spacing=6)

        e = UndoEntry()
        e.set_tooltip_text(
            _("The GStreamer output pipeline used for "
              "playback. Leave blank for the default pipeline. "
              "In case the pipeline contains a sink, "
              "it will be used instead of the default one."))

        e.set_text(config.get('player', 'gst_pipeline'))

        def changed(entry):
            config.set('player', 'gst_pipeline', entry.get_text())

        e.connect('changed', changed)

        pipe_label = Gtk.Label(label=_('_Output pipeline:'))
        pipe_label.set_use_underline(True)
        pipe_label.set_mnemonic_widget(e)

        apply_button = Button(_("_Apply"))

        def format_buffer(scale, value):
            return _("%.1f seconds") % value

        def scale_changed(scale):
            duration_msec = int(scale.get_value() * 1000)
            player._set_buffer_duration(duration_msec)

        duration = config.getfloat("player", "gst_buffer")
        scale = Gtk.HScale.new(
            Gtk.Adjustment(value=duration, lower=0.2, upper=10))
        scale.set_value_pos(Gtk.PositionType.RIGHT)
        scale.set_show_fill_level(True)
        scale.connect('format-value', format_buffer)
        scale.connect('value-changed', scale_changed)

        buffer_label = Gtk.Label(label=_('_Buffer duration:'))
        buffer_label.set_use_underline(True)
        buffer_label.set_mnemonic_widget(scale)

        def rebuild_pipeline(*args):
            player._rebuild_pipeline()

        apply_button.connect('clicked', rebuild_pipeline)

        gapless_button = ConfigCheckButton(
            _('Disable _gapless playback'),
            "player",
            "gst_disable_gapless",
            populate=True,
            tooltip=_(
                "Disabling gapless playback can avoid track changing problems "
                "with some GStreamer versions"))

        jack_button = ConfigCheckButton(
            _('Use JACK for playback if available'),
            "player",
            "gst_use_jack",
            populate=True,
            tooltip=_(
                "Uses `jackaudiosink` for playbin sink if it can be detected"))
        jack_connect = ConfigCheckButton(
            _('Auto-connect to JACK output devices'),
            "player",
            "gst_jack_auto_connect",
            populate=True,
            tooltip=_("Tells `jackaudiosink` to auto-connect"))

        def _jack_toggled(widget: ConfigCheckButton) -> None:
            jack_connect.set_sensitive(widget.get_active())

        jack_button.connect("clicked", _jack_toggled)
        _jack_toggled(jack_button)
        widgets = [(pipe_label, e, apply_button), (buffer_label, scale, None)]

        table = Gtk.Table(n_rows=len(widgets) + 3, n_columns=3)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        for i, (left, middle, right) in enumerate(widgets):
            left.set_alignment(0.0, 0.5)
            table.attach(left,
                         0,
                         1,
                         i,
                         i + 1,
                         xoptions=Gtk.AttachOptions.FILL
                         | Gtk.AttachOptions.SHRINK)
            if right:
                table.attach(middle, 1, 2, i, i + 1)
                table.attach(right,
                             2,
                             3,
                             i,
                             i + 1,
                             xoptions=Gtk.AttachOptions.FILL
                             | Gtk.AttachOptions.SHRINK)
            else:
                table.attach(middle, 1, 3, i, i + 1)

        table.attach(gapless_button, 0, 3, 2, 3)
        table.attach(jack_button, 0, 3, 3, 4)
        table.attach(jack_connect, 0, 3, 4, 5)

        self.pack_start(table, True, True, 0)

        if debug:

            def print_bin(player):
                player._print_pipeline()

            b = Button("Print Pipeline", Icons.DIALOG_INFORMATION)
            connect_obj(b, 'clicked', print_bin, player)
            self.pack_start(b, True, True, 0)
Exemplo n.º 35
0
        def __init__(self):
            super(PreferencesWindow.Browsers, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Browsers")

            # Search
            vb = Gtk.VBox(spacing=6)
            hb = Gtk.HBox(spacing=6)
            l = Gtk.Label(label=_("_Global filter:"))
            l.set_use_underline(True)
            e = ValidatingEntry(Query.is_valid_color)
            e.set_text(config.get("browsers", "background"))
            e.connect('changed', self._entry, 'background', 'browsers')
            e.set_tooltip_text(_("Apply this query in addition to all others"))
            l.set_mnemonic_widget(e)
            hb.pack_start(l, False, True, 0)
            hb.pack_start(e, True, True, 0)
            vb.pack_start(hb, False, True, 0)

            # Translators: The heading of the preference group, no action
            f = qltk.Frame(Q_("heading|Search"), child=vb)
            self.pack_start(f, False, True, 0)

            # Ratings
            vb = Gtk.VBox(spacing=6)
            c1 = CCB(_("Confirm _multiple ratings"),
                     'browsers', 'rating_confirm_multiple', populate=True,
                     tooltip=_("Ask for confirmation before changing the "
                               "rating of multiple songs at once"))

            c2 = CCB(_("Enable _one-click ratings"),
                     'browsers', 'rating_click', populate=True,
                     tooltip=_("Enable rating by clicking on the rating "
                               "column in the song list"))

            vbox = Gtk.VBox(spacing=6)
            vbox.pack_start(c1, False, True, 0)
            vbox.pack_start(c2, False, True, 0)
            f = qltk.Frame(_("Ratings"), child=vbox)
            self.pack_start(f, False, True, 0)

            # Album Art
            vb = Gtk.VBox(spacing=6)
            c = CCB(_("_Use rounded corners on thumbnails"),
                    'albumart', 'round', populate=True,
                    tooltip=_("Round the corners of album artwork thumbnail "
                              "images. May require restart to take effect."))
            vb.pack_start(c, False, True, 0)

            # Filename choice algorithm config
            cb = CCB(_("Prefer _embedded art"),
                     'albumart', 'prefer_embedded', populate=True,
                     tooltip=_("Choose to use artwork embedded in the audio "
                               "(where available) over other sources"))
            vb.pack_start(cb, False, True, 0)

            hb = Gtk.HBox(spacing=3)
            cb = CCB(_("_Fixed image filename:"),
                     'albumart', 'force_filename', populate=True,
                     tooltip=_("The single image filename to use if "
                               "selected"))
            hb.pack_start(cb, False, True, 0)

            entry = UndoEntry()
            entry.set_tooltip_text(
                    _("The album art image file to use when forced"))
            entry.set_text(config.get("albumart", "filename"))
            entry.connect('changed', self.__changed_text, 'filename')
            # Disable entry when not forcing
            entry.set_sensitive(cb.get_active())
            cb.connect('toggled', self.__toggled_force_filename, entry)
            hb.pack_start(entry, True, True, 0)
            vb.pack_start(hb, False, True, 0)

            f = qltk.Frame(_("Album Art"), child=vb)
            self.pack_start(f, False, True, 0)

            for child in self.get_children():
                child.show_all()
Exemplo n.º 36
0
        def __init__(self):
            super(PreferencesWindow.Browsers, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Browsers")

            # Search
            vb = gtk.VBox(spacing=6)
            hb = gtk.HBox(spacing=6)
            l = gtk.Label(_("_Global filter:"))
            l.set_use_underline(True)
            e = ValidatingEntry(Query.is_valid_color)
            e.set_text(config.get("browsers", "background"))
            e.connect('changed', self._entry, 'background', 'browsers')
            e.set_tooltip_text(_("Apply this query in addition to all others"))
            l.set_mnemonic_widget(e)
            hb.pack_start(l, expand=False)
            hb.pack_start(e)
            vb.pack_start(hb, expand=False)

            c = ConfigCheckButton(_("Search after _typing"),
                                  'settings', 'eager_search', populate=True)
            c.set_tooltip_text(_("Show search results after the user "
                "stops typing."))
            vb.pack_start(c, expand=False)
            # Translators: The heading of the preference group, no action
            f = qltk.Frame(Q_("heading|Search"), child=vb)
            self.pack_start(f, expand=False)

            # Ratings
            vb = gtk.VBox(spacing=6)
            c1 = ConfigCheckButton(
                    _("Confirm _multiple ratings"),
                    'browsers', 'rating_confirm_multiple', populate=True)
            c1.set_tooltip_text(_("Ask for confirmation before changing the "
                                  "rating of multiple songs at once"))

            c2 = ConfigCheckButton(_("Enable _one-click ratings"),
                                   'browsers', 'rating_click', populate=True)
            c2.set_tooltip_text(_("Enable rating by clicking on the rating "
                                  "column in the song list"))

            vbox = gtk.VBox(spacing=6)
            vbox.pack_start(c1, expand=False)
            vbox.pack_start(c2, expand=False)
            f = qltk.Frame(_("Ratings"), child=vbox)
            self.pack_start(f, expand=False)

            # Album Art
            vb = gtk.VBox(spacing=6)
            c = ConfigCheckButton(_("_Use rounded corners on thumbnails"),
                                  'albumart', 'round', populate=True)
            c.set_tooltip_text(_("Round the corners of album artwork "
                    "thumbnail images. May require restart to take effect."))
            vb.pack_start(c, expand=False)

            # Filename choice algorithm config
            cb = ConfigCheckButton(_("Prefer _embedded art"),
                                   'albumart', 'prefer_embedded', populate=True)
            cb.set_tooltip_text(_("Choose to use artwork embedded in the audio "
                                  "(where available) over other sources"))
            vb.pack_start(cb, expand=False)

            hb = gtk.HBox(spacing=3)
            cb = ConfigCheckButton(_("_Force image filename:"),
                                   'albumart', 'force_filename', populate=True)
            hb.pack_start(cb, expand=False)

            entry = UndoEntry()
            entry.set_tooltip_text(
                    _("The album art image file to use when forced"))
            entry.set_text(config.get("albumart", "filename"))
            entry.connect('changed', self.__changed_text, 'filename')
            # Disable entry when not forcing
            entry.set_sensitive(cb.get_active())
            cb.connect('toggled', self.__toggled_force_filename, entry)
            hb.pack_start(entry)
            vb.pack_start(hb, expand=False)

            f = qltk.Frame(_("Album Art"), child=vb)
            self.pack_start(f, expand=False)
Exemplo n.º 37
0
    def __init__(self, parent, library):
        super(EditTags, self).__init__(spacing=12)
        self.title = _("Edit Tags")
        self.set_border_width(12)

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

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

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

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

        column.set_cell_data_func(render, cell_data_tag)

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

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

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

        column.set_cell_data_func(render, cell_data_value)

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

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

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

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

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

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

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

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

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

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

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

        self._parent = parent

        for child in self.get_children():
            child.show_all()
Exemplo n.º 38
0
    def __init__(self, player, debug=False):
        super(GstPlayerPreferences, self).__init__(spacing=6)

        e = UndoEntry()
        e.set_tooltip_text(
            _("The GStreamer output pipeline used for "
              "playback, such as 'alsasink device=default'. "
              "Leave blank for default pipeline."))
        e.set_text(config.get('player', 'gst_pipeline'))

        def changed(entry):
            config.set('player', 'gst_pipeline', entry.get_text())

        e.connect('changed', changed)

        pipe_label = Gtk.Label(label=_('_Output pipeline:'))
        pipe_label.set_use_underline(True)
        pipe_label.set_mnemonic_widget(e)

        apply_button = Gtk.Button(stock=Gtk.STOCK_APPLY)

        def format_buffer(scale, value):
            return _("%.1f seconds") % value

        def scale_changed(scale):
            duration_msec = int(scale.get_value() * 1000)
            player._set_buffer_duration(duration_msec)

        duration = config.getfloat("player", "gst_buffer")
        scale = Gtk.HScale.new(Gtk.Adjustment(duration, 0.2, 10))
        scale.set_value_pos(Gtk.PositionType.RIGHT)
        scale.set_show_fill_level(True)
        scale.connect('format-value', format_buffer)
        scale.connect('value-changed', scale_changed)

        buffer_label = Gtk.Label(label=_('_Buffer duration:'))
        buffer_label.set_use_underline(True)
        buffer_label.set_mnemonic_widget(scale)

        def rebuild_pipeline(*args):
            player._rebuild_pipeline()

        apply_button.connect('clicked', rebuild_pipeline)

        gapless_button = ConfigCheckButton(_('Disable _gapless playback'),
                                           "player",
                                           "gst_disable_gapless",
                                           populate=True)
        gapless_button.set_alignment(0.0, 0.5)
        gapless_button.set_tooltip_text(
            _("Disabling gapless playback can avoid track changing problems "
              "with some GStreamer versions."))

        widgets = [
            (pipe_label, e, apply_button),
            (buffer_label, scale, None),
        ]

        table = Gtk.Table(len(widgets), 3)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        for i, (left, middle, right) in enumerate(widgets):
            left.set_alignment(0.0, 0.5)
            table.attach(left,
                         0,
                         1,
                         i,
                         i + 1,
                         xoptions=Gtk.AttachOptions.FILL
                         | Gtk.AttachOptions.SHRINK)
            if right:
                table.attach(middle, 1, 2, i, i + 1)
                table.attach(right,
                             2,
                             3,
                             i,
                             i + 1,
                             xoptions=Gtk.AttachOptions.FILL
                             | Gtk.AttachOptions.SHRINK)
            else:
                table.attach(middle, 1, 3, i, i + 1)

        table.attach(gapless_button, 0, 3, 2, 3)

        self.pack_start(table, True, True, 0)

        if debug:

            def print_bin(player):
                player._print_pipeline()

            b = Button("Print Pipeline", Gtk.STOCK_DIALOG_INFO)
            b.connect_object('clicked', print_bin, player)
            self.pack_start(b, True, True, 0)
Exemplo n.º 39
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)
Exemplo n.º 40
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)
Exemplo n.º 41
0
        def __init__(self):
            def create_display_frame():
                vbox = Gtk.VBox(spacing=6)
                model = Gtk.ListStore(str, str)

                def on_changed(combo):
                    it = combo.get_active_iter()
                    if it is None:
                        return
                    DURATION.format = model[it][0]
                    app.window.songlist.info.refresh()
                    app.window.qexpander.refresh()
                    # TODO: refresh info windows ideally too (but see #2019)

                def draw_duration(column, cell, model, it, data):
                    df, example = model[it]
                    cell.set_property('text', example)

                for df in sorted(DurationFormat.values):
                    # 4954s == longest ever CD, FWIW
                    model.append([df, format_time_preferred(4954, df)])
                duration = Gtk.ComboBox(model=model)
                cell = Gtk.CellRendererText()
                duration.pack_start(cell, True)
                duration.set_cell_data_func(cell, draw_duration, None)
                index = sorted(DurationFormat.values).index(DURATION.format)
                duration.set_active(index)
                duration.connect('changed', on_changed)
                hbox = Gtk.HBox(spacing=6)
                label = Gtk.Label(label=_("Duration totals") + ":",
                                  use_underline=True)
                label.set_mnemonic_widget(duration)
                hbox.pack_start(label, False, True, 0)
                hbox.pack_start(duration, False, True, 0)

                vbox.pack_start(hbox, False, True, 0)
                return qltk.Frame(_("Display"), child=vbox)

            def create_search_frame():
                vb = Gtk.VBox(spacing=6)
                hb = Gtk.HBox(spacing=6)
                l = Gtk.Label(label=_("_Global filter:"))
                l.set_use_underline(True)
                e = ValidatingEntry(Query.validator)
                e.set_text(config.get("browsers", "background"))
                e.connect('changed', self._entry, 'background', 'browsers')
                e.set_tooltip_text(
                    _("Apply this query in addition to all others"))
                l.set_mnemonic_widget(e)
                hb.pack_start(l, False, True, 0)
                hb.pack_start(e, True, True, 0)
                vb.pack_start(hb, False, True, 0)
                # Translators: The heading of the preference group, no action
                return qltk.Frame(C_("heading", "Search"), child=vb)

            super().__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Browsers")
            self.pack_start(create_search_frame(), False, True, 0)
            self.pack_start(create_display_frame(), False, True, 0)

            # Ratings
            vb = Gtk.VBox(spacing=6)
            c1 = CCB(_("Confirm _multiple ratings"),
                     'browsers', 'rating_confirm_multiple', populate=True,
                     tooltip=_("Ask for confirmation before changing the "
                               "rating of multiple songs at once"))

            c2 = CCB(_("Enable _one-click ratings"),
                     'browsers', 'rating_click', populate=True,
                     tooltip=_("Enable rating by clicking on the rating "
                               "column in the song list"))

            vbox = Gtk.VBox(spacing=6)
            vbox.pack_start(c1, False, True, 0)
            vbox.pack_start(c2, False, True, 0)
            f = qltk.Frame(_("Ratings"), child=vbox)
            self.pack_start(f, False, True, 0)

            vb = Gtk.VBox(spacing=6)

            # Filename choice algorithm config
            cb = CCB(_("Prefer _embedded art"),
                     'albumart', 'prefer_embedded', populate=True,
                     tooltip=_("Choose to use artwork embedded in the audio "
                               "(where available) over other sources"))
            vb.pack_start(cb, False, True, 0)

            hb = Gtk.HBox(spacing=3)

            preferred_image_filename_tooltip = _(
                "The album art image file(s) to use when available "
                "(supports wildcards). If you want to supply more "
                "than one, separate them with commas.")

            cb = CCB(_("_Preferred image filename(s):"),
                     'albumart', 'force_filename', populate=True,
                     tooltip=preferred_image_filename_tooltip)
            hb.pack_start(cb, False, True, 0)

            entry = UndoEntry()
            entry.set_tooltip_text(preferred_image_filename_tooltip)
            entry.set_text(config.get("albumart", "filename"))
            entry.connect('changed', self.__changed_text, 'filename')
            # Disable entry when not forcing
            entry.set_sensitive(cb.get_active())
            cb.connect('toggled', self.__toggled_force_filename, entry)
            hb.pack_start(entry, True, True, 0)
            vb.pack_start(hb, False, True, 0)

            f = qltk.Frame(_("Album Art"), child=vb)
            self.pack_start(f, False, True, 0)

            for child in self.get_children():
                child.show_all()
Exemplo n.º 42
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()
Exemplo n.º 43
0
    def __init__(self, activator):
        super(Preferences, self).__init__(spacing=12)

        self.set_border_width(6)

        ccb = ConfigCheckButton(_("Hide main window on close"), 'plugins',
                                'trayicon_window_hide')
        ccb.set_active(get_hide_window())
        self.pack_start(ccb, False, True, 0)

        combo = Gtk.ComboBoxText()
        combo.append_text(
            _("Scroll wheel adjusts volume\n"
              "Shift and scroll wheel changes song"))
        combo.append_text(
            _("Scroll wheel changes song\n"
              "Shift and scroll wheel adjusts volume"))
        combo.set_active(
            int(config.getboolean("plugins", "icon_modifier_swap", False)))
        combo.connect('changed', self.__changed_combo)

        self.pack_start(qltk.Frame(_("Scroll _Wheel"), child=combo), True,
                        True, 0)

        box = Gtk.VBox(spacing=12)
        table = Gtk.Table(n_rows=2, n_columns=4)
        table.set_row_spacings(6)
        table.set_col_spacings(12)

        cbs = []
        for i, tag in enumerate([
                "genre", "artist", "album", "discnumber", "part",
                "tracknumber", "title", "version"
        ]):
            cb = Gtk.CheckButton(label=util.tag(tag))
            cb.tag = tag
            cbs.append(cb)
            table.attach(cb, i % 3, i % 3 + 1, i // 3, i // 3 + 1)
        box.pack_start(table, True, True, 0)

        entry = Gtk.Entry()
        box.pack_start(entry, False, True, 0)

        preview = Gtk.Label()
        preview.set_ellipsize(Pango.EllipsizeMode.END)
        ev = Gtk.EventBox()
        ev.add(preview)
        box.pack_start(ev, False, True, 0)

        frame = qltk.Frame(_("Tooltip Display"), child=box)
        frame.get_label_widget().set_mnemonic_widget(entry)
        self.pack_start(frame, True, True, 0)

        for cb in cbs:
            cb.connect('toggled', self.__changed_cb, cbs, entry)
        entry.connect('changed', self.__changed_entry, cbs, preview)
        try:
            entry.set_text(config.get("plugins", "icon_tooltip"))
        except:
            entry.set_text(
                "<album|<album~discnumber~part~tracknumber~title~version>|"
                "<artist~title~version>>")

        for child in self.get_children():
            child.show_all()
Exemplo n.º 44
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
Exemplo n.º 45
0
        def __init__(self):
            super(PreferencesWindow.Player, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Playback")

            # player backend
            if app.player and hasattr(app.player, 'PlayerPreferences'):
                player_prefs = app.player.PlayerPreferences()
                f = qltk.Frame(_("Output Configuration"), child=player_prefs)
                self.pack_start(f, False, True, 0)

            # replaygain
            fallback_gain = config.getfloat("player", "fallback_gain", 0.0)
            adj = Gtk.Adjustment.new(fallback_gain, -12.0, 12.0, 0.5, 0.5, 0.0)
            fb_spin = Gtk.SpinButton(adjustment=adj)
            fb_spin.set_digits(1)
            fb_spin.connect('changed', self.__changed,
                            'player', 'fallback_gain')
            fb_spin.set_tooltip_text(
                _("If no Replay Gain information is available "
                  "for a song, scale the volume by this value"))

            fb_label = Gtk.Label(label=_("_Fall-back gain (dB):"))
            fb_label.set_use_underline(True)
            fb_label.set_mnemonic_widget(fb_spin)

            pre_amp_gain = config.getfloat("player", "pre_amp_gain", 0.0)
            adj = Gtk.Adjustment.new(pre_amp_gain, -6, 6, 0.5, 0.5, 0.0)
            adj.connect('value-changed', self.__changed,
                        'player', 'pre_amp_gain')
            pre_spin = Gtk.SpinButton(adjustment=adj)
            pre_spin.set_digits(1)
            pre_spin.set_tooltip_text(
                _("Scale volume for all songs by this value, "
                  "as long as the result will not clip"))

            pre_label = Gtk.Label(label=_("_Pre-amp gain (dB):"))
            pre_label.set_use_underline(True)
            pre_label.set_mnemonic_widget(pre_spin)

            widgets = [pre_label, pre_spin, fb_label, fb_spin]
            c = CCB(_("_Enable Replay Gain volume adjustment"),
                    "player", "replaygain", populate=True)
            c.connect('toggled', self.__toggled_gain, widgets)

            # packing
            table = Gtk.Table.new(3, 2, False)
            table.set_col_spacings(6)
            table.set_row_spacings(6)

            table.attach(c, 0, 2, 0, 1)
            fb_label.set_alignment(0, 0.5)
            table.attach(fb_label, 0, 1, 1, 2,
                         xoptions=Gtk.AttachOptions.FILL)
            pre_label.set_alignment(0, 0.5)
            table.attach(pre_label, 0, 1, 2, 3,
                         xoptions=Gtk.AttachOptions.FILL)

            fb_align = Align(halign=Gtk.Align.START)
            fb_align.add(fb_spin)
            table.attach(fb_align, 1, 2, 1, 2)

            pre_align = Align(halign=Gtk.Align.START)
            pre_align.add(pre_spin)
            table.attach(pre_align, 1, 2, 2, 3)

            f = qltk.Frame(_("Replay Gain Volume Adjustment"), child=table)

            c.emit('toggled')

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

            for child in self.get_children():
                child.show_all()
Exemplo n.º 46
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()
Exemplo n.º 47
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()
Exemplo n.º 48
0
    def __init__(self, activator):
        super(Preferences, self).__init__(spacing=12)

        self.set_border_width(6)

        ccb = ConfigCheckButton(_("Hide main window on close"),
                                'plugins', 'trayicon_window_hide')
        ccb.set_active(get_hide_window())
        self.pack_start(ccb, False, True, 0)

        combo = Gtk.ComboBoxText()
        combo.append_text(_("Scroll wheel adjusts volume\n"
                            "Shift and scroll wheel changes song"))
        combo.append_text(_("Scroll wheel changes song\n"
                            "Shift and scroll wheel adjusts volume"))
        combo.set_active(int(
                config.getboolean("plugins", "icon_modifier_swap", False)))
        combo.connect('changed', self.__changed_combo)

        self.pack_start(qltk.Frame(_("Scroll _Wheel"), child=combo),
                        True, True, 0)

        box = Gtk.VBox(spacing=12)
        table = Gtk.Table(n_rows=2, n_columns=4)
        table.set_row_spacings(6)
        table.set_col_spacings(12)

        cbs = []
        for i, tag in enumerate([
                "genre", "artist", "album", "discnumber", "part",
                "tracknumber", "title", "version"]):
            cb = Gtk.CheckButton(label=util.tag(tag))
            cb.tag = tag
            cbs.append(cb)
            table.attach(cb, i % 3, i % 3 + 1, i // 3, i // 3 + 1)
        box.pack_start(table, True, True, 0)

        entry = Gtk.Entry()
        box.pack_start(entry, False, True, 0)

        preview = Gtk.Label()
        preview.set_ellipsize(Pango.EllipsizeMode.END)
        ev = Gtk.EventBox()
        ev.add(preview)
        box.pack_start(ev, False, True, 0)

        frame = qltk.Frame(_("Tooltip Display"), child=box)
        frame.get_label_widget().set_mnemonic_widget(entry)
        self.pack_start(frame, True, True, 0)

        for cb in cbs:
            cb.connect('toggled', self.__changed_cb, cbs, entry)
        entry.connect(
            'changed', self.__changed_entry, cbs, preview)
        try:
            entry.set_text(config.get("plugins", "icon_tooltip"))
        except:
            entry.set_text(
                "<album|<album~discnumber~part~tracknumber~title~version>|"
                "<artist~title~version>>")

        for child in self.get_children():
            child.show_all()
Exemplo n.º 49
0
        def __init__(self):
            super(PreferencesWindow.Browsers, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Browsers")

            # Search
            vb = Gtk.VBox(spacing=6)
            hb = Gtk.HBox(spacing=6)
            l = Gtk.Label(label=_("_Global filter:"))
            l.set_use_underline(True)
            e = ValidatingEntry(QueryValidator)
            e.set_text(config.get("browsers", "background"))
            e.connect('changed', self._entry, 'background', 'browsers')
            e.set_tooltip_text(_("Apply this query in addition to all others"))
            l.set_mnemonic_widget(e)
            hb.pack_start(l, False, True, 0)
            hb.pack_start(e, True, True, 0)
            vb.pack_start(hb, False, True, 0)

            # Translators: The heading of the preference group, no action
            f = qltk.Frame(C_("heading", "Search"), child=vb)
            self.pack_start(f, False, True, 0)

            # Ratings
            vb = Gtk.VBox(spacing=6)
            c1 = CCB(_("Confirm _multiple ratings"),
                     'browsers', 'rating_confirm_multiple', populate=True,
                     tooltip=_("Ask for confirmation before changing the "
                               "rating of multiple songs at once"))

            c2 = CCB(_("Enable _one-click ratings"),
                     'browsers', 'rating_click', populate=True,
                     tooltip=_("Enable rating by clicking on the rating "
                               "column in the song list"))

            vbox = Gtk.VBox(spacing=6)
            vbox.pack_start(c1, False, True, 0)
            vbox.pack_start(c2, False, True, 0)
            f = qltk.Frame(_("Ratings"), child=vbox)
            self.pack_start(f, False, True, 0)

            vb = Gtk.VBox(spacing=6)

            # Filename choice algorithm config
            cb = CCB(_("Prefer _embedded art"),
                     'albumart', 'prefer_embedded', populate=True,
                     tooltip=_("Choose to use artwork embedded in the audio "
                               "(where available) over other sources"))
            vb.pack_start(cb, False, True, 0)

            hb = Gtk.HBox(spacing=3)
            cb = CCB(_("_Fixed image filename:"),
                     'albumart', 'force_filename', populate=True,
                     tooltip=_("The single image filename to use if "
                               "selected"))
            hb.pack_start(cb, False, True, 0)

            entry = UndoEntry()
            entry.set_tooltip_text(
                    _("The album art image file to use when forced"))
            entry.set_text(config.get("albumart", "filename"))
            entry.connect('changed', self.__changed_text, 'filename')
            # Disable entry when not forcing
            entry.set_sensitive(cb.get_active())
            cb.connect('toggled', self.__toggled_force_filename, entry)
            hb.pack_start(entry, True, True, 0)
            vb.pack_start(hb, False, True, 0)

            f = qltk.Frame(_("Album Art"), child=vb)
            self.pack_start(f, False, True, 0)

            for child in self.get_children():
                child.show_all()
Exemplo n.º 50
0
        def __init__(self):
            super(PreferencesWindow.Connection, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Connection")
            
            vbox = gtk.VBox(spacing=6)
            hb = gtk.HBox(spacing=6)
            e = UndoEntry()
            e.set_text(config.get("connection", "hostname"))
            e.connect('changed', self.__changed_tb, 'connection', 'hostname')
            e.set_tooltip_text(
                    _("The MPD Host to Connect to"))
            l = gtk.Label(_("Hostname:"))
            l.set_use_underline(True)
            l.set_mnemonic_widget(e)
            hb.pack_start(l, expand=False)
            hb.pack_start(e)
            vbox.pack_start(hb, expand=False)
            
            hb = gtk.HBox(spacing=6)
            e = UndoEntry()
            e.set_text(config.get("connection", "port"))
            e.connect('changed', self.__changed_tb, 'connection', 'port')
            e.set_tooltip_text(
                    _("Port of the MPD Host"))
            l = gtk.Label(_("Port:"))
            l.set_use_underline(True)
            l.set_mnemonic_widget(e)
            hb.pack_start(l, expand=False)
            hb.pack_start(e)
            vbox.pack_start(hb, expand=False)
            
            hb = gtk.HBox(spacing=6)
            e = UndoEntry()
            e.set_text(config.get("connection", "password"))
            e.connect('changed', self.__changed_tb, 'connection', 'password')
            e.set_tooltip_text(
                    _("Password for the MPD Host (if necessary)"))
            e.set_visibility(False)
            l = gtk.Label(_("Password:"******"MPD Server Connection"), child=vbox)
            self.pack_start(f, expand=False)

            # player backend
#            if player.backend and hasattr(player.device, 'PlayerPreferences'):
#                player_prefs = player.device.PlayerPreferences()
#                f = qltk.Frame(_("Output Configuration"), child=player_prefs)
#                self.pack_start(f, expand=False)

            # replaygain
            fallback_gain = config.getfloat("player", "fallback_gain", 0.0)
            adj = gtk.Adjustment(fallback_gain, -12.0, 12.0, 0.5, 0.5, 0.0)
            fb_spin = gtk.SpinButton(adj)
            fb_spin.set_digits(1)
            fb_spin.connect('changed', self.__changed,
                            'player', 'fallback_gain')
            fb_spin.set_tooltip_text(
                _("If no Replay Gain information is available "
                  "for a song, scale the volume by this value"))

            fb_label = gtk.Label(_("_Fall-back gain (dB):"))
            fb_label.set_use_underline(True)
            fb_label.set_mnemonic_widget(fb_spin)

            pre_amp_gain = config.getfloat("player", "pre_amp_gain", 0.0)
            adj = gtk.Adjustment(pre_amp_gain, -6, 6, 0.5, 0.5, 0.0)
            adj.connect('value-changed', self.__changed,
                        'player', 'pre_amp_gain')
            pre_spin = gtk.SpinButton(adj)
            pre_spin.set_digits(1)
            pre_spin.set_tooltip_text(
                _("Scale volume for all songs by this value, "
                  "as long as the result will not clip"))

            pre_label = gtk.Label(_("_Pre-amp gain (dB):"))
            pre_label.set_use_underline(True)
            pre_label.set_mnemonic_widget(pre_spin)

            widgets = [pre_label, pre_spin, fb_label, fb_spin]
            c = ConfigCheckButton(_("_Enable Replay Gain volume adjustment"),
                                    "player", "replaygain", populate=True)
            c.connect('toggled', self.__toggled_gain, widgets)

            # packing
            table = gtk.Table(3, 2)
            table.set_col_spacings(6)
            table.set_row_spacings(6)

            table.attach(c, 0, 2, 0, 1)
            fb_label.set_alignment(0, 0.5)
            table.attach(fb_label, 0, 1, 1, 2,
                         xoptions=0)
            pre_label.set_alignment(0, 0.5)
            table.attach(pre_label, 0, 1, 2, 3,
                         xoptions=0)

            fb_align = gtk.Alignment(0, 0.5, 0, 1)
            fb_align.add(fb_spin)
            table.attach(fb_align, 1, 2, 1, 2)

            pre_align = gtk.Alignment(0, 0.5, 0, 1)
            pre_align.add(pre_spin)
            table.attach(pre_align, 1, 2, 2, 3)

            f = qltk.Frame(_("Replay Gain Volume Adjustment"), child=table)

            c.emit('toggled')

            self.pack_start(f, expand=False)
            self.show_all()
Exemplo n.º 51
0
        def __init__(self):
            super(PreferencesWindow.Player, self).__init__(spacing=12)
            self.set_border_width(12)
            self.title = _("Playback")

            # player backend
            if app.player and hasattr(app.player, 'PlayerPreferences'):
                player_prefs = app.player.PlayerPreferences()
                f = qltk.Frame(_("Output Configuration"), child=player_prefs)
                self.pack_start(f, False, True, 0)

            # replaygain
            fallback_gain = config.getfloat("player", "fallback_gain", 0.0)
            adj = Gtk.Adjustment.new(fallback_gain, -12.0, 12.0, 0.5, 0.5, 0.0)
            fb_spin = Gtk.SpinButton(adjustment=adj)
            fb_spin.set_digits(1)
            fb_spin.connect('changed', self.__changed,
                            'player', 'fallback_gain')
            fb_spin.set_tooltip_text(
                _("If no Replay Gain information is available "
                  "for a song, scale the volume by this value"))

            fb_label = Gtk.Label(label=_("_Fall-back gain (dB):"))
            fb_label.set_use_underline(True)
            fb_label.set_mnemonic_widget(fb_spin)

            pre_amp_gain = config.getfloat("player", "pre_amp_gain", 0.0)
            adj = Gtk.Adjustment.new(pre_amp_gain, -6, 6, 0.5, 0.5, 0.0)
            adj.connect('value-changed', self.__changed,
                        'player', 'pre_amp_gain')
            pre_spin = Gtk.SpinButton(adjustment=adj)
            pre_spin.set_digits(1)
            pre_spin.set_tooltip_text(
                _("Scale volume for all songs by this value, "
                  "as long as the result will not clip"))

            pre_label = Gtk.Label(label=_("_Pre-amp gain (dB):"))
            pre_label.set_use_underline(True)
            pre_label.set_mnemonic_widget(pre_spin)

            widgets = [pre_label, pre_spin, fb_label, fb_spin]
            c = CCB(_("_Enable Replay Gain volume adjustment"),
                    "player", "replaygain", populate=True)
            c.connect('toggled', self.__toggled_gain, widgets)

            # packing
            table = Gtk.Table.new(3, 2, False)
            table.set_col_spacings(6)
            table.set_row_spacings(6)

            table.attach(c, 0, 2, 0, 1)
            fb_label.set_alignment(0, 0.5)
            table.attach(fb_label, 0, 1, 1, 2,
                         xoptions=0)
            pre_label.set_alignment(0, 0.5)
            table.attach(pre_label, 0, 1, 2, 3,
                         xoptions=0)

            fb_align = Gtk.Alignment.new(0, 0.5, 0, 1)
            fb_align.add(fb_spin)
            table.attach(fb_align, 1, 2, 1, 2)

            pre_align = Gtk.Alignment.new(0, 0.5, 0, 1)
            pre_align.add(pre_spin)
            table.attach(pre_align, 1, 2, 2, 3)

            f = qltk.Frame(_("Replay Gain Volume Adjustment"), child=table)

            c.emit('toggled')

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

            for child in self.get_children():
                child.show_all()
Exemplo n.º 52
0
    def PluginPreferences(self, parent):
        vbox = Gtk.VBox(spacing=6)

        queries = {}

        query_path = os.path.join(get_user_dir(), 'lists', 'queries.saved')
        with open(query_path, 'rU', encoding='utf-8') as query_file:
            for query_string in query_file:
                name = next(query_file).strip()
                queries[name] = Query(query_string.strip())

        for query_name, query in queries.items():
            check_button = ConfigCheckButton((query_name), "plugins",
                                             self._config_key(query_name))
            check_button.set_active(self.config_get_bool(query_name))
            vbox.pack_start(check_button, False, True, 0)

        chooserButton = Gtk.FileChooserButton(_('Select destination folder'))
        chooserButton.set_current_folder(self.lastfolder)
        chooserButton.set_action(Gtk.FileChooserAction.SELECT_FOLDER)

        # https://stackoverflow.com/a/14742779/109813
        def get_actual_filename(name):
            # Do nothing except on Windows
            if os.name != 'nt':
                return name

            dirs = name.split('\\')
            # disk letter
            test_name = [dirs[0].upper()]
            for d in dirs[1:]:
                test_name += ["%s[%s]" % (d[:-1], d[-1])]
            res = glob.glob('\\'.join(test_name))
            if not res:
                # File not found, return the input
                return name
            return res[0]

        def __file_error(file_path):
            qltk.ErrorMessage(
                None, _("Unable to export playlist"),
                _("Writing to <b>%s</b> failed.") %
                util.escape(file_path)).run()

        def __m3u_export(dir_path, query_name, songs):
            file_path = os.path.join(dir_path, query_name + '.m3u')
            try:
                fhandler = open(file_path, "wb")
            except IOError:
                __file_error(file_path)
            else:
                text = "#EXTM3U\n"

                for song in songs:
                    title = "%s - %s" % (song('~people').replace(
                        "\n", ", "), song('~title~version'))
                    path = song('~filename')
                    path = get_actual_filename(path)
                    try:
                        path = relpath(path, dir_path)
                    except ValueError:
                        # Keep absolute path
                        pass
                    text += "#EXTINF:%d,%s\n" % (song('~#length'), title)
                    text += path + "\n"

                fhandler.write(text.encode("utf-8"))
                fhandler.close()

        def __start(button):
            target_folder = chooserButton.get_filename()

            songs = app.library.get_content()
            for query_name, query in queries.items():
                if self.config_get_bool(query_name):
                    # Query is enabled
                    songs_for_query = query.filter(songs)
                    __m3u_export(target_folder, query_name, songs_for_query)

            message = qltk.Message(Gtk.MessageType.INFO, app.window, _("Done"),
                                   _("Export finished."))
            message.run()

        start_button = Gtk.Button(label=("Export"))
        start_button.connect('clicked', __start)

        vbox.pack_start(chooserButton, True, True, 0)
        vbox.pack_start(start_button, True, True, 0)
        label = Gtk.Label(
            label=
            "Quod Libet may become unresponsive. You will get a message when finished."
        )
        vbox.pack_start(label, True, True, 0)
        return qltk.Frame(("Select the saved searches to copy:"), child=vbox)
Exemplo n.º 53
0
 def _jack_toggled(widget: ConfigCheckButton) -> None:
     jack_connect.set_sensitive(widget.get_active())
Exemplo n.º 54
0
    def PluginPreferences(self, parent):
        # Check if the queries file exists
        if not os.path.exists(self.path_query):
            return self._no_queries_frame()

        # Read saved searches from file
        self.queries = {}
        with open(self.path_query, 'r', encoding='utf-8') as query_file:
            for query_string in query_file:
                name = next(query_file).strip()
                self.queries[name] = Query(query_string.strip())
        if not self.queries:
            # query_file is empty
            return self._no_queries_frame()

        main_vbox = Gtk.VBox(spacing=self.spacing_main)
        self.main_vbox = main_vbox

        # Saved search selection frame
        saved_search_vbox = Gtk.VBox(spacing=self.spacing_large)
        self.saved_search_vbox = saved_search_vbox
        for query_name, query in self.queries.items():
            query_config = self.CONFIG_QUERY_PREFIX + query_name
            check_button = ConfigCheckButton(query_name, PM.CONFIG_SECTION,
                                             self._config_key(query_config))
            check_button.set_active(self.config_get_bool(query_config))
            saved_search_vbox.pack_start(check_button, False, False, 0)
        saved_search_scroll = self._expandable_scroll(min_h=0, max_h=300)
        saved_search_scroll.add(saved_search_vbox)
        frame = qltk.Frame(
            label=_('Synchronize the following saved searches:'),
            child=saved_search_scroll)
        main_vbox.pack_start(frame, False, False, 0)

        # Destination path entry field
        destination_entry = Gtk.Entry(
            placeholder_text=_('The absolute path to your export location'),
            text=config.get(PM.CONFIG_SECTION, self.CONFIG_PATH_KEY, ''))
        destination_entry.connect('changed', self._destination_path_changed)
        self.destination_entry = destination_entry

        # Destination path selection button
        destination_button = qltk.Button(label='', icon_name=Icons.FOLDER_OPEN)
        destination_button.connect('clicked', self._select_destination_path)

        # Destination path hbox
        destination_path_hbox = Gtk.HBox(spacing=self.spacing_small)
        destination_path_hbox.pack_start(destination_entry, True, True, 0)
        destination_path_hbox.pack_start(destination_button, False, False, 0)

        # Destination path information
        destination_warn_label = self._label_with_icon(
            _("All pre-existing files in the destination folder that aren't in "
              "the saved searches will be deleted."), Icons.DIALOG_WARNING)
        destination_info_label = self._label_with_icon(
            _('For devices mounted with MTP, export to a local destination '
              'folder, then transfer it to your device with rsync. '
              'Or, when syncing many files to an Android Device, use adb-sync, '
              'which is much faster.'), Icons.DIALOG_INFORMATION)

        # Destination path frame
        destination_vbox = Gtk.VBox(spacing=self.spacing_large)
        destination_vbox.pack_start(destination_path_hbox, False, False, 0)
        destination_vbox.pack_start(destination_warn_label, False, False, 0)
        destination_vbox.pack_start(destination_info_label, False, False, 0)
        frame = qltk.Frame(label=_('Destination path:'),
                           child=destination_vbox)
        main_vbox.pack_start(frame, False, False, 0)

        # Export pattern frame
        export_pattern_combo = ComboBoxEntrySave(
            self.path_pattern, [self.default_export_pattern],
            title=_('Path Patterns'),
            edit_title=_(u'Edit saved patterns…'))
        export_pattern_combo.enable_clear_button()
        export_pattern_combo.show_all()
        export_pattern_entry = export_pattern_combo.get_child()
        export_pattern_entry.set_placeholder_text(
            _('The structure of the exported filenames, based on their tags'))
        export_pattern_entry.set_text(
            config.get(PM.CONFIG_SECTION, self.CONFIG_PATTERN_KEY,
                       self.default_export_pattern))
        export_pattern_entry.connect('changed', self._export_pattern_changed)
        self.export_pattern_entry = export_pattern_entry
        frame = qltk.Frame(label=_('Export pattern:'),
                           child=export_pattern_combo)
        main_vbox.pack_start(frame, False, False, 0)

        # Start preview button
        preview_start_button = qltk.Button(label=_('Preview'),
                                           icon_name=Icons.VIEW_REFRESH)
        preview_start_button.set_visible(True)
        preview_start_button.connect('clicked', self._start_preview)
        self.preview_start_button = preview_start_button

        # Stop preview button
        preview_stop_button = qltk.Button(label=_('Stop preview'),
                                          icon_name=Icons.PROCESS_STOP)
        preview_stop_button.set_visible(False)
        preview_stop_button.set_no_show_all(True)
        preview_stop_button.connect('clicked', self._stop_preview)
        self.preview_stop_button = preview_stop_button

        # Details view
        column_types = [column[1] for column in self.model_cols.values()]
        self.model = Gtk.ListStore(*column_types)
        self.details_tree = details_tree = HintedTreeView(model=self.model)
        details_scroll = self._expandable_scroll()
        details_scroll.set_shadow_type(Gtk.ShadowType.IN)
        details_scroll.add(details_tree)
        self.renders = {}

        # Preview column: status
        render = Gtk.CellRendererText()
        column = self._tree_view_column(render,
                                        self._cdf_status,
                                        title=_('Status'),
                                        expand=False,
                                        sort=self._model_col_id('tag'))
        details_tree.append_column(column)

        # Preview column: file
        render = Gtk.CellRendererText()
        column = self._tree_view_column(render,
                                        self._cdf_source_path,
                                        title=_('Source File'),
                                        sort=self._model_col_id('filename'))
        details_tree.append_column(column)

        # Preview column: export path
        render = Gtk.CellRendererText()
        render.set_property('editable', True)
        render.connect('edited', self._row_edited)
        column = self._tree_view_column(render,
                                        self._cdf_export_path,
                                        title=_('Export Path'),
                                        sort=self._model_col_id('export'))
        details_tree.append_column(column)

        # Status labels
        self.status_operation = Gtk.Label(xalign=0.0,
                                          yalign=0.5,
                                          wrap=True,
                                          visible=False,
                                          no_show_all=True)
        self.status_progress = Gtk.Label(xalign=0.0,
                                         yalign=0.5,
                                         wrap=True,
                                         visible=False,
                                         no_show_all=True)
        self.status_duplicates = self._label_with_icon(_(
            'Duplicate export paths detected! The export paths above can be '
            'edited before starting the synchronization.'),
                                                       Icons.DIALOG_WARNING,
                                                       visible=False)
        self.status_deletions = self._label_with_icon(
            _('Existing files in the destination path will be deleted!'),
            Icons.DIALOG_WARNING,
            visible=False)

        # Section for previewing exported files
        preview_vbox = Gtk.VBox(spacing=self.spacing_large)
        preview_vbox.pack_start(preview_start_button, False, False, 0)
        preview_vbox.pack_start(preview_stop_button, False, False, 0)
        preview_vbox.pack_start(details_scroll, True, True, 0)
        preview_vbox.pack_start(self.status_operation, False, False, 0)
        preview_vbox.pack_start(self.status_progress, False, False, 0)
        preview_vbox.pack_start(self.status_duplicates, False, False, 0)
        preview_vbox.pack_start(self.status_deletions, False, False, 0)
        main_vbox.pack_start(preview_vbox, True, True, 0)

        # Start sync button
        sync_start_button = qltk.Button(label=_('Start synchronization'),
                                        icon_name=Icons.DOCUMENT_SAVE)
        sync_start_button.set_sensitive(False)
        sync_start_button.set_visible(True)
        sync_start_button.connect('clicked', self._start_sync)
        self.sync_start_button = sync_start_button

        # Stop sync button
        sync_stop_button = qltk.Button(label=_('Stop synchronization'),
                                       icon_name=Icons.PROCESS_STOP)
        sync_stop_button.set_visible(False)
        sync_stop_button.set_no_show_all(True)
        sync_stop_button.connect('clicked', self._stop_sync)
        self.sync_stop_button = sync_stop_button

        # Section for the sync buttons
        sync_vbox = Gtk.VBox(spacing=self.spacing_large)
        sync_vbox.pack_start(sync_start_button, False, False, 0)
        sync_vbox.pack_start(sync_stop_button, False, False, 0)
        main_vbox.pack_start(sync_vbox, False, False, 0)

        return main_vbox
Exemplo n.º 55
0
 def ConfigCheckButton(self, label, option, **kwargs):
     return ConfigCheckButton(label, PM.CONFIG_SECTION,
                              self._option(option), **kwargs)
Exemplo n.º 56
0
    def __init__(self, menu, library, player):
        super(QueueExpander, self).__init__()
        sw = ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.queue = PlayQueue(library, player)
        sw.add(self.queue)

        outer = Gtk.HBox(spacing=12)

        left = Gtk.HBox(spacing=12)

        hb2 = Gtk.HBox(spacing=3)
        state_icon = PlaybackStatusIcon()
        state_icon.stop()
        state_icon.show()
        hb2.pack_start(state_icon, True, True, 0)
        name_label = Gtk.Label(label=_("_Queue"), use_underline=True)
        hb2.pack_start(name_label, True, True, 0)
        left.pack_start(hb2, False, True, 0)

        b = SmallImageButton(
            image=Gtk.Image.new_from_stock(Gtk.STOCK_CLEAR, Gtk.IconSize.MENU))
        b.set_tooltip_text(_("Remove all songs from the queue"))
        b.connect('clicked', self.__clear_queue)
        b.hide()
        b.set_relief(Gtk.ReliefStyle.NONE)
        left.pack_start(b, False, False, 0)

        count_label = Gtk.Label()
        left.pack_start(count_label, False, True, 0)

        outer.pack_start(left, True, True, 0)

        close_button = SmallImageButton(image=SymbolicIconImage(
            "window-close", Gtk.IconSize.MENU),
                                        relief=Gtk.ReliefStyle.NONE)

        close_button.connect("clicked", lambda *x: self.hide())

        outer.pack_start(close_button, False, False, 6)
        self.set_label_fill(True)

        cb = ConfigCheckButton(_("_Random"), "memory", "shufflequeue")
        cb.connect('toggled', self.__queue_shuffle, self.queue.model)
        cb.set_active(config.getboolean("memory", "shufflequeue"))
        left.pack_start(cb, False, True, 0)

        self.set_label_widget(outer)
        self.add(sw)
        self.connect_object('notify::expanded', self.__expand, cb, b)

        targets = [("text/x-quodlibet-songs", Gtk.TargetFlags.SAME_APP,
                    DND_QL), ("text/uri-list", 0, DND_URI_LIST)]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]

        self.drag_dest_set(Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY)
        self.connect('drag-motion', self.__motion)
        self.connect('drag-data-received', self.__drag_data_received)

        self.show_all()

        self.queue.model.connect_after(
            'row-inserted', util.DeferredSignal(self.__check_expand),
            count_label)
        self.queue.model.connect_after(
            'row-deleted', util.DeferredSignal(self.__update_count),
            count_label)
        cb.hide()

        self.connect_object('notify::visible', self.__visible, cb, menu, b)
        self.__update_count(self.model, None, count_label)

        player.connect('song-started', self.__update_state_icon, state_icon)
        player.connect('paused', self.__update_state_icon_pause, state_icon,
                       True)
        player.connect('unpaused', self.__update_state_icon_pause, state_icon,
                       False)

        # to make the children clickable if mapped
        # ....no idea why, but works
        def hack(expander):
            label = expander.get_label_widget()
            if label:
                label.unmap()
                label.map()

        self.connect("map", hack)
Exemplo n.º 57
0
    def __init__(self, parent, library):
        super(EditTags, self).__init__(spacing=12)
        self.title = _("Edit Tags")
        self.set_border_width(12)

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

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

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

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

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

        column.set_cell_data_func(render, cell_data_tag)

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

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

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

        column.set_cell_data_func(render, cell_data_value)

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

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

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

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

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

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

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

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

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

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

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

        self._parent = parent

        for child in self.get_children():
            child.show_all()
Exemplo n.º 58
0
    def PluginPreferences(cls, parent):
        vb = Gtk.VBox(spacing=12)

        # Tabulate all settings for neatness
        table = Gtk.Table(n_rows=1, n_columns=2)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        rows = []

        def process_option_changed(combo):
            #xcode = combo.get_child().get_text()
            model = combo.get_model()
            lbl, value = model[combo.get_active()]
            cls.config_set("process_if", value)

        def create_model():
            model = Gtk.ListStore(str, str)
            model.append(["<b>%s</b>" % _("always"), UpdateMode.ALWAYS])
            model.append([_("if <b>any</b> RG tags are missing"),
                          UpdateMode.ANY_MISSING])
            model.append([_("if <b>album</b> RG tags are missing"),
                          UpdateMode.ALBUM_MISSING])
            return model

        def set_active(value):
            for i, item in enumerate(model):
                if value == item[1]:
                    combo.set_active(i)

        model = create_model()
        combo = Gtk.ComboBox(model=model)
        set_active(cls.config_get("process_if", PrefDefaults.update_mode))
        renderer = Gtk.CellRendererText()
        combo.connect('changed', process_option_changed)
        combo.pack_start(renderer, True)
        combo.add_attribute(renderer, "markup", 0)

        rows.append((_("_Process albums:"), combo))

        for (row, (label_text, entry)) in enumerate(rows):
            label = Gtk.Label(label=label_text)
            label.set_alignment(0.0, 0.5)
            label.set_use_underline(True)
            label.set_mnemonic_widget(entry)
            table.attach(label, 0, 1, row, row + 1,
                         xoptions=Gtk.AttachOptions.FILL)
            table.attach(entry, 1, 2, row, row + 1)

        # Processing Options
        frame = Frame(_("Processing Options"), table)
        vb.pack_start(frame, True, True, 0)

        # Options
        toggles = [
            ('write_rl', _("Store _reference loudness"),
                PrefDefaults.write_rl),
            ('delete_unused', _("_Delete tags that this scanner doesn't use"),
                PrefDefaults.delete_unused),
            ('never_overwrite', _("_Never overwrite existing tags"),
                PrefDefaults.never_overwrite),
        ]
        vb2 = Gtk.VBox(spacing=6)
        for key, label, dv in toggles:
            ccb = ConfigCheckButton(label, 'plugins', cls._config_key(key))
            ccb.set_active(cls.config_get_bool(key, dv))
            vb2.pack_start(ccb, True, True, 0)

        frame2 = Frame(_("Misc Options"), vb2)
        vb.pack_start(frame2, False, True, 0)

        return vb