From 80e698680bba0438c88672a996baccbd299a03a5 Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Sun, 12 Mar 2023 09:53:11 +0000 Subject: [PATCH] Clean up header and note updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • rationalise number of functions • make colour handling cleaner • optimise when playlist is saved --- app/models.py | 6 +- app/musicmuster.py | 6 +- app/playlists.py | 175 +++++++++++++++++++++------------------------ 3 files changed, 86 insertions(+), 101 deletions(-) diff --git a/app/models.py b/app/models.py index 7191428..c0f1396 100644 --- a/app/models.py +++ b/app/models.py @@ -98,13 +98,13 @@ class NoteColours(Base): ) @staticmethod - def get_colour(session: scoped_session, text: str) -> str: + def get_colour(session: scoped_session, text: str) -> Optional[str]: """ Parse text and return colour string if matched, else empty string """ if not text: - return "" + return None for rec in session.execute( select(NoteColours) @@ -126,7 +126,7 @@ class NoteColours(Base): if rec.substring.lower() in text.lower(): return rec.colour - return "" + return None class Playdates(Base): diff --git a/app/musicmuster.py b/app/musicmuster.py index ce84388..2149f8a 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -1518,9 +1518,9 @@ class Window(QMainWindow, Ui_MainWindow): # May also be called when last tab is closed pass - def this_is_the_next_playlist_row(self, session: scoped_session, - plr: PlaylistRows, - next_track_playlist_tab: PlaylistTab) -> None: + def this_is_the_next_playlist_row( + self, session: scoped_session, plr: PlaylistRows, + next_track_playlist_tab: PlaylistTab) -> None: """ This is notification from a playlist tab that it holds the next playlist row to be played. diff --git a/app/playlists.py b/app/playlists.py index e65cb64..4a3f89e 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -198,7 +198,6 @@ class PlaylistTab(QTableWidget): # Connect signals self.horizontalHeader().sectionResized.connect(self._column_resize) self.signals.save_playlist_signal.connect(self._deferred_save) - self.signals.update_row_note_signal.connect(self._update_row_note) # Load playlist rows self.populate_display(session, self.playlist_id) @@ -332,10 +331,11 @@ class PlaylistTab(QTableWidget): if self.edit_cell_type == ROW_NOTES: plr_item.note = new_text - session.flush() - self.signals.update_row_note_signal.emit(row) + if track_id: + self._set_row_note_text(session, row, new_text) + else: + self._set_row_header_text(session, row, new_text) else: - track = None if track_id: track = session.get(Tracks, track_id) if track: @@ -517,9 +517,7 @@ class PlaylistTab(QTableWidget): row_number = self.get_new_row_number() plr = PlaylistRows(session, self.playlist_id, None, row_number, note) self.insert_row(session, plr) - self._set_row_note_colour(session, row_number, note, - section_header=True) - self.save_playlist(session) + self._set_row_header_text(session, row_number, note) def insert_row(self, session: scoped_session, plr: PlaylistRows, update_track_times: bool = True, played=False) -> None: @@ -539,7 +537,7 @@ class PlaylistTab(QTableWidget): _ = self._set_row_userdata(row, self.PLAYED, True) if plr.note is None: plr.note = "" - self._set_row_note_colour(session, row, plr.note) + self._set_row_note_text(session, row, plr.note) else: # This is a section header so it must have note text if plr.note is None: @@ -548,13 +546,9 @@ class PlaylistTab(QTableWidget): ) return - # In order to colour the row, we need items in every column - for i in range(1, len(columns)): - self._set_item_text(row, i, None) - + # Use one QTableWidgetItem to span all columns from column 1 + self._set_row_header_text(session, row, plr.note) self.setSpan(row, HEADER_NOTES_COLUMN, 1, len(columns) - 1) - _ = self._set_row_note_colour(session, row, plr.note, - section_header=True) # Save (or clear) track_id _ = self._set_row_track_id(row, 0) @@ -562,8 +556,12 @@ class PlaylistTab(QTableWidget): # Set bold as needed self._set_row_bold(row, bold) + self.save_playlist(session) + if update_track_times: - self._update_start_end_times() + # Queue up time calculations to take place after UI has + # updated + QTimer.singleShot(0, self._update_start_end_times) def insert_track(self, session: scoped_session, track: Tracks, note: str = "", repaint: bool = True) -> None: @@ -603,7 +601,6 @@ class PlaylistTab(QTableWidget): plr = PlaylistRows(session, self.playlist_id, track.id, row_number, note) self.insert_row(session, plr) - self.save_playlist(session) def play_ended(self) -> None: """ @@ -889,7 +886,7 @@ class PlaylistTab(QTableWidget): # Update attributes of row self._set_row_bold(row) self._set_row_colour_default(plr.row_number) - _ = self._set_row_note_colour(session, row, plr.note) + self._set_row_header_text(session, row, plr.note) self._update_row_track_info(session, row, track) self._update_start_end_times() self.clear_selection() @@ -1504,10 +1501,7 @@ class PlaylistTab(QTableWidget): # Span the rows self.setSpan(row, HEADER_NOTES_COLUMN, 1, len(columns) - 1) # Set note text in correct column for section head - _ = self._set_item_text(row, HEADER_NOTES_COLUMN, plr.note) - - _ = self._set_row_note_colour(session, row, plr.note, - section_header=True) + self._set_row_header_text(session, row, plr.note) self.clear_selection() # Set track start/end times after track list is populated @@ -1532,7 +1526,7 @@ class PlaylistTab(QTableWidget): note_text = "" else: note_text += f"{track_id=} not found" - self._set_row_note_colour(session, row, note_text) + self._set_row_header_text(session, row, note_text) log.error( f"playlists._rescan({track_id=}): " "Track not found" @@ -1667,15 +1661,15 @@ class PlaylistTab(QTableWidget): self.musicmuster.lblSumPlaytime.setText("") def _set_cell_colour(self, row: int, column: int, - colour: Optional[QColor] = None) -> None: + colour: Optional[str] = None) -> None: """ Set or reset a cell background colour """ - if colour: - brush = QBrush(colour) - else: + if colour is None: brush = QBrush() + else: + brush = QBrush(QColor(colour)) item = self.item(row, column) if item: @@ -1829,15 +1823,15 @@ class PlaylistTab(QTableWidget): item.setFont(boldfont) def _set_row_colour(self, row: int, - colour: Optional[QColor] = None) -> None: + colour: Optional[str] = None) -> None: """ Set or reset row background colour """ - if colour: - brush = QBrush(colour) - else: + if colour is None: brush = QBrush() + else: + brush = QBrush(QColor(colour)) for column in range(1, self.columnCount()): if column in [START_GAP, BITRATE]: @@ -1851,7 +1845,7 @@ class PlaylistTab(QTableWidget): Set current track row colour """ - self._set_row_colour(row, QColor(Config.COLOUR_CURRENT_PLAYLIST)) + self._set_row_colour(row, Config.COLOUR_CURRENT_PLAYLIST) def _set_row_colour_default(self, row: int) -> None: """ @@ -1865,14 +1859,14 @@ class PlaylistTab(QTableWidget): Set next track row colour """ - self._set_row_colour(row, QColor(Config.COLOUR_NEXT_PLAYLIST)) + self._set_row_colour(row, Config.COLOUR_NEXT_PLAYLIST) def _set_row_colour_unreadable(self, row: int) -> None: """ Set unreadable row colour """ - self._set_row_colour(row, QColor(Config.COLOUR_UNREADABLE)) + self._set_row_colour(row, Config.COLOUR_UNREADABLE) def _set_row_duration(self, row: int, ms: Optional[int]) -> QTableWidgetItem: @@ -1897,6 +1891,32 @@ class PlaylistTab(QTableWidget): return self._set_item_text(row, END_TIME, time_str) + def _set_row_header_text(self, session: scoped_session, + row_number: int, text: str) -> None: + """ + Set header text and row colour + """ + + # Sanity check: this should be a header row and thus not have a + # track associate + if self._get_row_track_id(row_number): + send_mail(Config.ERRORS_TO, + Config.ERRORS_FROM, + "playists:_set_row_header_text() called on track row", + stackprinter.format() + ) + return + + # Set text + _ = self._set_item_text(row_number, HEADER_NOTES_COLUMN, text) + + # Set colour + note_colour = NoteColours.get_colour(session, text) + if not note_colour: + note_colour = Config.COLOUR_NOTES_PLAYLIST + + self._set_row_colour(row_number, note_colour) + def _set_row_last_played(self, row: int, last_played: Optional[datetime]) \ -> QTableWidgetItem: """Set row last played time""" @@ -1910,34 +1930,28 @@ class PlaylistTab(QTableWidget): self._set_row_bold(row, False) - def _set_row_note_colour(self, session: scoped_session, row: int, - note_text: Optional[str], - section_header: bool = False) -> QTableWidgetItem: - """Set row note and colour""" + def _set_row_note_text(self, session: scoped_session, + row_number: int, text: str) -> None: + """ + Set row note text and note colour + """ - if section_header: - column = HEADER_NOTES_COLUMN - else: - column = ROW_NOTES + # Sanity check: this should be a track row and thus have a + # track associated + if not self._get_row_track_id(row_number): + send_mail(Config.ERRORS_TO, + Config.ERRORS_FROM, + "playists:_set_row_note_text() called on header row", + stackprinter.format() + ) + return - if not note_text: - note_text = "" + # Set text + _ = self._set_item_text(row_number, ROW_NOTES, text) - notes_item = self._set_item_text(row, column, note_text) - - note_colour = NoteColours.get_colour(session, note_text) - if section_header and not note_colour: - note_colour = Config.COLOUR_NOTES_PLAYLIST - if note_colour: - new_colour = QColor(note_colour) - else: - new_colour = None - if section_header: - self._set_row_colour(row, new_colour) - else: - self._set_cell_colour(row, column, new_colour) - - return notes_item + # Set colour + note_colour = NoteColours.get_colour(session, text) + self._set_cell_colour(row_number, ROW_NOTES, note_colour) def _set_row_plr_id(self, row: int, plr_id: int) -> QTableWidgetItem: """ @@ -2055,19 +2069,6 @@ class PlaylistTab(QTableWidget): return total_time - def _update_note_text(self, playlist_row: PlaylistRows, - new_text: str) -> None: - """Update note text""" - - # Column to update is either HEADER_NOTES_COLUMN for a section - # header or the appropriate row_notes column for a track row - if playlist_row.track_id: - column = ROW_NOTES - else: - column = HEADER_NOTES_COLUMN - - _ = self._set_item_text(playlist_row.row_number, column, new_text) - def _update_row_track_info(self, session: scoped_session, row: int, track: Tracks) -> None: """ @@ -2089,26 +2090,6 @@ class PlaylistTab(QTableWidget): if not file_is_readable(track.path): self._set_row_colour_unreadable(row) - def _update_row_note(self, row_number: int) -> None: - """ - Called by signal when row note is updated - """ - - # Set/clear row start time accordingly - note_text = self._get_row_note(row_number) - start_time = self._get_note_text_time(note_text) - if start_time: - self._set_row_start_time(row_number, start_time) - else: - self._set_row_start_time(row_number, None) - - is_section_header = not bool(self._get_row_track_id(row_number)) - with Session() as session: - self._set_row_note_colour(session, row_number, note_text, - section_header=is_section_header) - - self._update_start_end_times() - def _update_section_headers(self, session: scoped_session) -> None: """ Update section headers with run time of section @@ -2133,7 +2114,8 @@ class PlaylistTab(QTableWidget): total_time = self._track_time_between_rows( session, from_plr, to_plr) time_str = self._get_section_timing_string(total_time) - self._update_note_text(from_plr, from_plr.note + time_str) + self._set_row_header_text(session, from_plr.row_number, + from_plr.note + time_str) # Update section end if to_plr.note.strip() == "-": @@ -2142,11 +2124,13 @@ class PlaylistTab(QTableWidget): section_header_cleanup_re, '', from_plr.note, ).strip() + "]" ) - self._update_note_text(plr, new_text) + self._set_row_header_text(session, plr.row_number, + new_text) except IndexError: # This ending row may have a time left from before a # starting row above was deleted, so replace content - self._update_note_text(plr, plr.note) + self._set_row_header_text(session, plr.row_number, + plr.note) continue # If we still have plrs in section_start_rows, there isn't an end @@ -2159,7 +2143,8 @@ class PlaylistTab(QTableWidget): from_plr, to_plr) time_str = self._get_section_timing_string(total_time, no_end=True) - self._update_note_text(from_plr, from_plr.note + time_str) + self._set_row_header_text(session, from_plr.row_number, + from_plr.note + time_str) def _update_start_end_times(self) -> None: """ Update track start and end times """