From a8867410792ef4f7419ea39189076028720287e4 Mon Sep 17 00:00:00 2001 From: 283375 Date: Tue, 5 Sep 2023 02:26:22 +0800 Subject: [PATCH] wip: split `SongIdSelector` --- ui/designer/components/chartSelector.ui | 134 ++---------- ui/designer/components/chartSelector_ui.py | 75 +------ ui/designer/components/songIdSelector.ui | 114 +++++++++++ ui/designer/components/songIdSelector_ui.py | 97 +++++++++ .../{chartSelector.py => songIdSelector.py} | 0 ui/implements/components/chartSelector.py | 179 ++-------------- ui/implements/components/songIdSelector.py | 191 ++++++++++++++++++ 7 files changed, 441 insertions(+), 349 deletions(-) create mode 100644 ui/designer/components/songIdSelector.ui create mode 100644 ui/designer/components/songIdSelector_ui.py rename ui/extends/components/{chartSelector.py => songIdSelector.py} (100%) create mode 100644 ui/implements/components/songIdSelector.py diff --git a/ui/designer/components/chartSelector.ui b/ui/designer/components/chartSelector.ui index 62e85fe..6ec23a1 100644 --- a/ui/designer/components/chartSelector.ui +++ b/ui/designer/components/chartSelector.ui @@ -26,122 +26,20 @@ songIdSelector.title + + 0 + + + 0 + + + 0 + + + 0 + - - - songIdSelector.quickActions - - - - - - - 100 - 0 - - - - songIdSelector.quickActions.nextPackageButton - - - - - - - - 100 - 0 - - - - songIdSelector.quickActions.nextSongIdButton - - - - - - - - 100 - 0 - - - - songIdSelector.quickActions.previousSongIdButton - - - - - - - - 100 - 0 - - - - songIdSelector.quickActions.previousPackageButton - - - - - - - - - - - 300 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - true - - - search.lineEdit.placeholder - - - true - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - + @@ -185,6 +83,12 @@
ui.implements.components.ratingClassSelector
1 + + SongIdSelector + QWidget +
ui.implements.components.songIdSelector
+ 1 +
diff --git a/ui/designer/components/chartSelector_ui.py b/ui/designer/components/chartSelector_ui.py index 51a79de..d3e8cdb 100644 --- a/ui/designer/components/chartSelector_ui.py +++ b/ui/designer/components/chartSelector_ui.py @@ -15,11 +15,11 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont, QFontDatabase, QGradient, QIcon, QImage, QKeySequence, QLinearGradient, QPainter, QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QComboBox, QGroupBox, QHBoxLayout, - QLabel, QLineEdit, QPushButton, QSizePolicy, - QSpacerItem, QVBoxLayout, QWidget) +from PySide6.QtWidgets import (QApplication, QGroupBox, QHBoxLayout, QLabel, + QPushButton, QSizePolicy, QVBoxLayout, QWidget) from ui.implements.components.ratingClassSelector import RatingClassSelector +from ui.implements.components.songIdSelector import SongIdSelector class Ui_ChartSelector(object): def setupUi(self, ChartSelector): @@ -38,66 +38,11 @@ class Ui_ChartSelector(object): self.songIdSelectorGroupBox.setSizePolicy(sizePolicy) self.verticalLayout_3 = QVBoxLayout(self.songIdSelectorGroupBox) self.verticalLayout_3.setObjectName(u"verticalLayout_3") - self.songIdSelectorQuickActionsGroupBox = QGroupBox(self.songIdSelectorGroupBox) - self.songIdSelectorQuickActionsGroupBox.setObjectName(u"songIdSelectorQuickActionsGroupBox") - self.horizontalLayout = QHBoxLayout(self.songIdSelectorQuickActionsGroupBox) - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.nextPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) - self.nextPackageButton.setObjectName(u"nextPackageButton") - self.nextPackageButton.setMinimumSize(QSize(100, 0)) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.songIdSelector = SongIdSelector(self.songIdSelectorGroupBox) + self.songIdSelector.setObjectName(u"songIdSelector") - self.horizontalLayout.addWidget(self.nextPackageButton) - - self.nextSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) - self.nextSongIdButton.setObjectName(u"nextSongIdButton") - self.nextSongIdButton.setMinimumSize(QSize(100, 0)) - - self.horizontalLayout.addWidget(self.nextSongIdButton) - - self.previousSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) - self.previousSongIdButton.setObjectName(u"previousSongIdButton") - self.previousSongIdButton.setMinimumSize(QSize(100, 0)) - - self.horizontalLayout.addWidget(self.previousSongIdButton) - - self.previousPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) - self.previousPackageButton.setObjectName(u"previousPackageButton") - self.previousPackageButton.setMinimumSize(QSize(100, 0)) - - self.horizontalLayout.addWidget(self.previousPackageButton) - - - self.verticalLayout_3.addWidget(self.songIdSelectorQuickActionsGroupBox) - - self.widget = QWidget(self.songIdSelectorGroupBox) - self.widget.setObjectName(u"widget") - self.widget.setMinimumSize(QSize(300, 0)) - self.verticalLayout = QVBoxLayout(self.widget) - self.verticalLayout.setObjectName(u"verticalLayout") - self.verticalLayout.setContentsMargins(0, 0, 0, 0) - self.searchLineEdit = QLineEdit(self.widget) - self.searchLineEdit.setObjectName(u"searchLineEdit") - self.searchLineEdit.setFrame(True) - self.searchLineEdit.setClearButtonEnabled(True) - - self.verticalLayout.addWidget(self.searchLineEdit) - - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout.addItem(self.verticalSpacer) - - self.packComboBox = QComboBox(self.widget) - self.packComboBox.setObjectName(u"packComboBox") - - self.verticalLayout.addWidget(self.packComboBox) - - self.songIdComboBox = QComboBox(self.widget) - self.songIdComboBox.setObjectName(u"songIdComboBox") - - self.verticalLayout.addWidget(self.songIdComboBox) - - - self.verticalLayout_3.addWidget(self.widget) + self.verticalLayout_3.addWidget(self.songIdSelector) self.mainVerticalLayout.addWidget(self.songIdSelectorGroupBox) @@ -137,12 +82,6 @@ class Ui_ChartSelector(object): def retranslateUi(self, ChartSelector): self.songIdSelectorGroupBox.setTitle(QCoreApplication.translate("ChartSelector", u"songIdSelector.title", None)) - self.songIdSelectorQuickActionsGroupBox.setTitle(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions", None)) - self.nextPackageButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.nextPackageButton", None)) - self.nextSongIdButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.nextSongIdButton", None)) - self.previousSongIdButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.previousSongIdButton", None)) - self.previousPackageButton.setText(QCoreApplication.translate("ChartSelector", u"songIdSelector.quickActions.previousPackageButton", None)) - self.searchLineEdit.setPlaceholderText(QCoreApplication.translate("ChartSelector", u"search.lineEdit.placeholder", None)) self.resetButton.setText(QCoreApplication.translate("ChartSelector", u"resetButton", None)) pass # retranslateUi diff --git a/ui/designer/components/songIdSelector.ui b/ui/designer/components/songIdSelector.ui new file mode 100644 index 0000000..4b6022f --- /dev/null +++ b/ui/designer/components/songIdSelector.ui @@ -0,0 +1,114 @@ + + + SongIdSelector + + + + 0 + 0 + 470 + 350 + + + + SongIdSelector + + + + + + songIdSelector.quickActions + + + + + + + 100 + 0 + + + + songIdSelector.quickActions.nextPackageButton + + + + + + + + 100 + 0 + + + + songIdSelector.quickActions.nextSongIdButton + + + + + + + + 100 + 0 + + + + songIdSelector.quickActions.previousSongIdButton + + + + + + + + 100 + 0 + + + + songIdSelector.quickActions.previousPackageButton + + + + + + + + + + true + + + search.lineEdit.placeholder + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + diff --git a/ui/designer/components/songIdSelector_ui.py b/ui/designer/components/songIdSelector_ui.py new file mode 100644 index 0000000..6f978cc --- /dev/null +++ b/ui/designer/components/songIdSelector_ui.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'songIdSelector.ui' +## +## Created by: Qt User Interface Compiler version 6.5.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QComboBox, QGroupBox, QHBoxLayout, + QLineEdit, QPushButton, QSizePolicy, QSpacerItem, + QVBoxLayout, QWidget) + +class Ui_SongIdSelector(object): + def setupUi(self, SongIdSelector): + if not SongIdSelector.objectName(): + SongIdSelector.setObjectName(u"SongIdSelector") + SongIdSelector.resize(470, 350) + SongIdSelector.setWindowTitle(u"SongIdSelector") + self.verticalLayout_2 = QVBoxLayout(SongIdSelector) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.songIdSelectorQuickActionsGroupBox = QGroupBox(SongIdSelector) + self.songIdSelectorQuickActionsGroupBox.setObjectName(u"songIdSelectorQuickActionsGroupBox") + self.horizontalLayout = QHBoxLayout(self.songIdSelectorQuickActionsGroupBox) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.nextPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) + self.nextPackageButton.setObjectName(u"nextPackageButton") + self.nextPackageButton.setMinimumSize(QSize(100, 0)) + + self.horizontalLayout.addWidget(self.nextPackageButton) + + self.nextSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) + self.nextSongIdButton.setObjectName(u"nextSongIdButton") + self.nextSongIdButton.setMinimumSize(QSize(100, 0)) + + self.horizontalLayout.addWidget(self.nextSongIdButton) + + self.previousSongIdButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) + self.previousSongIdButton.setObjectName(u"previousSongIdButton") + self.previousSongIdButton.setMinimumSize(QSize(100, 0)) + + self.horizontalLayout.addWidget(self.previousSongIdButton) + + self.previousPackageButton = QPushButton(self.songIdSelectorQuickActionsGroupBox) + self.previousPackageButton.setObjectName(u"previousPackageButton") + self.previousPackageButton.setMinimumSize(QSize(100, 0)) + + self.horizontalLayout.addWidget(self.previousPackageButton) + + + self.verticalLayout_2.addWidget(self.songIdSelectorQuickActionsGroupBox) + + self.searchLineEdit = QLineEdit(SongIdSelector) + self.searchLineEdit.setObjectName(u"searchLineEdit") + self.searchLineEdit.setFrame(True) + self.searchLineEdit.setClearButtonEnabled(True) + + self.verticalLayout_2.addWidget(self.searchLineEdit) + + self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout_2.addItem(self.verticalSpacer) + + self.packComboBox = QComboBox(SongIdSelector) + self.packComboBox.setObjectName(u"packComboBox") + + self.verticalLayout_2.addWidget(self.packComboBox) + + self.songIdComboBox = QComboBox(SongIdSelector) + self.songIdComboBox.setObjectName(u"songIdComboBox") + + self.verticalLayout_2.addWidget(self.songIdComboBox) + + + self.retranslateUi(SongIdSelector) + + QMetaObject.connectSlotsByName(SongIdSelector) + # setupUi + + def retranslateUi(self, SongIdSelector): + self.songIdSelectorQuickActionsGroupBox.setTitle(QCoreApplication.translate("SongIdSelector", u"songIdSelector.quickActions", None)) + self.nextPackageButton.setText(QCoreApplication.translate("SongIdSelector", u"songIdSelector.quickActions.nextPackageButton", None)) + self.nextSongIdButton.setText(QCoreApplication.translate("SongIdSelector", u"songIdSelector.quickActions.nextSongIdButton", None)) + self.previousSongIdButton.setText(QCoreApplication.translate("SongIdSelector", u"songIdSelector.quickActions.previousSongIdButton", None)) + self.previousPackageButton.setText(QCoreApplication.translate("SongIdSelector", u"songIdSelector.quickActions.previousPackageButton", None)) + self.searchLineEdit.setPlaceholderText(QCoreApplication.translate("SongIdSelector", u"search.lineEdit.placeholder", None)) + pass + # retranslateUi + diff --git a/ui/extends/components/chartSelector.py b/ui/extends/components/songIdSelector.py similarity index 100% rename from ui/extends/components/chartSelector.py rename to ui/extends/components/songIdSelector.py diff --git a/ui/implements/components/chartSelector.py b/ui/implements/components/chartSelector.py index b1fe55e..7618ae0 100644 --- a/ui/implements/components/chartSelector.py +++ b/ui/implements/components/chartSelector.py @@ -1,17 +1,13 @@ import logging -import re -from typing import Literal from arcaea_offline.database import Database from arcaea_offline.models import Chart from arcaea_offline.utils.rating import rating_class_to_text -from PySide6.QtCore import QModelIndex, Qt, Signal, Slot +from PySide6.QtCore import Signal, Slot from PySide6.QtGui import QShowEvent -from PySide6.QtWidgets import QCompleter, QWidget +from PySide6.QtWidgets import QWidget from ui.designer.components.chartSelector_ui import Ui_ChartSelector -from ui.extends.components.chartSelector import SearchCompleterModel -from ui.extends.shared.delegates.descriptionDelegate import DescriptionDelegate logger = logging.getLogger(__name__) @@ -24,89 +20,24 @@ class ChartSelector(Ui_ChartSelector, QWidget): self.db = Database() self.setupUi(self) - self.previousPackageButton.clicked.connect( - lambda: self.quickSwitchSelection("previous", "package") - ) - self.previousSongIdButton.clicked.connect( - lambda: self.quickSwitchSelection("previous", "songId") - ) - self.nextSongIdButton.clicked.connect( - lambda: self.quickSwitchSelection("next", "songId") - ) - self.nextPackageButton.clicked.connect( - lambda: self.quickSwitchSelection("next", "package") - ) - self.valueChanged.connect(self.updateResultLabel) + self.songIdSelector.valueChanged.connect(self.updateRatingClassEnabled) - self.fillPackComboBox() - self.packComboBox.setCurrentIndex(-1) - self.songIdComboBox.setCurrentIndex(-1) - - self.searchCompleterModel = SearchCompleterModel() - self.searchCompleter = QCompleter(self.searchCompleterModel) - self.searchCompleter.popup().setItemDelegate( - DescriptionDelegate(self.searchCompleter.popup()) - ) - self.searchCompleter.activated[QModelIndex].connect( - self.searchCompleterSetSelection - ) - self.searchLineEdit.setCompleter(self.searchCompleter) - - self.packComboBox.setItemDelegate(DescriptionDelegate(self.packComboBox)) - self.songIdComboBox.setItemDelegate(DescriptionDelegate(self.songIdComboBox)) - + self.songIdSelector.valueChanged.connect(self.valueChanged) self.ratingClassSelector.valueChanged.connect(self.valueChanged) - self.packComboBox.currentIndexChanged.connect(self.valueChanged) - self.songIdComboBox.currentIndexChanged.connect(self.valueChanged) - - def quickSwitchSelection( - self, - direction: Literal["previous", "next"], - model: Literal["package", "songId"], - ): - minIndex = 0 - if model == "package": - maxIndex = self.packComboBox.count() - 1 - currentIndex = self.packComboBox.currentIndex() + ( - 1 if direction == "next" else -1 - ) - currentIndex = max(min(maxIndex, currentIndex), minIndex) - self.packComboBox.setCurrentIndex(currentIndex) - elif model == "songId": - maxIndex = self.songIdComboBox.count() - 1 - currentIndex = self.songIdComboBox.currentIndex() + ( - 1 if direction == "next" else -1 - ) - currentIndex = max(min(maxIndex, currentIndex), minIndex) - self.songIdComboBox.setCurrentIndex(currentIndex) - else: - return def value(self): - packId = self.packComboBox.currentData() - songId = self.songIdComboBox.currentData() + songId = self.songIdSelector.value() ratingClass = self.ratingClassSelector.value() - if packId and songId and isinstance(ratingClass, int): + if songId and isinstance(ratingClass, int): return self.db.get_chart(songId, ratingClass) return None def showEvent(self, event: QShowEvent): - # update database results when widget visible - self.searchCompleterModel.updateSearcherSongs() - # remember selection and restore later - pack = self.packComboBox.currentData() - songId = self.songIdComboBox.currentData() ratingClass = self.ratingClassSelector.value() - self.fillPackComboBox() - - if pack: - self.selectPack(pack) - if songId: - self.selectSongId(songId) if ratingClass is not None: self.ratingClassSelector.select(ratingClass) return super().showEvent(event) @@ -132,106 +63,22 @@ class ChartSelector(Ui_ChartSelector, QWidget): else: self.resultLabel.setText("...") - def fillPackComboBox(self): - self.packComboBox.clear() - packs = self.db.get_packs() - for pack in packs: - isAppendPack = re.search(r"_append_.*$", pack.id) - if isAppendPack: - basePackId = re.sub(r"_append_.*$", "", pack.id) - basePackName = self.db.get_pack_by_id(basePackId).name - packName = f"{basePackName} - {pack.name}" - else: - packName = pack.name - self.packComboBox.addItem(f"{packName} ({pack.id})", pack.id) - row = self.packComboBox.count() - 1 - self.packComboBox.setItemData( - row, packName, DescriptionDelegate.MainTextRole - ) - self.packComboBox.setItemData( - row, pack.id, DescriptionDelegate.DescriptionTextRole - ) - - self.packComboBox.setCurrentIndex(-1) - - def fillSongIdComboBox(self): - self.songIdComboBox.clear() - packId = self.packComboBox.currentData() - if packId: - charts = self.db.get_charts_by_pack_id(packId) - inserted_song_ids = [] - for chart in charts: - if chart.song_id not in inserted_song_ids: - self.songIdComboBox.addItem( - f"{chart.title} ({chart.song_id})", chart.song_id - ) - inserted_song_ids.append(chart.song_id) - row = self.songIdComboBox.count() - 1 - self.songIdComboBox.setItemData( - row, chart.title, DescriptionDelegate.MainTextRole - ) - self.songIdComboBox.setItemData( - row, chart.song_id, DescriptionDelegate.DescriptionTextRole - ) - self.songIdComboBox.setCurrentIndex(-1) - - @Slot() - def on_packComboBox_activated(self): - self.fillSongIdComboBox() - - @Slot(int) - def on_songIdComboBox_currentIndexChanged(self, index: int): + def updateRatingClassEnabled(self): ratingClasses = [] - if index > -1: - charts = self.db.get_charts_by_song_id(self.songIdComboBox.currentData()) + songId = self.songIdSelector.value() + if songId: + charts = self.db.get_charts_by_song_id(songId) ratingClasses = [chart.rating_class for chart in charts] self.ratingClassSelector.setButtonsEnabled(ratingClasses) @Slot() def on_resetButton_clicked(self): - self.packComboBox.setCurrentIndex(-1) - self.songIdComboBox.setCurrentIndex(-1) - - @Slot(str) - def on_searchLineEdit_textChanged(self, text: str): - if text: - self.searchCompleterModel.getSearchResult(text) - else: - self.searchCompleterModel.clear() - - def selectPack(self, packId: str) -> bool: - packIdIndex = self.packComboBox.findData(packId) - if packIdIndex > -1: - self.packComboBox.setCurrentIndex(packIdIndex) - self.fillSongIdComboBox() - return True - else: - logger.warning(f'Attempting to select an unknown pack "{packId}"') - return False - - def selectSongId(self, songId: str) -> bool: - songIdIndex = self.songIdComboBox.findData(songId) - if songIdIndex > -1: - self.songIdComboBox.setCurrentIndex(songIdIndex) - return True - else: - logger.warning( - f'Attempting to select an unknown song "{songId}", maybe try selecting a pack first?' - ) - return False + self.songIdSelector.reset() def selectChart(self, chart: Chart): - if not self.selectPack(chart.set): + if not self.songIdSelector.selectPack(chart.set): return False - if not self.selectSongId(chart.song_id): + if not self.songIdSelector.selectSongId(chart.song_id): return False self.ratingClassSelector.select(chart.rating_class) return True - - @Slot(QModelIndex) - def searchCompleterSetSelection(self, index: QModelIndex): - chart = index.data(Qt.ItemDataRole.UserRole + 10) # type: Chart - self.selectChart(chart) - - self.searchLineEdit.clear() - self.searchLineEdit.clearFocus() diff --git a/ui/implements/components/songIdSelector.py b/ui/implements/components/songIdSelector.py new file mode 100644 index 0000000..6b88f0f --- /dev/null +++ b/ui/implements/components/songIdSelector.py @@ -0,0 +1,191 @@ +import logging +import re +from typing import Literal + +from arcaea_offline.database import Database +from arcaea_offline.models import Chart +from PySide6.QtCore import QModelIndex, Qt, Signal, Slot +from PySide6.QtGui import QShowEvent +from PySide6.QtWidgets import QCompleter, QWidget + +from ui.designer.components.songIdSelector_ui import Ui_SongIdSelector +from ui.extends.components.songIdSelector import SearchCompleterModel +from ui.extends.shared.delegates.descriptionDelegate import DescriptionDelegate + +logger = logging.getLogger(__name__) + + +class SongIdSelector(Ui_SongIdSelector, QWidget): + valueChanged = Signal() + + def __init__(self, parent=None): + super().__init__(parent) + self.db = Database() + self.setupUi(self) + + self.previousPackageButton.clicked.connect( + lambda: self.quickSwitchSelection("previous", "package") + ) + self.previousSongIdButton.clicked.connect( + lambda: self.quickSwitchSelection("previous", "songId") + ) + self.nextSongIdButton.clicked.connect( + lambda: self.quickSwitchSelection("next", "songId") + ) + self.nextPackageButton.clicked.connect( + lambda: self.quickSwitchSelection("next", "package") + ) + + self.fillPackComboBox() + self.packComboBox.setCurrentIndex(-1) + self.songIdComboBox.setCurrentIndex(-1) + + self.searchCompleterModel = SearchCompleterModel() + self.searchCompleter = QCompleter(self.searchCompleterModel) + self.searchCompleter.popup().setItemDelegate( + DescriptionDelegate(self.searchCompleter.popup()) + ) + self.searchCompleter.activated[QModelIndex].connect( + self.searchCompleterSetSelection + ) + self.searchLineEdit.setCompleter(self.searchCompleter) + + self.packComboBox.setItemDelegate(DescriptionDelegate(self.packComboBox)) + self.songIdComboBox.setItemDelegate(DescriptionDelegate(self.songIdComboBox)) + + self.packComboBox.currentIndexChanged.connect(self.valueChanged) + self.songIdComboBox.currentIndexChanged.connect(self.valueChanged) + + def quickSwitchSelection( + self, + direction: Literal["previous", "next"], + model: Literal["package", "songId"], + ): + minIndex = 0 + if model == "package": + maxIndex = self.packComboBox.count() - 1 + currentIndex = self.packComboBox.currentIndex() + ( + 1 if direction == "next" else -1 + ) + currentIndex = max(min(maxIndex, currentIndex), minIndex) + self.packComboBox.setCurrentIndex(currentIndex) + elif model == "songId": + maxIndex = self.songIdComboBox.count() - 1 + currentIndex = self.songIdComboBox.currentIndex() + ( + 1 if direction == "next" else -1 + ) + currentIndex = max(min(maxIndex, currentIndex), minIndex) + self.songIdComboBox.setCurrentIndex(currentIndex) + else: + return + + def value(self): + return self.songIdComboBox.currentData() + + def reset(self): + self.packComboBox.setCurrentIndex(-1) + self.songIdComboBox.setCurrentIndex(-1) + + def showEvent(self, event: QShowEvent): + # update database results when widget visible + self.searchCompleterModel.updateSearcherSongs() + + # remember selection and restore later + pack = self.packComboBox.currentData() + songId = self.songIdComboBox.currentData() + + self.fillPackComboBox() + + if pack: + self.selectPack(pack) + if songId: + self.selectSongId(songId) + return super().showEvent(event) + + def fillPackComboBox(self): + self.packComboBox.clear() + packs = self.db.get_packs() + for pack in packs: + isAppendPack = re.search(r"_append_.*$", pack.id) + if isAppendPack: + basePackId = re.sub(r"_append_.*$", "", pack.id) + basePackName = self.db.get_pack_by_id(basePackId).name + packName = f"{basePackName} - {pack.name}" + else: + packName = pack.name + self.packComboBox.addItem(f"{packName} ({pack.id})", pack.id) + row = self.packComboBox.count() - 1 + self.packComboBox.setItemData( + row, packName, DescriptionDelegate.MainTextRole + ) + self.packComboBox.setItemData( + row, pack.id, DescriptionDelegate.DescriptionTextRole + ) + + self.packComboBox.setCurrentIndex(-1) + + def fillSongIdComboBox(self): + self.songIdComboBox.clear() + packId = self.packComboBox.currentData() + if packId: + charts = self.db.get_charts_by_pack_id(packId) + inserted_song_ids = [] + for chart in charts: + if chart.song_id not in inserted_song_ids: + self.songIdComboBox.addItem( + f"{chart.title} ({chart.song_id})", chart.song_id + ) + inserted_song_ids.append(chart.song_id) + row = self.songIdComboBox.count() - 1 + self.songIdComboBox.setItemData( + row, chart.title, DescriptionDelegate.MainTextRole + ) + self.songIdComboBox.setItemData( + row, chart.song_id, DescriptionDelegate.DescriptionTextRole + ) + self.songIdComboBox.setCurrentIndex(-1) + + @Slot() + def on_packComboBox_activated(self): + self.fillSongIdComboBox() + + @Slot(str) + def on_searchLineEdit_textChanged(self, text: str): + if text: + self.searchCompleterModel.getSearchResult(text) + else: + self.searchCompleterModel.clear() + + def selectPack(self, packId: str) -> bool: + packIdIndex = self.packComboBox.findData(packId) + if packIdIndex > -1: + self.packComboBox.setCurrentIndex(packIdIndex) + self.fillSongIdComboBox() + return True + else: + logger.warning(f'Attempting to select an unknown pack "{packId}"') + return False + + def selectSongId(self, songId: str) -> bool: + songIdIndex = self.songIdComboBox.findData(songId) + if songIdIndex > -1: + self.songIdComboBox.setCurrentIndex(songIdIndex) + return True + else: + logger.warning( + f'Attempting to select an unknown song "{songId}", maybe try selecting a pack first?' + ) + return False + + def selectChart(self, chart: Chart): + if not self.selectPack(chart.set): + return False + return self.selectSongId(chart.song_id) + + @Slot(QModelIndex) + def searchCompleterSetSelection(self, index: QModelIndex): + chart = index.data(Qt.ItemDataRole.UserRole + 10) # type: Chart + self.selectChart(chart) + + self.searchLineEdit.clear() + self.searchLineEdit.clearFocus()