Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
    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)
Beispiel #4
0
    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)
Beispiel #5
0
    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(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:
            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):
                    msg = ErrorMessage(self.plugin_window,
                                 _("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)