Start work on persistent install wizard
This commit is contained in:
@@ -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
|
|
||||||
|
|||||||
@@ -43,48 +43,52 @@ 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 show_seed_box_msg(seedphrase, sid=None):
|
def layout(self):
|
||||||
msg = _("Your wallet generation seed is") + ":"
|
return self.vbox
|
||||||
vbox = show_seed_box(msg, seedphrase, sid)
|
|
||||||
msg = ''.join([
|
|
||||||
"<p>",
|
|
||||||
_("Please save these %d words on paper (order is important).")%len(seedphrase.split()) + " ",
|
|
||||||
_("This seed will allow you to recover your wallet in case of computer failure.") + "<br/>",
|
|
||||||
"</p>",
|
|
||||||
"<b>" + _("WARNING") + ":</b> ",
|
|
||||||
"<ul>",
|
|
||||||
"<li>" + _("Never disclose your seed.") + "</li>",
|
|
||||||
"<li>" + _("Never type it on a website.") + "</li>",
|
|
||||||
"<li>" + _("Do not send your seed to a printer.") + "</li>",
|
|
||||||
"</ul>"
|
|
||||||
])
|
|
||||||
label2 = QLabel(msg)
|
|
||||||
label2.setWordWrap(True)
|
|
||||||
vbox.addWidget(label2)
|
|
||||||
vbox.addStretch(1)
|
|
||||||
return vbox
|
|
||||||
|
|
||||||
def show_seed_box(msg, seed, sid):
|
def seed_edit(self):
|
||||||
vbox, seed_e = enter_seed_box(msg, None, sid=sid, text=seed)
|
return self.seed_e
|
||||||
return vbox
|
|
||||||
|
|
||||||
def enter_seed_box(msg, window, sid=None, text=None):
|
def seed_and_warning_layout(self, seed, sid=None):
|
||||||
vbox = QVBoxLayout()
|
vbox = QVBoxLayout()
|
||||||
logo = QLabel()
|
vbox.addLayout(self.seed_layout(seed, sid))
|
||||||
logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56))
|
msg = ''.join([
|
||||||
logo.setMaximumWidth(60)
|
"<p>",
|
||||||
label = QLabel(msg)
|
_("Please save these %d words on paper (order is important). "),
|
||||||
label.setWordWrap(True)
|
_("This seed will allow you to recover your wallet in case "
|
||||||
if not text:
|
"of computer failure.") + "<br/>",
|
||||||
seed_e = ScanQRTextEdit()
|
"</p>",
|
||||||
seed_e.setTabChangesFocus(True)
|
"<b>" + _("WARNING") + ":</b> ",
|
||||||
else:
|
"<ul>",
|
||||||
seed_e = ShowQRTextEdit(text=text)
|
"<li>" + _("Never disclose your seed.") + "</li>",
|
||||||
seed_e.setMaximumHeight(130)
|
"<li>" + _("Never type it on a website.") + "</li>",
|
||||||
vbox.addWidget(label)
|
"<li>" + _("Do not send your seed to a printer.") + "</li>",
|
||||||
grid = QGridLayout()
|
"</ul>"
|
||||||
grid.addWidget(logo, 0, 0)
|
]) % len(seed.split())
|
||||||
grid.addWidget(seed_e, 0, 1)
|
label2 = QLabel(msg)
|
||||||
vbox.addLayout(grid)
|
label2.setWordWrap(True)
|
||||||
return vbox, seed_e
|
vbox.addWidget(label2)
|
||||||
|
return vbox
|
||||||
|
|
||||||
|
def seed_layout(self, seed, sid=None):
|
||||||
|
logo = QLabel()
|
||||||
|
logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56))
|
||||||
|
logo.setMaximumWidth(60)
|
||||||
|
if not seed:
|
||||||
|
seed_e = ScanQRTextEdit()
|
||||||
|
seed_e.setTabChangesFocus(True)
|
||||||
|
else:
|
||||||
|
seed_e = ShowQRTextEdit(text=seed)
|
||||||
|
seed_e.setMaximumHeight(100)
|
||||||
|
self.seed_e = seed_e
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
hbox.addWidget(logo)
|
||||||
|
hbox.addWidget(seed_e)
|
||||||
|
return hbox
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user