add file selector and password dialog to wizard (fix #1730)

This commit is contained in:
ThomasV 2017-03-05 13:30:57 +01:00
parent 83e925c0cd
commit 45f25586ef
4 changed files with 113 additions and 41 deletions

View File

@ -159,30 +159,19 @@ class ElectrumGui:
w.bring_to_top() w.bring_to_top()
break break
else: else:
if not os.path.exists(path): wallet = self.daemon.get_wallet(path)
wizard = InstallWizard(self.config, self.app, self.plugins, path) if not wallet:
wallet = wizard.run_and_get_wallet() storage = WalletStorage(path)
if not wallet: if not storage.file_exists or storage.is_encrypted():
return wizard = InstallWizard(self.config, self.app, self.plugins, storage)
wallet = wizard.run_and_get_wallet()
if not wallet:
return
else:
storage.read(None)
wallet = Wallet(storage)
wallet.start_threads(self.daemon.network) wallet.start_threads(self.daemon.network)
self.daemon.add_wallet(wallet) self.daemon.add_wallet(wallet)
else:
from password_dialog import PasswordDialog
msg = _("The file '%s' is encrypted.") % os.path.basename(path)
password_getter = lambda: PasswordDialog(msg=msg).run()
while True:
try:
wallet = self.daemon.load_wallet(path, password_getter)
break
except UserCancelled:
return
except InvalidPassword as e:
QMessageBox.information(None, _('Error'), str(e), _('OK'))
continue
except BaseException as e:
traceback.print_exc(file=sys.stdout)
QMessageBox.information(None, _('Error'), str(e), _('OK'))
return
w = self.create_window_for_wallet(wallet) w = self.create_window_for_wallet(wallet)
if uri: if uri:
w.pay_to_URI(uri) w.pay_to_URI(uri)

View File

@ -6,8 +6,8 @@ from PyQt4.QtCore import *
import PyQt4.QtCore as QtCore import PyQt4.QtCore as QtCore
import electrum import electrum
from electrum.wallet import Wallet from electrum.wallet import Wallet, WalletStorage
from electrum.util import UserCancelled from electrum.util import UserCancelled, InvalidPassword
from electrum.base_wizard import BaseWizard from electrum.base_wizard import BaseWizard
from electrum.i18n import _ from electrum.i18n import _
@ -147,6 +147,78 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
def run_and_get_wallet(self): def run_and_get_wallet(self):
def on_filename():
wallet_folder = os.path.dirname(self.storage.path)
path = unicode(QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder))
if path:
self.name_e.setText(path)
self.storage = WalletStorage(path)
update_layout()
def update_layout():
name = os.path.basename(self.storage.path)
vbox = QVBoxLayout()
hbox = QHBoxLayout()
hbox.addWidget(QLabel(_('Wallet') + ':'))
self.name_e = QLineEdit(text=name)
hbox.addWidget(self.name_e)
button = QPushButton(_('Choose...'))
button.clicked.connect(on_filename)
hbox.addWidget(button)
vbox.addLayout(hbox)
self.pw_e = None
if not self.storage.file_exists:
msg = _("This file does not exist.") + '\n' \
+ _("Press 'Next' to create this wallet, or chose another file.")
vbox.addWidget(QLabel(msg))
elif self.storage.file_exists and self.storage.is_encrypted():
msg = _("This file is encrypted.") + '\n' + _('Enter your password or choose another file.')
vbox.addWidget(QLabel(msg))
hbox2 = QHBoxLayout()
self.pw_e = QLineEdit('', self)
self.pw_e.setFixedWidth(150)
self.pw_e.setEchoMode(2)
hbox2.addWidget(QLabel(_('Password') + ':'))
hbox2.addWidget(self.pw_e)
hbox2.addStretch()
vbox.addLayout(hbox2)
else:
msg = _("Press 'Next' to open this wallet.")
vbox.addWidget(QLabel(msg))
self.set_layout(vbox, title=_('Electrum wallet'))
if self.pw_e:
self.pw_e.show()
self.pw_e.setFocus()
while True:
update_layout()
if self.storage.file_exists and not self.storage.is_encrypted():
self.storage.read(None)
break
if not self.loop.exec_():
return
if not self.storage.file_exists:
break
if self.storage.file_exists and self.storage.is_encrypted():
password = unicode(self.pw_e.text())
try:
self.storage.read(password)
break
except InvalidPassword as e:
QMessageBox.information(None, _('Error'), str(e), _('OK'))
continue
except BaseException as e:
traceback.print_exc(file=sys.stdout)
QMessageBox.information(None, _('Error'), str(e), _('OK'))
return
path = self.storage.path path = self.storage.path
if self.storage.requires_split(): if self.storage.requires_split():
self.hide() self.hide()
@ -188,6 +260,11 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
self.run(action) self.run(action)
return self.wallet return self.wallet
self.wallet = Wallet(self.storage)
self.terminate()
return self.wallet
def finished(self): def finished(self):
"""Called in hardware client wrapper, in order to close popups.""" """Called in hardware client wrapper, in order to close popups."""
@ -203,7 +280,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
self.logo.setPixmap(QPixmap(filename).scaledToWidth(60)) self.logo.setPixmap(QPixmap(filename).scaledToWidth(60))
return prior_filename return prior_filename
def set_main_layout(self, layout, title=None, raise_on_cancel=True, def set_layout(self, layout, title=None, raise_on_cancel=True,
next_enabled=True): next_enabled=True):
self.title.setText("<b>%s</b>"%title if title else "") self.title.setText("<b>%s</b>"%title if title else "")
self.title.setVisible(bool(title)) self.title.setVisible(bool(title))
@ -218,6 +295,10 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
self.next_button.setFocus() self.next_button.setFocus()
self.main_widget.setVisible(True) self.main_widget.setVisible(True)
self.please_wait.setVisible(False) self.please_wait.setVisible(False)
def exec_layout(self, layout, title=None, raise_on_cancel=True,
next_enabled=True):
self.set_layout(layout, title, next_enabled)
result = self.loop.exec_() result = self.loop.exec_()
if not result and raise_on_cancel: if not result and raise_on_cancel:
raise UserCancelled raise UserCancelled
@ -241,12 +322,12 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
def text_input(self, title, message, is_valid): def text_input(self, title, message, is_valid):
slayout = KeysLayout(parent=self, title=message, is_valid=is_valid) slayout = KeysLayout(parent=self, title=message, is_valid=is_valid)
self.set_main_layout(slayout, title, next_enabled=False) self.exec_layout(slayout, title, next_enabled=False)
return slayout.get_text() return slayout.get_text()
def seed_input(self, title, message, is_seed, options): def seed_input(self, title, message, is_seed, options):
slayout = SeedLayout(title=message, is_seed=is_seed, options=options, parent=self) slayout = SeedLayout(title=message, is_seed=is_seed, options=options, parent=self)
self.set_main_layout(slayout, title, next_enabled=False) self.exec_layout(slayout, title, next_enabled=False)
return slayout.get_seed(), slayout.is_bip39, slayout.is_ext return slayout.get_seed(), slayout.is_bip39, slayout.is_ext
@wizard_dialog @wizard_dialog
@ -289,13 +370,13 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
def show_seed_dialog(self, run_next, seed_text): def show_seed_dialog(self, run_next, seed_text):
title = _("Your wallet generation seed is:") title = _("Your wallet generation seed is:")
slayout = SeedLayout(seed=seed_text, title=title, msg=True, options=['ext']) slayout = SeedLayout(seed=seed_text, title=title, msg=True, options=['ext'])
self.set_main_layout(slayout) self.exec_layout(slayout)
return slayout.is_ext return slayout.is_ext
def pw_layout(self, msg, kind): def pw_layout(self, msg, kind):
playout = PasswordLayout(None, msg, kind, self.next_button) playout = PasswordLayout(None, msg, kind, self.next_button)
playout.encrypt_cb.setChecked(True) playout.encrypt_cb.setChecked(True)
self.set_main_layout(playout.layout()) self.exec_layout(playout.layout())
return playout.new_password(), playout.encrypt_cb.isChecked() return playout.new_password(), playout.encrypt_cb.isChecked()
@wizard_dialog @wizard_dialog
@ -332,7 +413,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
def confirm(self, message, title): def confirm(self, message, title):
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.addWidget(WWLabel(message)) vbox.addWidget(WWLabel(message))
self.set_main_layout(vbox, title) self.exec_layout(vbox, title)
@wizard_dialog @wizard_dialog
def action_dialog(self, action, run_next): def action_dialog(self, action, run_next):
@ -355,7 +436,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
clayout = ChoicesLayout(message, c_titles) clayout = ChoicesLayout(message, c_titles)
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.addLayout(clayout.layout()) vbox.addLayout(clayout.layout())
self.set_main_layout(vbox, title) self.exec_layout(vbox, title)
action = c_values[clayout.selected_index()] action = c_values[clayout.selected_index()]
return action return action
@ -364,7 +445,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
clayout = ChoicesLayout(msg, choices) clayout = ChoicesLayout(msg, choices)
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.addLayout(clayout.layout()) vbox.addLayout(clayout.layout())
self.set_main_layout(vbox, '') self.exec_layout(vbox, '')
return clayout.selected_index() return clayout.selected_index()
@wizard_dialog @wizard_dialog
@ -378,7 +459,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
line.textEdited.connect(f) line.textEdited.connect(f)
vbox.addWidget(line) vbox.addWidget(line)
vbox.addWidget(WWLabel(warning)) vbox.addWidget(WWLabel(warning))
self.set_main_layout(vbox, title, next_enabled=test(default)) self.exec_layout(vbox, title, next_enabled=test(default))
return ' '.join(unicode(line.text()).split()) return ' '.join(unicode(line.text()).split())
@wizard_dialog @wizard_dialog
@ -390,7 +471,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
vbox = QVBoxLayout() vbox = QVBoxLayout()
layout = SeedLayout(xpub, title=msg, icon=False) layout = SeedLayout(xpub, title=msg, icon=False)
vbox.addLayout(layout.layout()) vbox.addLayout(layout.layout())
self.set_main_layout(vbox, _('Master Public Key')) self.exec_layout(vbox, _('Master Public Key'))
return None return None
def init_network(self, network): def init_network(self, network):
@ -404,14 +485,14 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
title = _("How do you want to connect to a server? ") title = _("How do you want to connect to a server? ")
clayout = ChoicesLayout(message, choices) clayout = ChoicesLayout(message, choices)
self.back_button.setText(_('Cancel')) self.back_button.setText(_('Cancel'))
self.set_main_layout(clayout.layout(), title) self.exec_layout(clayout.layout(), title)
r = clayout.selected_index() r = clayout.selected_index()
if r == 0: if r == 0:
auto_connect = True auto_connect = True
elif r == 1: elif r == 1:
auto_connect = True auto_connect = True
nlayout = NetworkChoiceLayout(network, self.config, wizard=True) nlayout = NetworkChoiceLayout(network, self.config, wizard=True)
if self.set_main_layout(nlayout.layout()): if self.exec_layout(nlayout.layout()):
auto_connect = False auto_connect = False
else: else:
auto_connect = True auto_connect = True
@ -451,7 +532,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
vbox.addWidget(cw) vbox.addWidget(cw)
vbox.addWidget(WWLabel(_("Choose the number of signatures needed to unlock funds in your wallet:"))) vbox.addWidget(WWLabel(_("Choose the number of signatures needed to unlock funds in your wallet:")))
vbox.addLayout(grid) vbox.addLayout(grid)
self.set_main_layout(vbox, _("Multi-Signature Wallet")) self.exec_layout(vbox, _("Multi-Signature Wallet"))
m = int(m_edit.value()) m = int(m_edit.value())
n = int(n_edit.value()) n = int(n_edit.value())
return (m, n) return (m, n)

View File

@ -32,10 +32,10 @@ from plugins import run_hook
class BaseWizard(object): class BaseWizard(object):
def __init__(self, config, path): def __init__(self, config, storage):
super(BaseWizard, self).__init__() super(BaseWizard, self).__init__()
self.config = config self.config = config
self.storage = WalletStorage(path) self.storage = storage
self.wallet = None self.wallet = None
self.stack = [] self.stack = []
self.plugin = None self.plugin = None
@ -72,9 +72,8 @@ class BaseWizard(object):
def new(self): def new(self):
name = os.path.basename(self.storage.path) name = os.path.basename(self.storage.path)
title = _("Welcome to the Electrum installation wizard.") title = _("Create '%s'"%name)
message = '\n'.join([ message = '\n'.join([
_("The wallet '%s' does not exist.") % name,
_("What kind of wallet do you want to create?") _("What kind of wallet do you want to create?")
]) ])
wallet_kinds = [ wallet_kinds = [

View File

@ -228,6 +228,9 @@ class Daemon(DaemonThread):
path = wallet.storage.path path = wallet.storage.path
self.wallets[path] = wallet self.wallets[path] = wallet
def get_wallet(self, path):
return self.wallets.get(path)
def stop_wallet(self, path): def stop_wallet(self, path):
wallet = self.wallets.pop(path) wallet = self.wallets.pop(path)
wallet.stop_threads() wallet.stop_threads()