WIP: queries management
Menus and management working. Wrong tracks showing up in queries.
This commit is contained in:
parent
aa6ab03555
commit
8e48d63ebb
@ -49,6 +49,18 @@ class Config(object):
|
|||||||
FADEOUT_DB = -10
|
FADEOUT_DB = -10
|
||||||
FADEOUT_SECONDS = 5
|
FADEOUT_SECONDS = 5
|
||||||
FADEOUT_STEPS_PER_SECOND = 5
|
FADEOUT_STEPS_PER_SECOND = 5
|
||||||
|
FILTER_DURATION_LONGER = "longer than"
|
||||||
|
FILTER_DURATION_MINUTES = "minutes"
|
||||||
|
FILTER_DURATION_SECONDS = "seconds"
|
||||||
|
FILTER_DURATION_SHORTER = "shorter than"
|
||||||
|
FILTER_PATH_CONTAINS = "contains"
|
||||||
|
FILTER_PATH_EXCLUDING = "excluding"
|
||||||
|
FILTER_PLAYED_BEFORE = "before"
|
||||||
|
FILTER_PLAYED_DAYS = "days"
|
||||||
|
FILTER_PLAYED_MONTHS = "months"
|
||||||
|
FILTER_PLAYED_NEVER = "never"
|
||||||
|
FILTER_PLAYED_WEEKS = "weeks"
|
||||||
|
FILTER_PLAYED_YEARS = "years"
|
||||||
FUZZYMATCH_MINIMUM_LIST = 60.0
|
FUZZYMATCH_MINIMUM_LIST = 60.0
|
||||||
FUZZYMATCH_MINIMUM_SELECT_ARTIST = 80.0
|
FUZZYMATCH_MINIMUM_SELECT_ARTIST = 80.0
|
||||||
FUZZYMATCH_MINIMUM_SELECT_TITLE = 80.0
|
FUZZYMATCH_MINIMUM_SELECT_TITLE = 80.0
|
||||||
|
|||||||
@ -25,7 +25,7 @@ from sqlalchemy.orm.session import Session
|
|||||||
from sqlalchemy.engine.row import RowMapping
|
from sqlalchemy.engine.row import RowMapping
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
from classes import ApplicationError
|
from classes import ApplicationError, Filter
|
||||||
from config import Config
|
from config import Config
|
||||||
from dbmanager import DatabaseManager
|
from dbmanager import DatabaseManager
|
||||||
import dbtables
|
import dbtables
|
||||||
@ -610,11 +610,21 @@ class Queries(dbtables.QueriesTable):
|
|||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all_queries(cls, session: Session) -> Sequence["Queries"]:
|
def get_all(cls, session: Session) -> Sequence["Queries"]:
|
||||||
"""Returns a list of all queries ordered by name"""
|
"""Returns a list of all queries ordered by name"""
|
||||||
|
|
||||||
return session.scalars(select(cls).order_by(cls.name)).all()
|
return session.scalars(select(cls).order_by(cls.name)).all()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_favourites(cls, session: Session) -> Sequence["Queries"]:
|
||||||
|
"""Returns a list of favourite queries ordered by name"""
|
||||||
|
|
||||||
|
return session.scalars(
|
||||||
|
select(cls)
|
||||||
|
.where(cls.favourite.is_(True))
|
||||||
|
.order_by(cls.name)
|
||||||
|
).all()
|
||||||
|
|
||||||
|
|
||||||
class Settings(dbtables.SettingsTable):
|
class Settings(dbtables.SettingsTable):
|
||||||
def __init__(self, session: Session, name: str) -> None:
|
def __init__(self, session: Session, name: str) -> None:
|
||||||
@ -700,6 +710,40 @@ class Tracks(dbtables.TracksTable):
|
|||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_filtered_tracks(cls, session: Session, filter: Filter) -> Sequence["Tracks"]:
|
||||||
|
"""
|
||||||
|
Return tracks matching filter
|
||||||
|
"""
|
||||||
|
|
||||||
|
query = select(cls)
|
||||||
|
if filter.path:
|
||||||
|
if filter.path_type == "contains":
|
||||||
|
query = query.where(cls.path.ilike(f"%{filter.path}%"))
|
||||||
|
elif filter.path_type == "excluding":
|
||||||
|
query = query.where(cls.path.notilike(f"%{filter.path}%"))
|
||||||
|
else:
|
||||||
|
raise ApplicationError(f"Can't process filter path ({filter=})")
|
||||||
|
# TODO
|
||||||
|
# if last_played_number:
|
||||||
|
# need group_by track_id and having max/min lastplayed gt/lt, etc
|
||||||
|
seconds_duration = filter.duration_number
|
||||||
|
if filter.duration_unit == Config.FILTER_DURATION_MINUTES:
|
||||||
|
seconds_duration *= 60
|
||||||
|
elif filter.duration_unit != Config.FILTER_DURATION_SECONDS:
|
||||||
|
raise ApplicationError(f"Can't process filter duration ({filter=})")
|
||||||
|
if filter.duration_type == Config.FILTER_DURATION_LONGER:
|
||||||
|
query = query.where(cls.duration >= seconds_duration)
|
||||||
|
elif filter.duration_unit == Config.FILTER_DURATION_SHORTER:
|
||||||
|
query = query.where(cls.duration <= seconds_duration)
|
||||||
|
else:
|
||||||
|
raise ApplicationError(f"Can't process filter duration type ({filter=})")
|
||||||
|
|
||||||
|
records = session.scalars(
|
||||||
|
query).unique().all()
|
||||||
|
|
||||||
|
return records
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_by_path(cls, session: Session, path: str) -> Optional["Tracks"]:
|
def get_by_path(cls, session: Session, path: str) -> Optional["Tracks"]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -20,6 +20,7 @@ from PyQt6.QtCore import (
|
|||||||
Qt,
|
Qt,
|
||||||
QTime,
|
QTime,
|
||||||
QTimer,
|
QTimer,
|
||||||
|
QVariant,
|
||||||
)
|
)
|
||||||
from PyQt6.QtGui import (
|
from PyQt6.QtGui import (
|
||||||
QAction,
|
QAction,
|
||||||
@ -32,6 +33,7 @@ from PyQt6.QtGui import (
|
|||||||
QShortcut,
|
QShortcut,
|
||||||
)
|
)
|
||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
|
QAbstractItemView,
|
||||||
QApplication,
|
QApplication,
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
QComboBox,
|
QComboBox,
|
||||||
@ -46,7 +48,9 @@ from PyQt6.QtWidgets import (
|
|||||||
QMenu,
|
QMenu,
|
||||||
QMessageBox,
|
QMessageBox,
|
||||||
QPushButton,
|
QPushButton,
|
||||||
|
QSizePolicy,
|
||||||
QSpinBox,
|
QSpinBox,
|
||||||
|
QTableView,
|
||||||
QTableWidget,
|
QTableWidget,
|
||||||
QTableWidgetItem,
|
QTableWidgetItem,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
@ -74,6 +78,7 @@ from models import db, Playdates, PlaylistRows, Playlists, Queries, Settings, Tr
|
|||||||
from music_manager import RowAndTrack, track_sequence
|
from music_manager import RowAndTrack, track_sequence
|
||||||
from playlistmodel import PlaylistModel, PlaylistProxyModel
|
from playlistmodel import PlaylistModel, PlaylistProxyModel
|
||||||
from playlists import PlaylistTab
|
from playlists import PlaylistTab
|
||||||
|
from querylistmodel import QuerylistModel
|
||||||
from ui import icons_rc # noqa F401
|
from ui import icons_rc # noqa F401
|
||||||
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore
|
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore
|
||||||
from ui.downloadcsv_ui import Ui_DateSelect # type: ignore
|
from ui.downloadcsv_ui import Ui_DateSelect # type: ignore
|
||||||
@ -190,7 +195,9 @@ class FilterDialog(QDialog):
|
|||||||
path_layout = QHBoxLayout()
|
path_layout = QHBoxLayout()
|
||||||
path_label = QLabel("Path")
|
path_label = QLabel("Path")
|
||||||
self.path_combo = QComboBox()
|
self.path_combo = QComboBox()
|
||||||
self.path_combo.addItems(["contains", "excluding"])
|
self.path_combo.addItems(
|
||||||
|
[Config.FILTER_PATH_CONTAINS, Config.FILTER_PATH_EXCLUDING]
|
||||||
|
)
|
||||||
for idx in range(self.path_combo.count()):
|
for idx in range(self.path_combo.count()):
|
||||||
if self.path_combo.itemText(idx) == filter.path_type:
|
if self.path_combo.itemText(idx) == filter.path_type:
|
||||||
self.path_combo.setCurrentIndex(idx)
|
self.path_combo.setCurrentIndex(idx)
|
||||||
@ -207,7 +214,9 @@ class FilterDialog(QDialog):
|
|||||||
last_played_layout = QHBoxLayout()
|
last_played_layout = QHBoxLayout()
|
||||||
last_played_label = QLabel("Last played")
|
last_played_label = QLabel("Last played")
|
||||||
self.last_played_combo = QComboBox()
|
self.last_played_combo = QComboBox()
|
||||||
self.last_played_combo.addItems(["before", "never"])
|
self.last_played_combo.addItems(
|
||||||
|
[Config.FILTER_PLAYED_BEFORE, Config.FILTER_PLAYED_NEVER]
|
||||||
|
)
|
||||||
for idx in range(self.last_played_combo.count()):
|
for idx in range(self.last_played_combo.count()):
|
||||||
if self.last_played_combo.itemText(idx) == filter.last_played_type:
|
if self.last_played_combo.itemText(idx) == filter.last_played_type:
|
||||||
self.last_played_combo.setCurrentIndex(idx)
|
self.last_played_combo.setCurrentIndex(idx)
|
||||||
@ -219,7 +228,14 @@ class FilterDialog(QDialog):
|
|||||||
self.last_played_spinbox.setValue(filter.last_played_number or 0)
|
self.last_played_spinbox.setValue(filter.last_played_number or 0)
|
||||||
|
|
||||||
self.last_played_unit = QComboBox()
|
self.last_played_unit = QComboBox()
|
||||||
self.last_played_unit.addItems(["years", "months", "weeks", "days"])
|
self.last_played_unit.addItems(
|
||||||
|
[
|
||||||
|
Config.FILTER_PLAYED_YEARS,
|
||||||
|
Config.FILTER_PLAYED_MONTHS,
|
||||||
|
Config.FILTER_PLAYED_WEEKS,
|
||||||
|
Config.FILTER_PLAYED_DAYS,
|
||||||
|
]
|
||||||
|
)
|
||||||
for idx in range(self.last_played_unit.count()):
|
for idx in range(self.last_played_unit.count()):
|
||||||
if self.last_played_unit.itemText(idx) == filter.last_played_unit:
|
if self.last_played_unit.itemText(idx) == filter.last_played_unit:
|
||||||
self.last_played_unit.setCurrentIndex(idx)
|
self.last_played_unit.setCurrentIndex(idx)
|
||||||
@ -239,7 +255,9 @@ class FilterDialog(QDialog):
|
|||||||
duration_layout = QHBoxLayout()
|
duration_layout = QHBoxLayout()
|
||||||
duration_label = QLabel("Duration")
|
duration_label = QLabel("Duration")
|
||||||
self.duration_combo = QComboBox()
|
self.duration_combo = QComboBox()
|
||||||
self.duration_combo.addItems(["longer than", "shorter than"])
|
self.duration_combo.addItems(
|
||||||
|
[Config.FILTER_DURATION_LONGER, Config.FILTER_DURATION_SHORTER]
|
||||||
|
)
|
||||||
for idx in range(self.duration_combo.count()):
|
for idx in range(self.duration_combo.count()):
|
||||||
if self.duration_combo.itemText(idx) == filter.duration_type:
|
if self.duration_combo.itemText(idx) == filter.duration_type:
|
||||||
self.duration_combo.setCurrentIndex(idx)
|
self.duration_combo.setCurrentIndex(idx)
|
||||||
@ -251,8 +269,10 @@ class FilterDialog(QDialog):
|
|||||||
self.duration_spinbox.setValue(filter.duration_number)
|
self.duration_spinbox.setValue(filter.duration_number)
|
||||||
|
|
||||||
self.duration_unit = QComboBox()
|
self.duration_unit = QComboBox()
|
||||||
self.duration_unit.addItems(["minutes", "seconds"])
|
self.duration_unit.addItems(
|
||||||
self.duration_unit.setCurrentText("minutes")
|
[Config.FILTER_DURATION_MINUTES, Config.FILTER_DURATION_SECONDS]
|
||||||
|
)
|
||||||
|
self.duration_unit.setCurrentText(Config.FILTER_DURATION_MINUTES)
|
||||||
for idx in range(self.duration_unit.count()):
|
for idx in range(self.duration_unit.count()):
|
||||||
if self.duration_unit.itemText(idx) == filter.duration_unit:
|
if self.duration_unit.itemText(idx) == filter.duration_unit:
|
||||||
self.duration_unit.setCurrentIndex(idx)
|
self.duration_unit.setCurrentIndex(idx)
|
||||||
@ -447,7 +467,7 @@ class ManageQueries(ItemlistManager):
|
|||||||
# Build a list of queries
|
# Build a list of queries
|
||||||
query_list: list[ItemlistItem] = []
|
query_list: list[ItemlistItem] = []
|
||||||
|
|
||||||
for query in Queries.get_all_queries(self.session):
|
for query in Queries.get_all(self.session):
|
||||||
query_list.append(
|
query_list.append(
|
||||||
ItemlistItem(name=query.name, id=query.id, favourite=query.favourite)
|
ItemlistItem(name=query.name, id=query.id, favourite=query.favourite)
|
||||||
)
|
)
|
||||||
@ -478,6 +498,7 @@ class ManageQueries(ItemlistManager):
|
|||||||
dlg = FilterDialog(query.name, query.filter)
|
dlg = FilterDialog(query.name, query.filter)
|
||||||
if dlg.exec():
|
if dlg.exec():
|
||||||
query.filter = dlg.filter
|
query.filter = dlg.filter
|
||||||
|
query.name = dlg.name_text.text()
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
def edit_item(self, query_id: int) -> None:
|
def edit_item(self, query_id: int) -> None:
|
||||||
@ -771,6 +792,230 @@ class PreviewManager:
|
|||||||
self.start_time = None
|
self.start_time = None
|
||||||
|
|
||||||
|
|
||||||
|
class QueryDialog(QDialog):
|
||||||
|
"""Dialog box to handle selecting track from a query"""
|
||||||
|
|
||||||
|
def __init__(self, session: Session, default: int = 0) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.session = session
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
# Build a list of (query-name, playlist-id) tuples
|
||||||
|
self.selected_tracks: list[int] = []
|
||||||
|
|
||||||
|
self.query_list: list[tuple[str, int]] = []
|
||||||
|
self.query_list.append((Config.NO_QUERY_NAME, 0))
|
||||||
|
for query in Queries.get_all(self.session):
|
||||||
|
self.query_list.append((query.name, query.id))
|
||||||
|
|
||||||
|
self.setWindowTitle("Query Selector")
|
||||||
|
|
||||||
|
# Create label
|
||||||
|
query_label = QLabel("Query:")
|
||||||
|
|
||||||
|
# Top layout (Query label, combo box, and info label)
|
||||||
|
top_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
# Query label
|
||||||
|
query_label = QLabel("Query:")
|
||||||
|
top_layout.addWidget(query_label)
|
||||||
|
|
||||||
|
# Combo Box with fixed width
|
||||||
|
self.combo_box = QComboBox()
|
||||||
|
# self.combo_box.setFixedWidth(150) # Adjust as necessary for 20 characters
|
||||||
|
for text, id_ in self.query_list:
|
||||||
|
self.combo_box.addItem(text, id_)
|
||||||
|
top_layout.addWidget(self.combo_box)
|
||||||
|
|
||||||
|
# Table (middle part)
|
||||||
|
self.table_view = QTableView()
|
||||||
|
self.table_view.setSelectionMode(
|
||||||
|
QAbstractItemView.SelectionMode.ExtendedSelection
|
||||||
|
)
|
||||||
|
self.table_view.setSelectionBehavior(
|
||||||
|
QAbstractItemView.SelectionBehavior.SelectRows
|
||||||
|
)
|
||||||
|
self.table_view.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
||||||
|
self.table_view.setAlternatingRowColors(True)
|
||||||
|
self.table_view.setVerticalScrollMode(
|
||||||
|
QAbstractItemView.ScrollMode.ScrollPerPixel
|
||||||
|
)
|
||||||
|
self.table_view.clicked.connect(self.handle_row_click)
|
||||||
|
|
||||||
|
# Bottom layout (buttons)
|
||||||
|
bottom_layout = QHBoxLayout()
|
||||||
|
bottom_layout.addStretch() # Push buttons to the right
|
||||||
|
|
||||||
|
self.add_tracks_button = QPushButton("Add tracks")
|
||||||
|
self.add_tracks_button.setEnabled(False) # Disabled by default
|
||||||
|
self.add_tracks_button.clicked.connect(self.add_tracks_clicked)
|
||||||
|
bottom_layout.addWidget(self.add_tracks_button)
|
||||||
|
|
||||||
|
self.cancel_button = QPushButton("Cancel")
|
||||||
|
self.cancel_button.clicked.connect(self.cancel_clicked)
|
||||||
|
bottom_layout.addWidget(self.cancel_button)
|
||||||
|
|
||||||
|
# Main layout
|
||||||
|
main_layout = QVBoxLayout()
|
||||||
|
main_layout.addLayout(top_layout)
|
||||||
|
main_layout.addWidget(self.table_view)
|
||||||
|
main_layout.addLayout(bottom_layout)
|
||||||
|
|
||||||
|
self.combo_box.currentIndexChanged.connect(self.query_changed)
|
||||||
|
if self.default:
|
||||||
|
default_idx = self.combo_box.findData(QVariant(self.default))
|
||||||
|
self.combo_box.setCurrentIndex(default_idx)
|
||||||
|
self.path_text = QLineEdit()
|
||||||
|
self.setLayout(main_layout)
|
||||||
|
|
||||||
|
# Stretch last column *after* setting column widths which is
|
||||||
|
# *much* faster
|
||||||
|
h_header = self.table_view.horizontalHeader()
|
||||||
|
if h_header:
|
||||||
|
h_header.sectionResized.connect(self._column_resize)
|
||||||
|
h_header.setStretchLastSection(True)
|
||||||
|
# Resize on vertical header click
|
||||||
|
v_header = self.table_view.verticalHeader()
|
||||||
|
if v_header:
|
||||||
|
v_header.setMinimumSectionSize(5)
|
||||||
|
v_header.sectionHandleDoubleClicked.disconnect()
|
||||||
|
v_header.sectionHandleDoubleClicked.connect(
|
||||||
|
self.table_view.resizeRowToContents
|
||||||
|
)
|
||||||
|
|
||||||
|
self.set_window_size()
|
||||||
|
self.resizeRowsToContents()
|
||||||
|
|
||||||
|
def add_tracks_clicked(self):
|
||||||
|
self.selected_tracks = self.table_view.model().get_selected_track_ids()
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
def cancel_clicked(self):
|
||||||
|
self.selected_tracks = []
|
||||||
|
self.reject()
|
||||||
|
|
||||||
|
def closeEvent(self, event: QCloseEvent | None) -> None:
|
||||||
|
"""
|
||||||
|
Record size and columns
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.save_sizes()
|
||||||
|
super().closeEvent(event)
|
||||||
|
|
||||||
|
def accept(self) -> None:
|
||||||
|
self.save_sizes()
|
||||||
|
super().accept()
|
||||||
|
|
||||||
|
def reject(self) -> None:
|
||||||
|
self.save_sizes()
|
||||||
|
super().reject()
|
||||||
|
|
||||||
|
def save_sizes(self) -> None:
|
||||||
|
"""
|
||||||
|
Save window size
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Save dialog box attributes
|
||||||
|
attributes_to_save = dict(
|
||||||
|
querylist_height=self.height(),
|
||||||
|
querylist_width=self.width(),
|
||||||
|
querylist_x=self.x(),
|
||||||
|
querylist_y=self.y(),
|
||||||
|
)
|
||||||
|
for name, value in attributes_to_save.items():
|
||||||
|
record = Settings.get_setting(self.session, name)
|
||||||
|
record.f_int = value
|
||||||
|
|
||||||
|
header = self.table_view.horizontalHeader()
|
||||||
|
if header is None:
|
||||||
|
return
|
||||||
|
column_count = header.count()
|
||||||
|
if column_count < 2:
|
||||||
|
return
|
||||||
|
for column_number in range(column_count - 1):
|
||||||
|
attr_name = f"querylist_col_{column_number}_width"
|
||||||
|
record = Settings.get_setting(self.session, attr_name)
|
||||||
|
record.f_int = self.table_view.columnWidth(column_number)
|
||||||
|
|
||||||
|
self.session.commit()
|
||||||
|
|
||||||
|
def _column_resize(self, column_number: int, _old: int, _new: int) -> None:
|
||||||
|
"""
|
||||||
|
Called when column width changes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
header = self.table_view.horizontalHeader()
|
||||||
|
if not header:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Resize rows if necessary
|
||||||
|
self.resizeRowsToContents()
|
||||||
|
|
||||||
|
def resizeRowsToContents(self):
|
||||||
|
header = self.table_view.verticalHeader()
|
||||||
|
model = self.table_view.model()
|
||||||
|
if model:
|
||||||
|
for row in range(model.rowCount()):
|
||||||
|
hint = self.table_view.sizeHintForRow(row)
|
||||||
|
header.resizeSection(row, hint)
|
||||||
|
|
||||||
|
def query_changed(self, idx: int) -> None:
|
||||||
|
"""
|
||||||
|
Called when user selects query
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get query id
|
||||||
|
query_id = self.combo_box.currentData()
|
||||||
|
query = self.session.get(Queries, query_id)
|
||||||
|
if not query:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create model
|
||||||
|
base_model = QuerylistModel(self.session, query.filter)
|
||||||
|
|
||||||
|
# Create table
|
||||||
|
self.table_view.setModel(base_model)
|
||||||
|
self.set_column_sizes()
|
||||||
|
|
||||||
|
def handle_row_click(self, index):
|
||||||
|
self.table_view.model().toggle_row_selection(index.row())
|
||||||
|
self.table_view.clearSelection()
|
||||||
|
|
||||||
|
# Enable 'Add tracks' button only when a row is selected
|
||||||
|
selected = self.table_view.model().get_selected_track_ids()
|
||||||
|
self.add_tracks_button.setEnabled(selected != [])
|
||||||
|
|
||||||
|
def set_window_size(self) -> None:
|
||||||
|
"""Set window sizes"""
|
||||||
|
|
||||||
|
x = Settings.get_setting(self.session, "querylist_x").f_int or 100
|
||||||
|
y = Settings.get_setting(self.session, "querylist_y").f_int or 100
|
||||||
|
width = Settings.get_setting(self.session, "querylist_width").f_int or 100
|
||||||
|
height = Settings.get_setting(self.session, "querylist_height").f_int or 100
|
||||||
|
self.setGeometry(x, y, width, height)
|
||||||
|
|
||||||
|
def set_column_sizes(self) -> None:
|
||||||
|
"""Set column sizes"""
|
||||||
|
|
||||||
|
header = self.table_view.horizontalHeader()
|
||||||
|
if header is None:
|
||||||
|
return
|
||||||
|
column_count = header.count()
|
||||||
|
if column_count < 2:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Last column is set to stretch so ignore it here
|
||||||
|
for column_number in range(column_count - 1):
|
||||||
|
attr_name = f"querylist_col_{column_number}_width"
|
||||||
|
record = Settings.get_setting(self.session, attr_name)
|
||||||
|
if record.f_int is not None:
|
||||||
|
self.table_view.setColumnWidth(column_number, record.f_int)
|
||||||
|
else:
|
||||||
|
self.table_view.setColumnWidth(
|
||||||
|
column_number, Config.DEFAULT_COLUMN_WIDTH
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SelectPlaylistDialog(QDialog):
|
class SelectPlaylistDialog(QDialog):
|
||||||
def __init__(self, parent=None, playlists=None, session=None):
|
def __init__(self, parent=None, playlists=None, session=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -1146,12 +1391,52 @@ class Window(QMainWindow):
|
|||||||
|
|
||||||
return submenu_items
|
return submenu_items
|
||||||
|
|
||||||
def get_query_dynamic_submenu_items(self):
|
def get_query_dynamic_submenu_items(
|
||||||
"""Returns dynamically generated menu items for Submenu 2."""
|
self,
|
||||||
return [
|
) -> list[dict[str, str | tuple[Session, int] | bool]]:
|
||||||
{"text": "Action Xargs", "handler": "kae", "args": (21,)},
|
"""
|
||||||
{"text": "Action Y", "handler": "action_y_handler"},
|
Return dynamically generated menu items, in this case
|
||||||
]
|
templates marked as favourite from which to generate a
|
||||||
|
new playlist.
|
||||||
|
|
||||||
|
The handler is to call show_query with a session
|
||||||
|
and query_id.
|
||||||
|
"""
|
||||||
|
|
||||||
|
with db.Session() as session:
|
||||||
|
submenu_items: list[dict[str, str | tuple[Session, int] | bool]] = [
|
||||||
|
{
|
||||||
|
"text": "Show all",
|
||||||
|
"handler": "show_query",
|
||||||
|
"args": (session, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"separator": True,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
queries = Queries.get_favourites(session)
|
||||||
|
for query in queries:
|
||||||
|
submenu_items.append(
|
||||||
|
{
|
||||||
|
"text": query.name,
|
||||||
|
"handler": "show_query",
|
||||||
|
"args": (
|
||||||
|
session,
|
||||||
|
query.id,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return submenu_items
|
||||||
|
|
||||||
|
def show_query(self, session: Session, query_id: int) -> None:
|
||||||
|
"""
|
||||||
|
Show query dialog with query_id selected
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Keep a reference else it will be gc'd
|
||||||
|
self.query_dialog = QueryDialog(session, query_id)
|
||||||
|
self.query_dialog.exec()
|
||||||
|
|
||||||
# # # # # # # # # # Playlist management functions # # # # # # # # # #
|
# # # # # # # # # # Playlist management functions # # # # # # # # # #
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ from helpers import (
|
|||||||
show_warning,
|
show_warning,
|
||||||
)
|
)
|
||||||
from log import log
|
from log import log
|
||||||
from models import db, Playdates
|
from models import db, Playdates, Tracks
|
||||||
from music_manager import RowAndTrack
|
from music_manager import RowAndTrack
|
||||||
|
|
||||||
|
|
||||||
@ -228,20 +228,20 @@ class QuerylistModel(QAbstractTableModel):
|
|||||||
row = 0
|
row = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = Tracks.get_filtered(self.session, self.filter)
|
results = Tracks.get_filtered_tracks(self.session, self.filter)
|
||||||
for result in results:
|
for result in results:
|
||||||
if hasattr(result, "lastplayed"):
|
if hasattr(result, "lastplayed"):
|
||||||
lastplayed = result["lastplayed"]
|
lastplayed = result["lastplayed"]
|
||||||
else:
|
else:
|
||||||
lastplayed = None
|
lastplayed = None
|
||||||
queryrow = QueryRow(
|
queryrow = QueryRow(
|
||||||
artist=result["artist"],
|
artist=result.artist,
|
||||||
bitrate=result["bitrate"],
|
bitrate=result.bitrate or 0,
|
||||||
duration=result["duration"],
|
duration=result.duration,
|
||||||
lastplayed=lastplayed,
|
lastplayed=lastplayed,
|
||||||
path=result["path"],
|
path=result.path,
|
||||||
title=result["title"],
|
title=result.title,
|
||||||
track_id=result["id"],
|
track_id=result.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.querylist_rows[row] = queryrow
|
self.querylist_rows[row] = queryrow
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user