thw_wallet: separate out common QtHandler code - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 134ae3d0440a60bf3912c1ff58b8e53d039b0157 DIR parent e461c1c818e5ffff7a510d372661a0e7eb3482c3 HTML Author: Neil Booth <kyuupichan@gmail.com> Date: Sat, 30 Jan 2016 12:46:54 +0900 hw_wallet: separate out common QtHandler code Diffstat: M plugins/hw_wallet/__init__.py | 1 + A plugins/hw_wallet/qt.py | 129 +++++++++++++++++++++++++++++++ M plugins/trezor/qt_generic.py | 104 ++----------------------------- 3 files changed, 135 insertions(+), 99 deletions(-) --- DIR diff --git a/plugins/hw_wallet/__init__.py b/plugins/hw_wallet/__init__.py t@@ -1 +1,2 @@ from hw_wallet import BIP44_HW_Wallet +from qt import QtHandlerBase DIR diff --git a/plugins/hw_wallet/qt.py b/plugins/hw_wallet/qt.py t@@ -0,0 +1,129 @@ +#!/usr/bin/env python2 +# -*- mode: python -*- +# +# Electrum - lightweight Bitcoin client +# Copyright (C) 2016 The Electrum developers +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import threading + +from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL +from electrum_gui.qt.password_dialog import PasswordDialog, PW_PASSPHRASE +from electrum_gui.qt.util import * + +from electrum.i18n import _ +from electrum.util import PrintError +from electrum.wallet import BIP44_Wallet + +# The trickiest thing about this handler was getting windows properly +# parented on MacOSX. +class QtHandlerBase(QObject, PrintError): + '''An interface between the GUI (here, QT) and the device handling + logic for handling I/O. This is a generic implementation of the + TREZOR protocol; derived classes can customize it.''' + + qcSig = pyqtSignal(object, object) + + def __init__(self, win, device): + super(QtHandlerBase, self).__init__() + win.connect(win, SIGNAL('clear_dialog'), self.clear_dialog) + win.connect(win, SIGNAL('error_dialog'), self.error_dialog) + win.connect(win, SIGNAL('message_dialog'), self.message_dialog) + win.connect(win, SIGNAL('passphrase_dialog'), self.passphrase_dialog) + win.connect(win, SIGNAL('word_dialog'), self.word_dialog) + self.qcSig.connect(self.win_query_choice) + self.win = win + self.device = device + self.dialog = None + self.done = threading.Event() + + def top_level_window(self): + return self.win.top_level_window() + + def watching_only_changed(self): + self.win.emit(SIGNAL('watching_only_changed')) + + def query_choice(self, msg, labels): + self.done.clear() + self.qcSig.emit(msg, labels) + self.done.wait() + return self.choice + + def show_message(self, msg, on_cancel=None): + self.win.emit(SIGNAL('message_dialog'), msg, on_cancel) + + def show_error(self, msg): + self.win.emit(SIGNAL('error_dialog'), msg) + + def finished(self): + self.win.emit(SIGNAL('clear_dialog')) + + def get_word(self, msg): + self.done.clear() + self.win.emit(SIGNAL('word_dialog'), msg) + self.done.wait() + return self.word + + def get_passphrase(self, msg): + self.done.clear() + self.win.emit(SIGNAL('passphrase_dialog'), msg) + self.done.wait() + return self.passphrase + + def passphrase_dialog(self, msg): + d = PasswordDialog(self.top_level_window(), None, msg, PW_PASSPHRASE) + confirmed, p, passphrase = d.run() + if confirmed: + passphrase = BIP44_Wallet.normalize_passphrase(passphrase) + self.passphrase = passphrase + self.done.set() + + def word_dialog(self, msg): + dialog = WindowModalDialog(self.top_level_window(), "") + hbox = QHBoxLayout(dialog) + hbox.addWidget(QLabel(msg)) + text = QLineEdit() + text.setMaximumWidth(100) + text.returnPressed.connect(dialog.accept) + hbox.addWidget(text) + hbox.addStretch(1) + dialog.exec_() # Firmware cannot handle cancellation + self.word = unicode(text.text()) + self.done.set() + + def message_dialog(self, msg, on_cancel): + # Called more than once during signing, to confirm output and fee + self.clear_dialog() + title = _('Please check your %s device') % self.device + self.dialog = dialog = WindowModalDialog(self.top_level_window(), title) + l = QLabel(msg) + vbox = QVBoxLayout(dialog) + vbox.addWidget(l) + if on_cancel: + dialog.rejected.connect(on_cancel) + vbox.addLayout(Buttons(CancelButton(dialog))) + dialog.show() + + def error_dialog(self, msg): + self.win.show_error(msg, parent=self.top_level_window()) + + def clear_dialog(self): + if self.dialog: + self.dialog.accept() + self.dialog = None + + def win_query_choice(self, msg, labels): + self.choice = self.win.query_choice(msg, labels) + self.done.set() DIR diff --git a/plugins/trezor/qt_generic.py b/plugins/trezor/qt_generic.py t@@ -5,9 +5,9 @@ from PyQt4.Qt import Qt from PyQt4.Qt import QGridLayout, QInputDialog, QPushButton from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL from electrum_gui.qt.main_window import StatusBarButton -from electrum_gui.qt.password_dialog import PasswordDialog, PW_PASSPHRASE from electrum_gui.qt.util import * -from .plugin import TrezorCompatiblePlugin, TIM_NEW, TIM_RECOVER, TIM_MNEMONIC +from .plugin import TIM_NEW, TIM_RECOVER, TIM_MNEMONIC +from ..hw_wallet import QtHandlerBase from electrum.i18n import _ from electrum.plugins import hook, DeviceMgr t@@ -126,54 +126,18 @@ class CharacterDialog(WindowModalDialog): if self.loop.exec_(): self.data = None # User cancelled -# By far the trickiest thing about this handler is the window stack; -# MacOSX is very fussy the modal dialogs are perfectly parented -class QtHandler(QObject, PrintError): - '''An interface between the GUI (here, QT) and the device handling - logic for handling I/O. This is a generic implementation of the - TREZOR protocol; derived classes can customize it.''' + +class QtHandler(QtHandlerBase): charSig = pyqtSignal(object) - qcSig = pyqtSignal(object, object) def __init__(self, win, pin_matrix_widget_class, device): - super(QtHandler, self).__init__() - win.connect(win, SIGNAL('clear_dialog'), self.clear_dialog) - win.connect(win, SIGNAL('error_dialog'), self.error_dialog) - win.connect(win, SIGNAL('message_dialog'), self.message_dialog) + super(QtHandler, self).__init__(win, device) win.connect(win, SIGNAL('pin_dialog'), self.pin_dialog) - win.connect(win, SIGNAL('passphrase_dialog'), self.passphrase_dialog) - win.connect(win, SIGNAL('word_dialog'), self.word_dialog) self.charSig.connect(self.update_character_dialog) - self.qcSig.connect(self.win_query_choice) - self.win = win self.pin_matrix_widget_class = pin_matrix_widget_class - self.device = device - self.dialog = None - self.done = threading.Event() self.character_dialog = None - def top_level_window(self): - return self.win.top_level_window() - - def watching_only_changed(self): - self.win.emit(SIGNAL('watching_only_changed')) - - def query_choice(self, msg, labels): - self.done.clear() - self.qcSig.emit(msg, labels) - self.done.wait() - return self.choice - - def show_message(self, msg, on_cancel=None): - self.win.emit(SIGNAL('message_dialog'), msg, on_cancel) - - def show_error(self, msg): - self.win.emit(SIGNAL('error_dialog'), msg) - - def finished(self): - self.win.emit(SIGNAL('clear_dialog')) - def get_char(self, msg): self.done.clear() self.charSig.emit(msg) t@@ -190,18 +154,6 @@ class QtHandler(QObject, PrintError): self.done.wait() return self.response - def get_word(self, msg): - self.done.clear() - self.win.emit(SIGNAL('word_dialog'), msg) - self.done.wait() - return self.word - - def get_passphrase(self, msg): - self.done.clear() - self.win.emit(SIGNAL('passphrase_dialog'), msg) - self.done.wait() - return self.passphrase - def pin_dialog(self, msg): # Needed e.g. when resetting a device self.clear_dialog() t@@ -216,58 +168,12 @@ class QtHandler(QObject, PrintError): self.response = str(matrix.get_value()) self.done.set() - def passphrase_dialog(self, msg): - d = PasswordDialog(self.top_level_window(), None, msg, PW_PASSPHRASE) - confirmed, p, passphrase = d.run() - if confirmed: - passphrase = BIP44_Wallet.normalize_passphrase(passphrase) - self.passphrase = passphrase - self.done.set() - - def word_dialog(self, msg): - dialog = WindowModalDialog(self.top_level_window(), "") - hbox = QHBoxLayout(dialog) - hbox.addWidget(QLabel(msg)) - text = QLineEdit() - text.setMaximumWidth(100) - text.returnPressed.connect(dialog.accept) - hbox.addWidget(text) - hbox.addStretch(1) - dialog.exec_() # Firmware cannot handle cancellation - self.word = unicode(text.text()) - self.done.set() - def update_character_dialog(self, msg): if not self.character_dialog: self.character_dialog = CharacterDialog(self.top_level_window()) self.character_dialog.get_char(msg.word_pos, msg.character_pos) self.done.set() - def message_dialog(self, msg, on_cancel): - # Called more than once during signing, to confirm output and fee - self.clear_dialog() - title = _('Please check your %s device') % self.device - self.dialog = dialog = WindowModalDialog(self.top_level_window(), title) - l = QLabel(msg) - vbox = QVBoxLayout(dialog) - vbox.addWidget(l) - if on_cancel: - dialog.rejected.connect(on_cancel) - vbox.addLayout(Buttons(CancelButton(dialog))) - dialog.show() - - def error_dialog(self, msg): - self.win.show_error(msg, parent=self.top_level_window()) - - def clear_dialog(self): - if self.dialog: - self.dialog.accept() - self.dialog = None - - def win_query_choice(self, msg, labels): - self.choice = self.win.query_choice(msg, labels) - self.done.set() - def request_trezor_init_settings(self, method, device): wizard = self.win