Top level window fix for tx_dialog and h/w wallets
This commit is contained in:
parent
43fd49aa8f
commit
f92843bb10
|
@ -178,9 +178,24 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
self.fetch_alias()
|
self.fetch_alias()
|
||||||
self.require_fee_update = False
|
self.require_fee_update = False
|
||||||
self.tx_notifications = []
|
self.tx_notifications = []
|
||||||
|
self.tl_windows = []
|
||||||
self.load_wallet(wallet)
|
self.load_wallet(wallet)
|
||||||
self.connect_slots(gui_object.timer)
|
self.connect_slots(gui_object.timer)
|
||||||
|
|
||||||
|
def push_top_level_window(self, window):
|
||||||
|
'''Used for e.g. tx dialog box to ensure new dialogs are appropriately
|
||||||
|
parented. This used to be done by explicitly providing the parent
|
||||||
|
window, but that isn't something hardware wallet prompts know.'''
|
||||||
|
self.tl_windows.append(window)
|
||||||
|
|
||||||
|
def pop_top_level_window(self, window):
|
||||||
|
self.tl_windows.remove(window)
|
||||||
|
|
||||||
|
def top_level_window(self):
|
||||||
|
'''Do the right thing in the presence of tx dialog windows'''
|
||||||
|
override = self.tl_windows[-1] if self.tl_windows else None
|
||||||
|
return self.top_level_window_recurse(override)
|
||||||
|
|
||||||
def diagnostic_name(self):
|
def diagnostic_name(self):
|
||||||
return "%s/%s" % (PrintError.diagnostic_name(self),
|
return "%s/%s" % (PrintError.diagnostic_name(self),
|
||||||
self.wallet.basename() if self.wallet else "None")
|
self.wallet.basename() if self.wallet else "None")
|
||||||
|
@ -1141,7 +1156,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
return value of the wrapped function, or None if cancelled.
|
return value of the wrapped function, or None if cancelled.
|
||||||
'''
|
'''
|
||||||
def request_password(self, *args, **kwargs):
|
def request_password(self, *args, **kwargs):
|
||||||
parent = kwargs.get('parent', self.top_level_window())
|
parent = self.top_level_window()
|
||||||
password = None
|
password = None
|
||||||
while self.wallet.use_encryption:
|
while self.wallet.use_encryption:
|
||||||
password = self.password_dialog(parent=parent)
|
password = self.password_dialog(parent=parent)
|
||||||
|
@ -1254,14 +1269,14 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
self.show_transaction(tx)
|
self.show_transaction(tx)
|
||||||
self.do_clear()
|
self.do_clear()
|
||||||
else:
|
else:
|
||||||
self.broadcast_transaction(tx, tx_desc, self)
|
self.broadcast_transaction(tx, tx_desc)
|
||||||
self.sign_tx_with_password(tx, sign_done, password, self)
|
self.sign_tx_with_password(tx, sign_done, password)
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
def sign_tx(self, tx, callback, password, parent):
|
def sign_tx(self, tx, callback, password):
|
||||||
self.sign_tx_with_password(tx, callback, password, parent)
|
self.sign_tx_with_password(tx, callback, password)
|
||||||
|
|
||||||
def sign_tx_with_password(self, tx, callback, password, parent):
|
def sign_tx_with_password(self, tx, callback, password):
|
||||||
'''Sign the transaction in a separate thread. When done, calls
|
'''Sign the transaction in a separate thread. When done, calls
|
||||||
the callback with a success code of True or False.
|
the callback with a success code of True or False.
|
||||||
'''
|
'''
|
||||||
|
@ -1270,7 +1285,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
return
|
return
|
||||||
|
|
||||||
# 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', self, tx)
|
||||||
|
|
||||||
def on_signed(result):
|
def on_signed(result):
|
||||||
callback(True)
|
callback(True)
|
||||||
|
@ -1279,10 +1294,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
callback(False)
|
callback(False)
|
||||||
|
|
||||||
task = partial(self.wallet.sign_transaction, tx, password)
|
task = partial(self.wallet.sign_transaction, tx, password)
|
||||||
WaitingDialog(parent, _('Signing transaction...'), task,
|
WaitingDialog(self, _('Signing transaction...'), task,
|
||||||
on_signed, on_failed)
|
on_signed, on_failed)
|
||||||
|
|
||||||
def broadcast_transaction(self, tx, tx_desc, parent):
|
def broadcast_transaction(self, tx, tx_desc):
|
||||||
|
|
||||||
def broadcast_thread():
|
def broadcast_thread():
|
||||||
# non-GUI thread
|
# non-GUI thread
|
||||||
|
@ -1304,6 +1319,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
msg = ack_msg
|
msg = ack_msg
|
||||||
return status, msg
|
return status, msg
|
||||||
|
|
||||||
|
# Capture current TL window; override might be removed on return
|
||||||
|
parent = self.top_level_window()
|
||||||
|
|
||||||
def broadcast_done(result):
|
def broadcast_done(result):
|
||||||
# GUI thread
|
# GUI thread
|
||||||
if result:
|
if result:
|
||||||
|
@ -1311,14 +1329,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
if status:
|
if status:
|
||||||
if tx_desc is not None and tx.is_complete():
|
if tx_desc is not None and tx.is_complete():
|
||||||
self.wallet.set_label(tx.hash(), tx_desc)
|
self.wallet.set_label(tx.hash(), tx_desc)
|
||||||
self.show_message(_('Payment sent.') + '\n' + msg,
|
parent.show_message(_('Payment sent.') + '\n' + msg)
|
||||||
parent=parent)
|
|
||||||
self.invoices_list.update()
|
self.invoices_list.update()
|
||||||
self.do_clear()
|
self.do_clear()
|
||||||
else:
|
else:
|
||||||
self.show_error(msg, parent=parent)
|
parent.show_error(msg)
|
||||||
|
|
||||||
WaitingDialog(parent, _('Broadcasting transaction...'),
|
WaitingDialog(self, _('Broadcasting transaction...'),
|
||||||
broadcast_thread, broadcast_done, self.on_error)
|
broadcast_thread, broadcast_done, self.on_error)
|
||||||
|
|
||||||
def prepare_for_payment_request(self):
|
def prepare_for_payment_request(self):
|
||||||
|
|
|
@ -116,7 +116,11 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def do_broadcast(self):
|
def do_broadcast(self):
|
||||||
self.main_window.broadcast_transaction(self.tx, self.desc, self)
|
self.main_window.push_top_level_window(self)
|
||||||
|
try:
|
||||||
|
self.main_window.broadcast_transaction(self.tx, self.desc)
|
||||||
|
finally:
|
||||||
|
self.main_window.pop_top_level_window(self)
|
||||||
self.broadcast = True
|
self.broadcast = True
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
@ -140,6 +144,7 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||||
def sign(self):
|
def sign(self):
|
||||||
def sign_done(success):
|
def sign_done(success):
|
||||||
self.sign_button.setDisabled(False)
|
self.sign_button.setDisabled(False)
|
||||||
|
self.main_window.pop_top_level_window(self)
|
||||||
if success:
|
if success:
|
||||||
self.prompt_if_unsaved = False
|
self.prompt_if_unsaved = False
|
||||||
self.saved = False
|
self.saved = False
|
||||||
|
@ -148,7 +153,8 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||||
self.sign_button.setDisabled(True)
|
self.sign_button.setDisabled(True)
|
||||||
# Note sign_tx is wrapped and parent= is actually passed
|
# Note sign_tx is wrapped and parent= is actually passed
|
||||||
# to the password input dialog box
|
# to the password input dialog box
|
||||||
self.main_window.sign_tx(self.tx, sign_done, parent=self)
|
self.main_window.push_top_level_window(self)
|
||||||
|
self.main_window.sign_tx(self.tx, sign_done)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
name = 'signed_%s.txn' % (self.tx.hash()[0:8]) if self.tx.is_complete() else 'unsigned.txn'
|
name = 'signed_%s.txn' % (self.tx.hash()[0:8]) if self.tx.is_complete() else 'unsigned.txn'
|
||||||
|
|
|
@ -146,15 +146,18 @@ class CancelButton(QPushButton):
|
||||||
self.clicked.connect(dialog.reject)
|
self.clicked.connect(dialog.reject)
|
||||||
|
|
||||||
class MessageBoxMixin(object):
|
class MessageBoxMixin(object):
|
||||||
def top_level_window(self, window=None):
|
def top_level_window_recurse(self, window=None):
|
||||||
window = window or self
|
window = window or self
|
||||||
classes = (WindowModalDialog, QMessageBox)
|
classes = (WindowModalDialog, QMessageBox)
|
||||||
for n, child in enumerate(window.children()):
|
for n, child in enumerate(window.children()):
|
||||||
# Test for visibility as old closed dialogs may not be GC-ed
|
# Test for visibility as old closed dialogs may not be GC-ed
|
||||||
if isinstance(child, classes) and child.isVisible():
|
if isinstance(child, classes) and child.isVisible():
|
||||||
return self.top_level_window(child)
|
return self.top_level_window_recurse(child)
|
||||||
return window
|
return window
|
||||||
|
|
||||||
|
def top_level_window(self):
|
||||||
|
return self.top_level_window_recurse()
|
||||||
|
|
||||||
def question(self, msg, parent=None, title=None, icon=None):
|
def question(self, msg, parent=None, title=None, icon=None):
|
||||||
Yes, No = QMessageBox.Yes, QMessageBox.No
|
Yes, No = QMessageBox.Yes, QMessageBox.No
|
||||||
return self.msg_box(icon or QMessageBox.Question,
|
return self.msg_box(icon or QMessageBox.Question,
|
||||||
|
@ -200,6 +203,8 @@ class WaitingDialog(WindowModalDialog):
|
||||||
necessary to maintain a reference to this dialog.'''
|
necessary to maintain a reference to this dialog.'''
|
||||||
def __init__(self, parent, message, task, on_success=None, on_error=None):
|
def __init__(self, parent, message, task, on_success=None, on_error=None):
|
||||||
assert parent
|
assert parent
|
||||||
|
if isinstance(parent, MessageBoxMixin):
|
||||||
|
parent = parent.top_level_window()
|
||||||
WindowModalDialog.__init__(self, parent, _("Please wait"))
|
WindowModalDialog.__init__(self, parent, _("Please wait"))
|
||||||
vbox = QVBoxLayout(self)
|
vbox = QVBoxLayout(self)
|
||||||
vbox.addWidget(QLabel(message))
|
vbox.addWidget(QLabel(message))
|
||||||
|
|
Loading…
Reference in New Issue