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
8 from seed_dialog import SeedDialog
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 from its seed"))
59 b3.setText(_("Create a watching-only version of an existing wallet"))
61 grid.addWidget(b1,1,0)
62 grid.addWidget(b2,2,0)
63 grid.addWidget(b3,3,0)
70 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
88 def verify_seed(self, seed):
89 r = self.seed_dialog(False)
94 QMessageBox.warning(None, _('Error'), _('Incorrect seed'), _('OK'))
100 def seed_dialog(self, is_restore=True):
104 msg = _("Please enter your wallet seed.") + "\n"
106 msg = _("Your seed is important!") \
107 + "\n" + _("To make sure that you have properly saved your seed, please retype it here.")
110 logo.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
111 logo.setMaximumWidth(60)
114 label.setWordWrap(True)
117 seed_e.setMaximumHeight(100)
119 vbox.addWidget(label)
122 grid.addWidget(logo, 0, 0)
123 grid.addWidget(seed_e, 0, 1)
128 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
130 self.set_layout(vbox)
134 seed = seed_e.toPlainText()
135 seed = unicode(seed.toLower())
138 QMessageBox.warning(None, _('Error'), _('No seed'), _('OK'))
141 if not Wallet.is_seed(seed):
142 QMessageBox.warning(None, _('Error'), _('Invalid seed'), _('OK'))
149 def waiting_dialog(self, task, msg= _("Electrum is generating your addresses, please wait.")):
152 self.emit(QtCore.SIGNAL('accept'))
155 self.waiting_label = QLabel(msg)
156 vbox.addWidget(self.waiting_label)
157 self.set_layout(vbox)
158 t = threading.Thread(target = target)
164 def mpk_dialog(self):
167 vbox.addWidget(QLabel(_("Please enter your master public key.")))
172 label = QLabel(_("Key"))
173 grid.addWidget(label, 0, 0)
175 mpk_e.setMaximumHeight(100)
176 grid.addWidget(mpk_e, 0, 1)
181 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
183 self.set_layout(vbox)
187 mpk = str(mpk_e.toPlainText()).strip()
191 def network_dialog(self):
196 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" \
197 + _("How do you want to connect to a server:")+" ")
198 label.setWordWrap(True)
199 grid.addWidget(label, 0, 0)
203 b1 = QRadioButton(gb)
204 b1.setText(_("Auto connect"))
207 b2 = QRadioButton(gb)
208 b2.setText(_("Select server manually"))
210 #b3 = QRadioButton(gb)
211 #b3.setText(_("Stay offline"))
213 grid.addWidget(b1,1,0)
214 grid.addWidget(b2,2,0)
215 #grid.addWidget(b3,3,0)
221 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
223 self.set_layout(vbox)
228 return NetworkDialog(self.network, self.config, None).do_exec()
231 self.config.set_key('auto_cycle', True, True)
235 self.config.set_key("server", None, True)
236 self.config.set_key('auto_cycle', False, True)
240 def show_message(self, msg):
242 vbox.addWidget(QLabel(msg))
244 vbox.addLayout(close_button(self, _('Next')))
245 self.set_layout(vbox)
249 def question(self, msg):
251 vbox.addWidget(QLabel(msg))
253 vbox.addLayout(ok_cancel_buttons(self, _('OK')))
254 self.set_layout(vbox)
260 def show_seed(self, seed, sid):
261 from seed_dialog import make_seed_dialog
262 vbox = make_seed_dialog(seed, sid)
263 vbox.addLayout(ok_cancel_buttons(self, _("Next")))
264 self.set_layout(vbox)
268 def password_dialog(self, wallet):
269 msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
270 +_("Leave these fields empty if you want to disable encryption.")
271 from password_dialog import make_password_dialog, run_password_dialog
272 self.set_layout( make_password_dialog(self, wallet, msg) )
273 return run_password_dialog(self, wallet, self)
276 def choose_wallet_type(self):
280 msg = _("Choose your wallet.")
282 label.setWordWrap(True)
283 grid.addWidget(label, 0, 0)
287 b1 = QRadioButton(gb)
288 b1.setText(_("Standard wallet (protected by password)"))
291 b2 = QRadioButton(gb)
292 b2.setText(_("Multi-signature wallet (two-factor authentication)"))
294 grid.addWidget(b1,1,0)
295 grid.addWidget(b2,2,0)
301 vbox.addLayout(ok_cancel_buttons(self, _('Next')))
303 self.set_layout(vbox)
313 def run(self, action = None):
316 action = self.restore_or_create()
321 if action == 'create':
322 t = self.choose_wallet_type()
324 run_hook('create_cold_seed', self.storage, self)
328 if action in ['create', 'create2of3']:
330 wallet = Wallet(self.storage)
332 wallet.init_seed(None)
333 seed = wallet.get_mnemonic(None)
334 if not self.show_seed(seed, 'hot' if action == 'create2of3' else None):
336 if not self.verify_seed(seed):
338 ok, old_password, password = self.password_dialog(wallet)
339 wallet.save_seed(password)
341 if action == 'create2of3':
342 run_hook('create_hot_seed', wallet, self)
344 wallet.create_accounts(password)
346 wallet.synchronize() # generate first addresses offline
347 self.waiting_dialog(create)
349 elif action == 'restore':
350 seed = self.seed_dialog()
351 if not Wallet.is_seed(seed):
353 wallet = Wallet.from_seed(seed, self.storage)
354 ok, old_password, password = self.password_dialog(wallet)
355 wallet.save_seed(password)
356 wallet.create_accounts(password)
358 elif action == 'watching':
359 mpk = self.mpk_dialog()
362 wallet = Wallet.from_mpk(mpk, self.storage)
366 #if not self.config.get('server'):
368 if self.network.interfaces:
369 self.network_dialog()
371 QMessageBox.information(None, _('Warning'), _('You are offline'), _('OK'))
375 # start wallet threads
376 wallet.start_threads(self.network)
378 if action == 'restore':
380 self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))
383 if wallet.is_found():
384 QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
386 QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
388 QMessageBox.information(None, _('Information'), _("This wallet was restored offline. It may contain more addresses than displayed."), _('OK'))