test_insert_header_row passes

This commit is contained in:
Keith Edmunds 2023-10-25 22:17:52 +01:00
parent b12b1501e7
commit 858c86d907
4 changed files with 96 additions and 30 deletions

View File

@ -22,6 +22,8 @@ from typing import (
Sequence,
)
from playlistmodel import PlaylistModel
from sqlalchemy import text
from PyQt6.QtCore import (
@ -1038,9 +1040,11 @@ class Window(QMainWindow, Ui_MainWindow):
"""Show dialog box to enter header text and add to playlist"""
try:
playlist_tab = self.visible_playlist_tab()
model = cast(PlaylistModel, self.visible_playlist_tab().model())
if model is None:
return
except AttributeError:
# Just return if there's no visible playlist tab
# Just return if there's no visible playlist tab model
return
# Get header text
@ -1050,9 +1054,10 @@ class Window(QMainWindow, Ui_MainWindow):
dlg.resize(500, 100)
ok = dlg.exec()
if ok:
with Session() as session:
playlist_tab.insert_header(session, dlg.textValue())
playlist_tab.save_playlist(session)
model.insert_header_row(
self.visible_playlist_tab().get_selected_row_number(),
dlg.textValue()
)
def insert_track(self) -> None:
"""Show dialog box to select and add track from database"""
@ -1513,20 +1518,24 @@ class Window(QMainWindow, Ui_MainWindow):
visible_playlist_id = self.visible_playlist_tab().playlist_id
# Get row number of duplicate rows
sql = text(f"""
sql = text(
f"""
SELECT max(plr_rownum)
FROM playlist_rows
WHERE playlist_id = {visible_playlist_id}
AND track_id != 0
GROUP BY track_id
HAVING count(id) > 1
""")
"""
)
with Session() as session:
row_numbers = [int(a) for a in session.execute(sql).scalars().all()]
if row_numbers:
self.visible_playlist_tab().select_rows(row_numbers)
self.statusbar.showMessage(f"{len(row_numbers)} duplicate rows selected", 10000)
self.statusbar.showMessage(
f"{len(row_numbers)} duplicate rows selected", 10000
)
def select_next_row(self) -> None:
"""Select next or first row in playlist"""

View File

@ -282,42 +282,72 @@ class PlaylistModel(QAbstractTableModel):
return QVariant()
def insert_row(self, session: scoped_session, row_number: int) -> int:
def insert_header_row(self, row_number: Optional[int], text: str) -> Optional[int]:
"""
Insert a header row. Return row number or None if insertion failed.
"""
with Session() as session:
prd = self._insert_row(session, row_number)
# Update playlist_rows
prd.note = text
# Get row from db and update
plr = session.get(PlaylistRows, prd.plrid)
if plr:
plr.note = text
self.refresh_row(session, plr.plr_rownum)
self.invalidate_row(plr.plr_rownum)
return plr.plr_rownum
return None
def _insert_row(
self, session: scoped_session, row_number: Optional[int]
) -> PlaylistRowData:
"""
Make space for a row at row_number. If row_number is greater
than length of list plus 1, or if row number is -1, put row at
end of list.
Return new row number that has an empty, valid entry in self.playlist_rows.
Return the new PlaylistData structure
"""
if row_number > len(self.playlist_rows) or row_number == -1:
new_row_number = len(self.playlist_rows) + 1
modified_rows: List[int] = []
if row_number is None or row_number > len(self.playlist_rows):
new_row_number = len(self.playlist_rows)
elif row_number < 0:
raise ValueError(
f"playlistmodel.insert_row, invalid row number ({row_number})"
)
else:
new_row_number = row_number
modified_rows.append(new_row_number)
# Move rows below new row down
modified_rows: List[int] = []
for i in reversed(range(new_row_number, len(self.playlist_rows))):
self.playlist_rows[i + 1] = self.playlist_rows[i]
self.playlist_rows[i + 1].plr_rownum += 1
modified_rows.append(i + 1)
# Replace old row
self.playlist_rows[new_row_number] = PlaylistRowData(
PlaylistRows(
session=session, playlist_id=self.playlist_id, row_number=new_row_number
)
# Insert new row, possibly replace old row
plr = PlaylistRows(
session=session, playlist_id=self.playlist_id, row_number=new_row_number
)
prd = PlaylistRowData(plr)
# Add row to playlist_rows
self.playlist_rows[new_row_number] = prd
# Refresh rows
self.invalidate_rows(modified_rows)
return prd
return new_row_number
def invalidate_row(self, modified_row: int) -> None:
"""
Signal to view to refresh invlidated row
"""
self.dataChanged.emit(
self.index(modified_row, 0), self.index(modified_row, self.columnCount())
)
def invalidate_rows(self, modified_rows: List[int]) -> None:
"""
@ -325,10 +355,7 @@ class PlaylistModel(QAbstractTableModel):
"""
for modified_row in modified_rows:
self.dataChanged.emit(
self.index(modified_row, 0),
self.index(modified_row, self.columnCount()),
)
self.invalidate_row(modified_row)
def move_rows(self, from_rows: List[int], to_row: int) -> None:
"""
@ -379,12 +406,13 @@ class PlaylistModel(QAbstractTableModel):
# Fix in self.playlist_rows
self.playlist_rows[idx].plr_rownum = idx
# Update display
self.invalidate_rows([idx])
self.invalidate_row(idx)
def refresh_data(self):
"""Populate dicts for data calls"""
# Populate self.playlist_rows with playlist data
self.playlist_rows.clear()
with Session() as session:
for p in PlaylistRows.deep_rows(session, self.playlist_id):
self.playlist_rows[p.plr_rownum] = PlaylistRowData(p)
@ -393,7 +421,6 @@ class PlaylistModel(QAbstractTableModel):
"""Populate dict for one row for data calls"""
p = PlaylistRows.deep_row(session, self.playlist_id, row_number)
self.playlist_rows.clear()
self.playlist_rows[p.plr_rownum] = PlaylistRowData(p)
def rowCount(self, index: QModelIndex = QModelIndex()) -> int:

View File

@ -522,6 +522,18 @@ class PlaylistTab(QTableView):
self.clearSelection()
# self.setDragEnabled(False)
def get_selected_row_number(self) -> Optional[int]:
"""
Return the selected row number or None if none selected.
"""
sm = self.selectionModel()
if sm and sm.hasSelection():
index = sm.currentIndex()
if index.isValid():
return index.row()
return None
# def get_new_row_number(self) -> int:
# """
# Return the selected row or the row count if no row selected

View File

@ -12,7 +12,8 @@ def create_model_with_playlist_rows(
# Create a model
model = playlistmodel.PlaylistModel(playlist.id, None)
for row in range(rows):
newrow = model.insert_row(session, row)
plr = model._insert_row(session, row)
newrow = plr.plr_rownum
model.playlist_rows[newrow].note = str(newrow)
session.commit()
@ -27,7 +28,7 @@ def test_insert_row(monkeypatch, Session):
# Create a model
model = playlistmodel.PlaylistModel(playlist.id, None)
assert model.rowCount() == 0
model.insert_row(session, 0)
model._insert_row(session, 0)
assert model.rowCount() == 1
@ -39,7 +40,7 @@ def test_insert_high_row(monkeypatch, Session):
# Create a model
model = playlistmodel.PlaylistModel(playlist.id, None)
assert model.rowCount() == 0
model.insert_row(session, 5)
model._insert_row(session, 5)
assert model.rowCount() == 1
@ -189,3 +190,20 @@ def test_move_rows_test8(monkeypatch, Session):
assert model.playlist_rows[row].plr_rownum == row
new_order.append(int(model.playlist_rows[row].note))
assert new_order == [0, 1, 2, 3, 4, 7, 8, 10, 5, 6, 9]
def test_insert_header_row(monkeypatch, Session):
# insert header row
monkeypatch.setattr(playlistmodel, "Session", Session)
note_text = "test text"
with Session() as session:
model = create_model_with_playlist_rows(session, 11)
row_number = model.insert_header_row(None, note_text)
session.flush()
assert model.rowCount() == row_number + 1
prd = model.playlist_rows[row_number]
# Test against edit_role because display_role for headers is
# handled differently (sets up row span)
assert model.edit_role(row_number, playlistmodel.Col.NOTE.value, prd) == note_text