electrum-bitcoinprivate/client/gui_qt.py

813 lines
27 KiB
Python
Raw Normal View History

2012-02-13 07:49:20 -08:00
import sys, time, datetime, re
2012-02-11 04:14:12 -08:00
2012-02-11 08:02:28 -08:00
# todo: see PySide
2012-02-11 04:14:12 -08:00
from PyQt4.QtGui import *
2012-02-11 08:02:28 -08:00
from PyQt4.QtCore import *
2012-02-11 04:14:12 -08:00
import PyQt4.QtCore as QtCore
2012-02-11 08:02:28 -08:00
import PyQt4.QtGui as QtGui
2012-02-11 04:14:12 -08:00
2012-02-14 02:33:09 -08:00
import icons_rc
2012-02-11 13:19:22 -08:00
from wallet import format_satoshis
2012-02-13 06:22:15 -08:00
from decimal import Decimal
2012-02-11 13:19:22 -08:00
2012-02-14 00:52:03 -08:00
2012-02-11 04:14:12 -08:00
2012-02-14 05:05:58 -08:00
class Timer(QtCore.QThread):
2012-02-11 13:19:22 -08:00
def run(self):
while True:
2012-02-14 05:05:58 -08:00
self.emit(QtCore.SIGNAL('timersignal'))
2012-02-11 13:19:22 -08:00
time.sleep(0.5)
2012-02-13 12:36:41 -08:00
class StatusBarButton(QPushButton):
def __init__(self, icon, tooltip, func):
QPushButton.__init__(self, icon, '')
self.setToolTip(tooltip)
self.setFlat(True)
self.setMaximumWidth(25)
self.clicked.connect(func)
self.func = func
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Return:
apply(self.func,())
2012-02-11 04:14:12 -08:00
2012-02-14 00:52:03 -08:00
def ok_cancel_buttons(dialog):
hbox = QHBoxLayout()
hbox.addStretch(1)
b = QPushButton("OK")
hbox.addWidget(b)
b.clicked.connect(dialog.accept)
b = QPushButton("Cancel")
hbox.addWidget(b)
b.clicked.connect(dialog.reject)
return hbox
2012-02-12 00:52:26 -08:00
class ElectrumWindow(QMainWindow):
2012-02-11 04:14:12 -08:00
def __init__(self, wallet):
2012-02-11 08:38:44 -08:00
QMainWindow.__init__(self)
2012-02-11 04:14:12 -08:00
self.wallet = wallet
2012-02-11 13:19:22 -08:00
2012-02-13 08:16:02 -08:00
self.tabs = tabs = QTabWidget(self)
2012-02-12 00:52:26 -08:00
tabs.addTab(self.create_history_tab(), 'History')
2012-02-11 08:38:44 -08:00
tabs.addTab(self.create_send_tab(), 'Send')
2012-02-12 00:52:26 -08:00
tabs.addTab(self.create_receive_tab(), 'Receive')
tabs.addTab(self.create_contacts_tab(),'Contacts')
tabs.addTab(self.create_wall_tab(), 'Wall')
2012-02-11 13:19:22 -08:00
tabs.setMinimumSize(600, 400)
2012-02-13 10:02:48 -08:00
tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
2012-02-12 00:52:26 -08:00
self.setCentralWidget(tabs)
2012-02-11 08:38:44 -08:00
self.create_status_bar()
2012-02-13 05:52:59 -08:00
self.setGeometry(100,100,840,400)
2012-02-13 08:28:50 -08:00
self.setWindowTitle( 'Electrum ' + self.wallet.electrum_version )
2012-02-11 08:38:44 -08:00
self.show()
2012-02-12 00:52:26 -08:00
QShortcut(QKeySequence("Ctrl+W"), self, self.close)
QShortcut(QKeySequence("Ctrl+Q"), self, self.close)
2012-02-13 05:52:59 -08:00
QShortcut(QKeySequence("Ctrl+PgUp"), self, lambda: tabs.setCurrentIndex( (tabs.currentIndex() - 1 )%tabs.count() ))
QShortcut(QKeySequence("Ctrl+PgDown"), self, lambda: tabs.setCurrentIndex( (tabs.currentIndex() + 1 )%tabs.count() ))
2012-02-12 00:52:26 -08:00
2012-02-14 00:52:03 -08:00
2012-02-12 00:52:26 -08:00
2012-02-11 13:19:22 -08:00
def connect_slots(self, sender):
2012-02-14 05:05:58 -08:00
self.connect(sender, QtCore.SIGNAL('timersignal'), self.update_wallet)
self.connect(sender, QtCore.SIGNAL('timersignal'), self.check_recipient)
self.previous_payto_e=''
def check_recipient(self):
if self.payto_e.hasFocus():
return
r = str( self.payto_e.text() )
if r != self.previous_payto_e:
self.previous_payto_e = r
r = r.strip()
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', r):
try:
to_address = self.wallet.get_alias(r, interactive=False)
except:
return
if to_address:
s = r + ' <' + to_address + '>'
self.payto_e.setText(s)
2012-02-11 13:19:22 -08:00
2012-02-12 00:52:26 -08:00
2012-02-11 13:19:22 -08:00
def update_wallet(self):
if self.wallet.interface.is_connected:
if self.wallet.interface.blocks == 0:
text = "Server not ready"
2012-02-14 02:33:09 -08:00
icon = QIcon(":icons/status_disconnected.png")
2012-02-11 13:19:22 -08:00
elif not self.wallet.interface.was_polled:
text = "Synchronizing..."
2012-02-14 02:33:09 -08:00
icon = QIcon(":icons/status_waiting.svg")
2012-02-11 13:19:22 -08:00
else:
c, u = self.wallet.get_balance()
text = "Balance: %s "%( format_satoshis(c) )
if u: text += "[%s unconfirmed]"%( format_satoshis(u,True) )
2012-02-14 02:33:09 -08:00
icon = QIcon(":icons/status_connected.png")
2012-02-11 13:19:22 -08:00
else:
text = "Not connected"
2012-02-14 02:33:09 -08:00
icon = QIcon(":icons/status_disconnected.png")
2012-02-12 08:19:16 -08:00
2012-02-11 13:19:22 -08:00
self.statusBar().showMessage(text)
2012-02-12 08:19:16 -08:00
self.status_button.setIcon( icon )
2012-02-11 13:19:22 -08:00
if self.wallet.interface.was_updated:
self.wallet.interface.was_updated = False
2012-02-12 00:52:26 -08:00
self.textbox.setText( self.wallet.interface.message )
2012-02-11 22:27:32 -08:00
self.update_history_tab()
2012-02-11 22:45:18 -08:00
self.update_receive_tab()
self.update_contacts_tab()
2012-02-11 22:27:32 -08:00
2012-02-11 04:14:12 -08:00
2012-02-11 08:02:28 -08:00
def create_history_tab(self):
2012-02-11 22:27:32 -08:00
self.history_list = w = QTreeWidget(self)
2012-02-13 05:52:59 -08:00
#print w.getContentsMargins()
2012-02-11 22:27:32 -08:00
w.setColumnCount(5)
2012-02-12 01:58:38 -08:00
w.setColumnWidth(0, 40)
w.setColumnWidth(1, 140)
2012-02-13 05:52:59 -08:00
w.setColumnWidth(2, 350)
w.setColumnWidth(3, 140)
w.setColumnWidth(4, 140)
2012-02-12 12:41:42 -08:00
w.setHeaderLabels( [ '', 'Date', 'Description', 'Amount', 'Balance'] )
2012-02-12 09:02:11 -08:00
self.connect(w, SIGNAL('itemActivated(QTreeWidgetItem*, int)'), self.tx_details)
2012-02-12 12:41:42 -08:00
self.connect(w, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), self.tx_label_clicked)
self.connect(w, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), self.tx_label_changed)
2012-02-11 22:27:32 -08:00
return w
2012-02-12 09:02:11 -08:00
def tx_details(self, item, column):
tx_hash = str(item.toolTip(0))
tx = self.wallet.tx_history.get(tx_hash)
if tx['height']:
conf = self.wallet.interface.blocks - tx['height'] + 1
time_str = datetime.datetime.fromtimestamp( tx['nTime']).isoformat(' ')[:-3]
else:
conf = 0
time_str = 'pending'
tx_details = "Transaction Details:\n\n" \
+ "Transaction ID:\n" + tx_hash + "\n\n" \
+ "Status: %d confirmations\n\n"%conf \
+ "Date: %s\n\n"%time_str \
+ "Inputs:\n-"+ '\n-'.join(tx['inputs']) + "\n\n" \
+ "Outputs:\n-"+ '\n-'.join(tx['outputs'])
r = self.wallet.receipts.get(tx_hash)
if r:
tx_details += "\n_______________________________________" \
+ '\n\nSigned URI: ' + r[2] \
+ "\n\nSigned by: " + r[0] \
+ '\n\nSignature: ' + r[1]
QMessageBox.information(self, 'Details', tx_details, 'OK')
2012-02-12 12:41:42 -08:00
def tx_label_clicked(self, item, column):
if column==2 and item.isSelected():
tx_hash = str(item.toolTip(0))
self.is_edit=True
#if not self.wallet.labels.get(tx_hash): item.setText(2,'')
item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
self.history_list.editItem( item, column )
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
self.is_edit=False
def tx_label_changed(self, item, column):
if self.is_edit:
return
self.is_edit=True
tx_hash = str(item.toolTip(0))
tx = self.wallet.tx_history.get(tx_hash)
s = self.wallet.labels.get(tx_hash)
text = str( item.text(2) )
2012-02-12 15:00:33 -08:00
if text:
2012-02-12 12:41:42 -08:00
self.wallet.labels[tx_hash] = text
item.setForeground(2, QBrush(QColor('black')))
else:
if s: self.wallet.labels.pop(tx_hash)
text = tx['default_label']
item.setText(2, text)
item.setForeground(2, QBrush(QColor('gray')))
self.is_edit=False
2012-02-12 09:02:11 -08:00
2012-02-12 15:00:33 -08:00
def address_label_clicked(self, item, column, l):
if column==1 and item.isSelected():
item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
l.editItem( item, column )
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
def address_label_changed(self, item, column, l):
addr = str(item.text(0))
text = str( item.text(1) )
if text:
self.wallet.labels[addr] = text
else:
s = self.wallet.labels.get(addr)
if s: self.wallet.labels.pop(addr)
self.update_history_tab()
2012-02-11 22:27:32 -08:00
def update_history_tab(self):
self.history_list.clear()
balance = 0
for tx in self.wallet.get_tx_history():
tx_hash = tx['tx_hash']
if tx['height']:
conf = self.wallet.interface.blocks - tx['height'] + 1
time_str = datetime.datetime.fromtimestamp( tx['nTime']).isoformat(' ')[:-3]
2012-02-14 02:33:09 -08:00
icon = QIcon(":icons/confirmed.png")
2012-02-11 22:27:32 -08:00
else:
conf = 0
time_str = 'pending'
2012-02-14 02:33:09 -08:00
icon = QIcon(":icons/unconfirmed.svg")
2012-02-11 22:27:32 -08:00
v = tx['value']
balance += v
label = self.wallet.labels.get(tx_hash)
is_default_label = (label == '') or (label is None)
if is_default_label: label = tx['default_label']
2012-02-12 09:02:11 -08:00
2012-02-12 01:58:38 -08:00
item = QTreeWidgetItem( [ '', time_str, label, format_satoshis(v,True), format_satoshis(balance)] )
2012-02-12 02:47:35 -08:00
item.setFont(2, QFont('monospace'))
2012-02-12 03:26:35 -08:00
item.setFont(3, QFont('monospace'))
item.setFont(4, QFont('monospace'))
2012-02-12 09:02:11 -08:00
item.setToolTip(0, tx_hash)
2012-02-12 02:51:06 -08:00
if is_default_label:
2012-02-12 12:41:42 -08:00
item.setForeground(2, QBrush(QColor('grey')))
2012-02-12 01:58:38 -08:00
item.setIcon(0, icon)
self.history_list.insertTopLevelItem(0,item)
2012-02-11 22:27:32 -08:00
2012-02-11 08:02:28 -08:00
def create_send_tab(self):
2012-02-11 22:27:32 -08:00
w = QWidget()
2012-02-13 10:02:48 -08:00
grid = QGridLayout()
2012-02-11 22:27:32 -08:00
grid.setSpacing(8)
2012-02-13 05:52:59 -08:00
grid.setColumnMinimumWidth(3,300)
grid.setColumnStretch(4,1)
2012-02-11 22:27:32 -08:00
2012-02-14 04:38:47 -08:00
self.payto_e = QLineEdit()
2012-02-11 22:27:32 -08:00
grid.addWidget(QLabel('Pay to'), 1, 0)
2012-02-14 04:38:47 -08:00
grid.addWidget(self.payto_e, 1, 1, 1, 3)
2012-02-11 22:27:32 -08:00
2012-02-14 04:38:47 -08:00
self.message_e = QLineEdit()
2012-02-11 22:27:32 -08:00
grid.addWidget(QLabel('Description'), 2, 0)
2012-02-14 04:38:47 -08:00
grid.addWidget(self.message_e, 2, 1, 1, 3)
2012-02-11 22:27:32 -08:00
2012-02-14 04:38:47 -08:00
self.amount_e = QLineEdit()
2012-02-11 22:27:32 -08:00
grid.addWidget(QLabel('Amount'), 3, 0)
2012-02-14 04:38:47 -08:00
grid.addWidget(self.amount_e, 3, 1, 1, 2)
2012-02-11 22:27:32 -08:00
2012-02-14 04:38:47 -08:00
self.fee_e = QLineEdit()
2012-02-11 22:27:32 -08:00
grid.addWidget(QLabel('Fee'), 4, 0)
2012-02-14 04:38:47 -08:00
grid.addWidget(self.fee_e, 4, 1, 1, 2)
2012-02-11 22:27:32 -08:00
2012-02-13 07:49:20 -08:00
b = QPushButton("Send")
2012-02-14 04:38:47 -08:00
b.clicked.connect( self.do_send )
2012-02-13 07:49:20 -08:00
grid.addWidget(b, 5, 1)
2012-02-13 05:52:59 -08:00
2012-02-13 07:49:20 -08:00
b = QPushButton("Clear")
2012-02-14 04:38:47 -08:00
b.clicked.connect( self.do_clear )
2012-02-13 07:49:20 -08:00
grid.addWidget(b, 5, 2)
2012-02-12 15:00:33 -08:00
2012-02-14 04:38:47 -08:00
self.payto_sig = QLabel('')
grid.addWidget(self.payto_sig, 6, 0, 1, 4)
2012-02-11 22:27:32 -08:00
w.setLayout(grid)
w.show()
w2 = QWidget()
2012-02-13 10:02:48 -08:00
vbox = QVBoxLayout()
2012-02-11 22:27:32 -08:00
vbox.addWidget(w)
vbox.addStretch(1)
w2.setLayout(vbox)
return w2
2012-02-11 08:02:28 -08:00
2012-02-14 04:38:47 -08:00
def do_send(self):
2012-02-13 07:49:20 -08:00
2012-02-14 04:38:47 -08:00
label = str( self.message_e.text() )
r = str( self.payto_e.text() )
2012-02-13 07:49:20 -08:00
r = r.strip()
m1 = re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', r)
m2 = re.match('(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+) \<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
if m1:
2012-02-14 00:52:03 -08:00
to_address = self.wallet.get_alias(r, True, self.show_message, self.question)
2012-02-13 07:49:20 -08:00
if not to_address:
return
elif m2:
to_address = m2.group(5)
else:
to_address = r
if not self.wallet.is_valid(to_address):
QMessageBox.warning(self, 'Error', 'Invalid Bitcoin Address:\n'+to_address, 'OK')
return
try:
2012-02-14 04:38:47 -08:00
amount = int( Decimal( str( self.amount_e.text())) * 100000000 )
2012-02-13 07:49:20 -08:00
except:
QMessageBox.warning(self, 'Error', 'Invalid Amount', 'OK')
return
try:
2012-02-14 04:38:47 -08:00
fee = int( Decimal( str( self.fee_e.text())) * 100000000 )
2012-02-13 07:49:20 -08:00
except:
QMessageBox.warning(self, 'Error', 'Invalid Fee', 'OK')
return
if self.wallet.use_encryption:
password = self.password_dialog()
if not password:
return
else:
password = None
try:
tx = self.wallet.mktx( to_address, amount, label, password, fee )
except BaseException, e:
self.show_message(e.message)
return
status, msg = self.wallet.sendtx( tx )
if status:
QMessageBox.information(self, '', 'Payment sent.\n'+msg, 'OK')
2012-02-14 04:38:47 -08:00
self.do_clear()
2012-02-13 07:49:20 -08:00
self.update_contacts_tab()
else:
QMessageBox.warning(self, 'Error', msg, 'OK')
2012-02-14 04:38:47 -08:00
def set_url(self, url):
2012-02-14 04:49:05 -08:00
payto, amount, label, message, signature, identity, url = self.wallet.parse_url(url, self.show_message, self.question)
2012-02-14 04:38:47 -08:00
self.tabs.setCurrentIndex(1)
self.payto_e.setText(payto)
self.message_e.setText(message)
self.amount_e.setText(amount)
if identity:
self.set_frozen(self.payto_e,True)
self.set_frozen(self.amount_e,True)
self.set_frozen(self.message_e,True)
self.payto_sig.setText( ' The bitcoin URI was signed by ' + identity )
else:
self.payto_sig.setVisible(False)
def do_clear(self):
self.payto_sig.setVisible(False)
for e in [self.payto_e, self.message_e, self.amount_e, self.fee_e]:
e.setText('')
self.set_frozen(e,False)
def set_frozen(self,entry,frozen):
if frozen:
entry.setReadOnly(True)
entry.setFrame(False)
palette = QPalette()
palette.setColor(entry.backgroundRole(), QColor('lightgray'))
entry.setPalette(palette)
else:
entry.setReadOnly(False)
entry.setFrame(True)
palette = QPalette()
palette.setColor(entry.backgroundRole(), QColor('white'))
entry.setPalette(palette)
2012-02-13 07:49:20 -08:00
2012-02-12 01:58:38 -08:00
def make_address_list(self, is_recv):
2012-02-11 08:02:28 -08:00
2012-02-12 02:26:38 -08:00
l = QTreeWidget(self)
l.setColumnCount(3)
2012-02-13 05:52:59 -08:00
l.setColumnWidth(0, 350)
l.setColumnWidth(1, 330)
2012-02-12 02:26:38 -08:00
l.setColumnWidth(2, 20)
l.setHeaderLabels( ['Address', 'Label','Tx'])
2012-02-12 01:58:38 -08:00
2012-02-13 10:02:48 -08:00
vbox = QVBoxLayout()
2012-02-12 03:37:43 -08:00
vbox.setMargin(0)
2012-02-12 08:19:16 -08:00
vbox.setSpacing(0)
2012-02-12 02:26:38 -08:00
vbox.addWidget(l)
2012-02-13 10:02:48 -08:00
hbox = QHBoxLayout()
2012-02-12 03:37:43 -08:00
hbox.setMargin(0)
2012-02-12 08:19:16 -08:00
hbox.setSpacing(0)
2012-02-13 10:02:48 -08:00
qrButton = QPushButton("QR")
copyButton = QPushButton("Copy to Clipboard")
2012-02-13 08:16:02 -08:00
def copy2clipboard(l):
i = l.currentItem()
if not i: return
addr = str( i.text(0) )
self.app.clipboard().setText(addr)
copyButton.clicked.connect(lambda: copy2clipboard(l))
2012-02-12 02:26:38 -08:00
hbox.addWidget(qrButton)
hbox.addWidget(copyButton)
if not is_recv:
2012-02-13 10:02:48 -08:00
addButton = QPushButton("New")
2012-02-12 15:00:33 -08:00
addButton.clicked.connect(self.newaddress_dialog)
2012-02-12 02:26:38 -08:00
hbox.addWidget(addButton)
2012-02-13 10:02:48 -08:00
paytoButton = QPushButton('Pay to')
2012-02-13 08:16:02 -08:00
def payto(l):
i = l.currentItem()
if not i: return
addr = str( i.text(0) )
self.tabs.setCurrentIndex(1)
2012-02-14 04:38:47 -08:00
self.payto_e.setText(addr)
2012-02-13 08:16:02 -08:00
paytoButton.clicked.connect(lambda : payto(l))
2012-02-12 02:26:38 -08:00
hbox.addWidget(paytoButton)
hbox.addStretch(1)
buttons = QWidget()
buttons.setLayout(hbox)
vbox.addWidget(buttons)
w = QWidget()
w.setLayout(vbox)
return w, l
def create_receive_tab(self):
2012-02-12 15:00:33 -08:00
w, l = self.make_address_list(True)
self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l))
self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l))
self.receive_list = l
return w
def create_contacts_tab(self):
w, l = self.make_address_list(False)
self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l))
self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l))
self.connect(l, SIGNAL('itemActivated(QTreeWidgetItem*, int)'), self.show_contact_details)
self.contacts_list = l
2012-02-12 02:26:38 -08:00
return w
2012-02-12 01:58:38 -08:00
2012-02-11 22:45:18 -08:00
def update_receive_tab(self):
self.receive_list.clear()
for address in self.wallet.all_addresses():
if self.wallet.is_change(address):continue
label = self.wallet.labels.get(address,'')
n = 0
h = self.wallet.history.get(address,[])
for item in h:
if not item['is_in'] : n=n+1
tx = "None" if n==0 else "%d"%n
item = QTreeWidgetItem( [ address, label, tx] )
2012-02-12 02:47:35 -08:00
item.setFont(0, QFont('monospace'))
2012-02-11 22:45:18 -08:00
self.receive_list.addTopLevelItem(item)
2012-02-12 12:41:42 -08:00
def show_contact_details(self, item, column):
m = str(item.text(0))
a = self.wallet.aliases.get(m)
if a:
if a[0] in self.wallet.authorities.keys():
s = self.wallet.authorities.get(a[0])
else:
s = "self-signed"
msg = 'Alias: '+ m + '\nTarget address: '+ a[1] + '\n\nSigned by: ' + s + '\nSigning address:' + a[0]
QMessageBox.information(self, 'Alias', msg, 'OK')
2012-02-11 22:45:18 -08:00
def update_contacts_tab(self):
self.contacts_list.clear()
for alias, v in self.wallet.aliases.items():
s, target = v
2012-02-12 08:19:16 -08:00
label = self.wallet.labels.get(alias,'')
2012-02-11 22:45:18 -08:00
item = QTreeWidgetItem( [ alias, label, '-'] )
self.contacts_list.addTopLevelItem(item)
for address in self.wallet.addressbook:
label = self.wallet.labels.get(address,'')
n = 0
for item in self.wallet.tx_history.values():
if address in item['outputs'] : n=n+1
tx = "None" if n==0 else "%d"%n
item = QTreeWidgetItem( [ address, label, tx] )
2012-02-12 02:47:35 -08:00
item.setFont(0, QFont('monospace'))
2012-02-11 22:45:18 -08:00
self.contacts_list.addTopLevelItem(item)
2012-02-11 08:02:28 -08:00
def create_wall_tab(self):
2012-02-11 13:19:22 -08:00
self.textbox = textbox = QTextEdit(self)
textbox.setReadOnly(True)
return textbox
2012-02-11 08:02:28 -08:00
2012-02-11 08:38:44 -08:00
def create_status_bar(self):
sb = QStatusBar()
2012-02-12 08:19:16 -08:00
sb.setFixedHeight(35)
2012-02-14 02:33:09 -08:00
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/lock.svg"), "Password", lambda: self.change_password_dialog(self.wallet, self) ) )
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), "Preferences", self.settings_dialog ) )
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), "Seed", lambda: self.show_seed_dialog(self.wallet, self) ) )
self.status_button = StatusBarButton( QIcon(":icons/status_disconnected.png"), "Network", lambda: self.network_dialog(self.wallet, self) )
2012-02-13 12:36:41 -08:00
sb.addPermanentWidget( self.status_button )
2012-02-11 08:38:44 -08:00
self.setStatusBar(sb)
2012-02-12 15:00:33 -08:00
def newaddress_dialog(self):
2012-02-13 10:02:48 -08:00
text, ok = QInputDialog.getText(self, 'New Contact', 'Address:')
2012-02-12 15:00:33 -08:00
address = str(text)
if ok:
if self.wallet.is_valid(address):
self.wallet.addressbook.append(address)
self.wallet.save()
self.update_contacts_tab()
else:
QMessageBox.warning(self, 'Error', 'Invalid Address', 'OK')
2012-02-14 00:52:03 -08:00
@staticmethod
def show_seed_dialog(wallet, parent=None):
2012-02-12 15:00:33 -08:00
import mnemonic
2012-02-14 00:52:03 -08:00
if wallet.use_encryption:
2012-02-14 02:10:06 -08:00
password = parent.password_dialog()
2012-02-13 06:11:31 -08:00
if not password: return
else:
password = None
try:
2012-02-14 00:52:03 -08:00
seed = wallet.pw_decode( wallet.seed, password)
2012-02-13 06:11:31 -08:00
except:
2012-02-14 00:52:03 -08:00
QMessageBox.warning(parent, 'Error', 'Invalid Password', 'OK')
2012-02-13 06:11:31 -08:00
return
2012-02-12 15:00:33 -08:00
2012-02-13 06:11:31 -08:00
msg = "Your wallet generation seed is:\n\n" + seed \
+ "\n\nPlease keep it in a safe place; if you lose it, you will not be able to restore your wallet.\n\n" \
+ "Equivalently, your wallet seed can be stored and recovered with the following mnemonic code:\n\n\"" \
+ ' '.join(mnemonic.mn_encode(seed)) + "\""
2012-02-14 00:52:03 -08:00
QMessageBox.information(parent, 'Seed', msg, 'OK')
2012-02-13 06:11:31 -08:00
2012-02-14 00:52:03 -08:00
def question(self, msg):
return QMessageBox.question(self, 'Message', msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
2012-02-13 06:11:31 -08:00
2012-02-14 00:52:03 -08:00
def show_message(self, msg):
QMessageBox.information(self, 'Message', msg, 'OK')
2012-02-14 02:10:06 -08:00
def password_dialog(self ):
d = QDialog(self)
2012-02-13 05:52:59 -08:00
d.setModal(1)
2012-02-13 06:11:31 -08:00
pw = QLineEdit()
pw.setEchoMode(2)
2012-02-13 10:02:48 -08:00
vbox = QVBoxLayout()
2012-02-13 06:11:31 -08:00
msg = 'Please enter your password'
2012-02-13 10:02:48 -08:00
vbox.addWidget(QLabel(msg))
2012-02-13 06:11:31 -08:00
2012-02-13 10:02:48 -08:00
grid = QGridLayout()
grid.setSpacing(8)
2012-02-13 06:11:31 -08:00
grid.addWidget(QLabel('Password'), 1, 0)
grid.addWidget(pw, 1, 1)
2012-02-13 10:02:48 -08:00
vbox.addLayout(grid)
2012-02-13 06:11:31 -08:00
2012-02-14 00:52:03 -08:00
vbox.addLayout(ok_cancel_buttons(d))
2012-02-13 10:02:48 -08:00
d.setLayout(vbox)
2012-02-13 06:11:31 -08:00
if not d.exec_(): return
return str(pw.text())
2012-02-14 00:52:03 -08:00
@staticmethod
def change_password_dialog( wallet, parent=None ):
d = QDialog(parent)
2012-02-13 06:11:31 -08:00
d.setModal(1)
2012-02-13 05:52:59 -08:00
pw = QLineEdit()
pw.setEchoMode(2)
new_pw = QLineEdit()
new_pw.setEchoMode(2)
conf_pw = QLineEdit()
conf_pw.setEchoMode(2)
2012-02-13 10:12:24 -08:00
vbox = QVBoxLayout()
2012-02-14 01:05:38 -08:00
if parent:
msg = 'Your wallet is encrypted. Use this dialog to change your password.\nTo disable wallet encryption, enter an empty new password.' if wallet.use_encryption else 'Your wallet keys are not encrypted'
else:
msg = "Please choose a password to encrypt your wallet keys.\nLeave these fields empty if you want to disable encryption."
2012-02-13 10:12:24 -08:00
vbox.addWidget(QLabel(msg))
2012-02-13 05:52:59 -08:00
grid = QGridLayout()
grid.setSpacing(8)
2012-02-14 00:52:03 -08:00
if wallet.use_encryption:
2012-02-13 05:56:31 -08:00
grid.addWidget(QLabel('Password'), 1, 0)
grid.addWidget(pw, 1, 1)
2012-02-13 05:52:59 -08:00
grid.addWidget(QLabel('New Password'), 2, 0)
grid.addWidget(new_pw, 2, 1)
grid.addWidget(QLabel('Confirm Password'), 3, 0)
grid.addWidget(conf_pw, 3, 1)
2012-02-13 10:12:24 -08:00
vbox.addLayout(grid)
2012-02-13 05:52:59 -08:00
2012-02-14 00:52:03 -08:00
vbox.addLayout(ok_cancel_buttons(d))
2012-02-13 10:02:48 -08:00
d.setLayout(vbox)
2012-02-13 05:52:59 -08:00
if not d.exec_(): return
2012-02-14 00:52:03 -08:00
password = str(pw.text()) if wallet.use_encryption else None
2012-02-13 05:52:59 -08:00
new_password = str(new_pw.text())
new_password2 = str(conf_pw.text())
try:
2012-02-14 00:52:03 -08:00
seed = wallet.pw_decode( wallet.seed, password)
2012-02-13 05:52:59 -08:00
except:
2012-02-14 00:52:03 -08:00
QMessageBox.warning(parent, 'Error', 'Incorrect Password', 'OK')
2012-02-13 05:52:59 -08:00
return
if new_password != new_password2:
2012-02-14 00:52:03 -08:00
QMessageBox.warning(parent, 'Error', 'Passwords do not match', 'OK')
2012-02-13 05:52:59 -08:00
return
2012-02-14 00:52:03 -08:00
wallet.update_password(seed, new_password)
@staticmethod
def seed_dialog(wallet, parent=None):
d = QDialog(parent)
d.setModal(1)
vbox = QVBoxLayout()
msg = "Please enter your wallet seed or the corresponding mnemonic list of words, and the gap limit of your wallet."
vbox.addWidget(QLabel(msg))
grid = QGridLayout()
grid.setSpacing(8)
seed_e = QLineEdit()
grid.addWidget(QLabel('Seed or mnemonic'), 1, 0)
grid.addWidget(seed_e, 1, 1)
gap_e = QLineEdit()
gap_e.setText("5")
grid.addWidget(QLabel('Gap limit'), 2, 0)
grid.addWidget(gap_e, 2, 1)
vbox.addLayout(grid)
vbox.addLayout(ok_cancel_buttons(d))
d.setLayout(vbox)
if not d.exec_(): return
try:
gap = int(str(gap_e.text()))
except:
show_message("error")
sys.exit(1)
try:
seed = str(seed_e.text())
seed.decode('hex')
except:
import mnemonic
print "not hex, trying decode"
seed = mnemonic.mn_decode( seed.split(' ') )
if not seed:
show_message("no seed")
sys.exit(1)
wallet.seed = seed
wallet.gap_limit = gap
return True
2012-02-13 05:52:59 -08:00
2012-02-13 06:22:15 -08:00
def settings_dialog(self):
d = QDialog(self)
d.setModal(1)
2012-02-13 10:02:48 -08:00
vbox = QVBoxLayout()
2012-02-13 06:22:15 -08:00
2012-02-14 00:52:03 -08:00
msg = 'Here are the settings of your wallet'
2012-02-13 10:02:48 -08:00
vbox.addWidget(QLabel(msg))
grid = QGridLayout()
grid.setSpacing(8)
2012-02-13 06:22:15 -08:00
fee_line = QLineEdit()
fee_line.setText("%s"% str( Decimal( self.wallet.fee)/100000000 ) )
grid.addWidget(QLabel('Fee'), 2, 0)
grid.addWidget(fee_line, 2, 1)
2012-02-13 10:02:48 -08:00
vbox.addLayout(grid)
2012-02-13 06:22:15 -08:00
2012-02-14 00:52:03 -08:00
vbox.addLayout(ok_cancel_buttons(d))
2012-02-13 10:02:48 -08:00
d.setLayout(vbox)
2012-02-13 06:22:15 -08:00
if not d.exec_(): return
fee = str(fee_line.text())
try:
fee = int( 100000000 * Decimal(fee) )
except:
QMessageBox.warning(self, 'Error', 'Invalid value:%s'%fee, 'OK')
return
self.wallet.fee = fee
self.wallet.save()
2012-02-14 00:52:03 -08:00
@staticmethod
def network_dialog(wallet, parent=None):
2012-02-14 01:05:38 -08:00
if parent:
2012-02-13 06:44:16 -08:00
if wallet.interface.is_connected:
status = "Connected to %s.\n%d blocks\nresponse time: %f"%(wallet.interface.host, wallet.interface.blocks, wallet.interface.rtime)
else:
status = "Not connected"
2012-02-13 12:36:41 -08:00
host = wallet.interface.host
port = wallet.interface.port
2012-02-13 06:44:16 -08:00
else:
import random
status = "Please choose a server."
host = random.choice( wallet.interface.servers )
port = 50000
2012-02-14 00:52:03 -08:00
d = QDialog(parent)
2012-02-13 06:44:16 -08:00
d.setModal(1)
2012-02-13 10:02:48 -08:00
vbox = QVBoxLayout()
vbox.addWidget(QLabel(status))
2012-02-13 06:44:16 -08:00
grid = QGridLayout()
grid.setSpacing(8)
host_line = QLineEdit()
host_line.setText("%s:%d"% (host,port) )
grid.addWidget(QLabel('Server'), 2, 0)
grid.addWidget(host_line, 2, 1)
2012-02-13 10:02:48 -08:00
vbox.addLayout(grid)
2012-02-13 06:44:16 -08:00
2012-02-14 00:52:03 -08:00
vbox.addLayout(ok_cancel_buttons(d))
2012-02-13 10:02:48 -08:00
d.setLayout(vbox)
2012-02-13 06:44:16 -08:00
if not d.exec_(): return
hh = str( host_line.text() )
try:
if ':' in hh:
host, port = hh.split(':')
port = int(port)
else:
host = hh
port = 50000
except:
show_message("error")
if parent == None:
sys.exit(1)
else:
return
wallet.interface.set_server(host, port)
2012-02-14 00:52:03 -08:00
return True
2012-02-13 06:44:16 -08:00
2012-02-14 00:52:03 -08:00
class ElectrumGui():
2012-02-11 04:14:12 -08:00
def __init__(self, wallet):
self.wallet = wallet
2012-02-14 00:52:03 -08:00
self.app = QApplication(sys.argv)
def restore_or_create(self):
msg = "Wallet file not found.\nDo you want to create a new wallet,\n or to restore an existing one?"
r = QMessageBox.question(None, 'Message', msg, 'create', 'restore', 'cancel', 0, 2)
if r==2: return False
is_recovery = (r==1)
wallet = self.wallet
2012-02-14 01:05:38 -08:00
# ask for the server.
if not ElectrumWindow.network_dialog( wallet, parent=None ): return False
2012-02-14 00:52:03 -08:00
if not is_recovery:
wallet.new_seed(None)
# generate first key
wallet.synchronize()
# run a dialog indicating the seed, ask the user to remember it
ElectrumWindow.show_seed_dialog(wallet)
#ask for password
ElectrumWindow.change_password_dialog(wallet)
else:
# ask for seed and gap.
2012-02-14 01:05:38 -08:00
if not ElectrumWindow.seed_dialog( wallet ): return False
2012-02-14 00:52:03 -08:00
wallet.init_mpk( wallet.seed ) # not encrypted at this point
wallet.synchronize()
if wallet.is_found():
# history and addressbook
wallet.update_tx_history()
wallet.fill_addressbook()
print "recovery successful"
wallet.save()
else:
QMessageBox.information(None, 'Message', "No transactions found for this seed", 'OK')
wallet.save()
return True
2012-02-14 03:45:39 -08:00
def main(self,url):
2012-02-14 05:05:58 -08:00
s = Timer()
2012-02-11 13:19:22 -08:00
s.start()
2012-02-12 00:52:26 -08:00
w = ElectrumWindow(self.wallet)
2012-02-14 03:45:39 -08:00
if url: w.set_url(url)
2012-02-14 00:52:03 -08:00
w.app = self.app
2012-02-11 13:19:22 -08:00
w.connect_slots(s)
2012-02-14 00:52:03 -08:00
self.app.exec_()