disable bip32
[electrum-nvc.git] / gui / qt / installwizard.py
1 from PyQt4.QtGui import *
2 from PyQt4.QtCore import *
3 import PyQt4.QtCore as QtCore
4
5 from electrum.i18n import _
6 from electrum import Wallet, mnemonic
7
8 from seed_dialog import SeedDialog
9 from network_dialog import NetworkDialog
10 from util import *
11 from amountedit import AmountEdit
12
13 import sys
14 import threading
15
16 class InstallWizard(QDialog):
17
18     def __init__(self, config, network, storage):
19         QDialog.__init__(self)
20         self.config = config
21         self.network = network
22         self.storage = storage
23         self.setMinimumSize(575, 400)
24         self.setWindowTitle('Electrum')
25         self.connect(self, QtCore.SIGNAL('accept'), self.accept)
26
27
28     def restore_or_create(self):
29
30         grid = QGridLayout()
31         grid.setSpacing(5)
32
33         msg = _("Electrum could not find an existing wallet.")+"\n\n"+_("Did you use Electrum before and want to restore a previous wallet or is this your first time and do you want to create a new wallet?")+"\n"
34         label = QLabel(msg)
35         label.setWordWrap(True)
36         grid.addWidget(label, 0, 0)
37
38         gb = QGroupBox()
39
40         b1 = QRadioButton(gb)
41         b1.setText(_("Create new wallet"))
42         b1.setChecked(True)
43
44         b2 = QRadioButton(gb)
45         b2.setText(_("Restore wallet from seed"))
46
47         b3 = QRadioButton(gb)
48         b3.setText(_("Restore wallet from master public key"))
49
50         grid.addWidget(b1,1,0)
51         grid.addWidget(b2,2,0)
52         grid.addWidget(b3,3,0)
53
54         vbox = QVBoxLayout(self)
55         vbox.addLayout(grid)
56
57         vbox.addStretch(1)
58         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
59
60         if not self.exec_():
61             return
62         
63         if b1.isChecked():
64             answer = 'create'
65         elif b2.isChecked():
66             answer = 'restore'
67         else:
68             answer = 'watching'
69
70         return answer
71
72
73     def verify_seed(self, wallet):
74         r = self.seed_dialog(False)
75         if not r:
76             return
77
78         if r != wallet.get_mnemonic(None):
79             QMessageBox.warning(None, _('Error'), _('Incorrect seed'), _('OK'))
80             return False
81         else:
82             return True
83
84
85     def seed_dialog(self, is_restore=True):
86
87         if self.layout(): QWidget().setLayout(self.layout())
88
89         vbox = QVBoxLayout(self)
90         if is_restore:
91             msg = _("Please enter your wallet seed.") + "\n"
92         else:
93             msg = _("Your seed is important!") \
94                 + "\n" + _("To make sure that you have properly saved your seed, please retype it here.")
95         
96         logo = QLabel()
97         logo.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
98         logo.setMaximumWidth(60)
99
100         label = QLabel(msg)
101         label.setWordWrap(True)
102
103         seed_e = QTextEdit()
104         seed_e.setMaximumHeight(100)
105
106         vbox.addWidget(label)
107
108         grid = QGridLayout()
109         grid.addWidget(logo, 0, 0)
110         grid.addWidget(seed_e, 0, 1)
111
112         vbox.addLayout(grid)
113
114
115         vbox.addStretch(1)
116         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
117
118         if not self.exec_():
119             return
120
121         seed = unicode(seed_e.toPlainText())
122
123         if not seed:
124             QMessageBox.warning(None, _('Error'), _('No seed'), _('OK'))
125             return
126
127         return seed
128
129
130
131     def waiting_dialog(self, task, msg= _("Electrum is generating your addresses, please wait.")):
132         def target():
133             task()
134             self.emit(QtCore.SIGNAL('accept'))
135
136         if self.layout(): QWidget().setLayout(self.layout())
137         vbox = QVBoxLayout(self)
138         self.waiting_label = QLabel(msg)
139         vbox.addWidget(self.waiting_label)
140         t = threading.Thread(target = target)
141         t.start()
142         self.exec_()
143
144
145
146     def mpk_dialog(self):
147
148         if self.layout(): QWidget().setLayout(self.layout())
149
150         vbox = QVBoxLayout(self)
151
152         vbox.addWidget(QLabel(_("Please enter your master public key.")))
153
154         grid = QGridLayout()
155         grid.setSpacing(8)
156
157         label = QLabel(_("Key")) 
158         grid.addWidget(label, 0, 0)
159         mpk_e = QTextEdit()
160         mpk_e.setMaximumHeight(100)
161         grid.addWidget(mpk_e, 0, 1)
162
163         label = QLabel(_("Chain")) 
164         grid.addWidget(label, 1, 0)
165         chain_e = QTextEdit()
166         chain_e.setMaximumHeight(100)
167         grid.addWidget(chain_e, 1, 1)
168
169         vbox.addLayout(grid)
170
171         vbox.addStretch(1)
172         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
173
174         if not self.exec_(): return None, None
175
176         mpk = str(mpk_e.toPlainText()).strip()
177         chain = str(chain_e.toPlainText()).strip()
178         return mpk, chain
179
180
181     def network_dialog(self):
182         
183         if self.layout(): QWidget().setLayout(self.layout())
184
185         grid = QGridLayout()
186         grid.setSpacing(5)
187
188         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" \
189                       + _("How do you want to connect to a server:")+" ")
190         label.setWordWrap(True)
191         grid.addWidget(label, 0, 0)
192
193         gb = QGroupBox()
194
195         b1 = QRadioButton(gb)
196         b1.setText(_("Auto connect"))
197         b1.setChecked(True)
198
199         b2 = QRadioButton(gb)
200         b2.setText(_("Select server manually"))
201
202         #b3 = QRadioButton(gb)
203         #b3.setText(_("Stay offline"))
204
205         grid.addWidget(b1,1,0)
206         grid.addWidget(b2,2,0)
207         #grid.addWidget(b3,3,0)
208
209         vbox = QVBoxLayout(self)
210         vbox.addLayout(grid)
211
212         vbox.addStretch(1)
213         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
214
215         if not self.exec_():
216             return
217         
218         if b2.isChecked():
219             return NetworkDialog(self.network, self.config, None).do_exec()
220
221         elif b1.isChecked():
222             self.config.set_key('auto_cycle', True, True)
223             return
224
225         else:
226             self.config.set_key("server", None, True)
227             self.config.set_key('auto_cycle', False, True)
228             return
229         
230         
231
232     def show_seed(self, wallet):
233         from seed_dialog import make_seed_dialog
234
235         vbox = make_seed_dialog(wallet.get_mnemonic(None), wallet.imported_keys)
236         vbox.addLayout(ok_cancel_buttons(self, _("Next")))
237
238         if self.layout(): QWidget().setLayout(self.layout())
239         self.setLayout(vbox)
240
241         if not self.exec_():
242             exit()
243
244
245     def password_dialog(self, wallet):
246         msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
247               +_("Leave these fields empty if you want to disable encryption.")
248         from password_dialog import make_password_dialog, run_password_dialog
249         if self.layout(): QWidget().setLayout(self.layout())
250         make_password_dialog(self, wallet, msg)
251         run_password_dialog(self, wallet, self)
252
253
254     def run(self):
255
256         action = self.restore_or_create()
257         if not action: exit()
258
259         wallet = Wallet(self.storage)
260         gap = self.config.get('gap_limit', 5)
261         if gap != 5:
262             wallet.gap_limit = gap
263             wallet.storage.put('gap_limit', gap, True)
264
265         if action == 'create':
266             wallet.init_seed(None)
267             self.show_seed(wallet)
268             if self.verify_seed(wallet):
269                 def create():
270                     wallet.save_seed()
271                     wallet.create_accounts()
272                     wallet.synchronize()  # generate first addresses offline
273                 self.waiting_dialog(create)
274             else:
275                 return
276                 
277         elif action == 'restore':
278             # ask for seed and gap.
279             seed = self.seed_dialog()
280             if not seed:
281                 return
282             try:
283                 wallet.init_seed(seed)
284             except:
285                 QMessageBox.warning(None, _('Error'), _('Incorrect seed'), _('OK'))
286                 return
287
288             wallet.save_seed()
289
290         elif action == 'watching':
291             # ask for seed and gap.
292             K, chain = self.mpk_dialog()
293             if not K or not chain:
294                 return
295             wallet.seed = ''
296             wallet.create_watching_only_wallet(chain,K)
297
298
299         else: raise
300                 
301         #if not self.config.get('server'):
302         self.network_dialog()
303
304         # start wallet threads
305         wallet.start_threads(self.network)
306
307         if action == 'restore':
308
309             self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))
310
311             if wallet.is_found():
312                 QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
313             else:
314                 QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
315             
316             wallet.fill_addressbook()
317
318         self.password_dialog(wallet)
319
320         return wallet