Merge branch 'client_thread'
This commit is contained in:
commit
eebabdf209
|
@ -14,6 +14,7 @@ from password_dialog import PasswordLayout, PW_NEW, PW_PASSPHRASE
|
||||||
|
|
||||||
from electrum.wallet import Wallet
|
from electrum.wallet import Wallet
|
||||||
from electrum.mnemonic import prepare_seed
|
from electrum.mnemonic import prepare_seed
|
||||||
|
from electrum.util import SilentException
|
||||||
from electrum.wizard import (WizardBase, UserCancelled,
|
from electrum.wizard import (WizardBase, UserCancelled,
|
||||||
MSG_ENTER_PASSWORD, MSG_RESTORE_PASSPHRASE,
|
MSG_ENTER_PASSWORD, MSG_RESTORE_PASSPHRASE,
|
||||||
MSG_COSIGNER, MSG_ENTER_SEED_OR_MPK,
|
MSG_COSIGNER, MSG_ENTER_SEED_OR_MPK,
|
||||||
|
@ -116,6 +117,11 @@ class InstallWizard(WindowModalDialog, WizardBase):
|
||||||
self.accept()
|
self.accept()
|
||||||
self.refresh_gui()
|
self.refresh_gui()
|
||||||
|
|
||||||
|
def on_error(self, exc_info):
|
||||||
|
if not isinstance(exc_info[1], SilentException):
|
||||||
|
traceback.print_exception(*exc_info)
|
||||||
|
self.show_error(str(exc_info[1]))
|
||||||
|
|
||||||
def set_icon(self, filename):
|
def set_icon(self, filename):
|
||||||
prior_filename, self.icon_filename = self.icon_filename, filename
|
prior_filename, self.icon_filename = self.icon_filename, filename
|
||||||
self.logo.setPixmap(QPixmap(filename).scaledToWidth(60))
|
self.logo.setPixmap(QPixmap(filename).scaledToWidth(60))
|
||||||
|
|
|
@ -37,9 +37,10 @@ import icons_rc
|
||||||
from electrum.bitcoin import COIN, is_valid, TYPE_ADDRESS
|
from electrum.bitcoin import COIN, is_valid, TYPE_ADDRESS
|
||||||
from electrum.plugins import run_hook
|
from electrum.plugins import run_hook
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import block_explorer, block_explorer_info, block_explorer_URL
|
from electrum.util import (block_explorer, block_explorer_info, format_time,
|
||||||
from electrum.util import format_satoshis, format_satoshis_plain, format_time
|
block_explorer_URL, format_satoshis, PrintError,
|
||||||
from electrum.util import PrintError, NotEnoughFunds, StoreDict
|
format_satoshis_plain, NotEnoughFunds, StoreDict,
|
||||||
|
SilentException)
|
||||||
from electrum import Transaction, mnemonic
|
from electrum import Transaction, mnemonic
|
||||||
from electrum import util, bitcoin, commands
|
from electrum import util, bitcoin, commands
|
||||||
from electrum import SimpleConfig, COIN_CHOOSERS, paymentrequest
|
from electrum import SimpleConfig, COIN_CHOOSERS, paymentrequest
|
||||||
|
@ -198,6 +199,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
self.raise_()
|
self.raise_()
|
||||||
|
|
||||||
def on_error(self, exc_info):
|
def on_error(self, exc_info):
|
||||||
|
if not isinstance(exc_info[1], SilentException):
|
||||||
traceback.print_exception(*exc_info)
|
traceback.print_exception(*exc_info)
|
||||||
self.show_error(str(exc_info[1]))
|
self.show_error(str(exc_info[1]))
|
||||||
|
|
||||||
|
@ -254,6 +256,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
run_hook('close_wallet', self.wallet)
|
run_hook('close_wallet', self.wallet)
|
||||||
|
|
||||||
def load_wallet(self, wallet):
|
def load_wallet(self, wallet):
|
||||||
|
wallet.thread = TaskThread(self, self.on_error)
|
||||||
self.wallet = wallet
|
self.wallet = wallet
|
||||||
self.update_recently_visited(wallet.storage.path)
|
self.update_recently_visited(wallet.storage.path)
|
||||||
self.import_old_contacts()
|
self.import_old_contacts()
|
||||||
|
@ -2059,14 +2062,14 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
d.setLayout(vbox)
|
d.setLayout(vbox)
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
def do_sign(self, address, message, signature, password):
|
def do_sign(self, address, message, signature, password):
|
||||||
message = unicode(message.toPlainText())
|
message = unicode(message.toPlainText()).encode('utf-8')
|
||||||
message = message.encode('utf-8')
|
task = partial(self.wallet.sign_message, str(address.text()),
|
||||||
sig = self.wallet.sign_message(str(address.text()), message, password)
|
message, password)
|
||||||
sig = base64.b64encode(sig)
|
def show_signed_message(sig):
|
||||||
signature.setText(sig)
|
signature.setText(base64.b64encode(sig))
|
||||||
|
self.wallet.thread.add(task, on_success=show_signed_message)
|
||||||
|
|
||||||
def do_verify(self, address, message, signature):
|
def do_verify(self, address, message, signature):
|
||||||
message = unicode(message.toPlainText())
|
message = unicode(message.toPlainText())
|
||||||
|
@ -2123,13 +2126,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
def do_decrypt(self, message_e, pubkey_e, encrypted_e, password):
|
def do_decrypt(self, message_e, pubkey_e, encrypted_e, password):
|
||||||
try:
|
cyphertext = str(encrypted_e.toPlainText())
|
||||||
decrypted = self.wallet.decrypt_message(str(pubkey_e.text()), str(encrypted_e.toPlainText()), password)
|
task = partial(self.wallet.decrypt_message, str(pubkey_e.text()),
|
||||||
message_e.setText(decrypted)
|
cyphertext, password)
|
||||||
except BaseException as e:
|
self.wallet.thread.add(task, on_success=message_e.setText)
|
||||||
traceback.print_exc(file=sys.stdout)
|
|
||||||
self.show_warning(str(e))
|
|
||||||
|
|
||||||
|
|
||||||
def do_encrypt(self, message_e, pubkey_e, encrypted_e):
|
def do_encrypt(self, message_e, pubkey_e, encrypted_e):
|
||||||
message = unicode(message_e.toPlainText())
|
message = unicode(message_e.toPlainText())
|
||||||
|
@ -2856,6 +2856,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
def clean_up(self):
|
def clean_up(self):
|
||||||
|
self.wallet.thread.stop()
|
||||||
if self.network:
|
if self.network:
|
||||||
self.network.unregister_callback(self.on_network)
|
self.network.unregister_callback(self.on_network)
|
||||||
self.config.set_key("is_maximized", self.isMaximized())
|
self.config.set_key("is_maximized", self.isMaximized())
|
||||||
|
|
|
@ -21,6 +21,10 @@ class InvalidPassword(Exception):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return _("Incorrect password")
|
return _("Incorrect password")
|
||||||
|
|
||||||
|
class SilentException(Exception):
|
||||||
|
'''An exception that should probably be suppressed from the user'''
|
||||||
|
pass
|
||||||
|
|
||||||
class MyEncoder(json.JSONEncoder):
|
class MyEncoder(json.JSONEncoder):
|
||||||
def default(self, obj):
|
def default(self, obj):
|
||||||
from transaction import Transaction
|
from transaction import Transaction
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from sys import stderr
|
from sys import stderr
|
||||||
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import PrintError
|
from electrum.util import PrintError, SilentException
|
||||||
|
|
||||||
|
|
||||||
class GuiMixin(object):
|
class GuiMixin(object):
|
||||||
|
@ -20,6 +20,16 @@ class GuiMixin(object):
|
||||||
'passphrase': _("Confirm on %s device to continue"),
|
'passphrase': _("Confirm on %s device to continue"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def callback_Failure(self, msg):
|
||||||
|
# BaseClient's unfortunate call() implementation forces us to
|
||||||
|
# raise exceptions on failure in order to unwind the stack.
|
||||||
|
# However, making the user acknowledge they cancelled
|
||||||
|
# gets old very quickly, so we suppress those.
|
||||||
|
if msg.code in (self.types.Failure_PinCancelled,
|
||||||
|
self.types.Failure_ActionCancelled):
|
||||||
|
raise SilentException()
|
||||||
|
raise RuntimeError(msg.message)
|
||||||
|
|
||||||
def callback_ButtonRequest(self, msg):
|
def callback_ButtonRequest(self, msg):
|
||||||
msg_code = self.msg_code_override or msg.code
|
msg_code = self.msg_code_override or msg.code
|
||||||
message = self.messages.get(msg_code, self.messages['default'])
|
message = self.messages.get(msg_code, self.messages['default'])
|
||||||
|
@ -65,6 +75,7 @@ class TrezorClientBase(GuiMixin, PrintError):
|
||||||
self.handler = handler
|
self.handler = handler
|
||||||
self.hid_id_ = hid_id
|
self.hid_id_ = hid_id
|
||||||
self.tx_api = plugin
|
self.tx_api = plugin
|
||||||
|
self.types = plugin.types
|
||||||
self.msg_code_override = None
|
self.msg_code_override = None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -172,9 +183,6 @@ class TrezorClientBase(GuiMixin, PrintError):
|
||||||
def wrapped(self, *args, **kwargs):
|
def wrapped(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
return func(self, *args, **kwargs)
|
return func(self, *args, **kwargs)
|
||||||
except BaseException as e:
|
|
||||||
self.handler.show_error(str(e))
|
|
||||||
raise e
|
|
||||||
finally:
|
finally:
|
||||||
self.handler.finished()
|
self.handler.finished()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import base64
|
import base64
|
||||||
import re
|
import re
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
@ -172,6 +173,7 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob):
|
||||||
|
|
||||||
def __init__(self, parent, config, name):
|
def __init__(self, parent, config, name):
|
||||||
BasePlugin.__init__(self, parent, config, name)
|
BasePlugin.__init__(self, parent, config, name)
|
||||||
|
self.main_thread = threading.current_thread()
|
||||||
self.device = self.wallet_class.device
|
self.device = self.wallet_class.device
|
||||||
self.wallet_class.plugin = self
|
self.wallet_class.plugin = self
|
||||||
self.prevent_timeout = time.time() + 3600 * 24 * 365
|
self.prevent_timeout = time.time() + 3600 * 24 * 365
|
||||||
|
@ -216,6 +218,8 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob):
|
||||||
return self.client_class(transport, handler, self, hid_id)
|
return self.client_class(transport, handler, self, hid_id)
|
||||||
|
|
||||||
def get_client(self, wallet, force_pair=True, check_firmware=True):
|
def get_client(self, wallet, force_pair=True, check_firmware=True):
|
||||||
|
assert self.main_thread != threading.current_thread()
|
||||||
|
|
||||||
'''check_firmware is ignored unless force_pair is True.'''
|
'''check_firmware is ignored unless force_pair is True.'''
|
||||||
client = self.device_manager().get_client(wallet, force_pair)
|
client = self.device_manager().get_client(wallet, force_pair)
|
||||||
|
|
||||||
|
@ -281,9 +285,11 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob):
|
||||||
(item, label, pin_protection, passphrase_protection) \
|
(item, label, pin_protection, passphrase_protection) \
|
||||||
= wallet.handler.request_trezor_init_settings(method, self.device)
|
= wallet.handler.request_trezor_init_settings(method, self.device)
|
||||||
|
|
||||||
client = self.get_client(wallet)
|
|
||||||
language = 'english'
|
language = 'english'
|
||||||
|
|
||||||
|
def initialize_device():
|
||||||
|
client = self.get_client(wallet)
|
||||||
|
|
||||||
if method == TIM_NEW:
|
if method == TIM_NEW:
|
||||||
strength = 64 * (item + 2) # 128, 192 or 256
|
strength = 64 * (item + 2) # 128, 192 or 256
|
||||||
client.reset_device(True, strength, passphrase_protection,
|
client.reset_device(True, strength, passphrase_protection,
|
||||||
|
@ -302,6 +308,8 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob):
|
||||||
client.load_device_by_xprv(item, pin, passphrase_protection,
|
client.load_device_by_xprv(item, pin, passphrase_protection,
|
||||||
label, language)
|
label, language)
|
||||||
|
|
||||||
|
wallet.thread.add(initialize_device)
|
||||||
|
|
||||||
def unpaired_clients(self, handler):
|
def unpaired_clients(self, handler):
|
||||||
'''Returns all connected, unpaired devices as a list of clients and a
|
'''Returns all connected, unpaired devices as a list of clients and a
|
||||||
list of descriptions.'''
|
list of descriptions.'''
|
||||||
|
|
|
@ -231,19 +231,25 @@ def qt_plugin_class(base_plugin_class):
|
||||||
window.statusBar().addPermanentWidget(window.tzb)
|
window.statusBar().addPermanentWidget(window.tzb)
|
||||||
wallet.handler = self.create_handler(window)
|
wallet.handler = self.create_handler(window)
|
||||||
# Trigger a pairing
|
# Trigger a pairing
|
||||||
self.get_client(wallet)
|
wallet.thread.add(partial(self.get_client, wallet))
|
||||||
|
|
||||||
def on_create_wallet(self, wallet, wizard):
|
def on_create_wallet(self, wallet, wizard):
|
||||||
assert type(wallet) == self.wallet_class
|
assert type(wallet) == self.wallet_class
|
||||||
wallet.handler = self.create_handler(wizard)
|
wallet.handler = self.create_handler(wizard)
|
||||||
|
wallet.thread = TaskThread(wizard, wizard.on_error)
|
||||||
self.select_device(wallet)
|
self.select_device(wallet)
|
||||||
wallet.create_hd_account(None)
|
# Create accounts in separate thread; wait until done
|
||||||
|
loop = QEventLoop()
|
||||||
|
wallet.thread.add(partial(wallet.create_hd_account, None),
|
||||||
|
on_done=loop.quit)
|
||||||
|
loop.exec_()
|
||||||
|
|
||||||
@hook
|
@hook
|
||||||
def receive_menu(self, menu, addrs, wallet):
|
def receive_menu(self, menu, addrs, wallet):
|
||||||
if type(wallet) == self.wallet_class and len(addrs) == 1:
|
if type(wallet) == self.wallet_class and len(addrs) == 1:
|
||||||
menu.addAction(_("Show on %s") % self.device,
|
def show_address():
|
||||||
lambda: self.show_address(wallet, addrs[0]))
|
wallet.thread.add(partial(self.show_address, wallet, addrs[0]))
|
||||||
|
menu.addAction(_("Show on %s") % self.device, show_address)
|
||||||
|
|
||||||
def settings_dialog(self, window):
|
def settings_dialog(self, window):
|
||||||
hid_id = self.choose_device(window)
|
hid_id = self.choose_device(window)
|
||||||
|
@ -296,23 +302,27 @@ class SettingsDialog(WindowModalDialog):
|
||||||
# wallet can be None, needn't be window.wallet
|
# wallet can be None, needn't be window.wallet
|
||||||
wallet = devmgr.wallet_by_hid_id(hid_id)
|
wallet = devmgr.wallet_by_hid_id(hid_id)
|
||||||
hs_rows, hs_cols = (64, 128)
|
hs_rows, hs_cols = (64, 128)
|
||||||
|
self.current_label=None
|
||||||
|
|
||||||
def get_client():
|
def invoke_client(method, *args, **kw_args):
|
||||||
client = devmgr.client_by_hid_id(hid_id, handler)
|
def task():
|
||||||
|
client = plugin.get_client(wallet, False)
|
||||||
if not client:
|
if not client:
|
||||||
self.show_error("Device not connected!")
|
|
||||||
raise RuntimeError("Device not connected")
|
raise RuntimeError("Device not connected")
|
||||||
return client
|
if method:
|
||||||
|
getattr(client, method)(*args, **kw_args)
|
||||||
|
update(client.features)
|
||||||
|
|
||||||
def update():
|
wallet.thread.add(task)
|
||||||
# self.features for outer scopes
|
|
||||||
client = get_client()
|
def update(features):
|
||||||
features = self.features = client.features
|
self.current_label = features.label
|
||||||
set_label_enabled()
|
set_label_enabled()
|
||||||
bl_hash = features.bootloader_hash.encode('hex')
|
bl_hash = features.bootloader_hash.encode('hex')
|
||||||
bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]])
|
bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]])
|
||||||
noyes = [_("No"), _("Yes")]
|
noyes = [_("No"), _("Yes")]
|
||||||
endis = [_("Enable Passphrases"), _("Disable Passphrases")]
|
endis = [_("Enable Passphrases"), _("Disable Passphrases")]
|
||||||
|
disen = [_("Disabled"), _("Enabled")]
|
||||||
setchange = [_("Set a PIN"), _("Change PIN")]
|
setchange = [_("Set a PIN"), _("Change PIN")]
|
||||||
|
|
||||||
version = "%d.%d.%d" % (features.major_version,
|
version = "%d.%d.%d" % (features.major_version,
|
||||||
|
@ -322,10 +332,10 @@ class SettingsDialog(WindowModalDialog):
|
||||||
|
|
||||||
device_label.setText(features.label)
|
device_label.setText(features.label)
|
||||||
pin_set_label.setText(noyes[features.pin_protection])
|
pin_set_label.setText(noyes[features.pin_protection])
|
||||||
|
passphrases_label.setText(disen[features.passphrase_protection])
|
||||||
bl_hash_label.setText(bl_hash)
|
bl_hash_label.setText(bl_hash)
|
||||||
label_edit.setText(features.label)
|
label_edit.setText(features.label)
|
||||||
device_id_label.setText(features.device_id)
|
device_id_label.setText(features.device_id)
|
||||||
serial_number_label.setText(client.hid_id())
|
|
||||||
initialized_label.setText(noyes[features.initialized])
|
initialized_label.setText(noyes[features.initialized])
|
||||||
version_label.setText(version)
|
version_label.setText(version)
|
||||||
coins_label.setText(coins)
|
coins_label.setText(coins)
|
||||||
|
@ -337,11 +347,10 @@ class SettingsDialog(WindowModalDialog):
|
||||||
language_label.setText(features.language)
|
language_label.setText(features.language)
|
||||||
|
|
||||||
def set_label_enabled():
|
def set_label_enabled():
|
||||||
label_apply.setEnabled(label_edit.text() != self.features.label)
|
label_apply.setEnabled(label_edit.text() != self.current_label)
|
||||||
|
|
||||||
def rename():
|
def rename():
|
||||||
get_client().change_label(unicode(label_edit.text()))
|
invoke_client('change_label', unicode(label_edit.text()))
|
||||||
update()
|
|
||||||
|
|
||||||
def toggle_passphrase():
|
def toggle_passphrase():
|
||||||
title = _("Confirm Toggle Passphrase Protection")
|
title = _("Confirm Toggle Passphrase Protection")
|
||||||
|
@ -354,9 +363,8 @@ class SettingsDialog(WindowModalDialog):
|
||||||
"Are you sure you want to proceed?") % plugin.device
|
"Are you sure you want to proceed?") % plugin.device
|
||||||
if not self.question(msg, title=title):
|
if not self.question(msg, title=title):
|
||||||
return
|
return
|
||||||
get_client().toggle_passphrase()
|
invoke_client('toggle_passphrase')
|
||||||
devmgr.unpair(hid_id)
|
devmgr.unpair(hid_id)
|
||||||
update()
|
|
||||||
|
|
||||||
def change_homescreen():
|
def change_homescreen():
|
||||||
from PIL import Image # FIXME
|
from PIL import Image # FIXME
|
||||||
|
@ -374,17 +382,16 @@ class SettingsDialog(WindowModalDialog):
|
||||||
img += '1' if pix[i, j] else '0'
|
img += '1' if pix[i, j] else '0'
|
||||||
img = ''.join(chr(int(img[i:i + 8], 2))
|
img = ''.join(chr(int(img[i:i + 8], 2))
|
||||||
for i in range(0, len(img), 8))
|
for i in range(0, len(img), 8))
|
||||||
get_client().change_homescreen(img)
|
invoke_client('change_homescreen', img)
|
||||||
|
|
||||||
def clear_homescreen():
|
def clear_homescreen():
|
||||||
get_client().change_homescreen('\x00')
|
invoke_client('change_homescreen', '\x00')
|
||||||
|
|
||||||
def set_pin(remove=False):
|
def set_pin():
|
||||||
get_client().set_pin(remove=remove)
|
invoke_client('set_pin', remove=False)
|
||||||
update()
|
|
||||||
|
|
||||||
def clear_pin():
|
def clear_pin():
|
||||||
set_pin(remove=True)
|
invoke_client('set_pin', remove=True)
|
||||||
|
|
||||||
def wipe_device():
|
def wipe_device():
|
||||||
if wallet and sum(wallet.get_balance()):
|
if wallet and sum(wallet.get_balance()):
|
||||||
|
@ -394,9 +401,8 @@ class SettingsDialog(WindowModalDialog):
|
||||||
if not self.question(msg, title=title,
|
if not self.question(msg, title=title,
|
||||||
icon=QMessageBox.Critical):
|
icon=QMessageBox.Critical):
|
||||||
return
|
return
|
||||||
get_client().wipe_device()
|
invoke_client('wipe_device')
|
||||||
devmgr.unpair(hid_id)
|
devmgr.unpair(hid_id)
|
||||||
update()
|
|
||||||
|
|
||||||
def slider_moved():
|
def slider_moved():
|
||||||
mins = timeout_slider.sliderPosition()
|
mins = timeout_slider.sliderPosition()
|
||||||
|
@ -406,8 +412,6 @@ class SettingsDialog(WindowModalDialog):
|
||||||
seconds = timeout_slider.sliderPosition() * 60
|
seconds = timeout_slider.sliderPosition() * 60
|
||||||
wallet.set_session_timeout(seconds)
|
wallet.set_session_timeout(seconds)
|
||||||
|
|
||||||
dialog_vbox = QVBoxLayout(self)
|
|
||||||
|
|
||||||
# Information tab
|
# Information tab
|
||||||
info_tab = QWidget()
|
info_tab = QWidget()
|
||||||
info_layout = QVBoxLayout(info_tab)
|
info_layout = QVBoxLayout(info_tab)
|
||||||
|
@ -415,9 +419,9 @@ class SettingsDialog(WindowModalDialog):
|
||||||
info_glayout.setColumnStretch(2, 1)
|
info_glayout.setColumnStretch(2, 1)
|
||||||
device_label = QLabel()
|
device_label = QLabel()
|
||||||
pin_set_label = QLabel()
|
pin_set_label = QLabel()
|
||||||
|
passphrases_label = QLabel()
|
||||||
version_label = QLabel()
|
version_label = QLabel()
|
||||||
device_id_label = QLabel()
|
device_id_label = QLabel()
|
||||||
serial_number_label = QLabel()
|
|
||||||
bl_hash_label = QLabel()
|
bl_hash_label = QLabel()
|
||||||
bl_hash_label.setWordWrap(True)
|
bl_hash_label.setWordWrap(True)
|
||||||
coins_label = QLabel()
|
coins_label = QLabel()
|
||||||
|
@ -427,9 +431,9 @@ class SettingsDialog(WindowModalDialog):
|
||||||
rows = [
|
rows = [
|
||||||
(_("Device Label"), device_label),
|
(_("Device Label"), device_label),
|
||||||
(_("PIN set"), pin_set_label),
|
(_("PIN set"), pin_set_label),
|
||||||
|
(_("Passphrases"), passphrases_label),
|
||||||
(_("Firmware Version"), version_label),
|
(_("Firmware Version"), version_label),
|
||||||
(_("Device ID"), device_id_label),
|
(_("Device ID"), device_id_label),
|
||||||
(_("Serial Number"), serial_number_label),
|
|
||||||
(_("Bootloader Hash"), bl_hash_label),
|
(_("Bootloader Hash"), bl_hash_label),
|
||||||
(_("Supported Coins"), coins_label),
|
(_("Supported Coins"), coins_label),
|
||||||
(_("Language"), language_label),
|
(_("Language"), language_label),
|
||||||
|
@ -580,8 +584,9 @@ class SettingsDialog(WindowModalDialog):
|
||||||
tabs.addTab(info_tab, _("Information"))
|
tabs.addTab(info_tab, _("Information"))
|
||||||
tabs.addTab(settings_tab, _("Settings"))
|
tabs.addTab(settings_tab, _("Settings"))
|
||||||
tabs.addTab(advanced_tab, _("Advanced"))
|
tabs.addTab(advanced_tab, _("Advanced"))
|
||||||
|
dialog_vbox = QVBoxLayout(self)
|
||||||
# Update information
|
|
||||||
update()
|
|
||||||
dialog_vbox.addWidget(tabs)
|
dialog_vbox.addWidget(tabs)
|
||||||
dialog_vbox.addLayout(Buttons(CloseButton(self)))
|
dialog_vbox.addLayout(Buttons(CloseButton(self)))
|
||||||
|
|
||||||
|
# Update information
|
||||||
|
invoke_client(None)
|
||||||
|
|
Loading…
Reference in New Issue