Add TaskThread, use to simplify WaitingDialog
This will be useful as a client thread for hardware wallets
This commit is contained in:
parent
d9a84875dc
commit
c714acf739
|
@ -197,6 +197,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
self.show()
|
self.show()
|
||||||
self.raise_()
|
self.raise_()
|
||||||
|
|
||||||
|
def on_error(self, exc_info):
|
||||||
|
traceback.print_exception(*exc_info)
|
||||||
|
self.show_error(str(exc_info[1]))
|
||||||
|
|
||||||
def on_network(self, event, *args):
|
def on_network(self, event, *args):
|
||||||
if event == 'updated':
|
if event == 'updated':
|
||||||
self.need_update.set()
|
self.need_update.set()
|
||||||
|
@ -1265,12 +1269,15 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
# call hook to see if plugin needs gui interaction
|
# call hook to see if plugin needs gui interaction
|
||||||
run_hook('sign_tx', parent, tx)
|
run_hook('sign_tx', parent, tx)
|
||||||
|
|
||||||
def sign_thread():
|
def on_signed(result):
|
||||||
self.wallet.sign_transaction(tx, password)
|
callback(True)
|
||||||
return True
|
def on_failed(exc_info):
|
||||||
|
self.on_error(exc_info)
|
||||||
|
callback(False)
|
||||||
|
|
||||||
WaitingDialog(parent, _('Signing transaction...'), sign_thread,
|
task = partial(self.wallet.sign_transaction, tx, password)
|
||||||
callback)
|
WaitingDialog(parent, _('Signing transaction...'), task,
|
||||||
|
on_signed, on_failed)
|
||||||
|
|
||||||
def broadcast_transaction(self, tx, tx_desc, parent):
|
def broadcast_transaction(self, tx, tx_desc, parent):
|
||||||
|
|
||||||
|
@ -1309,7 +1316,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
self.show_error(msg, parent=parent)
|
self.show_error(msg, parent=parent)
|
||||||
|
|
||||||
WaitingDialog(parent, _('Broadcasting transaction...'),
|
WaitingDialog(parent, _('Broadcasting transaction...'),
|
||||||
broadcast_thread, broadcast_done)
|
broadcast_thread, broadcast_done, self.on_error)
|
||||||
|
|
||||||
def prepare_for_payment_request(self):
|
def prepare_for_payment_request(self):
|
||||||
self.tabs.setCurrentIndex(1)
|
self.tabs.setCurrentIndex(1)
|
||||||
|
|
|
@ -4,6 +4,8 @@ import traceback
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import platform
|
import platform
|
||||||
|
import Queue
|
||||||
|
from collections import namedtuple
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
|
@ -211,39 +213,26 @@ class WindowModalDialog(QDialog, MessageBoxMixin):
|
||||||
if title:
|
if title:
|
||||||
self.setWindowTitle(title)
|
self.setWindowTitle(title)
|
||||||
|
|
||||||
class WaitingDialog(QThread, MessageBoxMixin):
|
|
||||||
|
class WaitingDialog(WindowModalDialog):
|
||||||
'''Shows a please wait dialog whilst runnning a task. It is not
|
'''Shows a please wait dialog whilst runnning a task. It is not
|
||||||
necessary to maintain a reference to this dialog.'''
|
necessary to maintain a reference to this dialog.'''
|
||||||
def __init__(self, parent, message, task, on_finished=None):
|
def __init__(self, parent, message, task, on_success=None, on_error=None):
|
||||||
global dialogs
|
assert parent
|
||||||
dialogs.append(self) # Prevent GC
|
WindowModalDialog.__init__(self, parent, _("Please wait"))
|
||||||
QThread.__init__(self)
|
vbox = QVBoxLayout(self)
|
||||||
self.task = task
|
|
||||||
self.on_finished = on_finished
|
|
||||||
self.dialog = WindowModalDialog(parent, _("Please wait"))
|
|
||||||
vbox = QVBoxLayout(self.dialog)
|
|
||||||
vbox.addWidget(QLabel(message))
|
vbox.addWidget(QLabel(message))
|
||||||
self.dialog.show()
|
self.accepted.connect(self.on_accepted)
|
||||||
self.dialog.connect(self, SIGNAL("finished()"), self.finished)
|
self.show()
|
||||||
self.start()
|
self.thread = TaskThread(self)
|
||||||
|
self.thread.add(task, on_success, self.accept, on_error)
|
||||||
|
|
||||||
def run(self):
|
def wait(self):
|
||||||
try:
|
self.thread.wait()
|
||||||
self.result = self.task()
|
|
||||||
self.error = None
|
def on_accepted(self):
|
||||||
except BaseException as e:
|
self.thread.stop()
|
||||||
traceback.print_exc(file=sys.stdout)
|
|
||||||
self.error = str(e)
|
|
||||||
self.result = None
|
|
||||||
|
|
||||||
def finished(self):
|
|
||||||
global dialogs
|
|
||||||
dialogs.remove(self)
|
|
||||||
self.dialog.accept()
|
|
||||||
if self.error:
|
|
||||||
self.show_error(self.error, parent=self.dialog.parent())
|
|
||||||
if self.on_finished:
|
|
||||||
self.on_finished(self.result)
|
|
||||||
|
|
||||||
def line_dialog(parent, title, label, ok_label, default=None):
|
def line_dialog(parent, title, label, ok_label, default=None):
|
||||||
dialog = WindowModalDialog(parent, title)
|
dialog = WindowModalDialog(parent, title)
|
||||||
|
@ -548,6 +537,46 @@ class ButtonsTextEdit(QPlainTextEdit, ButtonsWidget):
|
||||||
return o
|
return o
|
||||||
|
|
||||||
|
|
||||||
|
class TaskThread(QThread):
|
||||||
|
'''Thread that runs background tasks. Callbacks are guaranteed
|
||||||
|
to happen in the context of its parent.'''
|
||||||
|
|
||||||
|
Task = namedtuple("Task", "task cb_success cb_done cb_error")
|
||||||
|
doneSig = pyqtSignal(object, object, object)
|
||||||
|
|
||||||
|
def __init__(self, parent, on_error=None):
|
||||||
|
super(TaskThread, self).__init__(parent)
|
||||||
|
self.on_error = on_error
|
||||||
|
self.tasks = Queue.Queue()
|
||||||
|
self.doneSig.connect(self.on_done)
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def add(self, task, on_success=None, on_done=None, on_error=None):
|
||||||
|
on_error = on_error or self.on_error
|
||||||
|
self.tasks.put(TaskThread.Task(task, on_success, on_done, on_error))
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while True:
|
||||||
|
task = self.tasks.get()
|
||||||
|
if not task:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
result = task.task()
|
||||||
|
self.doneSig.emit(result, task.cb_done, task.cb_success)
|
||||||
|
except BaseException:
|
||||||
|
self.doneSig.emit(sys.exc_info(), task.cb_done, task.cb_error)
|
||||||
|
|
||||||
|
def on_done(self, result, cb_done, cb):
|
||||||
|
# This runs in the parent's thread.
|
||||||
|
if cb_done:
|
||||||
|
cb_done()
|
||||||
|
if cb:
|
||||||
|
cb(result)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.tasks.put(None)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done", _('OK')))
|
t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done", _('OK')))
|
||||||
|
|
Loading…
Reference in New Issue