2012-02-11 22:27:32 -08:00
|
|
|
import sys, time, datetime
|
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-11 13:19:22 -08:00
|
|
|
from wallet import format_satoshis
|
|
|
|
|
2012-02-11 04:14:12 -08:00
|
|
|
def restore_create_dialog(wallet):
|
|
|
|
pass
|
|
|
|
|
2012-02-11 13:19:22 -08:00
|
|
|
class Sender(QtCore.QThread):
|
|
|
|
def run(self):
|
|
|
|
while True:
|
|
|
|
self.emit(QtCore.SIGNAL('testsignal'))
|
|
|
|
time.sleep(0.5)
|
|
|
|
|
2012-02-11 04:14:12 -08:00
|
|
|
|
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-11 08:38:44 -08:00
|
|
|
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-11 22:27:32 -08:00
|
|
|
tabs.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.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-12 03:26:35 -08:00
|
|
|
self.setGeometry(100,100,800,400)
|
2012-02-12 01:58:38 -08:00
|
|
|
self.setWindowTitle( 'Electrum ' + self.wallet.electrum_version + ' - Qt')
|
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-11 13:19:22 -08:00
|
|
|
def connect_slots(self, sender):
|
|
|
|
self.connect(sender, QtCore.SIGNAL('testsignal'), self.update_wallet)
|
|
|
|
|
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-12 08:19:16 -08:00
|
|
|
icon = QIcon("icons/status_disconnected.svg")
|
2012-02-11 13:19:22 -08:00
|
|
|
elif not self.wallet.interface.was_polled:
|
|
|
|
text = "Synchronizing..."
|
2012-02-12 08:19:16 -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-12 08:19:16 -08:00
|
|
|
icon = QIcon("icons/status_connected.png")
|
2012-02-11 13:19:22 -08:00
|
|
|
else:
|
|
|
|
text = "Not connected"
|
2012-02-12 08:19:16 -08:00
|
|
|
icon = QIcon("icons/status_disconnected.svg")
|
|
|
|
|
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)
|
|
|
|
w.setColumnCount(5)
|
2012-02-12 01:58:38 -08:00
|
|
|
w.setColumnWidth(0, 40)
|
|
|
|
w.setColumnWidth(1, 140)
|
|
|
|
w.setColumnWidth(2, 340)
|
2012-02-12 03:26:35 -08:00
|
|
|
w.setColumnWidth(3, 120)
|
|
|
|
w.setColumnWidth(4, 120)
|
2012-02-12 09:02:11 -08:00
|
|
|
w.setHeaderLabels( [ '', 'Date', 'Description', 'Amount', 'Balance', ''] )
|
|
|
|
self.connect(w, SIGNAL('itemClicked(QTreeWidgetItem*, int)'), self.tx_label)
|
|
|
|
self.connect(w, SIGNAL('itemActivated(QTreeWidgetItem*, int)'), self.tx_details)
|
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')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def tx_label(self, item, column):
|
|
|
|
if column==2:
|
|
|
|
print 's', item, column
|
|
|
|
|
|
|
|
|
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-12 05:27:36 -08:00
|
|
|
icon = QIcon("icons/confirmed.png")
|
2012-02-11 22:27:32 -08:00
|
|
|
else:
|
|
|
|
conf = 0
|
|
|
|
time_str = 'pending'
|
2012-02-12 05:27:36 -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:
|
|
|
|
item.setForeground(2, QBrush(QColor('gray')))
|
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()
|
|
|
|
|
|
|
|
paytoEdit = QtGui.QLineEdit()
|
|
|
|
descriptionEdit = QtGui.QLineEdit()
|
|
|
|
amountEdit = QtGui.QLineEdit()
|
|
|
|
feeEdit = QtGui.QLineEdit()
|
|
|
|
|
|
|
|
grid = QtGui.QGridLayout()
|
|
|
|
grid.setSpacing(8)
|
|
|
|
|
|
|
|
grid.addWidget(QLabel('Pay to'), 1, 0)
|
|
|
|
grid.addWidget(paytoEdit, 1, 1)
|
|
|
|
|
|
|
|
grid.addWidget(QLabel('Description'), 2, 0)
|
|
|
|
grid.addWidget(descriptionEdit, 2, 1)
|
|
|
|
|
|
|
|
grid.addWidget(QLabel('Amount'), 3, 0)
|
|
|
|
grid.addWidget(amountEdit, 3, 1)
|
|
|
|
|
|
|
|
grid.addWidget(QLabel('Fee'), 4, 0)
|
|
|
|
grid.addWidget(feeEdit, 4, 1)
|
|
|
|
|
|
|
|
w.setLayout(grid)
|
|
|
|
w.show()
|
|
|
|
|
|
|
|
w2 = QWidget()
|
|
|
|
vbox = QtGui.QVBoxLayout()
|
|
|
|
vbox.addWidget(w)
|
|
|
|
vbox.addStretch(1)
|
|
|
|
w2.setLayout(vbox)
|
|
|
|
|
|
|
|
return w2
|
2012-02-11 08:02:28 -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)
|
|
|
|
l.setColumnWidth(0, 330)
|
|
|
|
l.setColumnWidth(1, 330)
|
|
|
|
l.setColumnWidth(2, 20)
|
|
|
|
l.setHeaderLabels( ['Address', 'Label','Tx'])
|
2012-02-12 01:58:38 -08:00
|
|
|
|
2012-02-12 02:26:38 -08:00
|
|
|
vbox = QtGui.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)
|
|
|
|
|
|
|
|
hbox = QtGui.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-12 02:26:38 -08:00
|
|
|
qrButton = QtGui.QPushButton("QR")
|
|
|
|
copyButton = QtGui.QPushButton("Copy to Clipboard")
|
|
|
|
hbox.addWidget(qrButton)
|
|
|
|
hbox.addWidget(copyButton)
|
|
|
|
if not is_recv:
|
|
|
|
addButton = QtGui.QPushButton("New")
|
|
|
|
paytoButton = QtGui.QPushButton("Pay to")
|
|
|
|
hbox.addWidget(addButton)
|
|
|
|
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):
|
|
|
|
w, self.receive_list = self.make_address_list(True)
|
|
|
|
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-11 08:02:28 -08:00
|
|
|
def create_contacts_tab(self):
|
2012-02-12 02:26:38 -08:00
|
|
|
w, self.contacts_list = self.make_address_list(False)
|
|
|
|
return w
|
2012-02-11 08:02:28 -08:00
|
|
|
|
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)
|
|
|
|
|
|
|
|
hbox = QtGui.QHBoxLayout()
|
|
|
|
hbox.setMargin(0)
|
|
|
|
buttons = QWidget()
|
|
|
|
buttons.setLayout(hbox)
|
2012-02-12 03:26:35 -08:00
|
|
|
|
2012-02-12 05:08:19 -08:00
|
|
|
icon = QIcon("icons/lock.svg")
|
2012-02-12 03:26:35 -08:00
|
|
|
b = QPushButton( icon, '' )
|
2012-02-12 05:08:19 -08:00
|
|
|
b.setToolTip("Password")
|
2012-02-12 03:26:35 -08:00
|
|
|
b.setFlat(True)
|
2012-02-12 05:08:19 -08:00
|
|
|
b.setMaximumWidth(25)
|
2012-02-12 08:19:16 -08:00
|
|
|
hbox.addWidget(b)
|
2012-02-12 03:26:35 -08:00
|
|
|
|
2012-02-12 05:08:19 -08:00
|
|
|
icon = QIcon("icons/preferences.svg")
|
2012-02-12 03:26:35 -08:00
|
|
|
b = QPushButton( icon, '' )
|
2012-02-12 05:08:19 -08:00
|
|
|
b.setToolTip("Preferences")
|
2012-02-12 03:26:35 -08:00
|
|
|
b.setFlat(True)
|
2012-02-12 05:08:19 -08:00
|
|
|
b.setMaximumWidth(25)
|
2012-02-12 08:19:16 -08:00
|
|
|
hbox.addWidget(b)
|
2012-02-12 03:26:35 -08:00
|
|
|
|
2012-02-12 05:08:19 -08:00
|
|
|
icon = QIcon("icons/seed.png")
|
2012-02-12 03:26:35 -08:00
|
|
|
b = QPushButton( icon, '' )
|
2012-02-12 05:08:19 -08:00
|
|
|
b.setToolTip("Seed")
|
2012-02-12 03:26:35 -08:00
|
|
|
b.setFlat(True)
|
2012-02-12 08:19:16 -08:00
|
|
|
b.setMaximumWidth(20)
|
|
|
|
hbox.addWidget(b)
|
2012-02-12 03:26:35 -08:00
|
|
|
|
2012-02-12 05:08:19 -08:00
|
|
|
icon = QIcon("icons/status_disconnected.svg")
|
2012-02-12 08:19:16 -08:00
|
|
|
self.status_button = b = QPushButton( icon, '' )
|
2012-02-12 05:08:19 -08:00
|
|
|
b.setToolTip("Network")
|
2012-02-12 03:26:35 -08:00
|
|
|
b.setFlat(True)
|
2012-02-12 05:08:19 -08:00
|
|
|
b.setMaximumWidth(25)
|
2012-02-12 08:19:16 -08:00
|
|
|
hbox.addWidget(b)
|
2012-02-12 03:26:35 -08:00
|
|
|
|
2012-02-12 08:19:16 -08:00
|
|
|
sb.addPermanentWidget(buttons)
|
2012-02-11 08:38:44 -08:00
|
|
|
self.setStatusBar(sb)
|
|
|
|
|
2012-02-11 04:14:12 -08:00
|
|
|
|
|
|
|
class BitcoinGUI():
|
|
|
|
|
|
|
|
def __init__(self, wallet):
|
|
|
|
self.wallet = wallet
|
|
|
|
|
|
|
|
def main(self):
|
2012-02-11 13:19:22 -08:00
|
|
|
s = Sender()
|
|
|
|
s.start()
|
2012-02-11 04:14:12 -08:00
|
|
|
app = QApplication(sys.argv)
|
2012-02-12 00:52:26 -08:00
|
|
|
w = ElectrumWindow(self.wallet)
|
2012-02-11 13:19:22 -08:00
|
|
|
w.connect_slots(s)
|
2012-02-11 04:14:12 -08:00
|
|
|
app.exec_()
|