1 from PyQt4.QtGui import *
2 from PyQt4.QtCore import *
3 import PyQt4.QtCore as QtCore
5 from electrum.i18n import _
6 from electrum import Wallet, Wallet_2of3
9 from network_dialog import NetworkDialog
11 from amountedit import AmountEdit
15 from electrum.plugins import run_hook
17 class InstallWizard(QDialog):
19 def __init__(self, config, network, storage):
20 QDialog.__init__(self)
22 self.network = network
23 self.storage = storage
24 self.setMinimumSize(575, 400)
25 self.setWindowTitle('Electrum')
26 self.connect(self, QtCore.SIGNAL('accept'), self.accept)
28 self.stack = QStackedLayout()
29 self.setLayout(self.stack)
32 def set_layout(self, layout):
35 self.stack.setCurrentIndex(self.stack.addWidget(w))
38 def restore_or_create(self):
43 msg = _("Electrum could not find an existing wallet.") + "\n\n" \
44 + _("What do you want to do?") + "\n"
46 label.setWordWrap(True)
47 grid.addWidget(label, 0, 0)
52 b1.setText(_("Create new wallet"))
56 b2.setText(_("Restore an existing wallet"))
58 grid.addWidget(b1,1,0)
59 grid.addWidget(b2,2,0)
66 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
71 return 'create' if b1.isChecked() else 'restore'
75 def verify_seed(self, seed, sid):
76 r = self.enter_seed_dialog(False, sid)
81 QMessageBox.warning(None, _('Error'), _('Incorrect seed'), _('OK'))
87 def get_seed_text(self, seed_e):
88 text = unicode(seed_e.toPlainText()).strip()
89 text = ' '.join(text.split())
93 def is_seed(self, seed_e):
94 text = self.get_seed_text(seed_e)
95 return Wallet.is_seed(text) or Wallet.is_mpk(text)
98 def enter_seed_dialog(self, is_restore, sid):
99 vbox, seed_e = seed_dialog.enter_seed_box(is_restore, sid)
101 hbox, button = ok_cancel_buttons2(self, _('Next'))
103 button.setEnabled(False)
104 seed_e.textChanged.connect(lambda: button.setEnabled(self.is_seed(seed_e)))
105 self.set_layout(vbox)
108 return self.get_seed_text(seed_e)
111 def double_seed_dialog(self):
113 vbox1, seed_e1 = seed_dialog.enter_seed_box(True, 'hot')
114 vbox2, seed_e2 = seed_dialog.enter_seed_box(True, 'cold')
115 vbox.addLayout(vbox1)
116 vbox.addLayout(vbox2)
118 hbox, button = ok_cancel_buttons2(self, _('Next'))
120 button.setEnabled(False)
121 f = lambda: button.setEnabled(self.is_seed(seed_e1) and self.is_seed(seed_e2))
122 seed_e1.textChanged.connect(f)
123 seed_e2.textChanged.connect(f)
124 self.set_layout(vbox)
127 return self.get_seed_text(seed_e1), self.get_seed_text(seed_e2)
132 def waiting_dialog(self, task, msg= _("Electrum is generating your addresses, please wait.")):
135 self.emit(QtCore.SIGNAL('accept'))
138 self.waiting_label = QLabel(msg)
139 vbox.addWidget(self.waiting_label)
140 self.set_layout(vbox)
141 t = threading.Thread(target = target)
148 def network_dialog(self):
153 label = QLabel(_("Electrum communicates with remote servers to get information about your transactions and addresses. The servers all fulfil the same purpose only differing in hardware. In most cases you simply want to let Electrum pick one at random if you have a preference though feel free to select a server manually.") + "\n\n" \
154 + _("How do you want to connect to a server:")+" ")
155 label.setWordWrap(True)
156 grid.addWidget(label, 0, 0)
160 b1 = QRadioButton(gb)
161 b1.setText(_("Auto connect"))
164 b2 = QRadioButton(gb)
165 b2.setText(_("Select server manually"))
167 #b3 = QRadioButton(gb)
168 #b3.setText(_("Stay offline"))
170 grid.addWidget(b1,1,0)
171 grid.addWidget(b2,2,0)
172 #grid.addWidget(b3,3,0)
178 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
180 self.set_layout(vbox)
185 return NetworkDialog(self.network, self.config, None).do_exec()
188 self.config.set_key('auto_cycle', True, True)
192 self.config.set_key("server", None, True)
193 self.config.set_key('auto_cycle', False, True)
197 def show_message(self, msg, icon=None):
199 self.set_layout(vbox)
204 vbox.addWidget(QLabel(msg))
206 vbox.addLayout(close_button(self, _('Next')))
211 def question(self, msg, icon=None):
213 self.set_layout(vbox)
218 vbox.addWidget(QLabel(msg))
220 vbox.addLayout(ok_cancel_buttons(self, _('OK')))
226 def show_seed(self, seed, sid):
227 vbox = seed_dialog.show_seed_box(seed, sid)
228 vbox.addLayout(ok_cancel_buttons(self, _("Next")))
229 self.set_layout(vbox)
233 def password_dialog(self):
234 msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
235 +_("Leave these fields empty if you want to disable encryption.")
236 from password_dialog import make_password_dialog, run_password_dialog
237 self.set_layout( make_password_dialog(self, None, msg) )
238 return run_password_dialog(self, None, self)[2]
241 def choose_wallet_type(self):
245 msg = _("Choose your wallet.")
247 label.setWordWrap(True)
248 grid.addWidget(label, 0, 0)
252 b1 = QRadioButton(gb)
253 b1.setText(_("Standard wallet (protected by password)"))
256 b2 = QRadioButton(gb)
257 b2.setText(_("Multi-signature wallet (two-factor authentication)"))
259 grid.addWidget(b1,1,0)
260 grid.addWidget(b2,2,0)
266 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
268 self.set_layout(vbox)
278 def run(self, action = None):
281 action = self.restore_or_create()
286 if action == 'create':
287 t = self.choose_wallet_type()
292 run_hook('create_cold_seed', self.storage, self)
296 if action in ['create', 'create2of3']:
298 wallet = Wallet(self.storage)
299 seed = wallet.make_seed()
300 sid = 'hot' if action == 'create2of3' else None
301 if not self.show_seed(seed, sid):
303 if not self.verify_seed(seed, sid):
305 password = self.password_dialog()
306 wallet.add_seed(seed, password)
308 if action == 'create2of3':
309 run_hook('create_third_key', wallet, self)
310 if not wallet.master_public_keys.get("remote/"):
313 wallet.create_accounts(password)
314 # generate first addresses offline
315 self.waiting_dialog(wallet.synchronize)
317 elif action == 'restore':
318 t = self.choose_wallet_type()
323 text = self.enter_seed_dialog(True, None)
324 if Wallet.is_seed(text):
325 password = self.password_dialog()
326 wallet = Wallet.from_seed(text, self.storage)
327 wallet.add_seed(text, password)
328 wallet.create_accounts(password)
329 elif Wallet.is_mpk(text):
330 wallet = Wallet.from_mpk(text, self.storage)
334 elif t in ['2of2', '2of3']:
335 r = self.double_seed_dialog()
339 password = self.password_dialog()
340 wallet = Wallet_2of3(self.storage)
342 if Wallet.is_seed(text1):
343 wallet.add_seed(text1, password)
344 if Wallet.is_seed(text2):
345 wallet.add_cold_seed(text2, password)
347 wallet.add_master_public_key("cold/", text2)
349 elif Wallet.is_mpk(text1):
350 if Wallet.is_seed(text2):
351 wallet.add_seed(text2, password)
352 wallet.add_master_public_key("cold/", text1)
354 wallet.add_master_public_key("m/", text1)
355 wallet.add_master_public_key("cold/", text2)
357 run_hook('restore_third_key', wallet, self)
359 wallet.create_accounts(None)
369 #if not self.config.get('server'):
371 if self.network.interfaces:
372 self.network_dialog()
374 QMessageBox.information(None, _('Warning'), _('You are offline'), _('OK'))
378 # start wallet threads
379 wallet.start_threads(self.network)
381 if action == 'restore':
383 self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))
386 if wallet.is_found():
387 QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
389 QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
391 QMessageBox.information(None, _('Information'), _("This wallet was restored offline. It may contain more addresses than displayed."), _('OK'))