diff --git a/app/musicmuster.py b/app/musicmuster.py index 7d1a116..30540b7 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -145,9 +145,9 @@ class SignalMonitor: @dataclass class Current: - base_model: PlaylistModel | None = None - proxy_model: PlaylistProxyModel | None = None - playlist_id: int = 0 + base_model: PlaylistModel + proxy_model: PlaylistProxyModel + playlist_id: int selected_row_numbers: list[int] = field(default_factory=list) @@ -1211,7 +1211,7 @@ class Window(QMainWindow): self.disable_selection_timing = False self.catch_return_key = False self.importer: FileImporter | None = None - self.current = Current() + self.current: Current | None = None self.track_sequence = TrackSequence() self.signals = MusicMusterSignals() self.connect_signals_slots() @@ -1241,7 +1241,10 @@ class Window(QMainWindow): return # Don't allow window to close when a track is playing - if self.track_sequence.current and self.track_sequence.current.music.is_playing(): + if ( + self.track_sequence.current + and self.track_sequence.current.music.is_playing() + ): event.ignore() helpers.show_warning( self, "Track playing", "Can't close application while track is playing" @@ -1494,6 +1497,9 @@ class Window(QMainWindow): but unused. """ + if self.current is None: + return + playlist = ds.playlist_by_id(self.current.playlist_id) if playlist: if helpers.ask_yes_no( @@ -1518,6 +1524,9 @@ class Window(QMainWindow): def save_as_template(self, checked: bool = False) -> None: """Save current playlist as template""" + if self.current is None: + return + template_names = [a.name for a in ds.playlists_templates_all()] while True: @@ -1607,6 +1616,9 @@ class Window(QMainWindow): Show query dialog with query_id selected """ + if self.current is None: + return + # Keep a reference else it will be gc'd self.query_dialog = QueryDialog(self.current.playlist_id, query_id) self.query_dialog.exec() @@ -1747,6 +1759,9 @@ class Window(QMainWindow): # TODO should be able to have the model handle row depending on # how current_row_or_end is used + if self.current is None: + return 0 # hack, but should never be called without self.current set + if self.current.selected_row_numbers: return self.current.selected_row_numbers[0] if not self.current.base_model: @@ -1836,6 +1851,9 @@ class Window(QMainWindow): def export_playlist_tab(self, checked: bool = False) -> None: """Export the current playlist to an m3u file""" + if self.current is None: + return + playlist_id = self.current.playlist_id playlist = ds.playlist_by_id(playlist_id) @@ -1917,12 +1935,18 @@ class Window(QMainWindow): # We need to keep a reference to the FileImporter else it will be # garbage collected while import threads are still running + if self.current is None: + return + self.importer = FileImporter(self.current.base_model, self.current_row_or_end()) self.importer.start() def insert_header(self, checked: bool = False) -> None: """Show dialog box to enter header text and add to playlist""" + if self.current is None: + return + # Get header text dlg: QInputDialog = QInputDialog(self) dlg.setInputMode(QInputDialog.InputMode.TextInput) @@ -1941,6 +1965,9 @@ class Window(QMainWindow): def insert_track(self, checked: bool = False) -> None: """Show dialog box to select and add track from database""" + if self.current is None: + return + dlg = TrackInsertDialog(parent=self, playlist_id=self.current.playlist_id) dlg.exec() @@ -1986,6 +2013,9 @@ class Window(QMainWindow): Cut rows ready for pasting. """ + if self.current is None: + return + # Save the selected PlaylistRows items ready for a later # paste self.move_source = MoveSource( @@ -2000,7 +2030,7 @@ class Window(QMainWindow): Move passed playlist rows to another playlist """ - if not row_numbers: + if not row_numbers or self.current is None: return # Identify destination playlist @@ -2036,6 +2066,9 @@ class Window(QMainWindow): Move selected rows to another playlist """ + if self.current is None: + return + self.move_playlist_rows(self.current.selected_row_numbers) def move_unplayed(self, checked: bool = False) -> None: @@ -2043,6 +2076,9 @@ class Window(QMainWindow): Move unplayed rows to another playlist """ + if self.current is None: + return + unplayed_rows = self.current.base_model.get_unplayed_rows() if not unplayed_rows: return @@ -2078,7 +2114,7 @@ class Window(QMainWindow): 'checked' is a dummy parameter passed to us by the menu """ - if not self.move_source: + if not self.move_source or self.current is None: return to_playlist_model = self.current.base_model @@ -2254,6 +2290,9 @@ class Window(QMainWindow): def preview_mark(self) -> None: """Set intro time""" + if self.current is None: + return + if self.preview_manager.is_playing(): track_id = self.preview_manager.track_id row_number = self.preview_manager.row_number @@ -2295,6 +2334,9 @@ class Window(QMainWindow): Rename current playlist. checked is passed by menu but not used here """ + if self.current is None: + return + playlist = ds.playlist_by_id(self.current.playlist_id) if playlist: new_name = self.get_playlist_name(playlist.name) @@ -2412,6 +2454,9 @@ class Window(QMainWindow): Incremental search of playlist """ + if self.current is None: + return + self.current.proxy_model.set_incremental_search(self.txtSearch.text()) def selected_or_next_track_info(self) -> PlaylistRow | None: @@ -2420,6 +2465,9 @@ class Window(QMainWindow): next track. If no next track, return None. """ + if self.current is None: + return None + row_number: int | None = None if self.current.selected_row_numbers: @@ -2452,6 +2500,9 @@ class Window(QMainWindow): Set currently-selected row on visible playlist tab as next track """ + if self.current is None: + return + self.signals.signal_set_next_row.emit(self.current.playlist_id) self.clear_selection() @@ -2490,6 +2541,9 @@ class Window(QMainWindow): def show_track(self, playlist_track: PlaylistRow) -> None: """Scroll to show track""" + if self.current is None: + return + # Switch to the correct tab playlist_id = playlist_track.playlist_id if not playlist_id: @@ -2508,12 +2562,17 @@ class Window(QMainWindow): self._active_tab().scroll_to_top(playlist_track.row_number) - def signal_playlist_selected_rows_handler(self, selected_rows: SelectedRows) -> None: + def playlist_selected_rows_handler( + self, selected_rows: SelectedRows + ) -> None: """ Handle signal_playlist_selected_rows to keep track of which rows are selected in the current model """ + if self.current is None: + return + self.current.selected_row_numbers = selected_rows.rows def set_next_track_handler(self, plr: PlaylistRow) -> None: @@ -2624,7 +2683,10 @@ class Window(QMainWindow): """ # If track is playing, update track clocks time and colours - if self.track_sequence.current and self.track_sequence.current.music.is_playing(): + if ( + self.track_sequence.current + and self.track_sequence.current.music.is_playing() + ): # Elapsed time self.header_section.label_elapsed_timer.setText( helpers.ms_to_mmss(self.track_sequence.current.time_playing()) @@ -2679,6 +2741,24 @@ class Window(QMainWindow): helpers.ms_to_mmss(time_to_silence) ) + def update_current( + self, + base_model: PlaylistModel, + proxy_model: PlaylistProxyModel, + playlist_id: int, + selected_row_numbers: list[int] + ) -> None: + """ + Update self.current when playlist tab changes. Called by new playlist + """ + + self.current = Current( + base_model=base_model, + proxy_model=proxy_model, + playlist_id=playlist_id, + selected_row_numbers=selected_row_numbers + ) + def update_headers(self) -> None: """ Update last / current / next track headers diff --git a/app/playlists.py b/app/playlists.py index f354640..ce32c13 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -1130,12 +1130,14 @@ class PlaylistTab(QTableView): """ # Update musicmuster - self.musicmuster.current.playlist_id = self.playlist_id - self.musicmuster.current.selected_row_numbers = self.get_selected_rows() - self.musicmuster.current.base_model = self.get_base_model() - self.musicmuster.current.proxy_model = self.model() + self.musicmuster.update_current( + base_model=self.get_base_model(), + proxy_model=self.model(), + playlist_id=self.playlist_id, + selected_row_numbers=self.get_selected_rows(), + ) - self.resize_rows() + self.resize_rows_handler() def _unmark_as_next(self) -> None: """Rescan track"""