Use signals a little better and avoid QDialog.exec
This commit is contained in:
parent
a9da87bff3
commit
13ee9e9ad8
@ -24,7 +24,7 @@ from comicapi.genericmetadata import GenericMetadata
|
||||
from comicapi.issuestring import IssueString
|
||||
from comictaggerlib.coverimagewidget import CoverImageWidget
|
||||
from comictaggerlib.ctsettings import ct_ns
|
||||
from comictaggerlib.seriesselectionwindow import SeriesSelectionWindow
|
||||
from comictaggerlib.seriesselectionwindow import SelectionWindow
|
||||
from comictaggerlib.ui import ui_path
|
||||
from comictalker.comictalker import ComicTalker, RLCallBack, TalkerError
|
||||
|
||||
@ -39,9 +39,44 @@ class IssueNumberTableWidgetItem(QtWidgets.QTableWidgetItem):
|
||||
return (IssueString(self_str).as_float() or 0) < (IssueString(other_str).as_float() or 0)
|
||||
|
||||
|
||||
class IssueSelectionWindow(SeriesSelectionWindow):
|
||||
class QueryThread(QtCore.QThread):
|
||||
def __init__(
|
||||
self,
|
||||
talker: ComicTalker,
|
||||
series_id: str,
|
||||
finish: QtCore.pyqtSignal,
|
||||
on_ratelimit: QtCore.pyqtSignal,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.series_id = series_id
|
||||
self.talker = talker
|
||||
self.finish = finish
|
||||
self.on_ratelimit = on_ratelimit
|
||||
|
||||
def run(self) -> None:
|
||||
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor))
|
||||
|
||||
try:
|
||||
issue_list = [
|
||||
x
|
||||
for x in self.talker.fetch_issues_in_series(
|
||||
self.series_id, on_rate_limit=RLCallBack(lambda x, y: self.on_ratelimit.emit(x, y), 10)
|
||||
)
|
||||
if x.issue_id is not None
|
||||
]
|
||||
except TalkerError as e:
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
QtWidgets.QMessageBox.critical(None, f"{e.source} {e.code_name} Error", f"{e}")
|
||||
return
|
||||
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
self.finish.emit(issue_list)
|
||||
|
||||
|
||||
class IssueSelectionWindow(SelectionWindow):
|
||||
ui_file = ui_path / "issueselectionwindow.ui"
|
||||
CoverImageMode = CoverImageWidget.AltCoverMode
|
||||
finish = QtCore.pyqtSignal(list)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -60,42 +95,28 @@ class IssueSelectionWindow(SeriesSelectionWindow):
|
||||
self.issue_number = "1"
|
||||
|
||||
self.initial_id: str = ""
|
||||
self.perform_query()
|
||||
|
||||
# now that the list has been sorted, find the initial record, and
|
||||
# select it
|
||||
if self.initial_id:
|
||||
for r in range(0, self.twList.rowCount()):
|
||||
issue_id = self.twList.item(r, 0).data(QtCore.Qt.ItemDataRole.UserRole)
|
||||
if issue_id == self.initial_id:
|
||||
self.twList.selectRow(r)
|
||||
break
|
||||
self.leFilter.textChanged.connect(self.filter)
|
||||
self.finish.connect(self.query_finished)
|
||||
|
||||
def showEvent(self, event: QtGui.QShowEvent) -> None:
|
||||
return
|
||||
self.perform_query()
|
||||
|
||||
def perform_query(self) -> None: # type: ignore[override]
|
||||
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor))
|
||||
|
||||
try:
|
||||
self.issue_list = {
|
||||
x.issue_id: x
|
||||
for x in self.talker.fetch_issues_in_series(
|
||||
self.series_id, on_rate_limit=RLCallBack(self.on_ratelimit, 10)
|
||||
)
|
||||
if x.issue_id is not None
|
||||
}
|
||||
except TalkerError as e:
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
QtWidgets.QMessageBox.critical(self, f"{e.source} {e.code_name} Error", f"{e}")
|
||||
return
|
||||
self.querythread = QueryThread(
|
||||
self.talker,
|
||||
self.series_id,
|
||||
self.finish,
|
||||
self.ratelimit,
|
||||
)
|
||||
self.querythread.start()
|
||||
|
||||
def query_finished(self, issues: list[GenericMetadata]) -> None:
|
||||
self.twList.setRowCount(0)
|
||||
|
||||
self.twList.setSortingEnabled(False)
|
||||
|
||||
for row, issue in enumerate(self.issue_list.values()):
|
||||
self.issue_list = {i.issue_id: i for i in issues if i.issue_id is not None}
|
||||
self.twList.clear()
|
||||
for row, issue in enumerate(issues):
|
||||
self.twList.insertRow(row)
|
||||
self.twList.setItem(row, 0, IssueNumberTableWidgetItem())
|
||||
self.twList.setItem(row, 1, QtWidgets.QTableWidgetItem())
|
||||
@ -108,8 +129,15 @@ class IssueSelectionWindow(SeriesSelectionWindow):
|
||||
|
||||
self.twList.setSortingEnabled(True)
|
||||
self.twList.sortItems(0, QtCore.Qt.SortOrder.AscendingOrder)
|
||||
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
self.twList: QtWidgets.QTableWidget
|
||||
if self.initial_id:
|
||||
for r in range(0, self.twList.rowCount()):
|
||||
item = self.twList.item(r, 0)
|
||||
issue_id = item.data(QtCore.Qt.ItemDataRole.UserRole)
|
||||
if issue_id == self.initial_id:
|
||||
self.twList.selectRow(r)
|
||||
self.twList.scrollToItem(item, QtWidgets.QAbstractItemView.ScrollHint.EnsureVisible)
|
||||
break
|
||||
|
||||
def cell_double_clicked(self, r: int, c: int) -> None:
|
||||
self.accept()
|
||||
|
@ -18,6 +18,7 @@ from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from collections import deque
|
||||
|
||||
import natsort
|
||||
@ -128,9 +129,11 @@ class IdentifyThread(QtCore.QThread):
|
||||
self.ratelimit.emit(full_time, sleep_time)
|
||||
|
||||
|
||||
class SeriesSelectionWindow(QtWidgets.QDialog):
|
||||
class SelectionWindow(QtWidgets.QDialog):
|
||||
__metaclass__ = ABCMeta
|
||||
ui_file = ui_path / "seriesselectionwindow.ui"
|
||||
CoverImageMode = CoverImageWidget.URLMode
|
||||
ratelimit = pyqtSignal(float, float)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -203,31 +206,107 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
|
||||
self.leFilter.textChanged.connect(self.filter)
|
||||
self.twList.selectRow(0)
|
||||
|
||||
if series_name:
|
||||
self.series_name = series_name
|
||||
self.issue_number = issue_number
|
||||
self.year = year
|
||||
self.issue_count = issue_count
|
||||
self.series_id: str = ""
|
||||
self.comic_archive = comic_archive
|
||||
self.immediate_autoselect = autoselect
|
||||
self.series_list: dict[str, ComicSeries] = {}
|
||||
self.literal = literal
|
||||
self.iddialog: IDProgressWindow | None = None
|
||||
self.id_thread: IdentifyThread | None = None
|
||||
self.progdialog: QtWidgets.QProgressDialog | None = None
|
||||
self.search_thread: SearchThread | None = None
|
||||
@abstractmethod
|
||||
def perform_query(self, refresh: bool = False) -> None: ...
|
||||
|
||||
self.use_publisher_filter = self.config.Auto_Tag__use_publisher_filter
|
||||
@abstractmethod
|
||||
def cell_double_clicked(self, r: int, c: int) -> None: ...
|
||||
|
||||
self.btnRequery.clicked.connect(self.requery)
|
||||
self.btnIssues.clicked.connect(self.show_issues)
|
||||
self.btnAutoSelect.clicked.connect(self.auto_select)
|
||||
@abstractmethod
|
||||
def update_row(self, row: int, series: ComicSeries) -> None: ...
|
||||
|
||||
self.cbxPublisherFilter.setChecked(self.use_publisher_filter)
|
||||
self.cbxPublisherFilter.toggled.connect(self.publisher_filter_toggled)
|
||||
def set_description(self, widget: QtWidgets.QWidget, text: str) -> None:
|
||||
if isinstance(widget, QtWidgets.QTextEdit):
|
||||
widget.setText(text.replace("</figure>", "</div>").replace("<figure", "<div"))
|
||||
else:
|
||||
html = text
|
||||
widget.setHtml(html, QUrl(self.talker.website))
|
||||
|
||||
self.update_buttons()
|
||||
def filter(self, text: str) -> None:
|
||||
rows = set(range(self.twList.rowCount()))
|
||||
for r in rows:
|
||||
self.twList.showRow(r)
|
||||
if text.strip():
|
||||
shown_rows = {x.row() for x in self.twList.findItems(text, QtCore.Qt.MatchFlag.MatchContains)}
|
||||
for r in rows - shown_rows:
|
||||
self.twList.hideRow(r)
|
||||
|
||||
@abstractmethod
|
||||
def _fetch(self, row: int) -> ComicSeries: ...
|
||||
|
||||
def on_ratelimit(self, full_time: float, sleep_time: float) -> None:
|
||||
self.ratelimit.emit(full_time, sleep_time)
|
||||
|
||||
def current_item_changed(self, curr: QtCore.QModelIndex | None, prev: QtCore.QModelIndex | None) -> None:
|
||||
if curr is None:
|
||||
return
|
||||
if prev is not None and prev.row() == curr.row():
|
||||
return
|
||||
|
||||
row = curr.row()
|
||||
|
||||
item = self._fetch(row)
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
|
||||
# Update current record information
|
||||
self.update_row(row, item)
|
||||
|
||||
|
||||
class SeriesSelectionWindow(SelectionWindow):
|
||||
ui_file = ui_path / "seriesselectionwindow.ui"
|
||||
CoverImageMode = CoverImageWidget.URLMode
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent: QtWidgets.QWidget,
|
||||
config: ct_ns,
|
||||
talker: ComicTalker,
|
||||
series_name: str = "",
|
||||
issue_number: str = "",
|
||||
comic_archive: ComicArchive | None = None,
|
||||
year: int | None = None,
|
||||
issue_count: int | None = None,
|
||||
autoselect: bool = False,
|
||||
literal: bool = False,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
parent,
|
||||
config,
|
||||
talker,
|
||||
series_name,
|
||||
issue_number,
|
||||
comic_archive,
|
||||
year,
|
||||
issue_count,
|
||||
autoselect,
|
||||
literal,
|
||||
)
|
||||
self.series_name = series_name
|
||||
self.issue_number = issue_number
|
||||
self.year = year
|
||||
self.issue_count = issue_count
|
||||
self.series_id: str = ""
|
||||
self.comic_archive = comic_archive
|
||||
self.immediate_autoselect = autoselect
|
||||
self.series_list: dict[str, ComicSeries] = {}
|
||||
self.literal = literal
|
||||
self.iddialog: IDProgressWindow | None = None
|
||||
self.id_thread: IdentifyThread | None = None
|
||||
self.progdialog: QtWidgets.QProgressDialog | None = None
|
||||
self.search_thread: SearchThread | None = None
|
||||
|
||||
self.use_publisher_filter = self.config.Auto_Tag__use_publisher_filter
|
||||
|
||||
self.btnRequery.clicked.connect(self.requery)
|
||||
self.btnIssues.clicked.connect(self.show_issues)
|
||||
self.btnAutoSelect.clicked.connect(self.auto_select)
|
||||
|
||||
self.cbxPublisherFilter.setChecked(self.use_publisher_filter)
|
||||
self.cbxPublisherFilter.toggled.connect(self.publisher_filter_toggled)
|
||||
|
||||
self.ratelimit.connect(self.ratelimit_message)
|
||||
|
||||
self.update_buttons()
|
||||
|
||||
def showEvent(self, event: QtGui.QShowEvent) -> None:
|
||||
self.perform_query()
|
||||
@ -251,8 +330,7 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
|
||||
)
|
||||
self.search_thread.searchComplete.connect(self.search_complete)
|
||||
self.search_thread.progressUpdate.connect(self.search_progress_update)
|
||||
self.search_thread.ratelimit.connect(self.on_ratelimit)
|
||||
self.search_thread.ratelimit.connect(self.parent().on_ratelimit)
|
||||
self.search_thread.ratelimit.connect(self.ratelimit)
|
||||
self.search_thread.start()
|
||||
|
||||
self.progdialog = QtWidgets.QProgressDialog("Searching Online", "Cancel", 0, 100, self)
|
||||
@ -269,11 +347,6 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
|
||||
def cell_double_clicked(self, r: int, c: int) -> None:
|
||||
self.show_issues()
|
||||
|
||||
def on_ratelimit(self, full_time: float, sleep_time: float) -> None:
|
||||
self.log_output(
|
||||
f"Rate limit reached: {full_time:.0f}s until next request. Waiting {sleep_time:.0f}s for ratelimit"
|
||||
)
|
||||
|
||||
def update_row(self, row: int, series: ComicSeries) -> None:
|
||||
item_text = series.name
|
||||
item = self.twList.item(row, 0)
|
||||
@ -380,21 +453,13 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
|
||||
self.id_thread.identifyComplete.connect(self.identify_complete)
|
||||
self.id_thread.identifyLogMsg.connect(self.log_output)
|
||||
self.id_thread.identifyProgress.connect(self.identify_progress)
|
||||
self.id_thread.ratelimit.connect(self.on_ratelimit)
|
||||
self.id_thread.ratelimit.connect(self.parent().on_ratelimit)
|
||||
self.id_thread.ratelimit.connect(self.ratelimit)
|
||||
self.iddialog.rejected.connect(self.id_thread.cancel)
|
||||
|
||||
self.id_thread.start()
|
||||
|
||||
self.iddialog.exec()
|
||||
|
||||
def log_output(self, text: str) -> None:
|
||||
if self.iddialog is not None:
|
||||
self.iddialog.textEdit.append(text.rstrip())
|
||||
self.iddialog.textEdit.ensureCursorVisible()
|
||||
QtCore.QCoreApplication.processEvents()
|
||||
QtCore.QCoreApplication.processEvents()
|
||||
QtCore.QCoreApplication.processEvents()
|
||||
self.selector = None
|
||||
|
||||
def identify_progress(self, cur: int, total: int) -> None:
|
||||
if self.iddialog is not None:
|
||||
@ -449,20 +514,24 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
|
||||
def show_issues(self) -> None:
|
||||
from comictaggerlib.issueselectionwindow import IssueSelectionWindow
|
||||
|
||||
selector = IssueSelectionWindow(self, self.config, self.talker, self.series_id, self.issue_number)
|
||||
self.selector = IssueSelectionWindow(self, self.config, self.talker, self.series_id, self.issue_number)
|
||||
self.selector.ratelimit.connect(self.ratelimit)
|
||||
title = ""
|
||||
for series in self.series_list.values():
|
||||
if series.id == self.series_id:
|
||||
title = f"{series.name} ({series.start_year:04}) - " if series.start_year else f"{series.name} - "
|
||||
break
|
||||
|
||||
selector.setWindowTitle(title + "Select Issue")
|
||||
selector.setModal(True)
|
||||
selector.exec()
|
||||
if selector.result():
|
||||
self.selector.setWindowTitle(title + "Select Issue")
|
||||
self.selector.setModal(True)
|
||||
self.selector.finished.connect(self.issue_selected)
|
||||
self.selector.open()
|
||||
|
||||
def issue_selected(self, result) -> None:
|
||||
if result and self.selector:
|
||||
# we should now have a series ID
|
||||
self.issue_number = selector.issue_number
|
||||
self.issue_id = selector.issue_id
|
||||
self.issue_number = self.selector.issue_number
|
||||
self.issue_id = self.selector.issue_id
|
||||
self.accept()
|
||||
else:
|
||||
self.cover_widget.update_content()
|
||||
@ -615,3 +684,16 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
|
||||
|
||||
# Update current record information
|
||||
self.update_row(row, item)
|
||||
|
||||
def ratelimit_message(self, full_time: float, sleep_time: float) -> None:
|
||||
self.log_output(
|
||||
f"Rate limit reached: {full_time:.0f}s until next request. Waiting {sleep_time:.0f}s for ratelimit"
|
||||
)
|
||||
|
||||
def log_output(self, text: str) -> None:
|
||||
if self.iddialog is not None:
|
||||
self.iddialog.textEdit.append(text.rstrip())
|
||||
self.iddialog.textEdit.ensureCursorVisible()
|
||||
QtCore.QCoreApplication.processEvents()
|
||||
QtCore.QCoreApplication.processEvents()
|
||||
QtCore.QCoreApplication.processEvents()
|
||||
|
@ -77,7 +77,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
appName = "ComicTagger"
|
||||
version = ctversion.version
|
||||
ratelimit = QtCore.pyqtSignal(float, float)
|
||||
finish = QtCore.pyqtSignal(GenericMetadata, str)
|
||||
query_finished = QtCore.pyqtSignal(GenericMetadata, str)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -290,7 +290,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
self.page_list_editor.set_blur(self.config[0].General__blur)
|
||||
|
||||
self.ratelimit.connect(self.on_ratelimit)
|
||||
self.finish.connect(self.finish_query)
|
||||
self.query_finished.connect(self.apply_query_metadata)
|
||||
|
||||
def _sync_blur(*args: Any) -> None:
|
||||
self.config[0].General__blur = self.page_list_editor.blur
|
||||
@ -1073,7 +1073,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
|
||||
issue_count = utils.xlate_int(self.leIssueCount.text())
|
||||
|
||||
selector = SeriesSelectionWindow(
|
||||
self.selector = SeriesSelectionWindow(
|
||||
self,
|
||||
self.config[0],
|
||||
self.current_talker(),
|
||||
@ -1085,13 +1085,16 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
autoselect,
|
||||
literal,
|
||||
)
|
||||
self.selector.ratelimit.connect(self.on_ratelimit)
|
||||
|
||||
selector.setWindowTitle(f"Search: '{series_name}' - Select Series")
|
||||
self.selector.setWindowTitle(f"Search: '{series_name}' - Select Series")
|
||||
self.selector.finished.connect(self.finish_query)
|
||||
|
||||
selector.setModal(True)
|
||||
selector.exec()
|
||||
self.selector.setModal(True)
|
||||
self.selector.open()
|
||||
|
||||
if selector.result():
|
||||
def finish_query(self, result) -> None:
|
||||
if result and self.selector:
|
||||
|
||||
class QueryThread(QtCore.QThread):
|
||||
def __init__(
|
||||
@ -1126,15 +1129,15 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
|
||||
self.querythread = QueryThread(
|
||||
self.current_talker(),
|
||||
selector.issue_id,
|
||||
selector.series_id,
|
||||
selector.issue_number,
|
||||
self.finish,
|
||||
self.selector.issue_id,
|
||||
self.selector.series_id,
|
||||
self.selector.issue_number,
|
||||
self.query_finished,
|
||||
self.ratelimit,
|
||||
)
|
||||
self.querythread.start()
|
||||
|
||||
def finish_query(self, new_metadata: GenericMetadata, issue_number: str) -> None:
|
||||
def apply_query_metadata(self, new_metadata: GenericMetadata, issue_number: str) -> None:
|
||||
# we should now have a series ID
|
||||
# QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor))
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
|
Loading…
Reference in New Issue
Block a user