diff --git a/app/models.py b/app/models.py index 6a02ae9..efe6f45 100644 --- a/app/models.py +++ b/app/models.py @@ -249,6 +249,14 @@ class Playlists(Base): return playlist + def delete(self, session: scoped_session) -> None: + """ + Mark as deleted + """ + + self.deleted = True + session.flush() + @classmethod def get_all(cls, session: scoped_session) -> List["Playlists"]: """Returns a list of all playlists ordered by last use""" @@ -286,7 +294,8 @@ class Playlists(Base): select(cls) .filter( cls.tab.is_(None), - cls.is_template.is_(False) + cls.is_template.is_(False), + cls.deleted.is_(False) ) .order_by(cls.last_used.desc()) ) @@ -336,6 +345,14 @@ class Playlists(Base): row_to.tab = frm row_frm.tab = to + def rename(self, session: scoped_session, new_name: str) -> None: + """ + Rename playlist + """ + + self.name = new_name + session.flush() + @staticmethod def save_as_template(session: scoped_session, playlist_id: int, template_name: str) -> None: diff --git a/app/musicmuster.py b/app/musicmuster.py index f77ea54..21692fb 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -491,17 +491,19 @@ class Window(QMainWindow, Ui_MainWindow): event.accept() - def close_playlist_tab(self) -> None: + def close_playlist_tab(self) -> bool: """ Close active playlist tab, called by menu item """ - self.close_tab(self.tabPlaylist.currentIndex()) + return self.close_tab(self.tabPlaylist.currentIndex()) - def close_tab(self, tab_index: int) -> None: + def close_tab(self, tab_index: int) -> bool: """ Close playlist tab unless it holds the current or next track. Called from close_playlist_tab() or by clicking close button on tab. + + Return True if tab closed else False. """ # Don't close current track playlist @@ -509,13 +511,13 @@ class Window(QMainWindow, Ui_MainWindow): self.current_track.playlist_tab): self.statusbar.showMessage( "Can't close current track playlist", 5000) - return + return False # Don't close next track playlist if self.tabPlaylist.widget(tab_index) == self.next_track.playlist_tab: self.statusbar.showMessage( "Can't close next track playlist", 5000) - return + return False # Record playlist as closed and update remaining playlist tabs with Session() as session: @@ -528,11 +530,14 @@ class Window(QMainWindow, Ui_MainWindow): self.tabPlaylist.widget(tab_index).close() self.tabPlaylist.removeTab(tab_index) + return True + def connect_signals_slots(self) -> None: self.action_About.triggered.connect(self.about) self.action_Clear_selection.triggered.connect(self.clear_selection) self.actionDebug.triggered.connect(self.debug) self.actionClosePlaylist.triggered.connect(self.close_playlist_tab) + self.actionDeletePlaylist.triggered.connect(self.delete_playlist) self.actionDownload_CSV_of_played_tracks.triggered.connect( self.download_played_tracks) self.actionEnable_controls.triggered.connect( @@ -553,6 +558,7 @@ class Window(QMainWindow, Ui_MainWindow): self.actionOpenPlaylist.triggered.connect(self.open_playlist) self.actionPaste.triggered.connect(self.paste_rows) self.actionPlay_next.triggered.connect(self.play_next) + self.actionRenamePlaylist.triggered.connect(self.rename_playlist) self.actionResume.triggered.connect(self.resume) self.actionSave_as_template.triggered.connect(self.save_as_template) self.actionSearch.triggered.connect(self.search_playlist) @@ -630,6 +636,22 @@ class Window(QMainWindow, Ui_MainWindow): import ipdb # type: ignore ipdb.set_trace() + def delete_playlist(self) -> None: + """ + Delete current playlist + """ + + with Session() as session: + playlist_id = self.visible_playlist_tab().playlist_id + playlist = session.get(Playlists, playlist_id) + if playlist: + if helpers.ask_yes_no("Delete playlist", + f"Delete playlist '{playlist.name}': " + "Are you sure?" + ): + if self.close_playlist_tab(): + playlist.delete(session) + def disable_play_next_controls(self) -> None: """ Disable "play next" keyboard controls @@ -1253,6 +1275,21 @@ class Window(QMainWindow, Ui_MainWindow): self.current_track.end_time.strftime( Config.TRACK_TIME_FORMAT)) + def rename_playlist(self) -> None: + """ + Rename current playlist + """ + + with Session() as session: + playlist_id = self.visible_playlist_tab().playlist_id + playlist = session.get(Playlists, playlist_id) + if playlist: + new_name = self.solicit_playlist_name(playlist.name) + if new_name: + playlist.rename(session, new_name) + idx = self.tabBar.currentIndex() + self.tabBar.setTabText(idx, new_name) + def resume(self) -> None: """ Resume playing stopped track @@ -1400,12 +1437,15 @@ class Window(QMainWindow, Ui_MainWindow): self.tabPlaylist.setCurrentWidget(self.next_track.playlist_tab) self.tabPlaylist.currentWidget().scroll_next_to_top() - def solicit_playlist_name(self) -> Optional[str]: + def solicit_playlist_name(self, + default: Optional[str] = "") -> Optional[str]: """Get name of playlist from user""" dlg = QInputDialog(self) dlg.setInputMode(QInputDialog.TextInput) dlg.setLabelText("Playlist name:") + if default: + dlg.setTextValue(default) dlg.resize(500, 100) ok = dlg.exec() if ok: diff --git a/app/ui/main_window.ui b/app/ui/main_window.ui index 9e2c7b5..3e510bd 100644 --- a/app/ui/main_window.ui +++ b/app/ui/main_window.ui @@ -831,18 +831,17 @@ padding-left: 8px; &Playlists + - - - - + + @@ -1036,7 +1035,7 @@ padding-left: 8px; - false + true &Rename... @@ -1044,7 +1043,7 @@ padding-left: 8px; - false + true Dele&te... diff --git a/app/ui/main_window_ui.py b/app/ui/main_window_ui.py index 7338d49..ae265cd 100644 --- a/app/ui/main_window_ui.py +++ b/app/ui/main_window_ui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'app/ui/main_window.ui' # -# Created by: PyQt5 UI code generator 5.15.6 +# Created by: PyQt5 UI code generator 5.15.9 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. @@ -452,10 +452,10 @@ class Ui_MainWindow(object): self.actionClosePlaylist.setEnabled(True) self.actionClosePlaylist.setObjectName("actionClosePlaylist") self.actionRenamePlaylist = QtWidgets.QAction(MainWindow) - self.actionRenamePlaylist.setEnabled(False) + self.actionRenamePlaylist.setEnabled(True) self.actionRenamePlaylist.setObjectName("actionRenamePlaylist") self.actionDeletePlaylist = QtWidgets.QAction(MainWindow) - self.actionDeletePlaylist.setEnabled(False) + self.actionDeletePlaylist.setEnabled(True) self.actionDeletePlaylist.setObjectName("actionDeletePlaylist") self.actionMoveSelected = QtWidgets.QAction(MainWindow) self.actionMoveSelected.setObjectName("actionMoveSelected") @@ -506,18 +506,17 @@ class Ui_MainWindow(object): self.actionResume = QtWidgets.QAction(MainWindow) self.actionResume.setObjectName("actionResume") self.menuFile.addAction(self.actionNewPlaylist) + self.menuFile.addAction(self.actionNew_from_template) self.menuFile.addAction(self.actionOpenPlaylist) self.menuFile.addAction(self.actionClosePlaylist) self.menuFile.addAction(self.actionRenamePlaylist) - self.menuFile.addAction(self.actionExport_playlist) self.menuFile.addAction(self.actionDeletePlaylist) - self.menuFile.addSeparator() - self.menuFile.addAction(self.actionNew_from_template) - self.menuFile.addAction(self.actionSave_as_template) + self.menuFile.addAction(self.actionExport_playlist) self.menuFile.addSeparator() self.menuFile.addAction(self.actionMoveSelected) self.menuFile.addAction(self.actionMoveUnplayed) self.menuFile.addAction(self.actionDownload_CSV_of_played_tracks) + self.menuFile.addAction(self.actionSave_as_template) self.menuFile.addSeparator() self.menuFile.addAction(self.actionE_xit) self.menuPlaylist.addSeparator()