electrum

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

commit 0219687d4168b80fa85b9dace7c17553a3a92af4
parent 576500aa2920ac657ae04723472178b213360ce2
Author: Neil Booth <kyuupichan@gmail.com>
Date:   Wed, 13 Jan 2016 19:20:58 +0900

Some work on multisig.

Diffstat:
Mgui/qt/installwizard.py | 82+++++++++++++++++++++++++++++--------------------------------------------------
Mgui/qt/seed_dialog.py | 91++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mgui/qt/util.py | 10+++++++---
Mplugins/trustedcoin/qt.py | 2+-
4 files changed, 89 insertions(+), 96 deletions(-)

diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py @@ -7,7 +7,7 @@ import PyQt4.QtCore as QtCore import electrum from electrum.i18n import _ -import seed_dialog +from seed_dialog import SeedDisplayLayout, SeedWarningLayout, SeedInputLayout from network_dialog import NetworkDialog from util import * from password_dialog import PasswordLayout, PW_NEW, PW_PASSPHRASE @@ -32,6 +32,8 @@ class CosignWidget(QWidget): QWidget.__init__(self) self.R = QRect(0, 0, self.size, self.size) self.setGeometry(self.R) + self.setMinimumHeight(self.size) + self.setMaximumHeight(self.size) self.m = m self.n = n @@ -74,8 +76,7 @@ class InstallWizard(WindowModalDialog, WizardBase): self.setMinimumSize(518, 360) self.setMaximumSize(518, 360) self.connect(self, QtCore.SIGNAL('accept'), self.accept) - self.title = QLabel() - self.title.setWordWrap(True) + self.title = WWLabel() self.main_widget = QWidget() self.cancel_button = QPushButton(_("Cancel"), self) self.next_button = QPushButton(_("Next"), self) @@ -100,13 +101,12 @@ class InstallWizard(WindowModalDialog, WizardBase): icon_vbox.addStretch(1) hbox = QHBoxLayout() hbox.addLayout(icon_vbox) + hbox.addSpacing(5) 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 @@ -120,6 +120,9 @@ class InstallWizard(WindowModalDialog, WizardBase): prior_layout = self.main_widget.layout() if prior_layout: QWidget().setLayout(prior_layout) + else: + self.show() + self.raise_() self.main_widget.setLayout(layout) self.cancel_button.setEnabled(True) self.next_button.setEnabled(True) @@ -155,7 +158,7 @@ class InstallWizard(WindowModalDialog, WizardBase): def request_seed(self, title, is_valid=None): is_valid = is_valid or Wallet.is_any - slayout = seed_dialog.SeedLayout(None) + slayout = SeedInputLayout() self.next_button.setEnabled(False) def sanitized_seed(): return clean_text(slayout.seed_edit()) @@ -167,7 +170,7 @@ class InstallWizard(WindowModalDialog, WizardBase): def show_seed(self, seed): title = _("Your wallet generation seed is:") - slayout = seed_dialog.SeedLayout(seed) + slayout = SeedWarningLayout(seed) self.set_main_layout(slayout.layout(), title) def verify_seed(self, seed, is_valid=None): @@ -185,11 +188,8 @@ class InstallWizard(WindowModalDialog, WizardBase): self.verify_seed(seed, is_valid) def pw_layout(self, msg, kind): - hbox = QHBoxLayout() playout = PasswordLayout(None, msg, kind, self.next_button) - hbox.addLayout(playout.layout()) - #hbox.addStretch(1) - self.set_main_layout(hbox) + self.set_main_layout(playout.layout()) return playout.new_password() def request_passphrase(self, device_text, restore=True): @@ -234,13 +234,6 @@ class InstallWizard(WindowModalDialog, WizardBase): self.please_wait.setText(MSG_GENERATING_WAIT) self.refresh_gui() - def set_layout(self, layout): - w = QWidget() - w.setLayout(layout) - self.stack.addWidget(w) - self.stack.setCurrentWidget(w) - self.show() - def query_create_or_restore(self, wallet_kinds): """Ask the user what they want to do, and which wallet kind. wallet_kinds is an array of translated wallet descriptions. @@ -264,37 +257,30 @@ class InstallWizard(WindowModalDialog, WizardBase): def request_many(self, n, xpub_hot=None): vbox = QVBoxLayout() scroll = QScrollArea() - scroll.setEnabled(True) scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.NoFrame) vbox.addWidget(scroll) w = QWidget() + innerVbox = QVBoxLayout(w) scroll.setWidget(w) - innerVbox = QVBoxLayout() - w.setLayout(innerVbox) - entries = [] + if xpub_hot: - vbox0 = seed_dialog.show_seed_box(MSG_SHOW_MPK, xpub_hot, 'hot') + layout = SeedDisplayLayout(xpub_hot, title=MSG_SHOW_MPK, sid='hot') else: - vbox0, seed_e1 = seed_dialog.enter_seed_box(MSG_ENTER_SEED_OR_MPK, self, 'hot') - entries.append(seed_e1) - innerVbox.addLayout(vbox0) + layout = SeedInputLayout(title=MSG_ENTER_SEED_OR_MPK, sid='hot') + entries.append(slayout.seed_edit()) + innerVbox.addLayout(layout.layout()) for i in range(n): - if xpub_hot: - msg = MSG_COSIGNER % (i + 1) - else: - msg = MSG_ENTER_SEED_OR_MPK - vbox2, seed_e2 = seed_dialog.enter_seed_box(msg, self, 'cold') - innerVbox.addLayout(vbox2) - entries.append(seed_e2) + msg = MSG_COSIGNER % (i + 1) if xpub_hot else MSG_ENTER_SEED_OR_MPK + layout = SeedInputLayout(title=msg, sid='cold') + innerVbox.addLayout(layout.layout()) + entries.append(layout.seed_edit()) - vbox.addStretch(1) - button = OkButton(self, _('Next')) - vbox.addLayout(Buttons(CancelButton(self), button)) - button.setEnabled(False) + self.next_button.setEnabled(False) def get_texts(): return [clean_text(entry) for entry in entries] def set_enabled(): @@ -304,12 +290,10 @@ class InstallWizard(WindowModalDialog, WizardBase): if xpub_hot: texts.append(xpub_hot) has_dups = len(set(texts)) < len(texts) - button.setEnabled(all_valid and not has_dups) + self.next_button.setEnabled(all_valid and not has_dups) for e in entries: e.textChanged.connect(set_enabled) - self.set_layout(vbox) - if not self.exec_(): - raise UserCancelled + self.set_main_layout(vbox) return get_texts() def network_dialog(self, network): @@ -355,14 +339,7 @@ class InstallWizard(WindowModalDialog, WizardBase): return clayout.selected_index() def query_multisig(self, action): - vbox = QVBoxLayout() - self.set_layout(vbox) - vbox.addWidget(QLabel(_("Multi Signature Wallet"))) - cw = CosignWidget(2, 2) - vbox.addWidget(cw, 1) - vbox.addWidget(QLabel(_("Please choose the number of signatures needed to unlock funds in your wallet") + ':')) - m_edit = QSpinBox() n_edit = QSpinBox() m_edit.setValue(2) @@ -384,11 +361,12 @@ class InstallWizard(WindowModalDialog, WizardBase): hbox.addWidget(QLabel(_('signatures'))) hbox.addStretch(1) + vbox = QVBoxLayout() + vbox.addWidget(cw) + vbox.addWidget(WWLabel(_("Choose the number of signatures needed " + "to unlock funds in your wallet:"))) vbox.addLayout(hbox) - vbox.addStretch(1) - vbox.addLayout(Buttons(CancelButton(self), OkButton(self, _('Next')))) - if not self.exec_(): - raise UserCancelled + self.set_main_layout(vbox, _("Multi-Signature Wallet")) m = int(m_edit.value()) n = int(n_edit.value()) wallet_type = '%dof%d'%(m,n) diff --git a/gui/qt/seed_dialog.py b/gui/qt/seed_dialog.py @@ -18,23 +18,11 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * -import PyQt4.QtCore as QtCore from electrum.i18n import _ from util import * from qrtextedit import ShowQRTextEdit, ScanQRTextEdit -class SeedDialog(WindowModalDialog): - def __init__(self, parent, seed, imported_keys): - WindowModalDialog.__init__(self, parent, ('Electrum - ' + _('Seed'))) - self.setMinimumWidth(400) - vbox = show_seed_box_msg(seed) - if imported_keys: - vbox.addWidget(QLabel("<b>"+_("WARNING")+":</b> " + _("Your wallet contains imported keys. These keys cannot be recovered from seed.") + "</b><p>")) - vbox.addLayout(Buttons(CloseButton(self))) - self.setLayout(vbox) - - def icon_filename(sid): if sid == 'cold': return ":icons/cold_seed.png" @@ -43,22 +31,61 @@ def icon_filename(sid): else: return ":icons/seed.png" -class SeedLayout(object): - def __init__(self, seed, sid=None): +class SeedDialog(WindowModalDialog): + def __init__(self, parent, seed, imported_keys): + WindowModalDialog.__init__(self, parent, ('Electrum - ' + _('Seed'))) + self.setMinimumWidth(400) + vbox = QVBoxLayout(self) + vbox.addLayout(SeedDisplayLayout(seed)) + if imported_keys: + warning = ("<b>" + _("WARNING") + ":</b> " + + _("Your wallet contains imported keys. These keys " + "cannot be recovered from your seed.") + "</b><p>") + vbox.addWidget(WWLabel(warning)) + vbox.addLayout(Buttons(CloseButton(self))) + + +class SeedLayoutBase(object): + def _seed_layout(self, seed=None, title=None, sid=None): + logo = QLabel() + logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56)) + logo.setMaximumWidth(60) if seed: - self.vbox = self.seed_and_warning_layout(seed, sid) + self.seed_e = ShowQRTextEdit() + self.seed_e.setText(seed) else: - self.vbox = self.seed_layout(seed, sid) + self.seed_e = ScanQRTextEdit() + self.seed_e.setTabChangesFocus(True) + self.seed_e.setMaximumHeight(75) + hbox = QHBoxLayout() + hbox.addWidget(logo) + hbox.addWidget(self.seed_e) + if not title: + return hbox + vbox = QVBoxLayout() + vbox.addWidget(WWLabel(title)) + vbox.addLayout(hbox) + return vbox def layout(self): - return self.vbox + return self.layout_ def seed_edit(self): return self.seed_e - def seed_and_warning_layout(self, seed, sid=None): - vbox = QVBoxLayout() - vbox.addLayout(self.seed_layout(seed, sid)) + +class SeedInputLayout(SeedLayoutBase): + def __init__(self, title=None, sid=None): + self.layout_ = self._seed_layout(title=title, sid=sid) + + +class SeedDisplayLayout(SeedLayoutBase): + def __init__(self, seed, title=None, sid=None): + self.layout_ = self._seed_layout(seed=seed, title=title, sid=sid) + + +class SeedWarningLayout(SeedLayoutBase): + def __init__(self, seed, title=None): msg = ''.join([ "<p>", _("Please save these %d words on paper (order is important). "), @@ -72,23 +99,7 @@ class SeedLayout(object): "<li>" + _("Do not send your seed to a printer.") + "</li>", "</ul>" ]) % len(seed.split()) - label2 = QLabel(msg) - label2.setWordWrap(True) - 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 + vbox = QVBoxLayout() + vbox.addLayout(self._seed_layout(seed=seed, title=title)) + vbox.addWidget(WWLabel(msg)) + self.layout_ = vbox diff --git a/gui/qt/util.py b/gui/qt/util.py @@ -86,6 +86,12 @@ class ThreadedButton(QPushButton): t.start() +class WWLabel(QLabel): + def __init__ (self, text="", parent=None): + QLabel.__init__(self, text, parent) + self.setWordWrap(True) + + class HelpLabel(QLabel): def __init__(self, text, help_text): @@ -272,9 +278,7 @@ class ChoicesLayout(object): def __init__(self, msg, choices, on_clicked=None): vbox = QVBoxLayout() if len(msg) > 50: - label = QLabel(msg) - label.setWordWrap(True) - vbox.addWidget(label) + vbox.addWidget(WWLabel(msg)) msg = "" gb2 = QGroupBox(msg) vbox.addWidget(gb2) diff --git a/plugins/trustedcoin/qt.py b/plugins/trustedcoin/qt.py @@ -108,7 +108,7 @@ class Plugin(TrustedCoinPlugin): label.setWordWrap(True) vbox = QVBoxLayout() vbox.addWidget(label) - window.set_main_layout(vbox, _("Two-Factor Authentication")) + window.set_main_layout(vbox) self.set_enabled(wallet, True) window.set_icon(prior_icon)