Flesh out the text for the install wizard
[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.seed:
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             msg += _("Your seed can be entered as a sequence of words, or as a hexadecimal string."+ ' \n')
93         else:
94             msg = _("Your seed is important!") \
95                   + "\n" + _("To make sure that you have properly saved your seed, please retype it here." + ' ')
96         
97         logo = QLabel()
98         logo.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
99         logo.setMaximumWidth(60)
100
101         label = QLabel(msg)
102         label.setWordWrap(True)
103
104         seed_e = QTextEdit()
105         seed_e.setMaximumHeight(100)
106
107         vbox.addWidget(label)
108
109         grid = QGridLayout()
110         grid.addWidget(logo, 0, 0)
111         grid.addWidget(seed_e, 0, 1)
112
113         vbox.addLayout(grid)
114
115
116         vbox.addStretch(1)
117         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
118
119         if not self.exec_():
120             return
121
122         try:
123             seed = str(seed_e.toPlainText())
124             seed.decode('hex')
125         except:
126             try:
127                 seed = mnemonic.mn_decode( seed.split() )
128             except:
129                 QMessageBox.warning(None, _('Error'), _('I cannot decode this'), _('OK'))
130                 return
131
132         if not seed:
133             QMessageBox.warning(None, _('Error'), _('No seed'), _('OK'))
134             return
135
136         return seed
137
138
139
140     def waiting_dialog(self, task, msg= _("Electrum is generating your addresses, please wait.")):
141         def target():
142             task()
143             self.emit(QtCore.SIGNAL('accept'))
144
145         if self.layout(): QWidget().setLayout(self.layout())
146         vbox = QVBoxLayout(self)
147         self.waiting_label = QLabel(msg)
148         vbox.addWidget(self.waiting_label)
149         self.show()
150         t = threading.Thread(target = target)
151         t.start()
152         self.exec_()
153
154
155
156     def mpk_dialog(self):
157
158         if self.layout(): QWidget().setLayout(self.layout())
159
160         vbox = QVBoxLayout(self)
161         msg = _("Please enter your master public key.")
162
163         label=QLabel(msg)
164         label.setWordWrap(True)
165         vbox.addWidget(label)
166
167         mpk_e = QTextEdit()
168         mpk_e.setMaximumHeight(100)
169         vbox.addWidget(mpk_e)
170
171         grid = QGridLayout()
172         grid.setSpacing(8)
173         vbox.addLayout(grid)
174
175         vbox.addStretch(1)
176         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
177
178         if not self.exec_(): return
179
180         mpk = str(mpk_e.toPlainText())
181         return mpk
182
183
184     def network_dialog(self):
185         
186         if self.layout(): QWidget().setLayout(self.layout())
187
188         grid = QGridLayout()
189         grid.setSpacing(5)
190
191         label = QLabel(_("Electrum communicates with Electrum 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 or stay offline.") + "\n\n" \
192                       + _("How do you want to connect to a server: "))
193         label.setWordWrap(True)
194         grid.addWidget(label, 0, 0)
195
196         gb = QGroupBox()
197
198         b1 = QRadioButton(gb)
199         b1.setText(_("Auto connect"))
200         b1.setChecked(True)
201
202         b2 = QRadioButton(gb)
203         b2.setText(_("Select server manually"))
204
205         b3 = QRadioButton(gb)
206         b3.setText(_("Stay offline"))
207
208         grid.addWidget(b1,1,0)
209         grid.addWidget(b2,2,0)
210         grid.addWidget(b3,3,0)
211
212         vbox = QVBoxLayout(self)
213         vbox.addLayout(grid)
214
215         vbox.addStretch(1)
216         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
217
218         if not self.exec_():
219             return
220         
221         if b2.isChecked():
222             return NetworkDialog(self.network, self.config, None).do_exec()
223
224         elif b1.isChecked():
225             self.config.set_key('auto_cycle', True, True)
226             return
227
228         else:
229             self.config.set_key("server", None, True)
230             self.config.set_key('auto_cycle', False, True)
231             return
232         
233         
234
235     def show_seed(self, wallet):
236         from seed_dialog import make_seed_dialog
237         if self.layout(): QWidget().setLayout(self.layout())
238         make_seed_dialog(self, wallet.seed, wallet.imported_keys)
239         self.exec_()
240
241
242     def password_dialog(self, wallet):
243         msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
244               +_("Leave these fields empty if you want to disable encryption.")
245         from password_dialog import make_password_dialog, run_password_dialog
246         if self.layout(): QWidget().setLayout(self.layout())
247         make_password_dialog(self, wallet, msg)
248         run_password_dialog(self, wallet, self)
249
250
251     def run(self):
252
253         action = self.restore_or_create()
254         if not action: exit()
255
256         wallet = Wallet(self.storage)
257         gap = self.config.get('gap_limit', 5)
258         if gap != 5:
259             wallet.gap_limit = gap
260             wallet.storage.put('gap_limit', gap, True)
261
262         if action == 'create':
263             wallet.init_seed(None)
264             self.show_seed(wallet)
265             if self.verify_seed(wallet):
266                 def create():
267                     wallet.save_seed()
268                     wallet.create_accounts()
269                     wallet.synchronize()  # generate first addresses offline
270                 self.waiting_dialog(create)
271             else:
272                 return
273                 
274         elif action == 'restore':
275             # ask for seed and gap.
276             seed = self.seed_dialog()
277             if not seed:
278                 return
279             wallet.init_seed(str(seed))
280             wallet.save_seed()
281
282         elif action == 'watching':
283             # ask for seed and gap.
284             mpk = self.mpk_dialog()
285             if not mpk:
286                 return
287             wallet.seed = ''
288
289             print eval(mpk)
290             try:
291                 c0, K0 = eval(mpk)
292             except:
293                 QMessageBox.warning(None, _('Error'), _('error'), _('OK'))
294                 return
295             wallet.create_watching_only_wallet(c0,K0)
296
297
298         else: raise
299                 
300         #if not self.config.get('server'):
301         self.network_dialog()
302
303         # start wallet threads
304         wallet.start_threads(self.network)
305
306         if action == 'restore':
307
308             self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))
309
310             if wallet.is_found():
311                 QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
312             else:
313                 QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
314             
315             wallet.fill_addressbook()
316
317         self.password_dialog(wallet)
318
319         return wallet