From 709347db6b2e72d110f450a4f3b76dca21417976 Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Fri, 10 Jun 2022 14:59:38 +0100 Subject: [PATCH] WIP: move notes with tracks --- app/models.py | 12 ++++++++++++ app/musicmuster.py | 13 ++++++++++--- app/playlists.py | 38 +++++++++++++++++++------------------- test_playlists.py | 20 ++++++++++---------- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/app/models.py b/app/models.py index fd81f00..b9fade8 100644 --- a/app/models.py +++ b/app/models.py @@ -153,6 +153,18 @@ class Notes(Base): session.query(Notes).filter_by(id=self.id).delete() session.flush() + @staticmethod + def move_rows(session: Session, rows: List[int], + from_playlist_id: int, to_playlist_id: int): + """ + Move note(s) to another playlist + """ + + session.query(Notes).filter( + Notes.playlist_id == from_playlist_id, + Notes.row.in_(rows) + ).update({'playlist_id': to_playlist_id}, False) + @classmethod def get_by_id(cls, session: Session, note_id: int) -> Optional["Notes"]: """Return note or None""" diff --git a/app/musicmuster.py b/app/musicmuster.py index 7c0e599..32cac45 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -34,7 +34,7 @@ import helpers import music from config import Config -from models import (Base, Playdates, Playlists, PlaylistTracks, +from models import (Base, Notes, Playdates, Playlists, PlaylistTracks, Settings, Tracks) from playlists import PlaylistTab from sqlalchemy.orm.exc import DetachedInstanceError @@ -506,8 +506,15 @@ class Window(QMainWindow, Ui_MainWindow): # Update database for both source and destination playlists rows = visible_tab.get_selected_rows() - PlaylistTracks.move_rows(session, rows, source_playlist.id, - destination_playlist.id) + notes_rows = visible_tab.get_notes_rows() + track_rows_to_move = [a for a in rows if a not in notes_rows] + note_rows_to_move = [a for a in rows if a in notes_rows] + PlaylistTracks.move_rows( + session, track_rows_to_move, source_playlist.id, + destination_playlist.id) + Notes.move_rows( + session, note_rows_to_move, source_playlist.id, + destination_playlist.id) # Update destination playlist_tab if visible (if not visible, it # will be re-populated when it is opened) diff --git a/app/playlists.py b/app/playlists.py index c589b51..95301fd 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -182,7 +182,7 @@ class PlaylistTab(QTableWidget): # rows. Check and fix: row = 0 # So row is defined even if there are no rows in range for row in range(drop_row, drop_row + len(rows_to_move)): - if row in self._get_notes_rows(): + if row in self.get_notes_rows(): self.setSpan( row, self.COL_NOTE, self.NOTE_ROW_SPAN, self.NOTE_COL_SPAN) @@ -305,6 +305,11 @@ class PlaylistTab(QTableWidget): session, self.playlist_id, row, dlg.textValue()) self._insert_note(session, note, row, True) # checked + def get_notes_rows(self) -> List[int]: + """Return rows marked as notes, or None""" + + return self._meta_search(RowMeta.NOTE, one=False) + def get_selected_row(self) -> Optional[int]: """Return row number of first selected row, or None if none selected""" @@ -534,7 +539,7 @@ class PlaylistTab(QTableWidget): # Create dictionaries indexed by note_id playlist_notes: Dict[int, Notes] = {} database_notes: Dict[int, Notes] = {} - notes_rows: List[int] = self._get_notes_rows() + notes_rows: List[int] = self.get_notes_rows() # PlaylistTab for row in notes_rows: @@ -606,7 +611,7 @@ class PlaylistTab(QTableWidget): # Don't select notes wrapped: bool = False - while row in self._get_notes_rows(): + while row in self.get_notes_rows(): row += 1 if row >= self.rowCount(): if wrapped: @@ -652,7 +657,7 @@ class PlaylistTab(QTableWidget): # Don't select notes wrapped: bool = False - while row in self._get_notes_rows(): + while row in self.get_notes_rows(): row -= 1 if row < 0: if wrapped: @@ -709,7 +714,7 @@ class PlaylistTab(QTableWidget): current_row: Optional[int] = self._get_current_track_row() next_row: Optional[int] = self._get_next_track_row() - notes: List[int] = self._get_notes_rows() + notes: List[int] = self.get_notes_rows() played: Optional[List[int]] = self._get_played_track_rows() unreadable: List[int] = self._get_unreadable_track_rows() @@ -896,7 +901,7 @@ class PlaylistTab(QTableWidget): DEBUG(f"_audacity({row})") - if row in self._get_notes_rows(): + if row in self.get_notes_rows(): return None with Session() as session: @@ -926,7 +931,7 @@ class PlaylistTab(QTableWidget): DEBUG(f"_copy_path({row})") - if row in self._get_notes_rows(): + if row in self.get_notes_rows(): return None with Session() as session: @@ -948,7 +953,7 @@ class PlaylistTab(QTableWidget): DEBUG(f"_cell_changed({row=}, {column=}, {new_text=}") with Session() as session: - if row in self._get_notes_rows(): + if row in self.get_notes_rows(): # Save change to database note: Notes = self._get_row_notes_object(row, session) note.update(session, row, new_text) @@ -1046,7 +1051,7 @@ class PlaylistTab(QTableWidget): set(item.row() for item in self.selectedItems()) ) rows_to_delete: List[int] = [] - note_rows: Optional[List[int]] = self._get_notes_rows() + note_rows: Optional[List[int]] = self.get_notes_rows() row: int row_object: Union[Tracks, Notes] @@ -1131,7 +1136,7 @@ class PlaylistTab(QTableWidget): starting_row = current_row + 1 else: starting_row = 0 - notes_rows = self._get_notes_rows() + notes_rows = self.get_notes_rows() played_rows = self._get_played_track_rows() for row in range(starting_row, self.rowCount()): if row in notes_rows or row in played_rows: @@ -1173,11 +1178,6 @@ class PlaylistTab(QTableWidget): except ValueError: return None - def _get_notes_rows(self) -> List[int]: - """Return rows marked as notes, or None""" - - return self._meta_search(RowMeta.NOTE, one=False) - def _get_row_duration(self, row: int) -> int: """Return duration associated with this row""" @@ -1219,7 +1219,7 @@ class PlaylistTab(QTableWidget): """Return rows marked as unplayed, or None""" unplayed_rows: Set[int] = set(self._meta_notset(RowMeta.PLAYED)) - notes_rows: Set[int] = set(self._get_notes_rows()) + notes_rows: Set[int] = set(self.get_notes_rows()) return list(unplayed_rows - notes_rows) @@ -1259,7 +1259,7 @@ class PlaylistTab(QTableWidget): txt: str with Session() as session: - if row in self._get_notes_rows(): + if row in self.get_notes_rows(): note: Notes = self._get_row_notes_object(row, session) txt = note.note else: @@ -1507,7 +1507,7 @@ class PlaylistTab(QTableWidget): self.musicmuster.lblSumPlaytime.setText("") return - notes_rows: Set[int] = set(self._get_notes_rows()) + notes_rows: Set[int] = set(self.get_notes_rows()) ms: int = 0 with Session() as session: for row in (sel_rows - notes_rows): @@ -1567,7 +1567,7 @@ class PlaylistTab(QTableWidget): DEBUG(f"_set_next({row=})") # Check row is a track row - if row in self._get_notes_rows(): + if row in self.get_notes_rows(): return None track: Tracks = self._get_row_track_object(row, session) if not track: diff --git a/test_playlists.py b/test_playlists.py index 24bb7e0..2d5be4d 100644 --- a/test_playlists.py +++ b/test_playlists.py @@ -101,7 +101,7 @@ def test_meta_all_clear(qtbot, session): assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_next_track_row() is None - assert playlist_tab._get_notes_rows() == [] + assert playlist_tab.get_notes_rows() == [] assert playlist_tab._get_played_track_rows() == [] assert len(playlist_tab._get_unreadable_track_rows()) == 3 @@ -131,13 +131,13 @@ def test_meta(qtbot, session): assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_next_track_row() is None - assert playlist_tab._get_notes_rows() == [] + assert playlist_tab.get_notes_rows() == [] playlist_tab._set_played_row(0) assert playlist_tab._get_played_track_rows() == [0] assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_next_track_row() is None - assert playlist_tab._get_notes_rows() == [] + assert playlist_tab.get_notes_rows() == [] # Add a note note_text = "my note" @@ -148,44 +148,44 @@ def test_meta(qtbot, session): assert playlist_tab._get_played_track_rows() == [0] assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_next_track_row() is None - assert playlist_tab._get_notes_rows() == [3] + assert playlist_tab.get_notes_rows() == [3] playlist_tab._set_next_track_row(1) assert playlist_tab._get_played_track_rows() == [0] assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_next_track_row() == 1 - assert playlist_tab._get_notes_rows() == [3] + assert playlist_tab.get_notes_rows() == [3] playlist_tab._set_current_track_row(2) assert playlist_tab._get_played_track_rows() == [0] assert playlist_tab._get_current_track_row() == 2 assert playlist_tab._get_next_track_row() == 1 - assert playlist_tab._get_notes_rows() == [3] + assert playlist_tab.get_notes_rows() == [3] playlist_tab._clear_played_row_status(0) assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_current_track_row() == 2 assert playlist_tab._get_next_track_row() == 1 - assert playlist_tab._get_notes_rows() == [3] + assert playlist_tab.get_notes_rows() == [3] playlist_tab._meta_clear_next() assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_current_track_row() == 2 assert playlist_tab._get_next_track_row() is None - assert playlist_tab._get_notes_rows() == [3] + assert playlist_tab.get_notes_rows() == [3] playlist_tab._clear_current_track_row() assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_next_track_row() is None - assert playlist_tab._get_notes_rows() == [3] + assert playlist_tab.get_notes_rows() == [3] # Test clearing again has no effect playlist_tab._clear_current_track_row() assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_next_track_row() is None - assert playlist_tab._get_notes_rows() == [3] + assert playlist_tab.get_notes_rows() == [3] def test_clear_next(qtbot, session):