Browse Source

Start work on persistent install wizard

283
Neil Booth 9 years ago
parent
commit
2ae3543dc4
  1. 157
      gui/qt/installwizard.py
  2. 52
      gui/qt/seed_dialog.py
  3. 9
      plugins/trustedcoin/qt.py

157
gui/qt/installwizard.py

@ -20,6 +20,11 @@ from electrum.wizard import (WizardBase, UserCancelled,
MSG_SHOW_MPK, MSG_VERIFY_SEED, MSG_SHOW_MPK, MSG_VERIFY_SEED,
MSG_GENERATING_WAIT) MSG_GENERATING_WAIT)
def clean_text(seed_e):
text = unicode(seed_e.toPlainText()).strip()
text = ' '.join(text.split())
return text
class CosignWidget(QWidget): class CosignWidget(QWidget):
size = 120 size = 120
@ -69,8 +74,64 @@ class InstallWizard(WindowModalDialog, WizardBase):
self.setMinimumSize(575, 400) self.setMinimumSize(575, 400)
self.setMaximumSize(575, 400) self.setMaximumSize(575, 400)
self.connect(self, QtCore.SIGNAL('accept'), self.accept) self.connect(self, QtCore.SIGNAL('accept'), self.accept)
self.stack = QStackedLayout() self.title = QLabel()
self.setLayout(self.stack) self.main_widget = QWidget()
self.cancel_button = QPushButton(_("Cancel"), self)
self.next_button = QPushButton(_("Next"), self)
self.next_button.setDefault(True)
self.logo = QLabel()
self.please_wait = QLabel(_("Please wait..."))
self.please_wait.setAlignment(Qt.AlignCenter)
self.icon_filename = None
self.loop = QEventLoop()
self.cancel_button.clicked.connect(lambda: self.loop.exit(False))
self.next_button.clicked.connect(lambda: self.loop.exit(True))
outer_vbox = QVBoxLayout(self)
inner_vbox = QVBoxLayout()
inner_vbox = QVBoxLayout()
inner_vbox.addWidget(self.title)
inner_vbox.addWidget(self.main_widget)
inner_vbox.addStretch(1)
inner_vbox.addWidget(self.please_wait)
inner_vbox.addStretch(1)
icon_vbox = QVBoxLayout()
icon_vbox.addWidget(self.logo)
icon_vbox.addStretch(1)
hbox = QHBoxLayout()
hbox.addLayout(icon_vbox)
hbox.addLayout(inner_vbox)
hbox.setStretchFactor(inner_vbox, 1)
outer_vbox.addLayout(hbox)
outer_vbox.addLayout(Buttons(self.cancel_button, self.next_button))
self.set_icon(':icons/electrum.png')
self.show()
self.raise_()
def set_icon(self, filename):
prior_filename, self.icon_filename = self.icon_filename, filename
self.logo.setPixmap(QPixmap(filename).scaledToWidth(70))
return prior_filename
def set_main_layout(self, layout, title):
self.title.setText(title)
prior_layout = self.main_widget.layout()
if prior_layout:
QWidget().setLayout(prior_layout)
self.main_widget.setLayout(layout)
self.cancel_button.setEnabled(True)
self.next_button.setEnabled(True)
self.main_widget.setVisible(True)
self.please_wait.setVisible(False)
if not self.loop.exec_():
raise UserCancelled
self.title.setText("")
self.cancel_button.setEnabled(False)
self.next_button.setEnabled(False)
self.main_widget.setVisible(False)
self.please_wait.setVisible(True)
# For some reason, to refresh the GUI this needs to be called twice
self.app.processEvents()
self.app.processEvents()
def open_wallet(self, *args): def open_wallet(self, *args):
'''Wrap the base wizard implementation with try/except blocks '''Wrap the base wizard implementation with try/except blocks
@ -80,28 +141,35 @@ class InstallWizard(WindowModalDialog, WizardBase):
wallet = super(InstallWizard, self).open_wallet(*args) wallet = super(InstallWizard, self).open_wallet(*args)
except UserCancelled: except UserCancelled:
self.print_error("wallet creation cancelled by user") self.print_error("wallet creation cancelled by user")
self.accept()
return wallet return wallet
def remove_from_recently_open(self, filename): def remove_from_recently_open(self, filename):
self.config.remove_from_recently_open(filename) self.config.remove_from_recently_open(filename)
# Called by plugins def request_seed(self, title, is_valid=None):
def confirm(self, msg, icon=None): is_valid = is_valid or Wallet.is_any
'''Returns True or False''' slayout = seed_dialog.SeedLayout(None)
vbox = QVBoxLayout() self.next_button.setEnabled(False)
self.set_layout(vbox) def sanitized_seed():
if icon: return clean_text(slayout.seed_edit())
logo = QLabel() def set_enabled():
logo.setPixmap(icon) self.next_button.setEnabled(is_valid(sanitized_seed()))
vbox.addWidget(logo) slayout.seed_edit().textChanged.connect(set_enabled)
label = QLabel(msg) self.set_main_layout(slayout.layout(), title)
label.setWordWrap(True) return sanitized_seed()
vbox.addWidget(label)
vbox.addStretch(1) def show_seed(self, seed):
vbox.addLayout(Buttons(CancelButton(self, _("Cancel")), title = _("Your wallet generation seed is:")
OkButton(self, _("Next")))) slayout = seed_dialog.SeedLayout(seed)
if not self.exec_(): self.set_main_layout(slayout.layout(), title)
raise UserCancelled
def verify_seed(self, seed, is_valid=None):
while True:
r = self.request_seed(MSG_VERIFY_SEED, is_valid)
if prepare_seed(r) == prepare_seed(seed):
return
self.show_error(_('Incorrect seed'))
def show_and_verify_seed(self, seed, is_valid=None): def show_and_verify_seed(self, seed, is_valid=None):
"""Show the user their seed. Ask them to re-enter it. Return """Show the user their seed. Ask them to re-enter it. Return
@ -179,55 +247,17 @@ class InstallWizard(WindowModalDialog, WizardBase):
actions = [_("Create a new wallet"), actions = [_("Create a new wallet"),
_("Restore a wallet or import keys")] _("Restore a wallet or import keys")]
main_label = QLabel(_("Electrum could not find an existing wallet.")) title = _("Electrum could not find an existing wallet.")
actions_clayout = ChoicesLayout(_("What do you want to do?"), actions) actions_clayout = ChoicesLayout(_("What do you want to do?"), actions)
wallet_clayout = ChoicesLayout(_("Wallet kind:"), wallet_kinds) wallet_clayout = ChoicesLayout(_("Wallet kind:"), wallet_kinds)
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.addWidget(main_label)
vbox.addLayout(actions_clayout.layout()) vbox.addLayout(actions_clayout.layout())
vbox.addLayout(wallet_clayout.layout()) vbox.addLayout(wallet_clayout.layout())
vbox.addStretch(1) self.set_main_layout(vbox, title)
OK = OkButton(self, _('Next'))
vbox.addLayout(Buttons(CancelButton(self), OK))
self.set_layout(vbox)
OK.setDefault(True)
self.raise_()
if not self.exec_():
raise UserCancelled
action = ['create', 'restore'][actions_clayout.selected_index()] action = ['create', 'restore'][actions_clayout.selected_index()]
return action, wallet_clayout.selected_index() return action, wallet_clayout.selected_index()
def verify_seed(self, seed, is_valid=None):
while True:
r = self.request_seed(MSG_VERIFY_SEED, is_valid)
if prepare_seed(r) == prepare_seed(seed):
return
self.show_error(_('Incorrect seed'))
def get_seed_text(self, seed_e):
text = unicode(seed_e.toPlainText()).strip()
text = ' '.join(text.split())
return text
def request_seed(self, msg, is_valid=None):
is_valid = is_valid or Wallet.is_any
vbox, seed_e = seed_dialog.enter_seed_box(msg, self)
vbox.addStretch(1)
button = OkButton(self, _('Next'))
vbox.addLayout(Buttons(CancelButton(self), button))
button.setEnabled(False)
def set_enabled():
button.setEnabled(is_valid(self.get_seed_text(seed_e)))
seed_e.textChanged.connect(set_enabled)
self.set_layout(vbox)
if not self.exec_():
raise UserCancelled
return self.get_seed_text(seed_e)
def request_many(self, n, xpub_hot=None): def request_many(self, n, xpub_hot=None):
vbox = QVBoxLayout() vbox = QVBoxLayout()
scroll = QScrollArea() scroll = QScrollArea()
@ -263,7 +293,7 @@ class InstallWizard(WindowModalDialog, WizardBase):
vbox.addLayout(Buttons(CancelButton(self), button)) vbox.addLayout(Buttons(CancelButton(self), button))
button.setEnabled(False) button.setEnabled(False)
def get_texts(): def get_texts():
return [self.get_seed_text(entry) for entry in entries] return [clean_text(entry) for entry in entries]
def set_enabled(): def set_enabled():
texts = get_texts() texts = get_texts()
is_valid = Wallet.is_xpub if xpub_hot else Wallet.is_any is_valid = Wallet.is_xpub if xpub_hot else Wallet.is_any
@ -360,10 +390,3 @@ class InstallWizard(WindowModalDialog, WizardBase):
n = int(n_edit.value()) n = int(n_edit.value())
wallet_type = '%dof%d'%(m,n) wallet_type = '%dof%d'%(m,n)
return wallet_type return wallet_type
def show_seed(self, seed):
vbox = seed_dialog.show_seed_box_msg(seed, None)
vbox.addLayout(Buttons(CancelButton(self), OkButton(self, _("Next"))))
self.set_layout(vbox)
if not self.exec_():
raise UserCancelled

52
gui/qt/seed_dialog.py

@ -43,14 +43,27 @@ def icon_filename(sid):
else: else:
return ":icons/seed.png" return ":icons/seed.png"
class SeedLayout(object):
def __init__(self, seed, sid=None):
if seed:
self.vbox = self.seed_and_warning_layout(seed, sid)
else:
self.vbox = self.seed_layout(seed, sid)
def layout(self):
return self.vbox
def show_seed_box_msg(seedphrase, sid=None): def seed_edit(self):
msg = _("Your wallet generation seed is") + ":" return self.seed_e
vbox = show_seed_box(msg, seedphrase, sid)
def seed_and_warning_layout(self, seed, sid=None):
vbox = QVBoxLayout()
vbox.addLayout(self.seed_layout(seed, sid))
msg = ''.join([ msg = ''.join([
"<p>", "<p>",
_("Please save these %d words on paper (order is important).")%len(seedphrase.split()) + " ", _("Please save these %d words on paper (order is important). "),
_("This seed will allow you to recover your wallet in case of computer failure.") + "<br/>", _("This seed will allow you to recover your wallet in case "
"of computer failure.") + "<br/>",
"</p>", "</p>",
"<b>" + _("WARNING") + ":</b> ", "<b>" + _("WARNING") + ":</b> ",
"<ul>", "<ul>",
@ -58,33 +71,24 @@ def show_seed_box_msg(seedphrase, sid=None):
"<li>" + _("Never type it on a website.") + "</li>", "<li>" + _("Never type it on a website.") + "</li>",
"<li>" + _("Do not send your seed to a printer.") + "</li>", "<li>" + _("Do not send your seed to a printer.") + "</li>",
"</ul>" "</ul>"
]) ]) % len(seed.split())
label2 = QLabel(msg) label2 = QLabel(msg)
label2.setWordWrap(True) label2.setWordWrap(True)
vbox.addWidget(label2) vbox.addWidget(label2)
vbox.addStretch(1)
return vbox return vbox
def show_seed_box(msg, seed, sid): def seed_layout(self, seed, sid=None):
vbox, seed_e = enter_seed_box(msg, None, sid=sid, text=seed)
return vbox
def enter_seed_box(msg, window, sid=None, text=None):
vbox = QVBoxLayout()
logo = QLabel() logo = QLabel()
logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56)) logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56))
logo.setMaximumWidth(60) logo.setMaximumWidth(60)
label = QLabel(msg) if not seed:
label.setWordWrap(True)
if not text:
seed_e = ScanQRTextEdit() seed_e = ScanQRTextEdit()
seed_e.setTabChangesFocus(True) seed_e.setTabChangesFocus(True)
else: else:
seed_e = ShowQRTextEdit(text=text) seed_e = ShowQRTextEdit(text=seed)
seed_e.setMaximumHeight(130) seed_e.setMaximumHeight(100)
vbox.addWidget(label) self.seed_e = seed_e
grid = QGridLayout() hbox = QHBoxLayout()
grid.addWidget(logo, 0, 0) hbox.addWidget(logo)
grid.addWidget(seed_e, 0, 1) hbox.addWidget(seed_e)
vbox.addLayout(grid) return hbox
return vbox, seed_e

9
plugins/trustedcoin/qt.py

@ -103,9 +103,14 @@ class Plugin(TrustedCoinPlugin):
on_finished) on_finished)
def show_disclaimer(self, wallet, window): def show_disclaimer(self, wallet, window):
icon = QPixmap(':icons/trustedcoin.png') prior_icon = window.set_icon(':icons/trustedcoin.png')
window.confirm('\n\n'.join(DISCLAIMER), icon=icon) label = QLabel('\n\n'.join(DISCLAIMER))
label.setWordWrap(True)
vbox = QVBoxLayout()
vbox.addWidget(label)
window.set_main_layout(vbox, _("Two-Factor Authentication"))
self.set_enabled(wallet, True) self.set_enabled(wallet, True)
window.set_icon(prior_icon)
@hook @hook
def abort_send(self, window): def abort_send(self, window):

Loading…
Cancel
Save