mirror of
https://github.com/283375/arcaea-offline-pyside-ui.git
synced 2025-04-21 10:10:17 +00:00
wip: b30 table viewer
This commit is contained in:
parent
70e9542422
commit
3d1012d782
139
ui/extends/shared/models/tables/b30.py
Normal file
139
ui/extends/shared/models/tables/b30.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
from arcaea_offline.models import Chart, Score
|
||||||
|
from PySide6.QtCore import QCoreApplication, QModelIndex, QSortFilterProxyModel, Qt
|
||||||
|
|
||||||
|
from .base import DbTableModel
|
||||||
|
|
||||||
|
|
||||||
|
class DbB30TableModel(DbTableModel):
|
||||||
|
IdRole = Qt.ItemDataRole.UserRole + 10
|
||||||
|
ChartRole = Qt.ItemDataRole.UserRole + 11
|
||||||
|
ScoreRole = Qt.ItemDataRole.UserRole + 12
|
||||||
|
PttRole = Qt.ItemDataRole.UserRole + 13
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.__items = []
|
||||||
|
|
||||||
|
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"),
|
||||||
|
# fmt: on
|
||||||
|
]
|
||||||
|
|
||||||
|
def syncDb(self):
|
||||||
|
self.__items.clear()
|
||||||
|
|
||||||
|
results = self._db.conn.execute(
|
||||||
|
'SELECT * FROM calculated ORDER BY "potential" DESC LIMIT 40'
|
||||||
|
).fetchall()
|
||||||
|
|
||||||
|
songIds = [r[0] for r in results]
|
||||||
|
ptts = [r[-1] for r in results]
|
||||||
|
|
||||||
|
for scoreId, ptt in zip(songIds, ptts):
|
||||||
|
score = Score.from_db_row(self._db.get_scores(score_id=scoreId)[0])
|
||||||
|
chart = Chart.from_db_row(
|
||||||
|
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.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)
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if index.isValid() and self.checkIndex(index):
|
||||||
|
if index.column() == 0 and role in [
|
||||||
|
Qt.ItemDataRole.DisplayRole,
|
||||||
|
self.IdRole,
|
||||||
|
]:
|
||||||
|
return self.__items[index.row()][self.IdRole]
|
||||||
|
elif index.column() == 1 and role == self.ChartRole:
|
||||||
|
return self.__items[index.row()][self.ChartRole]
|
||||||
|
elif index.column() == 2 and role in [self.ChartRole, self.ScoreRole]:
|
||||||
|
return self.__items[index.row()][role]
|
||||||
|
elif index.column() == 3:
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole:
|
||||||
|
return f"{self.__items[index.row()][self.PttRole]:.3f}"
|
||||||
|
elif role == self.PttRole:
|
||||||
|
return self.__items[index.row()][self.PttRole]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def setData(self, index, value, role):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def flags(self, index) -> Qt.ItemFlag:
|
||||||
|
flags = super().flags(index)
|
||||||
|
flags &= ~(Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable)
|
||||||
|
return flags
|
||||||
|
|
||||||
|
def _removeRow(self, row: int, syncDb: bool = True):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def removeRow(self, row: int, parent=...):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def removeRows(self, row: int, count: int, parent=...):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def removeRowList(self, rowList: list[int]):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class DbB30TableSortFilterProxyModel(QSortFilterProxyModel):
|
||||||
|
Sort_C2_ScoreRole = Qt.ItemDataRole.UserRole + 75
|
||||||
|
Sort_C2_TimeRole = Qt.ItemDataRole.UserRole + 76
|
||||||
|
|
||||||
|
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
|
||||||
|
# always show not sorted row sequence
|
||||||
|
if (
|
||||||
|
orientation != Qt.Orientation.Vertical
|
||||||
|
or role != Qt.ItemDataRole.DisplayRole
|
||||||
|
):
|
||||||
|
return super().headerData(section, orientation, role)
|
||||||
|
return section + 1
|
||||||
|
|
||||||
|
def lessThan(self, source_left, source_right) -> bool:
|
||||||
|
if source_left.column() != source_right.column():
|
||||||
|
return
|
||||||
|
|
||||||
|
column = source_left.column()
|
||||||
|
if column == 0:
|
||||||
|
return source_left.data(DbB30TableModel.IdRole) < source_right.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):
|
||||||
|
if self.sortRole() == self.Sort_C2_ScoreRole:
|
||||||
|
return score_left.score < score_right.score
|
||||||
|
elif self.sortRole() == self.Sort_C2_TimeRole:
|
||||||
|
return score_left.time < score_right.time
|
||||||
|
elif column == 3:
|
||||||
|
return source_left.data(DbB30TableModel.PttRole) < source_right.data(
|
||||||
|
DbB30TableModel.PttRole
|
||||||
|
)
|
||||||
|
return super().lessThan(source_left, source_right)
|
100
ui/implements/tabs/tabDb/tabDb_B30TableViewer.py
Normal file
100
ui/implements/tabs/tabDb/tabDb_B30TableViewer.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
from arcaea_offline.models import ScoreInsert
|
||||||
|
from PySide6.QtCore import QModelIndex, Qt, Slot
|
||||||
|
from PySide6.QtGui import QColor, QPalette
|
||||||
|
from PySide6.QtWidgets import QMessageBox
|
||||||
|
|
||||||
|
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
|
||||||
|
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
|
||||||
|
from ui.extends.shared.models.tables.b30 import (
|
||||||
|
DbB30TableModel,
|
||||||
|
DbB30TableSortFilterProxyModel,
|
||||||
|
)
|
||||||
|
from ui.implements.components.dbTableViewer import DbTableViewer
|
||||||
|
|
||||||
|
|
||||||
|
class TableChartDelegate(ChartDelegate):
|
||||||
|
def getChart(self, index):
|
||||||
|
return index.data(DbB30TableModel.ChartRole)
|
||||||
|
|
||||||
|
|
||||||
|
class TableScoreDelegate(ScoreDelegate):
|
||||||
|
def getChart(self, index):
|
||||||
|
return index.data(DbB30TableModel.ChartRole)
|
||||||
|
|
||||||
|
def getScoreInsert(self, index: QModelIndex) -> ScoreInsert | None:
|
||||||
|
return super().getScoreInsert(index)
|
||||||
|
|
||||||
|
def getScore(self, index):
|
||||||
|
return index.data(DbB30TableModel.ScoreRole)
|
||||||
|
|
||||||
|
def setModelData(self, editor, model, index):
|
||||||
|
QMessageBox.information(self, None, "Cannot edit read only table.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class DbB30TableViewer(DbTableViewer):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.tableView.verticalHeader().setVisible(True)
|
||||||
|
|
||||||
|
self.tableModel = DbB30TableModel(self)
|
||||||
|
self.tableProxyModel = DbB30TableSortFilterProxyModel(self)
|
||||||
|
self.tableProxyModel.setSourceModel(self.tableModel)
|
||||||
|
self.tableView.setModel(self.tableProxyModel)
|
||||||
|
self.tableView.setItemDelegateForColumn(1, TableChartDelegate(self.tableView))
|
||||||
|
self.tableView.setItemDelegateForColumn(2, 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)
|
||||||
|
self.tableModel.dataChanged.connect(self.resizeTableView)
|
||||||
|
|
||||||
|
self.fillSortComboBox()
|
||||||
|
|
||||||
|
def fillSortComboBox(self):
|
||||||
|
self.sort_comboBox.addItem("ID", [0, 1])
|
||||||
|
self.sort_comboBox.addItem(
|
||||||
|
"Score", [3, DbB30TableSortFilterProxyModel.Sort_C2_ScoreRole]
|
||||||
|
)
|
||||||
|
self.sort_comboBox.addItem(
|
||||||
|
"Time", [3, DbB30TableSortFilterProxyModel.Sort_C2_TimeRole]
|
||||||
|
)
|
||||||
|
self.sort_comboBox.addItem("Potential", [3, 1])
|
||||||
|
self.sort_comboBox.setCurrentIndex(0)
|
||||||
|
self.on_sort_comboBox_activated()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def resizeTableView(self):
|
||||||
|
self.tableView.resizeRowsToContents()
|
||||||
|
self.tableView.resizeColumnsToContents()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def on_sort_comboBox_activated(self):
|
||||||
|
self.sortProxyModel()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def on_sort_descendingCheckBox_toggled(self):
|
||||||
|
self.sortProxyModel()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def sortProxyModel(self):
|
||||||
|
if self.sort_comboBox.currentIndex() > -1:
|
||||||
|
column, role = self.sort_comboBox.currentData()
|
||||||
|
self.tableProxyModel.setSortRole(role)
|
||||||
|
self.tableProxyModel.sort(
|
||||||
|
column,
|
||||||
|
Qt.SortOrder.DescendingOrder
|
||||||
|
if self.sort_descendingCheckBox.isChecked()
|
||||||
|
else Qt.SortOrder.AscendingOrder,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def on_action_removeSelectedButton_clicked(self):
|
||||||
|
QMessageBox.information(self, None, "Cannot edit read only table.")
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def on_refreshButton_clicked(self):
|
||||||
|
self.tableModel.syncDb()
|
||||||
|
self.resizeTableView()
|
@ -2,6 +2,7 @@ from PySide6.QtCore import QCoreApplication
|
|||||||
from PySide6.QtWidgets import QWidget
|
from PySide6.QtWidgets import QWidget
|
||||||
|
|
||||||
from ui.designer.tabs.tabDbEntry_ui import Ui_TabDbEntry
|
from ui.designer.tabs.tabDbEntry_ui import Ui_TabDbEntry
|
||||||
|
from ui.implements.tabs.tabDb.tabDb_B30TableViewer import DbB30TableViewer
|
||||||
from ui.implements.tabs.tabDb.tabDb_ScoreTableViewer import DbScoreTableViewer
|
from ui.implements.tabs.tabDb.tabDb_ScoreTableViewer import DbScoreTableViewer
|
||||||
|
|
||||||
|
|
||||||
@ -14,3 +15,7 @@ class TabDbEntry(Ui_TabDbEntry, QWidget):
|
|||||||
DbScoreTableViewer(self),
|
DbScoreTableViewer(self),
|
||||||
QCoreApplication.translate("TabDbEntry", "tab.scoreTableViewer"),
|
QCoreApplication.translate("TabDbEntry", "tab.scoreTableViewer"),
|
||||||
)
|
)
|
||||||
|
self.tabWidget.addTab(
|
||||||
|
DbB30TableViewer(self),
|
||||||
|
QCoreApplication.translate("TabDbEntry", "tab.b30TableViewer"),
|
||||||
|
)
|
||||||
|
@ -12,8 +12,8 @@ from PySide6.QtWidgets import QWidget
|
|||||||
|
|
||||||
from ui.designer.tabs.tabOcr.tabOcr_B30_ui import Ui_TabOcr_B30
|
from ui.designer.tabs.tabOcr.tabOcr_B30_ui import Ui_TabOcr_B30
|
||||||
from ui.extends.components.ocrQueue import OcrQueueModel
|
from ui.extends.components.ocrQueue import OcrQueueModel
|
||||||
from ui.extends.shared.settings import Settings
|
|
||||||
from ui.extends.shared.cv2_utils import cv2BgrMatToQImage, qImageToCvMatBgr
|
from ui.extends.shared.cv2_utils import cv2BgrMatToQImage, qImageToCvMatBgr
|
||||||
|
from ui.extends.shared.settings import Settings
|
||||||
from ui.extends.tabs.tabOcr.tabOcr_B30 import (
|
from ui.extends.tabs.tabOcr.tabOcr_B30 import (
|
||||||
ChieriV4OcrRunnable,
|
ChieriV4OcrRunnable,
|
||||||
b30ResultToScoreInsert,
|
b30ResultToScoreInsert,
|
||||||
|
@ -49,6 +49,34 @@
|
|||||||
<translation>Reset</translation>
|
<translation>Reset</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>DB30TableModel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="21"/>
|
||||||
|
<source>horizontalHeader.tableId</source>
|
||||||
|
<translation>No.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="22"/>
|
||||||
|
<source>horizontalHeader.id</source>
|
||||||
|
<translation>ID</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="23"/>
|
||||||
|
<source>horizontalHeader.chart</source>
|
||||||
|
<translation>Chart</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="24"/>
|
||||||
|
<source>horizontalHeader.score</source>
|
||||||
|
<translation>Score</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="25"/>
|
||||||
|
<source>horizontalHeader.potential</source>
|
||||||
|
<translation>Potential</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>DatabaseChecker</name>
|
<name>DatabaseChecker</name>
|
||||||
<message>
|
<message>
|
||||||
@ -260,22 +288,22 @@ validation</translation>
|
|||||||
<context>
|
<context>
|
||||||
<name>OcrTableModel</name>
|
<name>OcrTableModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../extends/components/ocrQueue/__init__.py" line="313"/>
|
<location filename="../../extends/components/ocrQueue.py" line="313"/>
|
||||||
<source>horizontalHeader.title.select</source>
|
<source>horizontalHeader.title.select</source>
|
||||||
<translation>Select</translation>
|
<translation>Select</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../extends/components/ocrQueue/__init__.py" line="314"/>
|
<location filename="../../extends/components/ocrQueue.py" line="314"/>
|
||||||
<source>horizontalHeader.title.imagePreview</source>
|
<source>horizontalHeader.title.imagePreview</source>
|
||||||
<translation>Image Preview</translation>
|
<translation>Image Preview</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../extends/components/ocrQueue/__init__.py" line="315"/>
|
<location filename="../../extends/components/ocrQueue.py" line="315"/>
|
||||||
<source>horizontalHeader.title.chart</source>
|
<source>horizontalHeader.title.chart</source>
|
||||||
<translation>Chart</translation>
|
<translation>Chart</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../extends/components/ocrQueue/__init__.py" line="316"/>
|
<location filename="../../extends/components/ocrQueue.py" line="316"/>
|
||||||
<source>horizontalHeader.title.score</source>
|
<source>horizontalHeader.title.score</source>
|
||||||
<translation>Score</translation>
|
<translation>Score</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -412,10 +440,15 @@ validation</translation>
|
|||||||
<translation>Manage</translation>
|
<translation>Manage</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/tabs/tabDbEntry.py" line="15"/>
|
<location filename="../../implements/tabs/tabDbEntry.py" line="16"/>
|
||||||
<source>tab.scoreTableViewer</source>
|
<source>tab.scoreTableViewer</source>
|
||||||
<translation>TABLE [Score]</translation>
|
<translation>TABLE [Score]</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../implements/tabs/tabDbEntry.py" line="20"/>
|
||||||
|
<source>tab.b30TableViewer</source>
|
||||||
|
<translation>TABLE [B30]</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>TabDb_Manage</name>
|
<name>TabDb_Manage</name>
|
||||||
|
@ -49,6 +49,34 @@
|
|||||||
<translation>重置</translation>
|
<translation>重置</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>DB30TableModel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="21"/>
|
||||||
|
<source>horizontalHeader.tableId</source>
|
||||||
|
<translation>序号</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="22"/>
|
||||||
|
<source>horizontalHeader.id</source>
|
||||||
|
<translation>ID</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="23"/>
|
||||||
|
<source>horizontalHeader.chart</source>
|
||||||
|
<translation>谱面</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="24"/>
|
||||||
|
<source>horizontalHeader.score</source>
|
||||||
|
<translation>分数</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../extends/shared/models/tables/b30.py" line="25"/>
|
||||||
|
<source>horizontalHeader.potential</source>
|
||||||
|
<translation>单曲 PTT</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>DatabaseChecker</name>
|
<name>DatabaseChecker</name>
|
||||||
<message>
|
<message>
|
||||||
@ -259,22 +287,22 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>OcrTableModel</name>
|
<name>OcrTableModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../extends/components/ocrQueue/__init__.py" line="313"/>
|
<location filename="../../extends/components/ocrQueue.py" line="313"/>
|
||||||
<source>horizontalHeader.title.select</source>
|
<source>horizontalHeader.title.select</source>
|
||||||
<translation>选择</translation>
|
<translation>选择</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../extends/components/ocrQueue/__init__.py" line="314"/>
|
<location filename="../../extends/components/ocrQueue.py" line="314"/>
|
||||||
<source>horizontalHeader.title.imagePreview</source>
|
<source>horizontalHeader.title.imagePreview</source>
|
||||||
<translation>图像预览</translation>
|
<translation>图像预览</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../extends/components/ocrQueue/__init__.py" line="315"/>
|
<location filename="../../extends/components/ocrQueue.py" line="315"/>
|
||||||
<source>horizontalHeader.title.chart</source>
|
<source>horizontalHeader.title.chart</source>
|
||||||
<translation>谱面</translation>
|
<translation>谱面</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../extends/components/ocrQueue/__init__.py" line="316"/>
|
<location filename="../../extends/components/ocrQueue.py" line="316"/>
|
||||||
<source>horizontalHeader.title.score</source>
|
<source>horizontalHeader.title.score</source>
|
||||||
<translation>分数</translation>
|
<translation>分数</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -411,10 +439,15 @@
|
|||||||
<translation>管理</translation>
|
<translation>管理</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/tabs/tabDbEntry.py" line="15"/>
|
<location filename="../../implements/tabs/tabDbEntry.py" line="16"/>
|
||||||
<source>tab.scoreTableViewer</source>
|
<source>tab.scoreTableViewer</source>
|
||||||
<translation>表 [分数]</translation>
|
<translation>表 [分数]</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../implements/tabs/tabDbEntry.py" line="20"/>
|
||||||
|
<source>tab.b30TableViewer</source>
|
||||||
|
<translation>表 [B30]</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>TabDb_Manage</name>
|
<name>TabDb_Manage</name>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user