mirror of
https://github.com/283375/arcaea-offline-pyside-ui.git
synced 2025-07-01 04:16:26 +00:00
wip: refactor
This commit is contained in:
174
ui/designer/components/ocrQueue.ui
Normal file
174
ui/designer/components/ocrQueue.ui
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>OcrQueue</class>
|
||||||
|
<widget class="QWidget" name="OcrQueue">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>741</width>
|
||||||
|
<height>372</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>OcrQueue</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>ocr.title</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>ocr.queue.title</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ocr_addImageButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>ocr.queue.addImageButton</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ocr_removeSelectedButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>ocr.queue.removeSelected</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ocr_removeAllButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>ocr.queue.removeAll</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="ocr_startButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>ocr.queue.startOcrButton</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="tableView">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::MultiSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progressBar">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="format">
|
||||||
|
<string notr="true">%v/%m - %p%</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_5">
|
||||||
|
<property name="title">
|
||||||
|
<string>ocr.results</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ocr_acceptSelectedButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>ocr.results.acceptSelectedButton</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ocr_acceptAllButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>ocr.results.acceptAllButton</string>
|
||||||
|
</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="QCheckBox" name="ocr_ignoreValidateCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>ocr.results.ignoreValidate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
141
ui/designer/components/ocrQueue_ui.py
Normal file
141
ui/designer/components/ocrQueue_ui.py
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## Form generated from reading UI file 'ocrQueue.ui'
|
||||||
|
##
|
||||||
|
## Created by: Qt User Interface Compiler version 6.5.1
|
||||||
|
##
|
||||||
|
## 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, QGroupBox,
|
||||||
|
QHBoxLayout, QHeaderView, QProgressBar, QPushButton,
|
||||||
|
QSizePolicy, QSpacerItem, QTableView, QVBoxLayout,
|
||||||
|
QWidget)
|
||||||
|
|
||||||
|
class Ui_OcrQueue(object):
|
||||||
|
def setupUi(self, OcrQueue):
|
||||||
|
if not OcrQueue.objectName():
|
||||||
|
OcrQueue.setObjectName(u"OcrQueue")
|
||||||
|
OcrQueue.resize(741, 372)
|
||||||
|
self.verticalLayout = QVBoxLayout(OcrQueue)
|
||||||
|
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||||
|
self.groupBox_2 = QGroupBox(OcrQueue)
|
||||||
|
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||||
|
self.horizontalLayout = QHBoxLayout(self.groupBox_2)
|
||||||
|
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||||
|
self.groupBox_3 = QGroupBox(self.groupBox_2)
|
||||||
|
self.groupBox_3.setObjectName(u"groupBox_3")
|
||||||
|
self.verticalLayout_2 = QVBoxLayout(self.groupBox_3)
|
||||||
|
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||||
|
self.ocr_addImageButton = QPushButton(self.groupBox_3)
|
||||||
|
self.ocr_addImageButton.setObjectName(u"ocr_addImageButton")
|
||||||
|
|
||||||
|
self.verticalLayout_2.addWidget(self.ocr_addImageButton)
|
||||||
|
|
||||||
|
self.ocr_removeSelectedButton = QPushButton(self.groupBox_3)
|
||||||
|
self.ocr_removeSelectedButton.setObjectName(u"ocr_removeSelectedButton")
|
||||||
|
self.ocr_removeSelectedButton.setEnabled(True)
|
||||||
|
|
||||||
|
self.verticalLayout_2.addWidget(self.ocr_removeSelectedButton)
|
||||||
|
|
||||||
|
self.ocr_removeAllButton = QPushButton(self.groupBox_3)
|
||||||
|
self.ocr_removeAllButton.setObjectName(u"ocr_removeAllButton")
|
||||||
|
self.ocr_removeAllButton.setEnabled(True)
|
||||||
|
|
||||||
|
self.verticalLayout_2.addWidget(self.ocr_removeAllButton)
|
||||||
|
|
||||||
|
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||||
|
|
||||||
|
self.verticalLayout_2.addItem(self.verticalSpacer)
|
||||||
|
|
||||||
|
self.ocr_startButton = QPushButton(self.groupBox_3)
|
||||||
|
self.ocr_startButton.setObjectName(u"ocr_startButton")
|
||||||
|
|
||||||
|
self.verticalLayout_2.addWidget(self.ocr_startButton)
|
||||||
|
|
||||||
|
|
||||||
|
self.horizontalLayout.addWidget(self.groupBox_3)
|
||||||
|
|
||||||
|
self.verticalLayout_3 = QVBoxLayout()
|
||||||
|
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
||||||
|
self.tableView = QTableView(self.groupBox_2)
|
||||||
|
self.tableView.setObjectName(u"tableView")
|
||||||
|
self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed)
|
||||||
|
self.tableView.setSelectionMode(QAbstractItemView.MultiSelection)
|
||||||
|
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
self.tableView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||||
|
self.tableView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||||
|
|
||||||
|
self.verticalLayout_3.addWidget(self.tableView)
|
||||||
|
|
||||||
|
self.progressBar = QProgressBar(self.groupBox_2)
|
||||||
|
self.progressBar.setObjectName(u"progressBar")
|
||||||
|
self.progressBar.setMinimum(0)
|
||||||
|
self.progressBar.setMaximum(0)
|
||||||
|
self.progressBar.setValue(0)
|
||||||
|
self.progressBar.setAlignment(Qt.AlignCenter)
|
||||||
|
self.progressBar.setFormat(u"%v/%m - %p%")
|
||||||
|
|
||||||
|
self.verticalLayout_3.addWidget(self.progressBar)
|
||||||
|
|
||||||
|
|
||||||
|
self.horizontalLayout.addLayout(self.verticalLayout_3)
|
||||||
|
|
||||||
|
self.groupBox_5 = QGroupBox(self.groupBox_2)
|
||||||
|
self.groupBox_5.setObjectName(u"groupBox_5")
|
||||||
|
self.verticalLayout_4 = QVBoxLayout(self.groupBox_5)
|
||||||
|
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
||||||
|
self.ocr_acceptSelectedButton = QPushButton(self.groupBox_5)
|
||||||
|
self.ocr_acceptSelectedButton.setObjectName(u"ocr_acceptSelectedButton")
|
||||||
|
self.ocr_acceptSelectedButton.setEnabled(True)
|
||||||
|
|
||||||
|
self.verticalLayout_4.addWidget(self.ocr_acceptSelectedButton)
|
||||||
|
|
||||||
|
self.ocr_acceptAllButton = QPushButton(self.groupBox_5)
|
||||||
|
self.ocr_acceptAllButton.setObjectName(u"ocr_acceptAllButton")
|
||||||
|
|
||||||
|
self.verticalLayout_4.addWidget(self.ocr_acceptAllButton)
|
||||||
|
|
||||||
|
self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||||
|
|
||||||
|
self.verticalLayout_4.addItem(self.verticalSpacer_2)
|
||||||
|
|
||||||
|
self.ocr_ignoreValidateCheckBox = QCheckBox(self.groupBox_5)
|
||||||
|
self.ocr_ignoreValidateCheckBox.setObjectName(u"ocr_ignoreValidateCheckBox")
|
||||||
|
|
||||||
|
self.verticalLayout_4.addWidget(self.ocr_ignoreValidateCheckBox)
|
||||||
|
|
||||||
|
|
||||||
|
self.horizontalLayout.addWidget(self.groupBox_5)
|
||||||
|
|
||||||
|
|
||||||
|
self.verticalLayout.addWidget(self.groupBox_2)
|
||||||
|
|
||||||
|
|
||||||
|
self.retranslateUi(OcrQueue)
|
||||||
|
|
||||||
|
QMetaObject.connectSlotsByName(OcrQueue)
|
||||||
|
# setupUi
|
||||||
|
|
||||||
|
def retranslateUi(self, OcrQueue):
|
||||||
|
OcrQueue.setWindowTitle(QCoreApplication.translate("OcrQueue", u"OcrQueue", None))
|
||||||
|
self.groupBox_2.setTitle(QCoreApplication.translate("OcrQueue", u"ocr.title", None))
|
||||||
|
self.groupBox_3.setTitle(QCoreApplication.translate("OcrQueue", u"ocr.queue.title", None))
|
||||||
|
self.ocr_addImageButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.queue.addImageButton", None))
|
||||||
|
self.ocr_removeSelectedButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.queue.removeSelected", None))
|
||||||
|
self.ocr_removeAllButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.queue.removeAll", None))
|
||||||
|
self.ocr_startButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.queue.startOcrButton", None))
|
||||||
|
self.groupBox_5.setTitle(QCoreApplication.translate("OcrQueue", u"ocr.results", None))
|
||||||
|
self.ocr_acceptSelectedButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.results.acceptSelectedButton", None))
|
||||||
|
self.ocr_acceptAllButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.results.acceptAllButton", None))
|
||||||
|
self.ocr_ignoreValidateCheckBox.setText(QCoreApplication.translate("OcrQueue", u"ocr.results.ignoreValidate", None))
|
||||||
|
# retranslateUi
|
||||||
|
|
@ -55,125 +55,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
<widget class="OcrQueue" name="ocrQueue" native="true"/>
|
||||||
<property name="title">
|
|
||||||
<string>ocr.queue.title</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="ocr_addImageButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>ocr.queue.addImageButton</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="ocr_removeSelectedButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>ocr.queue.removeSelected</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="ocr_removeAllButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>ocr.queue.removeAll</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="ocr_startButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>ocr.queue.startOcrButton</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QTableView" name="tableView">
|
|
||||||
<property name="editTriggers">
|
|
||||||
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
|
|
||||||
</property>
|
|
||||||
<property name="selectionMode">
|
|
||||||
<enum>QAbstractItemView::MultiSelection</enum>
|
|
||||||
</property>
|
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
|
||||||
</property>
|
|
||||||
<property name="verticalScrollMode">
|
|
||||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollMode">
|
|
||||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_5">
|
|
||||||
<property name="title">
|
|
||||||
<string>ocr.results</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="ocr_acceptSelectedButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>ocr.results.acceptSelectedButton</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="ocr_acceptAllButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>ocr.results.acceptAllButton</string>
|
|
||||||
</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="QCheckBox" name="ocr_ignoreValidateCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>ocr.results.ignoreValidate</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@ -192,6 +74,12 @@
|
|||||||
<extends>QComboBox</extends>
|
<extends>QComboBox</extends>
|
||||||
<header>ui.implements.components</header>
|
<header>ui.implements.components</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>OcrQueue</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>ui.implements.components</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
## Form generated from reading UI file 'tabOcr.ui'
|
## Form generated from reading UI file 'tabOcr.ui'
|
||||||
##
|
##
|
||||||
## Created by: Qt User Interface Compiler version 6.5.0
|
## Created by: Qt User Interface Compiler version 6.5.1
|
||||||
##
|
##
|
||||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||||
################################################################################
|
################################################################################
|
||||||
@ -15,11 +15,10 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
|||||||
QFont, QFontDatabase, QGradient, QIcon,
|
QFont, QFontDatabase, QGradient, QIcon,
|
||||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||||
from PySide6.QtWidgets import (QAbstractItemView, QApplication, QCheckBox, QGroupBox,
|
from PySide6.QtWidgets import (QApplication, QGroupBox, QHBoxLayout, QPushButton,
|
||||||
QHBoxLayout, QHeaderView, QPushButton, QSizePolicy,
|
QSizePolicy, QVBoxLayout, QWidget)
|
||||||
QSpacerItem, QTableView, QVBoxLayout, QWidget)
|
|
||||||
|
|
||||||
from ui.implements.components import (DevicesComboBox, FileSelector)
|
from ui.implements.components import (DevicesComboBox, FileSelector, OcrQueue)
|
||||||
|
|
||||||
class Ui_TabOcr(object):
|
class Ui_TabOcr(object):
|
||||||
def setupUi(self, TabOcr):
|
def setupUi(self, TabOcr):
|
||||||
@ -67,75 +66,10 @@ class Ui_TabOcr(object):
|
|||||||
self.groupBox_2.setObjectName(u"groupBox_2")
|
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||||
self.horizontalLayout = QHBoxLayout(self.groupBox_2)
|
self.horizontalLayout = QHBoxLayout(self.groupBox_2)
|
||||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||||
self.groupBox_3 = QGroupBox(self.groupBox_2)
|
self.ocrQueue = OcrQueue(self.groupBox_2)
|
||||||
self.groupBox_3.setObjectName(u"groupBox_3")
|
self.ocrQueue.setObjectName(u"ocrQueue")
|
||||||
self.verticalLayout_2 = QVBoxLayout(self.groupBox_3)
|
|
||||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
|
||||||
self.ocr_addImageButton = QPushButton(self.groupBox_3)
|
|
||||||
self.ocr_addImageButton.setObjectName(u"ocr_addImageButton")
|
|
||||||
|
|
||||||
self.verticalLayout_2.addWidget(self.ocr_addImageButton)
|
self.horizontalLayout.addWidget(self.ocrQueue)
|
||||||
|
|
||||||
self.ocr_removeSelectedButton = QPushButton(self.groupBox_3)
|
|
||||||
self.ocr_removeSelectedButton.setObjectName(u"ocr_removeSelectedButton")
|
|
||||||
self.ocr_removeSelectedButton.setEnabled(True)
|
|
||||||
|
|
||||||
self.verticalLayout_2.addWidget(self.ocr_removeSelectedButton)
|
|
||||||
|
|
||||||
self.ocr_removeAllButton = QPushButton(self.groupBox_3)
|
|
||||||
self.ocr_removeAllButton.setObjectName(u"ocr_removeAllButton")
|
|
||||||
self.ocr_removeAllButton.setEnabled(True)
|
|
||||||
|
|
||||||
self.verticalLayout_2.addWidget(self.ocr_removeAllButton)
|
|
||||||
|
|
||||||
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
|
||||||
|
|
||||||
self.verticalLayout_2.addItem(self.verticalSpacer)
|
|
||||||
|
|
||||||
self.ocr_startButton = QPushButton(self.groupBox_3)
|
|
||||||
self.ocr_startButton.setObjectName(u"ocr_startButton")
|
|
||||||
|
|
||||||
self.verticalLayout_2.addWidget(self.ocr_startButton)
|
|
||||||
|
|
||||||
|
|
||||||
self.horizontalLayout.addWidget(self.groupBox_3)
|
|
||||||
|
|
||||||
self.tableView = QTableView(self.groupBox_2)
|
|
||||||
self.tableView.setObjectName(u"tableView")
|
|
||||||
self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed)
|
|
||||||
self.tableView.setSelectionMode(QAbstractItemView.MultiSelection)
|
|
||||||
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
||||||
self.tableView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
|
||||||
self.tableView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
|
||||||
|
|
||||||
self.horizontalLayout.addWidget(self.tableView)
|
|
||||||
|
|
||||||
self.groupBox_5 = QGroupBox(self.groupBox_2)
|
|
||||||
self.groupBox_5.setObjectName(u"groupBox_5")
|
|
||||||
self.verticalLayout_4 = QVBoxLayout(self.groupBox_5)
|
|
||||||
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
|
||||||
self.ocr_acceptSelectedButton = QPushButton(self.groupBox_5)
|
|
||||||
self.ocr_acceptSelectedButton.setObjectName(u"ocr_acceptSelectedButton")
|
|
||||||
self.ocr_acceptSelectedButton.setEnabled(True)
|
|
||||||
|
|
||||||
self.verticalLayout_4.addWidget(self.ocr_acceptSelectedButton)
|
|
||||||
|
|
||||||
self.ocr_acceptAllButton = QPushButton(self.groupBox_5)
|
|
||||||
self.ocr_acceptAllButton.setObjectName(u"ocr_acceptAllButton")
|
|
||||||
|
|
||||||
self.verticalLayout_4.addWidget(self.ocr_acceptAllButton)
|
|
||||||
|
|
||||||
self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
|
||||||
|
|
||||||
self.verticalLayout_4.addItem(self.verticalSpacer_2)
|
|
||||||
|
|
||||||
self.ocr_ignoreValidateCheckBox = QCheckBox(self.groupBox_5)
|
|
||||||
self.ocr_ignoreValidateCheckBox.setObjectName(u"ocr_ignoreValidateCheckBox")
|
|
||||||
|
|
||||||
self.verticalLayout_4.addWidget(self.ocr_ignoreValidateCheckBox)
|
|
||||||
|
|
||||||
|
|
||||||
self.horizontalLayout.addWidget(self.groupBox_5)
|
|
||||||
|
|
||||||
|
|
||||||
self.verticalLayout_3.addWidget(self.groupBox_2)
|
self.verticalLayout_3.addWidget(self.groupBox_2)
|
||||||
@ -151,15 +85,6 @@ class Ui_TabOcr(object):
|
|||||||
self.groupBox.setTitle(QCoreApplication.translate("TabOcr", u"deviceSelector.title", None))
|
self.groupBox.setTitle(QCoreApplication.translate("TabOcr", u"deviceSelector.title", None))
|
||||||
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr", u"tesseractSelector.title", None))
|
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr", u"tesseractSelector.title", None))
|
||||||
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr", u"ocr.title", None))
|
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr", u"ocr.title", None))
|
||||||
self.groupBox_3.setTitle(QCoreApplication.translate("TabOcr", u"ocr.queue.title", None))
|
|
||||||
self.ocr_addImageButton.setText(QCoreApplication.translate("TabOcr", u"ocr.queue.addImageButton", None))
|
|
||||||
self.ocr_removeSelectedButton.setText(QCoreApplication.translate("TabOcr", u"ocr.queue.removeSelected", None))
|
|
||||||
self.ocr_removeAllButton.setText(QCoreApplication.translate("TabOcr", u"ocr.queue.removeAll", None))
|
|
||||||
self.ocr_startButton.setText(QCoreApplication.translate("TabOcr", u"ocr.queue.startOcrButton", None))
|
|
||||||
self.groupBox_5.setTitle(QCoreApplication.translate("TabOcr", u"ocr.results", None))
|
|
||||||
self.ocr_acceptSelectedButton.setText(QCoreApplication.translate("TabOcr", u"ocr.results.acceptSelectedButton", None))
|
|
||||||
self.ocr_acceptAllButton.setText(QCoreApplication.translate("TabOcr", u"ocr.results.acceptAllButton", None))
|
|
||||||
self.ocr_ignoreValidateCheckBox.setText(QCoreApplication.translate("TabOcr", u"ocr.results.ignoreValidate", None))
|
|
||||||
pass
|
pass
|
||||||
# retranslateUi
|
# retranslateUi
|
||||||
|
|
||||||
|
394
ui/extends/components/ocrQueue/__init__.py
Normal file
394
ui/extends/components/ocrQueue/__init__.py
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
import logging
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
from arcaea_offline.calculate import calculate_score_range
|
||||||
|
from arcaea_offline.database import Database
|
||||||
|
from arcaea_offline.models import Chart, ScoreInsert
|
||||||
|
from arcaea_offline_ocr.device.shared import DeviceOcrResult
|
||||||
|
from PySide6.QtCore import (
|
||||||
|
QAbstractListModel,
|
||||||
|
QAbstractTableModel,
|
||||||
|
QCoreApplication,
|
||||||
|
QFileInfo,
|
||||||
|
QModelIndex,
|
||||||
|
QObject,
|
||||||
|
QRunnable,
|
||||||
|
Qt,
|
||||||
|
QThreadPool,
|
||||||
|
Signal,
|
||||||
|
Slot,
|
||||||
|
)
|
||||||
|
from PySide6.QtGui import QImage, QPixmap
|
||||||
|
|
||||||
|
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
|
||||||
|
from ui.extends.shared.delegates.imageDelegate import ImageDelegate
|
||||||
|
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class OcrRunnableSignals(QObject):
|
||||||
|
rowId: int = -1
|
||||||
|
|
||||||
|
resultReady = Signal(DeviceOcrResult)
|
||||||
|
finished = Signal()
|
||||||
|
|
||||||
|
|
||||||
|
class OcrRunnable(QRunnable):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.signals = OcrRunnableSignals()
|
||||||
|
|
||||||
|
|
||||||
|
class OcrQueueModel(QAbstractListModel):
|
||||||
|
ImagePathRole = Qt.ItemDataRole.UserRole + 1
|
||||||
|
ImageQImageRole = Qt.ItemDataRole.UserRole + 2
|
||||||
|
ImagePixmapRole = Qt.ItemDataRole.UserRole + 3
|
||||||
|
|
||||||
|
DeviceOcrResultRole = Qt.ItemDataRole.UserRole + 10
|
||||||
|
ScoreInsertRole = Qt.ItemDataRole.UserRole + 11
|
||||||
|
ChartRole = Qt.ItemDataRole.UserRole + 12
|
||||||
|
ScoreValidateOkRole = Qt.ItemDataRole.UserRole + 13
|
||||||
|
|
||||||
|
OcrRunnableRole = Qt.ItemDataRole.UserRole + 20
|
||||||
|
ProcessOcrResultFuncRole = (
|
||||||
|
Qt.ItemDataRole.UserRole + 21
|
||||||
|
) # Callable[[imageStr, DeviceOcrResult], tuple[Chart, ScoreInsert]]
|
||||||
|
|
||||||
|
started = Signal()
|
||||||
|
progress = Signal(int)
|
||||||
|
finished = Signal()
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.__db = Database()
|
||||||
|
self.__items: list[dict[int, Any]] = []
|
||||||
|
|
||||||
|
self.__taskFinishedNum = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def imagePaths(self):
|
||||||
|
return [item.get(self.ImagePathRole) for item in self.__items]
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.beginResetModel()
|
||||||
|
self.beginRemoveRows(QModelIndex(), 0, self.rowCount() - 1)
|
||||||
|
self.__items.clear()
|
||||||
|
self.endRemoveRows()
|
||||||
|
self.__taskFinishedNum = 0
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def rowCount(self, *args):
|
||||||
|
return len(self.__items)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if (
|
||||||
|
index.isValid()
|
||||||
|
and 0 <= index.row() < self.rowCount()
|
||||||
|
and index.column() == 0
|
||||||
|
):
|
||||||
|
return self.__items[index.row()].get(role)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def setData(self, index: QModelIndex, value: Any, role: int):
|
||||||
|
if not 0 <= index.row() < self.rowCount():
|
||||||
|
return False
|
||||||
|
|
||||||
|
item = self.__items[index.row()]
|
||||||
|
updateRole = None
|
||||||
|
|
||||||
|
if role == self.DeviceOcrResultRole and isinstance(value, DeviceOcrResult):
|
||||||
|
item[self.DeviceOcrResultRole] = value
|
||||||
|
self.updateRole = role
|
||||||
|
|
||||||
|
if role == self.ChartRole and isinstance(value, Chart):
|
||||||
|
item[self.ChartRole] = value
|
||||||
|
self.updateScoreValidateOk(index.row())
|
||||||
|
self.updateRole = role
|
||||||
|
|
||||||
|
if role == self.ScoreInsertRole and isinstance(value, ScoreInsert):
|
||||||
|
item[self.ScoreInsertRole] = value
|
||||||
|
self.updateScoreValidateOk(index.row())
|
||||||
|
self.updateRole = role
|
||||||
|
|
||||||
|
if role == self.ScoreValidateOkRole and isinstance(value, bool):
|
||||||
|
item[self.ScoreValidateOkRole] = value
|
||||||
|
self.updateRole = role
|
||||||
|
|
||||||
|
if role == self.OcrRunnableRole and isinstance(value, OcrRunnable):
|
||||||
|
item[self.OcrRunnableRole] = value
|
||||||
|
self.updateRole = role
|
||||||
|
|
||||||
|
if role == self.ProcessOcrResultFuncRole and callable(value):
|
||||||
|
item[self.ProcessOcrResultFuncRole] = value
|
||||||
|
self.updateRole = role
|
||||||
|
|
||||||
|
if updateRole is not None:
|
||||||
|
self.dataChanged.emit(index, index, [updateRole])
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def addItem(
|
||||||
|
self,
|
||||||
|
imagePath: str,
|
||||||
|
runnable: OcrRunnable = None,
|
||||||
|
process_func: Callable = None,
|
||||||
|
):
|
||||||
|
if imagePath in self.imagePaths or not QFileInfo(imagePath).exists():
|
||||||
|
logger.warning(f"Attempting to add an invalid file {imagePath}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
|
||||||
|
self.__items.append(
|
||||||
|
{
|
||||||
|
self.ImagePathRole: imagePath,
|
||||||
|
self.ImageQImageRole: QImage(imagePath),
|
||||||
|
self.ImagePixmapRole: QPixmap(imagePath),
|
||||||
|
self.DeviceOcrResultRole: None,
|
||||||
|
self.ScoreInsertRole: None,
|
||||||
|
self.ChartRole: None,
|
||||||
|
self.ScoreValidateOkRole: False,
|
||||||
|
self.OcrRunnableRole: runnable,
|
||||||
|
self.ProcessOcrResultFuncRole: process_func,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.endInsertRows()
|
||||||
|
|
||||||
|
def updateOcrResult(self, row: int, result: DeviceOcrResult) -> bool:
|
||||||
|
if not 0 <= row < self.rowCount() or not isinstance(result, DeviceOcrResult):
|
||||||
|
return False
|
||||||
|
|
||||||
|
index = self.index(row, 0)
|
||||||
|
imagePath: str = index.data(self.ImagePathRole)
|
||||||
|
processOcrResultFunc = index.data(self.ProcessOcrResultFuncRole)
|
||||||
|
|
||||||
|
chart, scoreInsert = processOcrResultFunc(imagePath, result)
|
||||||
|
|
||||||
|
# song_id = self.__db.fuzzy_search_song_id(result.title)[0][0]
|
||||||
|
|
||||||
|
self.setData(index, result, self.DeviceOcrResultRole)
|
||||||
|
self.setData(index, chart, self.ChartRole)
|
||||||
|
self.setData(index, scoreInsert, self.ScoreInsertRole)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@Slot(DeviceOcrResult)
|
||||||
|
def ocrTaskReady(self, result: DeviceOcrResult):
|
||||||
|
row = self.sender().rowId
|
||||||
|
print(row)
|
||||||
|
self.updateOcrResult(row, result)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def ocrTaskFinished(self):
|
||||||
|
self.__taskFinishedNum += 1
|
||||||
|
self.progress.emit(self.__taskFinishedNum)
|
||||||
|
if self.__taskFinishedNum == self.__taskNum:
|
||||||
|
self.finished.emit()
|
||||||
|
print("model finished")
|
||||||
|
|
||||||
|
def startQueue(self):
|
||||||
|
self.__taskNum = self.rowCount()
|
||||||
|
self.__taskFinishedNum = 0
|
||||||
|
self.started.emit()
|
||||||
|
for row in range(self.rowCount()):
|
||||||
|
modelIndex = self.index(row, 0)
|
||||||
|
runnable: OcrRunnable = modelIndex.data(self.OcrRunnableRole)
|
||||||
|
runnable.signals.rowId = row
|
||||||
|
runnable.signals.resultReady.connect(self.ocrTaskReady)
|
||||||
|
runnable.signals.finished.connect(self.ocrTaskFinished)
|
||||||
|
QThreadPool.globalInstance().start(runnable)
|
||||||
|
|
||||||
|
def updateScoreValidateOk(self, row: int):
|
||||||
|
if not 0 <= row < self.rowCount():
|
||||||
|
return
|
||||||
|
|
||||||
|
index = self.index(row, 0)
|
||||||
|
chart = index.data(self.ChartRole)
|
||||||
|
score = index.data(self.ScoreInsertRole)
|
||||||
|
if isinstance(chart, Chart) and isinstance(score, ScoreInsert):
|
||||||
|
scoreRange = calculate_score_range(chart, score.pure, score.far)
|
||||||
|
scoreValidateOk = scoreRange[0] <= score.score <= scoreRange[1]
|
||||||
|
self.setData(index, scoreValidateOk, self.ScoreValidateOkRole)
|
||||||
|
else:
|
||||||
|
self.setData(index, False, self.ScoreValidateOkRole)
|
||||||
|
|
||||||
|
def acceptItem(self, row: int, ignoreValidate: bool = False):
|
||||||
|
if not 0 <= row < self.rowCount():
|
||||||
|
return
|
||||||
|
|
||||||
|
item = self.__items[row]
|
||||||
|
score = item[self.ScoreInsertRole]
|
||||||
|
if not isinstance(score, ScoreInsert) or (
|
||||||
|
not item[self.ScoreValidateOkRole] and not ignoreValidate
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.__db.insert_score(score)
|
||||||
|
self.beginRemoveRows(QModelIndex(), row, row)
|
||||||
|
self.__items.pop(row)
|
||||||
|
self.endRemoveRows()
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Error accepting {repr(item)}")
|
||||||
|
return
|
||||||
|
|
||||||
|
def acceptItems(self, __rows: list[int], ignoreValidate: bool = False):
|
||||||
|
items = sorted(__rows, reverse=True)
|
||||||
|
[self.acceptItem(item, ignoreValidate) for item in items]
|
||||||
|
|
||||||
|
def acceptAllItems(self, ignoreValidate: bool = False):
|
||||||
|
self.acceptItems([*range(self.rowCount())], ignoreValidate)
|
||||||
|
|
||||||
|
def removeItem(self, row: int):
|
||||||
|
if not 0 <= row < self.rowCount():
|
||||||
|
return
|
||||||
|
|
||||||
|
self.beginRemoveRows(QModelIndex(), row, row)
|
||||||
|
self.__items.pop(row)
|
||||||
|
self.endRemoveRows()
|
||||||
|
|
||||||
|
def removeItems(self, __rows: list[int]):
|
||||||
|
rows = sorted(__rows, reverse=True)
|
||||||
|
[self.removeItem(row) for row in rows]
|
||||||
|
|
||||||
|
|
||||||
|
class OcrQueueTableProxyModel(QAbstractTableModel):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.retranslateHeaders()
|
||||||
|
self.__sourceModel = None
|
||||||
|
self.__columnRoleMapping = [
|
||||||
|
[Qt.ItemDataRole.CheckStateRole],
|
||||||
|
[
|
||||||
|
OcrQueueModel.ImagePathRole,
|
||||||
|
OcrQueueModel.ImageQImageRole,
|
||||||
|
OcrQueueModel.ImagePixmapRole,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
OcrQueueModel.DeviceOcrResultRole,
|
||||||
|
OcrQueueModel.ChartRole,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
OcrQueueModel.DeviceOcrResultRole,
|
||||||
|
OcrQueueModel.ScoreInsertRole,
|
||||||
|
OcrQueueModel.ChartRole,
|
||||||
|
OcrQueueModel.ScoreValidateOkRole,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
def retranslateHeaders(self):
|
||||||
|
self.__horizontalHeaders = [
|
||||||
|
# fmt: off
|
||||||
|
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.select"),
|
||||||
|
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.imagePreview"),
|
||||||
|
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.chart"),
|
||||||
|
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.score"),
|
||||||
|
# fmt: on
|
||||||
|
]
|
||||||
|
|
||||||
|
def sourceModel(self) -> OcrQueueModel:
|
||||||
|
return self.__sourceModel
|
||||||
|
|
||||||
|
def setSourceModel(self, sourceModel):
|
||||||
|
if not isinstance(sourceModel, OcrQueueModel):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# connect signals
|
||||||
|
sourceModel.rowsAboutToBeInserted.connect(self.rowsAboutToBeInserted)
|
||||||
|
sourceModel.rowsInserted.connect(self.rowsInserted)
|
||||||
|
sourceModel.rowsAboutToBeRemoved.connect(self.rowsAboutToBeRemoved)
|
||||||
|
sourceModel.rowsRemoved.connect(self.rowsRemoved)
|
||||||
|
sourceModel.dataChanged.connect(self.dataChanged)
|
||||||
|
sourceModel.layoutAboutToBeChanged.connect(self.layoutAboutToBeChanged)
|
||||||
|
sourceModel.layoutChanged.connect(self.layoutChanged)
|
||||||
|
|
||||||
|
self.__sourceModel = sourceModel
|
||||||
|
return True
|
||||||
|
|
||||||
|
def rowCount(self, *args):
|
||||||
|
return self.sourceModel().rowCount()
|
||||||
|
|
||||||
|
def columnCount(self, *args):
|
||||||
|
return len(self.__horizontalHeaders)
|
||||||
|
|
||||||
|
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
|
||||||
|
if (
|
||||||
|
orientation == Qt.Orientation.Horizontal
|
||||||
|
and 0 <= section < len(self.__horizontalHeaders)
|
||||||
|
and role == Qt.ItemDataRole.DisplayRole
|
||||||
|
):
|
||||||
|
return self.__horizontalHeaders[section]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if (
|
||||||
|
0 <= index.row() < self.rowCount()
|
||||||
|
and 0 <= index.column() < self.columnCount()
|
||||||
|
and role in self.__columnRoleMapping[index.column()]
|
||||||
|
):
|
||||||
|
srcIndex = self.sourceModel().index(index.row(), 0)
|
||||||
|
return srcIndex.data(role)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def setData(self, index, value, role):
|
||||||
|
if index.column() == 2 and role == OcrQueueModel.ChartRole:
|
||||||
|
return self.sourceModel().setItemChart(index.row(), value)
|
||||||
|
if index.column() == 3 and role == OcrQueueModel.ScoreInsertRole:
|
||||||
|
return self.sourceModel().setItemScore(index.row(), value)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
|
||||||
|
flags = (
|
||||||
|
self.sourceModel().flags(index)
|
||||||
|
if isinstance(self.sourceModel(), OcrQueueModel)
|
||||||
|
else super().flags(index)
|
||||||
|
)
|
||||||
|
flags = flags | Qt.ItemFlag.ItemIsEnabled
|
||||||
|
flags = flags | Qt.ItemFlag.ItemIsEditable
|
||||||
|
flags = flags | Qt.ItemFlag.ItemIsSelectable
|
||||||
|
if index.column() == 0:
|
||||||
|
flags = flags & ~Qt.ItemFlag.ItemIsEnabled & ~Qt.ItemFlag.ItemIsEditable
|
||||||
|
return flags
|
||||||
|
|
||||||
|
|
||||||
|
class OcrImageDelegate(ImageDelegate):
|
||||||
|
def getPixmap(self, index: QModelIndex):
|
||||||
|
return index.data(OcrQueueModel.ImagePixmapRole)
|
||||||
|
|
||||||
|
def getImagePath(self, index: QModelIndex):
|
||||||
|
return index.data(OcrQueueModel.ImagePathRole)
|
||||||
|
|
||||||
|
|
||||||
|
class OcrChartDelegate(ChartDelegate):
|
||||||
|
def getChart(self, index: QModelIndex) -> Chart | None:
|
||||||
|
return index.data(OcrQueueModel.ChartRole)
|
||||||
|
|
||||||
|
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
||||||
|
return isinstance(
|
||||||
|
index.data(OcrQueueModel.DeviceOcrResultRole), DeviceOcrResult
|
||||||
|
)
|
||||||
|
|
||||||
|
def setModelData(self, editor, model: OcrQueueTableProxyModel, index):
|
||||||
|
if editor.validate():
|
||||||
|
model.setData(index, editor.value(), OcrQueueModel.ChartRole)
|
||||||
|
|
||||||
|
|
||||||
|
class OcrScoreDelegate(ScoreDelegate):
|
||||||
|
def getScoreInsert(self, index: QModelIndex):
|
||||||
|
return index.data(OcrQueueModel.ScoreInsertRole)
|
||||||
|
|
||||||
|
def getChart(self, index: QModelIndex):
|
||||||
|
return index.data(OcrQueueModel.ChartRole)
|
||||||
|
|
||||||
|
def getScoreValidateOk(self, index: QModelIndex):
|
||||||
|
return index.data(OcrQueueModel.ScoreValidateOkRole)
|
||||||
|
|
||||||
|
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
||||||
|
return isinstance(
|
||||||
|
index.data(OcrQueueModel.DeviceOcrResultRole), DeviceOcrResult
|
||||||
|
)
|
||||||
|
|
||||||
|
def setModelData(self, editor, model: OcrQueueTableProxyModel, index):
|
||||||
|
if super().confirmSetModelData(editor):
|
||||||
|
model.setData(index, editor.value(), OcrQueueModel.ScoreInsertRole)
|
@ -1,16 +1,24 @@
|
|||||||
try:
|
try:
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from arcaea_offline_ocr.device import Device
|
from arcaea_offline_ocr.device.v1.definition import DeviceV1
|
||||||
|
from arcaea_offline_ocr.device.v2.definition import DeviceV2
|
||||||
|
|
||||||
def load_devices_json(filepath: str) -> list[Device]:
|
def load_devices_json(filepath: str) -> list[DeviceV1]:
|
||||||
with open(filepath, "r", encoding="utf-8") as f:
|
with open(filepath, "r", encoding="utf-8") as f:
|
||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
if len(file_content) == 0:
|
if len(file_content) == 0:
|
||||||
return []
|
return []
|
||||||
content = json.loads(file_content)
|
content = json.loads(file_content)
|
||||||
assert isinstance(content, list)
|
assert isinstance(content, list)
|
||||||
return [Device.from_json_object(item) for item in content]
|
devices = []
|
||||||
|
for item in content:
|
||||||
|
version = item["version"]
|
||||||
|
if version == 1:
|
||||||
|
devices.append(DeviceV1(**item))
|
||||||
|
elif version == 2:
|
||||||
|
devices.append(DeviceV2(**item))
|
||||||
|
return devices
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
||||||
|
70
ui/extends/shared/delegates/imageDelegate.py
Normal file
70
ui/extends/shared/delegates/imageDelegate.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
from PySide6.QtCore import QFileInfo, QModelIndex, QRect, QSize, Qt
|
||||||
|
from PySide6.QtGui import QPixmap
|
||||||
|
from PySide6.QtWidgets import QLabel, QStyledItemDelegate, QWidget
|
||||||
|
|
||||||
|
|
||||||
|
class ImageDelegate(QStyledItemDelegate):
|
||||||
|
def getPixmap(self, index: QModelIndex):
|
||||||
|
raise NotImplementedError("getPixmap not implemented.")
|
||||||
|
|
||||||
|
def getImagePath(self, index: QModelIndex):
|
||||||
|
raise NotImplementedError("getImagePath not implemented.")
|
||||||
|
|
||||||
|
def scalePixmap(self, pixmap: QPixmap):
|
||||||
|
return pixmap.scaled(
|
||||||
|
100,
|
||||||
|
100,
|
||||||
|
Qt.AspectRatioMode.KeepAspectRatio,
|
||||||
|
Qt.TransformationMode.SmoothTransformation,
|
||||||
|
)
|
||||||
|
|
||||||
|
def paint(self, painter, option, index):
|
||||||
|
pixmap = self.getPixmap(index)
|
||||||
|
if not isinstance(pixmap, QPixmap):
|
||||||
|
imagePath = self.getImagePath(index)
|
||||||
|
option.text = imagePath
|
||||||
|
super().paint(painter, option, index)
|
||||||
|
else:
|
||||||
|
pixmap = self.scalePixmap(pixmap)
|
||||||
|
# https://stackoverflow.com/a/32047499/16484891
|
||||||
|
# CC BY-SA 3.0
|
||||||
|
x = option.rect.center().x() - pixmap.rect().width() / 2
|
||||||
|
y = option.rect.center().y() - pixmap.rect().height() / 2
|
||||||
|
|
||||||
|
painter.drawPixmap(
|
||||||
|
QRect(x, y, pixmap.rect().width(), pixmap.rect().height()), pixmap
|
||||||
|
)
|
||||||
|
|
||||||
|
def sizeHint(self, option, index) -> QSize:
|
||||||
|
pixmap = self.getPixmap(index)
|
||||||
|
if isinstance(pixmap, QPixmap):
|
||||||
|
pixmap = self.scalePixmap(pixmap)
|
||||||
|
return pixmap.size()
|
||||||
|
else:
|
||||||
|
return QSize(100, 75)
|
||||||
|
|
||||||
|
def createEditor(self, parent, option, index) -> QWidget:
|
||||||
|
pixmap = self.getPixmap(index)
|
||||||
|
if isinstance(pixmap, QPixmap):
|
||||||
|
label = QLabel(parent)
|
||||||
|
label.setWindowFlags(Qt.WindowType.Window)
|
||||||
|
label.setWindowFlag(Qt.WindowType.WindowMinimizeButtonHint, False)
|
||||||
|
label.setWindowFlag(Qt.WindowType.WindowMaximizeButtonHint, False)
|
||||||
|
label.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, True)
|
||||||
|
label.setWindowTitle(QFileInfo(self.getImagePath(index)).fileName())
|
||||||
|
pixmap = pixmap.scaled(
|
||||||
|
800,
|
||||||
|
800,
|
||||||
|
Qt.AspectRatioMode.KeepAspectRatio,
|
||||||
|
Qt.TransformationMode.SmoothTransformation,
|
||||||
|
)
|
||||||
|
label.setMinimumSize(pixmap.size())
|
||||||
|
label.setPixmap(pixmap)
|
||||||
|
label.move(parent.mapToGlobal(parent.pos()))
|
||||||
|
return label
|
||||||
|
|
||||||
|
def setModelData(self, *args):
|
||||||
|
...
|
||||||
|
|
||||||
|
def updateEditorGeometry(self, *args):
|
||||||
|
...
|
@ -126,6 +126,8 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
score_str = str(score.score).rjust(8, "0")
|
||||||
|
score_str = f"{score_str[:-6]}'{score_str[-6:-3]}'{score_str[-3:]}"
|
||||||
score_font = QFont(option.font)
|
score_font = QFont(option.font)
|
||||||
score_font.setPointSize(12)
|
score_font.setPointSize(12)
|
||||||
score_grade_font = QFont(score_font)
|
score_grade_font = QFont(score_font)
|
||||||
@ -140,7 +142,7 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
self.FontRole: score_grade_font,
|
self.FontRole: score_grade_font,
|
||||||
},
|
},
|
||||||
{self.TextRole: " | "},
|
{self.TextRole: " | "},
|
||||||
{self.TextRole: str(score.score), self.FontRole: score_font},
|
{self.TextRole: score_str, self.FontRole: score_font},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -1,133 +1,43 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Tuple
|
||||||
|
|
||||||
import exif
|
|
||||||
from arcaea_offline.calculate import calculate_score_range
|
|
||||||
from arcaea_offline.database import Database
|
from arcaea_offline.database import Database
|
||||||
from arcaea_offline.models import Chart, ScoreInsert
|
from arcaea_offline.models import ScoreInsert, Chart
|
||||||
from arcaea_offline_ocr.device import Device
|
from arcaea_offline_ocr.device.shared import DeviceOcrResult
|
||||||
from arcaea_offline_ocr.recognize import RecognizeResult, recognize
|
from arcaea_offline_ocr.device.v2.ocr import DeviceV2Ocr
|
||||||
from PySide6.QtCore import (
|
from arcaea_offline_ocr.device.v2.rois import DeviceV2Rois
|
||||||
QAbstractListModel,
|
from arcaea_offline_ocr.utils import imread_unicode
|
||||||
QAbstractTableModel,
|
from PySide6.QtCore import QDateTime, QFileInfo
|
||||||
QCoreApplication,
|
|
||||||
QDateTime,
|
|
||||||
QFileInfo,
|
|
||||||
QModelIndex,
|
|
||||||
QObject,
|
|
||||||
QRect,
|
|
||||||
QRunnable,
|
|
||||||
QSize,
|
|
||||||
Qt,
|
|
||||||
QThreadPool,
|
|
||||||
Signal,
|
|
||||||
Slot,
|
|
||||||
)
|
|
||||||
from PySide6.QtGui import QPixmap
|
|
||||||
from PySide6.QtWidgets import QLabel, QStyledItemDelegate, QWidget
|
|
||||||
|
|
||||||
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
|
from ui.extends.components.ocrQueue import OcrRunnable
|
||||||
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
|
|
||||||
from ui.implements.components.scoreEditor import ScoreEditor
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
import exif
|
||||||
class OcrTaskSignals(QObject):
|
|
||||||
resultReady = Signal(int, RecognizeResult)
|
|
||||||
finished = Signal(int)
|
|
||||||
|
|
||||||
|
|
||||||
class OcrTask(QRunnable):
|
class TabDeviceV2OcrRunnable(OcrRunnable):
|
||||||
def __init__(self, index: int, device: Device, imagePath: str):
|
def __init__(self, imagePath, device, knnModel, siftDb):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.index = index
|
|
||||||
self.device = device
|
|
||||||
self.imagePath = imagePath
|
self.imagePath = imagePath
|
||||||
self.signals = OcrTaskSignals()
|
self.device = device
|
||||||
|
self.knnModel = knnModel
|
||||||
|
self.siftDb = siftDb
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
result = recognize(self.imagePath, self.device)
|
rois = DeviceV2Rois(self.device, imread_unicode(self.imagePath))
|
||||||
self.signals.resultReady.emit(self.index, result)
|
ocr = DeviceV2Ocr(self.knnModel, self.siftDb)
|
||||||
logger.info(
|
result = ocr.ocr(rois)
|
||||||
f"OcrTask {self.imagePath} with {repr(self.device)} got result {repr(result)}"
|
self.signals.resultReady.emit(result)
|
||||||
)
|
except Exception:
|
||||||
except Exception as e:
|
logger.exception(f"DeviceV2 ocr {self.imagePath} error")
|
||||||
logger.exception(
|
|
||||||
f"OcrTask {self.imagePath} with {repr(self.device)} failed"
|
|
||||||
)
|
|
||||||
finally:
|
finally:
|
||||||
self.signals.finished.emit(self.index)
|
self.signals.finished.emit()
|
||||||
|
|
||||||
|
|
||||||
class OcrQueueModel(QAbstractListModel):
|
def getImageDate(imagePath: str) -> QDateTime:
|
||||||
ImagePathRole = Qt.ItemDataRole.UserRole + 1
|
|
||||||
ImagePixmapRole = Qt.ItemDataRole.UserRole + 2
|
|
||||||
RecognizeResultRole = Qt.ItemDataRole.UserRole + 10
|
|
||||||
ScoreInsertRole = Qt.ItemDataRole.UserRole + 11
|
|
||||||
ChartRole = Qt.ItemDataRole.UserRole + 12
|
|
||||||
ScoreValidateOkRole = Qt.ItemDataRole.UserRole + 13
|
|
||||||
|
|
||||||
started = Signal()
|
|
||||||
finished = Signal()
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.__db = Database()
|
|
||||||
self.__items: list[dict[int, Any]] = []
|
|
||||||
|
|
||||||
@property
|
|
||||||
def imagePaths(self):
|
|
||||||
return [item.get(self.ImagePathRole) for item in self.__items]
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self.beginResetModel()
|
|
||||||
self.beginRemoveRows(QModelIndex(), 0, self.rowCount() - 1)
|
|
||||||
self.__items.clear()
|
|
||||||
self.endRemoveRows()
|
|
||||||
self.endResetModel()
|
|
||||||
|
|
||||||
def rowCount(self, *args):
|
|
||||||
return len(self.__items)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
|
||||||
if (
|
|
||||||
index.isValid()
|
|
||||||
and 0 <= index.row() < self.rowCount()
|
|
||||||
and index.column() == 0
|
|
||||||
):
|
|
||||||
return self.__items[index.row()].get(role)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def setData(self, *args):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def addItem(self, imagePath: str):
|
|
||||||
if imagePath in self.imagePaths or not QFileInfo(imagePath).exists():
|
|
||||||
return
|
|
||||||
|
|
||||||
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
|
|
||||||
self.__items.append(
|
|
||||||
{
|
|
||||||
self.ImagePathRole: imagePath,
|
|
||||||
self.ImagePixmapRole: QPixmap(imagePath),
|
|
||||||
self.RecognizeResultRole: None,
|
|
||||||
self.ScoreInsertRole: None,
|
|
||||||
self.ChartRole: None,
|
|
||||||
self.ScoreValidateOkRole: False,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.endInsertRows()
|
|
||||||
|
|
||||||
def updateOcrResult(self, row: int, result: RecognizeResult) -> bool:
|
|
||||||
if not 0 <= row < self.rowCount() or not isinstance(result, RecognizeResult):
|
|
||||||
return False
|
|
||||||
|
|
||||||
item = self.__items[row]
|
|
||||||
|
|
||||||
imagePath: str = item[self.ImagePathRole]
|
|
||||||
datetime = None
|
datetime = None
|
||||||
with contextlib.suppress(Exception):
|
with contextlib.suppress(Exception):
|
||||||
with open(imagePath, "rb") as imgf:
|
with open(imagePath, "rb") as imgf:
|
||||||
@ -137,340 +47,25 @@ class OcrQueueModel(QAbstractListModel):
|
|||||||
datetime = QDateTime.fromString(datetimeStr, "yyyy:MM:dd hh:mm:ss")
|
datetime = QDateTime.fromString(datetimeStr, "yyyy:MM:dd hh:mm:ss")
|
||||||
if not isinstance(datetime, QDateTime):
|
if not isinstance(datetime, QDateTime):
|
||||||
datetime = QFileInfo(imagePath).birthTime()
|
datetime = QFileInfo(imagePath).birthTime()
|
||||||
|
return datetime
|
||||||
|
|
||||||
score = ScoreInsert(
|
|
||||||
song_id=self.__db.fuzzy_search_song_id(result.title)[0][0],
|
class ScoreInsertConverter:
|
||||||
|
@staticmethod
|
||||||
|
def deviceV2(imagePath: str, result: DeviceOcrResult) -> Tuple[Chart, ScoreInsert]:
|
||||||
|
db = Database()
|
||||||
|
scoreInsert = ScoreInsert(
|
||||||
|
song_id=result.song_id,
|
||||||
rating_class=result.rating_class,
|
rating_class=result.rating_class,
|
||||||
score=result.score,
|
score=result.score,
|
||||||
pure=result.pure,
|
pure=result.pure,
|
||||||
far=result.far,
|
far=result.far,
|
||||||
lost=result.lost,
|
lost=result.lost,
|
||||||
time=datetime.toSecsSinceEpoch(),
|
time=getImageDate(imagePath).toSecsSinceEpoch(),
|
||||||
max_recall=result.max_recall,
|
max_recall=result.max_recall,
|
||||||
clear_type=None,
|
clear_type=None,
|
||||||
)
|
)
|
||||||
chart = Chart.from_db_row(
|
chart = Chart.from_db_row(
|
||||||
self.__db.get_chart(score.song_id, score.rating_class)
|
db.get_chart(scoreInsert.song_id, scoreInsert.rating_class)
|
||||||
)
|
)
|
||||||
|
return (chart, scoreInsert)
|
||||||
item[self.RecognizeResultRole] = result
|
|
||||||
self.setItemChart(row, chart)
|
|
||||||
self.setItemScore(row, score)
|
|
||||||
modelIndex = self.index(row, 0)
|
|
||||||
self.dataChanged.emit(
|
|
||||||
modelIndex,
|
|
||||||
modelIndex,
|
|
||||||
[self.RecognizeResultRole, self.ScoreInsertRole, self.ChartRole],
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
|
|
||||||
@Slot(int, RecognizeResult)
|
|
||||||
def ocrTaskReady(self, row: int, result: RecognizeResult):
|
|
||||||
self.updateOcrResult(row, result)
|
|
||||||
|
|
||||||
@Slot(int)
|
|
||||||
def ocrTaskFinished(self, row: int):
|
|
||||||
self.__taskFinishedNum += 1
|
|
||||||
if self.__taskFinishedNum == self.__taskNum:
|
|
||||||
self.finished.emit()
|
|
||||||
|
|
||||||
def startQueue(self, device: Device):
|
|
||||||
self.__taskNum = self.rowCount()
|
|
||||||
self.__taskFinishedNum = 0
|
|
||||||
self.started.emit()
|
|
||||||
for row in range(self.rowCount()):
|
|
||||||
modelIndex = self.index(row, 0)
|
|
||||||
imagePath: str = modelIndex.data(self.ImagePathRole)
|
|
||||||
task = OcrTask(row, device, imagePath)
|
|
||||||
task.signals.resultReady.connect(self.ocrTaskReady)
|
|
||||||
task.signals.finished.connect(self.ocrTaskFinished)
|
|
||||||
QThreadPool.globalInstance().start(task)
|
|
||||||
|
|
||||||
def updateScoreValidateOk(self, row: int):
|
|
||||||
if not 0 <= row < self.rowCount():
|
|
||||||
return
|
|
||||||
|
|
||||||
item = self.__items[row]
|
|
||||||
chart = item[self.ChartRole]
|
|
||||||
score = item[self.ScoreInsertRole]
|
|
||||||
if isinstance(chart, Chart) and isinstance(score, ScoreInsert):
|
|
||||||
scoreRange = calculate_score_range(chart, score.pure, score.far)
|
|
||||||
scoreValidateOk = scoreRange[0] <= score.score <= scoreRange[1]
|
|
||||||
item[self.ScoreValidateOkRole] = scoreValidateOk
|
|
||||||
else:
|
|
||||||
item[self.ScoreValidateOkRole] = False
|
|
||||||
|
|
||||||
modelIndex = self.index(row, 0)
|
|
||||||
self.dataChanged.emit(modelIndex, modelIndex, [self.ScoreValidateOkRole])
|
|
||||||
|
|
||||||
def setItemChart(self, row: int, chart: Chart):
|
|
||||||
if not 0 <= row < self.rowCount() or not isinstance(chart, Chart):
|
|
||||||
return False
|
|
||||||
|
|
||||||
item = self.__items[row]
|
|
||||||
item[self.ChartRole] = chart
|
|
||||||
updatedRoles = [self.ChartRole]
|
|
||||||
|
|
||||||
self.updateScoreValidateOk(row)
|
|
||||||
|
|
||||||
modelIndex = self.index(row, 0)
|
|
||||||
self.dataChanged.emit(modelIndex, modelIndex, updatedRoles)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def setItemScore(self, row: int, score: ScoreInsert) -> bool:
|
|
||||||
if not 0 <= row < self.rowCount() or not isinstance(score, ScoreInsert):
|
|
||||||
return False
|
|
||||||
|
|
||||||
item = self.__items[row]
|
|
||||||
item[self.ScoreInsertRole] = score
|
|
||||||
updatedRoles = [self.ScoreInsertRole]
|
|
||||||
|
|
||||||
self.updateScoreValidateOk(row)
|
|
||||||
|
|
||||||
modelIndex = self.index(row, 0)
|
|
||||||
self.dataChanged.emit(modelIndex, modelIndex, updatedRoles)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def acceptItem(self, row: int, ignoreValidate: bool = False):
|
|
||||||
if not 0 <= row < self.rowCount():
|
|
||||||
return
|
|
||||||
|
|
||||||
item = self.__items[row]
|
|
||||||
score = item[self.ScoreInsertRole]
|
|
||||||
if not isinstance(score, ScoreInsert) or (
|
|
||||||
not item[self.ScoreValidateOkRole] and not ignoreValidate
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.__db.insert_score(score)
|
|
||||||
self.beginRemoveRows(QModelIndex(), row, row)
|
|
||||||
self.__items.pop(row)
|
|
||||||
self.endRemoveRows()
|
|
||||||
return
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception(f"Error accepting {repr(item)}")
|
|
||||||
return
|
|
||||||
|
|
||||||
def acceptItems(self, __rows: list[int], ignoreValidate: bool = False):
|
|
||||||
items = sorted(__rows, reverse=True)
|
|
||||||
[self.acceptItem(item, ignoreValidate) for item in items]
|
|
||||||
|
|
||||||
def acceptAllItems(self, ignoreValidate: bool = False):
|
|
||||||
self.acceptItems([*range(self.rowCount())], ignoreValidate)
|
|
||||||
|
|
||||||
def removeItem(self, row: int):
|
|
||||||
if not 0 <= row < self.rowCount():
|
|
||||||
return
|
|
||||||
|
|
||||||
self.beginRemoveRows(QModelIndex(), row, row)
|
|
||||||
self.__items.pop(row)
|
|
||||||
self.endRemoveRows()
|
|
||||||
|
|
||||||
def removeItems(self, __rows: list[int]):
|
|
||||||
rows = sorted(__rows, reverse=True)
|
|
||||||
[self.removeItem(row) for row in rows]
|
|
||||||
|
|
||||||
|
|
||||||
class OcrQueueTableProxyModel(QAbstractTableModel):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.retranslateHeaders()
|
|
||||||
self.__sourceModel = None
|
|
||||||
self.__columnRoleMapping = [
|
|
||||||
[Qt.ItemDataRole.CheckStateRole],
|
|
||||||
[OcrQueueModel.ImagePathRole, OcrQueueModel.ImagePixmapRole],
|
|
||||||
[
|
|
||||||
OcrQueueModel.RecognizeResultRole,
|
|
||||||
OcrQueueModel.ChartRole,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
OcrQueueModel.RecognizeResultRole,
|
|
||||||
OcrQueueModel.ScoreInsertRole,
|
|
||||||
OcrQueueModel.ChartRole,
|
|
||||||
OcrQueueModel.ScoreValidateOkRole,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
|
|
||||||
def retranslateHeaders(self):
|
|
||||||
self.__horizontalHeaders = [
|
|
||||||
# fmt: off
|
|
||||||
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.select"),
|
|
||||||
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.imagePreview"),
|
|
||||||
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.chart"),
|
|
||||||
QCoreApplication.translate("OcrTableModel", "horizontalHeader.title.score"),
|
|
||||||
# fmt: on
|
|
||||||
]
|
|
||||||
|
|
||||||
def sourceModel(self) -> OcrQueueModel:
|
|
||||||
return self.__sourceModel
|
|
||||||
|
|
||||||
def setSourceModel(self, sourceModel):
|
|
||||||
if not isinstance(sourceModel, OcrQueueModel):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# connect signals
|
|
||||||
sourceModel.rowsAboutToBeInserted.connect(self.rowsAboutToBeInserted)
|
|
||||||
sourceModel.rowsInserted.connect(self.rowsInserted)
|
|
||||||
sourceModel.rowsAboutToBeRemoved.connect(self.rowsAboutToBeRemoved)
|
|
||||||
sourceModel.rowsRemoved.connect(self.rowsRemoved)
|
|
||||||
sourceModel.dataChanged.connect(self.dataChanged)
|
|
||||||
sourceModel.layoutAboutToBeChanged.connect(self.layoutAboutToBeChanged)
|
|
||||||
sourceModel.layoutChanged.connect(self.layoutChanged)
|
|
||||||
|
|
||||||
self.__sourceModel = sourceModel
|
|
||||||
return True
|
|
||||||
|
|
||||||
def rowCount(self, *args):
|
|
||||||
return self.sourceModel().rowCount()
|
|
||||||
|
|
||||||
def columnCount(self, *args):
|
|
||||||
return len(self.__horizontalHeaders)
|
|
||||||
|
|
||||||
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
|
|
||||||
if (
|
|
||||||
orientation == Qt.Orientation.Horizontal
|
|
||||||
and 0 <= section < len(self.__horizontalHeaders)
|
|
||||||
and role == Qt.ItemDataRole.DisplayRole
|
|
||||||
):
|
|
||||||
return self.__horizontalHeaders[section]
|
|
||||||
return None
|
|
||||||
|
|
||||||
def data(self, index, role):
|
|
||||||
if (
|
|
||||||
0 <= index.row() < self.rowCount()
|
|
||||||
and 0 <= index.column() < self.columnCount()
|
|
||||||
and role in self.__columnRoleMapping[index.column()]
|
|
||||||
):
|
|
||||||
srcIndex = self.sourceModel().index(index.row(), 0)
|
|
||||||
return srcIndex.data(role)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def setData(self, index, value, role):
|
|
||||||
if index.column() == 2 and role == OcrQueueModel.ChartRole:
|
|
||||||
return self.sourceModel().setItemChart(index.row(), value)
|
|
||||||
if index.column() == 3 and role == OcrQueueModel.ScoreInsertRole:
|
|
||||||
return self.sourceModel().setItemScore(index.row(), value)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
|
|
||||||
flags = (
|
|
||||||
self.sourceModel().flags(index)
|
|
||||||
if isinstance(self.sourceModel(), OcrQueueModel)
|
|
||||||
else super().flags(index)
|
|
||||||
)
|
|
||||||
flags = flags | Qt.ItemFlag.ItemIsEnabled
|
|
||||||
flags = flags | Qt.ItemFlag.ItemIsEditable
|
|
||||||
flags = flags | Qt.ItemFlag.ItemIsSelectable
|
|
||||||
if index.column() == 0:
|
|
||||||
flags = flags & ~Qt.ItemFlag.ItemIsEnabled & ~Qt.ItemFlag.ItemIsEditable
|
|
||||||
return flags
|
|
||||||
|
|
||||||
|
|
||||||
class ImageDelegate(QStyledItemDelegate):
|
|
||||||
def getPixmap(self, index: QModelIndex):
|
|
||||||
return index.data(OcrQueueModel.ImagePixmapRole)
|
|
||||||
|
|
||||||
def getImagePath(self, index: QModelIndex):
|
|
||||||
return index.data(OcrQueueModel.ImagePathRole)
|
|
||||||
|
|
||||||
def scalePixmap(self, pixmap: QPixmap):
|
|
||||||
return pixmap.scaled(
|
|
||||||
100,
|
|
||||||
100,
|
|
||||||
Qt.AspectRatioMode.KeepAspectRatio,
|
|
||||||
Qt.TransformationMode.SmoothTransformation,
|
|
||||||
)
|
|
||||||
|
|
||||||
def paint(self, painter, option, index):
|
|
||||||
pixmap = self.getPixmap(index)
|
|
||||||
if not isinstance(pixmap, QPixmap):
|
|
||||||
imagePath = self.getImagePath(index)
|
|
||||||
option.text = imagePath
|
|
||||||
super().paint(painter, option, index)
|
|
||||||
else:
|
|
||||||
pixmap = self.scalePixmap(pixmap)
|
|
||||||
# https://stackoverflow.com/a/32047499/16484891
|
|
||||||
# CC BY-SA 3.0
|
|
||||||
x = option.rect.center().x() - pixmap.rect().width() / 2
|
|
||||||
y = option.rect.center().y() - pixmap.rect().height() / 2
|
|
||||||
|
|
||||||
painter.drawPixmap(
|
|
||||||
QRect(x, y, pixmap.rect().width(), pixmap.rect().height()), pixmap
|
|
||||||
)
|
|
||||||
|
|
||||||
def sizeHint(self, option, index) -> QSize:
|
|
||||||
pixmap = self.getPixmap(index)
|
|
||||||
if isinstance(pixmap, QPixmap):
|
|
||||||
pixmap = self.scalePixmap(pixmap)
|
|
||||||
return pixmap.size()
|
|
||||||
else:
|
|
||||||
return QSize(100, 75)
|
|
||||||
|
|
||||||
def createEditor(self, parent, option, index) -> QWidget:
|
|
||||||
pixmap = self.getPixmap(index)
|
|
||||||
if isinstance(pixmap, QPixmap):
|
|
||||||
label = QLabel(parent)
|
|
||||||
label.setWindowFlags(Qt.WindowType.Window)
|
|
||||||
label.setWindowFlag(Qt.WindowType.WindowMinimizeButtonHint, False)
|
|
||||||
label.setWindowFlag(Qt.WindowType.WindowMaximizeButtonHint, False)
|
|
||||||
label.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, True)
|
|
||||||
label.setWindowTitle(QFileInfo(self.getImagePath(index)).fileName())
|
|
||||||
pixmap = pixmap.scaled(
|
|
||||||
800,
|
|
||||||
800,
|
|
||||||
Qt.AspectRatioMode.KeepAspectRatio,
|
|
||||||
Qt.TransformationMode.SmoothTransformation,
|
|
||||||
)
|
|
||||||
label.setMinimumSize(pixmap.size())
|
|
||||||
label.setPixmap(pixmap)
|
|
||||||
label.move(parent.mapToGlobal(parent.pos()))
|
|
||||||
return label
|
|
||||||
|
|
||||||
def setModelData(self, *args):
|
|
||||||
...
|
|
||||||
|
|
||||||
def updateEditorGeometry(self, *args):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class TableChartDelegate(ChartDelegate):
|
|
||||||
def getChart(self, index: QModelIndex) -> Chart | None:
|
|
||||||
return index.data(OcrQueueModel.ChartRole)
|
|
||||||
|
|
||||||
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
|
||||||
return isinstance(
|
|
||||||
index.data(OcrQueueModel.RecognizeResultRole), RecognizeResult
|
|
||||||
)
|
|
||||||
|
|
||||||
def setModelData(self, editor, model: OcrQueueTableProxyModel, index):
|
|
||||||
if editor.validate():
|
|
||||||
model.setData(index, editor.value(), OcrQueueModel.ChartRole)
|
|
||||||
|
|
||||||
|
|
||||||
class TableScoreDelegate(ScoreDelegate):
|
|
||||||
def getScoreInsert(self, index: QModelIndex):
|
|
||||||
return index.data(OcrQueueModel.ScoreInsertRole)
|
|
||||||
|
|
||||||
def getChart(self, index: QModelIndex):
|
|
||||||
return index.data(OcrQueueModel.ChartRole)
|
|
||||||
|
|
||||||
def getScoreValidateOk(self, index: QModelIndex):
|
|
||||||
return index.data(OcrQueueModel.ScoreValidateOkRole)
|
|
||||||
|
|
||||||
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
|
||||||
return isinstance(
|
|
||||||
index.data(OcrQueueModel.RecognizeResultRole), RecognizeResult
|
|
||||||
)
|
|
||||||
|
|
||||||
# def createEditor(self, parent, option, index):
|
|
||||||
# editor = super().createEditor(parent, option, index)
|
|
||||||
# editor.setManualHandleCommit(True)
|
|
||||||
# return editor
|
|
||||||
|
|
||||||
def setModelData(self, editor, model: OcrQueueTableProxyModel, index):
|
|
||||||
# userAcceptMessageBox = editor.triggerValidateMessageBox()
|
|
||||||
# if userAcceptMessageBox:
|
|
||||||
# model.setData(index, editor.value(), OcrQueueModel.ScoreInsertRole)
|
|
||||||
if super().confirmSetModelData(editor):
|
|
||||||
model.setData(index, editor.value(), OcrQueueModel.ScoreInsertRole)
|
|
||||||
|
@ -4,3 +4,4 @@ from .elidedLabel import ElidedLabel
|
|||||||
from .fileSelector import FileSelector
|
from .fileSelector import FileSelector
|
||||||
from .ratingClassRadioButton import RatingClassRadioButton
|
from .ratingClassRadioButton import RatingClassRadioButton
|
||||||
from .scoreEditor import ScoreEditor
|
from .scoreEditor import ScoreEditor
|
||||||
|
from .ocrQueue import OcrQueue
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from arcaea_offline_ocr.device import Device
|
from arcaea_offline_ocr.device.v1.definition import DeviceV1
|
||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt
|
||||||
from PySide6.QtWidgets import QComboBox
|
from PySide6.QtWidgets import QComboBox
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ class DevicesComboBox(QComboBox):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setItemDelegate(DescriptionDelegate(self))
|
self.setItemDelegate(DescriptionDelegate(self))
|
||||||
|
|
||||||
def setDevices(self, devices: list[Device]):
|
def setDevices(self, devices: list[DeviceV1]):
|
||||||
self.clear()
|
self.clear()
|
||||||
for device in devices:
|
for device in devices:
|
||||||
self.addItem(f"{device.name} ({device.uuid})", device)
|
self.addItem(f"{device.name} ({device.uuid})", device)
|
||||||
|
133
ui/implements/components/ocrQueue.py
Normal file
133
ui/implements/components/ocrQueue.py
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt, QTimer, Slot
|
||||||
|
from PySide6.QtGui import QColor, QPalette
|
||||||
|
from PySide6.QtWidgets import QWidget
|
||||||
|
|
||||||
|
from ui.designer.components.ocrQueue_ui import Ui_OcrQueue
|
||||||
|
from ui.extends.components.ocrQueue import (
|
||||||
|
OcrChartDelegate,
|
||||||
|
OcrImageDelegate,
|
||||||
|
OcrQueueModel,
|
||||||
|
OcrQueueTableProxyModel,
|
||||||
|
OcrScoreDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class OcrQueue(Ui_OcrQueue, QWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setupUi(self)
|
||||||
|
self.__model: Optional[OcrQueueModel] = None
|
||||||
|
self.__tableProxyModel: Optional[OcrQueueTableProxyModel] = None
|
||||||
|
|
||||||
|
self.__firstResizeDone = False
|
||||||
|
self.resizeTimer = QTimer(self)
|
||||||
|
self.resizeTimer.timeout.connect(self.tableView.resizeRowsToContents)
|
||||||
|
self.resizeTimer.timeout.connect(self.tableView.resizeColumnsToContents)
|
||||||
|
|
||||||
|
self.tableView.setItemDelegateForColumn(1, OcrImageDelegate(self.tableView))
|
||||||
|
self.tableView.setItemDelegateForColumn(2, OcrChartDelegate(self.tableView))
|
||||||
|
self.tableView.setItemDelegateForColumn(3, OcrScoreDelegate(self.tableView))
|
||||||
|
|
||||||
|
tableViewPalette = QPalette(self.tableView.palette())
|
||||||
|
highlightColor = QColor(tableViewPalette.color(QPalette.ColorRole.Highlight))
|
||||||
|
highlightColor.setAlpha(25)
|
||||||
|
tableViewPalette.setColor(QPalette.ColorRole.Highlight, highlightColor)
|
||||||
|
self.tableView.setPalette(tableViewPalette)
|
||||||
|
|
||||||
|
def model(self):
|
||||||
|
return self.__model
|
||||||
|
|
||||||
|
def setModel(self, model: OcrQueueModel):
|
||||||
|
model.dataChanged.connect(self.resizeViewWhenDataChanged)
|
||||||
|
model.started.connect(self.ocrStarted)
|
||||||
|
model.progress.connect(self.ocrProgress)
|
||||||
|
model.finished.connect(self.ocrFinished)
|
||||||
|
model.rowsInserted.connect(self.updateProgressBarMaximum)
|
||||||
|
model.rowsRemoved.connect(self.updateProgressBarMaximum)
|
||||||
|
model.modelReset.connect(self.modelReseted)
|
||||||
|
proxyModel = OcrQueueTableProxyModel(self)
|
||||||
|
proxyModel.setSourceModel(model)
|
||||||
|
self.tableView.setModel(proxyModel)
|
||||||
|
|
||||||
|
if self.__model:
|
||||||
|
self.__model.dataChanged.disconnect(self.resizeViewWhenDataChanged)
|
||||||
|
self.__model.started.disconnect(self.ocrStarted)
|
||||||
|
self.__model.progress.disconnect(self.ocrProgress)
|
||||||
|
self.__model.finished.disconnect(self.ocrFinished)
|
||||||
|
self.__model.rowsInserted.disconnect(self.updateProgressBarMaximum)
|
||||||
|
self.__model.rowsRemoved.disconnect(self.updateProgressBarMaximum)
|
||||||
|
self.__model.modelReset.disconnect(self.modelReseted)
|
||||||
|
if self.__tableProxyModel:
|
||||||
|
self.__tableProxyModel.deleteLater()
|
||||||
|
|
||||||
|
self.__model = model
|
||||||
|
self.__tableProxyModel = proxyModel
|
||||||
|
|
||||||
|
def tableProxyModel(self):
|
||||||
|
return self.__tableProxyModel
|
||||||
|
|
||||||
|
def setOcrButtonsEnabled(self, __bool: bool):
|
||||||
|
self.ocr_addImageButton.setEnabled(__bool)
|
||||||
|
self.ocr_removeSelectedButton.setEnabled(__bool)
|
||||||
|
self.ocr_removeAllButton.setEnabled(__bool)
|
||||||
|
self.ocr_startButton.setEnabled(__bool)
|
||||||
|
self.ocr_acceptSelectedButton.setEnabled(__bool)
|
||||||
|
self.ocr_acceptAllButton.setEnabled(__bool)
|
||||||
|
self.ocr_ignoreValidateCheckBox.setEnabled(__bool)
|
||||||
|
|
||||||
|
def resizeTableView(self):
|
||||||
|
self.tableView.resizeRowsToContents()
|
||||||
|
self.tableView.resizeColumnsToContents()
|
||||||
|
|
||||||
|
def resizeViewWhenDataChanged(self):
|
||||||
|
if not self.__firstResizeDone:
|
||||||
|
self.resizeTableView()
|
||||||
|
self.__firstResizeDone = True
|
||||||
|
|
||||||
|
def ocrStarted(self):
|
||||||
|
self.setOcrButtonsEnabled(False)
|
||||||
|
|
||||||
|
def updateProgressBarMaximum(self):
|
||||||
|
self.progressBar.setMaximum(self.model().rowCount())
|
||||||
|
|
||||||
|
@Slot(int)
|
||||||
|
def ocrProgress(self, progress: int):
|
||||||
|
self.progressBar.setValue(progress)
|
||||||
|
|
||||||
|
def ocrFinished(self):
|
||||||
|
self.resizeTableView()
|
||||||
|
self.setOcrButtonsEnabled(True)
|
||||||
|
|
||||||
|
def modelReseted(self):
|
||||||
|
self.progressBar.setMaximum(0)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def on_ocr_removeSelectedButton_clicked(self):
|
||||||
|
if self.model():
|
||||||
|
rows = [
|
||||||
|
modelIndex.row()
|
||||||
|
for modelIndex in self.tableView.selectionModel().selectedRows(0)
|
||||||
|
]
|
||||||
|
self.model().removeItems(rows)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def on_ocr_acceptSelectedButton_clicked(self):
|
||||||
|
if self.model():
|
||||||
|
ignoreValidate = (
|
||||||
|
self.ocr_ignoreValidateCheckBox.checkState() == Qt.CheckState.Checked
|
||||||
|
)
|
||||||
|
rows = [
|
||||||
|
modelIndex.row()
|
||||||
|
for modelIndex in self.tableView.selectionModel().selectedRows(0)
|
||||||
|
]
|
||||||
|
self.model().acceptItems(rows, ignoreValidate)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def on_ocr_acceptAllButton_clicked(self):
|
||||||
|
if self.model():
|
||||||
|
ignoreValidate = (
|
||||||
|
self.ocr_ignoreValidateCheckBox.checkState() == Qt.CheckState.Checked
|
||||||
|
)
|
||||||
|
self.model().acceptAllItems(ignoreValidate)
|
@ -1,24 +1,21 @@
|
|||||||
import pytesseract
|
import pytesseract
|
||||||
from arcaea_offline_ocr_device_creation_wizard.implements.wizard import Wizard
|
|
||||||
|
# from arcaea_offline_ocr_device_creation_wizard.implements.wizard import Wizard
|
||||||
from PySide6.QtCore import QModelIndex, Qt, Slot
|
from PySide6.QtCore import QModelIndex, Qt, Slot
|
||||||
from PySide6.QtGui import QColor, QPalette
|
from PySide6.QtGui import QColor
|
||||||
from PySide6.QtWidgets import QFileDialog, QWidget
|
from PySide6.QtWidgets import QFileDialog, QHeaderView, QWidget
|
||||||
|
|
||||||
from ui.designer.tabs.tabOcr_ui import Ui_TabOcr
|
from ui.designer.tabs.tabOcr_ui import Ui_TabOcr
|
||||||
|
from ui.extends.components.ocrQueue import OcrQueueModel
|
||||||
from ui.extends.settings import Settings
|
from ui.extends.settings import Settings
|
||||||
from ui.extends.tabs.tabOcr import (
|
from ui.extends.tabs.tabOcr import TabDeviceV2OcrRunnable, ScoreInsertConverter
|
||||||
ImageDelegate,
|
|
||||||
OcrQueueModel,
|
|
||||||
OcrQueueTableProxyModel,
|
|
||||||
TableChartDelegate,
|
|
||||||
TableScoreDelegate,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TabOcr(Ui_TabOcr, QWidget):
|
class TabOcr(Ui_TabOcr, QWidget):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
self.openWizardButton.setEnabled(False)
|
||||||
|
|
||||||
self.deviceFileSelector.filesSelected.connect(self.deviceFileSelected)
|
self.deviceFileSelector.filesSelected.connect(self.deviceFileSelected)
|
||||||
self.tesseractFileSelector.filesSelected.connect(
|
self.tesseractFileSelector.filesSelected.connect(
|
||||||
@ -31,36 +28,14 @@ class TabOcr(Ui_TabOcr, QWidget):
|
|||||||
self.deviceComboBox.selectDevice(settings.deviceUuid())
|
self.deviceComboBox.selectDevice(settings.deviceUuid())
|
||||||
|
|
||||||
self.ocrQueueModel = OcrQueueModel(self)
|
self.ocrQueueModel = OcrQueueModel(self)
|
||||||
self.ocrQueueModel.dataChanged.connect(self.resizeViewWhenScoreChanged)
|
self.ocrQueue.setModel(self.ocrQueueModel)
|
||||||
self.ocrQueueModel.started.connect(self.ocrStarted)
|
self.ocrQueueProxyModel = self.ocrQueue.tableProxyModel()
|
||||||
self.ocrQueueModel.finished.connect(self.ocrFinished)
|
|
||||||
self.ocrQueueProxyModel = OcrQueueTableProxyModel(self)
|
|
||||||
self.ocrQueueProxyModel.setSourceModel(self.ocrQueueModel)
|
|
||||||
|
|
||||||
self.tableView.setModel(self.ocrQueueProxyModel)
|
|
||||||
self.tableView.setItemDelegateForColumn(1, ImageDelegate(self.tableView))
|
|
||||||
self.tableView.setItemDelegateForColumn(2, TableChartDelegate(self.tableView))
|
|
||||||
self.tableView.setItemDelegateForColumn(3, TableScoreDelegate(self.tableView))
|
|
||||||
|
|
||||||
tableViewPalette = QPalette(self.tableView.palette())
|
|
||||||
highlightColor = QColor(tableViewPalette.color(QPalette.ColorRole.Highlight))
|
|
||||||
highlightColor.setAlpha(25)
|
|
||||||
tableViewPalette.setColor(QPalette.ColorRole.Highlight, highlightColor)
|
|
||||||
self.tableView.setPalette(tableViewPalette)
|
|
||||||
|
|
||||||
@Slot(QModelIndex, QModelIndex, list)
|
|
||||||
def resizeViewWhenScoreChanged(
|
|
||||||
self, topleft: QModelIndex, bottomRight: QModelIndex, roles: list[int]
|
|
||||||
):
|
|
||||||
if OcrQueueModel.ScoreInsertRole in roles:
|
|
||||||
rows = [*range(topleft.row(), bottomRight.row() + 1)]
|
|
||||||
[self.tableView.resizeRowToContents(row) for row in rows]
|
|
||||||
self.tableView.resizeColumnsToContents()
|
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def on_openWizardButton_clicked(self):
|
def on_openWizardButton_clicked(self):
|
||||||
wizard = Wizard(self)
|
# wizard = Wizard(self)
|
||||||
wizard.open()
|
# wizard.open()
|
||||||
|
pass
|
||||||
|
|
||||||
def deviceFileSelected(self):
|
def deviceFileSelected(self):
|
||||||
selectedFiles = self.deviceFileSelector.selectedFiles()
|
selectedFiles = self.deviceFileSelector.selectedFiles()
|
||||||
@ -73,15 +48,6 @@ class TabOcr(Ui_TabOcr, QWidget):
|
|||||||
if selectedFiles:
|
if selectedFiles:
|
||||||
pytesseract.pytesseract.tesseract_cmd = selectedFiles[0]
|
pytesseract.pytesseract.tesseract_cmd = selectedFiles[0]
|
||||||
|
|
||||||
def setOcrButtonsEnabled(self, __bool: bool):
|
|
||||||
self.ocr_addImageButton.setEnabled(__bool)
|
|
||||||
self.ocr_removeSelectedButton.setEnabled(__bool)
|
|
||||||
self.ocr_removeAllButton.setEnabled(__bool)
|
|
||||||
self.ocr_startButton.setEnabled(__bool)
|
|
||||||
self.ocr_acceptSelectedButton.setEnabled(__bool)
|
|
||||||
self.ocr_acceptAllButton.setEnabled(__bool)
|
|
||||||
self.ocr_ignoreValidateCheckBox.setEnabled(__bool)
|
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def on_ocr_addImageButton_clicked(self):
|
def on_ocr_addImageButton_clicked(self):
|
||||||
files, _filter = QFileDialog.getOpenFileNames(
|
files, _filter = QFileDialog.getOpenFileNames(
|
||||||
@ -89,45 +55,24 @@ class TabOcr(Ui_TabOcr, QWidget):
|
|||||||
)
|
)
|
||||||
for file in files:
|
for file in files:
|
||||||
self.ocrQueueModel.addItem(file)
|
self.ocrQueueModel.addItem(file)
|
||||||
self.tableView.resizeRowsToContents()
|
self.ocrQueue.resizeTableView()
|
||||||
self.tableView.resizeColumnsToContents()
|
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def on_ocr_startButton_clicked(self):
|
def on_ocr_startButton_clicked(self):
|
||||||
self.ocrQueueModel.startQueue(self.deviceComboBox.currentData())
|
for row in range(self.ocrQueueModel.rowCount()):
|
||||||
|
index = self.ocrQueueModel.index(row, 0)
|
||||||
def ocrStarted(self):
|
imagePath = index.data(OcrQueueModel.ImagePathRole)
|
||||||
self.setOcrButtonsEnabled(False)
|
runnable = TabDeviceV2OcrRunnable(
|
||||||
|
imagePath, self.deviceComboBox.currentData(), self.knn, self.siftDb
|
||||||
def ocrFinished(self):
|
)
|
||||||
self.setOcrButtonsEnabled(True)
|
self.ocrQueueModel.setData(index, runnable, OcrQueueModel.OcrRunnableRole)
|
||||||
|
self.ocrQueueModel.setData(
|
||||||
@Slot()
|
index,
|
||||||
def on_ocr_removeSelectedButton_clicked(self):
|
ScoreInsertConverter.deviceV2,
|
||||||
rows = [
|
OcrQueueModel.ProcessOcrResultFuncRole,
|
||||||
modelIndex.row()
|
)
|
||||||
for modelIndex in self.tableView.selectionModel().selectedRows(0)
|
self.ocrQueueModel.startQueue()
|
||||||
]
|
|
||||||
self.ocrQueueModel.removeItems(rows)
|
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def on_ocr_removeAllButton_clicked(self):
|
def on_ocr_removeAllButton_clicked(self):
|
||||||
self.ocrQueueModel.clear()
|
self.ocrQueueModel.clear()
|
||||||
|
|
||||||
@Slot()
|
|
||||||
def on_ocr_acceptSelectedButton_clicked(self):
|
|
||||||
ignoreValidate = (
|
|
||||||
self.ocr_ignoreValidateCheckBox.checkState() == Qt.CheckState.Checked
|
|
||||||
)
|
|
||||||
rows = [
|
|
||||||
modelIndex.row()
|
|
||||||
for modelIndex in self.tableView.selectionModel().selectedRows(0)
|
|
||||||
]
|
|
||||||
self.ocrQueueModel.acceptItems(rows, ignoreValidate)
|
|
||||||
|
|
||||||
@Slot()
|
|
||||||
def on_ocr_acceptAllButton_clicked(self):
|
|
||||||
ignoreValidate = (
|
|
||||||
self.ocr_ignoreValidateCheckBox.checkState() == Qt.CheckState.Checked
|
|
||||||
)
|
|
||||||
self.ocrQueueModel.acceptAllItems(ignoreValidate)
|
|
||||||
|
Reference in New Issue
Block a user