Compare commits
3 Commits
25771f5235
...
c58eb47cc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c58eb47cc1 | ||
|
|
847840251c | ||
|
|
f172eaaeb2 |
@ -247,11 +247,6 @@ class MusicMusterSignals(QObject):
|
|||||||
# Signals that the playlist_id passed should resize all rows.
|
# Signals that the playlist_id passed should resize all rows.
|
||||||
resize_rows_signal = pyqtSignal(int)
|
resize_rows_signal = pyqtSignal(int)
|
||||||
|
|
||||||
# Signal to open browser at songfacts or wikipedia page matching
|
|
||||||
# passed string.
|
|
||||||
search_songfacts_signal = pyqtSignal(str)
|
|
||||||
search_wikipedia_signal = pyqtSignal(str)
|
|
||||||
|
|
||||||
# Displays a warning dialog
|
# Displays a warning dialog
|
||||||
show_warning_signal = pyqtSignal(str, str)
|
show_warning_signal = pyqtSignal(str, str)
|
||||||
|
|
||||||
@ -284,14 +279,14 @@ class MusicMusterSignals(QObject):
|
|||||||
# Emited when a track starts playing
|
# Emited when a track starts playing
|
||||||
signal_track_started = pyqtSignal()
|
signal_track_started = pyqtSignal()
|
||||||
|
|
||||||
|
# Emitted when track ends or is manually faded
|
||||||
|
signal_track_ended = pyqtSignal(int)
|
||||||
|
|
||||||
# Used by model to signal spanning of cells to playlist for headers
|
# Used by model to signal spanning of cells to playlist for headers
|
||||||
span_cells_signal = pyqtSignal(int, int, int, int, int)
|
span_cells_signal = pyqtSignal(int, int, int, int, int)
|
||||||
|
|
||||||
# Dispay status message to user
|
# Dispay status message to user
|
||||||
status_message_signal = pyqtSignal(str, int)
|
status_message_signal = pyqtSignal(str, int)
|
||||||
|
|
||||||
# Emitted when track ends or is manually faded
|
|
||||||
signal_track_ended = pyqtSignal(int)
|
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|||||||
@ -101,7 +101,7 @@ class Music:
|
|||||||
if not self.player.get_position() > 0 and self.player.is_playing():
|
if not self.player.get_position() > 0 and self.player.is_playing():
|
||||||
return
|
return
|
||||||
|
|
||||||
self.signal_track_ended()
|
self.emit_signal_track_ended()
|
||||||
|
|
||||||
self.fader_worker = _FadeTrack(self.player, fade_seconds=fade_seconds)
|
self.fader_worker = _FadeTrack(self.player, fade_seconds=fade_seconds)
|
||||||
self.fader_worker.finished.connect(self.player.release)
|
self.fader_worker.finished.connect(self.player.release)
|
||||||
@ -225,7 +225,7 @@ class Music:
|
|||||||
log.debug(f"Volume reset from {volume=}")
|
log.debug(f"Volume reset from {volume=}")
|
||||||
sleep(0.1)
|
sleep(0.1)
|
||||||
|
|
||||||
def signal_track_ended(self) -> None:
|
def emit_signal_track_ended(self) -> None:
|
||||||
"""
|
"""
|
||||||
Multiple parts of the Music class can signal that the track has
|
Multiple parts of the Music class can signal that the track has
|
||||||
ended. Handle them all here to ensure that only one such signal
|
ended. Handle them all here to ensure that only one such signal
|
||||||
@ -254,7 +254,7 @@ class Music:
|
|||||||
self.player.stop()
|
self.player.stop()
|
||||||
self.player.release()
|
self.player.release()
|
||||||
self.player = None
|
self.player = None
|
||||||
self.signal_track_ended()
|
self.emit_signal_track_ended()
|
||||||
|
|
||||||
def track_end_event_handler(self, event: vlc.Event) -> None:
|
def track_end_event_handler(self, event: vlc.Event) -> None:
|
||||||
"""
|
"""
|
||||||
@ -262,4 +262,4 @@ class Music:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
log.debug("track_end_event_handler() called")
|
log.debug("track_end_event_handler() called")
|
||||||
self.signal_track_ended()
|
self.emit_signal_track_ended()
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from functools import partial
|
|||||||
from slugify import slugify # type: ignore
|
from slugify import slugify # type: ignore
|
||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
import argparse
|
import argparse
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, field
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -70,14 +70,14 @@ from classes import (
|
|||||||
MusicMusterSignals,
|
MusicMusterSignals,
|
||||||
PlaylistDTO,
|
PlaylistDTO,
|
||||||
QueryDTO,
|
QueryDTO,
|
||||||
TrackAndPlaylist,
|
SelectedRows,
|
||||||
TrackInfo,
|
TrackInfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from dialogs import TrackInsertDialog
|
from dialogs import TrackInsertDialog
|
||||||
from file_importer import FileImporter
|
from file_importer import FileImporter
|
||||||
from helpers import ask_yes_no, file_is_unreadable, get_name
|
from helpers import file_is_unreadable, get_name
|
||||||
from log import log, log_call
|
from log import log, log_call
|
||||||
from playlistmodel import PlaylistModel, PlaylistProxyModel
|
from playlistmodel import PlaylistModel, PlaylistProxyModel
|
||||||
from playlistrow import PlaylistRow, TrackSequence
|
from playlistrow import PlaylistRow, TrackSequence
|
||||||
@ -104,15 +104,6 @@ class SignalMonitor:
|
|||||||
self.signals.resize_rows_signal.connect(
|
self.signals.resize_rows_signal.connect(
|
||||||
partial(self.show_signal, "resize_rows_signal ")
|
partial(self.show_signal, "resize_rows_signal ")
|
||||||
)
|
)
|
||||||
self.signals.search_songfacts_signal.connect(
|
|
||||||
partial(self.show_signal, "search_songfacts_signal ")
|
|
||||||
)
|
|
||||||
self.signals.search_wikipedia_signal.connect(
|
|
||||||
partial(self.show_signal, "search_wikipedia_signal ")
|
|
||||||
)
|
|
||||||
self.signals.show_warning_signal.connect(
|
|
||||||
partial(self.show_signal, "show_warning_signal ")
|
|
||||||
)
|
|
||||||
self.signals.signal_add_track_to_header.connect(
|
self.signals.signal_add_track_to_header.connect(
|
||||||
partial(self.show_signal, "signal_add_track_to_header ")
|
partial(self.show_signal, "signal_add_track_to_header ")
|
||||||
)
|
)
|
||||||
@ -152,17 +143,12 @@ class SignalMonitor:
|
|||||||
log.debug(f"{name=}, args={args}")
|
log.debug(f"{name=}, args={args}")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class Current:
|
class Current:
|
||||||
base_model: PlaylistModel
|
base_model: PlaylistModel
|
||||||
proxy_model: PlaylistProxyModel
|
proxy_model: PlaylistProxyModel
|
||||||
playlist_id: int = 0
|
playlist_id: int
|
||||||
selected_row_numbers: list[int] = []
|
selected_row_numbers: list[int] = field(default_factory=list)
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return (
|
|
||||||
f"<Current(base_model={self.base_model}, proxy_model={self.proxy_model}, "
|
|
||||||
f"playlist_id={self.playlist_id}, selected_rows={self.selected_row_numbers}>"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class DownloadCSV(QDialog):
|
class DownloadCSV(QDialog):
|
||||||
@ -1225,7 +1211,7 @@ class Window(QMainWindow):
|
|||||||
self.disable_selection_timing = False
|
self.disable_selection_timing = False
|
||||||
self.catch_return_key = False
|
self.catch_return_key = False
|
||||||
self.importer: FileImporter | None = None
|
self.importer: FileImporter | None = None
|
||||||
self.current = Current()
|
self.current: Current | None = None
|
||||||
self.track_sequence = TrackSequence()
|
self.track_sequence = TrackSequence()
|
||||||
self.signals = MusicMusterSignals()
|
self.signals = MusicMusterSignals()
|
||||||
self.connect_signals_slots()
|
self.connect_signals_slots()
|
||||||
@ -1255,7 +1241,10 @@ class Window(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Don't allow window to close when a track is playing
|
# Don't allow window to close when a track is playing
|
||||||
if self.track_sequence.current and self.track_sequence.current.music.is_playing():
|
if (
|
||||||
|
self.track_sequence.current
|
||||||
|
and self.track_sequence.current.music.is_playing()
|
||||||
|
):
|
||||||
event.ignore()
|
event.ignore()
|
||||||
helpers.show_warning(
|
helpers.show_warning(
|
||||||
self, "Track playing", "Can't close application while track is playing"
|
self, "Track playing", "Can't close application while track is playing"
|
||||||
@ -1508,6 +1497,9 @@ class Window(QMainWindow):
|
|||||||
but unused.
|
but unused.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
playlist = ds.playlist_by_id(self.current.playlist_id)
|
playlist = ds.playlist_by_id(self.current.playlist_id)
|
||||||
if playlist:
|
if playlist:
|
||||||
if helpers.ask_yes_no(
|
if helpers.ask_yes_no(
|
||||||
@ -1532,6 +1524,9 @@ class Window(QMainWindow):
|
|||||||
def save_as_template(self, checked: bool = False) -> None:
|
def save_as_template(self, checked: bool = False) -> None:
|
||||||
"""Save current playlist as template"""
|
"""Save current playlist as template"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
template_names = [a.name for a in ds.playlists_templates_all()]
|
template_names = [a.name for a in ds.playlists_templates_all()]
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@ -1621,6 +1616,9 @@ class Window(QMainWindow):
|
|||||||
Show query dialog with query_id selected
|
Show query dialog with query_id selected
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
# Keep a reference else it will be gc'd
|
# Keep a reference else it will be gc'd
|
||||||
self.query_dialog = QueryDialog(self.current.playlist_id, query_id)
|
self.query_dialog = QueryDialog(self.current.playlist_id, query_id)
|
||||||
self.query_dialog.exec()
|
self.query_dialog.exec()
|
||||||
@ -1738,14 +1736,13 @@ class Window(QMainWindow):
|
|||||||
self.tabBar = self.playlist_section.tabPlaylist.tabBar()
|
self.tabBar = self.playlist_section.tabPlaylist.tabBar()
|
||||||
self.txtSearch.textChanged.connect(self.search_playlist_text_changed)
|
self.txtSearch.textChanged.connect(self.search_playlist_text_changed)
|
||||||
|
|
||||||
self.signals.enable_escape_signal.connect(self.enable_escape)
|
self.signals.enable_escape_signal.connect(self.enable_escape_signal_handler)
|
||||||
self.signals.search_songfacts_signal.connect(self.open_songfacts_browser)
|
|
||||||
self.signals.search_wikipedia_signal.connect(self.open_wikipedia_browser)
|
|
||||||
self.signals.show_warning_signal.connect(self.show_warning)
|
self.signals.show_warning_signal.connect(self.show_warning)
|
||||||
self.signals.signal_next_track_changed.connect(self.signal_next_track_changed_handler)
|
self.signals.signal_next_track_changed.connect(self.next_track_changed_handler)
|
||||||
self.signals.signal_set_next_track.connect(self.signal_set_next_track_handler)
|
self.signals.signal_set_next_track.connect(self.set_next_track_handler)
|
||||||
self.signals.status_message_signal.connect(self.show_status_message)
|
self.signals.status_message_signal.connect(self.show_status_message)
|
||||||
self.signals.signal_track_ended.connect(self.end_of_track_actions)
|
self.signals.signal_track_ended.connect(self.track_ended_handler)
|
||||||
|
self.signals.signal_playlist_selected_rows.connect(self.playlist_selected_rows_handler)
|
||||||
|
|
||||||
self.timer10.timeout.connect(self.tick_10ms)
|
self.timer10.timeout.connect(self.tick_10ms)
|
||||||
self.timer500.timeout.connect(self.tick_500ms)
|
self.timer500.timeout.connect(self.tick_500ms)
|
||||||
@ -1762,8 +1759,13 @@ class Window(QMainWindow):
|
|||||||
|
|
||||||
# TODO should be able to have the model handle row depending on
|
# TODO should be able to have the model handle row depending on
|
||||||
# how current_row_or_end is used
|
# how current_row_or_end is used
|
||||||
|
if self.current is None:
|
||||||
|
return 0 # hack, but should never be called without self.current set
|
||||||
|
|
||||||
if self.current.selected_row_numbers:
|
if self.current.selected_row_numbers:
|
||||||
return self.current.selected_row_numbers[0]
|
return self.current.selected_row_numbers[0]
|
||||||
|
if not self.current.base_model:
|
||||||
|
return 0 # hack, but mostly there WILL be a current model
|
||||||
return self.current.base_model.rowCount()
|
return self.current.base_model.rowCount()
|
||||||
|
|
||||||
def debug(self, checked: bool = False) -> None:
|
def debug(self, checked: bool = False) -> None:
|
||||||
@ -1806,7 +1808,7 @@ class Window(QMainWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def enable_escape(self, enabled: bool) -> None:
|
def enable_escape_signal_handler(self, enabled: bool) -> None:
|
||||||
"""
|
"""
|
||||||
Manage signal to enable/disable handling ESC character.
|
Manage signal to enable/disable handling ESC character.
|
||||||
|
|
||||||
@ -1818,7 +1820,7 @@ class Window(QMainWindow):
|
|||||||
self.menu_actions["clear_selection"].setEnabled(enabled)
|
self.menu_actions["clear_selection"].setEnabled(enabled)
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def end_of_track_actions(self) -> None:
|
def track_ended_handler(self) -> None:
|
||||||
"""
|
"""
|
||||||
Called by signal_track_ended
|
Called by signal_track_ended
|
||||||
|
|
||||||
@ -1849,6 +1851,9 @@ class Window(QMainWindow):
|
|||||||
def export_playlist_tab(self, checked: bool = False) -> None:
|
def export_playlist_tab(self, checked: bool = False) -> None:
|
||||||
"""Export the current playlist to an m3u file"""
|
"""Export the current playlist to an m3u file"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
playlist_id = self.current.playlist_id
|
playlist_id = self.current.playlist_id
|
||||||
|
|
||||||
playlist = ds.playlist_by_id(playlist_id)
|
playlist = ds.playlist_by_id(playlist_id)
|
||||||
@ -1921,7 +1926,7 @@ class Window(QMainWindow):
|
|||||||
self.current.base_model.hide_played_tracks(True)
|
self.current.base_model.hide_played_tracks(True)
|
||||||
|
|
||||||
# Reset row heights
|
# Reset row heights
|
||||||
self._active_tab().resize_rows()
|
self.signals.resize_rows_signal.emit(self.current.playlist_id)
|
||||||
|
|
||||||
def import_files_wrapper(self, checked: bool = False) -> None:
|
def import_files_wrapper(self, checked: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1930,12 +1935,18 @@ class Window(QMainWindow):
|
|||||||
|
|
||||||
# We need to keep a reference to the FileImporter else it will be
|
# We need to keep a reference to the FileImporter else it will be
|
||||||
# garbage collected while import threads are still running
|
# garbage collected while import threads are still running
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
self.importer = FileImporter(self.current.base_model, self.current_row_or_end())
|
self.importer = FileImporter(self.current.base_model, self.current_row_or_end())
|
||||||
self.importer.start()
|
self.importer.start()
|
||||||
|
|
||||||
def insert_header(self, checked: bool = False) -> None:
|
def insert_header(self, checked: bool = False) -> None:
|
||||||
"""Show dialog box to enter header text and add to playlist"""
|
"""Show dialog box to enter header text and add to playlist"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
# Get header text
|
# Get header text
|
||||||
dlg: QInputDialog = QInputDialog(self)
|
dlg: QInputDialog = QInputDialog(self)
|
||||||
dlg.setInputMode(QInputDialog.InputMode.TextInput)
|
dlg.setInputMode(QInputDialog.InputMode.TextInput)
|
||||||
@ -1954,6 +1965,9 @@ class Window(QMainWindow):
|
|||||||
def insert_track(self, checked: bool = False) -> None:
|
def insert_track(self, checked: bool = False) -> None:
|
||||||
"""Show dialog box to select and add track from database"""
|
"""Show dialog box to select and add track from database"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
dlg = TrackInsertDialog(parent=self, playlist_id=self.current.playlist_id)
|
dlg = TrackInsertDialog(parent=self, playlist_id=self.current.playlist_id)
|
||||||
dlg.exec()
|
dlg.exec()
|
||||||
|
|
||||||
@ -1981,7 +1995,7 @@ class Window(QMainWindow):
|
|||||||
if not track_info:
|
if not track_info:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.signals.search_songfacts_signal.emit(track_info.title)
|
self.open_songfacts_browser(track_info.title)
|
||||||
|
|
||||||
def lookup_row_in_wikipedia(self, checked: bool = False) -> None:
|
def lookup_row_in_wikipedia(self, checked: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1992,13 +2006,16 @@ class Window(QMainWindow):
|
|||||||
if not track_info:
|
if not track_info:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.signals.search_wikipedia_signal.emit(track_info.title)
|
self.open_wikipedia_browser(track_info.title)
|
||||||
|
|
||||||
def mark_rows_for_moving(self, checked: bool = False) -> None:
|
def mark_rows_for_moving(self, checked: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Cut rows ready for pasting.
|
Cut rows ready for pasting.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
# Save the selected PlaylistRows items ready for a later
|
# Save the selected PlaylistRows items ready for a later
|
||||||
# paste
|
# paste
|
||||||
self.move_source = MoveSource(
|
self.move_source = MoveSource(
|
||||||
@ -2013,7 +2030,7 @@ class Window(QMainWindow):
|
|||||||
Move passed playlist rows to another playlist
|
Move passed playlist rows to another playlist
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not row_numbers:
|
if not row_numbers or self.current is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Identify destination playlist
|
# Identify destination playlist
|
||||||
@ -2049,6 +2066,9 @@ class Window(QMainWindow):
|
|||||||
Move selected rows to another playlist
|
Move selected rows to another playlist
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
self.move_playlist_rows(self.current.selected_row_numbers)
|
self.move_playlist_rows(self.current.selected_row_numbers)
|
||||||
|
|
||||||
def move_unplayed(self, checked: bool = False) -> None:
|
def move_unplayed(self, checked: bool = False) -> None:
|
||||||
@ -2056,6 +2076,9 @@ class Window(QMainWindow):
|
|||||||
Move unplayed rows to another playlist
|
Move unplayed rows to another playlist
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
unplayed_rows = self.current.base_model.get_unplayed_rows()
|
unplayed_rows = self.current.base_model.get_unplayed_rows()
|
||||||
if not unplayed_rows:
|
if not unplayed_rows:
|
||||||
return
|
return
|
||||||
@ -2091,7 +2114,7 @@ class Window(QMainWindow):
|
|||||||
'checked' is a dummy parameter passed to us by the menu
|
'checked' is a dummy parameter passed to us by the menu
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not self.move_source:
|
if not self.move_source or self.current is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
to_playlist_model = self.current.base_model
|
to_playlist_model = self.current.base_model
|
||||||
@ -2106,7 +2129,7 @@ class Window(QMainWindow):
|
|||||||
from_rows, to_row, to_playlist_model.playlist_id
|
from_rows, to_row, to_playlist_model.playlist_id
|
||||||
)
|
)
|
||||||
|
|
||||||
self._active_tab().resize_rows()
|
self.signals.resize_rows_signal.emit(self.current.playlist_id)
|
||||||
self._active_tab().clear_selection()
|
self._active_tab().clear_selection()
|
||||||
|
|
||||||
# If we move a row to immediately under the current track, make
|
# If we move a row to immediately under the current track, make
|
||||||
@ -2116,7 +2139,7 @@ class Window(QMainWindow):
|
|||||||
and self.track_sequence.current.playlist_id == to_playlist_model.playlist_id
|
and self.track_sequence.current.playlist_id == to_playlist_model.playlist_id
|
||||||
and to_row == self.track_sequence.current.row_number + 1
|
and to_row == self.track_sequence.current.row_number + 1
|
||||||
):
|
):
|
||||||
to_playlist_model.set_next_row(to_row)
|
to_playlist_model.set_next_row_handler(to_row)
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def play_next(self, position: float | None = None, checked: bool = False) -> None:
|
def play_next(self, position: float | None = None, checked: bool = False) -> None:
|
||||||
@ -2159,7 +2182,7 @@ class Window(QMainWindow):
|
|||||||
if self.track_sequence.current:
|
if self.track_sequence.current:
|
||||||
self.track_sequence.current.fade()
|
self.track_sequence.current.fade()
|
||||||
|
|
||||||
# Move next track to current track. end_of_track_actions() will
|
# Move next track to current track. signal_track_ended_handler() will
|
||||||
# have been called when previous track ended or when fade() was
|
# have been called when previous track ended or when fade() was
|
||||||
# called above, and that in turn will have saved current track to
|
# called above, and that in turn will have saved current track to
|
||||||
# previous_track
|
# previous_track
|
||||||
@ -2267,6 +2290,9 @@ class Window(QMainWindow):
|
|||||||
def preview_mark(self) -> None:
|
def preview_mark(self) -> None:
|
||||||
"""Set intro time"""
|
"""Set intro time"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
if self.preview_manager.is_playing():
|
if self.preview_manager.is_playing():
|
||||||
track_id = self.preview_manager.track_id
|
track_id = self.preview_manager.track_id
|
||||||
row_number = self.preview_manager.row_number
|
row_number = self.preview_manager.row_number
|
||||||
@ -2308,6 +2334,9 @@ class Window(QMainWindow):
|
|||||||
Rename current playlist. checked is passed by menu but not used here
|
Rename current playlist. checked is passed by menu but not used here
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
playlist = ds.playlist_by_id(self.current.playlist_id)
|
playlist = ds.playlist_by_id(self.current.playlist_id)
|
||||||
if playlist:
|
if playlist:
|
||||||
new_name = self.get_playlist_name(playlist.name)
|
new_name = self.get_playlist_name(playlist.name)
|
||||||
@ -2425,6 +2454,9 @@ class Window(QMainWindow):
|
|||||||
Incremental search of playlist
|
Incremental search of playlist
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
self.current.proxy_model.set_incremental_search(self.txtSearch.text())
|
self.current.proxy_model.set_incremental_search(self.txtSearch.text())
|
||||||
|
|
||||||
def selected_or_next_track_info(self) -> PlaylistRow | None:
|
def selected_or_next_track_info(self) -> PlaylistRow | None:
|
||||||
@ -2433,6 +2465,9 @@ class Window(QMainWindow):
|
|||||||
next track. If no next track, return None.
|
next track. If no next track, return None.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return None
|
||||||
|
|
||||||
row_number: int | None = None
|
row_number: int | None = None
|
||||||
|
|
||||||
if self.current.selected_row_numbers:
|
if self.current.selected_row_numbers:
|
||||||
@ -2465,6 +2500,9 @@ class Window(QMainWindow):
|
|||||||
Set currently-selected row on visible playlist tab as next track
|
Set currently-selected row on visible playlist tab as next track
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
self.signals.signal_set_next_row.emit(self.current.playlist_id)
|
self.signals.signal_set_next_row.emit(self.current.playlist_id)
|
||||||
self.clear_selection()
|
self.clear_selection()
|
||||||
|
|
||||||
@ -2503,6 +2541,9 @@ class Window(QMainWindow):
|
|||||||
def show_track(self, playlist_track: PlaylistRow) -> None:
|
def show_track(self, playlist_track: PlaylistRow) -> None:
|
||||||
"""Scroll to show track"""
|
"""Scroll to show track"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
# Switch to the correct tab
|
# Switch to the correct tab
|
||||||
playlist_id = playlist_track.playlist_id
|
playlist_id = playlist_track.playlist_id
|
||||||
if not playlist_id:
|
if not playlist_id:
|
||||||
@ -2521,7 +2562,20 @@ class Window(QMainWindow):
|
|||||||
|
|
||||||
self._active_tab().scroll_to_top(playlist_track.row_number)
|
self._active_tab().scroll_to_top(playlist_track.row_number)
|
||||||
|
|
||||||
def signal_set_next_track_handler(self, plr: PlaylistRow) -> None:
|
def playlist_selected_rows_handler(
|
||||||
|
self, selected_rows: SelectedRows
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Handle signal_playlist_selected_rows to keep track of which rows
|
||||||
|
are selected in the current model
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.current is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.current.selected_row_numbers = selected_rows.rows
|
||||||
|
|
||||||
|
def set_next_track_handler(self, plr: PlaylistRow) -> None:
|
||||||
"""
|
"""
|
||||||
Handle signal_set_next_track
|
Handle signal_set_next_track
|
||||||
"""
|
"""
|
||||||
@ -2529,7 +2583,7 @@ class Window(QMainWindow):
|
|||||||
self.track_sequence.set_next(plr)
|
self.track_sequence.set_next(plr)
|
||||||
self.signals.signal_next_track_changed.emit()
|
self.signals.signal_next_track_changed.emit()
|
||||||
|
|
||||||
def signal_next_track_changed_handler(self) -> None:
|
def next_track_changed_handler(self) -> None:
|
||||||
"""
|
"""
|
||||||
Handle next track changed
|
Handle next track changed
|
||||||
"""
|
"""
|
||||||
@ -2629,7 +2683,10 @@ class Window(QMainWindow):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# If track is playing, update track clocks time and colours
|
# If track is playing, update track clocks time and colours
|
||||||
if self.track_sequence.current and self.track_sequence.current.music.is_playing():
|
if (
|
||||||
|
self.track_sequence.current
|
||||||
|
and self.track_sequence.current.music.is_playing()
|
||||||
|
):
|
||||||
# Elapsed time
|
# Elapsed time
|
||||||
self.header_section.label_elapsed_timer.setText(
|
self.header_section.label_elapsed_timer.setText(
|
||||||
helpers.ms_to_mmss(self.track_sequence.current.time_playing())
|
helpers.ms_to_mmss(self.track_sequence.current.time_playing())
|
||||||
@ -2684,6 +2741,24 @@ class Window(QMainWindow):
|
|||||||
helpers.ms_to_mmss(time_to_silence)
|
helpers.ms_to_mmss(time_to_silence)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def update_current(
|
||||||
|
self,
|
||||||
|
base_model: PlaylistModel,
|
||||||
|
proxy_model: PlaylistProxyModel,
|
||||||
|
playlist_id: int,
|
||||||
|
selected_row_numbers: list[int]
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Update self.current when playlist tab changes. Called by new playlist
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.current = Current(
|
||||||
|
base_model=base_model,
|
||||||
|
proxy_model=proxy_model,
|
||||||
|
playlist_id=playlist_id,
|
||||||
|
selected_row_numbers=selected_row_numbers
|
||||||
|
)
|
||||||
|
|
||||||
def update_headers(self) -> None:
|
def update_headers(self) -> None:
|
||||||
"""
|
"""
|
||||||
Update last / current / next track headers
|
Update last / current / next track headers
|
||||||
|
|||||||
@ -93,17 +93,15 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
self.played_tracks_hidden = False
|
self.played_tracks_hidden = False
|
||||||
|
|
||||||
# Connect signals
|
# Connect signals
|
||||||
self.signals.signal_add_track_to_header.connect(self.add_track_to_header)
|
self.signals.signal_add_track_to_header.connect(self.signal_add_track_to_header_handler)
|
||||||
self.signals.signal_begin_insert_rows.connect(self.begin_insert_rows)
|
self.signals.signal_begin_insert_rows.connect(self.begin_insert_rows_handler)
|
||||||
self.signals.signal_end_insert_rows.connect(self.end_insert_rows)
|
self.signals.signal_end_insert_rows.connect(self.end_insert_rows_handler)
|
||||||
self.signals.signal_insert_track.connect(self.insert_row_signal_handler)
|
self.signals.signal_insert_track.connect(self.insert_row_signal_handler)
|
||||||
self.signals.signal_playlist_selected_rows.connect(self.set_selected_rows)
|
self.signals.signal_playlist_selected_rows.connect(self.playlist_selected_rows_handler)
|
||||||
self.signals.signal_set_next_row.connect(self.set_next_row)
|
self.signals.signal_set_next_row.connect(self.set_next_row_handler)
|
||||||
self.signals.signal_track_started.connect(self.track_started)
|
self.signals.signal_track_started.connect(self.track_started_handler)
|
||||||
self.signals.signal_track_ended.connect(self.previous_track_ended)
|
self.signals.signal_track_ended.connect(self.signal_track_ended_handler)
|
||||||
self.signals.signal_next_track_changed.connect(
|
self.signals.signal_next_track_changed.connect(self.next_track_changed_handler)
|
||||||
self.signal_next_track_changed_handler
|
|
||||||
)
|
|
||||||
|
|
||||||
# Populate self.playlist_rows
|
# Populate self.playlist_rows
|
||||||
for dto in ds.playlistrows_by_playlist(self.playlist_id):
|
for dto in ds.playlistrows_by_playlist(self.playlist_id):
|
||||||
@ -152,7 +150,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
return header_row
|
return header_row
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def add_track_to_header(self, track_and_playlist: TrackAndPlaylist) -> None:
|
def signal_add_track_to_header_handler(self, track_and_playlist: TrackAndPlaylist) -> None:
|
||||||
"""
|
"""
|
||||||
Handle signal_add_track_to_header
|
Handle signal_add_track_to_header
|
||||||
"""
|
"""
|
||||||
@ -251,7 +249,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
return len(Col)
|
return len(Col)
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def track_started(self) -> None:
|
def track_started_handler(self) -> None:
|
||||||
"""
|
"""
|
||||||
Handle signal_track_started signal.
|
Handle signal_track_started signal.
|
||||||
|
|
||||||
@ -896,7 +894,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
self.track_sequence.update()
|
self.track_sequence.update()
|
||||||
self.update_track_times()
|
self.update_track_times()
|
||||||
|
|
||||||
def begin_insert_rows(self, insert_rows: InsertRows) -> None:
|
def begin_insert_rows_handler(self, insert_rows: InsertRows) -> None:
|
||||||
"""
|
"""
|
||||||
Prepare model to insert rows
|
Prepare model to insert rows
|
||||||
"""
|
"""
|
||||||
@ -906,7 +904,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
|
|
||||||
super().beginInsertRows(QModelIndex(), insert_rows.from_row, insert_rows.to_row)
|
super().beginInsertRows(QModelIndex(), insert_rows.from_row, insert_rows.to_row)
|
||||||
|
|
||||||
def end_insert_rows(self, playlist_id: int) -> None:
|
def end_insert_rows_handler(self, playlist_id: int) -> None:
|
||||||
"""
|
"""
|
||||||
End insert rows
|
End insert rows
|
||||||
"""
|
"""
|
||||||
@ -972,7 +970,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def previous_track_ended(self, playlist_id: int) -> None:
|
def signal_track_ended_handler(self, playlist_id: int) -> None:
|
||||||
"""
|
"""
|
||||||
Notification from signal_track_ended that the previous track has ended.
|
Notification from signal_track_ended that the previous track has ended.
|
||||||
|
|
||||||
@ -988,12 +986,12 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
# Sanity check
|
# Sanity check
|
||||||
if not self.track_sequence.previous:
|
if not self.track_sequence.previous:
|
||||||
log.error(
|
log.error(
|
||||||
f"{self}: playlistmodel:previous_track_ended called with no current track"
|
f"{self}: playlistmodel:signal_track_ended_handler called with no current track"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if self.track_sequence.previous.row_number is None:
|
if self.track_sequence.previous.row_number is None:
|
||||||
log.error(
|
log.error(
|
||||||
f"{self}: previous_track_ended called with no row number "
|
f"{self}: signal_track_ended_handler called with no row number "
|
||||||
f"({self.track_sequence.previous=})"
|
f"({self.track_sequence.previous=})"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@ -1255,7 +1253,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def set_selected_rows(self, selected_rows: SelectedRows) -> None:
|
def playlist_selected_rows_handler(self, selected_rows: SelectedRows) -> None:
|
||||||
"""
|
"""
|
||||||
Handle signal_playlist_selected_rows to keep track of which rows
|
Handle signal_playlist_selected_rows to keep track of which rows
|
||||||
are selected in the view
|
are selected in the view
|
||||||
@ -1267,7 +1265,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
self.selected_rows = [self.playlist_rows[a] for a in selected_rows.rows]
|
self.selected_rows = [self.playlist_rows[a] for a in selected_rows.rows]
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def set_next_row(self, playlist_id: int) -> None:
|
def set_next_row_handler(self, playlist_id: int) -> None:
|
||||||
"""
|
"""
|
||||||
Handle signal_set_next_row
|
Handle signal_set_next_row
|
||||||
"""
|
"""
|
||||||
@ -1306,7 +1304,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self.signals.signal_set_next_track.emit(plr)
|
self.signals.signal_set_next_track.emit(plr)
|
||||||
|
|
||||||
def signal_next_track_changed_handler(self) -> None:
|
def next_track_changed_handler(self) -> None:
|
||||||
"""
|
"""
|
||||||
Handle next track changed
|
Handle next track changed
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -41,7 +41,6 @@ from classes import (
|
|||||||
MusicMusterSignals,
|
MusicMusterSignals,
|
||||||
PlaylistStyle,
|
PlaylistStyle,
|
||||||
SelectedRows,
|
SelectedRows,
|
||||||
TrackAndPlaylist,
|
|
||||||
TrackInfo
|
TrackInfo
|
||||||
)
|
)
|
||||||
from config import Config
|
from config import Config
|
||||||
@ -310,9 +309,9 @@ class PlaylistTab(QTableView):
|
|||||||
|
|
||||||
# Connect signals
|
# Connect signals
|
||||||
self.signals = MusicMusterSignals()
|
self.signals = MusicMusterSignals()
|
||||||
self.signals.resize_rows_signal.connect(self.resize_rows)
|
self.signals.resize_rows_signal.connect(self.resize_rows_handler)
|
||||||
self.signals.span_cells_signal.connect(self._span_cells)
|
self.signals.span_cells_signal.connect(self._span_cells_handler)
|
||||||
self.signals.signal_track_started.connect(self.track_started)
|
self.signals.signal_track_started.connect(self.track_started_handler)
|
||||||
|
|
||||||
# Selection model
|
# Selection model
|
||||||
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
||||||
@ -343,7 +342,7 @@ class PlaylistTab(QTableView):
|
|||||||
v_header.sectionHandleDoubleClicked.connect(self.resizeRowToContents)
|
v_header.sectionHandleDoubleClicked.connect(self.resizeRowToContents)
|
||||||
|
|
||||||
# Setting ResizeToContents causes screen flash on load
|
# Setting ResizeToContents causes screen flash on load
|
||||||
self.resize_rows()
|
self.resize_rows_handler()
|
||||||
|
|
||||||
# ########## Overridden class functions ##########
|
# ########## Overridden class functions ##########
|
||||||
|
|
||||||
@ -354,12 +353,12 @@ class PlaylistTab(QTableView):
|
|||||||
Override closeEditor to enable play controls and update display.
|
Override closeEditor to enable play controls and update display.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.musicmuster.enable_escape(True)
|
self.signals.enable_escape_signal.emit(True)
|
||||||
|
|
||||||
super(PlaylistTab, self).closeEditor(editor, hint)
|
super(PlaylistTab, self).closeEditor(editor, hint)
|
||||||
|
|
||||||
# Optimise row heights after increasing row height for editing
|
# Optimise row heights after increasing row height for editing
|
||||||
self.resize_rows()
|
self.resize_rows_handler()
|
||||||
|
|
||||||
# Update start times in case a start time in a note has been
|
# Update start times in case a start time in a note has been
|
||||||
# edited
|
# edited
|
||||||
@ -430,11 +429,11 @@ class PlaylistTab(QTableView):
|
|||||||
self.clear_selection()
|
self.clear_selection()
|
||||||
|
|
||||||
# Resize rows
|
# Resize rows
|
||||||
self.resize_rows()
|
self.resize_rows_handler()
|
||||||
|
|
||||||
# Set next row if we are immediately under current row
|
# Set next row if we are immediately under current row
|
||||||
if set_next_row:
|
if set_next_row:
|
||||||
self.get_base_model().set_next_row(set_next_row)
|
self.get_base_model().set_next_row_handler(set_next_row)
|
||||||
|
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
@ -729,7 +728,7 @@ class PlaylistTab(QTableView):
|
|||||||
cb.setText(track_path, mode=cb.Mode.Clipboard)
|
cb.setText(track_path, mode=cb.Mode.Clipboard)
|
||||||
|
|
||||||
# @log_call
|
# @log_call
|
||||||
def track_started(self) -> None:
|
def track_started_handler(self) -> None:
|
||||||
"""
|
"""
|
||||||
Called when track starts playing
|
Called when track starts playing
|
||||||
"""
|
"""
|
||||||
@ -965,7 +964,7 @@ class PlaylistTab(QTableView):
|
|||||||
self.get_base_model().rescan_track(row_number)
|
self.get_base_model().rescan_track(row_number)
|
||||||
self.clear_selection()
|
self.clear_selection()
|
||||||
|
|
||||||
def resize_rows(self, playlist_id: Optional[int] = None) -> None:
|
def resize_rows_handler(self, playlist_id: Optional[int] = None) -> None:
|
||||||
"""
|
"""
|
||||||
If playlist_id is us, resize rows
|
If playlist_id is us, resize rows
|
||||||
"""
|
"""
|
||||||
@ -1092,10 +1091,10 @@ class PlaylistTab(QTableView):
|
|||||||
log.debug(f"set_row_as_next_track() {model_row_number=}")
|
log.debug(f"set_row_as_next_track() {model_row_number=}")
|
||||||
if model_row_number is None:
|
if model_row_number is None:
|
||||||
return
|
return
|
||||||
self.get_base_model().set_next_row(model_row_number)
|
self.get_base_model().set_next_row_handler(model_row_number)
|
||||||
self.clearSelection()
|
self.clearSelection()
|
||||||
|
|
||||||
def _span_cells(
|
def _span_cells_handler(
|
||||||
self, playlist_id: int, row: int, column: int, rowSpan: int, columnSpan: int
|
self, playlist_id: int, row: int, column: int, rowSpan: int, columnSpan: int
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1131,12 +1130,14 @@ class PlaylistTab(QTableView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Update musicmuster
|
# Update musicmuster
|
||||||
self.musicmuster.current.playlist_id = self.playlist_id
|
self.musicmuster.update_current(
|
||||||
self.musicmuster.current.selected_row_numbers = self.get_selected_rows()
|
base_model=self.get_base_model(),
|
||||||
self.musicmuster.current.base_model = self.get_base_model()
|
proxy_model=self.model(),
|
||||||
self.musicmuster.current.proxy_model = self.model()
|
playlist_id=self.playlist_id,
|
||||||
|
selected_row_numbers=self.get_selected_rows(),
|
||||||
|
)
|
||||||
|
|
||||||
self.resize_rows()
|
self.resize_rows_handler()
|
||||||
|
|
||||||
def _unmark_as_next(self) -> None:
|
def _unmark_as_next(self) -> None:
|
||||||
"""Rescan track"""
|
"""Rescan track"""
|
||||||
|
|||||||
@ -225,7 +225,7 @@ class TestMMMiscRowMove(unittest.TestCase):
|
|||||||
self.model.selected_rows = [self.model.playlist_rows[insert_row]]
|
self.model.selected_rows = [self.model.playlist_rows[insert_row]]
|
||||||
|
|
||||||
prd = self.model.playlist_rows[1]
|
prd = self.model.playlist_rows[1]
|
||||||
self.model.add_track_to_header(
|
self.model.signal_add_track_to_header_handler(
|
||||||
TrackAndPlaylist(playlist_id=self.model.playlist_id, track_id=prd.track_id)
|
TrackAndPlaylist(playlist_id=self.model.playlist_id, track_id=prd.track_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user