separate directories for GUIs
[electrum-nvc.git] / gui / gui_classic / installwizard.py
1 from PyQt4.QtGui import *
2 from PyQt4.QtCore import *
3 import PyQt4.QtCore as QtCore
4 from i18n import _
5
6 from electrum import Wallet, mnemonic
7
8 from seed_dialog import SeedDialog
9 from network_dialog import NetworkDialog
10 from qt_util import *
11 from amountedit import AmountEdit
12
13 import sys
14
15 class InstallWizard(QDialog):
16
17     def __init__(self, config, network, storage):
18         QDialog.__init__(self)
19         self.config = config
20         self.network = network
21         self.storage = storage
22
23
24     def restore_or_create(self):
25
26         d = QDialog()
27         d.setModal(1)
28
29         grid = QGridLayout()
30         grid.setSpacing(5)
31
32         msg = _("Wallet file not found.")+"\n"+_("Do you want to create a new wallet, or to restore an existing one?")
33         label = QLabel(msg)
34         label.setWordWrap(True)
35         grid.addWidget(label, 0, 0)
36
37         gb = QGroupBox()
38
39         b1 = QRadioButton(gb)
40         b1.setText(_("Create new wallet"))
41         b1.setChecked(True)
42
43         b2 = QRadioButton(gb)
44         b2.setText(_("Restore wallet from seed"))
45
46         b3 = QRadioButton(gb)
47         b3.setText(_("Restore wallet from master public key"))
48
49         grid.addWidget(b1,1,0)
50         grid.addWidget(b2,2,0)
51         grid.addWidget(b3,3,0)
52
53         vbox = QVBoxLayout()
54         vbox.addLayout(grid)
55         vbox.addLayout(ok_cancel_buttons(d, _('Next')))
56         d.setLayout(vbox) 
57
58         if not d.exec_():
59             return
60         
61         if b1.isChecked():
62             return 'create'
63         elif b2.isChecked():
64             return 'restore'
65         else:
66             return 'watching'
67
68
69
70     def verify_seed(self, wallet):
71         r = self.seed_dialog(False)
72         if not r:
73             return
74
75         if r != wallet.seed:
76             QMessageBox.warning(None, _('Error'), 'incorrect seed', 'OK')
77             return False
78         else:
79             return True
80
81
82     def seed_dialog(self, is_restore=True):
83         d = QDialog()
84         d.setModal(1)
85
86         vbox = QVBoxLayout()
87         if is_restore:
88             msg = _("Please enter your wallet seed (or your master public key if you want to create a watching-only wallet)." + ' ')
89         else:
90             msg = _("Your seed is important! To make sure that you have properly saved your seed, please type it here." + ' ')
91
92         msg += _("Your seed can be entered as a sequence of words, or as a hexadecimal string."+ '\n')
93         
94         label=QLabel(msg)
95         label.setWordWrap(True)
96         vbox.addWidget(label)
97
98         seed_e = QTextEdit()
99         seed_e.setMaximumHeight(100)
100         vbox.addWidget(seed_e)
101
102         if is_restore:
103             grid = QGridLayout()
104             grid.setSpacing(8)
105             gap_e = AmountEdit(None, True)
106             gap_e.setText("5")
107             grid.addWidget(QLabel(_('Gap limit')), 2, 0)
108             grid.addWidget(gap_e, 2, 1)
109             grid.addWidget(HelpButton(_('Keep the default value unless you modified this parameter in your wallet.')), 2, 3)
110             vbox.addLayout(grid)
111
112         vbox.addLayout(ok_cancel_buttons(d, _('Next')))
113         d.setLayout(vbox) 
114
115         if not d.exec_(): return
116
117         try:
118             seed = str(seed_e.toPlainText())
119             seed.decode('hex')
120         except:
121             try:
122                 seed = mnemonic.mn_decode( seed.split() )
123             except:
124                 QMessageBox.warning(None, _('Error'), _('I cannot decode this'), _('OK'))
125                 return
126
127         if not seed:
128             QMessageBox.warning(None, _('Error'), _('No seed'), _('OK'))
129             return
130
131         if not is_restore:
132             return seed
133         else:
134             try:
135                 gap = int(unicode(gap_e.text()))
136             except:
137                 QMessageBox.warning(None, _('Error'), 'error', 'OK')
138                 return
139             return seed, gap
140
141
142     def mpk_dialog(self):
143         d = QDialog()
144         d.setModal(1)
145
146         vbox = QVBoxLayout()
147         msg = _("Please enter your master public key.")
148
149         label=QLabel(msg)
150         label.setWordWrap(True)
151         vbox.addWidget(label)
152
153         mpk_e = QTextEdit()
154         mpk_e.setMaximumHeight(100)
155         vbox.addWidget(mpk_e)
156
157         grid = QGridLayout()
158         grid.setSpacing(8)
159         gap_e = AmountEdit(None, True)
160         gap_e.setText("5")
161         grid.addWidget(QLabel(_('Gap limit')), 2, 0)
162         grid.addWidget(gap_e, 2, 1)
163         grid.addWidget(HelpButton(_('Keep the default value unless you modified this parameter in your wallet.')), 2, 3)
164         vbox.addLayout(grid)
165
166         vbox.addLayout(ok_cancel_buttons(d, _('Next')))
167         d.setLayout(vbox) 
168
169         if not d.exec_(): return
170
171         mpk = str(mpk_e.toPlainText())
172
173         try:
174             gap = int(unicode(gap_e.text()))
175         except:
176             QMessageBox.warning(None, _('Error'), 'error', 'OK')
177             return
178
179         return mpk, gap
180
181
182     def network_dialog(self):
183         
184         d = QDialog()
185         d.setModal(1)
186
187         grid = QGridLayout()
188         grid.setSpacing(5)
189
190         label = QLabel(_("Network") + ":")
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()
210         vbox.addLayout(grid)
211         vbox.addLayout(ok_cancel_buttons(d, _('Next')))
212         d.setLayout(vbox) 
213
214         if not d.exec_():
215             return
216         
217         if b2.isChecked():
218             return NetworkDialog(self.network, self.config, None).do_exec()
219
220         elif b1.isChecked():
221             self.config.set_key('auto_cycle', True, True)
222             return
223
224         else:
225             self.config.set_key("server", None, True)
226             self.config.set_key('auto_cycle', False, True)
227             return
228         
229         
230
231     def show_seed(self, wallet):
232         d = SeedDialog()
233         d.show_seed(wallet.seed, wallet.imported_keys)
234
235
236     def password_dialog(self, wallet):
237         from password_dialog import PasswordDialog
238         d = PasswordDialog(wallet)
239         d.run()
240
241
242     def restore_wallet(self, wallet):
243
244         # wait until we are connected, because the user might have selected another server
245         if not wallet.interface.is_connected:
246             waiting = lambda: False if wallet.interface.is_connected else "%s \n" % (_("Connecting..."))
247             waiting_dialog(waiting)
248
249         waiting = lambda: False if wallet.is_up_to_date() else "%s\n%s %d\n%s %.1f"\
250             %(_("Please wait..."),_("Addresses generated:"),len(wallet.addresses(True)),_("Kilobytes received:"), wallet.interface.bytes_received/1024.)
251
252         # try to restore old account
253         wallet.create_old_account()
254         wallet.set_up_to_date(False)
255         wallet.interface.poke('synchronizer')
256         waiting_dialog(waiting)
257
258         if wallet.is_found():
259             wallet.seed_version = 4
260             wallet.storage.put('seed_version', wallet.seed_version, True)
261         else:
262             wallet.accounts.pop(0)
263             wallet.create_accounts()
264             wallet.set_up_to_date(False)
265             wallet.interface.poke('synchronizer')
266             waiting_dialog(waiting)
267
268         if wallet.is_found():
269             QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
270         else:
271             QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
272
273         return True
274
275
276     def run(self):
277
278         action = self.restore_or_create()
279         if not action: exit()
280
281         wallet = Wallet(self.storage)
282
283         if action == 'create':
284             wallet.init_seed(None)
285             self.show_seed(wallet)
286             if self.verify_seed(wallet):
287                 wallet.save_seed()
288                 wallet.create_accounts()
289                 # generate first addresses offline
290                 wallet.synchronize()
291             else:
292                 return
293                 
294         elif action == 'restore':
295             # ask for seed and gap.
296             sg = self.seed_dialog()
297             if not sg:
298                 return
299             seed, gap = sg
300             if not seed:
301                 return
302             wallet.gap_limit = gap
303             wallet.init_seed(str(seed))
304             wallet.save_seed()
305
306         elif action == 'watching':
307             # ask for seed and gap.
308             sg = self.mpk_dialog()
309             if not sg:
310                 return
311             mpk, gap = sg
312             if not mpk:
313                 return
314             wallet.gap_limit = gap
315             wallet.seed = ''
316
317             print eval(mpk)
318             try:
319                 c0, K0 = eval(mpk)
320             except:
321                 QMessageBox.warning(None, _('Error'), _('error'), _('OK'))
322                 return
323             wallet.create_watching_only_wallet(c0,K0)
324
325
326         else: raise
327                 
328         #if not self.config.get('server'):
329         self.network_dialog()
330
331         # start wallet threads
332         wallet.start_threads(self.network)
333
334         if action == 'restore':
335             try:
336                 keep_it = self.restore_wallet(wallet)
337                 wallet.fill_addressbook()
338             except:
339                 import traceback
340                 traceback.print_exc(file=sys.stdout)
341                 exit()
342
343             if not keep_it: return
344
345         self.password_dialog(wallet)
346         
347         return wallet