Compare commits

...

8 Commits

Author SHA1 Message Date
Keith Edmunds
f19fc2e8c0 Remove dummy_for_profiling parameters 2024-11-16 13:06:35 +00:00
Keith Edmunds
40b5fc020d Fix playlist_rows row_number corruption 2024-11-16 13:04:39 +00:00
Keith Edmunds
98a8e20baa Move track to under current makes it next track
Fixes #261
2024-11-16 13:04:11 +00:00
Keith Edmunds
3cec08db85 Remove profiler decorations 2024-11-16 13:03:10 +00:00
Keith Edmunds
f5b26028f5 Improve RowAndTrack repr 2024-11-16 13:02:21 +00:00
Keith Edmunds
4c420d01ca Preserve row order when moving rows 2024-11-16 10:44:30 +00:00
Keith Edmunds
7cfd2a45a2 Speed up moving rows
Fixes #262
Fixed #260
2024-11-16 09:58:08 +00:00
Keith Edmunds
b4fcd5f2c9 Don't try to move rows if no rows selected
Fixes #263
2024-11-15 21:38:24 +00:00
6 changed files with 66 additions and 41 deletions

View File

@ -534,6 +534,7 @@ class RowAndTrack:
return (
f"<RowAndTrack(playlist_id={self.playlist_id}, "
f"row_number={self.row_number}, "
f"playlistrow_id={self.playlistrow_id}, "
f"note={self.note}, track_id={self.track_id}>"
)

View File

@ -8,7 +8,6 @@ import sys
# PyQt imports
# Third party imports
import line_profiler
from sqlalchemy import (
bindparam,
delete,
@ -564,7 +563,6 @@ class PlaylistRows(dbtables.PlaylistRowsTable):
)
@staticmethod
@line_profiler.profile
def update_plr_row_numbers(
session: Session, playlist_id: int, sqla_map: List[dict[str, int]]
) -> None:

View File

@ -44,7 +44,6 @@ from PyQt6.QtWidgets import (
)
# Third party imports
import line_profiler
import pipeclient
from pygame import mixer
from sqlalchemy.exc import IntegrityError
@ -1069,13 +1068,12 @@ class Window(QMainWindow, Ui_MainWindow):
else:
webbrowser.get("browser").open_new_tab(url)
@line_profiler.profile
def paste_rows(self, dummy_for_profiling=None) -> None:
def paste_rows(self) -> None:
"""
Paste earlier cut rows.
"""
if self.move_source_rows is None or self.move_source_model is None:
if not self.move_source_rows or not self.move_source_model:
return
to_playlist_model: PlaylistModel = self.active_tab().source_model
@ -1085,6 +1083,16 @@ class Window(QMainWindow, Ui_MainWindow):
else:
destination_row = self.active_proxy_model().rowCount()
# If we move a row to immediately under the current track, make
# that moved row the next track
set_next_row: Optional[int] = None
if (
track_sequence.current
and track_sequence.current.playlist_id == to_playlist_model.playlist_id
and destination_row == track_sequence.current.row_number + 1
):
set_next_row = destination_row
if (
to_playlist_model.playlist_id
== self.move_source_model.source_model.playlist_id
@ -1097,6 +1105,9 @@ class Window(QMainWindow, Ui_MainWindow):
self.active_tab().resize_rows()
self.active_tab().clear_selection()
if set_next_row:
to_playlist_model.set_next_row(set_next_row)
def play_next(self, position: Optional[float] = None) -> None:
"""
Play next track, optionally from passed position.

View File

@ -26,7 +26,6 @@ from PyQt6.QtGui import (
)
# Third party imports
import line_profiler
import obswebsocket # type: ignore
# import snoop # type: ignore
@ -737,8 +736,7 @@ class PlaylistModel(QAbstractTableModel):
self.update_track_times()
self.invalidate_rows(row_numbers)
@line_profiler.profile
def move_rows(self, from_rows: list[int], to_row_number: int, dummy_for_profiling=None) -> None:
def move_rows(self, from_rows: list[int], to_row_number: int) -> None:
"""
Move the playlist rows given to to_row and below.
"""
@ -785,18 +783,6 @@ class PlaylistModel(QAbstractTableModel):
if old_row != new_row:
row_map[old_row] = new_row
# Check to see whether any rows in track_sequence have moved
if track_sequence.previous and track_sequence.previous.row_number in row_map:
track_sequence.previous.row_number = row_map[
track_sequence.previous.row_number
]
if track_sequence.current and track_sequence.current.row_number in row_map:
track_sequence.current.row_number = row_map[
track_sequence.current.row_number
]
if track_sequence.next and track_sequence.next.row_number in row_map:
track_sequence.next.row_number = row_map[track_sequence.next.row_number]
# For SQLAlchemy, build a list of dictionaries that map playlistrow_id to
# new row number:
sqla_map: list[dict[str, int]] = []
@ -831,26 +817,27 @@ class PlaylistModel(QAbstractTableModel):
# endRemoveRows and the row range must be contiguous. Process
# the highest rows first so the lower row numbers are unchanged
row_groups = self._reversed_contiguous_row_groups(from_rows)
next_to_row = to_row_number
# Prepare destination playlist for a reset
self.signals.begin_reset_model_signal.emit(to_playlist_id)
with db.Session() as session:
# Make room in destination playlist
max_destination_row_number = PlaylistRows.get_last_used_row(
session, to_playlist_id
)
if (
max_destination_row_number
and to_row_number <= max_destination_row_number
):
# Move the destination playlist rows down to make room.
PlaylistRows.move_rows_down(
session, to_playlist_id, to_row_number, len(from_rows)
)
for row_group in row_groups:
# Make room in destination playlist
max_destination_row_number = PlaylistRows.get_last_used_row(
session, to_playlist_id
)
if (
max_destination_row_number
and to_row_number <= max_destination_row_number
):
# Move the destination playlist rows down to make room.
PlaylistRows.move_rows_down(
session, to_playlist_id, to_row_number, len(row_group)
)
next_to_row = to_row_number
super().beginRemoveRows(QModelIndex(), min(row_group), max(row_group))
for playlist_row in PlaylistRows.plrids_to_plrs(
session,
@ -988,14 +975,29 @@ class PlaylistModel(QAbstractTableModel):
# Update display
self.invalidate_row(track_sequence.previous.row_number)
@line_profiler.profile
def refresh_data(self, session: db.session, dummy_for_profiling=None) -> None:
"""Populate dicts for data calls"""
def refresh_data(self, session: db.session) -> None:
"""Populate self.playlist_rows with playlist data"""
# Populate self.playlist_rows with playlist data
self.playlist_rows.clear()
# We used to clear self.playlist_rows each time but that's
# expensive and slow on big playlists
# Note where each playlist_id is
plid_to_row: dict[int, int] = {}
for oldrow in self.playlist_rows:
plrdata = self.playlist_rows[oldrow]
plid_to_row[plrdata.playlistrow_id] = plrdata.row_number
# build a new playlist_rows
new_playlist_rows: dict[int, RowAndTrack] = {}
for p in PlaylistRows.get_playlist_rows(session, self.playlist_id):
self.playlist_rows[p.row_number] = RowAndTrack(p)
if p.id not in plid_to_row:
new_playlist_rows[p.row_number] = RowAndTrack(p)
else:
new_playlist_rows[p.row_number] = self.playlist_rows[plid_to_row[p.id]]
new_playlist_rows[p.row_number].row_number = p.row_number
# Copy to self.playlist_rows
self.playlist_rows = new_playlist_rows
def refresh_row(self, session, row_number):
"""Populate dict for one row from database"""

View File

@ -296,6 +296,15 @@ class PlaylistTab(QTableView):
and 0 <= max(from_rows) <= self.source_model.rowCount()
and 0 <= to_model_row <= self.source_model.rowCount()
):
# If we move a row to immediately under the current track, make
# that moved row the next track
set_next_row: Optional[int] = None
if (
track_sequence.current
and to_model_row == track_sequence.current.row_number + 1
):
set_next_row = to_model_row
self.source_model.move_rows(from_rows, to_model_row)
# Reset drag mode to allow row selection by dragging
@ -307,6 +316,10 @@ class PlaylistTab(QTableView):
# Resize rows
self.resize_rows()
# Set next row if we are immediately under current row
if set_next_row:
self.source_model.set_next_row(set_next_row)
event.accept()
def mouseReleaseEvent(self, event):

View File

@ -387,9 +387,9 @@ class TestMMMiscRowMove(unittest.TestCase):
assert [int(a) for a in row_notes] == [
0,
1,
1,
3,
4,
1,
2,
3,
4,