45 Commits

Author SHA1 Message Date
d5895fe230 chore: v0.3.8 2024-04-01 01:00:46 +08:00
cd2e3f51ca ci: update build actions 2024-04-01 01:00:27 +08:00
4a09dc210a Merge pull request #7 from ArcaeaOffline/fix-issue-6
fix: rating class selection logic
2024-03-24 16:40:24 +08:00
cc8ab11b78 fix: rating class selection logic 2024-03-24 16:17:48 +08:00
48c5682e55 Merge pull request #5 from ArcaeaOffline/fix-issue-4
fix: linux dbUrl issue
2024-03-23 19:08:23 +08:00
ee03770764 chore: update README 2024-03-23 18:21:48 +08:00
b45c7f7de5 chore: dependencies 2024-03-23 18:18:53 +08:00
15bc56e6f9 fix: linux dbUrl issue 2024-03-23 17:41:36 +08:00
39ee379010 feat: ETERNAL rating class support 2024-03-20 15:52:26 +08:00
5a71a5822b feat: sync chart info database 2024-03-16 02:14:47 +08:00
c888b312b3 feat: DEF v2 scores export support 2024-02-27 17:24:49 +08:00
8e4fdc30b5 refactor(ui): TabDb_Manage 2024-02-15 17:59:14 +08:00
1ca868cfc6 ci: get full repo history for VERSION generating 2023-11-09 21:53:55 +08:00
d63d2f0d8b ci: build actions improve 2023-11-01 21:30:31 +08:00
3cd187fde3 ci: github actions 2023-11-01 20:00:16 +08:00
cce918a121 chore: update dependencies 2023-11-01 15:57:11 +08:00
1ec302d98c Merge branch 'master' of github.com:283375/arcaea-offline-pyside-ui 2023-10-29 17:13:52 +08:00
3d6e5f997e pre-commit 2023-10-29 00:12:01 +08:00
495f6dc424 impr: TabDb_RemoveDuplicateScores chart selecting 2023-10-25 20:04:23 +08:00
0b599e3d9c fix: ensure database reset works 2023-10-25 18:58:13 +08:00
a51a67fae3 impr: minor improvements 2023-10-25 17:53:21 +08:00
b48e177ae8 feat: TabDb_RemoveDuplicateScores 2023-10-25 17:41:40 +08:00
865fc8b7c8 style: isort & black ignore files 2023-10-23 23:51:29 +08:00
1eeec6f745 wip: TabDb_RemoveDuplicateScores ui 2023-10-23 23:51:11 +08:00
8558f5e403 impr: handle exceptions in TabOverview 2023-10-23 16:18:35 +08:00
1a37310091 impr: TabTools_Andreal source code link 2023-10-23 16:15:26 +08:00
d460e935b4 fix: DbB30TableModel 2023-10-23 16:08:51 +08:00
38d2e4ad5a fix: translation file extraction script 2023-10-23 16:08:11 +08:00
28599cfb04 feat: DatabaseChecker re-init database button 2023-10-23 15:31:56 +08:00
1d01356327 impr: popup PlayRatingCalculator when double clicking an item in TabTools_ChartRecommend 2023-10-23 15:19:56 +08:00
738975a83d chore: translations 2023-10-23 14:39:46 +08:00
5adea908f9 impr: PlayRatingCalculator ui 2023-10-23 14:39:36 +08:00
21ca1018db impr: translation file extraction script 2023-10-23 14:39:11 +08:00
51e15c68e0 chore: dependencies 2023-10-23 13:28:42 +08:00
00f680edd3 fix: cv2.Mat type annotation 2023-10-23 13:28:33 +08:00
7dee8114bf impr: prebuild update 2023-10-23 13:28:06 +08:00
90e66a43fe impr: log Andreal executable output 2023-10-23 10:16:19 +08:00
381f27db87 fix: crop black edges before ocr 2023-10-22 01:57:18 +08:00
e0d92b7784 impr: TabTools_StepCalculator ui 2023-10-22 01:17:16 +08:00
5aedf91c09 impr: ChartInfoEditor tap stop order 2023-10-22 00:51:21 +08:00
b193b82d95 feat: PlayRatingCalculator component 2023-10-22 00:51:07 +08:00
01457f3559 feat: SmartRTE csv export 2023-10-21 23:03:59 +08:00
dd647d6963 fix: DbScoreTableModel score committing 2023-10-21 18:59:42 +08:00
7de2eda517 impr: score validation 2023-10-21 18:58:30 +08:00
d918032b9c impr: log uncaught exceptions 2023-10-21 14:00:27 +08:00
47 changed files with 2677 additions and 742 deletions

View File

@ -0,0 +1,40 @@
name: Build UI from latest `arcaea-offline-*` dependencies
run-name: ${{ github.actor }} started a build request.
on:
workflow_dispatch:
jobs:
build-windows:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.11"
# install dependencies
- run: "pip install -r requirements.txt"
- run: "pip uninstall arcaea-offline arcaea-offline-ocr -y"
- run: "pip install git+https://github.com/283375/arcaea-offline"
- run: "pip install git+https://github.com/283375/arcaea-offline-ocr"
- run: "pip install nuitka imageio"
- name: Install UPX
uses: crazy-max/ghaction-upx@v3
with:
install-only: true
# release builtin files
- run: 'pyside6-lrelease.exe .\ui\resources\lang\en_US.ts .\ui\resources\lang\zh_CN.ts'
- run: "python prebuild.py"
- run: 'pyside6-rcc.exe .\ui\resources\resources.qrc -o .\ui\resources\resources_rc.py'
# build
- run: "python -m nuitka --plugin-enable=upx --enable-plugin=pyside6 --assume-yes-for-downloads --windows-icon-from-ico=./ui/resources/images/icon.png --standalone --onefile index.py"
- uses: actions/upload-artifact@v3
with:
name: build-windows
path: index.exe

49
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,49 @@
name: Build UI
run-name: ${{ github.actor }} started a build request.
on:
workflow_dispatch:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
permissions:
contents: write
discussions: write
jobs:
build-windows:
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"
# install dependencies
- run: "pip install -r requirements.txt"
- run: "pip install nuitka imageio"
- name: Install UPX
uses: crazy-max/ghaction-upx@v3
with:
install-only: true
# release builtin files
- run: 'pyside6-lrelease.exe .\ui\resources\lang\en_US.ts .\ui\resources\lang\zh_CN.ts'
- run: "python prebuild.py"
- run: 'pyside6-rcc.exe .\ui\resources\resources.qrc -o .\ui\resources\resources_rc.py'
# build
- run: "python -m nuitka --plugin-enable=upx --enable-plugin=pyside6 --assume-yes-for-downloads --windows-icon-from-ico=./ui/resources/images/icon.png --standalone --onefile index.py"
- name: Draft a release
uses: softprops/action-gh-release@v2
with:
discussion_category_name: New releases
draft: true
generate_release_notes: true
files: |
index.exe

14
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,14 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort

View File

@ -1,9 +1,27 @@
# Arcaea Offline PySide UI
GUI for both [283375/arcaea-offline](https://github.com/283375/arcaea-offline) and [283375/arcaea-offline-ocr](https://github.com/283375/arcaea-offline-ocr)
GUI for both [283375/arcaea-offline](https://github.com/283375/arcaea-offline) and [ArcaeaOffline/core-ocr](https://github.com/ArcaeaOffline/core-ocr).
## Before you run `python index.py`...
## Prerequisites
* Install requirements
* Release translation files from `ui/resources/lang/*.ts`
* Run `prebuild.py`
* Compile `ui/resources/resources.qrc` to `ui/resources/resources_rc.py`
You can refer to the [GitHub Actions file](./.github/workflows/build.yml) for a rough reference.
```
pip install -r ./requirements.txt
pyside6-lrelease ./ui/resources/lang/en_US.ts ./ui/resources/lang/zh_CN.ts
python prebuild.py
pyside6-rcc ./ui/resources/resources.qrc -o ./ui/resources/resources_rc.py
```
Sometimes you have to install the latest, unpublished version of `arcaea-offline` and `arcaea-offline-ocr`.
```
pip uninstall -y arcaea-offline arcaea-offline-ocr
pip install git+https://github.com/283375/arcaea-offline
pip install git+https://github.com/ArcaeaOffline/core-ocr
```

View File

@ -23,6 +23,19 @@ rootLoggerFormatter = logging.Formatter(
)
def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
rootLogger.critical(
"Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)
)
sys.excepthook = handle_exception
if __name__ == "__main__":
QCoreApplication.setApplicationName("Arcaea Offline")
@ -55,7 +68,7 @@ if __name__ == "__main__":
databaseChecker = DatabaseChecker()
databaseChecker.setWindowIcon(QIcon(":/images/icon.png"))
databaseCheckResult = databaseChecker.confirmDb()
databaseCheckResult = databaseChecker.confirmDb() if Settings().databaseUrl() else 0
if not databaseCheckResult & DatabaseCheckerResult.Initted:
result = databaseChecker.exec()

View File

@ -1,70 +1,86 @@
import os
import platform
import subprocess
from importlib import metadata
from pathlib import Path
# fill VERSION file
versionFile = Path("ui/resources/VERSION")
assert versionFile.exists()
versionTexts = []
def getGitDesc():
gitDescribe = subprocess.run(
["git", "describe", "--tags", "--long"],
capture_output=True,
encoding="utf-8",
)
if gitDescribe.returncode == 0:
return gitDescribe.stdout.replace("\n", "")
projectVersionText = "arcaea-offline-pyside-ui\n"
gitDescribe = os.popen("git describe --tags --long")
gitDescribeContent = gitDescribe.read().replace("\n", "")
if gitDescribe.close() is None:
projectVersionText += f"{gitDescribeContent}"
else:
gitRevParse = os.popen("git rev-parse --short HEAD")
gitRevParseContent = gitRevParse.read().replace("\n", "")
projectVersionText += f"commit {gitRevParseContent}"
gitRevParse.close()
projectVersionText += "\n"
# describe failed, try rev-parse
gitRevParse = subprocess.run(
["git", "rev-parse", "--short", "HEAD"],
capture_output=True,
encoding="utf-8",
)
if gitRevParse.returncode == 0:
return f"commit {gitRevParse.stdout}".replace("\n", "")
versionTexts.append(projectVersionText)
return "version/commit unknown"
# detect pip
pipName = None
possiblePipNames = ["pip3", "pip"]
for possiblePipName in possiblePipNames:
result = os.popen(possiblePipName).read()
if (
"<command> [options]" in result
and "install" in result
and "--upgrade" in result
):
pipName = possiblePipName
break
def getBuildToolsVer():
texts = []
possibleBuildTools = ["Nuitka", "pyinstaller"]
for possibleBuildTool in possibleBuildTools:
try:
version = metadata.version(possibleBuildTool)
texts.append(f"{possibleBuildTool}=={version}")
except metadata.PackageNotFoundError:
texts.append(f"{possibleBuildTool} not installed")
return ", ".join(texts)
# if possiblePipName:
# pipFreezeLines = os.popen(f"{possiblePipName} freeze").read().split("\n")
# text = [
# pipFreezeResult
# for pipFreezeResult in pipFreezeLines
# if (
# "arcaea-offline" in pipFreezeResult
# or "PySide6" in pipFreezeResult
# or "exif" in pipFreezeResult
# or "opencv-python" in pipFreezeResult
# or "SQLAlchemy" in pipFreezeResult
# )
# ]
# versionTexts.append("\n".join(text))
def writeVersionFile():
versionFile = Path("ui/resources/VERSION")
importLibTexts = [
f"{module}=={metadata.version(module)}"
for module in [
"arcaea-offline",
"arcaea-offline-ocr",
"exif",
"opencv-python",
"PySide6",
"SQLAlchemy",
"SQLAlchemy-Utils",
versionText = (
"arcaea-offline-pyside-ui\n{gitDesc}\n{buildToolsVer}\n\n"
"{pythonVer}\n\n"
"{depsVer}\n"
)
gitDesc = getGitDesc()
buildToolsVer = getBuildToolsVer()
pythonVer = f"{platform.python_implementation()} {platform.python_version()} ({platform.python_build()[0]})"
importLibTexts = [
f"{module}=={metadata.version(module)}"
for module in sorted(
[
"arcaea-offline",
"arcaea-offline-ocr",
"exif",
"numpy",
"opencv-python",
"Pillow",
"PySide6",
"SQLAlchemy",
"SQLAlchemy-Utils",
"Whoosh",
],
key=lambda s: s.lower(),
)
]
]
versionTexts.append("\n".join(importLibTexts))
importLibText = "\n".join(importLibTexts)
with versionFile.open("w", encoding="utf-8") as vf:
vf.write("\n".join(versionTexts))
with versionFile.open("w", encoding="utf-8") as vf:
vf.write(
versionText.format(
gitDesc=gitDesc,
buildToolsVer=buildToolsVer,
pythonVer=pythonVer,
depsVer=importLibText,
)
)
writeVersionFile()

View File

@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
[project]
name = "arcaea-offline-pyside-ui"
version = "0.1.0"
version = "0.3.8"
authors = [{ name = "283375", email = "log_283375@163.com" }]
description = "No description."
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"arcaea-offline==0.1.0",
"arcaea-offline-ocr==0.1.0",
"arcaea-offline==0.2.2",
"arcaea-offline-ocr==0.0.98",
"exif==1.6.0",
"PySide6==6.5.2",
]
@ -21,13 +21,14 @@ classifiers = [
]
[project.urls]
"Homepage" = "https://github.com/283375/arcaea-offline-pyside-ui"
"Bug Tracker" = "https://github.com/283375/arcaea-offline-pyside-ui/issues"
"Homepage" = "https://github.com/ArcaeaOffline/client-pyside6"
"Bug Tracker" = "https://github.com/ArcaeaOffline/client-pyside6/issues"
[tool.black]
force-exclude = '''
(
ui/designer
| .*_ui.py
| .*_rc.py
)
'''
@ -35,7 +36,7 @@ force-exclude = '''
[tool.isort]
profile = "black"
extend_skip = ["ui/designer"]
extend_skip_glob = ["*_rc.py"]
extend_skip_glob = ["*_ui.py", "*_rc.py"]
[tool.pyright]
ignore = ["**/__debug*.*"]

View File

@ -1,2 +1,4 @@
black == 23.7.0
isort == 5.12.0
imageio==2.31.4
Nuitka==1.8.4

View File

@ -1,4 +1,5 @@
arcaea-offline==0.1.0
arcaea-offline-ocr==0.1.0
arcaea-offline==0.2.2
arcaea-offline-ocr==0.0.98
exif==1.6.0
Pillow==10.1.0
PySide6==6.5.2

View File

@ -258,6 +258,13 @@
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>listView</tabstop>
<tabstop>constantLineEdit</tabstop>
<tabstop>notesLineEdit</tabstop>
<tabstop>commitButton</tabstop>
<tabstop>deleteButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -179,6 +179,10 @@ class Ui_TabDb_ChartInfoEditor(object):
self.gridLayout.addWidget(self.listView, 1, 0, 1, 1)
QWidget.setTabOrder(self.listView, self.constantLineEdit)
QWidget.setTabOrder(self.constantLineEdit, self.notesLineEdit)
QWidget.setTabOrder(self.notesLineEdit, self.commitButton)
QWidget.setTabOrder(self.commitButton, self.deleteButton)
self.retranslateUi(TabDb_ChartInfoEditor)

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>528</height>
<width>580</width>
<height>551</height>
</rect>
</property>
<property name="windowTitle">
@ -17,70 +17,21 @@
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QPushButton" name="syncArcSongDbButton">
<property name="text">
<string>syncArcSongDbButton</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>syncArcSongDb.description</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="importSt3Button">
<property name="text">
<string>importSt3Button</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>importSt3.description</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QPushButton" name="exportScoresButton">
<property name="text">
<string>exportScoresButton</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>exportScores.description</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="1" column="0">
<widget class="QPushButton" name="importPacklistButton">
<property name="text">
<string>importPacklistButton</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="1" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>importPacklist.description</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="importSonglistButton">
<property name="text">
<string>importSonglistButton</string>
@ -88,61 +39,259 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>importPacklist.description</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string>importSonglist.description</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QPushButton" name="exportArcsongJsonButton">
<property name="text">
<string>exportArcsongJsonButton</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>exportArcsongJson.description</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="3" column="0">
<widget class="QPushButton" name="importApkButton">
<property name="text">
<string>importApkButton</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="3" column="1">
<widget class="QLabel" name="label_7">
<property name="text">
<string>importApk.description</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QLabel" name="label_11">
<property name="font">
<font>
<pointsize>12</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>chartInfoGroup</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="syncArcSongDbButton">
<property name="text">
<string>syncArcSongDbButton</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>syncArcSongDb.description</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="QLabel" name="label_12">
<property name="font">
<font>
<pointsize>12</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>importScoreGroup</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QPushButton" name="importSt3Button">
<property name="text">
<string>importSt3Button</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>importSt3.description</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QPushButton" name="importOnlineButton">
<property name="text">
<string>importOnlineButton</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="11" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>importOnline.description</string>
</property>
</widget>
</item>
<item row="13" column="0" colspan="2">
<widget class="QLabel" name="label_13">
<property name="font">
<font>
<pointsize>12</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>exportScoreGroup</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QPushButton" name="exportScoresButton">
<property name="text">
<string>exportScoresButton</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>exportScores.description</string>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QPushButton" name="exportSmartRteB30Button">
<property name="text">
<string>exportSmartRteB30Button</string>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_9">
<property name="text">
<string>exportSmartRteB30.description</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item row="17" column="0" colspan="2">
<widget class="QLabel" name="label_14">
<property name="font">
<font>
<pointsize>12</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>miscGroup</string>
</property>
</widget>
</item>
<item row="18" column="0">
<widget class="QPushButton" name="exportArcsongJsonButton">
<property name="text">
<string>exportArcsongJsonButton</string>
</property>
</widget>
</item>
<item row="18" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>exportArcsongJson.description</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
<pointsize>12</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>packSongInfoGroup</string>
</property>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="12" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="16" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="0">
<widget class="QPushButton" name="syncChartInfoDbButton">
<property name="text">
<string>syncChartInfoDbButton</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_15">
<property name="text">
<string>syncChartInfoDb.description</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@ -15,111 +15,168 @@ 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, QFormLayout, QFrame, QLabel,
QPushButton, QSizePolicy, QWidget)
from PySide6.QtWidgets import (QApplication, QFormLayout, QLabel, QPushButton,
QSizePolicy, QSpacerItem, QWidget)
class Ui_TabDb_Manage(object):
def setupUi(self, TabDb_Manage):
if not TabDb_Manage.objectName():
TabDb_Manage.setObjectName(u"TabDb_Manage")
TabDb_Manage.resize(630, 528)
TabDb_Manage.resize(580, 551)
TabDb_Manage.setWindowTitle(u"TabDb_Manage")
self.formLayout = QFormLayout(TabDb_Manage)
self.formLayout.setObjectName(u"formLayout")
self.formLayout.setLabelAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
self.syncArcSongDbButton = QPushButton(TabDb_Manage)
self.syncArcSongDbButton.setObjectName(u"syncArcSongDbButton")
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.syncArcSongDbButton)
self.label = QLabel(TabDb_Manage)
self.label.setObjectName(u"label")
self.formLayout.setWidget(0, QFormLayout.FieldRole, self.label)
self.importSt3Button = QPushButton(TabDb_Manage)
self.importSt3Button.setObjectName(u"importSt3Button")
self.formLayout.setWidget(5, QFormLayout.LabelRole, self.importSt3Button)
self.label_2 = QLabel(TabDb_Manage)
self.label_2.setObjectName(u"label_2")
self.formLayout.setWidget(5, QFormLayout.FieldRole, self.label_2)
self.line = QFrame(TabDb_Manage)
self.line.setObjectName(u"line")
self.line.setFrameShape(QFrame.HLine)
self.line.setFrameShadow(QFrame.Sunken)
self.formLayout.setWidget(7, QFormLayout.SpanningRole, self.line)
self.exportScoresButton = QPushButton(TabDb_Manage)
self.exportScoresButton.setObjectName(u"exportScoresButton")
self.formLayout.setWidget(8, QFormLayout.LabelRole, self.exportScoresButton)
self.label_3 = QLabel(TabDb_Manage)
self.label_3.setObjectName(u"label_3")
self.formLayout.setWidget(8, QFormLayout.FieldRole, self.label_3)
self.line_2 = QFrame(TabDb_Manage)
self.line_2.setObjectName(u"line_2")
self.line_2.setFrameShape(QFrame.HLine)
self.line_2.setFrameShadow(QFrame.Sunken)
self.formLayout.setWidget(1, QFormLayout.SpanningRole, self.line_2)
self.importPacklistButton = QPushButton(TabDb_Manage)
self.importPacklistButton.setObjectName(u"importPacklistButton")
self.formLayout.setWidget(2, QFormLayout.LabelRole, self.importPacklistButton)
self.importSonglistButton = QPushButton(TabDb_Manage)
self.importSonglistButton.setObjectName(u"importSonglistButton")
self.formLayout.setWidget(3, QFormLayout.LabelRole, self.importSonglistButton)
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.importPacklistButton)
self.label_4 = QLabel(TabDb_Manage)
self.label_4.setObjectName(u"label_4")
self.formLayout.setWidget(2, QFormLayout.FieldRole, self.label_4)
self.formLayout.setWidget(1, QFormLayout.FieldRole, self.label_4)
self.importSonglistButton = QPushButton(TabDb_Manage)
self.importSonglistButton.setObjectName(u"importSonglistButton")
self.formLayout.setWidget(2, QFormLayout.LabelRole, self.importSonglistButton)
self.label_5 = QLabel(TabDb_Manage)
self.label_5.setObjectName(u"label_5")
self.formLayout.setWidget(3, QFormLayout.FieldRole, self.label_5)
self.exportArcsongJsonButton = QPushButton(TabDb_Manage)
self.exportArcsongJsonButton.setObjectName(u"exportArcsongJsonButton")
self.formLayout.setWidget(9, QFormLayout.LabelRole, self.exportArcsongJsonButton)
self.label_6 = QLabel(TabDb_Manage)
self.label_6.setObjectName(u"label_6")
self.formLayout.setWidget(9, QFormLayout.FieldRole, self.label_6)
self.formLayout.setWidget(2, QFormLayout.FieldRole, self.label_5)
self.importApkButton = QPushButton(TabDb_Manage)
self.importApkButton.setObjectName(u"importApkButton")
self.formLayout.setWidget(4, QFormLayout.LabelRole, self.importApkButton)
self.formLayout.setWidget(3, QFormLayout.LabelRole, self.importApkButton)
self.label_7 = QLabel(TabDb_Manage)
self.label_7.setObjectName(u"label_7")
self.formLayout.setWidget(4, QFormLayout.FieldRole, self.label_7)
self.formLayout.setWidget(3, QFormLayout.FieldRole, self.label_7)
self.label_11 = QLabel(TabDb_Manage)
self.label_11.setObjectName(u"label_11")
font = QFont()
font.setPointSize(12)
font.setBold(False)
self.label_11.setFont(font)
self.formLayout.setWidget(5, QFormLayout.SpanningRole, self.label_11)
self.syncArcSongDbButton = QPushButton(TabDb_Manage)
self.syncArcSongDbButton.setObjectName(u"syncArcSongDbButton")
self.formLayout.setWidget(6, QFormLayout.LabelRole, self.syncArcSongDbButton)
self.label = QLabel(TabDb_Manage)
self.label.setObjectName(u"label")
self.formLayout.setWidget(6, QFormLayout.FieldRole, self.label)
self.label_12 = QLabel(TabDb_Manage)
self.label_12.setObjectName(u"label_12")
self.label_12.setFont(font)
self.formLayout.setWidget(9, QFormLayout.SpanningRole, self.label_12)
self.importSt3Button = QPushButton(TabDb_Manage)
self.importSt3Button.setObjectName(u"importSt3Button")
self.formLayout.setWidget(10, QFormLayout.LabelRole, self.importSt3Button)
self.label_2 = QLabel(TabDb_Manage)
self.label_2.setObjectName(u"label_2")
self.formLayout.setWidget(10, QFormLayout.FieldRole, self.label_2)
self.importOnlineButton = QPushButton(TabDb_Manage)
self.importOnlineButton.setObjectName(u"importOnlineButton")
self.formLayout.setWidget(6, QFormLayout.LabelRole, self.importOnlineButton)
self.formLayout.setWidget(11, QFormLayout.LabelRole, self.importOnlineButton)
self.label_8 = QLabel(TabDb_Manage)
self.label_8.setObjectName(u"label_8")
self.formLayout.setWidget(6, QFormLayout.FieldRole, self.label_8)
self.formLayout.setWidget(11, QFormLayout.FieldRole, self.label_8)
self.label_13 = QLabel(TabDb_Manage)
self.label_13.setObjectName(u"label_13")
self.label_13.setFont(font)
self.formLayout.setWidget(13, QFormLayout.SpanningRole, self.label_13)
self.exportScoresButton = QPushButton(TabDb_Manage)
self.exportScoresButton.setObjectName(u"exportScoresButton")
self.formLayout.setWidget(14, QFormLayout.LabelRole, self.exportScoresButton)
self.label_3 = QLabel(TabDb_Manage)
self.label_3.setObjectName(u"label_3")
self.formLayout.setWidget(14, QFormLayout.FieldRole, self.label_3)
self.exportSmartRteB30Button = QPushButton(TabDb_Manage)
self.exportSmartRteB30Button.setObjectName(u"exportSmartRteB30Button")
self.formLayout.setWidget(15, QFormLayout.LabelRole, self.exportSmartRteB30Button)
self.label_9 = QLabel(TabDb_Manage)
self.label_9.setObjectName(u"label_9")
self.label_9.setOpenExternalLinks(True)
self.label_9.setTextInteractionFlags(Qt.LinksAccessibleByKeyboard|Qt.LinksAccessibleByMouse)
self.formLayout.setWidget(15, QFormLayout.FieldRole, self.label_9)
self.label_14 = QLabel(TabDb_Manage)
self.label_14.setObjectName(u"label_14")
self.label_14.setFont(font)
self.formLayout.setWidget(17, QFormLayout.SpanningRole, self.label_14)
self.exportArcsongJsonButton = QPushButton(TabDb_Manage)
self.exportArcsongJsonButton.setObjectName(u"exportArcsongJsonButton")
self.formLayout.setWidget(18, QFormLayout.LabelRole, self.exportArcsongJsonButton)
self.label_6 = QLabel(TabDb_Manage)
self.label_6.setObjectName(u"label_6")
self.formLayout.setWidget(18, QFormLayout.FieldRole, self.label_6)
self.label_10 = QLabel(TabDb_Manage)
self.label_10.setObjectName(u"label_10")
self.label_10.setFont(font)
self.formLayout.setWidget(0, QFormLayout.SpanningRole, self.label_10)
self.verticalSpacer = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Minimum)
self.formLayout.setItem(4, QFormLayout.LabelRole, self.verticalSpacer)
self.verticalSpacer_2 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Minimum)
self.formLayout.setItem(8, QFormLayout.LabelRole, self.verticalSpacer_2)
self.verticalSpacer_3 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Minimum)
self.formLayout.setItem(12, QFormLayout.LabelRole, self.verticalSpacer_3)
self.verticalSpacer_4 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Minimum)
self.formLayout.setItem(16, QFormLayout.LabelRole, self.verticalSpacer_4)
self.syncChartInfoDbButton = QPushButton(TabDb_Manage)
self.syncChartInfoDbButton.setObjectName(u"syncChartInfoDbButton")
self.formLayout.setWidget(7, QFormLayout.LabelRole, self.syncChartInfoDbButton)
self.label_15 = QLabel(TabDb_Manage)
self.label_15.setObjectName(u"label_15")
self.formLayout.setWidget(7, QFormLayout.FieldRole, self.label_15)
self.retranslateUi(TabDb_Manage)
@ -128,22 +185,30 @@ class Ui_TabDb_Manage(object):
# setupUi
def retranslateUi(self, TabDb_Manage):
self.syncArcSongDbButton.setText(QCoreApplication.translate("TabDb_Manage", u"syncArcSongDbButton", None))
self.label.setText(QCoreApplication.translate("TabDb_Manage", u"syncArcSongDb.description", None))
self.importSt3Button.setText(QCoreApplication.translate("TabDb_Manage", u"importSt3Button", None))
self.label_2.setText(QCoreApplication.translate("TabDb_Manage", u"importSt3.description", None))
self.exportScoresButton.setText(QCoreApplication.translate("TabDb_Manage", u"exportScoresButton", None))
self.label_3.setText(QCoreApplication.translate("TabDb_Manage", u"exportScores.description", None))
self.importPacklistButton.setText(QCoreApplication.translate("TabDb_Manage", u"importPacklistButton", None))
self.importSonglistButton.setText(QCoreApplication.translate("TabDb_Manage", u"importSonglistButton", None))
self.label_4.setText(QCoreApplication.translate("TabDb_Manage", u"importPacklist.description", None))
self.importSonglistButton.setText(QCoreApplication.translate("TabDb_Manage", u"importSonglistButton", None))
self.label_5.setText(QCoreApplication.translate("TabDb_Manage", u"importSonglist.description", None))
self.exportArcsongJsonButton.setText(QCoreApplication.translate("TabDb_Manage", u"exportArcsongJsonButton", None))
self.label_6.setText(QCoreApplication.translate("TabDb_Manage", u"exportArcsongJson.description", None))
self.importApkButton.setText(QCoreApplication.translate("TabDb_Manage", u"importApkButton", None))
self.label_7.setText(QCoreApplication.translate("TabDb_Manage", u"importApk.description", None))
self.label_11.setText(QCoreApplication.translate("TabDb_Manage", u"chartInfoGroup", None))
self.syncArcSongDbButton.setText(QCoreApplication.translate("TabDb_Manage", u"syncArcSongDbButton", None))
self.label.setText(QCoreApplication.translate("TabDb_Manage", u"syncArcSongDb.description", None))
self.label_12.setText(QCoreApplication.translate("TabDb_Manage", u"importScoreGroup", None))
self.importSt3Button.setText(QCoreApplication.translate("TabDb_Manage", u"importSt3Button", None))
self.label_2.setText(QCoreApplication.translate("TabDb_Manage", u"importSt3.description", None))
self.importOnlineButton.setText(QCoreApplication.translate("TabDb_Manage", u"importOnlineButton", None))
self.label_8.setText(QCoreApplication.translate("TabDb_Manage", u"importOnline.description", None))
self.label_13.setText(QCoreApplication.translate("TabDb_Manage", u"exportScoreGroup", None))
self.exportScoresButton.setText(QCoreApplication.translate("TabDb_Manage", u"exportScoresButton", None))
self.label_3.setText(QCoreApplication.translate("TabDb_Manage", u"exportScores.description", None))
self.exportSmartRteB30Button.setText(QCoreApplication.translate("TabDb_Manage", u"exportSmartRteB30Button", None))
self.label_9.setText(QCoreApplication.translate("TabDb_Manage", u"exportSmartRteB30.description", None))
self.label_14.setText(QCoreApplication.translate("TabDb_Manage", u"miscGroup", None))
self.exportArcsongJsonButton.setText(QCoreApplication.translate("TabDb_Manage", u"exportArcsongJsonButton", None))
self.label_6.setText(QCoreApplication.translate("TabDb_Manage", u"exportArcsongJson.description", None))
self.label_10.setText(QCoreApplication.translate("TabDb_Manage", u"packSongInfoGroup", None))
self.syncChartInfoDbButton.setText(QCoreApplication.translate("TabDb_Manage", u"syncChartInfoDbButton", None))
self.label_15.setText(QCoreApplication.translate("TabDb_Manage", u"syncChartInfoDb.description", None))
pass
# retranslateUi

View File

@ -0,0 +1,286 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TabDb_RemoveDuplicateScores</class>
<widget class="QWidget" name="TabDb_RemoveDuplicateScores">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">TabDb_RemoveDuplicateScores</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>scan.title</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="scan_option_scoreCheckBox">
<property name="text">
<string>scan.option.score</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="scan_option_pureCheckBox">
<property name="text">
<string notr="true">PURE</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="scan_option_farCheckBox">
<property name="text">
<string notr="true">FAR</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="scan_option_lostCheckBox">
<property name="text">
<string notr="true">LOST</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="scan_option_maxRecallCheckBox">
<property name="text">
<string notr="true">MAX RECALL</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="scan_option_dateCheckBox">
<property name="text">
<string>scan.option.date</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="scan_option_modifierCheckBox">
<property name="text">
<string>scan.option.modifier</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="scan_option_clearTypeCheckBox">
<property name="text">
<string>scan.option.clearType</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="scan_scanButton">
<property name="text">
<string>scan.scanButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeView" name="treeView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>quickSelect.title</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>quickSelect.description</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="quickSelect_comboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="quickSelect_selectButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>quickSelect.selectButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QPushButton" name="deselectAllButton">
<property name="text">
<string>deselectAllButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="reverseSelectionButton">
<property name="text">
<string>reverseSelectionButton</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="collapseAllButton">
<property name="text">
<string>collapseAllButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="expandAllButton">
<property name="text">
<string>expandAllButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="resetModelButton">
<property name="text">
<string>resetModelButton</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="deleteSelectionButton">
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">QPushButton { color: red };</string>
</property>
<property name="text">
<string>deleteSelectionButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>scan_option_scoreCheckBox</tabstop>
<tabstop>scan_option_pureCheckBox</tabstop>
<tabstop>scan_option_farCheckBox</tabstop>
<tabstop>scan_option_lostCheckBox</tabstop>
<tabstop>scan_option_maxRecallCheckBox</tabstop>
<tabstop>scan_option_dateCheckBox</tabstop>
<tabstop>scan_option_modifierCheckBox</tabstop>
<tabstop>scan_option_clearTypeCheckBox</tabstop>
<tabstop>scan_scanButton</tabstop>
<tabstop>treeView</tabstop>
<tabstop>quickSelect_comboBox</tabstop>
<tabstop>quickSelect_selectButton</tabstop>
<tabstop>deselectAllButton</tabstop>
<tabstop>reverseSelectionButton</tabstop>
<tabstop>collapseAllButton</tabstop>
<tabstop>expandAllButton</tabstop>
<tabstop>resetModelButton</tabstop>
<tabstop>deleteSelectionButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,245 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'tabDb_RemoveDuplicateScores.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 (QAbstractItemView, QApplication, QCheckBox, QComboBox,
QGroupBox, QHBoxLayout, QHeaderView, QLabel,
QPushButton, QSizePolicy, QSpacerItem, QTreeView,
QVBoxLayout, QWidget)
class Ui_TabDb_RemoveDuplicateScores(object):
def setupUi(self, TabDb_RemoveDuplicateScores):
if not TabDb_RemoveDuplicateScores.objectName():
TabDb_RemoveDuplicateScores.setObjectName(u"TabDb_RemoveDuplicateScores")
TabDb_RemoveDuplicateScores.resize(600, 500)
TabDb_RemoveDuplicateScores.setWindowTitle(u"TabDb_RemoveDuplicateScores")
self.verticalLayout_2 = QVBoxLayout(TabDb_RemoveDuplicateScores)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.groupBox_2 = QGroupBox(TabDb_RemoveDuplicateScores)
self.groupBox_2.setObjectName(u"groupBox_2")
self.verticalLayout = QVBoxLayout(self.groupBox_2)
self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout_4 = QVBoxLayout()
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.scan_option_scoreCheckBox = QCheckBox(self.groupBox_2)
self.scan_option_scoreCheckBox.setObjectName(u"scan_option_scoreCheckBox")
self.horizontalLayout_2.addWidget(self.scan_option_scoreCheckBox)
self.scan_option_pureCheckBox = QCheckBox(self.groupBox_2)
self.scan_option_pureCheckBox.setObjectName(u"scan_option_pureCheckBox")
self.scan_option_pureCheckBox.setText(u"PURE")
self.horizontalLayout_2.addWidget(self.scan_option_pureCheckBox)
self.scan_option_farCheckBox = QCheckBox(self.groupBox_2)
self.scan_option_farCheckBox.setObjectName(u"scan_option_farCheckBox")
self.scan_option_farCheckBox.setText(u"FAR")
self.horizontalLayout_2.addWidget(self.scan_option_farCheckBox)
self.scan_option_lostCheckBox = QCheckBox(self.groupBox_2)
self.scan_option_lostCheckBox.setObjectName(u"scan_option_lostCheckBox")
self.scan_option_lostCheckBox.setText(u"LOST")
self.horizontalLayout_2.addWidget(self.scan_option_lostCheckBox)
self.scan_option_maxRecallCheckBox = QCheckBox(self.groupBox_2)
self.scan_option_maxRecallCheckBox.setObjectName(u"scan_option_maxRecallCheckBox")
self.scan_option_maxRecallCheckBox.setText(u"MAX RECALL")
self.horizontalLayout_2.addWidget(self.scan_option_maxRecallCheckBox)
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
self.verticalLayout.addLayout(self.verticalLayout_4)
self.horizontalLayout_3 = QHBoxLayout()
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.scan_option_dateCheckBox = QCheckBox(self.groupBox_2)
self.scan_option_dateCheckBox.setObjectName(u"scan_option_dateCheckBox")
self.horizontalLayout_3.addWidget(self.scan_option_dateCheckBox)
self.scan_option_modifierCheckBox = QCheckBox(self.groupBox_2)
self.scan_option_modifierCheckBox.setObjectName(u"scan_option_modifierCheckBox")
self.horizontalLayout_3.addWidget(self.scan_option_modifierCheckBox)
self.scan_option_clearTypeCheckBox = QCheckBox(self.groupBox_2)
self.scan_option_clearTypeCheckBox.setObjectName(u"scan_option_clearTypeCheckBox")
self.horizontalLayout_3.addWidget(self.scan_option_clearTypeCheckBox)
self.verticalLayout.addLayout(self.horizontalLayout_3)
self.scan_scanButton = QPushButton(self.groupBox_2)
self.scan_scanButton.setObjectName(u"scan_scanButton")
self.verticalLayout.addWidget(self.scan_scanButton)
self.verticalLayout_2.addWidget(self.groupBox_2)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.treeView = QTreeView(TabDb_RemoveDuplicateScores)
self.treeView.setObjectName(u"treeView")
self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.treeView.setSelectionMode(QAbstractItemView.NoSelection)
self.treeView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
self.treeView.setHeaderHidden(True)
self.horizontalLayout.addWidget(self.treeView)
self.verticalLayout_6 = QVBoxLayout()
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
self.groupBox = QGroupBox(TabDb_RemoveDuplicateScores)
self.groupBox.setObjectName(u"groupBox")
self.verticalLayout_3 = QVBoxLayout(self.groupBox)
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.label = QLabel(self.groupBox)
self.label.setObjectName(u"label")
self.verticalLayout_3.addWidget(self.label)
self.quickSelect_comboBox = QComboBox(self.groupBox)
self.quickSelect_comboBox.setObjectName(u"quickSelect_comboBox")
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.quickSelect_comboBox.sizePolicy().hasHeightForWidth())
self.quickSelect_comboBox.setSizePolicy(sizePolicy)
self.verticalLayout_3.addWidget(self.quickSelect_comboBox)
self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.verticalLayout_3.addItem(self.verticalSpacer_2)
self.quickSelect_selectButton = QPushButton(self.groupBox)
self.quickSelect_selectButton.setObjectName(u"quickSelect_selectButton")
sizePolicy.setHeightForWidth(self.quickSelect_selectButton.sizePolicy().hasHeightForWidth())
self.quickSelect_selectButton.setSizePolicy(sizePolicy)
self.verticalLayout_3.addWidget(self.quickSelect_selectButton)
self.verticalLayout_6.addWidget(self.groupBox)
self.groupBox_3 = QGroupBox(TabDb_RemoveDuplicateScores)
self.groupBox_3.setObjectName(u"groupBox_3")
self.verticalLayout_5 = QVBoxLayout(self.groupBox_3)
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
self.deselectAllButton = QPushButton(self.groupBox_3)
self.deselectAllButton.setObjectName(u"deselectAllButton")
self.verticalLayout_5.addWidget(self.deselectAllButton)
self.reverseSelectionButton = QPushButton(self.groupBox_3)
self.reverseSelectionButton.setObjectName(u"reverseSelectionButton")
self.verticalLayout_5.addWidget(self.reverseSelectionButton)
self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.verticalLayout_5.addItem(self.verticalSpacer_3)
self.collapseAllButton = QPushButton(self.groupBox_3)
self.collapseAllButton.setObjectName(u"collapseAllButton")
self.verticalLayout_5.addWidget(self.collapseAllButton)
self.expandAllButton = QPushButton(self.groupBox_3)
self.expandAllButton.setObjectName(u"expandAllButton")
self.verticalLayout_5.addWidget(self.expandAllButton)
self.resetModelButton = QPushButton(self.groupBox_3)
self.resetModelButton.setObjectName(u"resetModelButton")
self.verticalLayout_5.addWidget(self.resetModelButton)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.verticalLayout_5.addItem(self.verticalSpacer)
self.deleteSelectionButton = QPushButton(self.groupBox_3)
self.deleteSelectionButton.setObjectName(u"deleteSelectionButton")
font = QFont()
font.setBold(True)
self.deleteSelectionButton.setFont(font)
self.deleteSelectionButton.setStyleSheet(u"QPushButton { color: red };")
self.verticalLayout_5.addWidget(self.deleteSelectionButton)
self.verticalLayout_6.addWidget(self.groupBox_3)
self.horizontalLayout.addLayout(self.verticalLayout_6)
self.verticalLayout_2.addLayout(self.horizontalLayout)
QWidget.setTabOrder(self.scan_option_scoreCheckBox, self.scan_option_pureCheckBox)
QWidget.setTabOrder(self.scan_option_pureCheckBox, self.scan_option_farCheckBox)
QWidget.setTabOrder(self.scan_option_farCheckBox, self.scan_option_lostCheckBox)
QWidget.setTabOrder(self.scan_option_lostCheckBox, self.scan_option_maxRecallCheckBox)
QWidget.setTabOrder(self.scan_option_maxRecallCheckBox, self.scan_option_dateCheckBox)
QWidget.setTabOrder(self.scan_option_dateCheckBox, self.scan_option_modifierCheckBox)
QWidget.setTabOrder(self.scan_option_modifierCheckBox, self.scan_option_clearTypeCheckBox)
QWidget.setTabOrder(self.scan_option_clearTypeCheckBox, self.scan_scanButton)
QWidget.setTabOrder(self.scan_scanButton, self.treeView)
QWidget.setTabOrder(self.treeView, self.quickSelect_comboBox)
QWidget.setTabOrder(self.quickSelect_comboBox, self.quickSelect_selectButton)
QWidget.setTabOrder(self.quickSelect_selectButton, self.deselectAllButton)
QWidget.setTabOrder(self.deselectAllButton, self.reverseSelectionButton)
QWidget.setTabOrder(self.reverseSelectionButton, self.collapseAllButton)
QWidget.setTabOrder(self.collapseAllButton, self.expandAllButton)
QWidget.setTabOrder(self.expandAllButton, self.resetModelButton)
QWidget.setTabOrder(self.resetModelButton, self.deleteSelectionButton)
self.retranslateUi(TabDb_RemoveDuplicateScores)
QMetaObject.connectSlotsByName(TabDb_RemoveDuplicateScores)
# setupUi
def retranslateUi(self, TabDb_RemoveDuplicateScores):
self.groupBox_2.setTitle(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"scan.title", None))
self.scan_option_scoreCheckBox.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"scan.option.score", None))
self.scan_option_dateCheckBox.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"scan.option.date", None))
self.scan_option_modifierCheckBox.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"scan.option.modifier", None))
self.scan_option_clearTypeCheckBox.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"scan.option.clearType", None))
self.scan_scanButton.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"scan.scanButton", None))
self.groupBox.setTitle(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"quickSelect.title", None))
self.label.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"quickSelect.description", None))
self.quickSelect_selectButton.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"quickSelect.selectButton", None))
self.groupBox_3.setTitle("")
self.deselectAllButton.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"deselectAllButton", None))
self.reverseSelectionButton.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"reverseSelectionButton", None))
self.collapseAllButton.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"collapseAllButton", None))
self.expandAllButton.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"expandAllButton", None))
self.resetModelButton.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"resetModelButton", None))
self.deleteSelectionButton.setText(QCoreApplication.translate("TabDb_RemoveDuplicateScores", u"deleteSelectionButton", None))
pass
# retranslateUi

View File

@ -29,6 +29,11 @@
<string>tab.chartInfoEditor</string>
</attribute>
</widget>
<widget class="TabDb_RemoveDuplicateScores" name="tab_removeDuplicateScores">
<attribute name="title">
<string>tab.removeDuplicateScores</string>
</attribute>
</widget>
</widget>
</item>
</layout>
@ -46,6 +51,12 @@
<header>ui.implements.tabs.tabDb.tabDb_ChartInfoEditor</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TabDb_RemoveDuplicateScores</class>
<extends>QWidget</extends>
<header>ui.implements.tabs.tabDb.tabDb_RemoveDuplicateScores</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@ -20,6 +20,7 @@ from PySide6.QtWidgets import (QApplication, QSizePolicy, QTabWidget, QVBoxLayou
from ui.implements.tabs.tabDb.tabDb_ChartInfoEditor import TabDb_ChartInfoEditor
from ui.implements.tabs.tabDb.tabDb_Manage import TabDb_Manage
from ui.implements.tabs.tabDb.tabDb_RemoveDuplicateScores import TabDb_RemoveDuplicateScores
class Ui_TabDbEntry(object):
def setupUi(self, TabDbEntry):
@ -37,6 +38,9 @@ class Ui_TabDbEntry(object):
self.tab_chartInfoEditor = TabDb_ChartInfoEditor()
self.tab_chartInfoEditor.setObjectName(u"tab_chartInfoEditor")
self.tabWidget.addTab(self.tab_chartInfoEditor, "")
self.tab_removeDuplicateScores = TabDb_RemoveDuplicateScores()
self.tab_removeDuplicateScores.setObjectName(u"tab_removeDuplicateScores")
self.tabWidget.addTab(self.tab_removeDuplicateScores, "")
self.verticalLayout.addWidget(self.tabWidget)
@ -52,6 +56,7 @@ class Ui_TabDbEntry(object):
def retranslateUi(self, TabDbEntry):
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_manage), QCoreApplication.translate("TabDbEntry", u"tab.manage", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_chartInfoEditor), QCoreApplication.translate("TabDbEntry", u"tab.chartInfoEditor", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_removeDuplicateScores), QCoreApplication.translate("TabDbEntry", u"tab.removeDuplicateScores", None))
pass
# retranslateUi

View File

@ -329,6 +329,36 @@
</item>
</layout>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>sourceCode</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_7">
<property name="text">
<string notr="true">&lt;a href=&quot;https://github.com/283375/AndrealImageGenerator&quot;&gt;283375/AndrealImageGenerator&lt;/a&gt;&lt;br&gt;(forked from &lt;a href=&quot;https://github.com/Awbugl/AndrealImageGenerator&quot;&gt;Awbugl/AndrealImageGenerator&lt;/a&gt;)</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -220,6 +220,22 @@ class Ui_TabTools_Andreal(object):
self.formLayout.setLayout(7, QFormLayout.SpanningRole, self.horizontalLayout_5)
self.label_4 = QLabel(TabTools_Andreal)
self.label_4.setObjectName(u"label_4")
self.formLayout.setWidget(9, QFormLayout.LabelRole, self.label_4)
self.label_7 = QLabel(TabTools_Andreal)
self.label_7.setObjectName(u"label_7")
self.label_7.setText(u"<a href=\"https://github.com/283375/AndrealImageGenerator\">283375/AndrealImageGenerator</a><br>(forked from <a href=\"https://github.com/Awbugl/AndrealImageGenerator\">Awbugl/AndrealImageGenerator</a>)")
self.label_7.setOpenExternalLinks(True)
self.formLayout.setWidget(9, QFormLayout.FieldRole, self.label_7)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.formLayout.setItem(8, QFormLayout.SpanningRole, self.verticalSpacer)
self.retranslateUi(TabTools_Andreal)
self.imageFormat_jpgRadioButton.toggled.connect(self.jpgQualityHolderWidget.setEnabled)
@ -241,6 +257,7 @@ class Ui_TabTools_Andreal(object):
self.exportJsonButton.setText(QCoreApplication.translate("TabTools_Andreal", u"exportJsonButton", None))
self.generatePreviewButton.setText(QCoreApplication.translate("TabTools_Andreal", u"generatePreviewButton", None))
self.generateImageButton.setText(QCoreApplication.translate("TabTools_Andreal", u"generateImageButton", None))
self.label_4.setText(QCoreApplication.translate("TabTools_Andreal", u"sourceCode", None))
pass
# retranslateUi

View File

@ -82,6 +82,9 @@
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
@ -325,7 +328,7 @@
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>

View File

@ -68,6 +68,7 @@ class Ui_TabTools_ChartRecommend(object):
self.chartsByConstant_modelView.setMinimumSize(QSize(150, 0))
self.chartsByConstant_modelView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.chartsByConstant_modelView.setSelectionMode(QAbstractItemView.NoSelection)
self.chartsByConstant_modelView.setSelectionBehavior(QAbstractItemView.SelectRows)
self.chartsByConstant_modelView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
self.chartsByConstant_modelView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
@ -228,7 +229,7 @@ class Ui_TabTools_ChartRecommend(object):
self.chartsRecommendFromPlayRating_modelView.setSizePolicy(sizePolicy2)
self.chartsRecommendFromPlayRating_modelView.setMinimumSize(QSize(200, 0))
self.chartsRecommendFromPlayRating_modelView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.chartsRecommendFromPlayRating_modelView.setSelectionMode(QAbstractItemView.SingleSelection)
self.chartsRecommendFromPlayRating_modelView.setSelectionMode(QAbstractItemView.NoSelection)
self.chartsRecommendFromPlayRating_modelView.setSelectionBehavior(QAbstractItemView.SelectRows)
self.chartsRecommendFromPlayRating_modelView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
self.chartsRecommendFromPlayRating_modelView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)

View File

@ -694,57 +694,9 @@
<property name="title">
<string>playRatingCalculate</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLineEdit" name="playRatingCalculateScoreLineEdit">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="inputMask">
<string notr="true">B9'999'999;_</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string notr="true">&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="playRatingCalculateResultLabel">
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
<widget class="PlayRatingCalculator" name="playRatingCalculator" native="true"/>
</item>
</layout>
</widget>
@ -764,6 +716,12 @@
<header>ui.implements.components.ratingClassSelector</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PlayRatingCalculator</class>
<extends>QWidget</extends>
<header>ui.implements.components.playRatingCalculator</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@ -16,9 +16,10 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QComboBox, QFrame, QGridLayout,
QGroupBox, QHBoxLayout, QLabel, QLineEdit,
QSizePolicy, QSpacerItem, QVBoxLayout, QWidget)
QGroupBox, QHBoxLayout, QLabel, QSizePolicy,
QVBoxLayout, QWidget)
from ui.implements.components.playRatingCalculator import PlayRatingCalculator
from ui.implements.components.ratingClassSelector import RatingClassSelector
from ui.implements.components.songIdSelector import SongIdSelector
@ -502,34 +503,12 @@ class Ui_TabTools_InfoLookup(object):
self.groupBox_6 = QGroupBox(TabTools_InfoLookup)
self.groupBox_6.setObjectName(u"groupBox_6")
self.horizontalLayout_5 = QHBoxLayout(self.groupBox_6)
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
self.playRatingCalculateScoreLineEdit = QLineEdit(self.groupBox_6)
self.playRatingCalculateScoreLineEdit.setObjectName(u"playRatingCalculateScoreLineEdit")
self.playRatingCalculateScoreLineEdit.setMinimumSize(QSize(100, 0))
self.playRatingCalculateScoreLineEdit.setMaximumSize(QSize(150, 16777215))
self.playRatingCalculateScoreLineEdit.setInputMask(u"B9'999'999;_")
self.verticalLayout_2 = QVBoxLayout(self.groupBox_6)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.playRatingCalculator = PlayRatingCalculator(self.groupBox_6)
self.playRatingCalculator.setObjectName(u"playRatingCalculator")
self.horizontalLayout_5.addWidget(self.playRatingCalculateScoreLineEdit)
self.label = QLabel(self.groupBox_6)
self.label.setObjectName(u"label")
self.label.setText(u">")
self.horizontalLayout_5.addWidget(self.label)
self.playRatingCalculateResultLabel = QLabel(self.groupBox_6)
self.playRatingCalculateResultLabel.setObjectName(u"playRatingCalculateResultLabel")
font = QFont()
font.setBold(True)
self.playRatingCalculateResultLabel.setFont(font)
self.playRatingCalculateResultLabel.setText(u"...")
self.horizontalLayout_5.addWidget(self.playRatingCalculateResultLabel)
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_5.addItem(self.horizontalSpacer)
self.verticalLayout_2.addWidget(self.playRatingCalculator)
self.verticalLayout.addWidget(self.groupBox_6)

View File

@ -165,7 +165,7 @@
<widget class="QRadioButton" name="legacyPlayPlus_x125fragRadioButton">
<property name="text">
<string notr="true">x1.25
125</string>
250</string>
</property>
</widget>
</item>
@ -361,6 +361,13 @@
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>calculate.toStep.playResultLabel</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="calculate_toStep_playResultSpinBox">
<property name="sizePolicy">
@ -380,10 +387,10 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<item row="1" column="1">
<widget class="QPushButton" name="calculate_toStep_calculatePlayResultFromScoreButton">
<property name="text">
<string>calculate.toStep.playResultLabel</string>
<string>calculate.toStep.calculatePlayResultFromScoreButton</string>
</property>
</widget>
</item>
@ -401,24 +408,36 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="calculate_toStep_resultLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="calculate_toStep_calculatePlayResultFromScoreButton">
<property name="text">
<string>calculate.toStep.calculatePlayResultFromScoreButton</string>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="calculate_toStep_resultLabel">
<property name="text">
<string notr="true">...</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="calculate_toStep_detailedResultLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">QLabel { color: gray; }</string>
</property>
<property name="text">
<string notr="true">...</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -463,17 +482,36 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="calculate_fromStep_resultLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">...</string>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QLabel" name="calculate_fromStep_resultLabel">
<property name="text">
<string notr="true">...</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="calculate_fromStep_detailedResultLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">QLabel { color: gray; }</string>
</property>
<property name="text">
<string notr="true">...</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>

View File

@ -137,7 +137,7 @@ class Ui_TabTools_StepCalculator(object):
self.legacyPlayPlus_x125fragRadioButton = QRadioButton(self.legacyPlayPlus_useFragmentsGroupBox)
self.legacyPlayPlus_x125fragRadioButton.setObjectName(u"legacyPlayPlus_x125fragRadioButton")
self.legacyPlayPlus_x125fragRadioButton.setText(u"x1.25\n"
"125")
"250")
self.horizontalLayout_3.addWidget(self.legacyPlayPlus_x125fragRadioButton)
@ -288,6 +288,11 @@ class Ui_TabTools_StepCalculator(object):
self.formLayout_2 = QFormLayout(self.groupBox)
self.formLayout_2.setObjectName(u"formLayout_2")
self.formLayout_2.setLabelAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
self.label_2 = QLabel(self.groupBox)
self.label_2.setObjectName(u"label_2")
self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_2)
self.calculate_toStep_playResultSpinBox = QDoubleSpinBox(self.groupBox)
self.calculate_toStep_playResultSpinBox.setObjectName(u"calculate_toStep_playResultSpinBox")
sizePolicy2.setHeightForWidth(self.calculate_toStep_playResultSpinBox.sizePolicy().hasHeightForWidth())
@ -298,10 +303,10 @@ class Ui_TabTools_StepCalculator(object):
self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.calculate_toStep_playResultSpinBox)
self.label_2 = QLabel(self.groupBox)
self.label_2.setObjectName(u"label_2")
self.calculate_toStep_calculatePlayResultFromScoreButton = QPushButton(self.groupBox)
self.calculate_toStep_calculatePlayResultFromScoreButton.setObjectName(u"calculate_toStep_calculatePlayResultFromScoreButton")
self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_2)
self.formLayout_2.setWidget(1, QFormLayout.FieldRole, self.calculate_toStep_calculatePlayResultFromScoreButton)
self.label_7 = QLabel(self.groupBox)
self.label_7.setObjectName(u"label_7")
@ -310,18 +315,28 @@ class Ui_TabTools_StepCalculator(object):
self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_7)
self.verticalLayout_9 = QVBoxLayout()
self.verticalLayout_9.setObjectName(u"verticalLayout_9")
self.calculate_toStep_resultLabel = QLabel(self.groupBox)
self.calculate_toStep_resultLabel.setObjectName(u"calculate_toStep_resultLabel")
sizePolicy4.setHeightForWidth(self.calculate_toStep_resultLabel.sizePolicy().hasHeightForWidth())
self.calculate_toStep_resultLabel.setSizePolicy(sizePolicy4)
self.calculate_toStep_resultLabel.setText(u"...")
self.calculate_toStep_resultLabel.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.formLayout_2.setWidget(2, QFormLayout.FieldRole, self.calculate_toStep_resultLabel)
self.verticalLayout_9.addWidget(self.calculate_toStep_resultLabel)
self.calculate_toStep_calculatePlayResultFromScoreButton = QPushButton(self.groupBox)
self.calculate_toStep_calculatePlayResultFromScoreButton.setObjectName(u"calculate_toStep_calculatePlayResultFromScoreButton")
self.calculate_toStep_detailedResultLabel = QLabel(self.groupBox)
self.calculate_toStep_detailedResultLabel.setObjectName(u"calculate_toStep_detailedResultLabel")
font = QFont()
font.setPointSize(8)
self.calculate_toStep_detailedResultLabel.setFont(font)
self.calculate_toStep_detailedResultLabel.setStyleSheet(u"QLabel { color: gray; }")
self.calculate_toStep_detailedResultLabel.setText(u"...")
self.calculate_toStep_detailedResultLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
self.formLayout_2.setWidget(1, QFormLayout.FieldRole, self.calculate_toStep_calculatePlayResultFromScoreButton)
self.verticalLayout_9.addWidget(self.calculate_toStep_detailedResultLabel)
self.formLayout_2.setLayout(2, QFormLayout.FieldRole, self.verticalLayout_9)
self.horizontalLayout_4.addWidget(self.groupBox)
@ -350,13 +365,26 @@ class Ui_TabTools_StepCalculator(object):
self.formLayout_3.setWidget(1, QFormLayout.LabelRole, self.label_9)
self.verticalLayout_10 = QVBoxLayout()
self.verticalLayout_10.setObjectName(u"verticalLayout_10")
self.calculate_fromStep_resultLabel = QLabel(self.groupBox_2)
self.calculate_fromStep_resultLabel.setObjectName(u"calculate_fromStep_resultLabel")
sizePolicy4.setHeightForWidth(self.calculate_fromStep_resultLabel.sizePolicy().hasHeightForWidth())
self.calculate_fromStep_resultLabel.setSizePolicy(sizePolicy4)
self.calculate_fromStep_resultLabel.setText(u"...")
self.calculate_fromStep_resultLabel.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
self.formLayout_3.setWidget(1, QFormLayout.FieldRole, self.calculate_fromStep_resultLabel)
self.verticalLayout_10.addWidget(self.calculate_fromStep_resultLabel)
self.calculate_fromStep_detailedResultLabel = QLabel(self.groupBox_2)
self.calculate_fromStep_detailedResultLabel.setObjectName(u"calculate_fromStep_detailedResultLabel")
self.calculate_fromStep_detailedResultLabel.setFont(font)
self.calculate_fromStep_detailedResultLabel.setStyleSheet(u"QLabel { color: gray; }")
self.calculate_fromStep_detailedResultLabel.setText(u"...")
self.calculate_fromStep_detailedResultLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
self.verticalLayout_10.addWidget(self.calculate_fromStep_detailedResultLabel)
self.formLayout_3.setLayout(1, QFormLayout.FieldRole, self.verticalLayout_10)
self.horizontalLayout_4.addWidget(self.groupBox_2)
@ -394,8 +422,8 @@ class Ui_TabTools_StepCalculator(object):
self.partnerSkillPresetButton_maya.setText(QCoreApplication.translate("TabTools_StepCalculator", u"partner.skill.presets.maya", None))
self.groupBox.setTitle(QCoreApplication.translate("TabTools_StepCalculator", u"calculate.toStep", None))
self.label_2.setText(QCoreApplication.translate("TabTools_StepCalculator", u"calculate.toStep.playResultLabel", None))
self.label_7.setText(QCoreApplication.translate("TabTools_StepCalculator", u"calculate.toStep.resultLabel", None))
self.calculate_toStep_calculatePlayResultFromScoreButton.setText(QCoreApplication.translate("TabTools_StepCalculator", u"calculate.toStep.calculatePlayResultFromScoreButton", None))
self.label_7.setText(QCoreApplication.translate("TabTools_StepCalculator", u"calculate.toStep.resultLabel", None))
self.groupBox_2.setTitle(QCoreApplication.translate("TabTools_StepCalculator", u"calculate.fromStep", None))
self.label_4.setText(QCoreApplication.translate("TabTools_StepCalculator", u"calculate.fromStep.targetStepLabel", None))
self.label_9.setText(QCoreApplication.translate("TabTools_StepCalculator", u"calculate.fromStep.resultLabel", None))

View File

@ -7,7 +7,7 @@ import numpy as np
from arcaea_offline_ocr.phash_db import phash_opencv
def preprocess_char_icon(img_gray: cv2.Mat):
def preprocess_char_icon(img_gray: np.ndarray):
h, w = img_gray.shape[:2]
img = cv2.fillPoly(
img_gray,
@ -23,7 +23,7 @@ def preprocess_char_icon(img_gray: cv2.Mat):
def build_image_phash_database(
images: list[cv2.Mat],
images: list[np.ndarray],
labels: list[str],
*,
hash_size: int = 16,

View File

@ -82,6 +82,7 @@ class ChartDelegate(TextSegmentDelegate):
QColor("#809955"),
QColor("#702d60"),
QColor("#710f25"),
QColor("#8b77a4"),
]
ChartInvalidBackgroundColor = QColor("#e6a23c")

View File

@ -1,6 +1,5 @@
from arcaea_offline.models import Chart, Score, ScoreBest
from PySide6.QtCore import QCoreApplication, QModelIndex, QSortFilterProxyModel, Qt
from sqlalchemy import select
from .base import DbTableModel
@ -18,50 +17,45 @@ class DbB30TableModel(DbTableModel):
def retranslateHeaders(self):
self._horizontalHeaders = [
# fmt: off
QCoreApplication.translate("DB30TableModel", "horizontalHeader.id"),
QCoreApplication.translate("DB30TableModel", "horizontalHeader.chart"),
QCoreApplication.translate("DB30TableModel", "horizontalHeader.score"),
QCoreApplication.translate("DB30TableModel", "horizontalHeader.potential"),
QCoreApplication.translate("DbB30TableModel", "horizontalHeader.id"),
QCoreApplication.translate("DbB30TableModel", "horizontalHeader.chart"),
QCoreApplication.translate("DbB30TableModel", "horizontalHeader.score"),
QCoreApplication.translate("DbB30TableModel", "horizontalHeader.potential"),
# fmt: on
]
def syncDb(self):
self.beginResetModel()
self.beginRemoveRows(QModelIndex(), 0, self.rowCount())
self.__items.clear()
self.endRemoveRows()
self.endResetModel()
with self._db.sessionmaker() as session:
results = list(
session.scalars(
select(ScoreBest).order_by(ScoreBest.potential.desc()).limit(40)
results = (
session.query(ScoreBest, Chart)
.join(
Chart,
(ScoreBest.song_id == Chart.song_id)
& (ScoreBest.rating_class == Chart.rating_class),
)
.order_by(ScoreBest.potential)
.limit(50)
.all()
)
songIds = [r.id for r in results]
ptts = [r.potential for r in results]
for scoreId, ptt in zip(songIds, ptts):
score = self._db.get_score(scoreId)
chart = self._db.get_chart(score.song_id, score.rating_class)
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
self.__items.append(
{
self.IdRole: score.id,
self.ChartRole: chart,
self.ScoreRole: score,
self.PttRole: ptt,
}
)
self.beginInsertRows(QModelIndex(), 0, len(results) - 1)
for scoreBest, chart in results:
self.__items.append(
{
self.IdRole: scoreBest.id,
self.ChartRole: chart,
self.ScoreRole: scoreBest,
self.PttRole: scoreBest.potential,
}
)
self.endInsertRows()
# trigger view update
topLeft = self.index(0, 0)
bottomRight = self.index(self.rowCount() - 1, self.columnCount() - 1)
self.dataChanged.emit(
topLeft,
bottomRight,
[Qt.ItemDataRole.DisplayRole, self.IdRole, self.ChartRole, self.ScoreRole],
)
def rowCount(self, *args):
return len(self.__items)
@ -117,30 +111,35 @@ class DbB30TableSortFilterProxyModel(QSortFilterProxyModel):
return super().headerData(section, orientation, role)
return section + 1
def lessThan(self, source_left, source_right) -> bool:
if source_left.column() != source_right.column():
def lessThan(self, sourceLeft: QModelIndex, sourceRight: QModelIndex) -> bool:
if sourceLeft.column() != sourceRight.column():
return
column = source_left.column()
column = sourceLeft.column()
if column == 0:
return source_left.data(DbB30TableModel.IdRole) < source_right.data(
return sourceLeft.data(DbB30TableModel.IdRole) < sourceRight.data(
DbB30TableModel.IdRole
)
elif column == 2:
score_left = source_left.data(DbB30TableModel.ScoreRole)
score_right = source_right.data(DbB30TableModel.ScoreRole)
if isinstance(score_left, Score) and isinstance(score_right, Score):
scoreLeft = sourceLeft.data(DbB30TableModel.ScoreRole)
scoreRight = sourceRight.data(DbB30TableModel.ScoreRole)
if isinstance(scoreLeft, Score) and isinstance(scoreRight, Score):
if self.sortRole() == self.Sort_C2_ScoreRole:
return score_left.score < score_right.score
return scoreLeft.score < scoreRight.score
elif self.sortRole() == self.Sort_C2_TimeRole:
if score_left.date and score_right.date:
return score_left.date < score_right.date
elif score_left.date:
if scoreLeft.date and scoreRight.date:
return scoreLeft.date < scoreRight.date
elif scoreLeft.date:
return False
else:
return True
elif column == 3:
return source_left.data(DbB30TableModel.PttRole) < source_right.data(
DbB30TableModel.PttRole
)
return super().lessThan(source_left, source_right)
pttLeft = sourceLeft.data(DbB30TableModel.PttRole)
pttRight = sourceRight.data(DbB30TableModel.PttRole)
if pttLeft and pttRight:
return pttLeft < pttRight
elif pttLeft:
return False
else:
return True
return super().lessThan(sourceLeft, sourceRight)

View File

@ -131,7 +131,7 @@ class DbScoreTableModel(DbTableModel):
return False
if index.column() == 2 and isinstance(value, Score) and role == self.ScoreRole:
self._db.update_score(self.__items[index.row()][self.IdRole], value)
self._db.update_score(value)
self.syncDb()
return True

View File

@ -7,6 +7,7 @@ import exif
from arcaea_offline.database import Database
from arcaea_offline.models import Chart, Score
from arcaea_offline.utils.partner import KanaeDayNight, kanae_day_night
from arcaea_offline_ocr.crop import CropBlackEdges
from arcaea_offline_ocr.device import DeviceOcr, DeviceOcrResult
from arcaea_offline_ocr.device.rois import (
DeviceRois,
@ -43,6 +44,7 @@ class TabDeviceOcrRunnable(OcrRunnable):
def run(self):
try:
img = imread_unicode(self.imagePath, cv2.IMREAD_COLOR)
img = CropBlackEdges.crop(img, cv2.COLOR_BGR2GRAY)
if isinstance(self.rois, type) and issubclass(self.rois, DeviceRoisAuto):
rois = self.rois(img.shape[1], img.shape[0])
else:

View File

@ -31,6 +31,9 @@ class AndrealExecuteRunnable(QRunnable):
encoding="utf-8",
)
result = subp.stdout
if subp.returncode != 0:
logger.error("AndrealImageGenerator Error: ")
logger.error(result)
b64Result = [s for s in result.split("\n") if s]
imageBytes = base64.b64decode(
re.sub(r"data:image/.*;base64,", "", b64Result[-1])

View File

@ -0,0 +1,23 @@
from PySide6.QtGui import QFont
from .focusSelectAllLineEdit import FocusSelectAllLineEdit
class ArcaeaScoreLineEdit(FocusSelectAllLineEdit):
def __init__(self, parent=None):
super().__init__(parent)
font = QFont("GeosansLight")
font.setPointSize(14)
font.setBold(True)
font.setStyleStrategy(
QFont.StyleStrategy.NoSubpixelAntialias
| QFont.StyleStrategy.PreferAntialias
)
self.setFont(font)
self.setInputMask("B9'999'999;_")
def score(self) -> int | None:
textWithoutMask = self.text().replace("'", "")
return int(textWithoutMask) if textWithoutMask else None

View File

@ -0,0 +1,85 @@
from arcaea_offline.calculate import calculate_play_rating
from PySide6.QtCore import QCoreApplication
from PySide6.QtGui import QGuiApplication
from PySide6.QtWidgets import (
QHBoxLayout,
QLabel,
QPushButton,
QSizePolicy,
QSpacerItem,
QWidget,
)
from ui.extends.shared.language import LanguageChangeEventFilter
from .arcaeaScoreLineEdit import ArcaeaScoreLineEdit
class PlayRatingCalculator(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
self.installEventFilter(self.languageChangeEventFilter)
self.setupUi()
self.arcaeaScoreLineEdit.textChanged.connect(self.updateResultLabel)
self.copyButton.clicked.connect(self.on_copyButton_clicked)
self.constant: int | None = None
def setConstant(self, constant: int | None):
self.constant = constant
self.updateResultLabel()
@property
def result(self):
if self.constant is None:
return None
score = self.arcaeaScoreLineEdit.score()
return None if score is None else calculate_play_rating(self.constant, score)
def updateResultLabel(self):
result = self.result
self.resultLabel.setText(str(round(result, 3)) if result is not None else "...")
self.resultLabel.setToolTip(str(result))
def on_copyButton_clicked(self):
result = self.result
if result is not None:
QGuiApplication.clipboard().setText(str(result))
def setupUi(self, *args):
self.horizontalLayout = QHBoxLayout(self)
self.arcaeaScoreLineEdit = ArcaeaScoreLineEdit(self)
self.horizontalLayout.addWidget(self.arcaeaScoreLineEdit)
self.label = QLabel(self)
self.label.setText(" > ")
self.horizontalLayout.addWidget(self.label)
self.resultLabel = QLabel(self)
self.resultLabel.setText("...")
self.resultLabel.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred
)
self.resultLabel.setMinimumWidth(100)
self.horizontalLayout.addWidget(self.resultLabel)
self.horizontalSpacer = QSpacerItem(
20, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred
)
self.horizontalLayout.addSpacerItem(self.horizontalSpacer)
self.copyButton = QPushButton(self)
self.horizontalLayout.addWidget(self.copyButton)
self.retranslateUi()
def retranslateUi(self, *args):
self.copyButton.setText(
QCoreApplication.translate("PotentialCalculator", "copyButton")
)

View File

@ -1,3 +1,4 @@
import logging
from typing import Type
from PySide6.QtCore import Signal
@ -6,6 +7,8 @@ from PySide6.QtWidgets import QHBoxLayout, QSizePolicy, QVBoxLayout, QWidget
from ui.implements.components.ratingClassRadioButton import RatingClassRadioButton
logger = logging.getLogger(__name__)
class RatingClassSelector(QWidget):
valueChanged = Signal()
@ -41,16 +44,30 @@ class RatingClassSelector(QWidget):
self.bydButton.setAutoExclusive(False)
self.preferredLayout.addWidget(self.bydButton)
self.buttons = [self.pstButton, self.prsButton, self.ftrButton, self.bydButton]
self.etrButton = RatingClassRadioButton(self)
self.etrButton.setObjectName("etrButton")
self.etrButton.setText("ETERNAL")
self.etrButton.setAutoExclusive(False)
self.preferredLayout.addWidget(self.etrButton)
self.buttons = [
self.pstButton,
self.prsButton,
self.ftrButton,
self.bydButton,
self.etrButton,
]
self.pstButton.setColors(QColor("#399bb2"), QColor("#f0f8fa"))
self.prsButton.setColors(QColor("#809955"), QColor("#f7f9f4"))
self.ftrButton.setColors(QColor("#702d60"), QColor("#f7ebf4"))
self.bydButton.setColors(QColor("#710f25"), QColor("#f9ced8"))
self.etrButton.setColors(QColor("#4f2c7a"), QColor("#e4daf1"))
self.pstButton.clicked.connect(self.select)
self.prsButton.clicked.connect(self.select)
self.ftrButton.clicked.connect(self.select)
self.bydButton.clicked.connect(self.select)
self.etrButton.clicked.connect(self.select)
self.reset()
self.setButtonsEnabled([])
@ -106,9 +123,10 @@ class RatingClassSelector(QWidget):
if ratingClass is None or isinstance(ratingClass, bool):
button = self.sender()
elif ratingClass in range(4):
elif ratingClass in range(len(self.buttons)):
button = self.buttons[ratingClass]
else:
logger.debug(f"Cannot select {ratingClass=}, condition check failed")
return
if not button.isEnabled():

View File

@ -302,7 +302,7 @@ class ScoreEditor(Ui_ScoreEditor, QWidget):
if score.score is None:
flags |= ScoreValidateResult.ScoreIncomplete
elif score.pure is None or score.far is None:
elif score.pure is None or score.far is None or score.lost is None:
flags |= ScoreValidateResult.ScoreIncompleteForValidate
elif self.__chart.notes is not None:
score_range = calculate_score_range(

View File

@ -1,3 +1,4 @@
import csv
import json
import logging
import traceback
@ -13,8 +14,10 @@ from arcaea_offline.external.arcaea import (
)
from arcaea_offline.external.arcaea.common import ArcaeaParser
from arcaea_offline.external.arcsong import ArcsongDbParser
from arcaea_offline.external.chart_info_db import ChartInfoDbParser
from arcaea_offline.external.smartrte import SmartRteB30CsvConverter
from arcaea_offline.models import Difficulty, Pack, Song
from PySide6.QtCore import QDir, Slot
from PySide6.QtCore import QDateTime, QDir, Slot
from PySide6.QtWidgets import QFileDialog, QMessageBox, QWidget
from ui.designer.tabs.tabDb.tabDb_Manage_ui import Ui_TabDb_Manage
@ -55,6 +58,29 @@ class TabDb_Manage(Ui_TabDb_Manage, QWidget):
self, "Sync Error", "\n".join(traceback.format_exception(e))
)
@Slot()
def on_syncChartInfoDbButton_clicked(self):
dbFile, filter = QFileDialog.getOpenFileName(
self, None, "", "DB File (*.db);;*"
)
if not dbFile:
return
try:
db = Database()
parser = ChartInfoDbParser(dbFile)
with db.sessionmaker() as session:
parser.write_database(session)
session.commit()
databaseUpdateSignals.chartInfoUpdated.emit()
QMessageBox.information(self, None, "OK")
except Exception as e:
logging.exception("Sync chart info database error")
QMessageBox.critical(
self, "Sync Error", "\n".join(traceback.format_exception(e))
)
def importFromArcaeaParser(
self, parser: ArcaeaParser, instance, logName, path
) -> int:
@ -206,14 +232,14 @@ class TabDb_Manage(Ui_TabDb_Manage, QWidget):
@Slot()
def on_exportScoresButton_clicked(self):
scores = Database().export_scores()
version = Database().version()
scores = Database().export_scores_def_v2()
timestamp = QDateTime.currentMSecsSinceEpoch()
content = json.dumps(scores, ensure_ascii=False)
exportLocation, _filter = QFileDialog.getSaveFileName(
self,
"Save your scores to...",
QDir.current().filePath(f"arcaea-offline-scores-v{version}.json"),
QDir.current().filePath(f"arcaea-offline-def-v2-scores-{timestamp}.json"),
"JSON (*.json);;*",
)
with open(exportLocation, "w", encoding="utf-8") as f:
@ -232,3 +258,27 @@ class TabDb_Manage(Ui_TabDb_Manage, QWidget):
)
with open(exportLocation, "w", encoding="utf-8") as f:
f.write(content)
@Slot()
def on_exportSmartRteB30Button_clicked(self):
try:
with Database().sessionmaker() as session:
converter = SmartRteB30CsvConverter(session)
csvRows = converter.rows()
exportLocation, _filter = QFileDialog.getSaveFileName(
self,
"Export CSV file",
QDir.current().filePath("smartrte_scores.csv"),
"CSV (*.csv);;*",
)
with open(exportLocation, "w", encoding="utf-8", newline="") as f:
csvWriter = csv.writer(f)
csvWriter.writerows(csvRows)
QMessageBox.information(self, None, "OK")
except Exception as e:
logging.exception("Export SmartRTE csv error:")
QMessageBox.critical(
self, "Export Error", "\n".join(traceback.format_exception(e))
)

View File

@ -0,0 +1,353 @@
from enum import IntEnum
from arcaea_offline.database import Database
from arcaea_offline.models import Chart, Difficulty, Score, Song
from PySide6.QtCore import QCoreApplication, QModelIndex, Qt, Slot
from PySide6.QtGui import QStandardItem, QStandardItemModel
from PySide6.QtWidgets import QMessageBox, QStyledItemDelegate, QWidget
from sqlalchemy import delete, func, select
from sqlalchemy.orm import InstrumentedAttribute, Session
from ui.designer.tabs.tabDb.tabDb_RemoveDuplicateScores_ui import (
Ui_TabDb_RemoveDuplicateScores,
)
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
from ui.extends.shared.language import LanguageChangeEventFilter
class RemoveDuplicateScoresModel(QStandardItemModel):
ScoreRole = Qt.ItemDataRole.UserRole
ChartRole = Qt.ItemDataRole.UserRole + 10
SongRole = Qt.ItemDataRole.UserRole + 11
DifficultyRole = Qt.ItemDataRole.UserRole + 12
def setChartDelegateDatas(
self, item: QStandardItem, songId: str, ratingClass: int, session: Session
):
chart = (
session.query(Chart)
.where((Chart.song_id == songId) & (Chart.rating_class == ratingClass))
.first()
)
song = session.query(Song).where(Song.id == songId).first()
difficulty = (
session.query(Difficulty)
.where(
(Difficulty.song_id == songId)
& (Difficulty.rating_class == ratingClass)
)
.first()
)
if chart is None and song is None and difficulty is None:
chart = Chart(song_id=songId, rating_class=ratingClass, set="unknown")
item.setData(chart, self.ChartRole)
item.setData(song, self.SongRole)
item.setData(difficulty, self.DifficultyRole)
def getGroupKey(self, score: Score, columns: list[InstrumentedAttribute]) -> str:
baseKeys = [score.song_id, str(score.rating_class)]
for column in columns:
key = f"{column.key}{getattr(score,column.key)}"
baseKeys.append(key)
return "||".join(baseKeys)
def setScores(self, scores: list[Score], columns: list[InstrumentedAttribute]):
self.clear()
scoreKeyMap: dict[str, list[Score]] = {}
for score in scores:
key = self.getGroupKey(score, columns)
if scoreKeyMap.get(key) is None:
scoreKeyMap[key] = [score]
else:
scoreKeyMap[key].append(score)
db = Database()
with db.sessionmaker() as session:
for key, scores in scoreKeyMap.items():
songId, ratingClass = key.split("||")[:2]
ratingClass = int(ratingClass)
parentCheckBoxItem = QStandardItem(f"{len(scores)} items")
parentChartItem = QStandardItem()
self.setChartDelegateDatas(
parentChartItem, songId, ratingClass, session
)
for i, score in enumerate(scores):
scoreCheckBoxItem = QStandardItem()
scoreCheckBoxItem.setEditable(False)
scoreCheckBoxItem.setCheckable(True)
scoreCheckBoxItem.setEnabled(True)
scoreItem = QStandardItem()
scoreItem.setData(score, self.ScoreRole)
scoreItem.setEditable(False)
scoreItem.setEnabled(True)
parentCheckBoxItem.setChild(i, 0, scoreCheckBoxItem)
parentCheckBoxItem.setChild(i, 1, scoreItem)
self.appendRow([parentCheckBoxItem, parentChartItem])
class TreeViewChartDelegate(ChartDelegate):
def getChart(self, index: QModelIndex):
return index.data(RemoveDuplicateScoresModel.ChartRole)
def getSong(self, index: QModelIndex):
return index.data(RemoveDuplicateScoresModel.SongRole)
def getDifficulty(self, index: QModelIndex):
return index.data(RemoveDuplicateScoresModel.DifficultyRole)
class TreeViewScoreDelegate(ScoreDelegate):
def getScore(self, index: QModelIndex):
return index.data(RemoveDuplicateScoresModel.ScoreRole)
class TreeViewProxyDelegate(QStyledItemDelegate):
def __init__(
self, chartDelegate: ChartDelegate, scoreDelegate: ScoreDelegate, parent=None
):
super().__init__(parent)
self.chartDelegate = chartDelegate
self.scoreDelegate = scoreDelegate
def delegateForIndex(self, index: QModelIndex) -> QStyledItemDelegate:
return self.scoreDelegate if index.parent().isValid() else self.chartDelegate
def sizeHint(self, option, index: QModelIndex):
return self.delegateForIndex(index).sizeHint(option, index)
def paint(self, painter, option, index: QModelIndex):
self.delegateForIndex(index).paint(painter, option, index)
QStyledItemDelegate.paint(self, painter, option, index)
class QuickSelectComboBoxValues(IntEnum):
ID_EARLIER = 0
DATE_EARLIER = 1
COLUMNS_INTEGRAL = 2
class TabDb_RemoveDuplicateScores(Ui_TabDb_RemoveDuplicateScores, QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
self.installEventFilter(self.languageChangeEventFilter)
self.db = Database()
self.removeDuplicateScoresModel = RemoveDuplicateScoresModel(self)
self.treeView.setModel(self.removeDuplicateScoresModel)
self.treeViewChartDelegate = TreeViewChartDelegate(self.treeView)
self.treeViewScoreDelegate = TreeViewScoreDelegate(self.treeView)
self.treeViewProxyDelegate = TreeViewProxyDelegate(
self.treeViewChartDelegate, self.treeViewScoreDelegate, self.treeView
)
self.treeView.setItemDelegateForColumn(1, self.treeViewProxyDelegate)
self.quickSelect_comboBox.addItem(
# fmt: off
QCoreApplication.translate("TabDb_RemoveDuplicateScores", "quickSelectComboBox.idEarlier"),
# fmt: on
QuickSelectComboBoxValues.ID_EARLIER
)
self.quickSelect_comboBox.addItem(
# fmt: off
QCoreApplication.translate("TabDb_RemoveDuplicateScores", "quickSelectComboBox.dateEarlier"),
# fmt: on
QuickSelectComboBoxValues.DATE_EARLIER
)
self.quickSelect_comboBox.addItem(
# fmt: off
QCoreApplication.translate("TabDb_RemoveDuplicateScores", "quickSelectComboBox.columnsIntegral"),
# fmt: on
QuickSelectComboBoxValues.COLUMNS_INTEGRAL
)
def getQueryColumns(self):
columns: list[InstrumentedAttribute] = [Score.song_id, Score.rating_class]
if self.scan_option_scoreCheckBox.isChecked():
columns.append(Score.score)
if self.scan_option_pureCheckBox.isChecked():
columns.append(Score.pure)
if self.scan_option_farCheckBox.isChecked():
columns.append(Score.far)
if self.scan_option_lostCheckBox.isChecked():
columns.append(Score.lost)
if self.scan_option_maxRecallCheckBox.isChecked():
columns.append(Score.max_recall)
if self.scan_option_dateCheckBox.isChecked():
columns.append(Score.date)
if self.scan_option_modifierCheckBox.isChecked():
columns.append(Score.modifier)
if self.scan_option_clearTypeCheckBox.isChecked():
columns.append(Score.clear_type)
return columns
def getQueryScores(self):
columns = self.getQueryColumns()
with self.db.sessionmaker() as session:
groupBySubquery = (
select(*columns).group_by(*columns).having(func.count() > 1).subquery()
)
selectInClause = [
col == getattr(groupBySubquery.c, col.key) for col in columns
]
return session.query(Score).where(*selectInClause).all()
def scan(self):
scores = self.getQueryScores()
self.removeDuplicateScoresModel.setScores(scores, self.getQueryColumns())
self.treeView.expandAll()
def deselectAll(self):
for row in range(self.removeDuplicateScoresModel.rowCount()):
parentItem = self.removeDuplicateScoresModel.item(row, 0)
for childRow in range(parentItem.rowCount()):
childCheckBoxItem = parentItem.child(childRow, 0)
childCheckBoxItem.setCheckState(Qt.CheckState.Unchecked)
def quickSelect(self):
mode = self.quickSelect_comboBox.currentData()
if mode is None:
return
for row in range(self.removeDuplicateScoresModel.rowCount()):
parentItem = self.removeDuplicateScoresModel.item(row, 0)
scores: list[Score] = []
for childRow in range(parentItem.rowCount()):
childScoreItem = parentItem.child(childRow, 1)
scores.append(childScoreItem.data(RemoveDuplicateScoresModel.ScoreRole))
if mode == QuickSelectComboBoxValues.ID_EARLIER:
chosenRow = min(enumerate(scores), key=lambda i: i[1].id)[0]
elif mode == QuickSelectComboBoxValues.DATE_EARLIER:
chosenRow = min(
enumerate(scores),
key=lambda i: float("inf") if i[1].date is None else i[1].date,
)[0]
elif mode == QuickSelectComboBoxValues.COLUMNS_INTEGRAL:
chosenRow = max(
enumerate(scores),
key=lambda i: sum(
getattr(i[1], col.key) is not None
for col in i[1].__table__.columns
),
)[0]
for childRow in range(parentItem.rowCount()):
childCheckBoxItem = parentItem.child(childRow, 0)
if childRow != chosenRow:
childCheckBoxItem.setCheckState(Qt.CheckState.Checked)
else:
childCheckBoxItem.setCheckState(Qt.CheckState.Unchecked)
def reverseSelection(self):
for row in range(self.removeDuplicateScoresModel.rowCount()):
parentItem = self.removeDuplicateScoresModel.item(row, 0)
# only when there's a checked item in this group, we perform a reversed selection
# otherwise we ignore this group
performReverse = any(
parentItem.child(childRow, 0).checkState() == Qt.CheckState.Checked
for childRow in range(parentItem.rowCount())
)
if not performReverse:
continue
for childRow in range(parentItem.rowCount()):
childCheckBoxItem = parentItem.child(childRow, 0)
newCheckState = (
Qt.CheckState.Unchecked
if childCheckBoxItem.checkState() != Qt.CheckState.Unchecked
else Qt.CheckState.Checked
)
childCheckBoxItem.setCheckState(newCheckState)
def deleteSelection(self):
selectedScores: list[Score] = []
for row in range(self.removeDuplicateScoresModel.rowCount()):
parentItem = self.removeDuplicateScoresModel.item(row, 0)
for childRow in range(parentItem.rowCount()):
childCheckBoxItem = parentItem.child(childRow, 0)
if childCheckBoxItem.checkState() == Qt.CheckState.Checked:
childScoreItem = parentItem.child(childRow, 1)
selectedScores.append(
childScoreItem.data(RemoveDuplicateScoresModel.ScoreRole)
)
confirm = QMessageBox.warning(
self,
None,
# fmt: off
QCoreApplication.translate("TabDb_RemoveDuplicateScores", "deleteSelectionDialog.content {}").format(len(selectedScores)),
# fmt: on
QMessageBox.StandardButton.Yes,
QMessageBox.StandardButton.No,
)
if confirm != QMessageBox.StandardButton.Yes:
return
with self.db.sessionmaker() as session:
ids = [s.id for s in selectedScores]
session.execute(delete(Score).where(Score.id.in_(ids)))
session.commit()
self.scan()
@Slot()
def on_scan_scanButton_clicked(self):
if len(self.getQueryColumns()) <= 2:
result = QMessageBox.warning(
self,
None,
# fmt: off
QCoreApplication.translate("TabDb_RemoveDuplicateScores", "scan_noColumnsDialog.content"),
# fmt: on
QMessageBox.StandardButton.Yes,
QMessageBox.StandardButton.No,
)
if result != QMessageBox.StandardButton.Yes:
return
self.scan()
@Slot()
def on_quickSelect_selectButton_clicked(self):
self.quickSelect()
@Slot()
def on_deselectAllButton_clicked(self):
self.deselectAll()
@Slot()
def on_reverseSelectionButton_clicked(self):
self.reverseSelection()
@Slot()
def on_expandAllButton_clicked(self):
self.treeView.expandAll()
@Slot()
def on_collapseAllButton_clicked(self):
self.treeView.collapseAll()
@Slot()
def on_resetModelButton_clicked(self):
self.removeDuplicateScoresModel.clear()
@Slot()
def on_deleteSelectionButton_clicked(self):
self.deleteSelection()

View File

@ -1,3 +1,5 @@
import logging
from arcaea_offline.database import Database
from PySide6.QtCore import QCoreApplication
from PySide6.QtGui import QShowEvent
@ -6,6 +8,8 @@ from PySide6.QtWidgets import QWidget
from ui.designer.tabs.tabOverview_ui import Ui_TabOverview
from ui.extends.shared.language import LanguageChangeEventFilter
logger = logging.getLogger(__name__)
class TabOverview(Ui_TabOverview, QWidget):
def __init__(self, parent=None):
@ -22,18 +26,27 @@ class TabOverview(Ui_TabOverview, QWidget):
return super().showEvent(event)
def updateOverview(self):
b30 = self.db.get_b30() or 0.00
self.b30Label.setText(str(f"{b30:.3f}"))
self.databaseDescribeLabel.setText(
self.describeFormatString.format(
self.db.count_packs(),
self.db.count_songs(),
self.db.count_difficulties(),
self.db.count_chart_infos(),
self.db.count_complete_chart_infos(),
self.db.count_scores(),
try:
b30 = self.db.get_b30() or 0.00
self.b30Label.setText(str(f"{b30:.3f}"))
except Exception:
logger.exception("Cannot get b30:")
self.b30Label.setText("ERR")
try:
self.databaseDescribeLabel.setText(
self.describeFormatString.format(
self.db.count_packs(),
self.db.count_songs(),
self.db.count_difficulties(),
self.db.count_chart_infos(),
self.db.count_complete_chart_infos(),
self.db.count_scores(),
)
)
)
except Exception:
logger.exception("Cannot update overview:")
self.databaseDescribeLabel.setText("ERR")
def retranslateUi(self, *args):
super().retranslateUi(self)

View File

@ -2,31 +2,52 @@ import logging
from arcaea_offline.calculate import calculate_constants_from_play_rating
from arcaea_offline.database import Database
from arcaea_offline.models import Chart, ScoreBest
from arcaea_offline.models import Chart, Score
from arcaea_offline.utils.rating import rating_class_to_text
from arcaea_offline.utils.score import score_to_grade_text
from PySide6.QtCore import Slot
from PySide6.QtWidgets import QWidget
from PySide6.QtCore import QModelIndex, Qt, Slot
from PySide6.QtWidgets import QDialog, QLabel, QVBoxLayout, QWidget
from ui.designer.tabs.tabTools.tabTools_ChartRecommend_ui import (
Ui_TabTools_ChartRecommend,
)
from ui.extends.shared.language import LanguageChangeEventFilter
from ui.extends.tabs.tabTools.tabTools_ChartRecommend import (
ChartsModel,
ChartsWithScoreBestModel,
CustomChartDelegate,
CustomScoreBestDelegate,
)
from ui.implements.components.playRatingCalculator import PlayRatingCalculator
logger = logging.getLogger(__name__)
def chartToText(chart: Chart):
return f"{chart.artist} - {chart.title}<br>({chart.song_id}) {rating_class_to_text(chart.rating_class)}"
class QuickPlayRatingCalculatorDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.verticalLayout = QVBoxLayout(self)
def scoreBestToText(score: ScoreBest):
return f"{score_to_grade_text(score.score)} {score.score} > {score.potential:.4f}"
self.chartLabel = QLabel(self)
self.verticalLayout.addWidget(self.chartLabel)
self.playRatingCalculator = PlayRatingCalculator(self)
self.verticalLayout.addWidget(self.playRatingCalculator)
self.setMinimumWidth(400)
self.playRatingCalculator.arcaeaScoreLineEdit.setFocus(
Qt.FocusReason.PopupFocusReason
)
def setChart(self, chart: Chart):
self.chartLabel.setText(
f"{chart.title} {rating_class_to_text(chart.rating_class)} {chart.constant / 10}"
)
self.playRatingCalculator.setConstant(chart.constant)
def setScore(self, score: Score):
self.playRatingCalculator.arcaeaScoreLineEdit.setText(str(score))
class TabTools_ChartRecommend(Ui_TabTools_ChartRecommend, QWidget):
@ -34,6 +55,9 @@ class TabTools_ChartRecommend(Ui_TabTools_ChartRecommend, QWidget):
super().__init__(parent)
self.setupUi(self)
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
self.installEventFilter(self.languageChangeEventFilter)
self.db = Database()
self.chartsByConstantModel = ChartsModel(self)
@ -62,6 +86,13 @@ class TabTools_ChartRecommend(Ui_TabTools_ChartRecommend, QWidget):
self.updateChartsRecommendFromPlayRating
)
self.chartsByConstant_modelView.doubleClicked.connect(
self.openQuickPlayRatingCalculator_chartsByConstant
)
self.chartsRecommendFromPlayRating_modelView.doubleClicked.connect(
self.openQuickPlayRatingCalculator_chartsRecommendFromPlayRating
)
@Slot(float)
def on_rangeFromPlayRating_playRatingSpinBox_valueChanged(self, value: float):
try:
@ -120,3 +151,26 @@ class TabTools_ChartRecommend(Ui_TabTools_ChartRecommend, QWidget):
self.chartsRecommendFromPlayRatingModel.setChartAndScore(charts, scores)
self.chartsRecommendFromPlayRating_modelView.resizeRowsToContents()
self.chartsRecommendFromPlayRating_modelView.resizeColumnsToContents()
@Slot(QModelIndex)
def openQuickPlayRatingCalculator_chartsByConstant(self, index: QModelIndex):
dialog = QuickPlayRatingCalculatorDialog(self)
chart = index.data(ChartsModel.ChartRole)
dialog.setChart(chart)
dialog.show()
@Slot(QModelIndex)
def openQuickPlayRatingCalculator_chartsRecommendFromPlayRating(
self, index: QModelIndex
):
dialog = QuickPlayRatingCalculatorDialog(self)
row = index.row()
chartIndex = self.chartsRecommendFromPlayRatingModel.item(row, 0)
scoreIndex = self.chartsRecommendFromPlayRatingModel.item(row, 1)
chart = chartIndex.data(ChartsWithScoreBestModel.ChartRole)
score: Score = scoreIndex.data(ChartsWithScoreBestModel.ScoreBestRole)
dialog.setChart(chart)
dialog.setScore(score.score)
dialog.show()

View File

@ -1,6 +1,5 @@
import re
from arcaea_offline.calculate import calculate_play_rating
from arcaea_offline.database import Database
from PySide6.QtCore import QDateTime
from PySide6.QtWidgets import QVBoxLayout, QWidget
@ -27,15 +26,8 @@ class TabTools_InfoLookup(Ui_TabTools_InfoLookup, QWidget):
self.ratingClassSelector.valueChanged.connect(self.updateDifficultyLabels)
self.ratingClassSelector.valueChanged.connect(self.updateChartInfoLabels)
self.songIdSelector.valueChanged.connect(
self.updatePlayRatingCalculateResultLabel
)
self.ratingClassSelector.valueChanged.connect(
self.updatePlayRatingCalculateResultLabel
)
self.playRatingCalculateScoreLineEdit.textChanged.connect(
self.updatePlayRatingCalculateResultLabel
)
self.songIdSelector.valueChanged.connect(self.updatePlayRatingCalculator)
self.ratingClassSelector.valueChanged.connect(self.updatePlayRatingCalculator)
self.langSelectComboBox.addItem("En - English [en]", "en")
self.langSelectComboBox.addItem("あ - Japanese [ja]", "ja")
@ -213,29 +205,12 @@ class TabTools_InfoLookup(Ui_TabTools_InfoLookup, QWidget):
str(chartInfo.notes) if chartInfo.notes is not None else "-"
)
def resetPlayRatingCalculateResultLabel(self):
self.playRatingCalculateResultLabel.setText("...")
def updatePlayRatingCalculateResultLabel(self):
def updatePlayRatingCalculator(self):
songId = self.songIdSelector.songId()
ratingClass = self.ratingClassSelector.value()
if not songId or ratingClass is None:
self.resetPlayRatingCalculateResultLabel()
return
chartInfo = self.db.get_chart_info(songId, ratingClass)
if not chartInfo or not chartInfo.constant:
self.resetPlayRatingCalculateResultLabel()
return
if scoreText := self.playRatingCalculateScoreLineEdit.text().replace("'", ""):
score = int(scoreText)
self.playRatingCalculateResultLabel.setText(
f"{calculate_play_rating(chartInfo.constant, score):.3f}"
)
if not chartInfo:
self.playRatingCalculator.setConstant(None)
else:
self.resetPlayRatingCalculateResultLabel()
return
self.playRatingCalculator.setConstant(chartInfo.constant)

View File

@ -1,6 +1,5 @@
import logging
from arcaea_offline.calculate import calculate_play_rating
from arcaea_offline.calculate.world_step import (
AmaneBelowExPartnerBonus,
AwakenedEtoPartnerBonus,
@ -15,14 +14,22 @@ from arcaea_offline.calculate.world_step import (
calculate_step,
calculate_step_original,
)
from arcaea_offline.models import Chart, Score
from PySide6.QtCore import QEasingCurve, QObject, QSize, Qt, QTimeLine
from PySide6.QtGui import QIcon, QPainter, QPaintEvent, QPixmap
from PySide6.QtCore import (
QCoreApplication,
QEasingCurve,
QObject,
QSize,
QTimeLine,
Signal,
)
from PySide6.QtGui import QIcon, QPixmap
from PySide6.QtWidgets import (
QAbstractButton,
QButtonGroup,
QDialog,
QGraphicsColorizeEffect,
QLabel,
QPushButton,
QVBoxLayout,
QWidget,
)
@ -30,26 +37,13 @@ from ui.designer.tabs.tabTools.tabTools_StepCalculator_ui import (
Ui_TabTools_StepCalculator,
)
from ui.extends.shared.language import LanguageChangeEventFilter
from ui.implements.components.chartAndScoreInput import ChartAndScoreInput
from ui.implements.components.chartSelector import ChartSelector
from ui.implements.components.playRatingCalculator import PlayRatingCalculator
from ui.implements.components.songIdSelector import SongIdSelectorMode
logger = logging.getLogger(__name__)
class MapTypeListWidgetWidget(QLabel):
def paintEvent(self, e: QPaintEvent) -> None:
size = self.size()
painter = QPainter(self)
scaledPixmap = self.pixmap().scaled(
size,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation,
)
x = (size.width() - scaledPixmap.width()) / 2
y = (size.height() - scaledPixmap.height()) / 2
painter.drawPixmap(x, y, scaledPixmap)
class ButtonGrayscaleEffectApplier(QObject):
def __init__(self, parent: QAbstractButton):
super().__init__(parent)
@ -79,11 +73,56 @@ class ButtonGrayscaleEffectApplier(QObject):
target.setGraphicsEffect(effect)
class ChartAndScoreInputDialog(ChartAndScoreInput):
class PlayRatingCalculatorDialog(QDialog):
accepted = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowFlag(Qt.WindowType.Dialog, True)
self.setSongIdSelectorMode(SongIdSelectorMode.Chart)
self.verticalLayout = QVBoxLayout(self)
self.chartSelector = ChartSelector(self)
self.chartSelector.setSongIdSelectorMode(SongIdSelectorMode.Chart)
self.verticalLayout.addWidget(self.chartSelector)
self.playRatingCalculator = PlayRatingCalculator(self)
self.verticalLayout.addWidget(self.playRatingCalculator)
self.acceptButton = QPushButton(self)
self.acceptButton.setText(
# fmt: off
QCoreApplication.translate("StepCalculator", "playRatingCalculatorDialog.acceptButton")
# fmt: on
)
self.acceptButton.setEnabled(False)
self.verticalLayout.addWidget(self.acceptButton)
self.chartSelector.valueChanged.connect(self.updatePlayRatingCalculator)
self.playRatingCalculator.arcaeaScoreLineEdit.textChanged.connect(
self.updateAcceptButton
)
self.acceptButton.clicked.connect(self.accepted)
def updatePlayRatingCalculator(self):
chart = self.chartSelector.value()
if chart is None:
self.playRatingCalculator.setConstant(None)
else:
self.playRatingCalculator.setConstant(chart.constant)
self.updateAcceptButton()
def updateAcceptButton(self):
if self.playRatingCalculator.result is None:
self.acceptButton.setEnabled(False)
else:
self.acceptButton.setEnabled(True)
def reset(self):
self.chartSelector.resetButton.click()
self.playRatingCalculator.arcaeaScoreLineEdit.clear()
def value(self):
return self.playRatingCalculator.result
class TabTools_StepCalculator(Ui_TabTools_StepCalculator, QWidget):
@ -203,23 +242,18 @@ class TabTools_StepCalculator(Ui_TabTools_StepCalculator, QWidget):
)
self.partnerSkillPresetButton_maya.clicked.connect(self.applyPartnerPreset)
def openChartAndScoreInputDialog(self):
dialog = ChartAndScoreInputDialog(self)
dialog.scoreCommited.connect(
lambda: self.setPlayResultFromChartAndScoreInput(dialog)
)
dialog.show()
self.playRatingCalculatorDialog = PlayRatingCalculatorDialog(self)
self.playRatingCalculatorDialog.accepted.connect(self.set_toStep_PlayRating)
def setPlayResultFromChartAndScoreInput(self, dialog: ChartAndScoreInputDialog):
if score := dialog.score():
chart = dialog.chart()
self.calculate_toStep_playResultSpinBox.setValue(
float(calculate_play_rating(chart.constant, score.score))
)
dialog.close()
dialog.deleteLater()
else:
return
def openChartAndScoreInputDialog(self):
self.playRatingCalculatorDialog.reset()
self.playRatingCalculatorDialog.show()
def set_toStep_PlayRating(self):
result = self.playRatingCalculatorDialog.value()
if result is not None:
self.calculate_toStep_playResultSpinBox.setValue(result)
self.playRatingCalculatorDialog.close()
def applyPartnerPreset(self):
if not self.sender():
@ -307,7 +341,8 @@ class TabTools_StepCalculator(Ui_TabTools_StepCalculator, QWidget):
step = calculate_step(
playResult, partner_bonus=partnerBonus, step_booster=stepBooster
)
self.calculate_toStep_resultLabel.setText(f"{step}<br>({stepOriginal})")
self.calculate_toStep_resultLabel.setText(str(step))
self.calculate_toStep_detailedResultLabel.setText(str(stepOriginal))
except Exception:
if self.detailedLogOutputCheckBox.isChecked():
logger.exception("Cannot calculate toStep")
@ -315,16 +350,14 @@ class TabTools_StepCalculator(Ui_TabTools_StepCalculator, QWidget):
# fromStep
try:
self.calculate_fromStep_resultLabel.setText(
str(
calculate_play_rating_from_step(
self.calculate_fromStep_targetStepSpinBox.value(),
self.partnerStepValueSpinBox.value(),
partner_bonus=partnerBonus,
step_booster=stepBooster,
)
)
fromStepResult = calculate_play_rating_from_step(
self.calculate_fromStep_targetStepSpinBox.value(),
self.partnerStepValueSpinBox.value(),
partner_bonus=partnerBonus,
step_booster=stepBooster,
)
self.calculate_fromStep_resultLabel.setText(str(round(fromStepResult, 2)))
self.calculate_fromStep_detailedResultLabel.setText(str(fromStepResult))
except Exception:
if self.detailedLogOutputCheckBox.isChecked():
logger.exception("Cannot calculate fromStep")

View File

@ -27,64 +27,45 @@
<translation>Reset</translation>
</message>
</context>
<context>
<name>DB30TableModel</name>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="21"/>
<source>horizontalHeader.id</source>
<translation>ID</translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="22"/>
<source>horizontalHeader.chart</source>
<translation>Chart</translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="23"/>
<source>horizontalHeader.score</source>
<translation>Score</translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="24"/>
<source>horizontalHeader.potential</source>
<translation>Potential</translation>
</message>
</context>
<context>
<name>DatabaseChecker</name>
<message>
<location filename="../../startup/databaseChecker.ui" line="23"/>
<location filename="../../startup/databaseChecker_ui.py" line="162"/>
<source>dbPathLabel</source>
<translation>Database path</translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="33"/>
<location filename="../../startup/databaseChecker_ui.py" line="165"/>
<source>dbFilenameLabel</source>
<translation>Database filename</translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="64"/>
<location filename="../../startup/databaseChecker_ui.py" line="168"/>
<source>confirmDbPathButton</source>
<translation>Confirm</translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="117"/>
<location filename="../../startup/databaseChecker_ui.py" line="177"/>
<source>dbVersionLabel</source>
<translation>Database version</translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="131"/>
<source>dbReInitLabel</source>
<translation>Re-initialize database</translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="138"/>
<source>dbReInitButton</source>
<translation>Re-initialize</translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="93"/>
<location filename="../../startup/databaseChecker_ui.py" line="171"/>
<source>dbCheckConnLabel</source>
<translation>Database connection</translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="110"/>
<location filename="../../startup/databaseChecker_ui.py" line="174"/>
<source>continueButton</source>
<translation>Continue</translation>
</message>
@ -99,6 +80,29 @@
<translation>Database file does not exist. Create now?</translation>
</message>
</context>
<context>
<name>DbB30TableModel</name>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="20"/>
<source>horizontalHeader.id</source>
<translation>ID</translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="21"/>
<source>horizontalHeader.chart</source>
<translation>Chart</translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="22"/>
<source>horizontalHeader.score</source>
<translation>Score</translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="23"/>
<source>horizontalHeader.potential</source>
<translation>Potential</translation>
</message>
</context>
<context>
<name>DbScoreTableModel</name>
<message>
@ -303,6 +307,14 @@ validation</translation>
<translation>Score</translation>
</message>
</context>
<context>
<name>PotentialCalculator</name>
<message>
<location filename="../../implements/components/playRatingCalculator.py" line="85"/>
<source>copyButton</source>
<translation>Copy</translation>
</message>
</context>
<context>
<name>ResettableItem</name>
<message>
@ -554,6 +566,14 @@ validation</translation>
<translation>Next</translation>
</message>
</context>
<context>
<name>StepCalculator</name>
<message>
<location filename="../../implements/tabs/tabTools/tabTools_StepCalculator.py" line="96"/>
<source>playRatingCalculatorDialog.acceptButton</source>
<translation>Accept</translation>
</message>
</context>
<context>
<name>TabAbout</name>
<message>
@ -579,6 +599,11 @@ validation</translation>
<source>tab.chartInfoEditor</source>
<translation>Chart Info Editor</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDbEntry.ui" line="34"/>
<source>tab.removeDuplicateScores</source>
<translation>Remove Duplicate Scores</translation>
</message>
<message>
<location filename="../../implements/tabs/tabDbEntry.py" line="20"/>
<source>tab.scoreTableViewer</source>
@ -647,84 +672,232 @@ validation</translation>
<context>
<name>TabDb_Manage</name>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="23"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="78"/>
<source>syncArcSongDbButton</source>
<translation>Sync arcsong.db</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="30"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="85"/>
<source>syncArcSongDb.description</source>
<translation>Update chart info</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="37"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="98"/>
<source>importScoreGroup</source>
<translation>Import Score</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="105"/>
<source>importSt3Button</source>
<translation>Import from Game Save</translation>
<translation>Game Save Database</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="44"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="112"/>
<source>importSt3.description</source>
<translation>Import scores from your game save</translation>
<translation>Import scores from your game save database</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="58"/>
<source>exportScoresButton</source>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="139"/>
<source>exportScoreGroup</source>
<translation>Export Scores</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="65"/>
<source>exportScores.description</source>
<translation>Export all your scores to a JSON file</translation>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="146"/>
<source>exportScoresButton</source>
<translation>D.E.F. V2</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="79"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="153"/>
<source>exportScores.description</source>
<translation>Export all your scores in &lt;i&gt;Arcaea Offline Data Exchange Format V2&lt;/i&gt; formed JSON file</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="186"/>
<source>miscGroup</source>
<translation>Miscellaneous</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="284"/>
<source>syncChartInfoDbButton</source>
<translation>Sync Chart Info Database</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="291"/>
<source>syncChartInfoDb.description</source>
<translation>Update chart info</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="23"/>
<source>importPacklistButton</source>
<translation>Import packlist</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="86"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="37"/>
<source>importSonglistButton</source>
<translation>Import songlist</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="93"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="30"/>
<source>importPacklist.description</source>
<translation>Import packlist file</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="100"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="44"/>
<source>importSonglist.description</source>
<translation>Import songlist file</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="107"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="193"/>
<source>exportArcsongJsonButton</source>
<translation>Export arcsong.json</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="114"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="200"/>
<source>exportArcsongJson.description</source>
<translation>Export arcsong.json file</translation>
<translation>Export arcsong.json file based on the information in database</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="121"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="51"/>
<source>importApkButton</source>
<translation>Import from APK</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="128"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="213"/>
<source>packSongInfoGroup</source>
<translation>Pack/Song Info</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="58"/>
<source>importApk.description</source>
<translation>Import packlist and songlist from .apk file</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="135"/>
<source>importOnlineButton</source>
<translation>Import from Arcaea Online</translation>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="71"/>
<source>chartInfoGroup</source>
<translation>Chart Info</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="142"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="119"/>
<source>importOnlineButton</source>
<translation>Arcaea Online</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="126"/>
<source>importOnline.description</source>
<translation>Import scores from the result of Arcaea Online API</translation>
<translation>Import scores from the Arcaea Online API result</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="160"/>
<source>exportSmartRteB30Button</source>
<translation>SmartRTE B30</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="167"/>
<source>exportSmartRteB30.description</source>
<translation>Export all your scores to &lt;a href=&quot;https://smartrte.github.io/b30gen.html&quot;&gt;smartrte.github.io&lt;/a&gt; compatible CSV file</translation>
</message>
</context>
<context>
<name>TabDb_RemoveDuplicateScores</name>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="20"/>
<source>scan.title</source>
<translation>Scan Options</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="30"/>
<source>scan.option.score</source>
<translation>Score</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="71"/>
<source>scan.option.date</source>
<translation>Date</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="78"/>
<source>scan.option.modifier</source>
<translation>Modifier</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="85"/>
<source>scan.option.clearType</source>
<translation>Clear Type</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="94"/>
<source>scan.scanButton</source>
<translation>Scan</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="124"/>
<source>quickSelect.title</source>
<translation>Quick Select</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="130"/>
<source>quickSelect.description</source>
<translation>Keep the first score item&lt;br&gt;that matches:</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="166"/>
<source>quickSelect.selectButton</source>
<translation>Select</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="182"/>
<source>deselectAllButton</source>
<translation>Clear Selection</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="189"/>
<source>reverseSelectionButton</source>
<translation>Reverse Selection</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="209"/>
<source>collapseAllButton</source>
<translation>Collapse All Groups</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="216"/>
<source>expandAllButton</source>
<translation>Expand All Groups</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="223"/>
<source>resetModelButton</source>
<translation>Reset Model</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="251"/>
<source>deleteSelectionButton</source>
<translation>Delete Selected Scores</translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="158"/>
<source>quickSelectComboBox.idEarlier</source>
<translation>Earlier ID</translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="164"/>
<source>quickSelectComboBox.dateEarlier</source>
<translation>Earlier date</translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="170"/>
<source>quickSelectComboBox.columnsIntegral</source>
<translation>More complete data</translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="295"/>
<source>deleteSelectionDialog.content {}</source>
<translation>Deleting {} scores from database, this cannot be undone!&lt;br&gt;Confirm?</translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="317"/>
<source>scan_noColumnsDialog.content</source>
<translation>You haven&apos;t selected any column! Are you sure to continue?</translation>
</message>
</context>
<context>
@ -881,7 +1054,7 @@ validation</translation>
<context>
<name>TabOverview</name>
<message>
<location filename="../../implements/tabs/tabOverview.py" line="43"/>
<location filename="../../implements/tabs/tabOverview.py" line="56"/>
<source>databaseDescribeLabel {} {} {} {} {} {}</source>
<translation>There are {} packs, {} songs, {} difficulties, {} chart info ({} complete) and {} scores in database.</translation>
</message>
@ -971,6 +1144,11 @@ validation</translation>
<source>generateImageButton</source>
<translation>Generate</translation>
</message>
<message>
<location filename="../../designer/tabs/tabTools/tabTools_Andreal.ui" line="335"/>
<source>sourceCode</source>
<translation>Source code</translation>
</message>
<message>
<location filename="../../implements/tabs/tabTools/tabTools_Andreal.py" line="138"/>
<source>imageWhatIsThisDialog.description</source>
@ -980,7 +1158,7 @@ validation</translation>
<context>
<name>TabTools_ChartRecommend</name>
<message>
<location filename="../../designer/tabs/tabTools/tabTools_ChartRecommend.ui" line="99"/>
<location filename="../../designer/tabs/tabTools/tabTools_ChartRecommend.ui" line="102"/>
<source>constantRangeFromPlayRating</source>
<translation>Chart Constant Range from Play Rating</translation>
</message>
@ -990,7 +1168,7 @@ validation</translation>
<translation>Charts by Constant</translation>
</message>
<message>
<location filename="../../designer/tabs/tabTools/tabTools_ChartRecommend.ui" line="245"/>
<location filename="../../designer/tabs/tabTools/tabTools_ChartRecommend.ui" line="248"/>
<source>chartsRecommendFromPlayRating</source>
<translation>Chart from Play Rating Based on Best Score</translation>
</message>

View File

@ -1,5 +1,5 @@
import argparse
import os
import subprocess
import sys
from pathlib import Path
@ -32,23 +32,31 @@ assert startup.exists()
no_obsolete = args.no_obsolete
commands = [
(
"pyside6-lupdate"
" -extensions py,ui"
f" {designer.absolute()} {extends.absolute()} {implements.absolute()} {startup.absolute()}"
f" -ts {str((output_dir_path / 'zh_CN.ts').absolute())}"
), # zh_CN
(
"pyside6-lupdate"
" -extensions py,ui"
f" {designer.absolute()} {extends.absolute()} {implements.absolute()} {startup.absolute()}"
f" -ts {str((output_dir_path / 'en_US.ts').absolute())}"
), # en_US
[
"pyside6-lupdate",
"-extensions",
"py,ui",
str(designer.absolute()),
str(extends.absolute()),
str(implements.absolute()),
str(startup.absolute()),
"-ts",
str((output_dir_path / "zh_CN.ts").absolute()),
], # zh_CN
[
"pyside6-lupdate",
"-extensions",
"py,ui",
str(designer.absolute()),
str(extends.absolute()),
str(implements.absolute()),
str(startup.absolute()),
"-ts",
str((output_dir_path / "en_US.ts").absolute()),
], # en_US
]
if no_obsolete:
commands = [f"{command} -no-obsolete" for command in commands]
commands = [command + ["-no-obsolete"] for command in commands]
for command in commands:
print(f"Executing '{command}'")
output = os.popen(command).read()
print(output)
subprocess.run(command)

View File

@ -27,64 +27,45 @@
<translation></translation>
</message>
</context>
<context>
<name>DB30TableModel</name>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="21"/>
<source>horizontalHeader.id</source>
<translation>ID</translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="22"/>
<source>horizontalHeader.chart</source>
<translation></translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="23"/>
<source>horizontalHeader.score</source>
<translation></translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="24"/>
<source>horizontalHeader.potential</source>
<translation> PTT</translation>
</message>
</context>
<context>
<name>DatabaseChecker</name>
<message>
<location filename="../../startup/databaseChecker.ui" line="23"/>
<location filename="../../startup/databaseChecker_ui.py" line="162"/>
<source>dbPathLabel</source>
<translation></translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="33"/>
<location filename="../../startup/databaseChecker_ui.py" line="165"/>
<source>dbFilenameLabel</source>
<translation></translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="64"/>
<location filename="../../startup/databaseChecker_ui.py" line="168"/>
<source>confirmDbPathButton</source>
<translation></translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="117"/>
<location filename="../../startup/databaseChecker_ui.py" line="177"/>
<source>dbVersionLabel</source>
<translation></translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="131"/>
<source>dbReInitLabel</source>
<translation></translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="138"/>
<source>dbReInitButton</source>
<translation></translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="93"/>
<location filename="../../startup/databaseChecker_ui.py" line="171"/>
<source>dbCheckConnLabel</source>
<translation></translation>
</message>
<message>
<location filename="../../startup/databaseChecker.ui" line="110"/>
<location filename="../../startup/databaseChecker_ui.py" line="174"/>
<source>continueButton</source>
<translation></translation>
</message>
@ -99,6 +80,29 @@
<translation></translation>
</message>
</context>
<context>
<name>DbB30TableModel</name>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="20"/>
<source>horizontalHeader.id</source>
<translation>ID</translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="21"/>
<source>horizontalHeader.chart</source>
<translation></translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="22"/>
<source>horizontalHeader.score</source>
<translation></translation>
</message>
<message>
<location filename="../../extends/shared/models/tables/b30.py" line="23"/>
<source>horizontalHeader.potential</source>
<translation> PTT</translation>
</message>
</context>
<context>
<name>DbScoreTableModel</name>
<message>
@ -302,6 +306,14 @@
<translation></translation>
</message>
</context>
<context>
<name>PotentialCalculator</name>
<message>
<location filename="../../implements/components/playRatingCalculator.py" line="85"/>
<source>copyButton</source>
<translation></translation>
</message>
</context>
<context>
<name>ResettableItem</name>
<message>
@ -553,6 +565,14 @@
<translation></translation>
</message>
</context>
<context>
<name>StepCalculator</name>
<message>
<location filename="../../implements/tabs/tabTools/tabTools_StepCalculator.py" line="96"/>
<source>playRatingCalculatorDialog.acceptButton</source>
<translation></translation>
</message>
</context>
<context>
<name>TabAbout</name>
<message>
@ -578,6 +598,11 @@
<source>tab.chartInfoEditor</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDbEntry.ui" line="34"/>
<source>tab.removeDuplicateScores</source>
<translation></translation>
</message>
<message>
<location filename="../../implements/tabs/tabDbEntry.py" line="20"/>
<source>tab.scoreTableViewer</source>
@ -646,85 +671,233 @@
<context>
<name>TabDb_Manage</name>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="23"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="78"/>
<source>syncArcSongDbButton</source>
<translation> arcsong.db</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="30"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="85"/>
<source>syncArcSongDb.description</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="37"/>
<source>importSt3Button</source>
<translation></translation>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="98"/>
<source>importScoreGroup</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="44"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="105"/>
<source>importSt3Button</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="112"/>
<source>importSt3.description</source>
<translation>姿&lt;br&gt;退</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="58"/>
<source>exportScoresButton</source>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="139"/>
<source>exportScoreGroup</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="65"/>
<source>exportScores.description</source>
<translation> JSON </translation>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="146"/>
<source>exportScoresButton</source>
<translation> V2</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="79"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="153"/>
<source>exportScores.description</source>
<translation> &lt;i&gt;Arcaea Offline V2&lt;/i&gt; JSON </translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="186"/>
<source>miscGroup</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="284"/>
<source>syncChartInfoDbButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="291"/>
<source>syncChartInfoDb.description</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="23"/>
<source>importPacklistButton</source>
<translation> packlist</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="86"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="37"/>
<source>importSonglistButton</source>
<translation> songlist</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="93"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="30"/>
<source>importPacklist.description</source>
<translation> packlist </translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="100"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="44"/>
<source>importSonglist.description</source>
<translation> songlist </translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="107"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="193"/>
<source>exportArcsongJsonButton</source>
<translation> arcsong.json</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="114"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="200"/>
<source>exportArcsongJson.description</source>
<translation> arcsong.json </translation>
<translation> arcsong.json </translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="121"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="51"/>
<source>importApkButton</source>
<translation> APK </translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="128"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="213"/>
<source>packSongInfoGroup</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="58"/>
<source>importApk.description</source>
<translation> .apk packlist songlist</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="135"/>
<source>importOnlineButton</source>
<translation> Arcaea Online </translation>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="71"/>
<source>chartInfoGroup</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="142"/>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="119"/>
<source>importOnlineButton</source>
<translation>Arcaea Online</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="126"/>
<source>importOnline.description</source>
<translation> Arcaea Online API </translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="160"/>
<source>exportSmartRteB30Button</source>
<translation>SmartRTE B30</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_Manage.ui" line="167"/>
<source>exportSmartRteB30.description</source>
<translation> &lt;a href=&quot;https://smartrte.github.io/b30gen.html&quot;&gt;smartrte.github.io&lt;/a&gt; 的 CSV 文件</translation>
</message>
</context>
<context>
<name>TabDb_RemoveDuplicateScores</name>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="20"/>
<source>scan.title</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="30"/>
<source>scan.option.score</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="71"/>
<source>scan.option.date</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="78"/>
<source>scan.option.modifier</source>
<translation>Modifier</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="85"/>
<source>scan.option.clearType</source>
<translation>Clear Type</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="94"/>
<source>scan.scanButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="124"/>
<source>quickSelect.title</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="130"/>
<source>quickSelect.description</source>
<translation>&lt;br&gt;</translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="166"/>
<source>quickSelect.selectButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="182"/>
<source>deselectAllButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="189"/>
<source>reverseSelectionButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="209"/>
<source>collapseAllButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="216"/>
<source>expandAllButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="223"/>
<source>resetModelButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabDb/tabDb_RemoveDuplicateScores.ui" line="251"/>
<source>deleteSelectionButton</source>
<translation></translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="158"/>
<source>quickSelectComboBox.idEarlier</source>
<translation>ID </translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="164"/>
<source>quickSelectComboBox.dateEarlier</source>
<translation></translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="170"/>
<source>quickSelectComboBox.columnsIntegral</source>
<translation></translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="295"/>
<source>deleteSelectionDialog.content {}</source>
<translation> {} &lt;br&gt;</translation>
</message>
<message>
<location filename="../../implements/tabs/tabDb/tabDb_RemoveDuplicateScores.py" line="317"/>
<source>scan_noColumnsDialog.content</source>
<translation></translation>
</message>
</context>
<context>
<name>TabOcrDisabled</name>
@ -880,7 +1053,7 @@
<context>
<name>TabOverview</name>
<message>
<location filename="../../implements/tabs/tabOverview.py" line="43"/>
<location filename="../../implements/tabs/tabOverview.py" line="56"/>
<source>databaseDescribeLabel {} {} {} {} {} {}</source>
<translation> {} {} {} {} {} {} </translation>
</message>
@ -970,6 +1143,11 @@
<source>generateImageButton</source>
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabTools/tabTools_Andreal.ui" line="335"/>
<source>sourceCode</source>
<translation></translation>
</message>
<message>
<location filename="../../implements/tabs/tabTools/tabTools_Andreal.py" line="138"/>
<source>imageWhatIsThisDialog.description</source>
@ -979,7 +1157,7 @@
<context>
<name>TabTools_ChartRecommend</name>
<message>
<location filename="../../designer/tabs/tabTools/tabTools_ChartRecommend.ui" line="99"/>
<location filename="../../designer/tabs/tabTools/tabTools_ChartRecommend.ui" line="102"/>
<source>constantRangeFromPlayRating</source>
<translation> PTT </translation>
</message>
@ -989,7 +1167,7 @@
<translation></translation>
</message>
<message>
<location filename="../../designer/tabs/tabTools/tabTools_ChartRecommend.ui" line="245"/>
<location filename="../../designer/tabs/tabTools/tabTools_ChartRecommend.ui" line="248"/>
<source>chartsRecommendFromPlayRating</source>
<translation> PTT </translation>
</message>

View File

@ -3,7 +3,7 @@ import traceback
from enum import IntEnum
from arcaea_offline.database import Database
from PySide6.QtCore import QCoreApplication, QDir, QFileInfo, Qt, QUrl, Slot
from PySide6.QtCore import QCoreApplication, QDir, QFileInfo, QSysInfo, Qt, QUrl, Slot
from PySide6.QtWidgets import QDialog, QMessageBox
from ui.extends.shared.database import create_engine
@ -59,8 +59,13 @@ class DatabaseChecker(Ui_DatabaseChecker, QDialog):
return QUrl.fromLocalFile(self.dbFileInfo().filePath())
def dbSqliteUrl(self):
# dbSqliteUrl.setScheme("sqlite")
return QUrl(self.dbFileUrl().toString().replace("file://", "sqlite://"))
kernelType = QSysInfo.kernelType()
# the slash count varies depending on the kernel
# https://docs.sqlalchemy.org/en/20/core/engines.html#sqlite
if kernelType == "winnt":
return QUrl(self.dbFileUrl().toString().replace("file://", "sqlite://"))
else:
return QUrl(self.dbFileUrl().toString().replace("file://", "sqlite:///"))
def confirmDb(self) -> DatabaseCheckerResult:
flags = 0x000
@ -138,6 +143,11 @@ class DatabaseChecker(Ui_DatabaseChecker, QDialog):
db.init()
self.updateLabels()
@Slot()
def on_dbReInitButton_clicked(self):
Database().init(checkfirst=True)
QMessageBox.information(self, None, "OK")
@Slot()
def on_continueButton_clicked(self):
self.accept()

View File

@ -125,6 +125,20 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>dbReInitLabel</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="dbReInitButton">
<property name="text">
<string>dbReInitButton</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -8,173 +8,131 @@
## 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,
Qt,
QTime,
QUrl,
)
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,
QFormLayout,
QFrame,
QHBoxLayout,
QLabel,
QLineEdit,
QPushButton,
QSizePolicy,
QSpacerItem,
QWidget,
)
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, QFormLayout, QFrame, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QSizePolicy,
QSpacerItem, QWidget)
from ui.implements.components.fileSelector import FileSelector
class Ui_DatabaseChecker(object):
def setupUi(self, DatabaseChecker):
if not DatabaseChecker.objectName():
DatabaseChecker.setObjectName("DatabaseChecker")
DatabaseChecker.setObjectName(u"DatabaseChecker")
DatabaseChecker.resize(350, 250)
DatabaseChecker.setWindowTitle("DatabaseChecker")
DatabaseChecker.setWindowTitle(u"DatabaseChecker")
self.formLayout = QFormLayout(DatabaseChecker)
self.formLayout.setObjectName("formLayout")
self.formLayout.setLabelAlignment(
Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter
)
self.formLayout.setObjectName(u"formLayout")
self.formLayout.setLabelAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
self.label = QLabel(DatabaseChecker)
self.label.setObjectName("label")
self.label.setObjectName(u"label")
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label)
self.dbDirSelector = FileSelector(DatabaseChecker)
self.dbDirSelector.setObjectName("dbDirSelector")
self.dbDirSelector.setObjectName(u"dbDirSelector")
self.formLayout.setWidget(0, QFormLayout.FieldRole, self.dbDirSelector)
self.label_3 = QLabel(DatabaseChecker)
self.label_3.setObjectName("label_3")
self.label_3.setObjectName(u"label_3")
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_3)
self.dbFilenameLineEdit = QLineEdit(DatabaseChecker)
self.dbFilenameLineEdit.setObjectName("dbFilenameLineEdit")
self.dbFilenameLineEdit.setObjectName(u"dbFilenameLineEdit")
self.formLayout.setWidget(1, QFormLayout.FieldRole, self.dbFilenameLineEdit)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.horizontalSpacer = QSpacerItem(
40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum
)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout.addItem(self.horizontalSpacer)
self.confirmDbPathButton = QPushButton(DatabaseChecker)
self.confirmDbPathButton.setObjectName("confirmDbPathButton")
self.confirmDbPathButton.setObjectName(u"confirmDbPathButton")
sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.confirmDbPathButton.sizePolicy().hasHeightForWidth()
)
sizePolicy.setHeightForWidth(self.confirmDbPathButton.sizePolicy().hasHeightForWidth())
self.confirmDbPathButton.setSizePolicy(sizePolicy)
self.horizontalLayout.addWidget(self.confirmDbPathButton)
self.formLayout.setLayout(2, QFormLayout.FieldRole, self.horizontalLayout)
self.dbVersionLabel = QLabel(DatabaseChecker)
self.dbVersionLabel.setObjectName("dbVersionLabel")
self.dbVersionLabel.setText("-")
self.dbVersionLabel.setObjectName(u"dbVersionLabel")
self.dbVersionLabel.setText(u"-")
self.formLayout.setWidget(4, QFormLayout.FieldRole, self.dbVersionLabel)
self.verticalSpacer = QSpacerItem(
20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding
)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.formLayout.setItem(6, QFormLayout.FieldRole, self.verticalSpacer)
self.label_5 = QLabel(DatabaseChecker)
self.label_5.setObjectName("label_5")
self.label_5.setObjectName(u"label_5")
self.formLayout.setWidget(7, QFormLayout.LabelRole, self.label_5)
self.dbCheckConnLabel = QLabel(DatabaseChecker)
self.dbCheckConnLabel.setObjectName("dbCheckConnLabel")
self.dbCheckConnLabel.setText("...")
self.dbCheckConnLabel.setObjectName(u"dbCheckConnLabel")
self.dbCheckConnLabel.setText(u"...")
self.formLayout.setWidget(7, QFormLayout.FieldRole, self.dbCheckConnLabel)
self.continueButton = QPushButton(DatabaseChecker)
self.continueButton.setObjectName("continueButton")
self.continueButton.setObjectName(u"continueButton")
self.continueButton.setEnabled(False)
self.formLayout.setWidget(8, QFormLayout.SpanningRole, self.continueButton)
self.label_2 = QLabel(DatabaseChecker)
self.label_2.setObjectName("label_2")
self.label_2.setObjectName(u"label_2")
self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label_2)
self.line = QFrame(DatabaseChecker)
self.line.setObjectName("line")
self.line.setObjectName(u"line")
self.line.setFrameShape(QFrame.HLine)
self.line.setFrameShadow(QFrame.Sunken)
self.formLayout.setWidget(3, QFormLayout.SpanningRole, self.line)
self.label_4 = QLabel(DatabaseChecker)
self.label_4.setObjectName(u"label_4")
self.formLayout.setWidget(5, QFormLayout.LabelRole, self.label_4)
self.dbReInitButton = QPushButton(DatabaseChecker)
self.dbReInitButton.setObjectName(u"dbReInitButton")
self.formLayout.setWidget(5, QFormLayout.FieldRole, self.dbReInitButton)
self.retranslateUi(DatabaseChecker)
QMetaObject.connectSlotsByName(DatabaseChecker)
# setupUi
def retranslateUi(self, DatabaseChecker):
self.label.setText(
QCoreApplication.translate("DatabaseChecker", "dbPathLabel", None)
)
self.label_3.setText(
QCoreApplication.translate("DatabaseChecker", "dbFilenameLabel", None)
)
self.confirmDbPathButton.setText(
QCoreApplication.translate("DatabaseChecker", "confirmDbPathButton", None)
)
self.label_5.setText(
QCoreApplication.translate("DatabaseChecker", "dbCheckConnLabel", None)
)
self.continueButton.setText(
QCoreApplication.translate("DatabaseChecker", "continueButton", None)
)
self.label_2.setText(
QCoreApplication.translate("DatabaseChecker", "dbVersionLabel", None)
)
self.label.setText(QCoreApplication.translate("DatabaseChecker", u"dbPathLabel", None))
self.label_3.setText(QCoreApplication.translate("DatabaseChecker", u"dbFilenameLabel", None))
self.confirmDbPathButton.setText(QCoreApplication.translate("DatabaseChecker", u"confirmDbPathButton", None))
self.label_5.setText(QCoreApplication.translate("DatabaseChecker", u"dbCheckConnLabel", None))
self.continueButton.setText(QCoreApplication.translate("DatabaseChecker", u"continueButton", None))
self.label_2.setText(QCoreApplication.translate("DatabaseChecker", u"dbVersionLabel", None))
self.label_4.setText(QCoreApplication.translate("DatabaseChecker", u"dbReInitLabel", None))
self.dbReInitButton.setText(QCoreApplication.translate("DatabaseChecker", u"dbReInitButton", None))
pass
# retranslateUi