URI: 
       tStart work on persistent install wizard - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 2ae3543dc4e84e5e9c1816a54be50057bdb673e9
   DIR parent f7b39f49524b8f907783e82533d1196f3c232a79
  HTML Author: Neil Booth <kyuupichan@gmail.com>
       Date:   Tue, 12 Jan 2016 22:31:53 +0900
       
       Start work on persistent install wizard
       
       Diffstat:
         M gui/qt/installwizard.py             |     157 ++++++++++++++++++-------------
         M gui/qt/seed_dialog.py               |      88 ++++++++++++++++---------------
         M plugins/trustedcoin/qt.py           |       9 +++++++--
       
       3 files changed, 143 insertions(+), 111 deletions(-)
       ---
   DIR diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
       t@@ -20,6 +20,11 @@ from electrum.wizard import (WizardBase, UserCancelled,
                                     MSG_SHOW_MPK, MSG_VERIFY_SEED,
                                     MSG_GENERATING_WAIT)
        
       +def clean_text(seed_e):
       +    text = unicode(seed_e.toPlainText()).strip()
       +    text = ' '.join(text.split())
       +    return text
       +
        class CosignWidget(QWidget):
            size = 120
        
       t@@ -69,8 +74,64 @@ class InstallWizard(WindowModalDialog, WizardBase):
                self.setMinimumSize(575, 400)
                self.setMaximumSize(575, 400)
                self.connect(self, QtCore.SIGNAL('accept'), self.accept)
       -        self.stack = QStackedLayout()
       -        self.setLayout(self.stack)
       +        self.title = QLabel()
       +        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):
                '''Wrap the base wizard implementation with try/except blocks
       t@@ -80,28 +141,35 @@ class InstallWizard(WindowModalDialog, WizardBase):
                    wallet = super(InstallWizard, self).open_wallet(*args)
                except UserCancelled:
                    self.print_error("wallet creation cancelled by user")
       +            self.accept()
                return wallet
        
            def remove_from_recently_open(self, filename):
                self.config.remove_from_recently_open(filename)
        
       -    # Called by plugins
       -    def confirm(self, msg, icon=None):
       -        '''Returns True or False'''
       -        vbox = QVBoxLayout()
       -        self.set_layout(vbox)
       -        if icon:
       -            logo = QLabel()
       -            logo.setPixmap(icon)
       -            vbox.addWidget(logo)
       -        label = QLabel(msg)
       -        label.setWordWrap(True)
       -        vbox.addWidget(label)
       -        vbox.addStretch(1)
       -        vbox.addLayout(Buttons(CancelButton(self, _("Cancel")),
       -                               OkButton(self, _("Next"))))
       -        if not self.exec_():
       -            raise UserCancelled
       +    def request_seed(self, title, is_valid=None):
       +        is_valid = is_valid or Wallet.is_any
       +        slayout = seed_dialog.SeedLayout(None)
       +        self.next_button.setEnabled(False)
       +        def sanitized_seed():
       +            return clean_text(slayout.seed_edit())
       +        def set_enabled():
       +            self.next_button.setEnabled(is_valid(sanitized_seed()))
       +        slayout.seed_edit().textChanged.connect(set_enabled)
       +        self.set_main_layout(slayout.layout(), title)
       +        return sanitized_seed()
       +
       +    def show_seed(self, seed):
       +        title =  _("Your wallet generation seed is:")
       +        slayout = seed_dialog.SeedLayout(seed)
       +        self.set_main_layout(slayout.layout(), title)
       +
       +    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):
                """Show the user their seed.  Ask them to re-enter it.  Return
       t@@ -179,55 +247,17 @@ class InstallWizard(WindowModalDialog, WizardBase):
                actions = [_("Create a new wallet"),
                           _("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)
                wallet_clayout = ChoicesLayout(_("Wallet kind:"), wallet_kinds)
        
                vbox = QVBoxLayout()
       -        vbox.addWidget(main_label)
                vbox.addLayout(actions_clayout.layout())
                vbox.addLayout(wallet_clayout.layout())
       -        vbox.addStretch(1)
       -
       -        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
       -
       +        self.set_main_layout(vbox, title)
                action = ['create', 'restore'][actions_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):
                vbox = QVBoxLayout()
                scroll = QScrollArea()
       t@@ -263,7 +293,7 @@ class InstallWizard(WindowModalDialog, WizardBase):
                vbox.addLayout(Buttons(CancelButton(self), button))
                button.setEnabled(False)
                def get_texts():
       -            return [self.get_seed_text(entry) for entry in entries]
       +            return [clean_text(entry) for entry in entries]
                def set_enabled():
                    texts = get_texts()
                    is_valid = Wallet.is_xpub if xpub_hot else Wallet.is_any
       t@@ -360,10 +390,3 @@ class InstallWizard(WindowModalDialog, WizardBase):
                n = int(n_edit.value())
                wallet_type = '%dof%d'%(m,n)
                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
   DIR diff --git a/gui/qt/seed_dialog.py b/gui/qt/seed_dialog.py
       t@@ -43,48 +43,52 @@ def icon_filename(sid):
            else:
                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):
       -    msg =  _("Your wallet generation seed is") + ":"
       -    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 layout(self):
       +        return self.vbox
        
       -def show_seed_box(msg, seed, sid):
       -    vbox, seed_e = enter_seed_box(msg, None, sid=sid, text=seed)
       -    return vbox
       +    def seed_edit(self):
       +        return self.seed_e
        
       -def enter_seed_box(msg, window, sid=None, text=None):
       -    vbox = QVBoxLayout()
       -    logo = QLabel()
       -    logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56))
       -    logo.setMaximumWidth(60)
       -    label = QLabel(msg)
       -    label.setWordWrap(True)
       -    if not text:
       -        seed_e = ScanQRTextEdit()
       -        seed_e.setTabChangesFocus(True)
       -    else:
       -        seed_e = ShowQRTextEdit(text=text)
       -    seed_e.setMaximumHeight(130)
       -    vbox.addWidget(label)
       -    grid = QGridLayout()
       -    grid.addWidget(logo, 0, 0)
       -    grid.addWidget(seed_e, 0, 1)
       -    vbox.addLayout(grid)
       -    return vbox, seed_e
       +    def seed_and_warning_layout(self, seed, sid=None):
       +        vbox = QVBoxLayout()
       +        vbox.addLayout(self.seed_layout(seed, sid))
       +        msg = ''.join([
       +            "<p>",
       +            _("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/>",
       +            "</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>"
       +        ]) % 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
   DIR diff --git a/plugins/trustedcoin/qt.py b/plugins/trustedcoin/qt.py
       t@@ -103,9 +103,14 @@ class Plugin(TrustedCoinPlugin):
                                     on_finished)
        
            def show_disclaimer(self, wallet, window):
       -        icon = QPixmap(':icons/trustedcoin.png')
       -        window.confirm('\n\n'.join(DISCLAIMER), icon=icon)
       +        prior_icon = window.set_icon(':icons/trustedcoin.png')
       +        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)
       +        window.set_icon(prior_icon)
        
            @hook
            def abort_send(self, window):