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 return unicode(seed_e.toPlainText())
91 def is_seed(self, seed_e):
92 text = self.get_seed_text(seed_e)
93 return Wallet.is_seed(text) or Wallet.is_mpk(text)
96 def enter_seed_dialog(self, is_restore, sid):
97 vbox, seed_e = seed_dialog.enter_seed_box(is_restore, sid)
99 hbox, button = ok_cancel_buttons2(self, _('Next'))
101 button.setEnabled(False)
102 seed_e.textChanged.connect(lambda: button.setEnabled(self.is_seed(seed_e)))
103 self.set_layout(vbox)
106 return self.get_seed_text(seed_e)
109 def double_seed_dialog(self):
111 vbox1, seed_e1 = seed_dialog.enter_seed_box(True, 'hot')
112 vbox2, seed_e2 = seed_dialog.enter_seed_box(True, 'cold')
113 vbox.addLayout(vbox1)
114 vbox.addLayout(vbox2)
116 hbox, button = ok_cancel_buttons2(self, _('Next'))
118 button.setEnabled(False)
119 f = lambda: button.setEnabled(self.is_seed(seed_e1) and self.is_seed(seed_e2))
120 seed_e1.textChanged.connect(f)
121 seed_e2.textChanged.connect(f)
122 self.set_layout(vbox)
125 return self.get_seed_text(seed_e1), self.get_seed_text(seed_e2)
130 def waiting_dialog(self, task, msg= _("Electrum is generating your addresses, please wait.")):
133 self.emit(QtCore.SIGNAL('accept'))
136 self.waiting_label = QLabel(msg)
137 vbox.addWidget(self.waiting_label)
138 self.set_layout(vbox)
139 t = threading.Thread(target = target)
146 def network_dialog(self):
151 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" \
152 + _("How do you want to connect to a server:")+" ")
153 label.setWordWrap(True)
154 grid.addWidget(label, 0, 0)
158 b1 = QRadioButton(gb)
159 b1.setText(_("Auto connect"))
162 b2 = QRadioButton(gb)
163 b2.setText(_("Select server manually"))
165 #b3 = QRadioButton(gb)
166 #b3.setText(_("Stay offline"))
168 grid.addWidget(b1,1,0)
169 grid.addWidget(b2,2,0)
170 #grid.addWidget(b3,3,0)
176 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
178 self.set_layout(vbox)
183 return NetworkDialog(self.network, self.config, None).do_exec()
186 self.config.set_key('auto_cycle', True, True)
190 self.config.set_key("server", None, True)
191 self.config.set_key('auto_cycle', False, True)
195 def show_message(self, msg):
197 vbox.addWidget(QLabel(msg))
199 vbox.addLayout(close_button(self, _('Next')))
200 self.set_layout(vbox)
204 def question(self, msg):
206 vbox.addWidget(QLabel(msg))
208 vbox.addLayout(ok_cancel_buttons(self, _('OK')))
209 self.set_layout(vbox)
215 def show_seed(self, seed, sid):
216 vbox = seed_dialog.show_seed_box(seed, sid)
217 vbox.addLayout(ok_cancel_buttons(self, _("Next")))
218 self.set_layout(vbox)
222 def password_dialog(self):
223 msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
224 +_("Leave these fields empty if you want to disable encryption.")
225 from password_dialog import make_password_dialog, run_password_dialog
226 self.set_layout( make_password_dialog(self, None, msg) )
227 return run_password_dialog(self, None, self)[2]
230 def choose_wallet_type(self):
234 msg = _("Choose your wallet.")
236 label.setWordWrap(True)
237 grid.addWidget(label, 0, 0)
241 b1 = QRadioButton(gb)
242 b1.setText(_("Standard wallet (protected by password)"))
245 b2 = QRadioButton(gb)
246 b2.setText(_("Multi-signature wallet (two-factor authentication)"))
248 grid.addWidget(b1,1,0)
249 grid.addWidget(b2,2,0)
255 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
257 self.set_layout(vbox)
267 def run(self, action = None):
270 action = self.restore_or_create()
275 if action == 'create':
276 t = self.choose_wallet_type()
281 run_hook('create_cold_seed', self.storage, self)
285 if action in ['create', 'create2of3']:
287 wallet = Wallet(self.storage)
288 seed = wallet.make_seed()
289 sid = 'hot' if action == 'create2of3' else None
290 if not self.show_seed(seed, sid):
292 if not self.verify_seed(seed, sid):
294 password = self.password_dialog()
295 wallet.save_seed(seed, password)
297 if action == 'create2of3':
298 run_hook('create_third_key', wallet, self)
299 if not wallet.master_public_keys.get("remote/"):
302 wallet.create_accounts(password)
303 # generate first addresses offline
304 self.waiting_dialog(wallet.synchronize)
306 elif action == 'restore':
307 t = self.choose_wallet_type()
312 text = self.enter_seed_dialog(True, None)
313 if Wallet.is_seed(text):
314 password = self.password_dialog()
315 wallet = Wallet.from_seed(text, self.storage)
316 wallet.save_seed(text, password)
317 wallet.create_accounts(password)
318 elif Wallet.is_mpk(text):
319 wallet = Wallet.from_mpk(text, self.storage)
323 elif t in ['2of2', '2of3']:
324 r = self.double_seed_dialog()
328 password = self.password_dialog()
329 wallet = Wallet_2of3(self.storage)
331 if Wallet.is_seed(text1):
332 wallet.add_root("m/", text1, password)
333 elif Wallet.is_mpk(text1):
334 wallet.add_master_public_key("m/", text1)
336 if Wallet.is_seed(text2):
337 wallet.add_root("cold/", text2, password)
338 elif Wallet.is_mpk(text2):
339 wallet.add_master_public_key("cold/", text2)
341 run_hook('restore_third_key', wallet, self)
343 wallet.create_accounts(None)
353 #if not self.config.get('server'):
355 if self.network.interfaces:
356 self.network_dialog()
358 QMessageBox.information(None, _('Warning'), _('You are offline'), _('OK'))
362 # start wallet threads
363 wallet.start_threads(self.network)
365 if action == 'restore':
367 self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))
370 if wallet.is_found():
371 QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
373 QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
375 QMessageBox.information(None, _('Information'), _("This wallet was restored offline. It may contain more addresses than displayed."), _('OK'))