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):
199 vbox.addWidget(QLabel(msg))
201 vbox.addLayout(close_button(self, _('Next')))
202 self.set_layout(vbox)
206 def question(self, msg):
208 vbox.addWidget(QLabel(msg))
210 vbox.addLayout(ok_cancel_buttons(self, _('OK')))
211 self.set_layout(vbox)
217 def show_seed(self, seed, sid):
218 vbox = seed_dialog.show_seed_box(seed, sid)
219 vbox.addLayout(ok_cancel_buttons(self, _("Next")))
220 self.set_layout(vbox)
224 def password_dialog(self):
225 msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
226 +_("Leave these fields empty if you want to disable encryption.")
227 from password_dialog import make_password_dialog, run_password_dialog
228 self.set_layout( make_password_dialog(self, None, msg) )
229 return run_password_dialog(self, None, self)[2]
232 def choose_wallet_type(self):
236 msg = _("Choose your wallet.")
238 label.setWordWrap(True)
239 grid.addWidget(label, 0, 0)
243 b1 = QRadioButton(gb)
244 b1.setText(_("Standard wallet (protected by password)"))
247 b2 = QRadioButton(gb)
248 b2.setText(_("Multi-signature wallet (two-factor authentication)"))
250 grid.addWidget(b1,1,0)
251 grid.addWidget(b2,2,0)
257 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
259 self.set_layout(vbox)
269 def run(self, action = None):
272 action = self.restore_or_create()
277 if action == 'create':
278 t = self.choose_wallet_type()
283 run_hook('create_cold_seed', self.storage, self)
287 if action in ['create', 'create2of3']:
289 wallet = Wallet(self.storage)
290 seed = wallet.make_seed()
291 sid = 'hot' if action == 'create2of3' else None
292 if not self.show_seed(seed, sid):
294 if not self.verify_seed(seed, sid):
296 password = self.password_dialog()
297 wallet.add_seed(seed, password)
299 if action == 'create2of3':
300 run_hook('create_third_key', wallet, self)
301 if not wallet.master_public_keys.get("remote/"):
304 wallet.create_accounts(password)
305 # generate first addresses offline
306 self.waiting_dialog(wallet.synchronize)
308 elif action == 'restore':
309 t = self.choose_wallet_type()
314 text = self.enter_seed_dialog(True, None)
315 if Wallet.is_seed(text):
316 password = self.password_dialog()
317 wallet = Wallet.from_seed(text, self.storage)
318 wallet.add_seed(text, password)
319 wallet.create_accounts(password)
320 elif Wallet.is_mpk(text):
321 wallet = Wallet.from_mpk(text, self.storage)
325 elif t in ['2of2', '2of3']:
326 r = self.double_seed_dialog()
330 password = self.password_dialog()
331 wallet = Wallet_2of3(self.storage)
333 if Wallet.is_seed(text1):
334 wallet.add_seed(text1, password)
335 if Wallet.is_seed(text2):
336 wallet.add_cold_seed(text2, password)
338 wallet.add_master_public_key("cold/", text2)
340 elif Wallet.is_mpk(text1):
341 if Wallet.is_seed(text2):
342 wallet.add_seed(text2, password)
343 wallet.add_master_public_key("cold/", text1)
345 wallet.add_master_public_key("m/", text1)
346 wallet.add_master_public_key("cold/", text2)
348 run_hook('restore_third_key', wallet, self)
350 wallet.create_accounts(None)
360 #if not self.config.get('server'):
362 if self.network.interfaces:
363 self.network_dialog()
365 QMessageBox.information(None, _('Warning'), _('You are offline'), _('OK'))
369 # start wallet threads
370 wallet.start_threads(self.network)
372 if action == 'restore':
374 self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))
377 if wallet.is_found():
378 QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
380 QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
382 QMessageBox.information(None, _('Information'), _("This wallet was restored offline. It may contain more addresses than displayed."), _('OK'))