Line breaks and blank spaces
[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         t = threading.Thread(target = target)
150         t.start()
151         self.exec_()
152
153
154
155     def mpk_dialog(self):
156
157         if self.layout(): QWidget().setLayout(self.layout())
158
159         vbox = QVBoxLayout(self)
160
161         vbox.addWidget(QLabel(_("Please enter your master public key.")))
162
163         grid = QGridLayout()
164         grid.setSpacing(8)
165
166         label = QLabel(_("Key")) 
167         grid.addWidget(label, 0, 0)
168         mpk_e = QTextEdit()
169         mpk_e.setMaximumHeight(100)
170         grid.addWidget(mpk_e, 0, 1)
171
172         label = QLabel(_("Chain")) 
173         grid.addWidget(label, 1, 0)
174         chain_e = QTextEdit()
175         chain_e.setMaximumHeight(100)
176         grid.addWidget(chain_e, 1, 1)
177
178         vbox.addLayout(grid)
179
180         vbox.addStretch(1)
181         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
182
183         if not self.exec_(): return None, None
184
185         mpk = str(mpk_e.toPlainText()).strip()
186         chain = str(chain_e.toPlainText()).strip()
187         return mpk, chain
188
189
190     def network_dialog(self):
191         
192         if self.layout(): QWidget().setLayout(self.layout())
193
194         grid = QGridLayout()
195         grid.setSpacing(5)
196
197         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" \
198                       + _("How do you want to connect to a server:")+" ")
199         label.setWordWrap(True)
200         grid.addWidget(label, 0, 0)
201
202         gb = QGroupBox()
203
204         b1 = QRadioButton(gb)
205         b1.setText(_("Auto connect"))
206         b1.setChecked(True)
207
208         b2 = QRadioButton(gb)
209         b2.setText(_("Select server manually"))
210
211         #b3 = QRadioButton(gb)
212         #b3.setText(_("Stay offline"))
213
214         grid.addWidget(b1,1,0)
215         grid.addWidget(b2,2,0)
216         #grid.addWidget(b3,3,0)
217
218         vbox = QVBoxLayout(self)
219         vbox.addLayout(grid)
220
221         vbox.addStretch(1)
222         vbox.addLayout(ok_cancel_buttons(self, _('Next')))
223
224         if not self.exec_():
225             return
226         
227         if b2.isChecked():
228             return NetworkDialog(self.network, self.config, None).do_exec()
229
230         elif b1.isChecked():
231             self.config.set_key('auto_cycle', True, True)
232             return
233
234         else:
235             self.config.set_key("server", None, True)
236             self.config.set_key('auto_cycle', False, True)
237             return
238         
239         
240
241     def show_seed(self, wallet):
242         from seed_dialog import make_seed_dialog
243
244         vbox = make_seed_dialog(wallet.seed, wallet.imported_keys)
245         vbox.addLayout(ok_cancel_buttons(self, _("Next")))
246
247         if self.layout(): QWidget().setLayout(self.layout())
248         self.setLayout(vbox)
249
250         if not self.exec_():
251             exit()
252
253
254     def password_dialog(self, wallet):
255         msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
256               +_("Leave these fields empty if you want to disable encryption.")
257         from password_dialog import make_password_dialog, run_password_dialog
258         if self.layout(): QWidget().setLayout(self.layout())
259         make_password_dialog(self, wallet, msg)
260         run_password_dialog(self, wallet, self)
261
262
263     def run(self):
264
265         action = self.restore_or_create()
266         if not action: exit()
267
268         wallet = Wallet(self.storage)
269         gap = self.config.get('gap_limit', 5)
270         if gap != 5:
271             wallet.gap_limit = gap
272             wallet.storage.put('gap_limit', gap, True)
273
274         if action == 'create':
275             wallet.init_seed(None)
276             self.show_seed(wallet)
277             if self.verify_seed(wallet):
278                 def create():
279                     wallet.save_seed()
280                     wallet.create_accounts()
281                     wallet.synchronize()  # generate first addresses offline
282                 self.waiting_dialog(create)
283             else:
284                 return
285                 
286         elif action == 'restore':
287             # ask for seed and gap.
288             seed = self.seed_dialog()
289             if not seed:
290                 return
291             wallet.init_seed(str(seed))
292             wallet.save_seed()
293
294         elif action == 'watching':
295             # ask for seed and gap.
296             K, chain = self.mpk_dialog()
297             if not K:
298                 return
299             wallet.seed = ''
300             wallet.create_watching_only_wallet(chain,K)
301
302
303         else: raise
304                 
305         #if not self.config.get('server'):
306         self.network_dialog()
307
308         # start wallet threads
309         wallet.start_threads(self.network)
310
311         if action == 'restore':
312
313             self.waiting_dialog(lambda: wallet.restore(self.waiting_label.setText))
314
315             if wallet.is_found():
316                 QMessageBox.information(None, _('Information'), _("Recovery successful"), _('OK'))
317             else:
318                 QMessageBox.information(None, _('Information'), _("No transactions found for this seed"), _('OK'))
319             
320             wallet.fill_addressbook()
321
322         self.password_dialog(wallet)
323
324         return wallet