Version 3.2.0: fast lists with loading spinners, names from the game files, INT docs and screenshots, cleanup
This commit is contained in:
@@ -4,7 +4,7 @@ One TextPanel per section: filters + table on top, the editor of the selected te
|
||||
through Workspace.texts (ackit/texts.py): subtitles in place into every copy (limited to the original's
|
||||
length), menu texts into the localization files. Revert per text or all; changed-underneath warnings.
|
||||
"""
|
||||
from PySide6.QtCore import QAbstractTableModel, QModelIndex, QSortFilterProxyModel, Qt, QTimer, Signal
|
||||
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, QTimer, Signal
|
||||
from PySide6.QtWidgets import (QAbstractItemView, QCheckBox, QComboBox, QDialog, QDialogButtonBox, QFormLayout,
|
||||
QHBoxLayout, QHeaderView, QLabel, QLineEdit, QPushButton, QSplitter, QTableView,
|
||||
QVBoxLayout, QWidget)
|
||||
@@ -12,6 +12,8 @@ from PySide6.QtWidgets import (QAbstractItemView, QCheckBox, QComboBox, QDialog,
|
||||
from ackit import subtitles
|
||||
from ackit.texts import CHANGED, FOREIGN, LOST, MODIFIED, ORIGINAL, TextConflictError
|
||||
from . import icons
|
||||
from .models import RowView
|
||||
from .spinner import BusyOverlay
|
||||
|
||||
ANY = "Any"
|
||||
STATE_TEXT = {ORIGINAL: "", MODIFIED: "modified", LOST: "lost", CHANGED: "changed outside", FOREIGN: "not original"}
|
||||
@@ -74,20 +76,24 @@ class TextModel(QAbstractTableModel):
|
||||
return None
|
||||
|
||||
|
||||
class TextFilter(QSortFilterProxyModel):
|
||||
class TextFilter(RowView):
|
||||
"""The text table's rows: search words, column filters, modified only; sorted case-insensitively."""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.words, self.col_filters, self.only_modified = [], {}, False
|
||||
self.setSortCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
|
||||
super().__init__(parent)
|
||||
|
||||
def refilter(self):
|
||||
if hasattr(self, "beginFilterChange"):
|
||||
self.beginFilterChange()
|
||||
self.endFilterChange(QSortFilterProxyModel.Direction.Rows)
|
||||
else:
|
||||
self.invalidateFilter()
|
||||
def source_len(self):
|
||||
return len(self.sourceModel().rows)
|
||||
|
||||
def filterAcceptsRow(self, row, parent):
|
||||
def sort_key(self, row, column):
|
||||
m = self.sourceModel()
|
||||
r = m.rows[row]
|
||||
n = len(r.cols)
|
||||
v = r.cols[column] if column < n else m.text_of(r) if column == n else ("modified" if r.key in m.modified else "")
|
||||
return v.lower() if isinstance(v, str) else v
|
||||
|
||||
def accepts(self, row):
|
||||
m = self.sourceModel()
|
||||
r = m.rows[row]
|
||||
if self.only_modified and r.key not in m.modified:
|
||||
@@ -101,7 +107,7 @@ class TextFilter(QSortFilterProxyModel):
|
||||
return True
|
||||
|
||||
def row_at(self, index):
|
||||
return self.sourceModel().rows[self.mapToSource(index).row()]
|
||||
return self.sourceModel().rows[self.rows[index.row()]]
|
||||
|
||||
|
||||
class FindReplaceDialog(QDialog):
|
||||
@@ -288,6 +294,9 @@ class TextPanel(QWidget):
|
||||
self.proxy.setSourceModel(self.model)
|
||||
self.table = QTableView()
|
||||
self.table.setModel(self.proxy)
|
||||
self.busy = BusyOverlay(self.table) # while the texts of a language load (background job)
|
||||
self._load_gen = 0
|
||||
self._pending_key = None
|
||||
self.table.setSortingEnabled(True)
|
||||
self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
@@ -367,9 +376,28 @@ class TextPanel(QWidget):
|
||||
self.lang = lang
|
||||
self.lbl_lang.setText("Language: %s" % lang if lang else "No %s in this language" % (
|
||||
"subtitles" if self.kind == "subs" else "menu text"))
|
||||
self._load_gen += 1
|
||||
gen = self._load_gen
|
||||
if not lang:
|
||||
self.busy.stop()
|
||||
self.model.reset([], {})
|
||||
return
|
||||
self.busy.start("Loading subtitles…" if self.kind == "subs" else "Loading menu text…")
|
||||
|
||||
def done(rows):
|
||||
if gen == self._load_gen: # a newer load replaces this one
|
||||
self.busy.stop()
|
||||
self._show_rows(rows)
|
||||
|
||||
def failed(e, tb):
|
||||
if gen == self._load_gen:
|
||||
self.busy.stop()
|
||||
self.message.emit("Could not load the texts: %s" % e)
|
||||
|
||||
self.win.runner.start(lambda job: self._rows(ws, lang), done, failed)
|
||||
|
||||
def _rows(self, ws, lang):
|
||||
"""The table rows of a language (runs as a background job)."""
|
||||
tx = ws.texts
|
||||
rows = []
|
||||
if self.kind == "subs":
|
||||
@@ -384,6 +412,9 @@ class TextPanel(QWidget):
|
||||
for e in tx.menu(lang):
|
||||
rows.append(Row("MENU:" + e.key, [e.file, e.section, e.name + ("#%d" % e.occurrence if e.occurrence > 1 else "")],
|
||||
self._menu_original(e)))
|
||||
return rows
|
||||
|
||||
def _show_rows(self, rows):
|
||||
self.model.reset(rows, self._modified())
|
||||
for i, cb in enumerate(self.filters.values()):
|
||||
col = (2 + i) if self.kind == "subs" else 0
|
||||
@@ -394,6 +425,9 @@ class TextPanel(QWidget):
|
||||
cb.setCurrentText(cur if cur else ANY)
|
||||
cb.blockSignals(False)
|
||||
self._filter()
|
||||
if self._pending_key: # asked for while the rows were loading
|
||||
key, self._pending_key = self._pending_key, None
|
||||
self.select_key(key)
|
||||
|
||||
def _menu_original(self, e):
|
||||
r = self.ws().texts.records().get("MENU:" + e.key)
|
||||
@@ -405,8 +439,7 @@ class TextPanel(QWidget):
|
||||
k.startswith("SUB:" if self.kind == "subs" else "MENU:")}
|
||||
|
||||
def refresh(self):
|
||||
self.model.set_modified(self._modified())
|
||||
self.proxy.refilter()
|
||||
self.model.set_modified(self._modified()) # the view refilters/re-sorts itself
|
||||
self._update_count()
|
||||
if self.current:
|
||||
self._show(self.current)
|
||||
@@ -426,6 +459,9 @@ class TextPanel(QWidget):
|
||||
return [self.proxy.row_at(self.proxy.index(i, 0)) for i in range(self.proxy.rowCount())]
|
||||
|
||||
def select_key(self, key):
|
||||
if self.busy.busy: # rows still loading: select when they arrive
|
||||
self._pending_key = key
|
||||
return True
|
||||
for i in range(self.proxy.rowCount()):
|
||||
if self.proxy.row_at(self.proxy.index(i, 0)).key == key:
|
||||
self.table.selectRow(i)
|
||||
|
||||
Reference in New Issue
Block a user