Example #1
0
 def test_toggle(self):
     config.set("memory", "bar", "on")
     c = ConfigCheckMenuItem("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())
Example #2
0
    def previous(self):
        """Go to the previous song"""

        keep_songs = config.getboolean("memory", "queue_keep_songs", False)
        q_ignore = config.getboolean("memory", "queue_ignore", False)

        if q_ignore or self.pl.sourced or not keep_songs:
            self.pl.previous()
        else:
            self.q.previous()
        self._check_sourced()
Example #3
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)
Example #4
0
    def next_ended(self):
        """Switch to the next song (action comes from the user)"""

        keep_songs = config.getboolean("memory", "queue_keep_songs", False)
        q_ignore = config.getboolean("memory", "queue_ignore", False)

        if (self.q.is_empty()
                or (q_ignore and not (keep_songs and self.q.sourced))):
            self.pl.next_ended()
        else:
            self.q.next_ended()
        self._check_sourced()
Example #5
0
 def __search_func(self, model, column, key, iter_, data):
     album = model.get_album(iter_)
     if album is None:
         return config.getboolean("browsers", "covergrid_all", False)
     key = key.decode('utf-8').lower()
     title = album.title.lower()
     if key in title:
         return False
     if config.getboolean("browsers", "album_substrings"):
         people = (p.lower() for p in album.list("~people"))
         for person in people:
             if key in person:
                 return False
     return True
Example #6
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()
Example #7
0
    def __button_press(self, view, event, librarian):
        if event.button != Gdk.BUTTON_PRIMARY:
            return
        x, y = map(int, [event.x, event.y])
        try:
            path, col, cellx, celly = view.get_path_at_pos(x, y)
        except TypeError:
            return True
        if event.window != self.get_bin_window():
            return False
        if col.header_name == "~rating":
            if not config.getboolean("browsers", "rating_click"):
                return

            song = view.get_model()[path][0]
            l = Gtk.Label()
            l.show()
            l.set_text(config.RATINGS.full_symbol)
            width = l.get_preferred_size()[1].width
            l.destroy()
            if not width:
                return False
            precision = config.RATINGS.precision
            count = int(float(cellx - 5) / width) + 1
            rating = max(0.0, min(1.0, count * precision))
            if rating <= precision and song("~#rating") == precision:
                rating = 0.0
            self.__set_rating(rating, [song], librarian)
Example #8
0
    def __about_to_finish_sync(self):
        """Returns a tuple (ok, next_song). ok is True if the next song
        should be set.
        """

        print_d("About to finish (sync)")

        # Chained oggs falsely trigger a gapless transition.
        # At least for radio streams we can safely ignore it because
        # transitions don't occur there.
        # https://github.com/quodlibet/quodlibet/issues/1454
        # https://bugzilla.gnome.org/show_bug.cgi?id=695474
        if self.song.multisong:
            print_d("multisong: ignore about to finish")
            return (False, None)

        if config.getboolean("player", "gst_disable_gapless"):
            print_d("Gapless disabled")
            return (False, None)

        # this can trigger twice, see issue 987
        if self._in_gapless_transition:
            return (False, None)
        self._in_gapless_transition = True

        print_d("Select next song in mainloop..")
        self._source.next_ended()
        print_d("..done.")

        return (True, self._source.current)
Example #9
0
    def refresh_panes(self):
        self.multi_paned.destroy()

        # Fill in the pane list. The last pane reports back to us.
        self._panes = [self]
        for header in reversed(get_headers()):
            pane = Pane(self._library, header, self._panes[0])
            pane.connect('row-activated',
                         lambda *x: self.songs_activated())
            self._panes.insert(0, pane)
        self._panes.pop()  # remove self

        # Put the panes in scrollable windows
        sws = []
        for pane in self._panes:
            sw = ScrolledWindow()
            sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
            sw.set_shadow_type(Gtk.ShadowType.IN)
            sw.add(pane)
            sws.append(sw)

        self.multi_paned.set_widgets(sws)
        self.multi_paned.show_all()
        self.main_box.pack1(self.multi_paned.get_paned(), True, False)

        self.__star = {}
        for p in self._panes:
            tags = [t for t in p.tags if not t.startswith("~#")]
            self.__star.update(dict.fromkeys(tags))

        self.set_wide_mode(config.getboolean("browsers", "pane_wide_mode"))
Example #10
0
def iter_backends():
    if config.getboolean("settings", "disable_mmkeys"):
        return

    try:
        from .gnome import GnomeBackend, GnomeBackendOldName, MateBackend
    except MMKeysImportError:
        pass
    else:
        yield GnomeBackend
        yield GnomeBackendOldName
        yield MateBackend

    try:
        from .keybinder import KeybinderBackend
    except MMKeysImportError:
        pass
    else:
        yield KeybinderBackend

    try:
        from .winhook import WinHookBackend
    except MMKeysImportError:
        pass
    else:
        yield WinHookBackend

    try:
        from .osx import OSXBackend
    except MMKeysImportError:
        pass
    else:
        yield OSXBackend
Example #11
0
    def plugin_songs(self, songs):
        value = -1
        while not 0 <= value <= 1:
            input_string = GetStringDialog(
                self.plugin_window, self.PLUGIN_NAME,
                _("Please give your desired rating on a scale "
                  "from 0.0 to 1.0"), _("_Apply"), Icons.NONE).run()

            if input_string is None:
                return

            try:
                value = float(input_string)
            except ValueError:
                continue

        count = len(songs)
        if (count > 1
                and config.getboolean("browsers", "rating_confirm_multiple")):
            confirm_dialog = ConfirmRateMultipleDialog(self.plugin_window,
                                                       _("Change _Rating"),
                                                       count, value)
            if confirm_dialog.run() != Gtk.ResponseType.YES:
                return

        for song in songs:
            song["~#rating"] = value
Example #12
0
    def __about_to_finish_sync(self):
        """Returns the next song uri to play or None"""

        print_d("About to finish (sync)")

        # Chained oggs falsely trigger a gapless transition.
        # At least for radio streams we can safely ignore it because
        # transitions don't occur there.
        # https://github.com/quodlibet/quodlibet/issues/1454
        # https://bugzilla.gnome.org/show_bug.cgi?id=695474
        if self.song.multisong:
            print_d("multisong: ignore about to finish")
            return

        # mod + gapless deadlocks
        # https://github.com/quodlibet/quodlibet/issues/2780
        if isinstance(self.song, ModFile):
            return

        if config.getboolean("player", "gst_disable_gapless"):
            print_d("Gapless disabled")
            return

        # this can trigger twice, see issue 987
        if self._in_gapless_transition:
            return
        self._in_gapless_transition = True

        print_d("Select next song in mainloop..")
        self._source.next_ended()
        print_d("..done.")

        song = self._source.current
        if song is not None:
            return song("~uri")
Example #13
0
    def refresh_panes(self):
        hbox = self.main_box.get_child1()
        if hbox:
            hbox.destroy()

        hbox = Gtk.HBox(spacing=6)
        hbox.set_homogeneous(True)

        # Fill in the pane list. The last pane reports back to us.
        self._panes = [self]
        for header in reversed(get_headers()):
            pane = Pane(self._library, header, self._panes[0])
            self._panes.insert(0, pane)
        self._panes.pop()  # remove self

        for pane in self._panes:
            pane.connect('row-activated', lambda *x: self.songs_activated())
            sw = ScrolledWindow()
            sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
            sw.set_shadow_type(Gtk.ShadowType.IN)
            sw.add(pane)
            hbox.pack_start(sw, True, True, 0)

        self.main_box.pack1(hbox, True, False)
        hbox.show_all()

        self.__star = {}
        for p in self._panes:
            tags = [t for t in p.tags if not t.startswith("~#")]
            self.__star.update(dict.fromkeys(tags))

        self.set_wide_mode(config.getboolean("browsers", "pane_wide_mode"))
Example #14
0
    def refresh_panes(self):
        hbox = self.main_box.get_child1()
        if hbox:
            hbox.destroy()

        hbox = Gtk.HBox(spacing=6)
        hbox.set_homogeneous(True)

        # Fill in the pane list. The last pane reports back to us.
        self._panes = [self]
        for header in reversed(get_headers()):
            pane = Pane(self._library, header, self._panes[0])
            self._panes.insert(0, pane)
        self._panes.pop()  # remove self

        for pane in self._panes:
            pane.connect('row-activated',
                         lambda *x: self.songs_activated())
            sw = ScrolledWindow()
            sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
            sw.set_shadow_type(Gtk.ShadowType.IN)
            sw.add(pane)
            hbox.pack_start(sw, True, True, 0)

        self.main_box.pack1(hbox, True, False)
        hbox.show_all()

        self.__star = {}
        for p in self._panes:
            tags = [t for t in p.tags if not t.startswith("~#")]
            self.__star.update(dict.fromkeys(tags))

        self.set_wide_mode(config.getboolean("browsers", "pane_wide_mode"))
Example #15
0
    def __init__(self):
        try:
            self.accounts = config.get('plugins', self.c_accounts).split()
        except:
            self.accounts = []
            config.set('plugins', self.c_accounts, '')

        try:
            self.paused = config.getboolean('plugins', self.c_paused)
        except:
            self.paused = True
            config.set('plugins', self.c_paused, 'True')

        try:
            self.statuses = config.get('plugins', self.c_statuses).split()
        except:
            self.statuses = ['online', 'chat']
            config.set('plugins', self.c_statuses, join(self.statuses))

        try:
            self.pattern = config.get('plugins', self.c_pattern)
        except:
            self.pattern = '<artist> - <title>'
            config.set('plugins', self.c_pattern, self.pattern)

        quodlibet.quit_add(0, self.quit)

        self.interface = None
        self.current = ''
Example #16
0
    def do_draw(self, cairo_context):
        pixbuf = self._get_pixbuf()
        if not pixbuf:
            return

        alloc = self.get_allocation()
        width, height = alloc.width, alloc.height

        scale_factor = get_scale_factor(self)

        width *= scale_factor
        height *= scale_factor

        if self._path:
            if width < 2 or height < 2:
                return
            round_thumbs = config.getboolean("albumart", "round")
            pixbuf = scale(
                pixbuf, (width - 2 * scale_factor, height - 2 * scale_factor))
            pixbuf = add_border_widget(pixbuf, self, None, round_thumbs)
        else:
            pixbuf = scale(pixbuf, (width, height))

        style_context = self.get_style_context()

        pbosf = get_pbosf_for_pixbuf(self, pixbuf)
        pbosf_render(style_context, cairo_context, pbosf, 0, 0)
Example #17
0
def iter_backends():
    try:
        from .gnome import GnomeBackend, MateBackend
    except MMKeysImportError:
        pass
    else:
        yield GnomeBackend
        yield MateBackend

    try:
        from .keybinder import KeybinderBackend
    except MMKeysImportError:
        pass
    else:
        yield KeybinderBackend

    try:
        from .pyhook import PyHookBackend
    except MMKeysImportError:
        pass
    else:
        yield PyHookBackend

    if config.getboolean("settings", "osx_mmkeys"):
        try:
            from .osx import OSXBackend
        except MMKeysImportError:
            pass
        else:
            yield OSXBackend
Example #18
0
    def __about_to_finish_sync(self):
        """Returns a tuple (ok, next_song). ok is True if the next song
        should be set.
        """

        print_d("About to finish (sync)")

        # Chained oggs falsely trigger a gapless transition.
        # At least for radio streams we can safely ignore it because
        # transitions don't occur there.
        # https://github.com/quodlibet/quodlibet/issues/1454
        # https://bugzilla.gnome.org/show_bug.cgi?id=695474
        if self.song.multisong:
            print_d("multisong: ignore about to finish")
            return (False, None)

        if config.getboolean("player", "gst_disable_gapless"):
            print_d("Gapless disabled")
            return (False, None)

        # this can trigger twice, see issue 987
        if self._in_gapless_transition:
            return (False, None)
        self._in_gapless_transition = True

        print_d("Select next song in mainloop..")
        self._source.next_ended()
        print_d("..done.")

        return (True, self._source.current)
Example #19
0
    def __init__(self, library):
        super(SearchBar, self).__init__()
        self.set_spacing(6)
        self.set_orientation(Gtk.Orientation.VERTICAL)

        self._query = None
        self._library = library

        completion = LibraryTagCompletion(library.librarian)
        self.accelerators = Gtk.AccelGroup()

        show_limit = config.getboolean("browsers", "search_limit")
        sbb = LimitSearchBarBox(completion=completion,
                                accel_group=self.accelerators,
                                show_limit=show_limit)

        sbb.connect('query-changed', self.__text_parse)
        sbb.connect('focus-out', self.__focus)
        self._sb_box = sbb

        prefs = PreferencesButton(sbb)
        sbb.pack_start(prefs, False, True, 0)

        align = Align(sbb, left=6, right=6, top=6)
        self.pack_start(align, False, True, 0)
        self.connect('destroy', self.__destroy)
        self.show_all()
Example #20
0
    def __key_press(self, songlist, event, librarian):
        rating_accels = [
            "<Primary>%d" % i for i in range(
                min(10, config.RATINGS.number + 1))]

        if (qltk.is_accel(event, *rating_accels) and
                config.getboolean("browsers", "rating_hotkeys")):
            rating = int(chr(event.keyval)) * config.RATINGS.precision
            self.__set_rating(rating, self.get_selected_songs(), librarian)
            return True
        elif qltk.is_accel(event, "<Primary>Return", "<Primary>KP_Enter"):
            self.__enqueue(self.get_selected_songs())
            return True
        elif qltk.is_accel(event, "<Primary>F"):
            self.emit('start-interactive-search')
            return True
        elif qltk.is_accel(event, "<Primary>Delete"):
            songs = self.get_selected_songs()
            if songs:
                trash_songs(self, songs, librarian)
            return True
        elif qltk.is_accel(event, "<alt>Return"):
            songs = self.get_selected_songs()
            if songs:
                window = SongProperties(librarian, songs, parent=self)
                window.show()
            return True
        elif qltk.is_accel(event, "<Primary>I"):
            songs = self.get_selected_songs()
            if songs:
                window = Information(librarian, songs, self)
                window.show()
            return True
        return False
Example #21
0
    def next(self):
        """Switch to the next song"""

        keep_songs = config.getboolean("memory", "queue_keep_songs", False)
        q_disable = config.getboolean("memory", "queue_disable", False)

        if (self.q.is_empty() or q_disable
                or (keep_songs and not self.q.sourced)):
            self.pl.next()
            if q_disable and self.q.sourced:
                # The go_to is to make sure the playlist begins playing
                # when the queue is disabled while being sourced
                self.go_to(self.pl.current)
        else:
            self.q.next()
        self._check_sourced()
Example #22
0
 def __clear_queue(self, activator):
     self.model.clear()
     stop_queue = config.getboolean("memory",
                                    "queue_stop_once_empty",
                                    False)
     if stop_queue:
         app.player_options.stop_after = True
Example #23
0
    def __update_image(self):
        height = self.__size
        if not height: return

        if self.__resize:
            height = min(self.__max_size, height)
            width = self.__max_size
        else:
            width = height

        if self.__path is None:
            pixbuf = self.__get_no_cover(width, height)
        else:
            try:
                round_thumbs = config.getboolean("albumart", "round")
                pixbuf = thumbnails.get_thumbnail(self.__path, (width, height))
                pixbuf = thumbnails.add_border(pixbuf, 80, round_thumbs)
            except gobject.GError:
                pixbuf = self.__get_no_cover(width, height)

        self.set_from_pixbuf(pixbuf)
        if self.__resize:
            self.__ignore = True
            self.__sig = self.connect_after("size-allocate",
                self.__stop_ignore)
Example #24
0
    def __button_press(self, view, event, librarian):
        if event.button != Gdk.BUTTON_PRIMARY:
            return
        x, y = map(int, [event.x, event.y])
        try:
            path, col, cellx, celly = view.get_path_at_pos(x, y)
        except TypeError:
            return True
        if event.window != self.get_bin_window():
            return False
        if col.header_name == "~rating":
            if not config.getboolean("browsers", "rating_click"):
                return

            song = view.get_model()[path][0]
            l = Gtk.Label()
            l.show()
            l.set_text(config.RATINGS.full_symbol)
            width = l.get_preferred_size()[1].width
            l.destroy()
            if not width:
                return False
            precision = config.RATINGS.precision
            count = int(float(cellx - 5) / width) + 1
            rating = max(0.0, min(1.0, count * precision))
            if (rating <= precision and
                    song("~#rating") == precision):
                rating = 0.0
            self.__set_rating(rating, [song], librarian)
Example #25
0
def iter_backends():
    if config.getboolean("settings", "disable_mmkeys"):
        return

    try:
        from .gnome import GnomeBackend, MateBackend
    except MMKeysImportError:
        pass
    else:
        yield GnomeBackend
        yield MateBackend

    try:
        from .keybinder import KeybinderBackend
    except MMKeysImportError:
        pass
    else:
        yield KeybinderBackend

    try:
        from .winhook import WinHookBackend
    except MMKeysImportError:
        pass
    else:
        yield WinHookBackend

    try:
        from .osx import OSXBackend
    except MMKeysImportError:
        pass
    else:
        yield OSXBackend
Example #26
0
    def __about_to_finish_sync(self):
        """Returns the next song uri to play or None"""

        print_d("About to finish (sync)")

        # Chained oggs falsely trigger a gapless transition.
        # At least for radio streams we can safely ignore it because
        # transitions don't occur there.
        # https://github.com/quodlibet/quodlibet/issues/1454
        # https://bugzilla.gnome.org/show_bug.cgi?id=695474
        if self.song.multisong:
            print_d("multisong: ignore about to finish")
            return

        # mod + gapless deadlocks
        # https://github.com/quodlibet/quodlibet/issues/2780
        if isinstance(self.song, ModFile):
            return

        if config.getboolean("player", "gst_disable_gapless"):
            print_d("Gapless disabled")
            return

        # this can trigger twice, see issue 987
        if self._in_gapless_transition:
            return
        self._in_gapless_transition = True

        print_d("Select next song in mainloop..")
        self._source.next_ended()
        print_d("..done.")

        song = self._source.current
        if song is not None:
            return song("~uri")
Example #27
0
    def bind_config(self, section, option):
        self.set_active(config.getboolean(section, option))

        def toggled_cb(*args):
            config.set(section, option, self.get_active())

        self.connect('toggled', toggled_cb)
Example #28
0
    def plugin_songs(self, songs):
        value = -1
        while not 0 <= value <= 1:
            input_string = GetStringDialog(
                self.plugin_window,
                self.PLUGIN_NAME,
                _("Please give your desired rating on a scale "
                  "from 0.0 to 1.0"),
                _("_Apply"),
                Icons.NONE
            ).run()

            if input_string is None:
                return

            try:
                value = float(input_string)
            except ValueError:
                continue

        count = len(songs)
        if (count > 1 and config.getboolean("browsers",
                "rating_confirm_multiple")):
            confirm_dialog = ConfirmRateMultipleDialog(
                self.plugin_window, count, value)
            if confirm_dialog.run() != Gtk.ResponseType.YES:
                return

        for song in songs:
            song["~#rating"] = value
Example #29
0
 def __init__(self):
     super(FilterCheckButton, self).__init__(self._label, self._section, self._key)
     try:
         self.set_active(config.getboolean(self._section, self._key))
     except:
         pass
     connect_obj(self, "toggled", self.emit, "preview")
Example #30
0
    def __init__(self, parent, library):
        super(TagsFromPath, self).__init__(spacing=6)

        self.set_border_width(12)
        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = TBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(TBP, 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)

        vbox = Gtk.VBox()
        addreplace = Gtk.ComboBoxText()
        addreplace.append_text(_("Tags replace existing ones"))
        addreplace.append_text(_("Tags are added to existing ones"))
        addreplace.set_active(config.getboolean("tagsfrompath", "add"))
        addreplace.connect('changed', self.__add_changed)
        vbox.pack_start(addreplace, True, True, 0)
        addreplace.show()
        self.pack_start(vbox, False, True, 0)

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

        # Save button
        self.save = qltk.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)

        connect_obj(self.preview, 'clicked', self.__preview, None)
        connect_obj(parent, 'changed', self.__class__.__preview, self)

        # Save changes
        connect_obj(self.save, 'clicked', self.__save, addreplace, library)

        for child in self.get_children():
            child.show()
Example #31
0
    def __init__(self, parent, library):
        super(TagsFromPath, self).__init__(spacing=6)

        self.set_border_width(12)
        hbox = Gtk.HBox(spacing=6)
        cbes_defaults = TBP_EXAMPLES.split("\n")
        self.combo = ComboBoxEntrySave(TBP, 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)

        vbox = Gtk.VBox()
        addreplace = Gtk.ComboBoxText()
        addreplace.append_text(_("Tags replace existing ones"))
        addreplace.append_text(_("Tags are added to existing ones"))
        addreplace.set_active(config.getboolean("tagsfrompath", "add"))
        addreplace.connect('changed', self.__add_changed)
        vbox.pack_start(addreplace, True, True, 0)
        addreplace.show()
        self.pack_start(vbox, False, True, 0)

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

        # Save button
        self.save = qltk.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)

        connect_obj(self.preview, 'clicked', self.__preview, None)
        connect_obj(parent, 'changed', self.__class__.__preview, self)

        # Save changes
        connect_obj(self.save, 'clicked', self.__save, addreplace, library)

        for child in self.get_children():
            child.show()
Example #32
0
 def __init__(self, label, section, option, populate=False, tooltip=None):
     super(ConfigCheckButton, self).__init__(label=label,
                                             use_underline=True)
     if populate:
         self.set_active(config.getboolean(section, option))
     if tooltip:
         self.set_tooltip_text(tooltip)
     self.connect('toggled', ConfigCheckButton.__toggled, section, option)
Example #33
0
 def __init__(self):
     super(FilterCheckButton, self).__init__(self._label, self._section,
                                             self._key)
     try:
         self.set_active(config.getboolean(self._section, self._key))
     except:
         pass
     connect_obj(self, 'toggled', self.emit, 'preview')
Example #34
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()
Example #35
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()
    def __window_map(self, win, *args):
        visible = config.getboolean("plugins", "icon_window_visible", False)

        config.set("plugins", "icon_window_visible", "true")

        # Only restore window state on start
        if not visible and self.__first_map:
            self.__hide_window()
    def __init__(self, activator):
        super(Preferences, self).__init__(spacing=12)

        self.set_border_width(6)

        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(2, 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(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()
Example #38
0
 def PluginPreferences(self):
     box = Gtk.HBox()
     ccb = ConfigCheckButton(
         _("Automatically start playing "
           "double-clicked songs"), 'plugins', 'queue_only_autoplay')
     autoplay = config.getboolean('plugins', 'queue_only_autoplay', False)
     ccb.set_active(autoplay)
     box.pack_start(qltk.Frame(_("Preferences"), child=ccb), True, True, 0)
     return box
Example #39
0
 def __set_rating(self, value, songs, librarian):
     count = len(songs)
     if count > 1 and config.getboolean("browsers", "rating_confirm_multiple"):
         dialog = ConfirmRateMultipleDialog(self, count, value)
         if dialog.run() != Gtk.ResponseType.YES:
             return
     for song in songs:
         song["~#rating"] = value
     librarian.changed(songs)
Example #40
0
def use_trash():
    """If the current platform supports moving files into a trash can."""

    # TODO: Use the glib API for trashing which supports trashing there
    if is_flatpak():
        return False

    return (os.name == "posix" and sys.platform != "darwin"
            and not config.getboolean("settings", "bypass_trash"))
Example #41
0
 def __init__(self, label, section, option, populate=False, tooltip=None,
              default=True):
     super(ConfigCheckButton, self).__init__(label=label,
                                             use_underline=True)
     if populate:
         self.set_active(config.getboolean(section, option, default))
     if tooltip:
         self.set_tooltip_text(tooltip)
     self.connect('toggled', ConfigCheckButton.__toggled, section, option)
Example #42
0
 def test_get(self):
     config.set("foo", "int", "1")
     config.set("foo", "float", "1.25")
     config.set("foo", "str", "foobar")
     config.set("foo", "bool", "True")
     self.failUnlessEqual(config.getint("foo", "int"), 1)
     self.failUnlessEqual(config.getfloat("foo", "float"), 1.25)
     self.failUnlessEqual(config.get("foo", "str"), "foobar")
     self.failUnlessEqual(config.getboolean("foo", "bool"), True)
Example #43
0
 def create_repeat(orders):
     repeat = ToggledPlayOrderMenu(
         Icons.MEDIA_PLAYLIST_REPEAT,
         orders=orders,
         current_order=self.__get_repeat_class(),
         enabled=config.getboolean("memory", "repeat", False),
         tooltip=_("Toggle repeat mode"))
     repeat.connect('changed', self.__repeat_updated)
     repeat.connect('toggled', self.__repeat_toggled)
     return repeat
Example #44
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
Example #45
0
 def __set_rating(self, value, songs, librarian):
     count = len(songs)
     if (count > 1 and
             config.getboolean("browsers", "rating_confirm_multiple")):
         dialog = ConfirmRateMultipleDialog(self, count, value)
         if dialog.run() != Gtk.ResponseType.YES:
             return
     for song in songs:
         song["~#rating"] = value
     librarian.changed(songs)
    def enabled(self):
        if not config.getboolean("editing", "save_to_songs"):
            config.set("editing", "save_to_songs", True)

            warning_text = _("The following setting was enabled as it's "
                             "required for this plugin to work:\n\n%s")
            setting_name = _("Save ratings and play _counts in tags")

            Message(Gtk.MessageType.INFO, app.window, _("Settings updated"),
                    warning_text % setting_name.replace("_", "")).run()
Example #47
0
 def create_repeat(orders):
     repeat = ToggledPlayOrderMenu(
         Icons.MEDIA_PLAYLIST_REPEAT,
         orders=orders,
         current_order=self.__get_repeat_class(),
         enabled=config.getboolean("memory", "repeat", False),
         tooltip=_("Toggle repeat mode"))
     repeat.connect('changed', self.__repeat_updated)
     repeat.connect('toggled', self.__repeat_toggled)
     return repeat
Example #48
0
 def create_shuffle(orders):
     shuffle = ToggledPlayOrderMenu(
         Icons.MEDIA_PLAYLIST_SHUFFLE,
         orders=orders,
         current_order=self.__get_shuffle_class(),
         enabled=(config.getboolean("memory", "shuffle", False)),
         tooltip=_("Toggle shuffle mode"))
     shuffle.connect('changed', self.__shuffle_updated)
     shuffle.connect('toggled', self.__shuffle_toggled)
     return shuffle
Example #49
0
 def __init__(self):
     super().__init__(self._label,
                      self._section,
                      self._key,
                      tooltip=self._tooltip)
     try:
         self.set_active(config.getboolean(self._section, self._key))
     except:
         pass
     connect_obj(self, 'toggled', self.emit, 'preview')
Example #50
0
 def create_shuffle(orders):
     shuffle = ToggledPlayOrderMenu(
         Icons.MEDIA_PLAYLIST_SHUFFLE,
         orders=orders,
         current_order=self.__get_shuffle_class(),
         enabled=(config.getboolean("memory", "shuffle", False)),
         tooltip=_("Toggle shuffle mode"))
     shuffle.connect('changed', self.__shuffle_updated)
     shuffle.connect('toggled', self.__shuffle_toggled)
     return shuffle
Example #51
0
 def set_rating(self, value, songs, librarian):
     count = len(songs)
     if (count > 1 and
             config.getboolean("browsers", "rating_confirm_multiple")):
         dialog = ConfirmRateMultipleDialog(self, count, value)
         if dialog.run() != gtk.RESPONSE_YES:
             return
     for song in songs:
         song["~#rating"] = value
     librarian.changed([song])
Example #52
0
 def __keep_songs_activated(self, activator):
     keep_song = config.getboolean("memory", "queue_keep_songs", False)
     if keep_song:
         self.queue.set_first_column_type(CurrentColumn)
     else:
         for col in self.queue.get_columns():
             # Remove the CurrentColum if it exists
             if isinstance(col, CurrentColumn):
                 self.queue.set_first_column_type(None)
                 break
Example #53
0
 def __update_queue_stop(self, player, song, stopped, model):
     enabled = config.getboolean("memory", "queue_stop_at_end", False)
     songs_left = len(model.get())
     queue_empty = songs_left == 0 and song is self._last_queue_song
     queue_finished = (self._curr_song_index and
                       self._curr_song_index + 1 >= songs_left)
     if (enabled and not stopped and (queue_empty or queue_finished)):
         app.player.stop()
     else:
         self.queue_finished = False
Example #54
0
def boolean_config(section, option, label, tooltip):
    def on_reverted(*args):
        config.reset(section, option)
        button.set_active(config.getboolean(section, option))

    def __toggled(self, section, option):
        config.set(section, option, str(bool(self.get_active())).lower())

    default = config.getboolean(section, option)
    button = Gtk.CheckButton()
    button.set_active(config.getboolean(section, option, default))
    button.set_tooltip_text(tooltip)
    button.connect('toggled', __toggled, section, option)
    revert = Gtk.Button()
    revert.add(Gtk.Image.new_from_icon_name(Icons.DOCUMENT_REVERT, Gtk.IconSize.BUTTON))
    revert.connect("clicked", on_reverted)

    lbl = Gtk.Label(label=label, use_underline=True)
    lbl.set_mnemonic_widget(button)
    return lbl, button, revert
Example #55
0
    def __jump_to_current(self, explicit, songlist=None, force_scroll=False):
        """Select/scroll to the current playing song in the playlist.
        If it can't be found tell the browser to properly fill the playlist
        with an appropriate selection containing the song.

        explicit means that the jump request comes from the user and not
        from an event like song-started.

        songlist is the songlist to be jumped within. Usually the main song
        list or the queue. If None, the currently sourced songlist will be
        used.

        force_scroll will ask the browser to refill the playlist in any case.
        """
        def idle_jump_to(song, select):
            ok = songlist.jump_to_song(song, select=select)
            if ok:
                songlist.grab_focus()
            return False

        if not songlist:
            if (config.getboolean("memory", "queue_keep_songs")
                    and self.qexpander.queue.sourced):
                songlist = self.qexpander.queue
            else:
                songlist = self.songlist

        if app.player is None:
            return

        song = app.player.song

        # We are not playing a song
        if song is None:
            return

        if not force_scroll:
            ok = songlist.jump_to_song(song, select=explicit)
        else:
            assert explicit
            ok = False

        if ok:
            songlist.grab_focus()
        elif explicit:
            # if we can't find it and the user requested it, try harder
            self.browser.scroll(song)
            # We need to wait until the browser has finished
            # scrolling/filling and the songlist is ready.
            # Not perfect, but works for now.
            GLib.idle_add(idle_jump_to,
                          song,
                          explicit,
                          priority=GLib.PRIORITY_LOW)
Example #56
0
 def set_tag(self, tag, library):
     if not config.getboolean("settings", "eager_search"):
         return
     elif tag is None:
         return
     elif tag in ("bpm date discnumber isrc originaldate recordingdate "
                  "tracknumber title").split() + MACHINE_TAGS:
         return
     elif tag in formats.PEOPLE:
         tag = "~people"
     copool.add(self.__fill_tag, tag, library)
Example #57
0
    def _update(self, songs=None):
        if songs is None:
            songs = self.__songinfo.songs
        else:
            self.__songinfo = AudioFileGroup(songs)
        songinfo = self.__songinfo

        keys = list(songinfo.keys())
        default_tags = get_default_tags()
        keys = set(keys + default_tags)

        def custom_sort(key):
            try:
                prio = default_tags.index(key)
            except ValueError:
                prio = len(default_tags)
            return (prio, tagsortkey(key))

        if not config.getboolean("editing", "alltags"):
            keys = filter(lambda k: k not in MACHINE_TAGS, keys)

        if not songs:
            keys = []

        with self._view.without_model() as model:
            model.clear()

            for tag in sorted(keys, key=custom_sort):
                canedit = songinfo.can_change(tag)

                # default tags
                if tag not in songinfo:
                    entry = ListEntry(tag, Comment(u""))
                    entry.canedit = canedit
                    model.append(row=[entry])
                    continue

                for value in songinfo[tag]:
                    entry = ListEntry(tag, value)
                    entry.origvalue = value
                    entry.edited = False
                    entry.canedit = canedit
                    entry.deleted = False
                    entry.renamed = False
                    entry.origtag = ""
                    model.append(row=[entry])

        self._buttonbox.set_sensitive(bool(songinfo.can_change()))
        self._revert.set_sensitive(False)
        self._remove.set_sensitive(False)
        self._save.set_sensitive(False)
        self._add.set_sensitive(bool(songs))
        self._parent.set_pending(None)
Example #58
0
 def set_rating(self, value, songs, librarian):
     count = len(songs)
     if (count > 1
             and config.getboolean("browsers", "rating_confirm_multiple")):
         parent = qltk.get_menu_item_top_parent(self)
         dialog = ConfirmRateMultipleDialog(parent, _("Change _Rating"),
                                            count, value)
         if dialog.run() != Gtk.ResponseType.YES:
             return
     for song in songs:
         song["~#rating"] = value
     librarian.changed(songs)
Example #59
0
    def __song_started(self, player, song):
        self.__update_title(player)

        for wid in ["Jump", "Next", "EditTags", "Information",
                    "EditBookmarks", "AddBookmark", "StopAfter"]:
            self.ui.get_widget(
                '/Menu/Control/' + wid).set_sensitive(bool(song))

        # don't jump on stream changes (player.info != player.song)
        if song and player.song is song and not self.songlist._activated and \
            config.getboolean("settings", "jump") and self.songlist.sourced:
            self.__jump_to_current(False)
Example #60
0
    def __text_changed(self, *args):
        # the combobox has an active entry selected -> no timeout
        # todo: we need a timeout when the selection changed because
        # of keyboard input (up/down arrows)
        if self.__combo.get_active() != -1:
            self.__filter_changed()
            return

        if not config.getboolean('settings', 'eager_search'):
            return

        self.__deferred_changed()