WIP: move notes with tracks

This commit is contained in:
Keith Edmunds 2022-06-10 14:59:38 +01:00
parent 8558de82b4
commit 709347db6b
4 changed files with 51 additions and 32 deletions

View File

@ -153,6 +153,18 @@ class Notes(Base):
session.query(Notes).filter_by(id=self.id).delete() session.query(Notes).filter_by(id=self.id).delete()
session.flush() 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 @classmethod
def get_by_id(cls, session: Session, note_id: int) -> Optional["Notes"]: def get_by_id(cls, session: Session, note_id: int) -> Optional["Notes"]:
"""Return note or None""" """Return note or None"""

View File

@ -34,7 +34,7 @@ import helpers
import music import music
from config import Config from config import Config
from models import (Base, Playdates, Playlists, PlaylistTracks, from models import (Base, Notes, Playdates, Playlists, PlaylistTracks,
Settings, Tracks) Settings, Tracks)
from playlists import PlaylistTab from playlists import PlaylistTab
from sqlalchemy.orm.exc import DetachedInstanceError from sqlalchemy.orm.exc import DetachedInstanceError
@ -506,8 +506,15 @@ class Window(QMainWindow, Ui_MainWindow):
# Update database for both source and destination playlists # Update database for both source and destination playlists
rows = visible_tab.get_selected_rows() rows = visible_tab.get_selected_rows()
PlaylistTracks.move_rows(session, rows, source_playlist.id, notes_rows = visible_tab.get_notes_rows()
destination_playlist.id) 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 # Update destination playlist_tab if visible (if not visible, it
# will be re-populated when it is opened) # will be re-populated when it is opened)

View File

@ -182,7 +182,7 @@ class PlaylistTab(QTableWidget):
# rows. Check and fix: # rows. Check and fix:
row = 0 # So row is defined even if there are no rows in range 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)): 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( self.setSpan(
row, self.COL_NOTE, self.NOTE_ROW_SPAN, self.NOTE_COL_SPAN) 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()) session, self.playlist_id, row, dlg.textValue())
self._insert_note(session, note, row, True) # checked 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]: def get_selected_row(self) -> Optional[int]:
"""Return row number of first selected row, or None if none selected""" """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 # Create dictionaries indexed by note_id
playlist_notes: Dict[int, Notes] = {} playlist_notes: Dict[int, Notes] = {}
database_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 # PlaylistTab
for row in notes_rows: for row in notes_rows:
@ -606,7 +611,7 @@ class PlaylistTab(QTableWidget):
# Don't select notes # Don't select notes
wrapped: bool = False wrapped: bool = False
while row in self._get_notes_rows(): while row in self.get_notes_rows():
row += 1 row += 1
if row >= self.rowCount(): if row >= self.rowCount():
if wrapped: if wrapped:
@ -652,7 +657,7 @@ class PlaylistTab(QTableWidget):
# Don't select notes # Don't select notes
wrapped: bool = False wrapped: bool = False
while row in self._get_notes_rows(): while row in self.get_notes_rows():
row -= 1 row -= 1
if row < 0: if row < 0:
if wrapped: if wrapped:
@ -709,7 +714,7 @@ class PlaylistTab(QTableWidget):
current_row: Optional[int] = self._get_current_track_row() current_row: Optional[int] = self._get_current_track_row()
next_row: Optional[int] = self._get_next_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() played: Optional[List[int]] = self._get_played_track_rows()
unreadable: List[int] = self._get_unreadable_track_rows() unreadable: List[int] = self._get_unreadable_track_rows()
@ -896,7 +901,7 @@ class PlaylistTab(QTableWidget):
DEBUG(f"_audacity({row})") DEBUG(f"_audacity({row})")
if row in self._get_notes_rows(): if row in self.get_notes_rows():
return None return None
with Session() as session: with Session() as session:
@ -926,7 +931,7 @@ class PlaylistTab(QTableWidget):
DEBUG(f"_copy_path({row})") DEBUG(f"_copy_path({row})")
if row in self._get_notes_rows(): if row in self.get_notes_rows():
return None return None
with Session() as session: with Session() as session:
@ -948,7 +953,7 @@ class PlaylistTab(QTableWidget):
DEBUG(f"_cell_changed({row=}, {column=}, {new_text=}") DEBUG(f"_cell_changed({row=}, {column=}, {new_text=}")
with Session() as session: with Session() as session:
if row in self._get_notes_rows(): if row in self.get_notes_rows():
# Save change to database # Save change to database
note: Notes = self._get_row_notes_object(row, session) note: Notes = self._get_row_notes_object(row, session)
note.update(session, row, new_text) note.update(session, row, new_text)
@ -1046,7 +1051,7 @@ class PlaylistTab(QTableWidget):
set(item.row() for item in self.selectedItems()) set(item.row() for item in self.selectedItems())
) )
rows_to_delete: List[int] = [] 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: int
row_object: Union[Tracks, Notes] row_object: Union[Tracks, Notes]
@ -1131,7 +1136,7 @@ class PlaylistTab(QTableWidget):
starting_row = current_row + 1 starting_row = current_row + 1
else: else:
starting_row = 0 starting_row = 0
notes_rows = self._get_notes_rows() notes_rows = self.get_notes_rows()
played_rows = self._get_played_track_rows() played_rows = self._get_played_track_rows()
for row in range(starting_row, self.rowCount()): for row in range(starting_row, self.rowCount()):
if row in notes_rows or row in played_rows: if row in notes_rows or row in played_rows:
@ -1173,11 +1178,6 @@ class PlaylistTab(QTableWidget):
except ValueError: except ValueError:
return None 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: def _get_row_duration(self, row: int) -> int:
"""Return duration associated with this row""" """Return duration associated with this row"""
@ -1219,7 +1219,7 @@ class PlaylistTab(QTableWidget):
"""Return rows marked as unplayed, or None""" """Return rows marked as unplayed, or None"""
unplayed_rows: Set[int] = set(self._meta_notset(RowMeta.PLAYED)) 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) return list(unplayed_rows - notes_rows)
@ -1259,7 +1259,7 @@ class PlaylistTab(QTableWidget):
txt: str txt: str
with Session() as session: 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) note: Notes = self._get_row_notes_object(row, session)
txt = note.note txt = note.note
else: else:
@ -1507,7 +1507,7 @@ class PlaylistTab(QTableWidget):
self.musicmuster.lblSumPlaytime.setText("") self.musicmuster.lblSumPlaytime.setText("")
return return
notes_rows: Set[int] = set(self._get_notes_rows()) notes_rows: Set[int] = set(self.get_notes_rows())
ms: int = 0 ms: int = 0
with Session() as session: with Session() as session:
for row in (sel_rows - notes_rows): for row in (sel_rows - notes_rows):
@ -1567,7 +1567,7 @@ class PlaylistTab(QTableWidget):
DEBUG(f"_set_next({row=})") DEBUG(f"_set_next({row=})")
# Check row is a track row # Check row is a track row
if row in self._get_notes_rows(): if row in self.get_notes_rows():
return None return None
track: Tracks = self._get_row_track_object(row, session) track: Tracks = self._get_row_track_object(row, session)
if not track: if not track:

View File

@ -101,7 +101,7 @@ def test_meta_all_clear(qtbot, session):
assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_current_track_row() is None
assert playlist_tab._get_next_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 playlist_tab._get_played_track_rows() == []
assert len(playlist_tab._get_unreadable_track_rows()) == 3 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_played_track_rows() == []
assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_current_track_row() is None
assert playlist_tab._get_next_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) playlist_tab._set_played_row(0)
assert playlist_tab._get_played_track_rows() == [0] assert playlist_tab._get_played_track_rows() == [0]
assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_current_track_row() is None
assert playlist_tab._get_next_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 # Add a note
note_text = "my 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_played_track_rows() == [0]
assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_current_track_row() is None
assert playlist_tab._get_next_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) playlist_tab._set_next_track_row(1)
assert playlist_tab._get_played_track_rows() == [0] assert playlist_tab._get_played_track_rows() == [0]
assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_current_track_row() is None
assert playlist_tab._get_next_track_row() == 1 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) playlist_tab._set_current_track_row(2)
assert playlist_tab._get_played_track_rows() == [0] assert playlist_tab._get_played_track_rows() == [0]
assert playlist_tab._get_current_track_row() == 2 assert playlist_tab._get_current_track_row() == 2
assert playlist_tab._get_next_track_row() == 1 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) playlist_tab._clear_played_row_status(0)
assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_played_track_rows() == []
assert playlist_tab._get_current_track_row() == 2 assert playlist_tab._get_current_track_row() == 2
assert playlist_tab._get_next_track_row() == 1 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() playlist_tab._meta_clear_next()
assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_played_track_rows() == []
assert playlist_tab._get_current_track_row() == 2 assert playlist_tab._get_current_track_row() == 2
assert playlist_tab._get_next_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._clear_current_track_row() playlist_tab._clear_current_track_row()
assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_played_track_rows() == []
assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_current_track_row() is None
assert playlist_tab._get_next_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 # Test clearing again has no effect
playlist_tab._clear_current_track_row() playlist_tab._clear_current_track_row()
assert playlist_tab._get_played_track_rows() == [] assert playlist_tab._get_played_track_rows() == []
assert playlist_tab._get_current_track_row() is None assert playlist_tab._get_current_track_row() is None
assert playlist_tab._get_next_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): def test_clear_next(qtbot, session):