electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 45f25586ef586c998ae3e24d731a7c3f651d90f2
parent 83e925c0cd31e31c467343c39fba0f889157f21a
Author: ThomasV <thomasv@electrum.org>
Date:   Sun,  5 Mar 2017 13:30:57 +0100

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

Diffstat:
Mgui/qt/__init__.py | 33+++++++++++----------------------
Mgui/qt/installwizard.py | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mlib/base_wizard.py | 7+++----
Mlib/daemon.py | 3+++
4 files changed, 113 insertions(+), 41 deletions(-)

diff --git a/gui/qt/__init__.py b/gui/qt/__init__.py @@ -159,30 +159,19 @@ class ElectrumGui: w.bring_to_top() break else: - if not os.path.exists(path): - wizard = InstallWizard(self.config, self.app, self.plugins, path) - wallet = wizard.run_and_get_wallet() - if not wallet: - return + wallet = self.daemon.get_wallet(path) + if not wallet: + storage = WalletStorage(path) + if not storage.file_exists or storage.is_encrypted(): + 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) 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) if uri: w.pay_to_URI(uri) diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py @@ -6,8 +6,8 @@ from PyQt4.QtCore import * import PyQt4.QtCore as QtCore import electrum -from electrum.wallet import Wallet -from electrum.util import UserCancelled +from electrum.wallet import Wallet, WalletStorage +from electrum.util import UserCancelled, InvalidPassword from electrum.base_wizard import BaseWizard from electrum.i18n import _ @@ -147,6 +147,78 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): 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 if self.storage.requires_split(): self.hide() @@ -188,6 +260,11 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): self.run(action) return self.wallet + self.wallet = Wallet(self.storage) + self.terminate() + return self.wallet + + def finished(self): """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)) 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): self.title.setText("<b>%s</b>"%title if title else "") self.title.setVisible(bool(title)) @@ -218,6 +295,10 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): self.next_button.setFocus() self.main_widget.setVisible(True) 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_() if not result and raise_on_cancel: raise UserCancelled @@ -241,12 +322,12 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): def text_input(self, title, message, 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() def seed_input(self, title, message, is_seed, options): 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 @wizard_dialog @@ -289,13 +370,13 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): def show_seed_dialog(self, run_next, seed_text): title = _("Your wallet generation seed is:") slayout = SeedLayout(seed=seed_text, title=title, msg=True, options=['ext']) - self.set_main_layout(slayout) + self.exec_layout(slayout) return slayout.is_ext def pw_layout(self, msg, kind): playout = PasswordLayout(None, msg, kind, self.next_button) playout.encrypt_cb.setChecked(True) - self.set_main_layout(playout.layout()) + self.exec_layout(playout.layout()) return playout.new_password(), playout.encrypt_cb.isChecked() @wizard_dialog @@ -332,7 +413,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): def confirm(self, message, title): vbox = QVBoxLayout() vbox.addWidget(WWLabel(message)) - self.set_main_layout(vbox, title) + self.exec_layout(vbox, title) @wizard_dialog def action_dialog(self, action, run_next): @@ -355,7 +436,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): clayout = ChoicesLayout(message, c_titles) vbox = QVBoxLayout() vbox.addLayout(clayout.layout()) - self.set_main_layout(vbox, title) + self.exec_layout(vbox, title) action = c_values[clayout.selected_index()] return action @@ -364,7 +445,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): clayout = ChoicesLayout(msg, choices) vbox = QVBoxLayout() vbox.addLayout(clayout.layout()) - self.set_main_layout(vbox, '') + self.exec_layout(vbox, '') return clayout.selected_index() @wizard_dialog @@ -378,7 +459,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): line.textEdited.connect(f) vbox.addWidget(line) 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()) @wizard_dialog @@ -390,7 +471,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): vbox = QVBoxLayout() layout = SeedLayout(xpub, title=msg, icon=False) vbox.addLayout(layout.layout()) - self.set_main_layout(vbox, _('Master Public Key')) + self.exec_layout(vbox, _('Master Public Key')) return None def init_network(self, network): @@ -404,14 +485,14 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): title = _("How do you want to connect to a server? ") clayout = ChoicesLayout(message, choices) self.back_button.setText(_('Cancel')) - self.set_main_layout(clayout.layout(), title) + self.exec_layout(clayout.layout(), title) r = clayout.selected_index() if r == 0: auto_connect = True elif r == 1: auto_connect = True nlayout = NetworkChoiceLayout(network, self.config, wizard=True) - if self.set_main_layout(nlayout.layout()): + if self.exec_layout(nlayout.layout()): auto_connect = False else: auto_connect = True @@ -451,7 +532,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): vbox.addWidget(cw) vbox.addWidget(WWLabel(_("Choose the number of signatures needed to unlock funds in your wallet:"))) vbox.addLayout(grid) - self.set_main_layout(vbox, _("Multi-Signature Wallet")) + self.exec_layout(vbox, _("Multi-Signature Wallet")) m = int(m_edit.value()) n = int(n_edit.value()) return (m, n) diff --git a/lib/base_wizard.py b/lib/base_wizard.py @@ -32,10 +32,10 @@ from plugins import run_hook class BaseWizard(object): - def __init__(self, config, path): + def __init__(self, config, storage): super(BaseWizard, self).__init__() self.config = config - self.storage = WalletStorage(path) + self.storage = storage self.wallet = None self.stack = [] self.plugin = None @@ -72,9 +72,8 @@ class BaseWizard(object): def new(self): name = os.path.basename(self.storage.path) - title = _("Welcome to the Electrum installation wizard.") + title = _("Create '%s'"%name) message = '\n'.join([ - _("The wallet '%s' does not exist.") % name, _("What kind of wallet do you want to create?") ]) wallet_kinds = [ diff --git a/lib/daemon.py b/lib/daemon.py @@ -228,6 +228,9 @@ class Daemon(DaemonThread): path = wallet.storage.path self.wallets[path] = wallet + def get_wallet(self, path): + return self.wallets.get(path) + def stop_wallet(self, path): wallet = self.wallets.pop(path) wallet.stop_threads()