def _new_playlist_submenu_for(self, song): submenu = self._playlists_item.get_submenu() if submenu: submenu.destroy() playlist_menu = PlaylistMenu([song], PlaylistsBrowser.playlists()) def on_new(widget, playlist): PlaylistsBrowser.changed(playlist) playlist_menu.connect('new', on_new) self._playlists_item.set_submenu(playlist_menu) self._playlists_item.set_sensitive(bool(song) and song.can_add) self._playlists_item.show_all()
def _new_playlist_submenu_for(self, song): submenu = self._playlists_item.get_submenu() if submenu: submenu.destroy() playlist_menu = PlaylistMenu([song]) self._playlists_item.set_submenu(playlist_menu) self._playlists_item.set_sensitive(bool(song) and song.can_add) self._playlists_item.show_all()
def __init__(self, library, songs, plugins=True, playlists=True, queue=True, remove=True, delete=False, edit=True, ratings=True, show_files=True, items=None, accels=True, removal_confirmer=None): super().__init__() # The library may actually be a librarian; if it is, use it, # otherwise find the real librarian. librarian = getattr(library, 'librarian', library) if ratings: ratings_item = RatingsMenuItem(songs, librarian) ratings_item.set_sensitive(bool(songs)) self.append(ratings_item) self.separate() # external item groups for subitems in reversed(items or []): self.separate() for item in subitems: self.append(item) self.separate() if plugins: submenu = self.plugins.Menu(librarian, songs) if submenu is not None: b = qltk.MenuItem(_("_Plugins"), Icons.SYSTEM_RUN) b.set_sensitive(bool(songs)) self.append(b) b.set_submenu(submenu) self.append(SeparatorMenuItem()) in_lib = True can_add = True is_file = True for song in songs: if song not in library: in_lib = False if not song.can_add: can_add = False if not song.is_file: is_file = False if playlists: # Needed here to avoid a circular import; most browsers use # a SongsMenu, but SongsMenu needs access to the playlist # browser for this item. # FIXME: Two things are now importing browsers, so we need # some kind of inversion of control here. from quodlibet.browsers.playlists.menu import PlaylistMenu from quodlibet.browsers.playlists import PlaylistsBrowser try: submenu = PlaylistMenu(songs, PlaylistsBrowser.playlists()) def on_new(widget, playlist): PlaylistsBrowser.changed(playlist) submenu.connect('new', on_new) except AttributeError as e: print_w("Couldn't get Playlists menu: %s" % e) else: b = qltk.MenuItem(_("Play_lists"), Icons.FOLDER_DRAG_ACCEPT) b.set_sensitive(can_add and bool(songs)) b.set_submenu(submenu) self.append(b) if queue: b = qltk.MenuItem(_("Add to _Queue"), Icons.LIST_ADD) def enqueue_cb(item, songs): songs = [s for s in songs if s.can_add] if songs: from quodlibet import app app.window.playlist.enqueue(songs) b.connect('activate', enqueue_cb, songs) if accels: qltk.add_fake_accel(b, "<Primary>Return") self.append(b) b.set_sensitive(can_add and bool(songs)) if remove or delete: self.separate() if remove: self._confirm_song_removal = (removal_confirmer or confirm_song_removal_invoke) b = qltk.MenuItem(_("_Remove from Library…"), Icons.LIST_REMOVE) if callable(remove): b.connect('activate', lambda item: remove(songs)) else: def remove_cb(item, songs, library): parent = get_menu_item_top_parent(item) if self._confirm_song_removal(parent, songs): library.remove(songs) b.connect('activate', remove_cb, songs, library) b.set_sensitive(in_lib and bool(songs)) self.append(b) if delete: if callable(delete): b = qltk.MenuItem(_("_Delete"), Icons.EDIT_DELETE) b.connect('activate', lambda item: delete(songs)) if accels: qltk.add_fake_accel(b, "<Primary>Delete") else: b = TrashMenuItem() if accels: qltk.add_fake_accel(b, "<Primary>Delete") def trash_cb(item): parent = get_menu_item_top_parent(item) trash_songs(parent, songs, librarian) b.connect('activate', trash_cb) b.set_sensitive(is_file and bool(songs)) self.append(b) if edit: self.separate() b = qltk.MenuItem(_("Edit _Tags"), Icons.EDIT) b.set_sensitive(bool(songs)) if accels: qltk.add_fake_accel(b, "<alt>Return") def song_properties_cb(menu_item): parent = get_menu_item_top_parent(menu_item) window = SongProperties(librarian, songs, parent) window.show() b.connect('activate', song_properties_cb) self.append(b) b = qltk.MenuItem(_("_Information"), Icons.DIALOG_INFORMATION) b.set_sensitive(bool(songs)) if accels: qltk.add_fake_accel(b, "<Primary>I") def information_cb(menu_item): parent = get_menu_item_top_parent(menu_item) window = Information(librarian, songs, parent) window.show() b.connect('activate', information_cb) self.append(b) if show_files and any(is_a_file(s) for s in songs): def show_files_cb(menu_item): print_d("Trying to show files...") if not show_songs(songs): parent = get_menu_item_top_parent(menu_item) msg = ErrorMessage( parent, _("Unable to show files"), _("Error showing files, " "or no program available to show them.")) msg.run() self.separate() total = len([s for s in songs if is_a_file(s)]) text = ngettext("_Show in File Manager", "_Show %(total)d Files in File Manager", total) % { "total": total } b = qltk.MenuItem(text, Icons.DOCUMENT_OPEN) b.set_sensitive( bool(songs) and len(songs) < MenuItemPlugin.MAX_INVOCATIONS) b.connect('activate', show_files_cb) self.append(b) def selection_done_cb(menu): menu.destroy() self.connect('selection-done', selection_done_cb)
def __init__(self, library, songs, plugins=True, playlists=True, queue=True, devices=True, remove=True, delete=False, edit=True, parent=None): super(SongsMenu, self).__init__() # The library may actually be a librarian; if it is, use it, # otherwise find the real librarian. librarian = getattr(library, 'librarian', library) if plugins: submenu = self.plugins.Menu(librarian, parent, songs) if submenu is not None: b = qltk.MenuItem(_("_Plugins"), Gtk.STOCK_EXECUTE) self.append(b) b.set_submenu(submenu) self.append(SeparatorMenuItem()) in_lib = True can_add = True is_file = True for song in songs: if song not in library: in_lib = False if not song.can_add: can_add = False if not song.is_file: is_file = False self.separate() if playlists: # Needed here to avoid a circular import; most browsers use # a SongsMenu, but SongsMenu needs access to the playlist # browser for this item. # FIXME: Two things are now importing browsers, so we need # some kind of inversion of control here. from quodlibet.browsers.playlists.menu import PlaylistMenu try: submenu = PlaylistMenu(songs, parent) except AttributeError as e: print_w("Couldn't get Playlists menu: %s" % e) else: b = qltk.MenuItem(_("Play_lists"), Gtk.STOCK_ADD) b.set_sensitive(can_add) b.set_submenu(submenu) self.append(b) if queue: b = qltk.MenuItem(_("Add to _Queue"), Gtk.STOCK_ADD) b.connect('activate', self.__enqueue, songs) qltk.add_fake_accel(b, "<ctrl>Return") self.append(b) b.set_sensitive(can_add) if devices: from quodlibet import browsers try: browsers.media except AttributeError: pass else: if browsers.media.MediaDevices in browsers.browsers: submenu = browsers.media.Menu(songs, library) b = qltk.MenuItem(_("_Copy to Device"), Gtk.STOCK_COPY) b.set_sensitive(can_add and len(submenu) > 0) b.set_submenu(submenu) self.append(b) if remove or delete: self.separate() if remove: b = qltk.MenuItem(_("_Remove from library"), Gtk.STOCK_REMOVE) if callable(remove): b.connect_object('activate', remove, songs) else: b.connect('activate', self.__remove, songs, library) b.set_sensitive(in_lib) self.append(b) if delete: if callable(delete): b = Gtk.ImageMenuItem(Gtk.STOCK_DELETE, use_stock=True) b.connect_object('activate', delete, songs) else: b = TrashMenuItem() b.connect_object('activate', trash_songs, parent, songs, librarian) b.set_sensitive(is_file) self.append(b) if edit: self.separate() b = qltk.MenuItem(_("Edit _Tags"), Gtk.STOCK_PROPERTIES) qltk.add_fake_accel(b, "<alt>Return") def song_properties_cb(menu_item): window = SongProperties(librarian, songs, parent) window.show() b.connect('activate', song_properties_cb) self.append(b) b = Gtk.ImageMenuItem(label=Gtk.STOCK_INFO, use_stock=True) qltk.add_fake_accel(b, "<ctrl>I") def information_cb(menu_item): window = Information(librarian, songs, parent) window.show() b.connect('activate', information_cb) self.append(b) self.connect_object('selection-done', Gtk.Menu.destroy, self)
def __init__(self, library, songs, plugins=True, playlists=True, queue=True, remove=True, delete=False, edit=True, ratings=True, items=None, accels=True): super(SongsMenu, self).__init__() # The library may actually be a librarian; if it is, use it, # otherwise find the real librarian. librarian = getattr(library, 'librarian', library) if ratings: ratings_item = RatingsMenuItem(songs, librarian) ratings_item.set_sensitive(bool(songs)) self.append(ratings_item) self.separate() # external item groups for subitems in reversed(items or []): self.separate() for item in subitems: self.append(item) self.separate() if plugins: submenu = self.plugins.Menu(librarian, songs) if submenu is not None: b = qltk.MenuItem(_("_Plugins"), Icons.SYSTEM_RUN) b.set_sensitive(bool(songs)) self.append(b) b.set_submenu(submenu) self.append(SeparatorMenuItem()) in_lib = True can_add = True is_file = True for song in songs: if song not in library: in_lib = False if not song.can_add: can_add = False if not song.is_file: is_file = False if playlists: # Needed here to avoid a circular import; most browsers use # a SongsMenu, but SongsMenu needs access to the playlist # browser for this item. # FIXME: Two things are now importing browsers, so we need # some kind of inversion of control here. from quodlibet.browsers.playlists.menu import PlaylistMenu from quodlibet.browsers.playlists import PlaylistsBrowser try: submenu = PlaylistMenu(songs, PlaylistsBrowser.playlists()) def on_new(widget, playlist): PlaylistsBrowser.changed(playlist) submenu.connect('new', on_new) except AttributeError as e: print_w("Couldn't get Playlists menu: %s" % e) else: b = qltk.MenuItem(_("Play_lists"), Icons.FOLDER_DRAG_ACCEPT) b.set_sensitive(can_add and bool(songs)) b.set_submenu(submenu) self.append(b) if queue: b = qltk.MenuItem(_("Add to _Queue"), Icons.LIST_ADD) def enqueue_cb(item, songs): songs = [s for s in songs if s.can_add] if songs: from quodlibet import app app.window.playlist.enqueue(songs) b.connect('activate', enqueue_cb, songs) if accels: qltk.add_fake_accel(b, "<Primary>Return") self.append(b) b.set_sensitive(can_add and bool(songs)) if remove or delete: self.separate() if remove: b = qltk.MenuItem(_("_Remove from Library"), Icons.LIST_REMOVE) if callable(remove): b.connect('activate', lambda item: remove(songs)) else: def remove_cb(item, songs, library): library.remove(set(songs)) b.connect('activate', remove_cb, songs, library) b.set_sensitive(in_lib and bool(songs)) self.append(b) if delete: if callable(delete): b = qltk.MenuItem(_("_Delete"), Icons.EDIT_DELETE) b.connect('activate', lambda item: delete(songs)) if accels: qltk.add_fake_accel(b, "<Primary>Delete") else: b = TrashMenuItem() if accels: qltk.add_fake_accel(b, "<Primary>Delete") def trash_cb(item): parent = get_menu_item_top_parent(item) trash_songs(parent, songs, librarian) b.connect('activate', trash_cb) b.set_sensitive(is_file and bool(songs)) self.append(b) if edit: self.separate() b = qltk.MenuItem(_("Edit _Tags"), Icons.EDIT) b.set_sensitive(bool(songs)) if accels: qltk.add_fake_accel(b, "<alt>Return") def song_properties_cb(menu_item): parent = get_menu_item_top_parent(menu_item) window = SongProperties(librarian, songs, parent) window.show() b.connect('activate', song_properties_cb) self.append(b) b = qltk.MenuItem(_("_Information"), Icons.DIALOG_INFORMATION) b.set_sensitive(bool(songs)) if accels: qltk.add_fake_accel(b, "<Primary>I") def information_cb(menu_item): parent = get_menu_item_top_parent(menu_item) window = Information(librarian, songs, parent) window.show() b.connect('activate', information_cb) self.append(b) def selection_done_cb(menu): menu.destroy() self.connect('selection-done', selection_done_cb)
def __init__(self, library, songs, plugins=True, playlists=True, queue=True, devices=True, remove=True, delete=False, edit=True, ratings=True, items=None, accels=True): super(SongsMenu, self).__init__() # The library may actually be a librarian; if it is, use it, # otherwise find the real librarian. librarian = getattr(library, 'librarian', library) if ratings: ratings_item = RatingsMenuItem(songs, librarian) ratings_item.set_sensitive(bool(songs)) self.append(ratings_item) self.separate() # external item groups for subitems in reversed(items or []): self.separate() for item in subitems: self.append(item) self.separate() if plugins: submenu = self.plugins.Menu(librarian, songs) if submenu is not None: b = qltk.MenuItem(_("_Plugins"), Icons.SYSTEM_RUN) b.set_sensitive(bool(songs)) self.append(b) b.set_submenu(submenu) self.append(SeparatorMenuItem()) in_lib = True can_add = True is_file = True for song in songs: if song not in library: in_lib = False if not song.can_add: can_add = False if not song.is_file: is_file = False if playlists: # Needed here to avoid a circular import; most browsers use # a SongsMenu, but SongsMenu needs access to the playlist # browser for this item. # FIXME: Two things are now importing browsers, so we need # some kind of inversion of control here. from quodlibet.browsers.playlists.menu import PlaylistMenu try: submenu = PlaylistMenu(songs) except AttributeError as e: print_w("Couldn't get Playlists menu: %s" % e) else: b = qltk.MenuItem(_("Play_lists"), Icons.LIST_ADD) b.set_sensitive(can_add and bool(songs)) b.set_submenu(submenu) self.append(b) if queue: b = qltk.MenuItem(_("Add to _Queue"), Icons.LIST_ADD) def enqueue_cb(item, songs): songs = filter(lambda s: s.can_add, songs) if songs: from quodlibet import app app.window.playlist.enqueue(songs) b.connect('activate', enqueue_cb, songs) if accels: qltk.add_fake_accel(b, "<Primary>Return") self.append(b) b.set_sensitive(can_add and bool(songs)) if devices: from quodlibet import browsers try: browsers.media except AttributeError: pass else: if browsers.media.MediaDevices in browsers.browsers: submenu = browsers.media.Menu(songs, library) b = qltk.MenuItem(_("_Copy to Device"), Icons.EDIT_COPY) b.set_sensitive(can_add and len(submenu) > 0 and bool(songs)) b.set_submenu(submenu) self.append(b) if remove or delete: self.separate() if remove: b = qltk.MenuItem(_("_Remove from Library"), Icons.LIST_REMOVE) if callable(remove): b.connect('activate', lambda item: remove(songs)) else: def remove_cb(item, songs, library): library.remove(set(songs)) b.connect('activate', remove_cb, songs, library) b.set_sensitive(in_lib and bool(songs)) self.append(b) if delete: if callable(delete): b = qltk.MenuItem(_("_Delete"), Icons.EDIT_DELETE) b.connect('activate', lambda item: delete(songs)) if accels: qltk.add_fake_accel(b, "<Primary>Delete") else: b = TrashMenuItem() if accels: qltk.add_fake_accel(b, "<Primary>Delete") def trash_cb(item): parent = get_menu_item_top_parent(item) trash_songs(parent, songs, librarian) b.connect('activate', trash_cb) b.set_sensitive(is_file and bool(songs)) self.append(b) if edit: self.separate() b = qltk.MenuItem(_("Edit _Tags"), Icons.DOCUMENT_PROPERTIES) b.set_sensitive(bool(songs)) if accels: qltk.add_fake_accel(b, "<alt>Return") def song_properties_cb(menu_item): parent = get_menu_item_top_parent(menu_item) window = SongProperties(librarian, songs, parent) window.show() b.connect('activate', song_properties_cb) self.append(b) b = qltk.MenuItem(_("_Information"), Icons.DIALOG_INFORMATION) b.set_sensitive(bool(songs)) if accels: qltk.add_fake_accel(b, "<Primary>I") def information_cb(menu_item): parent = get_menu_item_top_parent(menu_item) window = Information(librarian, songs, parent) window.show() b.connect('activate', information_cb) self.append(b) def selection_done_cb(menu): menu.destroy() self.connect('selection-done', selection_done_cb)
def __init__(self, library, songs, plugins=True, playlists=True, queue=True, remove=True, delete=False, edit=True, ratings=True, show_files=True, download=False, items=None, accels=True, removal_confirmer=None, folder_chooser=None): super().__init__() # The library may actually be a librarian; if it is, use it, # otherwise find the real librarian. librarian = getattr(library, 'librarian', library) if ratings: ratings_item = RatingsMenuItem(songs, librarian) ratings_item.set_sensitive(bool(songs)) self.append(ratings_item) self.separate() # external item groups for subitems in reversed(items or []): self.separate() for item in subitems: self.append(item) self.separate() if plugins: submenu = self.plugins.Menu(librarian, songs) if submenu is not None: b = qltk.MenuItem(_("_Plugins"), Icons.SYSTEM_RUN) b.set_sensitive(bool(songs)) self.append(b) b.set_submenu(submenu) self.append(SeparatorMenuItem()) in_lib = True can_add = True is_file = True for song in songs: if song not in library: in_lib = False if not song.can_add: can_add = False if not song.is_file: is_file = False if playlists: try: from quodlibet.browsers.playlists.menu import PlaylistMenu submenu = PlaylistMenu(songs, library.playlists) except AttributeError as e: print_w("Couldn't get Playlists menu: %s" % e) else: b = qltk.MenuItem(_("Play_lists"), Icons.FOLDER_DRAG_ACCEPT) b.set_sensitive(can_add and bool(songs)) b.set_submenu(submenu) self.append(b) if queue: b = qltk.MenuItem(_("Add to _Queue"), Icons.LIST_ADD) def enqueue_cb(item, songs): songs = [s for s in songs if s.can_add] if songs: from quodlibet import app app.window.playlist.enqueue(songs) b.connect('activate', enqueue_cb, songs) if accels: qltk.add_fake_accel(b, "<Primary>Return") self.append(b) b.set_sensitive(can_add and bool(songs)) if remove or delete: self.separate() if remove: self._confirm_song_removal = (removal_confirmer or confirm_song_removal_invoke) b = qltk.MenuItem(_("_Remove from Library…"), Icons.LIST_REMOVE) if callable(remove): b.connect('activate', lambda item: remove(songs)) else: def remove_cb(item, songs, library): parent = get_menu_item_top_parent(item) if self._confirm_song_removal(parent, songs): library.remove(songs) b.connect('activate', remove_cb, songs, library) b.set_sensitive(in_lib and bool(songs)) self.append(b) if delete: if callable(delete): b = qltk.MenuItem(_("_Delete"), Icons.EDIT_DELETE) b.connect('activate', lambda item: delete(songs)) if accels: qltk.add_fake_accel(b, "<Primary>Delete") else: b = TrashMenuItem() if accels: qltk.add_fake_accel(b, "<Primary>Delete") def trash_cb(item): parent = get_menu_item_top_parent(item) trash_songs(parent, songs, librarian) b.connect('activate', trash_cb) b.set_sensitive(is_file and bool(songs)) self.append(b) if edit: self.separate() b = qltk.MenuItem(_("Edit _Tags"), Icons.EDIT) b.set_sensitive(bool(songs)) if accels: qltk.add_fake_accel(b, "<alt>Return") def song_properties_cb(menu_item): parent = get_menu_item_top_parent(menu_item) window = SongProperties(librarian, songs, parent) window.show() b.connect('activate', song_properties_cb) self.append(b) b = qltk.MenuItem(_("_Information"), Icons.DIALOG_INFORMATION) b.set_sensitive(bool(songs)) if accels: qltk.add_fake_accel(b, "<Primary>I") def information_cb(menu_item): parent = get_menu_item_top_parent(menu_item) window = Information(librarian, songs, parent) window.show() b.connect('activate', information_cb) self.append(b) if show_files and any(is_a_file(s) for s in songs): def show_files_cb(menu_item): print_d("Trying to show files...") if not show_songs(songs): parent = get_menu_item_top_parent(menu_item) msg = ErrorMessage( parent, _("Unable to show files"), _("Error showing files, " "or no program available to show them.")) msg.run() self.separate() total = len([s for s in songs if is_a_file(s)]) text = ngettext("_Show in File Manager", "_Show %(total)d Files in File Manager", total) % { "total": total } b = qltk.MenuItem(text, Icons.DOCUMENT_OPEN) b.set_sensitive( bool(songs) and len(songs) < MenuItemPlugin.MAX_INVOCATIONS) b.connect('activate', show_files_cb) self.append(b) if download: def is_downloadable(song: AudioFile): return bool(not song.is_file and song.get("~uri", False)) self.separate() relevant = [s for s in songs if is_downloadable(s)] total = len(relevant) text = ngettext("_Download file…", "_Download %(total)d files…", total) % { "total": total } b = qltk.MenuItem(text, Icons.EMBLEM_DOWNLOADS) b.set_sensitive(relevant and len(relevant) < MenuItemPlugin.MAX_INVOCATIONS) def _finished(p, successes, failures): msg = (f"<b>{successes}</b> " + _("successful") + f"\n<b>{failures}</b> " + _("failed")) print_d(msg.replace("\n", "; ")) warning = Message(Gtk.MessageType.INFO, app.window, _("Downloads complete"), msg, escape_desc=False) warning.run() def download_cb(menu_item): songs = relevant total = len(songs) msg = ngettext("Download {name!r} to", "Download {total} files to", total) msg = msg.format( name=next(iter(songs))("title")[:99] if total else "?", total=total) chooser = folder_chooser or choose_folders paths = chooser(None, msg, _("Download here"), allow_multiple=False) if not paths: print_d("Cancelling download") return path = paths[0] progress = DownloadProgress(songs) progress.connect('finished', _finished) copool.add(progress.download_songs, path) b.connect('activate', download_cb) self.append(b) def selection_done_cb(menu): menu.destroy() self.connect('selection-done', selection_done_cb)