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()
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()
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)
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)
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()
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()
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")
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()
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
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)
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()
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()
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()
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()
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)
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()
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()
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)
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)
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()
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()
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()
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()
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)