From 444c3e4fb43a3d3ab81d19016bab5bdaf45cdf19 Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Fri, 23 Dec 2022 20:15:07 +0000 Subject: [PATCH] Remove rows from playlist works and db updates --- app/models.py | 17 +++--- app/playlists.py | 156 +++++++++++++++++++++++++---------------------- 2 files changed, 91 insertions(+), 82 deletions(-) diff --git a/app/models.py b/app/models.py index 909cf7d..777301f 100644 --- a/app/models.py +++ b/app/models.py @@ -457,7 +457,7 @@ class PlaylistRows(Base): -> None: """ Delete rows in given playlist that have a higher row number - than 'row' + than 'maxrow' """ # Log the rows to be deleted @@ -470,9 +470,7 @@ class PlaylistRows(Base): return for row in rows_to_go: - log.debug(f"Should delete: {row}") - # If needed later: - # session.delete(row) + session.delete(row) @staticmethod def delete_rows(session: Session, ids: List[int]) -> None: @@ -617,23 +615,22 @@ class PlaylistRows(Base): ) @staticmethod - def indexed_by_row(session: Session, playlist_id: int) -> dict: + def indexed_by_id(session: Session, plr_ids: List[int]) -> dict: """ - Return a dictionary of playlist_rows indexed by row number for - the passed playlist_id. + Return a dictionary of playlist_rows indexed by their plr id from + the passed plr_id list. """ plrs = session.execute( select(PlaylistRows) .where( - PlaylistRows.playlist_id == playlist_id, + PlaylistRows.id.in_(plr_ids) ) - .order_by(PlaylistRows.row_number) ).scalars().all() result = {} for plr in plrs: - result[plr.row_number] = plr + result[plr.id] = plr return result diff --git a/app/playlists.py b/app/playlists.py index d112e78..0b763c7 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -822,22 +822,39 @@ class PlaylistTab(QTableWidget): def save_playlist(self, session: Session) -> None: """ - All playlist rows have a PlaylistRows id. Check that that id points - to this playlist (in case track has been moved from other) and that - the row number is correct (in case tracks have been reordered). + Get the PlaylistRow objects for each row in the display. Correct + the row_number and playlist_id if necessary. Remove any row + numbers in the database that are higher than the last row in + the display. """ - plr_dict = PlaylistRows.indexed_by_row(session, self.playlist_id) + # Build a dictionary of + # {display_row_number: display_row_plr_id} + display_plr_ids = {row_number: self._get_playlistrow_id(row_number) + for row_number in range(self.rowCount())} + + # Now build a dictionary of + # {display_row_number: display_row_plr} + plr_dict_by_id = PlaylistRows.indexed_by_id(session, + display_plr_ids.values()) + + # Finally a dictionary of + # {display_row_number: plr} + row_plr = {row_number: plr_dict_by_id[display_plr_ids[row_number]] + for row_number in range(self.rowCount())} + + # Ensure all row plrs have correct row number and playlist_id for row in range(self.rowCount()): - # Set the row number and playlist id (even if correct) - plr_dict[row].row_number = row - plr_dict[row].playlist_id = self.playlist_id + row_plr[row].row_number = row + row_plr[row].playlist_id = self.playlist_id # Any rows in the database with a row_number higher that the # current value of 'row' should not be there. Commit session # first to ensure any changes made above are committed. session.commit() - PlaylistRows.delete_higher_rows(session, self.playlist_id, row) + PlaylistRows.delete_higher_rows(session, self.playlist_id, + self.rowCount() - 1) + session.commit() def scroll_current_to_top(self) -> None: """Scroll currently-playing row to top""" @@ -860,65 +877,6 @@ class PlaylistTab(QTableWidget): return self._search(next=True) - def _search(self, next: bool = True) -> None: - """ - Select next/previous row containg self.search_string. Start from - top selected row if there is one, else from top. - - Wrap at last/first row. - """ - - if not self.search_text: - return - - selected_row = self._get_selected_row() - if next: - if selected_row is not None and selected_row < self.rowCount() - 1: - starting_row = selected_row + 1 - else: - starting_row = 0 - else: - if selected_row is not None and selected_row > 0: - starting_row = selected_row - 1 - else: - starting_row = self.rowCount() - 1 - - wrapped = False - match_row = None - row = starting_row - needle = self.search_text.lower() - while True: - # Check for match in title, artist or notes - title = self._get_row_title(row) - if title and needle in title.lower(): - match_row = row - break - artist = self._get_row_artist(row) - if artist and needle in artist.lower(): - match_row = row - break - note = self._get_row_note(row) - if note and needle in note.lower(): - match_row = row - break - if next: - row += 1 - if wrapped and row >= starting_row: - break - if row >= self.rowCount(): - row = 0 - wrapped = True - else: - row -= 1 - if wrapped and row <= starting_row: - break - if row < 0: - row = self.rowCount() - 1 - wrapped = True - - if match_row is not None: - self.selectRow(row) - def search_next(self) -> None: """ Select next row containg self.search_string. @@ -1541,11 +1499,6 @@ class PlaylistTab(QTableWidget): return self._meta_search(RowMeta.UNREADABLE, one=False) - # def _header_click(self, index: int) -> None: - # """Handle playlist header click""" - - # print(f"_header_click({index=})") - def _info_row(self, track_id: int) -> None: """Display popup with info re row""" @@ -1765,6 +1718,65 @@ class PlaylistTab(QTableWidget): scroll_item = self.item(top_row, 0) self.scrollToItem(scroll_item, QAbstractItemView.PositionAtTop) + def _search(self, next: bool = True) -> None: + """ + Select next/previous row containg self.search_string. Start from + top selected row if there is one, else from top. + + Wrap at last/first row. + """ + + if not self.search_text: + return + + selected_row = self._get_selected_row() + if next: + if selected_row is not None and selected_row < self.rowCount() - 1: + starting_row = selected_row + 1 + else: + starting_row = 0 + else: + if selected_row is not None and selected_row > 0: + starting_row = selected_row - 1 + else: + starting_row = self.rowCount() - 1 + + wrapped = False + match_row = None + row = starting_row + needle = self.search_text.lower() + while True: + # Check for match in title, artist or notes + title = self._get_row_title(row) + if title and needle in title.lower(): + match_row = row + break + artist = self._get_row_artist(row) + if artist and needle in artist.lower(): + match_row = row + break + note = self._get_row_note(row) + if note and needle in note.lower(): + match_row = row + break + if next: + row += 1 + if wrapped and row >= starting_row: + break + if row >= self.rowCount(): + row = 0 + wrapped = True + else: + row -= 1 + if wrapped and row <= starting_row: + break + if row < 0: + row = self.rowCount() - 1 + wrapped = True + + if match_row is not None: + self.selectRow(row) + def _select_event(self) -> None: """ Called when item selection changes.