Compare commits

...

3 Commits

Author SHA1 Message Date
Keith Edmunds
9554336860 Move SQLAlchemy statements to models.py 2023-10-31 13:04:21 +00:00
Keith Edmunds
813b325029 Black reformatting, tidying 2023-10-31 08:15:24 +00:00
Keith Edmunds
734d5cb545 Make MusicMusterSignals a singleton class
Moved into datastructures.py
2023-10-31 08:14:34 +00:00
7 changed files with 164 additions and 175 deletions

20
app/datastructures.py Normal file
View File

@ -0,0 +1,20 @@
from PyQt6.QtCore import pyqtSignal, QObject
from helpers import singleton
@singleton
class MusicMusterSignals(QObject):
"""
Class for all MusicMuster signals. See:
- https://zetcode.com/gui/pyqt5/eventssignals/
- https://stackoverflow.com/questions/62654525/
emit-a-signal-from-another-class-to-main-class
and Singleton class at
https://refactoring.guru/design-patterns/singleton/python/example#example-0
"""
enable_escape_signal = pyqtSignal(bool)
set_next_track_signal = pyqtSignal(int, int)
span_cells_signal = pyqtSignal(int, int, int, int)
add_track_to_playlist_signal = pyqtSignal(int, int, int, str)

View File

@ -1,3 +1,4 @@
import functools
import os import os
import psutil import psutil
import shutil import shutil
@ -154,23 +155,21 @@ def get_file_metadata(filepath: str) -> dict:
# Get title, artist, bitrate, duration, path # Get title, artist, bitrate, duration, path
metadata: Dict[str, str | int | float] = get_tags(filepath) metadata: Dict[str, str | int | float] = get_tags(filepath)
metadata['mtime'] = os.path.getmtime(filepath) metadata["mtime"] = os.path.getmtime(filepath)
# Set start_gap, fade_at and silence_at # Set start_gap, fade_at and silence_at
audio = get_audio_segment(filepath) audio = get_audio_segment(filepath)
if not audio: if not audio:
audio_values = dict( audio_values = dict(start_gap=0, fade_at=0, silence_at=0)
start_gap=0,
fade_at=0,
silence_at=0
)
else: else:
audio_values = dict( audio_values = dict(
start_gap=leading_silence(audio), start_gap=leading_silence(audio),
fade_at=int(round(fade_point(audio) / 1000, Config.MILLISECOND_SIGFIGS) * 1000), fade_at=int(
round(fade_point(audio) / 1000, Config.MILLISECOND_SIGFIGS) * 1000
),
silence_at=int( silence_at=int(
round(trailing_silence(audio) / 1000, Config.MILLISECOND_SIGFIGS) * 1000 round(trailing_silence(audio) / 1000, Config.MILLISECOND_SIGFIGS) * 1000
) ),
) )
metadata |= audio_values metadata |= audio_values
@ -381,6 +380,22 @@ def show_warning(parent: QMainWindow, title: str, msg: str) -> None:
QMessageBox.warning(parent, title, msg, buttons=QMessageBox.StandardButton.Cancel) QMessageBox.warning(parent, title, msg, buttons=QMessageBox.StandardButton.Cancel)
def singleton(cls):
"""
Make a class a Singleton class (see
https://realpython.com/primer-on-python-decorators/#creating-singletons)
"""
@functools.wraps(cls)
def wrapper_singleton(*args, **kwargs):
if not wrapper_singleton.instance:
wrapper_singleton.instance = cls(*args, **kwargs)
return wrapper_singleton.instance
wrapper_singleton.instance = None
return wrapper_singleton
def trailing_silence( def trailing_silence(
audio_segment: AudioSegment, audio_segment: AudioSegment,
silence_threshold: int = -50, silence_threshold: int = -50,

View File

@ -11,6 +11,7 @@ from typing import List, Optional, Sequence
from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy import ( from sqlalchemy import (
bindparam,
Boolean, Boolean,
DateTime, DateTime,
delete, delete,
@ -49,9 +50,9 @@ class Carts(Base):
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
cart_number: Mapped[int] = mapped_column(unique=True) cart_number: Mapped[int] = mapped_column(unique=True)
name: Mapped[str] = mapped_column(String(256), index=True) name: Mapped[str] = mapped_column(String(256), index=True)
duration: Mapped[int] = mapped_column(index=True) duration: Mapped[Optional[int]] = mapped_column(index=True)
path: Mapped[str] = mapped_column(String(2048), index=False) path: Mapped[Optional[str]] = mapped_column(String(2048), index=False)
enabled: Mapped[bool] = mapped_column(default=False) enabled: Mapped[Optional[bool]] = mapped_column(default=False)
def __repr__(self) -> str: def __repr__(self) -> str:
return ( return (
@ -63,7 +64,7 @@ class Carts(Base):
self, self,
session: scoped_session, session: scoped_session,
cart_number: int, cart_number: int,
name: Optional[str] = None, name: str,
duration: Optional[int] = None, duration: Optional[int] = None,
path: Optional[str] = None, path: Optional[str] = None,
enabled: bool = True, enabled: bool = True,
@ -134,14 +135,11 @@ class NoteColours(Base):
if not text: if not text:
return None return None
for rec in ( for rec in session.scalars(
session.scalars(
select(NoteColours) select(NoteColours)
.filter(NoteColours.enabled.is_(True)) .filter(NoteColours.enabled.is_(True))
.order_by(NoteColours.order) .order_by(NoteColours.order)
) ).all():
.all()
):
if rec.is_regex: if rec.is_regex:
flags = re.UNICODE flags = re.UNICODE
if not rec.is_casesensitive: if not rec.is_casesensitive:
@ -202,14 +200,11 @@ class Playdates(Base):
def played_after(session: scoped_session, since: datetime) -> Sequence["Playdates"]: def played_after(session: scoped_session, since: datetime) -> Sequence["Playdates"]:
"""Return a list of Playdates objects since passed time""" """Return a list of Playdates objects since passed time"""
return ( return session.scalars(
session.scalars(
select(Playdates) select(Playdates)
.where(Playdates.lastplayed >= since) .where(Playdates.lastplayed >= since)
.order_by(Playdates.lastplayed) .order_by(Playdates.lastplayed)
) ).all()
.all()
)
class Playlists(Base): class Playlists(Base):
@ -285,32 +280,25 @@ class Playlists(Base):
def get_all(cls, session: scoped_session) -> Sequence["Playlists"]: def get_all(cls, session: scoped_session) -> Sequence["Playlists"]:
"""Returns a list of all playlists ordered by last use""" """Returns a list of all playlists ordered by last use"""
return ( return session.scalars(
session.scalars(
select(cls) select(cls)
.filter(cls.is_template.is_(False)) .filter(cls.is_template.is_(False))
.order_by(cls.tab.desc(), cls.last_used.desc()) .order_by(cls.tab.desc(), cls.last_used.desc())
) ).all()
.all()
)
@classmethod @classmethod
def get_all_templates(cls, session: scoped_session) -> Sequence["Playlists"]: def get_all_templates(cls, session: scoped_session) -> Sequence["Playlists"]:
"""Returns a list of all templates ordered by name""" """Returns a list of all templates ordered by name"""
return ( return session.scalars(
session.scalars(
select(cls).filter(cls.is_template.is_(True)).order_by(cls.name) select(cls).filter(cls.is_template.is_(True)).order_by(cls.name)
) ).all()
.all()
)
@classmethod @classmethod
def get_closed(cls, session: scoped_session) -> Sequence["Playlists"]: def get_closed(cls, session: scoped_session) -> Sequence["Playlists"]:
"""Returns a list of all closed playlists ordered by last use""" """Returns a list of all closed playlists ordered by last use"""
return ( return session.scalars(
session.scalars(
select(cls) select(cls)
.filter( .filter(
cls.tab.is_(None), cls.tab.is_(None),
@ -318,9 +306,7 @@ class Playlists(Base):
cls.deleted.is_(False), cls.deleted.is_(False),
) )
.order_by(cls.last_used.desc()) .order_by(cls.last_used.desc())
) ).all()
.all()
)
@classmethod @classmethod
def get_open(cls, session: scoped_session) -> Sequence[Optional["Playlists"]]: def get_open(cls, session: scoped_session) -> Sequence[Optional["Playlists"]]:
@ -328,10 +314,9 @@ class Playlists(Base):
Return a list of loaded playlists ordered by tab order. Return a list of loaded playlists ordered by tab order.
""" """
return ( return session.scalars(
session.scalars(select(cls).where(cls.tab.is_not(None)).order_by(cls.tab)) select(cls).where(cls.tab.is_not(None)).order_by(cls.tab)
.all() ).all()
)
def mark_open(self, session: scoped_session, tab_index: int) -> None: def mark_open(self, session: scoped_session, tab_index: int) -> None:
"""Mark playlist as loaded and used now""" """Mark playlist as loaded and used now"""
@ -433,12 +418,9 @@ class PlaylistRows(Base):
def copy_playlist(session: scoped_session, src_id: int, dst_id: int) -> None: def copy_playlist(session: scoped_session, src_id: int, dst_id: int) -> None:
"""Copy playlist entries""" """Copy playlist entries"""
src_rows = ( src_rows = session.scalars(
session.scalars(
select(PlaylistRows).filter(PlaylistRows.playlist_id == src_id) select(PlaylistRows).filter(PlaylistRows.playlist_id == src_id)
) ).all()
.all()
)
for plr in src_rows: for plr in src_rows:
PlaylistRows( PlaylistRows(
@ -512,14 +494,11 @@ class PlaylistRows(Base):
Ensure the row numbers for passed playlist have no gaps Ensure the row numbers for passed playlist have no gaps
""" """
plrs = ( plrs = session.scalars(
session.scalars(
select(PlaylistRows) select(PlaylistRows)
.where(PlaylistRows.playlist_id == playlist_id) .where(PlaylistRows.playlist_id == playlist_id)
.order_by(PlaylistRows.plr_rownum) .order_by(PlaylistRows.plr_rownum)
) ).all()
.all()
)
for i, plr in enumerate(plrs): for i, plr in enumerate(plrs):
plr.plr_rownum = i plr.plr_rownum = i
@ -536,14 +515,11 @@ class PlaylistRows(Base):
PlaylistRows objects PlaylistRows objects
""" """
plrs = ( plrs = session.scalars(
session.scalars(
select(cls) select(cls)
.where(cls.playlist_id == playlist_id, cls.id.in_(plr_ids)) .where(cls.playlist_id == playlist_id, cls.id.in_(plr_ids))
.order_by(cls.plr_rownum) .order_by(cls.plr_rownum)
) ).all()
.all()
)
return plrs return plrs
@ -581,14 +557,11 @@ class PlaylistRows(Base):
have been played. have been played.
""" """
plrs = ( plrs = session.scalars(
session.scalars(
select(cls) select(cls)
.where(cls.playlist_id == playlist_id, cls.played.is_(True)) .where(cls.playlist_id == playlist_id, cls.played.is_(True))
.order_by(cls.plr_rownum) .order_by(cls.plr_rownum)
) ).all()
.all()
)
return plrs return plrs
@ -626,8 +599,7 @@ class PlaylistRows(Base):
have not been played. have not been played.
""" """
plrs = ( plrs = session.scalars(
session.scalars(
select(cls) select(cls)
.where( .where(
cls.playlist_id == playlist_id, cls.playlist_id == playlist_id,
@ -635,12 +607,17 @@ class PlaylistRows(Base):
cls.played.is_(False), cls.played.is_(False),
) )
.order_by(cls.plr_rownum) .order_by(cls.plr_rownum)
) ).all()
.all()
)
return plrs return plrs
@classmethod
def insert_row(
cls, session: scoped_session, playlist_id: int, new_row_number: int
) -> "PlaylistRows":
cls.move_rows_down(session, playlist_id, new_row_number, 1)
return cls(session, playlist_id, new_row_number)
@staticmethod @staticmethod
def move_rows_down( def move_rows_down(
session: scoped_session, playlist_id: int, starting_row: int, move_by: int session: scoped_session, playlist_id: int, starting_row: int, move_by: int
@ -659,6 +636,26 @@ class PlaylistRows(Base):
.values(plr_rownum=PlaylistRows.plr_rownum + move_by) .values(plr_rownum=PlaylistRows.plr_rownum + move_by)
) )
@staticmethod
def update_plr_rownumbers(
session: scoped_session, playlist_id: int, sqla_map: List[dict[str, int]]
) -> None:
"""
Take a {plrid: plr_rownum} dictionary and update the row numbers accordingly
"""
# Update database. Ref:
# https://docs.sqlalchemy.org/en/20/tutorial/data_update.html#the-update-sql-expression-construct
stmt = (
update(PlaylistRows)
.where(
PlaylistRows.playlist_id == playlist_id,
PlaylistRows.id == bindparam("plrid"),
)
.values(plr_rownum=bindparam("plr_rownum"))
)
session.connection().execute(stmt, sqla_map)
class Settings(Base): class Settings(Base):
"""Manage settings""" """Manage settings"""

View File

@ -15,7 +15,6 @@ from datetime import datetime, timedelta
from pygame import mixer from pygame import mixer
from time import sleep from time import sleep
from typing import ( from typing import (
Callable,
cast, cast,
List, List,
Optional, Optional,
@ -69,6 +68,7 @@ import icons_rc # noqa F401
import music import music
from models import Base, Carts, Playdates, PlaylistRows, Playlists, Settings, Tracks from models import Base, Carts, Playdates, PlaylistRows, Playlists, Settings, Tracks
from config import Config from config import Config
from datastructures import MusicMusterSignals
from playlists import PlaylistTab from playlists import PlaylistTab
from ui.dlg_cart_ui import Ui_DialogCartEdit # type: ignore from ui.dlg_cart_ui import Ui_DialogCartEdit # type: ignore
from ui.dlg_TrackSelect_ui import Ui_Dialog # type: ignore from ui.dlg_TrackSelect_ui import Ui_Dialog # type: ignore
@ -238,20 +238,6 @@ class ImportTrack(QObject):
self.finished.emit(self.playlist) self.finished.emit(self.playlist)
class MusicMusterSignals(QObject):
"""
Class for all MusicMuster signals. See:
- https://zetcode.com/gui/pyqt5/eventssignals/
- https://stackoverflow.com/questions/62654525/
emit-a-signal-from-another-class-to-main-class
"""
enable_escape_signal = pyqtSignal(bool)
set_next_track_signal = pyqtSignal(int, int)
span_cells_signal = pyqtSignal(int, int, int, int)
add_track_to_playlist_signal = pyqtSignal(int, int, str)
class PlaylistTrack: class PlaylistTrack:
""" """
Used to provide a single reference point for specific playlist tracks, Used to provide a single reference point for specific playlist tracks,
@ -349,8 +335,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.previous_track_position: Optional[float] = None self.previous_track_position: Optional[float] = None
self.selected_plrs: Optional[List[PlaylistRows]] = None self.selected_plrs: Optional[List[PlaylistRows]] = None
self.signals = MusicMusterSignals()
self.set_main_window_size() self.set_main_window_size()
self.lblSumPlaytime = QLabel("") self.lblSumPlaytime = QLabel("")
self.statusbar.addPermanentWidget(self.lblSumPlaytime) self.statusbar.addPermanentWidget(self.lblSumPlaytime)
@ -379,6 +363,7 @@ class Window(QMainWindow, Ui_MainWindow):
self.timer10.start(10) self.timer10.start(10)
self.timer500.start(500) self.timer500.start(500)
self.timer1000.start(1000) self.timer1000.start(1000)
self.signals = MusicMusterSignals()
self.connect_signals_slots() self.connect_signals_slots()
def about(self) -> None: def about(self) -> None:
@ -731,7 +716,6 @@ class Window(QMainWindow, Ui_MainWindow):
playlist_tab = PlaylistTab( playlist_tab = PlaylistTab(
musicmuster=self, musicmuster=self,
playlist_id=playlist.id, playlist_id=playlist.id,
signals=self.signals,
) )
idx = self.tabPlaylist.addTab(playlist_tab, playlist.name) idx = self.tabPlaylist.addTab(playlist_tab, playlist.name)
self.tabPlaylist.setCurrentIndex(idx) self.tabPlaylist.setCurrentIndex(idx)
@ -1065,7 +1049,7 @@ class Window(QMainWindow, Ui_MainWindow):
with Session() as session: with Session() as session:
dlg = TrackSelectDialog( dlg = TrackSelectDialog(
session=session, session=session,
signals=self.signals, new_row_number=self.active_tab().get_selected_row_number(),
playlist_id=self.active_tab().playlist_id, playlist_id=self.active_tab().playlist_id,
) )
dlg.exec() dlg.exec()
@ -1923,7 +1907,7 @@ class TrackSelectDialog(QDialog):
def __init__( def __init__(
self, self,
session: scoped_session, session: scoped_session,
signals: MusicMusterSignals, new_row_number: int,
playlist_id: int, playlist_id: int,
*args, *args,
**kwargs, **kwargs,
@ -1934,7 +1918,7 @@ class TrackSelectDialog(QDialog):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.session = session self.session = session
self.signals = signals self.new_row_number = new_row_number
self.playlist_id = playlist_id self.playlist_id = playlist_id
self.ui = Ui_Dialog() self.ui = Ui_Dialog()
self.ui.setupUi(self) self.ui.setupUi(self)
@ -1946,6 +1930,7 @@ class TrackSelectDialog(QDialog):
self.ui.radioTitle.toggled.connect(self.title_artist_toggle) self.ui.radioTitle.toggled.connect(self.title_artist_toggle)
self.ui.searchString.textEdited.connect(self.chars_typed) self.ui.searchString.textEdited.connect(self.chars_typed)
self.track: Optional[Tracks] = None self.track: Optional[Tracks] = None
self.signals = MusicMusterSignals()
record = Settings.get_int_settings(self.session, "dbdialog_width") record = Settings.get_int_settings(self.session, "dbdialog_width")
width = record.f_int or 800 width = record.f_int or 800
@ -1974,7 +1959,9 @@ class TrackSelectDialog(QDialog):
track_id = None track_id = None
if track: if track:
track_id = track.id track_id = track.id
self.signals.add_track_to_playlist_signal.emit(self.playlist_id, track_id, note) self.signals.add_track_to_playlist_signal.emit(
self.playlist_id, self.new_row_number, track_id, note
)
def add_selected_and_close(self) -> None: def add_selected_and_close(self) -> None:
"""Handle Add and Close button""" """Handle Add and Close button"""

View File

@ -3,15 +3,12 @@ from enum import auto, Enum
from sqlalchemy import bindparam, update from sqlalchemy import bindparam, update
from typing import List, Optional, TYPE_CHECKING from typing import List, Optional, TYPE_CHECKING
from dbconfig import scoped_session, Session
from PyQt6.QtCore import ( from PyQt6.QtCore import (
QAbstractTableModel, QAbstractTableModel,
QModelIndex, QModelIndex,
Qt, Qt,
QVariant, QVariant,
) )
from PyQt6.QtGui import ( from PyQt6.QtGui import (
QBrush, QBrush,
QColor, QColor,
@ -19,14 +16,15 @@ from PyQt6.QtGui import (
) )
from config import Config from config import Config
from playlists import PlaylistTab from datastructures import MusicMusterSignals
from dbconfig import scoped_session, Session
from helpers import ( from helpers import (
file_is_unreadable, file_is_unreadable,
) )
from models import PlaylistRows, Tracks from models import PlaylistRows, Tracks
if TYPE_CHECKING:
from musicmuster import MusicMusterSignals HEADER_NOTES_COLUMN = 1
class Col(Enum): class Col(Enum):
@ -41,9 +39,6 @@ class Col(Enum):
NOTE = auto() NOTE = auto()
HEADER_NOTES_COLUMN = 1
class PlaylistRowData: class PlaylistRowData:
def __init__(self, plr: PlaylistRows) -> None: def __init__(self, plr: PlaylistRows) -> None:
""" """
@ -98,18 +93,15 @@ class PlaylistModel(QAbstractTableModel):
def __init__( def __init__(
self, self,
playlist: PlaylistTab,
playlist_id: int, playlist_id: int,
signals: "MusicMusterSignals",
*args, *args,
**kwargs, **kwargs,
): ):
self.playlist = playlist
self.playlist_id = playlist_id self.playlist_id = playlist_id
self.signals = signals
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.playlist_rows: dict[int, PlaylistRowData] = {} self.playlist_rows: dict[int, PlaylistRowData] = {}
self.signals = MusicMusterSignals()
self.signals.add_track_to_playlist_signal.connect(self.add_track) self.signals.add_track_to_playlist_signal.connect(self.add_track)
@ -122,7 +114,11 @@ class PlaylistModel(QAbstractTableModel):
) )
def add_track( def add_track(
self, playlist_id: int, track: Optional[Tracks], note: Optional[str] self,
playlist_id: int,
new_row_number: int,
track_id: Optional[int],
note: Optional[str],
) -> None: ) -> None:
""" """
Add track if it's for our playlist Add track if it's for our playlist
@ -132,14 +128,12 @@ class PlaylistModel(QAbstractTableModel):
if playlist_id != self.playlist_id: if playlist_id != self.playlist_id:
return return
row_number = self.playlist.get_selected_row_number()
# Insert track if we have one # Insert track if we have one
if track: if track_id:
self.insert_track_row(row_number, track, note) self.insert_track_row(new_row_number, track_id, note)
# If we only have a note, add as a header row # If we only have a note, add as a header row
elif note: elif note:
self.insert_header_row(row_number, note) self.insert_header_row(new_row_number, note)
else: else:
# No track, no note, no point # No track, no note, no point
return return
@ -366,16 +360,8 @@ class PlaylistModel(QAbstractTableModel):
else: else:
new_row_number = row_number new_row_number = row_number
# Move rows below new row down
stmt = (
update(PlaylistRows)
.where(PlaylistRows.plr_rownum >= new_row_number)
.values({PlaylistRows.plr_rownum: PlaylistRows.plr_rownum + 1})
)
session.execute(stmt)
# Insert the new row and return it # Insert the new row and return it
return PlaylistRows(session, self.playlist_id, new_row_number) return PlaylistRows.insert_row(session, self.playlist_id, new_row_number)
def insert_track_row( def insert_track_row(
self, row_number: Optional[int], track_id: int, text: Optional[str] self, row_number: Optional[int], track_id: int, text: Optional[str]
@ -452,20 +438,8 @@ class PlaylistModel(QAbstractTableModel):
plrid = self.playlist_rows[oldrow].plrid plrid = self.playlist_rows[oldrow].plrid
sqla_map.append({"plrid": plrid, "plr_rownum": newrow}) sqla_map.append({"plrid": plrid, "plr_rownum": newrow})
# Update database. Ref:
# https://docs.sqlalchemy.org/en/20/tutorial/data_update.html#the-update-sql-expression-construct
stmt = (
update(PlaylistRows)
.where(
PlaylistRows.playlist_id == self.playlist_id,
PlaylistRows.id == bindparam("plrid"),
)
.values(plr_rownum=bindparam("plr_rownum"))
)
with Session() as session: with Session() as session:
session.connection().execute(stmt, sqla_map) PlaylistRows.update_plr_rownumbers(session, self.playlist_id, sqla_map)
# Update playlist_rows # Update playlist_rows
self.refresh_data(session) self.refresh_data(session)

View File

@ -6,7 +6,6 @@ import threading
import obsws_python as obs # type: ignore import obsws_python as obs # type: ignore
# from collections import namedtuple
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Any, cast, List, Optional, Tuple, TYPE_CHECKING from typing import Any, cast, List, Optional, Tuple, TYPE_CHECKING
@ -36,8 +35,9 @@ from PyQt6.QtWidgets import (
QStyleOption, QStyleOption,
) )
from config import Config from datastructures import MusicMusterSignals
from dbconfig import Session, scoped_session from dbconfig import Session, scoped_session
from config import Config
from helpers import ( from helpers import (
ask_yes_no, ask_yes_no,
file_is_unreadable, file_is_unreadable,
@ -48,10 +48,8 @@ from helpers import (
set_track_metadata, set_track_metadata,
) )
from log import log from log import log
from models import Playlists, PlaylistRows, Settings, Tracks, NoteColours from models import Playlists, PlaylistRows, Settings, Tracks, NoteColours
from playlistmodel import PlaylistModel
import playlistmodel
if TYPE_CHECKING: if TYPE_CHECKING:
from musicmuster import Window, MusicMusterSignals from musicmuster import Window, MusicMusterSignals
@ -66,9 +64,9 @@ class EscapeDelegate(QStyledItemDelegate):
- checks with user before abandoning edit on Escape - checks with user before abandoning edit on Escape
""" """
def __init__(self, parent, signals: "MusicMusterSignals") -> None: def __init__(self, parent) -> None:
super().__init__(parent) super().__init__(parent)
self.signals = signals self.signals = MusicMusterSignals()
def createEditor( def createEditor(
self, self,
@ -80,7 +78,7 @@ class EscapeDelegate(QStyledItemDelegate):
Intercept createEditor call and make row just a little bit taller Intercept createEditor call and make row just a little bit taller
""" """
self.signals.enable_escape_signal.emit(False) signals.enable_escape_signal.emit(False)
if isinstance(self.parent(), PlaylistTab): if isinstance(self.parent(), PlaylistTab):
p = cast(PlaylistTab, self.parent()) p = cast(PlaylistTab, self.parent())
if isinstance(index.data(), str): if isinstance(index.data(), str):
@ -156,17 +154,15 @@ class PlaylistTab(QTableView):
self, self,
musicmuster: "Window", musicmuster: "Window",
playlist_id: int, playlist_id: int,
signals: "MusicMusterSignals",
) -> None: ) -> None:
super().__init__() super().__init__()
# Save passed settings # Save passed settings
self.musicmuster = musicmuster self.musicmuster = musicmuster
self.playlist_id = playlist_id self.playlist_id = playlist_id
self.signals = signals
# Set up widget # Set up widget
self.setItemDelegate(EscapeDelegate(self, self.signals)) self.setItemDelegate(EscapeDelegate(self))
self.setAlternatingRowColors(True) self.setAlternatingRowColors(True)
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
@ -194,6 +190,7 @@ class PlaylistTab(QTableView):
h_header.setStretchLastSection(True) h_header.setStretchLastSection(True)
# self.itemSelectionChanged.connect(self._select_event) # self.itemSelectionChanged.connect(self._select_event)
# self.signals.set_next_track_signal.connect(self._reset_next) # self.signals.set_next_track_signal.connect(self._reset_next)
self.signals = MusicMusterSignals()
self.signals.span_cells_signal.connect(self._span_cells) self.signals.span_cells_signal.connect(self._span_cells)
# Call self.eventFilter() for events # Call self.eventFilter() for events
@ -205,7 +202,7 @@ class PlaylistTab(QTableView):
# self.edit_cell_type: Optional[int] # self.edit_cell_type: Optional[int]
# Load playlist rows # Load playlist rows
self.setModel(playlistmodel.PlaylistModel(self, playlist_id, signals)) self.setModel(PlaylistModel(playlist_id))
self._set_column_widths() self._set_column_widths()
# kae def __repr__(self) -> str: # kae def __repr__(self) -> str:

View File

@ -4,13 +4,12 @@ from app.models import (
from app import playlistmodel from app import playlistmodel
from dbconfig import scoped_session from dbconfig import scoped_session
def create_model_with_playlist_rows( def create_model_with_playlist_rows(
session: scoped_session, rows: int session: scoped_session, rows: int
) -> "playlistmodel.PlaylistModel": ) -> "playlistmodel.PlaylistModel":
playlist = Playlists(session, "test playlist") playlist = Playlists(session, "test playlist")
# Create a model # Create a model
model = playlistmodel.PlaylistModel(playlist.id, None) model = playlistmodel.PlaylistModel(playlist.id)
for row in range(rows): for row in range(rows):
plr = model._insert_row(session, row) plr = model._insert_row(session, row)
newrow = plr.plr_rownum newrow = plr.plr_rownum