def __init__(self, library):
        super(AudioFeeds, self).__init__(spacing=6)
        self.set_orientation(Gtk.Orientation.VERTICAL)

        self.__view = view = AllTreeView()
        self.__render = render = Gtk.CellRendererText()
        render.set_property('ellipsize', Pango.EllipsizeMode.END)
        col = Gtk.TreeViewColumn("Audio Feeds", render)
        col.set_cell_data_func(render, AudioFeeds.cell_data)
        view.append_column(col)
        view.set_model(self.__feeds)
        view.set_rules_hint(True)
        view.set_headers_visible(False)
        swin = ScrolledWindow()
        swin.set_shadow_type(Gtk.ShadowType.IN)
        swin.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        swin.add(view)
        self.pack_start(swin, True, True, 0)

        new = Button(_("_New"), Icons.LIST_ADD, Gtk.IconSize.MENU)
        new.connect('clicked', self.__new_feed)
        view.get_selection().connect('changed', self.__changed)
        view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        view.connect('popup-menu', self.__popup_menu)

        targets = [("text/uri-list", 0, DND_URI_LIST),
                   ("text/x-moz-url", 0, DND_MOZ_URL)]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]

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

        connect_obj(self, 'destroy', self.__save, view)

        self.pack_start(Align(new, left=3, bottom=3), False, True, 0)

        for child in self.get_children():
            child.show_all()
Exemple #2
0
    def __init__(self, library):
        super(FileSystem, self).__init__()
        sw = ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)

        dt = MainDirectoryTree(folders=get_scan_dirs())
        targets = [("text/x-quodlibet-songs", Gtk.TargetFlags.SAME_APP,
                    self.TARGET_QL), ("text/uri-list", 0, self.TARGET_EXT)]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]

        dt.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, targets,
                           Gdk.DragAction.COPY)
        dt.connect('drag-data-get', self.__drag_data_get)

        sel = dt.get_selection()
        sel.unselect_all()
        connect_obj(sel, 'changed', copool.add, self.__songs_selected, dt)
        dt.connect('row-activated', lambda *a: self.songs_activated())
        sw.add(dt)
        self.pack_start(sw, True, True, 0)

        self.show_all()
Exemple #3
0
    def __init__(self, initial=None, filter=filesel_filter, folders=None):
        """
        initial -- a path to a file which should be shown initially
        filter -- a function which filters paths shown in the file list
        folders -- list of shown folders in the directory tree
        """

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

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

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

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

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

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

        column.set_cell_data_func(render, cell_icon)

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

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

        column.set_cell_data_func(render, cell_data)

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

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

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

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

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

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

        sw = ScrolledWindow()
        sw.add(filelist)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.pack2(sw, resize=True)
Exemple #4
0
    def __init__(self, parent=None):
        if self.is_not_unique():
            return
        on_top = config.getboolean("settings", "plugins_window_on_top", False)
        super().__init__(dialog=on_top)
        self.set_title(_("Plugins"))
        self.set_default_size(750, 500)
        if parent and on_top:
            self.set_transient_for(parent)
        self.set_type_hint(Gdk.WindowTypeHint.NORMAL)
        self.enable_window_tracking("plugin_prefs")

        model = ObjectStore()
        filter_model = ObjectModelFilter(child_model=model)

        self._list_view = plv = PluginListView()
        plv.set_model(filter_model)
        plv.set_rules_hint(True)

        plv.connect("plugin-toggled", self.__plugin_toggled)
        sw = ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
        sw.add(plv)
        sw.set_shadow_type(Gtk.ShadowType.IN)

        fb = Gtk.HBox(spacing=6)

        enabled_combo = PluginEnabledFilterCombo()
        enabled_combo.connect("changed", lambda s: filter_model.refilter())
        enabled_combo.set_tooltip_text(_("Filter by plugin state / tag"))
        fb.pack_start(enabled_combo, True, True, 0)
        self._enabled_combo = enabled_combo

        type_combo = PluginTypeFilterCombo()
        type_combo.connect("changed", lambda s: filter_model.refilter())
        type_combo.set_tooltip_text(_("Filter by plugin type"))
        fb.pack_start(type_combo, True, True, 0)
        self._type_combo = type_combo

        self._filter_entry = fe = UndoSearchEntry()
        fe.set_tooltip_text(_("Filter by plugin name or description"))
        fe.connect("changed", lambda s: filter_model.refilter())

        errors = qltk.Button(_("Show _Errors"), Icons.DIALOG_WARNING)
        errors.set_focus_on_click(False)
        errors.connect('clicked', self.__show_errors)
        errors.show()
        errors = Align(errors, top=6, bottom=6)
        errors.set_no_show_all(True)
        bbox = Gtk.VBox()
        bbox.pack_start(errors, True, True, 0)

        pref_box = PluginPreferencesContainer()

        if const.DEBUG:
            refresh = qltk.Button(_("_Refresh"), Icons.VIEW_REFRESH)
            refresh.set_focus_on_click(False)
            refresh.connect('clicked', self.__refresh, plv, pref_box, errors,
                            enabled_combo)
            bbox.pack_start(refresh, True, True, 0)

        filter_box = Gtk.VBox(spacing=6)
        filter_box.pack_start(fb, False, True, 0)
        filter_box.pack_start(fe, False, True, 0)

        vbox = Gtk.VBox()
        vbox.pack_start(Align(filter_box, border=6, right=-6), False, False, 0)
        vbox.pack_start(sw, True, True, 0)
        vbox.pack_start(Align(bbox, left=3, right=3, top=0), False, False, 3)
        paned = Paned()
        paned.pack1(vbox, False, False)

        close = qltk.Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        bb_align = Align(halign=Gtk.Align.END, valign=Gtk.Align.END)
        bb = Gtk.HButtonBox()
        bb.set_layout(Gtk.ButtonBoxStyle.END)
        bb.pack_start(close, True, True, 0)
        bb_align.add(bb)

        selection = plv.get_selection()
        selection.connect('changed', self.__selection_changed, pref_box)
        selection.emit('changed')

        right_box = Gtk.VBox()
        right_box.pack_start(pref_box, True, True, 0)
        if not self.has_close_button():
            right_box.pack_start(bb_align, True, True, 0)

        align = Align(right_box, left=6, right=15, top=12, bottom=3)
        paned.pack2(align, True, False)
        paned.set_position(290)

        self.add(paned)

        self.__refill(plv, pref_box, errors, enabled_combo)

        self.connect('destroy', self.__destroy)
        filter_model.set_visible_func(
            self.__filter, (fe, enabled_combo, type_combo))

        self.get_child().show_all()
        fe.grab_focus()

        restore_id = config.get("memory", "plugin_selection")
        plv.select_by_plugin_id(restore_id)
Exemple #5
0
    def __init__(self, library):
        super(CollectionBrowser, self).__init__(spacing=6)
        self.set_orientation(Gtk.Orientation.VERTICAL)

        self._register_instance()
        if self.__model is None:
            self._init_model(library)

        sw = ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.view = view = CollectionView()
        view.set_headers_visible(False)
        model_sort = CollectionSortModel(model=self.__model)
        model_filter = CollectionFilterModel(child_model=model_sort)
        self.__filter = None
        self.__bg_filter = background_filter()
        model_filter.set_visible_func(self.__parse_query)
        view.set_model(model_filter)

        def cmpa(a, b):
            """Like cmp but treats values that evaluate to false as inf"""
            if not a and b:
                return 1
            if not b and a:
                return -1
            return cmp(a, b)

        def cmp_rows(model, i1, i2, data):
            t1, t2 = model[i1][0], model[i2][0]
            pos1 = _ORDERING.get(t1, 0)
            pos2 = _ORDERING.get(t2, 0)
            if pos1 or pos2:
                return cmp(pos1, pos2)

            if not isinstance(t1, AlbumNode):
                return cmp(util.human_sort_key(t1), util.human_sort_key(t2))

            a1, a2 = t1.album, t2.album
            return (cmpa(a1.peoplesort, a2.peoplesort)
                    or cmpa(a1.date, a2.date) or cmpa(a1.sort, a2.sort)
                    or cmp(a1.key, a2.key))

        model_sort.set_sort_func(0, cmp_rows)
        model_sort.set_sort_column_id(0, Gtk.SortType.ASCENDING)

        column = Gtk.TreeViewColumn("albums")

        def cell_data(column, cell, model, iter_, data):
            markup = model.get_markup(self.__model.tags, iter_)
            cell.markup = markup
            cell.set_property('markup', markup)

        def get_scaled_cover(item):
            if item.scanned:
                return item.cover

            scale_factor = self.get_scale_factor()
            item.scan_cover(scale_factor=scale_factor)
            return item.cover

        def cell_data_pb(column, cell, model, iter_, data):
            album = model.get_album(iter_)
            if album is None:
                cell.set_property('icon-name', Icons.FOLDER)
            else:
                item = model.get_value(iter_)
                cover = get_scaled_cover(item)
                if cover:
                    cover = add_border_widget(cover, view)
                    surface = get_surface_for_pixbuf(self, cover)
                    cell.set_property("surface", surface)
                else:
                    cell.set_property('icon-name', Icons.MEDIA_OPTICAL)

        imgrender = Gtk.CellRendererPixbuf()
        render = Gtk.CellRendererText()
        if view.supports_hints():
            render.set_property('ellipsize', Pango.EllipsizeMode.END)
        column.pack_start(imgrender, False)
        column.pack_start(render, True)
        column.set_cell_data_func(render, cell_data)
        column.set_cell_data_func(imgrender, cell_data_pb)
        view.append_column(column)

        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.add(view)

        hbox = Gtk.HBox(spacing=6)

        prefs = Gtk.Button()
        prefs.add(SymbolicIconImage(Icons.EMBLEM_SYSTEM, Gtk.IconSize.MENU))
        prefs.connect('clicked', lambda *x: Preferences(self))

        self.accelerators = Gtk.AccelGroup()
        search = SearchBarBox(completion=AlbumTagCompletion(),
                              accel_group=self.accelerators)
        search.connect('query-changed', self.__update_filter)
        connect_obj(search, 'focus-out', lambda w: w.grab_focus(), view)
        self.__search = search

        hbox.pack_start(search, True, True, 0)
        hbox.pack_start(prefs, False, True, 0)

        self.pack_start(Align(hbox, left=6, top=6), False, True, 0)
        self.pack_start(sw, True, True, 0)

        view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        self.__sig = view.get_selection().connect('changed',
                                                  self.__selection_changed)
        view.connect('row-activated', self.__play)
        connect_obj(view, 'popup-menu', self.__popup, view, library)

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

        view.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, targets,
                             Gdk.DragAction.COPY)
        view.connect("drag-data-get", self.__drag_data_get)

        self.connect("destroy", self.__destroy)

        self.show_all()
Exemple #6
0
    def __init__(self, library):
        super(AlbumList, self).__init__(spacing=6)
        self.set_orientation(Gtk.Orientation.VERTICAL)

        self._register_instance()
        if self.__model is None:
            self._init_model(library)

        self._cover_cancel = Gio.Cancellable()

        sw = ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.view = view = AllTreeView()
        view.set_headers_visible(False)
        model_sort = AlbumSortModel(model=self.__model)
        model_filter = AlbumFilterModel(child_model=model_sort)

        self.__bg_filter = background_filter()
        self.__filter = None
        model_filter.set_visible_func(self.__parse_query)

        render = Gtk.CellRendererPixbuf()
        self.__cover_column = column = Gtk.TreeViewColumn("covers", render)
        column.set_visible(config.getboolean("browsers", "album_covers"))
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        column.set_fixed_width(get_cover_size() + 12)
        render.set_property('height', get_cover_size() + 8)
        render.set_property('width', get_cover_size() + 8)

        def cell_data_pb(column, cell, model, iter_, no_cover):
            item = model.get_value(iter_)

            if item.album is None:
                surface = None
            elif item.cover:
                pixbuf = item.cover
                pixbuf = add_border_widget(pixbuf, self.view)
                surface = get_surface_for_pixbuf(self, pixbuf)
                # don't cache, too much state has an effect on the result
                self.__last_render_surface = None
            else:
                surface = no_cover

            if self.__last_render_surface == surface:
                return
            self.__last_render_surface = surface
            cell.set_property("surface", surface)

        column.set_cell_data_func(render, cell_data_pb, self._no_cover)
        view.append_column(column)

        render = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("albums", render)
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        if view.supports_hints():
            render.set_property('ellipsize', Pango.EllipsizeMode.END)

        def cell_data(column, cell, model, iter_, data):
            album = model.get_album(iter_)

            if album is None:
                text = "<b>%s</b>\n" % _("All Albums")
                text += numeric_phrase("%d album", "%d albums", len(model) - 1)
                markup = text
            else:
                markup = self.display_pattern % album

            if self.__last_render == markup:
                return
            self.__last_render = markup
            cell.markup = markup
            cell.set_property('markup', markup)

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

        view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        view.set_rules_hint(True)
        view.set_search_equal_func(self.__search_func, None)
        view.set_search_column(0)
        view.set_model(model_filter)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.add(view)

        view.connect('row-activated', self.__play_selection)
        self.__sig = view.connect(
            'selection-changed',
            util.DeferredSignal(self.__update_songs, owner=view))

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

        view.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, targets,
                             Gdk.DragAction.COPY)
        view.connect("drag-data-get", self.__drag_data_get)
        connect_obj(view, 'popup-menu', self.__popup, view, library)

        self.accelerators = Gtk.AccelGroup()
        search = SearchBarBox(completion=AlbumTagCompletion(),
                              accel_group=self.accelerators)
        search.connect('query-changed', self.__update_filter)
        connect_obj(search, 'focus-out', lambda w: w.grab_focus(), view)
        self.__search = search

        prefs = PreferencesButton(self, model_sort)
        search.pack_start(prefs, False, True, 0)
        self.pack_start(Align(search, left=6, top=6), False, True, 0)
        self.pack_start(sw, True, True, 0)

        self.connect("destroy", self.__destroy)

        self.enable_row_update(view, sw, self.__cover_column)

        self.connect('key-press-event', self.__key_pressed, library.librarian)

        if app.cover_manager:
            connect_destroy(app.cover_manager, "cover-changed",
                            self._cover_changed)

        self.show_all()
Exemple #7
0
    def __init__(self, library, player, headless=False, restore_cb=None):
        super().__init__(dialog=False)

        self.__destroyed = False
        self.__update_title(player)
        self.set_default_size(600, 480)

        main_box = Gtk.VBox()
        self.add(main_box)
        self.side_book = qltk.Notebook()

        # get the playlist up before other stuff
        self.songlist = MainSongList(library, player)
        self.songlist.connect("key-press-event", self.__songlist_key_press)
        self.songlist.connect_after('drag-data-received',
                                    self.__songlist_drag_data_recv)
        self.song_scroller = ScrolledWindow()
        self.song_scroller.set_policy(Gtk.PolicyType.AUTOMATIC,
                                      Gtk.PolicyType.AUTOMATIC)
        self.song_scroller.set_shadow_type(Gtk.ShadowType.IN)
        self.song_scroller.add(self.songlist)

        self.qexpander = QueueExpander(library, player)
        self.qexpander.set_no_show_all(True)
        self.qexpander.set_visible(config.getboolean("memory", "queue"))

        def on_queue_visible(qex, param):
            config.set("memory", "queue", str(qex.get_visible()))

        self.qexpander.connect("notify::visible", on_queue_visible)

        self.playlist = PlaylistMux(player, self.qexpander.model,
                                    self.songlist.model)

        self.__player = player
        # create main menubar, load/restore accelerator groups
        self.__library = library
        ui = self.__create_menu(player, library)
        accel_group = ui.get_accel_group()
        self.add_accel_group(accel_group)

        def scroll_and_jump(*args):
            self.__jump_to_current(True, None, True)

        keyval, mod = Gtk.accelerator_parse("<Primary><shift>J")
        accel_group.connect(keyval, mod, 0, scroll_and_jump)

        # custom accel map
        accel_fn = os.path.join(quodlibet.get_user_dir(), "accels")
        Gtk.AccelMap.load(accel_fn)
        # save right away so we fill the file with example comments of all
        # accels
        Gtk.AccelMap.save(accel_fn)

        menubar = ui.get_widget("/Menu")

        # Since https://git.gnome.org/browse/gtk+/commit/?id=b44df22895c79
        # toplevel menu items show an empty 16x16 image. While we don't
        # need image items there UIManager creates them by default.
        # Work around by removing the empty GtkImages
        for child in menubar.get_children():
            if isinstance(child, Gtk.ImageMenuItem):
                child.set_image(None)

        main_box.pack_start(menubar, False, True, 0)

        top_bar = TopBar(self, player, library)
        main_box.pack_start(top_bar, False, True, 0)
        self.top_bar = top_bar

        self.__browserbox = Align(bottom=3)
        self.__paned = paned = ConfigRHPaned("memory", "sidebar_pos", 0.25)
        paned.pack1(self.__browserbox, resize=True)
        # We'll pack2 when necessary (when the first sidebar plugin is set up)

        main_box.pack_start(paned, True, True, 0)

        play_order = PlayOrderWidget(self.songlist.model, player)
        statusbox = StatusBarBox(play_order, self.qexpander)
        self.order = play_order
        self.statusbar = statusbox.statusbar

        main_box.pack_start(Align(statusbox, border=3, top=-3), False, True, 0)

        self.songpane = SongListPaned(self.song_scroller, self.qexpander)
        self.songpane.show_all()

        try:
            orders = []
            for e in config.getstringlist('memory', 'sortby', []):
                orders.append((e[1:], int(e[0])))
        except ValueError:
            pass
        else:
            self.songlist.set_sort_orders(orders)

        self.browser = None
        self.ui = ui

        main_box.show_all()

        self._playback_error_dialog = None
        connect_destroy(player, 'song-started', self.__song_started)
        connect_destroy(player, 'paused', self.__update_paused, True)
        connect_destroy(player, 'unpaused', self.__update_paused, False)
        # make sure we redraw all error indicators before opening
        # a dialog (blocking the main loop), so connect after default handlers
        connect_after_destroy(player, 'error', self.__player_error)
        # connect after to let SongTracker update stats
        connect_after_destroy(player, "song-ended", self.__song_ended)

        # set at least the playlist. the song should be restored
        # after the browser emits the song list
        player.setup(self.playlist, None, 0)
        self.__restore_cb = restore_cb
        self.__first_browser_set = True

        restore_browser = not headless
        try:
            self._select_browser(self, config.get("memory", "browser"),
                                 library, player, restore_browser)
        except:
            config.set("memory", "browser", browsers.name(browsers.default))
            config.save()
            raise

        self.songlist.connect('popup-menu', self.__songs_popup_menu)
        self.songlist.connect('columns-changed', self.__cols_changed)
        self.songlist.connect('columns-changed', self.__hide_headers)
        self.songlist.info.connect("changed", self.__set_totals)

        lib = library.librarian
        connect_destroy(lib, 'changed', self.__song_changed, player)

        targets = [("text/uri-list", Gtk.TargetFlags.OTHER_APP, 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-data-received', self.__drag_data_received)

        if not headless:
            on_first_map(self, self.__configure_scan_dirs, library)

        if config.getboolean('library', 'refresh_on_start'):
            self.__rebuild(None, False)

        self.connect("key-press-event", self.__key_pressed, player)

        self.connect("destroy", self.__destroy)

        self.enable_window_tracking("quodlibet")
Exemple #8
0
    def __init__(self, library, main):
        super(InternetRadio, self).__init__(spacing=12)

        if not self.instances():
            self._init(library)
        self._register_instance()

        self.connect('destroy', self.__destroy)

        completion = LibraryTagCompletion(self.__stations)
        self.accelerators = Gtk.AccelGroup()
        self.__searchbar = search = SearchBarBox(completion=completion,
                                                 accel_group=self.accelerators)
        gobject_weak(search.connect, 'query-changed', self.__filter_changed)

        menu = Gtk.Menu()
        new_item = MenuItem(_("_New Station..."), Gtk.STOCK_ADD)
        gobject_weak(new_item.connect, 'activate', self.__add)
        menu.append(new_item)
        update_item = MenuItem(_("_Update Stations"), Gtk.STOCK_REFRESH)
        gobject_weak(update_item.connect, 'activate', self.__update)
        menu.append(update_item)
        menu.show_all()

        button = MenuButton(
            SymbolicIconImage("emblem-system", Gtk.IconSize.MENU),
            arrow=True)
        button.set_menu(menu)

        def focus(widget, *args):
            qltk.get_top_parent(widget).songlist.grab_focus()
        gobject_weak(search.connect, 'focus-out', focus, parent=self)

        # treeview
        scrolled_window = ScrolledWindow()
        scrolled_window.set_shadow_type(Gtk.ShadowType.IN)
        self.view = view = AllTreeView()
        view.set_headers_visible(False)
        scrolled_window.set_policy(
            Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scrolled_window.add(view)
        model = Gtk.ListStore(int, str, str, str)

        model.append(row=[self.TYPE_ALL, Gtk.STOCK_DIRECTORY, "__all",
                          _("All Stations")])
        model.append(row=[self.TYPE_SEP, Gtk.STOCK_DIRECTORY, "", ""])
        #Translators: Favorite radio stations
        model.append(row=[self.TYPE_FAV, Gtk.STOCK_DIRECTORY, "__fav",
                          _("Favorites")])
        model.append(row=[self.TYPE_SEP, Gtk.STOCK_DIRECTORY, "", ""])

        filters = self.filters
        for text, k in sorted([(filters.text(k), k) for k in filters.keys()]):
            model.append(row=[self.TYPE_FILTER, Gtk.STOCK_FIND, k, text])

        model.append(row=[self.TYPE_NOCAT, Gtk.STOCK_DIRECTORY,
                          "nocat", _("No Category")])

        def separator(model, iter, data):
            return model[iter][self.TYPE] == self.TYPE_SEP
        view.set_row_separator_func(separator, None)

        def search_func(model, column, key, iter, data):
            return key.lower() not in model[iter][column].lower()
        view.set_search_column(self.NAME)
        view.set_search_equal_func(search_func, None)

        column = Gtk.TreeViewColumn("genres")
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)

        renderpb = Gtk.CellRendererPixbuf()
        renderpb.props.xpad = 3
        column.pack_start(renderpb, False)
        column.add_attribute(renderpb, "stock_id", self.STOCK)

        render = Gtk.CellRendererText()
        render.set_property('ellipsize', Pango.EllipsizeMode.END)
        view.append_column(column)
        column.pack_start(render, True)
        column.add_attribute(render, "text", self.NAME)

        view.set_model(model)

        # selection
        selection = view.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.__changed_sig = gobject_weak(selection.connect, 'changed',
            util.DeferredSignal(lambda x: self.activate()), parent=view)

        box = Gtk.HBox(spacing=6)
        box.pack_start(search, True, True, 0)
        box.pack_start(button, False, True, 0)
        if main:
            self.pack_start(Alignment(box, left=6, right=6, top=6),
                            True, True, 0)
        else:
            self.pack_start(box, True, True, 0)
        self.__filter_list = scrolled_window

        def qbar_response(infobar, response_id):
            if response_id == infobar.RESPONSE_LOAD:
                self.__update()

        self.qbar = QuestionBar()
        self.qbar.connect("response", qbar_response)
        if self._is_library_empty():
            self.qbar.show()

        self.show_all()
Exemple #9
0
    def _create_category_widget(self):
        scrolled_window = ScrolledWindow()
        scrolled_window.show()
        scrolled_window.set_shadow_type(Gtk.ShadowType.IN)
        self.view = view = RCMHintedTreeView()
        view.show()
        view.set_headers_visible(False)
        scrolled_window.set_policy(Gtk.PolicyType.NEVER,
                                   Gtk.PolicyType.AUTOMATIC)
        scrolled_window.add(view)
        model = Gtk.ListStore(int, str, str, str, bool)
        filters = self.filters
        for (i, (name, data)) in enumerate(iteritems(filters)):
            filter_type, icon, query, always = data
            enabled = always or self.online
            model.append(row=[filter_type, icon, name, query, enabled])
            if i + 1 < len(filters):
                model.append(row=[FilterType.SEP, None, "", None, False])

        def is_separator(model, iter_, data):
            return model[iter_][self.ModelIndex.TYPE] == FilterType.SEP

        view.set_row_separator_func(is_separator, None)

        def search_func(model, column, key, iter, data):
            return key.lower() not in model[iter][column].lower()

        view.set_search_column(self.ModelIndex.NAME)
        view.set_search_equal_func(search_func, None)

        column = Gtk.TreeViewColumn("Songs")
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        renderpb = Gtk.CellRendererPixbuf()
        renderpb.props.xpad = 6
        renderpb.props.ypad = 6
        column.pack_start(renderpb, False)
        column.add_attribute(renderpb, "icon-name", self.ModelIndex.ICON_NAME)
        render = Gtk.CellRendererText()
        render.set_property('ellipsize', Pango.EllipsizeMode.END)

        def cdf(column, cell, model, iter_, user_data):
            on = (self.online or model[iter_][self.ModelIndex.ALWAYS_ENABLE])
            cell.set_sensitive(on)

        column.set_cell_data_func(render, cdf)
        column.set_cell_data_func(renderpb, cdf)

        view.append_column(column)
        column.pack_start(render, True)
        column.add_attribute(render, "text", self.ModelIndex.NAME)
        view.set_model(model)

        selection = view.get_selection()

        def select_func(sel, model, path, value):
            return (self.online or
                    model[model.get_iter(path)][self.ModelIndex.ALWAYS_ENABLE])

        selection.set_select_function(select_func)
        self._refresh_online_filters()
        self.__changed_sig = connect_destroy(selection, 'changed',
                                             DeferredSignal(self._on_select))
        return scrolled_window
Exemple #10
0
 def __embed_in_scrolledwin(self, view):
     swin = ScrolledWindow()
     swin.set_shadow_type(Gtk.ShadowType.IN)
     swin.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
     swin.add(view)
     self.pack_start(swin, True, True, 0)
Exemple #11
0
    def __init__(self, library, player):
        super().__init__(spacing=3)
        sw = ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        save_interval_secs = config.getint("autosave", "queue_interval")
        self.queue = PlayQueue(library, player, save_interval_secs)
        self.queue.props.expand = True
        sw.add(self.queue)

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

        outer = ExpandBoxHack()

        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)
        name_label.set_size_request(-1, 24)
        hb2.pack_start(name_label, True, True, 0)
        left.pack_start(hb2, False, True, 0)

        menu = Gtk.Menu()

        self.count_label = count_label = Gtk.Label()
        self.count_label.set_property("ellipsize", Pango.EllipsizeMode.END)
        self.count_label.set_width_chars(10)
        self.count_label.get_style_context().add_class("dim-label")
        left.pack_start(count_label, False, True, 0)

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

        self.set_label_fill(True)

        clear_item = SmallImageButton(image=SymbolicIconImage(
            Icons.USER_TRASH, Gtk.IconSize.MENU),
                                      relief=Gtk.ReliefStyle.NONE,
                                      tooltip_text=_("Clear Queue"))
        clear_item.connect("clicked", self.__clear_queue)
        outer.pack_start(clear_item, False, False, 3)

        toggle = SmallImageToggleButton(
            image=SymbolicIconImage(Icons.SYSTEM_LOCK_SCREEN,
                                    Gtk.IconSize.MENU),
            relief=Gtk.ReliefStyle.NONE,
            tooltip_text=_(
                "Disable queue - the queue will be ignored when playing"))
        disabled = config.getboolean("memory", "queue_disable", False)
        toggle.props.active = disabled
        self.__queue_disable(disabled)
        toggle.connect('toggled',
                       lambda b: self.__queue_disable(b.props.active))
        outer.pack_start(toggle, False, False, 3)

        mode_menu = Gtk.Menu()

        norm_mode_item = RadioMenuItem(
            label=_("Ephemeral"),
            tooltip_text=_("Remove songs from the queue after playing them"),
            group=None)
        mode_menu.append(norm_mode_item)
        norm_mode_item.set_active(True)
        norm_mode_item.connect("toggled",
                               lambda _: self.__keep_songs_enable(False))

        keep_mode_item = RadioMenuItem(
            label=_("Persistent"),
            tooltip_text=_("Keep songs in the queue after playing them"),
            group=norm_mode_item)
        mode_menu.append(keep_mode_item)
        keep_mode_item.connect("toggled",
                               lambda b: self.__keep_songs_enable(True))
        keep_mode_item.set_active(
            config.getboolean("memory", "queue_keep_songs", False))

        mode_item = MenuItem(_("Mode"), Icons.SYSTEM_RUN)
        mode_item.set_submenu(mode_menu)
        menu.append(mode_item)

        rand_checkbox = ConfigCheckMenuItem(_("_Random"),
                                            "memory",
                                            "shufflequeue",
                                            populate=True)
        rand_checkbox.connect('toggled', self.__queue_shuffle)
        self.set_shuffled(rand_checkbox.get_active())
        menu.append(rand_checkbox)

        stop_checkbox = ConfigCheckMenuItem(_("Stop at End"),
                                            "memory",
                                            "queue_stop_at_end",
                                            populate=True)
        menu.append(stop_checkbox)

        button = SmallMenuButton(SymbolicIconImage(Icons.EMBLEM_SYSTEM,
                                                   Gtk.IconSize.MENU),
                                 arrow=True)
        button.set_relief(Gtk.ReliefStyle.NORMAL)
        button.show_all()
        button.hide()
        button.set_no_show_all(True)
        menu.show_all()
        button.set_menu(menu)

        outer.pack_start(button, False, False, 3)

        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_widget(outer)
        self.add(sw)
        self.connect('notify::expanded', self.__expand, button)
        self.connect('notify::expanded', self.__expand, button)

        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',
                                       DeferredSignal(self.__check_expand),
                                       count_label)
        self.queue.model.connect_after('row-deleted',
                                       DeferredSignal(self.__update_count),
                                       count_label)

        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)

        connect_destroy(player, 'song-started', self.__song_started,
                        self.queue.model)
        connect_destroy(player, 'song-ended', self.__update_queue_stop,
                        self.queue.model)

        # 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()
Exemple #12
0
    def __init__(self, library, songs, parent=None):
        super(SongProperties, self).__init__(dialog=False)
        self.set_transient_for(qltk.get_top_parent(parent))

        default_width = 600
        config_suffix = ""
        if len(songs) <= 1:
            default_width -= 200
            config_suffix += "single"
        self.set_default_size(default_width, 400)

        self.enable_window_tracking("quodlibet_properties",
                                    size_suffix=config_suffix)

        self.auto_save_on_change = config.getboolean(
                'editing', 'auto_save_changes', False)

        paned = ConfigRPaned("memory", "quodlibet_properties_pos", 0.4)
        notebook = qltk.Notebook()
        notebook.props.scrollable = True
        pages = []
        pages.extend([Ctr(self, library) for Ctr in
                      [EditTags, TagsFromPath, RenameFiles]])
        if len(songs) > 1:
            pages.append(TrackNumbers(self, library))
        for page in pages:
            page.show()
            notebook.append_page(page)

        fbasemodel = ObjectStore()
        fmodel = ObjectModelSort(model=fbasemodel)
        fview = HintedTreeView(model=fmodel)
        fview.connect('button-press-event', self.__pre_selection_changed)
        fview.set_rules_hint(True)
        selection = fview.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.__save = None

        render = Gtk.CellRendererText()
        c1 = Gtk.TreeViewColumn(_('File'), render)
        if fview.supports_hints():
            render.set_property('ellipsize', Pango.EllipsizeMode.END)
        render.set_property('xpad', 3)

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

        c1.set_cell_data_func(render, cell_data)

        def sort_func(model, a, b, data):
            a = model.get_value(a)
            b = model.get_value(b)
            return cmp(a.name, b.name)

        fmodel.set_sort_func(100, sort_func)
        c1.set_sort_column_id(100)
        fview.append_column(c1)

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

        # only show the list if there are is more than one song
        if len(songs) > 1:
            sw.show_all()

        paned.pack1(sw, shrink=False, resize=True)

        for song in songs:
            fbasemodel.append(row=[_ListEntry(song)])

        self.connect("changed", self.__on_changed)

        selection.select_all()
        paned.pack2(notebook, shrink=False, resize=True)

        csig = selection.connect('changed', self.__selection_changed)
        connect_destroy(library,
            'changed', self.__on_library_changed, fbasemodel, fview)
        connect_destroy(library,
            'removed', self.__on_library_removed, fbasemodel, selection, csig)

        self.emit('changed', songs)
        self.add(paned)
        paned.set_position(175)
        notebook.show()
        paned.show()
Exemple #13
0
    def __init__(self, library, main):
        super(AlbumList, self).__init__(spacing=6)
        self._register_instance()
        if self.__model is None:
            self._init_model(library)

        sw = ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.view = view = AllTreeView()
        view.set_headers_visible(False)
        model_sort = AlbumSortModel(model=self.__model)
        model_filter = AlbumFilterModel(child_model=model_sort)

        self.__bg_filter = background_filter()
        self.__filter = None
        model_filter.set_visible_func(self.__parse_query)

        render = Gtk.CellRendererPixbuf()
        self.__cover_column = column = Gtk.TreeViewColumn("covers", render)
        column.set_visible(config.getboolean("browsers", "album_covers"))
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        column.set_fixed_width(Album.COVER_SIZE + 12)
        render.set_property('height', Album.COVER_SIZE + 8)

        def cell_data_pb(column, cell, model, iter_, no_cover):
            album = model.get_album(iter_)
            if album is None:
                pixbuf = None
            elif album.cover:
                pixbuf = album.cover
            else:
                pixbuf = no_cover
            if self.__last_render_pb == pixbuf:
                return
            self.__last_render_pb = pixbuf
            cell.set_property('pixbuf', pixbuf)

        column.set_cell_data_func(render, cell_data_pb, self.__no_cover)
        view.append_column(column)

        render = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("albums", render)
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
        render.set_property('ellipsize', Pango.EllipsizeMode.END)

        def cell_data(column, cell, model, iter_, data):
            album = model.get_album(iter_)

            if album is None:
                text = "<b>%s</b>" % _("All Albums")
                text += "\n" + ngettext("%d album", "%d albums",
                        len(model) - 1) % (len(model) - 1)
                markup = text
            else:
                markup = AlbumList._pattern % album

            if self.__last_render == markup:
                return
            self.__last_render = markup
            cell.markup = markup
            cell.set_property('markup', markup)

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

        view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        view.set_rules_hint(True)
        view.set_search_equal_func(self.__search_func, None)
        view.set_search_column(0)
        view.set_model(model_filter)
        sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        sw.add(view)

        if main:
            gobject_weak(view.connect, 'row-activated',
                         self.__play_selection)

        self.__sig = gobject_weak(
            view.get_selection().connect, 'changed',
            util.DeferredSignal(self.__update_songs), parent=view)

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

        view.drag_source_set(
            Gdk.ModifierType.BUTTON1_MASK, targets, Gdk.DragAction.COPY)
        gobject_weak(view.connect, "drag-data-get", self.__drag_data_get)
        gobject_weak(view.connect_object, 'popup-menu',
                     self.__popup, view, library)

        self.accelerators = Gtk.AccelGroup()
        search = SearchBarBox(completion=AlbumTagCompletion(),
                              accel_group=self.accelerators)
        gobject_weak(search.connect, 'query-changed', self.__update_filter)
        gobject_weak(search.connect_object,
                     'focus-out', lambda w: w.grab_focus(), view)
        self.__search = search

        prefs = PreferencesButton(self, model_sort)
        search.pack_start(prefs, False, True, 0)
        if main:
            self.pack_start(Alignment(search, left=6, top=6), False, True, 0)
        else:
            self.pack_start(search, False, True, 0)

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

        self.connect("destroy", self.__destroy)

        self.enable_row_update(view, sw, self.__cover_column)

        self.connect('key-press-event', self.__key_pressed, library.librarian)

        self.show_all()
Exemple #14
0
    def __init__(self, library):
        super(MediaDevices, self).__init__(spacing=6)
        self.set_orientation(Gtk.Orientation.VERTICAL)
        self._register_instance()

        self.__cache = {}

        # Device list on the left pane
        swin = ScrolledWindow()
        swin.set_shadow_type(Gtk.ShadowType.IN)
        swin.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        self.pack_start(swin, True, True, 0)

        self.__view = view = AllTreeView()
        view.set_model(self.__devices)
        view.set_rules_hint(True)
        view.set_headers_visible(False)
        view.get_selection().set_mode(Gtk.SelectionMode.BROWSE)
        connect_obj(view.get_selection(), 'changed', self.__refresh, False)
        view.connect('popup-menu', self.__popup_menu, library)
        view.connect('row-activated', lambda *a: self.songs_activated())
        swin.add(view)

        col = Gtk.TreeViewColumn("Devices")
        view.append_column(col)

        render = Gtk.CellRendererPixbuf()
        col.pack_start(render, False)
        col.add_attribute(render, 'icon-name', 1)

        self.__render = render = Gtk.CellRendererText()
        render.set_property('ellipsize', Pango.EllipsizeMode.END)
        render.connect('edited', self.__edited)
        col.pack_start(render, True)
        col.set_cell_data_func(render, MediaDevices.cell_data)

        hbox = Gtk.HBox(spacing=6)
        hbox.set_homogeneous(True)
        self.pack_start(Align(hbox, left=3, bottom=3), False, True, 0)

        # refresh button
        refresh = Button(_("_Refresh"), Icons.VIEW_REFRESH, Gtk.IconSize.MENU)
        self.__refresh_button = refresh
        connect_obj(refresh, 'clicked', self.__refresh, True)
        refresh.set_sensitive(False)
        hbox.pack_start(refresh, True, True, 0)

        # eject button
        eject = Button(_("_Eject"), Icons.MEDIA_EJECT, Gtk.IconSize.MENU)
        self.__eject_button = eject
        eject.connect('clicked', self.__eject)
        eject.set_sensitive(False)
        hbox.pack_start(eject, True, True, 0)

        # Device info on the right pane
        self.__header = table = Gtk.Table()
        table.set_col_spacings(8)

        self.__device_icon = icon = Gtk.Image()
        icon.set_size_request(48, 48)
        table.attach(icon, 0, 1, 0, 2, 0)

        self.__device_name = label = Gtk.Label()
        label.set_ellipsize(Pango.EllipsizeMode.END)
        label.set_alignment(0, 0)
        table.attach(label, 1, 3, 0, 1)

        self.__device_space = label = Gtk.Label()
        label.set_ellipsize(Pango.EllipsizeMode.END)
        label.set_alignment(0, 0.5)
        table.attach(label, 1, 2, 1, 2)

        self.__progress = progress = Gtk.ProgressBar()
        progress.set_size_request(150, -1)
        table.attach(progress, 2, 3, 1, 2, xoptions=0, yoptions=0)

        self.accelerators = Gtk.AccelGroup()
        key, mod = Gtk.accelerator_parse('F2')
        self.accelerators.connect(key, mod, 0, self.__rename)

        self.__statusbar = WaitLoadBar()

        for child in self.get_children():
            child.show_all()
Exemple #15
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)
Exemple #16
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()

        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)
        name_label.set_size_request(-1, 24)
        hb2.pack_start(name_label, True, True, 0)
        left.pack_start(hb2, False, True, 0)

        menu = Gtk.Menu()

        self.count_label = count_label = Gtk.Label()
        self.count_label.set_property("ellipsize", Pango.EllipsizeMode.END)
        self.count_label.set_width_chars(10)
        self.count_label.get_style_context().add_class("dim-label")
        left.pack_start(count_label, False, True, 0)

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

        self.set_label_fill(True)

        rand_checkbox = ConfigCheckMenuItem(
                _("_Random"), "memory", "shufflequeue", populate=True)
        rand_checkbox.connect('toggled', self.__queue_shuffle)
        self.set_shuffled(rand_checkbox.get_active())
        menu.append(rand_checkbox)

        stop_checkbox = ConfigCheckMenuItem(
            _("Stop Once Empty"), "memory", "queue_stop_once_empty",
            populate=True)
        menu.append(stop_checkbox)

        clear_item = MenuItem(_("_Clear Queue"), Icons.EDIT_CLEAR)
        menu.append(clear_item)
        clear_item.connect("activate", self.__clear_queue)

        button = SmallMenuButton(
            SymbolicIconImage(Icons.EMBLEM_SYSTEM, Gtk.IconSize.MENU),
            arrow=True)
        button.set_relief(Gtk.ReliefStyle.NONE)
        button.show_all()
        button.hide()
        button.set_no_show_all(True)
        menu.show_all()
        button.set_menu(menu)

        outer.pack_start(button, False, False, 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_widget(outer)
        self.add(sw)
        self.connect('notify::expanded', self.__expand, button)
        self.connect('notify::expanded', self.__expand, button)

        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)

        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)

        connect_destroy(
            player, 'song-started', self.__song_started, self.queue.model)
        connect_destroy(
            player, 'song-ended', self.__update_queue_stop, self.queue.model)

        self._last_queue_song = None

        # 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()
Exemple #17
0
    def __init__(self, library):
        Browser.__init__(self, spacing=6)
        self.set_orientation(Gtk.Orientation.VERTICAL)
        self.songcontainer = qltk.paned.ConfigRVPaned(
            "browsers", "covergrid_pos", 0.4)
        if config.getboolean("browsers", "covergrid_wide", False):
            self.songcontainer.set_orientation(Gtk.Orientation.HORIZONTAL)

        self._register_instance()
        if self.__model is None:
            self._init_model(library)

        self._cover_cancel = Gio.Cancellable()

        self.scrollwin = sw = ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.IN)
        model_sort = AlbumSortModel(model=self.__model)
        model_filter = AlbumFilterModel(child_model=model_sort)
        self.view = view = IconView(model_filter)
        #view.set_item_width(get_cover_size() + 12)
        self.view.set_row_spacing(config.getint("browsers", "row_spacing", 6))
        self.view.set_column_spacing(config.getint("browsers",
            "column_spacing", 6))
        self.view.set_item_padding(config.getint("browsers",
            "item_padding", 6))
        self.view.set_has_tooltip(True)
        self.view.connect("query-tooltip", self._show_tooltip)

        self.__bg_filter = background_filter()
        self.__filter = None
        model_filter.set_visible_func(self.__parse_query)

        mag = config.getfloat("browsers", "covergrid_magnification", 3.)

        self.view.set_item_width(get_cover_size() * mag + 8)

        self.__cover = render = Gtk.CellRendererPixbuf()
        render.set_property('width', get_cover_size() * mag + 8)
        render.set_property('height', get_cover_size() * mag + 8)
        view.pack_start(render, False)

        def cell_data_pb(view, cell, model, iter_, no_cover):
            item = model.get_value(iter_)

            if item.album is None:
                surface = None
            elif item.cover:
                pixbuf = item.cover
                pixbuf = add_border_widget(pixbuf, self.view)
                surface = get_surface_for_pixbuf(self, pixbuf)
                # don't cache, too much state has an effect on the result
                self.__last_render_surface = None
            else:
                surface = no_cover

            if self.__last_render_surface == surface:
                return
            self.__last_render_surface = surface
            cell.set_property("surface", surface)

        view.set_cell_data_func(render, cell_data_pb, self._no_cover)

        self.__text_cells = render = Gtk.CellRendererText()
        render.set_visible(config.getboolean("browsers", "album_text", True))
        render.set_property('alignment', Pango.Alignment.CENTER)
        render.set_property('xalign', 0.5)
        render.set_property('ellipsize', Pango.EllipsizeMode.END)
        view.pack_start(render, False)

        def cell_data(view, cell, model, iter_, data):
            album = model.get_album(iter_)

            if album is None:
                text = "<b>%s</b>" % _("All Albums")
                text += "\n" + ngettext("%d album", "%d albums",
                        len(model) - 1) % (len(model) - 1)
                markup = text
            else:
                markup = self.display_pattern % album

            if self.__last_render == markup:
                return
            self.__last_render = markup
            cell.markup = markup
            cell.set_property('markup', markup)

        view.set_cell_data_func(render, cell_data, None)

        view.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
        sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        sw.add(view)

        view.connect('item-activated', self.__play_selection, None)

        self.__sig = connect_destroy(
            view, 'selection-changed',
            util.DeferredSignal(self.__update_songs, owner=self))

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

        view.drag_source_set(
            Gdk.ModifierType.BUTTON1_MASK, targets, Gdk.DragAction.COPY)
        view.connect("drag-data-get", self.__drag_data_get) # NOT WORKING
        connect_obj(view, 'button-press-event',
            self.__rightclick, view, library)
        connect_obj(view, 'popup-menu', self.__popup, view, library)

        self.accelerators = Gtk.AccelGroup()
        search = SearchBarBox(completion=AlbumTagCompletion(),
                              accel_group=self.accelerators)
        search.connect('query-changed', self.__update_filter)
        connect_obj(search, 'focus-out', lambda w: w.grab_focus(), view)
        self.__search = search

        prefs = PreferencesButton(self, model_sort)
        search.pack_start(prefs, False, True, 0)
        self.pack_start(Align(search, left=6, top=6), False, True, 0)
        self.pack_start(sw, True, True, 0)

        self.connect("destroy", self.__destroy)

        self.enable_row_update(view, sw, self.view)

        self.__update_filter()

        self.connect('key-press-event', self.__key_pressed, library.librarian)

        if app.cover_manager:
            connect_destroy(
                app.cover_manager, "cover-changed", self._cover_changed)

        self.show_all()
Exemple #18
0
    def __init__(self, initial=None, filter=filesel_filter, folders=None):
        """
        initial -- a path to a file which should be shown initially
        filter -- a function which filters paths shown in the file list
        folders -- list of shown folders in the directory tree
        """

        super(FileSelector, self).__init__()
        self.__filter = filter

        if initial is not None:
            initial = util.fsnative(initial)

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

        model = ObjectStore()
        filelist = AllTreeView(model)

        column = TreeViewColumn(_("Songs"))
        column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        render = Gtk.CellRendererPixbuf()
        render.set_property('stock_id', Gtk.STOCK_FILE)
        render.props.xpad = 3
        column.pack_start(render, False)
        render = Gtk.CellRendererText()
        column.pack_start(render, True)

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

        column.set_cell_data_func(render, cell_data)

        filelist.append_column(column)
        filelist.set_rules_hint(True)
        filelist.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        filelist.set_search_equal_func(search_func, False)
        # Allow to drag and drop files from outside
        filelist.enable_model_drag_dest([], Gdk.DragAction.COPY)
        filelist.drag_dest_add_uri_targets()
        filelist.connect('drag-data-received', self.__file_dropped)

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

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

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

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

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

        sw = ScrolledWindow()
        sw.add(filelist)
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.pack2(sw, resize=True)
Exemple #19
0
    def __init__(self, Kind, library, player):
        super(LibraryBrowser, self).__init__(dialog=False)
        self._register_instance()
        self.name = Kind.__name__

        self.set_default_size(600, 400)
        self.enable_window_tracking("browser_" + self.name)
        self.set_title(Kind.name + " - Quod Libet")
        self.add(Gtk.VBox())

        view = SongList(library, update=True)
        view.info.connect("changed", self.__set_time)
        self.songlist = view

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

        self.browser = browser = Kind(library)
        if browser.can_reorder:
            view.enable_drop()
        elif browser.dropped:
            view.enable_drop(False)
        if browser.accelerators:
            self.add_accel_group(browser.accelerators)

        self.__container = browser.pack(sw)
        self.get_child().pack_start(self.__container, True, True, 0)

        main = self.get_child()
        bottom = Gtk.HBox()
        main.pack_end(bottom, False, True, 0)

        self._filter_menu = filter_menu = FilterMenu(library, player)
        filter_menu.set_browser(self.browser)
        self.add_accel_group(filter_menu.get_accel_group())
        bottom.pack_start(filter_menu.get_widget(), False, True, 0)
        filter_menu.get_widget().show()

        self.__statusbar = Gtk.Label()
        self.__statusbar.set_alignment(1.0, 0.5)
        self.__statusbar.set_padding(6, 3)
        self.__statusbar.set_ellipsize(Pango.EllipsizeMode.START)
        bottom.pack_end(self.__statusbar, True, True, 0)
        self.__statusbar.show()
        bottom.show()

        browser.connect('songs-selected', self.__browser_cb)
        browser.finalize(False)
        view.connect('popup-menu', self.__menu, library)
        view.connect('drag-data-received', self.__drag_data_recv)
        view.connect('row-activated', self.__enqueue, player)

        if browser.headers is not None:
            view.connect('columns-changed', self.__cols_changed, browser)
            self.__cols_changed(view, browser)
        sw.show_all()
        for c in self.get_child().get_children():
            c.show()
        self.get_child().show()

        self.connect("destroy", self._on_destroy)
Exemple #20
0
    def __init__(self, library, songs, parent=None):
        super(SongProperties, self).__init__(dialog=False)
        self.set_transient_for(qltk.get_top_parent(parent))

        default_width = 600
        config_suffix = ""
        if len(songs) <= 1:
            default_width -= 200
            config_suffix += "single"
        self.set_default_size(default_width, 400)

        self.enable_window_tracking("quodlibet_properties",
                                    size_suffix=config_suffix)

        self.auto_save_on_change = config.getboolean(
                'editing', 'auto_save_changes', False)

        paned = Gtk.HPaned()
        notebook = qltk.Notebook()
        notebook.props.scrollable = True
        pages = []
        pages.extend([Ctr(self, library) for Ctr in
                      [EditTags, TagsFromPath, RenameFiles]])
        if len(songs) > 1:
            pages.append(TrackNumbers(self, library))
        for page in pages:
            page.show()
            notebook.append_page(page)

        fbasemodel = Gtk.ListStore(object, str)
        fmodel = Gtk.TreeModelSort(model=fbasemodel)
        fview = HintedTreeView(model=fmodel)
        fview.connect('button-press-event', self.__pre_selection_changed)
        fview.set_rules_hint(True)
        selection = fview.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.__save = None

        if len(songs) > 1:
            render = Gtk.CellRendererText()
            c1 = Gtk.TreeViewColumn(_('File'), render, text=1)
            render.set_property('ellipsize', Pango.EllipsizeMode.END)
            render.set_property('xpad', 3)
            c1.set_sort_column_id(1)
            fview.append_column(c1)
            sw = ScrolledWindow()
            sw.add(fview)
            sw.set_shadow_type(Gtk.ShadowType.IN)
            sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
            sw.show_all()
            paned.pack1(sw, shrink=False, resize=True)

        # Invisible selections behave a little strangely. So, when
        # handling this selection, there's a lot of if len(model) == 1
        # checks that "hardcode" the first row being selected.

        for song in songs:
            fbasemodel.append(row=[song, fsdecode(song("~basename"))])

        self.connect_object('changed', SongProperties.__set_title, self)

        selection.select_all()
        paned.pack2(notebook, shrink=False, resize=True)

        csig = selection.connect('changed', self.__selection_changed)
        s1 = library.connect(
            'changed', self.__refresh, fbasemodel, fview)
        s2 = library.connect(
            'removed', self.__remove, fbasemodel, selection, csig)
        self.connect_object('destroy', library.disconnect, s1)
        self.connect_object('destroy', library.disconnect, s2)
        self.connect_object('changed', self.set_pending, None)

        self.emit('changed', songs)
        self.add(paned)
        paned.set_position(175)
        notebook.show()
        paned.show()
Exemple #21
0
    def __init__(self, library):
        super(InternetRadio, self).__init__(spacing=12)
        self.set_orientation(Gtk.Orientation.VERTICAL)

        if not self.instances():
            self._init(library)
        self._register_instance()

        self.connect('destroy', self.__destroy)

        completion = LibraryTagCompletion(self.__stations)
        self.accelerators = Gtk.AccelGroup()
        self.__searchbar = search = SearchBarBox(completion=completion,
                                                 accel_group=self.accelerators)
        search.connect('query-changed', self.__filter_changed)

        menu = Gtk.Menu()
        new_item = MenuItem(_(u"_New Station…"), Icons.LIST_ADD)
        new_item.connect('activate', self.__add)
        menu.append(new_item)
        update_item = MenuItem(_("_Update Stations"), Icons.VIEW_REFRESH)
        update_item.connect('activate', self.__update)
        menu.append(update_item)
        menu.show_all()

        button = MenuButton(SymbolicIconImage(Icons.EMBLEM_SYSTEM,
                                              Gtk.IconSize.MENU),
                            arrow=True)
        button.set_menu(menu)

        def focus(widget, *args):
            qltk.get_top_parent(widget).songlist.grab_focus()

        search.connect('focus-out', focus)

        # treeview
        scrolled_window = ScrolledWindow()
        scrolled_window.show()
        scrolled_window.set_shadow_type(Gtk.ShadowType.IN)
        self.view = view = AllTreeView()
        view.show()
        view.set_headers_visible(False)
        scrolled_window.set_policy(Gtk.PolicyType.NEVER,
                                   Gtk.PolicyType.AUTOMATIC)
        scrolled_window.add(view)
        model = Gtk.ListStore(int, str, str, str)

        model.append(
            row=[self.TYPE_ALL, Icons.FOLDER, "__all",
                 _("All Stations")])
        model.append(row=[self.TYPE_SEP, Icons.FOLDER, "", ""])
        #Translators: Favorite radio stations
        model.append(
            row=[self.TYPE_FAV, Icons.FOLDER, "__fav",
                 _("Favorites")])
        model.append(row=[self.TYPE_SEP, Icons.FOLDER, "", ""])

        filters = self.filters
        for text, k in sorted([(filters.text(k), k) for k in filters.keys()]):
            model.append(row=[self.TYPE_FILTER, Icons.EDIT_FIND, k, text])

        model.append(
            row=[self.TYPE_NOCAT, Icons.FOLDER, "nocat",
                 _("No Category")])

        def separator(model, iter, data):
            return model[iter][self.TYPE] == self.TYPE_SEP

        view.set_row_separator_func(separator, None)

        def search_func(model, column, key, iter, data):
            return key.lower() not in model[iter][column].lower()

        view.set_search_column(self.NAME)
        view.set_search_equal_func(search_func, None)

        column = Gtk.TreeViewColumn("genres")
        column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)

        renderpb = Gtk.CellRendererPixbuf()
        renderpb.props.xpad = 3
        column.pack_start(renderpb, False)
        column.add_attribute(renderpb, "icon-name", self.ICON_NAME)

        render = Gtk.CellRendererText()
        render.set_property('ellipsize', Pango.EllipsizeMode.END)
        view.append_column(column)
        column.pack_start(render, True)
        column.add_attribute(render, "text", self.NAME)

        view.set_model(model)

        # selection
        selection = view.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.__changed_sig = connect_destroy(
            selection, 'changed',
            util.DeferredSignal(lambda x: self.activate()))

        box = Gtk.HBox(spacing=6)
        box.pack_start(search, True, True, 0)
        box.pack_start(button, False, True, 0)
        self._searchbox = Align(box, left=0, right=6, top=6)
        self._searchbox.show_all()

        def qbar_response(infobar, response_id):
            if response_id == infobar.RESPONSE_LOAD:
                self.__update()

        self.qbar = QuestionBar()
        self.qbar.connect("response", qbar_response)
        if self._is_library_empty():
            self.qbar.show()

        pane = qltk.ConfigRHPaned("browsers", "internetradio_pos", 0.4)
        pane.show()
        pane.pack1(scrolled_window, resize=False, shrink=False)
        songbox = Gtk.VBox(spacing=6)
        songbox.pack_start(self._searchbox, False, True, 0)
        self._songpane_container = Gtk.VBox()
        self._songpane_container.show()
        songbox.pack_start(self._songpane_container, True, True, 0)
        songbox.pack_start(self.qbar, False, True, 0)
        songbox.show()
        pane.pack2(songbox, resize=True, shrink=False)
        self.pack_start(pane, True, True, 0)
        self.show()
Exemple #22
0
    def __init__(self, library):
        super(PlaylistsBrowser, self).__init__(spacing=6)
        self.__view = view = RCMHintedTreeView()
        self.__view.set_enable_search(True)
        self.__view.set_search_column(0)
        self.__view.set_search_equal_func(
            lambda model, col, key, iter, data: not model[iter][col].name.
            lower().startswith(key.lower()), None)
        self.__render = render = Gtk.CellRendererText()
        render.set_property('ellipsize', Pango.EllipsizeMode.END)
        render.connect('editing-started', self.__start_editing)
        render.connect('edited', self.__edited)
        col = Gtk.TreeViewColumn("Playlists", render)
        col.set_cell_data_func(render, PlaylistsBrowser.cell_data)
        view.append_column(col)
        view.set_model(self.__lists)
        view.set_rules_hint(True)
        view.set_headers_visible(False)
        swin = ScrolledWindow()
        swin.set_shadow_type(Gtk.ShadowType.IN)
        swin.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        swin.add(view)
        self.pack_start(swin, True, True, 0)

        newpl = qltk.Button(_("_New"), Gtk.STOCK_NEW, Gtk.IconSize.MENU)
        newpl.connect('clicked', self.__new_playlist)

        importpl = qltk.Button(_("_Import"), Gtk.STOCK_ADD, Gtk.IconSize.MENU)
        importpl.connect('clicked', self.__import, library)
        hb = Gtk.HBox(spacing=6)
        hb.set_homogeneous(True)
        hb.pack_start(newpl, True, True, 0)
        hb.pack_start(importpl, True, True, 0)
        self.pack_start(Align(hb, left=3, bottom=3), False, True, 0)

        view.connect('popup-menu', self.__popup_menu, library)

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

        view.drag_dest_set(Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY)
        view.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, targets[:2],
                             Gdk.DragAction.COPY)
        view.connect('drag-data-received', self.__drag_data_received, library)
        view.connect('drag-data-get', self.__drag_data_get)
        view.connect('drag-motion', self.__drag_motion)
        view.connect('drag-leave', self.__drag_leave)

        view.connect('row-activated', lambda *x: self.songs_activated())

        view.get_selection().connect('changed', self.activate)

        s = view.get_model().connect('row-changed', self.__check_current)
        connect_obj(self, 'destroy', view.get_model().disconnect, s)

        self.connect('key-press-event', self.__key_pressed)

        for child in self.get_children():
            child.show_all()
Exemple #23
0
    def __init__(self, library):
        super(CollectionBrowser, self).__init__(spacing=6)
        self.set_orientation(Gtk.Orientation.VERTICAL)

        self._register_instance()
        if self.__model is None:
            self._init_model(library)

        sw = ScrolledWindow()
        sw.set_shadow_type(Gtk.ShadowType.IN)
        self.view = view = CollectionView()
        view.set_headers_visible(False)
        model_sort = CollectionSortModel(model=self.__model)
        model_filter = CollectionFilterModel(child_model=model_sort)
        self.__filter = None
        self.__bg_filter = background_filter()
        model_filter.set_visible_func(self.__parse_query)
        view.set_model(model_filter)

        def sort(model, i1, i2, data):
            t1, t2 = model[i1][0], model[i2][0]
            if t1 is None or t2 is None:
                # FIXME: why?
                return 0

            # FIXME: order this deterministically
            if t1 is MultiNode or t1 is UnknownNode or \
                    t2 is MultiNode or t2 is UnknownNode:
                return -cmp(t1, t2)

            if not isinstance(t1, Album):
                return cmp(util.human_sort_key(t1), util.human_sort_key(t2))

            a1, a2 = t1, t2
            return (cmp(a1.peoplesort and a1.peoplesort[0],
                        a2.peoplesort and a2.peoplesort[0]) or
                        cmp(a1.date or "ZZZZ", a2.date or "ZZZZ") or
                        cmp((a1.sort, a1.key), (a2.sort, a2.key)))

        model_sort.set_sort_func(0, sort)
        model_sort.set_sort_column_id(0, Gtk.SortType.ASCENDING)

        column = Gtk.TreeViewColumn("albums")

        def cell_data(column, cell, model, iter_, data):
            markup = model.get_markup(self.__model.tags, iter_)
            cell.markup = markup
            cell.set_property('markup', markup)

        def get_scaled_cover(album):
            # XXX: Cache this somewhere else
            cover = None
            if not hasattr(album, "_scaled_cover"):
                scale_factor = self.get_scale_factor()
                album.scan_cover(scale_factor=scale_factor)
                if album.cover:
                    s = 25 * scale_factor
                    cover = scale(album.cover, (s, s))
                    album._scaled_cover = cover
            else:
                cover = album._scaled_cover
            return cover

        def cell_data_pb(column, cell, model, iter_, data):
            album = model.get_album(iter_)
            if album is None:
                cell.set_property('icon-name', Icons.FOLDER)
            else:
                cover = get_scaled_cover(album)
                if cover:
                    cover = add_border_widget(cover, view)
                    surface = get_surface_for_pixbuf(self, cover)
                    cell.set_property("surface", surface)
                else:
                    cell.set_property('icon-name', Icons.MEDIA_OPTICAL)

        imgrender = Gtk.CellRendererPixbuf()
        render = Gtk.CellRendererText()
        if view.supports_hints():
            render.set_property('ellipsize', Pango.EllipsizeMode.END)
        column.pack_start(imgrender, False)
        column.pack_start(render, True)
        column.set_cell_data_func(render, cell_data)
        column.set_cell_data_func(imgrender, cell_data_pb)
        view.append_column(column)

        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.add(view)

        hbox = Gtk.HBox(spacing=6)

        prefs = Gtk.Button()
        prefs.add(SymbolicIconImage(Icons.EMBLEM_SYSTEM, Gtk.IconSize.MENU))
        prefs.connect('clicked', lambda *x: Preferences(self))

        search = SearchBarBox(completion=AlbumTagCompletion(),
                              accel_group=self.accelerators)

        search.connect('query-changed', self.__update_filter)
        self.__search = search

        hbox.pack_start(search, True, True, 0)
        hbox.pack_start(prefs, False, True, 0)

        self.pack_start(Align(hbox, left=6, top=6), False, True, 0)
        self.pack_start(sw, True, True, 0)

        view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        self.__sig = view.get_selection().connect('changed',
            self.__selection_changed)
        view.connect('row-activated', self.__play)
        connect_obj(view, 'popup-menu', self.__popup, view, library)

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

        view.drag_source_set(
            Gdk.ModifierType.BUTTON1_MASK, targets, Gdk.DragAction.COPY)
        view.connect("drag-data-get", self.__drag_data_get)

        self.connect("destroy", self.__destroy)

        self.show_all()
Exemple #24
0
    def __init__(self, parent=None):
        if self.is_not_unique():
            return
        super(PluginWindow, self).__init__()
        self.set_title(_("Plugins"))
        self.set_default_size(700, 500)
        self.set_transient_for(parent)
        self.enable_window_tracking("plugin_prefs")

        paned = Paned()
        vbox = Gtk.VBox()

        sw = ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)

        model = ObjectStore()
        filter_model = ObjectModelFilter(child_model=model)

        tv = PluginListView()
        tv.set_model(filter_model)
        tv.set_rules_hint(True)

        tv.connect("plugin-toggled", self.__plugin_toggled)

        fb = Gtk.HBox(spacing=6)

        filter_combo = PluginFilterCombo()
        filter_combo.connect("changed", lambda s: filter_model.refilter())
        fb.pack_start(filter_combo, False, True, 0)

        filter_entry = ClearEntry()
        filter_entry.connect("changed", lambda s: filter_model.refilter())
        filter_entry.enable_clear_button()
        fb.pack_start(filter_entry, True, True, 0)

        sw.add(tv)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        sw.set_size_request(200, -1)

        bbox = Gtk.HBox(homogeneous=True, spacing=12)

        errors = qltk.Button(_("Show _Errors"), Icons.DIALOG_WARNING)
        errors.set_focus_on_click(False)
        errors.connect('clicked', self.__show_errors)
        errors.set_no_show_all(True)
        bbox.pack_start(Align(errors, border=6, right=-6), True, True, 0)

        pref_box = PluginPreferencesContainer()

        if const.DEBUG:
            refresh = qltk.Button(_("_Refresh"), Icons.VIEW_REFRESH)
            refresh.set_focus_on_click(False)
            refresh.connect('clicked', self.__refresh, tv, pref_box, errors,
                            filter_combo)
            bbox.pack_start(Align(refresh, border=6), True, True, 0)

        vbox.pack_start(Align(fb, border=6, right=-6), False, True, 0)
        vbox.pack_start(sw, True, True, 0)
        vbox.pack_start(bbox, False, True, 0)
        paned.pack1(vbox, False, False)

        close = qltk.Button(_("_Close"), Icons.WINDOW_CLOSE)
        close.connect('clicked', lambda *x: self.destroy())
        bb_align = Align(halign=Gtk.Align.END, valign=Gtk.Align.END)
        bb = Gtk.HButtonBox()
        bb.set_layout(Gtk.ButtonBoxStyle.END)
        bb.pack_start(close, True, True, 0)
        bb_align.add(bb)

        selection = tv.get_selection()
        selection.connect('changed', self.__selection_changed, pref_box)
        selection.emit('changed')

        right_box = Gtk.VBox(spacing=12)
        right_box.pack_start(pref_box, True, True, 0)
        self.use_header_bar()
        if not self.has_close_button():
            right_box.pack_start(bb_align, True, True, 0)

        paned.pack2(Align(right_box, border=12), True, False)
        paned.set_position(250)

        self.add(paned)

        self.__refill(tv, pref_box, errors, filter_combo)

        self.connect('destroy', self.__destroy)
        filter_model.set_visible_func(self.__filter,
                                      (filter_entry, filter_combo))

        self.get_child().show_all()
        filter_entry.grab_focus()

        restore_id = config.get("memory", "plugin_selection")
        tv.select_by_plugin_id(restore_id)