text: 
  import os
  import sys
  import threading
  import traceback
  
  from PyQt5.QtCore import *
  from PyQt5.QtGui import *
  from PyQt5.QtWidgets import *
  
  from electrum_axe.wallet import Wallet
  from electrum_axe.storage import WalletStorage
  from electrum_axe.util import UserCancelled, InvalidPassword
  from electrum_axe.base_wizard import BaseWizard, HWD_SETUP_DECRYPT_WALLET, GoBack
  from electrum_axe.i18n import _
  
  from .seed_dialog import SeedLayout, KeysLayout
  from .network_dialog import NetworkChoiceLayout
  from .util import *
  from .password_dialog import PasswordLayout, PasswordLayoutForHW, PW_NEW
  
  
  MSG_ENTER_PASSWORD = _("Choose a password to encrypt your wallet keys.") + '\n'\
                       + _("Leave this field empty if you want to disable encryption.")
  MSG_HW_STORAGE_ENCRYPTION = _("Set wallet file encryption.") + '\n'\
                            + _("Your wallet file does not contain secrets, mostly just metadata. ") \
                            + _("It also contains your master public key that allows watching your addresses.") + '\n\n'\
                            + _("Note: If you enable this setting, you will need your hardware device to open your wallet.")
  WIF_HELP_TEXT = (_('WIF keys are typed in Electrum, based on script type.') + '\n\n' +
                   _('A few examples') + ':\n' +
                   'p2pkh:XERBBcaPf5D5...       \t-> XhGqfhnL...\n')
  # note: full key is XERBBcaPf5D5oFXTEP7TdPWLem5ktc2Zr3AhhQhHVQaF49fDP6tN
  MSG_PASSPHRASE_WARN_ISSUE4566 = _("Warning") + ": "\
                                + _("You have multiple consecutive whitespaces or leading/trailing "
                                    "whitespaces in your passphrase.") + " " \
                                + _("This is discouraged.") + " " \
                                + _("Due to a bug, old versions of Electrum will NOT be creating the "
                                    "same wallet as newer versions or other software.")
  
  
  class CosignWidget(QWidget):
      size = 120
  
      def __init__(self, m, n):
          QWidget.__init__(self)
          self.R = QRect(4, 4, self.size-8, self.size-8)
          self.setGeometry(self.R)
          self.setMinimumHeight(self.size)
          self.setMaximumHeight(self.size)
          self.m = m
          self.n = n
  
      def set_n(self, n):
          self.n = n
          self.update()
  
      def set_m(self, m):
          self.m = m
          self.update()
  
      def paintEvent(self, event):
          bgcolor = self.palette().color(QPalette.Background)
          pen = QPen(bgcolor, 8, Qt.SolidLine)
          qp = QPainter()
          qp.begin(self)
          qp.setPen(pen)
          qp.setRenderHint(QPainter.Antialiasing)
          qp.setBrush(Qt.gray)
          for i in range(self.n):
              alpha = int(16* 360 * i/self.n)
              alpha2 = int(16* 360 * 1/self.n)
              qp.setBrush(Qt.green if i<self.m else Qt.gray)
              qp.drawPie(self.R, alpha, alpha2)
          qp.end()
  
  
  
  def wizard_dialog(func):
      def func_wrapper(*args, **kwargs):
          run_next = kwargs['run_next']
          wizard = args[0]
          wizard.back_button.setText(_('Back') if wizard.can_go_back() else _('Cancel'))
          try:
              out = func(*args, **kwargs)
          except GoBack:
              wizard.go_back() if wizard.can_go_back() else wizard.close()
              return
          except UserCancelled:
              return
          #if out is None:
          #    out = ()
          if type(out) is not tuple:
              out = (out,)
          run_next(*out)
      return func_wrapper
  
  
  
  # WindowModalDialog must come first as it overrides show_error
  class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
  
      accept_signal = pyqtSignal()
  
      def __init__(self, config, app, plugins, storage):
          BaseWizard.__init__(self, config, plugins, storage)
          QDialog.__init__(self, None)
          self.setWindowTitle('Electrum-AXE  -  ' + _('Install Wizard'))
          self.app = app
          self.config = config
          # Set for base base class
          self.language_for_seed = config.get('language')
          self.setMinimumSize(600, 400)
          self.accept_signal.connect(self.accept)
          self.title = QLabel()
          self.main_widget = QWidget()
          self.back_button = QPushButton(_("Back"), self)
          self.back_button.setText(_('Back') if self.can_go_back() else _('Cancel'))
          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.rejected.connect(lambda: self.loop.exit(0))
          self.back_button.clicked.connect(lambda: self.loop.exit(1))
          self.next_button.clicked.connect(lambda: self.loop.exit(2))
          outer_vbox = QVBoxLayout(self)
          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)
          scroll_widget = QWidget()
          scroll_widget.setLayout(inner_vbox)
          scroll = QScrollArea()
          scroll.setWidget(scroll_widget)
          scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
          scroll.setWidgetResizable(True)
          icon_vbox = QVBoxLayout()
          icon_vbox.addWidget(self.logo)
          icon_vbox.addStretch(1)
          hbox = QHBoxLayout()
          hbox.addLayout(icon_vbox)
          hbox.addSpacing(5)
          hbox.addWidget(scroll)
          hbox.setStretchFactor(scroll, 1)
          outer_vbox.addLayout(hbox)
          outer_vbox.addLayout(Buttons(self.back_button, self.next_button))
          self.set_icon(':icons/electrum-axe.png')
          self.show()
          self.raise_()
          self.refresh_gui()  # Need for QT on MacOSX.  Lame.
  
      def run_and_get_wallet(self, get_wallet_from_daemon):
  
          vbox = QVBoxLayout()
          hbox = QHBoxLayout()
          hbox.addWidget(QLabel(_('Wallet') + ':'))
          self.name_e = QLineEdit()
          hbox.addWidget(self.name_e)
          button = QPushButton(_('Choose...'))
          hbox.addWidget(button)
          vbox.addLayout(hbox)
  
          self.msg_label = QLabel('')
          vbox.addWidget(self.msg_label)
          hbox2 = QHBoxLayout()
          self.pw_e = QLineEdit('', self)
          self.pw_e.setFixedWidth(150)
          self.pw_e.setEchoMode(2)
          self.pw_label = QLabel(_('Password') + ':')
          hbox2.addWidget(self.pw_label)
          hbox2.addWidget(self.pw_e)
          hbox2.addStretch()
          vbox.addLayout(hbox2)
          self.set_layout(vbox, title=_('Electrum-AXE wallet'))
  
          wallet_folder = os.path.dirname(self.storage.path)
  
          def on_choose():
              path, __ = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
              if path:
                  self.name_e.setText(path)
  
          def on_filename(filename):
              path = os.path.join(wallet_folder, filename)
              wallet_from_memory = get_wallet_from_daemon(path)
              try:
                  if wallet_from_memory:
                      self.storage = wallet_from_memory.storage
                  else:
                      self.storage = WalletStorage(path, manual_upgrades=True)
                  self.next_button.setEnabled(True)
              except BaseException:
                  traceback.print_exc(file=sys.stderr)
                  self.storage = None
                  self.next_button.setEnabled(False)
              if self.storage:
                  if not self.storage.file_exists():
                      msg =_("This file does not exist.") + '\n' \
                            + _("Press 'Next' to create this wallet, or choose another file.")
                      pw = False
                  elif not wallet_from_memory:
                      if self.storage.is_encrypted_with_user_pw():
                          msg = _("This file is encrypted with a password.") + '\n' \
                                + _('Enter your password or choose another file.')
                          pw = True
                      elif self.storage.is_encrypted_with_hw_device():
                          msg = _("This file is encrypted using a hardware device.") + '\n' \
                                + _("Press 'Next' to choose device to decrypt.")
                          pw = False
                      else:
                          msg = _("Press 'Next' to open this wallet.")
                          pw = False
                  else:
                      msg = _("This file is already open in memory.") + "\n" \
                          + _("Press 'Next' to create/focus window.")
                      pw = False
              else:
                  msg = _('Cannot read file')
                  pw = False
              self.msg_label.setText(msg)
              if pw:
                  self.pw_label.show()
                  self.pw_e.show()
                  self.pw_e.setFocus()
              else:
                  self.pw_label.hide()
                  self.pw_e.hide()
  
          button.clicked.connect(on_choose)
          self.name_e.textChanged.connect(on_filename)
          n = os.path.basename(self.storage.path)
          self.name_e.setText(n)
  
          while True:
              if self.loop.exec_() != 2:  # 2 = next
                  return
              if self.storage.file_exists() and not self.storage.is_encrypted():
                  break
              if not self.storage.file_exists():
                  break
              wallet_from_memory = get_wallet_from_daemon(self.storage.path)
              if wallet_from_memory:
                  return wallet_from_memory
              if self.storage.file_exists() and self.storage.is_encrypted():
                  if self.storage.is_encrypted_with_user_pw():
                      password = self.pw_e.text()
                      try:
                          self.storage.decrypt(password)
                          break
                      except InvalidPassword as e:
                          QMessageBox.information(None, _('Error'), str(e))
                          continue
                      except BaseException as e:
                          traceback.print_exc(file=sys.stdout)
                          QMessageBox.information(None, _('Error'), str(e))
                          return
                  elif self.storage.is_encrypted_with_hw_device():
                      try:
                          self.run('choose_hw_device', HWD_SETUP_DECRYPT_WALLET)
                      except InvalidPassword as e:
                          QMessageBox.information(
                              None, _('Error'),
                              _('Failed to decrypt using this hardware device.') + '\n' +
                              _('If you use a passphrase, make sure it is correct.'))
                          self.stack = []
                          return self.run_and_get_wallet(get_wallet_from_daemon)
                      except BaseException as e:
                          traceback.print_exc(file=sys.stdout)
                          QMessageBox.information(None, _('Error'), str(e))
                          return
                      if self.storage.is_past_initial_decryption():
                          break
                      else:
                          return
                  else:
                      raise Exception('Unexpected encryption version')
  
          path = self.storage.path
          if self.storage.requires_split():
              self.hide()
              msg = _("The wallet '{}' contains multiple accounts, which are no longer supported since Electrum-AXE 2.7.\n\n"
                      "Do you want to split your wallet into multiple files?").format(path)
              if not self.question(msg):
                  return
              file_list = '\n'.join(self.storage.split_accounts())
              msg = _('Your accounts have been moved to') + ':\n' + file_list + '\n\n'+ _('Do you want to delete the old file') + ':\n' + path
              if self.question(msg):
                  os.remove(path)
                  self.show_warning(_('The file was removed'))
              return
  
          action = self.storage.get_action()
          if action and action not in ('new', 'upgrade_storage'):
              self.hide()
              msg = _("The file '{}' contains an incompletely created wallet.\n"
                      "Do you want to complete its creation now?").format(path)
              if not self.question(msg):
                  if self.question(_("Do you want to delete '{}'?").format(path)):
                      os.remove(path)
                      self.show_warning(_('The file was removed'))
                  return
              self.show()
          if action:
              # self.wallet is set in run
              self.run(action)
              return self.wallet
  
          self.wallet = Wallet(self.storage)
          return self.wallet
  
      def finished(self):
          """Called in hardware client wrapper, in order to close popups."""
          return
  
      def on_error(self, exc_info):
          if not isinstance(exc_info[1], UserCancelled):
              traceback.print_exception(*exc_info)
              self.show_error(str(exc_info[1]))
  
      def set_icon(self, filename):
          prior_filename, self.icon_filename = self.icon_filename, filename
          self.logo.setPixmap(QPixmap(filename).scaledToWidth(60, mode=Qt.SmoothTransformation))
          return prior_filename
  
      def set_layout(self, layout, title=None, next_enabled=True):
          self.title.setText("<b>%s</b>"%title if title else "")
          self.title.setVisible(bool(title))
          # Get rid of any prior layout by assigning it to a temporary widget
          prior_layout = self.main_widget.layout()
          if prior_layout:
              QWidget().setLayout(prior_layout)
          self.main_widget.setLayout(layout)
          self.back_button.setEnabled(True)
          self.next_button.setEnabled(next_enabled)
          if next_enabled:
              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
          if result == 1:
              raise GoBack from None
          self.title.setVisible(False)
          self.back_button.setEnabled(False)
          self.next_button.setEnabled(False)
          self.main_widget.setVisible(False)
          self.please_wait.setVisible(True)
          self.refresh_gui()
          return result
  
      def refresh_gui(self):
          # For some reason, to refresh the GUI this needs to be called twice
          self.app.processEvents()
          self.app.processEvents()
  
      def remove_from_recently_open(self, filename):
          self.config.remove_from_recently_open(filename)
  
      def text_input(self, title, message, is_valid, allow_multi=False):
          slayout = KeysLayout(parent=self, header_layout=message, is_valid=is_valid,
                               allow_multi=allow_multi)
          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.exec_layout(slayout, title, next_enabled=False)
          return slayout.get_seed(), slayout.is_bip39, slayout.is_ext
  
      @wizard_dialog
      def add_xpub_dialog(self, title, message, is_valid, run_next, allow_multi=False, show_wif_help=False):
          header_layout = QHBoxLayout()
          label = WWLabel(message)
          label.setMinimumWidth(400)
          header_layout.addWidget(label)
          if show_wif_help:
              header_layout.addWidget(InfoButton(WIF_HELP_TEXT), alignment=Qt.AlignRight)
          return self.text_input(title, header_layout, is_valid, allow_multi)
  
      @wizard_dialog
      def add_cosigner_dialog(self, run_next, index, is_valid):
          title = _("Add Cosigner") + " %d"%index
          message = ' '.join([
              _('Please enter the master public key (xpub) of your cosigner.'),
              _('Enter their master private key (xprv) if you want to be able to sign for them.')
          ])
          return self.text_input(title, message, is_valid)
  
      @wizard_dialog
      def restore_seed_dialog(self, run_next, test):
          options = []
          if self.opt_ext:
              options.append('ext')
          if self.opt_bip39:
              options.append('bip39')
          title = _('Enter Seed')
          message = _('Please enter your seed phrase in order to restore your wallet.')
          return self.seed_input(title, message, test, options)
  
      @wizard_dialog
      def confirm_seed_dialog(self, run_next, test):
          self.app.clipboard().clear()
          title = _('Confirm Seed')
          message = ' '.join([
              _('Your seed is important!'),
              _('If you lose your seed, your money will be permanently lost.'),
              _('To make sure that you have properly saved your seed, please retype it here.')
          ])
          seed, is_bip39, is_ext = self.seed_input(title, message, test, None)
          return seed
  
      @wizard_dialog
      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.exec_layout(slayout)
          return slayout.is_ext
  
      def pw_layout(self, msg, kind, force_disable_encrypt_cb):
          playout = PasswordLayout(None, msg, kind, self.next_button,
                                   force_disable_encrypt_cb=force_disable_encrypt_cb)
          playout.encrypt_cb.setChecked(True)
          self.exec_layout(playout.layout())
          return playout.new_password(), playout.encrypt_cb.isChecked()
  
      @wizard_dialog
      def request_password(self, run_next, force_disable_encrypt_cb=False):
          """Request the user enter a new password and confirm it.  Return
          the password or None for no password."""
          return self.pw_layout(MSG_ENTER_PASSWORD, PW_NEW, force_disable_encrypt_cb)
  
      @wizard_dialog
      def request_storage_encryption(self, run_next):
          playout = PasswordLayoutForHW(None, MSG_HW_STORAGE_ENCRYPTION, PW_NEW, self.next_button)
          playout.encrypt_cb.setChecked(True)
          self.exec_layout(playout.layout())
          return playout.encrypt_cb.isChecked()
  
      @wizard_dialog
      def confirm_dialog(self, title, message, run_next):
          self.confirm(message, title)
  
      def confirm(self, message, title):
          label = WWLabel(message)
          vbox = QVBoxLayout()
          vbox.addWidget(label)
          self.exec_layout(vbox, title)
  
      @wizard_dialog
      def action_dialog(self, action, run_next):
          self.run(action)
  
      def terminate(self):
          self.accept_signal.emit()
  
      def waiting_dialog(self, task, msg, on_finished=None):
          label = WWLabel(msg)
          vbox = QVBoxLayout()
          vbox.addSpacing(100)
          label.setMinimumWidth(300)
          label.setAlignment(Qt.AlignCenter)
          vbox.addWidget(label)
          self.set_layout(vbox, next_enabled=False)
          self.back_button.setEnabled(False)
  
          t = threading.Thread(target=task)
          t.start()
          while True:
              t.join(1.0/60)
              if t.is_alive():
                  self.refresh_gui()
              else:
                  break
          if on_finished:
              on_finished()
  
      @wizard_dialog
      def choice_dialog(self, title, message, choices, run_next):
          c_values = [x[0] for x in choices]
          c_titles = [x[1] for x in choices]
          clayout = ChoicesLayout(message, c_titles)
          vbox = QVBoxLayout()
          vbox.addLayout(clayout.layout())
          self.exec_layout(vbox, title)
          action = c_values[clayout.selected_index()]
          return action
  
      def query_choice(self, msg, choices):
          """called by hardware wallets"""
          clayout = ChoicesLayout(msg, choices)
          vbox = QVBoxLayout()
          vbox.addLayout(clayout.layout())
          self.exec_layout(vbox, '')
          return clayout.selected_index()
  
      @wizard_dialog
      def choice_and_line_dialog(self, title, message1, choices, message2,
                                 test_text, run_next) -> (str, str):
          vbox = QVBoxLayout()
  
          c_values = [x[0] for x in choices]
          c_titles = [x[1] for x in choices]
          c_default_text = [x[2] for x in choices]
          def on_choice_click(clayout):
              idx = clayout.selected_index()
              line.setText(c_default_text[idx])
          clayout = ChoicesLayout(message1, c_titles, on_choice_click)
          vbox.addLayout(clayout.layout())
  
          vbox.addSpacing(50)
          vbox.addWidget(WWLabel(message2))
  
          line = QLineEdit()
          def on_text_change(text):
              self.next_button.setEnabled(test_text(text))
          line.textEdited.connect(on_text_change)
          on_choice_click(clayout)  # set default text for "line"
          vbox.addWidget(line)
  
          self.exec_layout(vbox, title)
          choice = c_values[clayout.selected_index()]
          return str(line.text()), choice
  
      @wizard_dialog
      def line_dialog(self, run_next, title, message, default, test, warning='',
                      presets=(), warn_issue4566=False):
          vbox = QVBoxLayout()
          vbox.addWidget(WWLabel(message))
          line = QLineEdit()
          line.setText(default)
          def f(text):
              self.next_button.setEnabled(test(text))
              if warn_issue4566:
                  text_whitespace_normalised = ' '.join(text.split())
                  warn_issue4566_label.setVisible(text != text_whitespace_normalised)
          line.textEdited.connect(f)
          vbox.addWidget(line)
          vbox.addWidget(WWLabel(warning))
  
          warn_issue4566_label = WWLabel(MSG_PASSPHRASE_WARN_ISSUE4566)
          warn_issue4566_label.setVisible(False)
          vbox.addWidget(warn_issue4566_label)
  
          for preset in presets:
              button = QPushButton(preset[0])
              button.clicked.connect(lambda __, text=preset[1]: line.setText(text))
              button.setMinimumWidth(150)
              hbox = QHBoxLayout()
              hbox.addWidget(button, alignment=Qt.AlignCenter)
              vbox.addLayout(hbox)
  
          self.exec_layout(vbox, title, next_enabled=test(default))
          return line.text()
  
      @wizard_dialog
      def show_xpub_dialog(self, xpub, run_next):
          msg = ' '.join([
              _("Here is your master public key."),
              _("Please share it with your cosigners.")
          ])
          vbox = QVBoxLayout()
          layout = SeedLayout(xpub, title=msg, icon=False, for_seed_words=False)
          vbox.addLayout(layout.layout())
          self.exec_layout(vbox, _('Master Public Key'))
          return None
  
      def init_network(self, network):
          message = _("Electrum-AXE communicates with remote servers to get "
                    "information about your transactions and addresses. The "
                    "servers all fulfill the same purpose only differing in "
                    "hardware. In most cases you simply want to let Electrum-AXE "
                    "pick one at random.  However if you prefer feel free to "
                    "select a server manually.")
          choices = [_("Auto connect"), _("Select server manually")]
          title = _("How do you want to connect to a server? ")
          clayout = ChoicesLayout(message, choices)
          self.back_button.setText(_('Cancel'))
          self.exec_layout(clayout.layout(), title)
          r = clayout.selected_index()
          if r == 1:
              nlayout = NetworkChoiceLayout(network, self.config, wizard=True)
              if self.exec_layout(nlayout.layout()):
                  nlayout.accept()
          else:
              network.auto_connect = True
              self.config.set_key('auto_connect', True, True)
  
      @wizard_dialog
      def multisig_dialog(self, run_next):
          cw = CosignWidget(2, 2)
          m_edit = QSlider(Qt.Horizontal, self)
          n_edit = QSlider(Qt.Horizontal, self)
          n_edit.setMinimum(2)
          n_edit.setMaximum(15)
          m_edit.setMinimum(1)
          m_edit.setMaximum(2)
          n_edit.setValue(2)
          m_edit.setValue(2)
          n_label = QLabel()
          m_label = QLabel()
          grid = QGridLayout()
          grid.addWidget(n_label, 0, 0)
          grid.addWidget(n_edit, 0, 1)
          grid.addWidget(m_label, 1, 0)
          grid.addWidget(m_edit, 1, 1)
          def on_m(m):
              m_label.setText(_('Require {0} signatures').format(m))
              cw.set_m(m)
          def on_n(n):
              n_label.setText(_('From {0} cosigners').format(n))
              cw.set_n(n)
              m_edit.setMaximum(n)
          n_edit.valueChanged.connect(on_n)
          m_edit.valueChanged.connect(on_m)
          on_n(2)
          on_m(2)
          vbox = QVBoxLayout()
          vbox.addWidget(cw)
          vbox.addWidget(WWLabel(_("Choose the number of signatures needed to unlock funds in your wallet:")))
          vbox.addLayout(grid)
          self.exec_layout(vbox, _("Multi-Signature Wallet"))
          m = int(m_edit.value())
          n = int(n_edit.value())
          return (m, n)
  