electrum-bitcoinprivate/lib/gui_qt.py

1426 lines
48 KiB
Python
Raw Normal View History

2012-02-14 07:44:23 -08:00
#!/usr/bin/env python
#
# Electrum - lightweight Bitcoin client
# Copyright (C) 2012 thomasv@gitorious
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2012-02-13 07:49:20 -08:00
import sys, time, datetime, re
from i18n import _
2012-02-11 04:14:12 -08:00
try:
import PyQt4
except:
print "could not import PyQt4"
print "on Linux systems, you may try 'sudo apt-get install python-qt4'"
sys.exit(1)
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-03-31 05:20:25 -07:00
from interface import DEFAULT_SERVERS
2012-02-11 04:14:12 -08:00
try:
import icons_rc
except:
2012-02-14 14:13:17 -08:00
print "Could not import icons_rp.py"
print "Please generate it with: 'pyrcc4 icons.qrc -o icons_rc.py'"
sys.exit(1)
2012-02-14 02:33:09 -08:00
2012-02-11 13:19:22 -08:00
from wallet import format_satoshis
import bmp, mnemonic, pyqrnative
2012-02-13 06:22:15 -08:00
from decimal import Decimal
2012-02-11 13:19:22 -08:00
2012-03-31 07:46:32 -07:00
import platform
MONOSPACE_FONT = 'Lucida Console' if platform.system() == 'Windows' else 'monospace'
ALIAS_REGEXP = '^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$'
2012-02-14 00:52:03 -08:00
2012-02-14 05:34:19 -08:00
def numbify(entry, is_int = False):
2012-02-14 14:11:59 -08:00
text = unicode(entry.text()).strip()
2012-02-14 05:34:19 -08:00
chars = '0123456789'
if not is_int: chars +='.'
s = ''.join([i for i in text if i in chars])
if not is_int:
if '.' in s:
p = s.find('.')
s = s.replace('.','')
s = s[:p] + '.' + s[p:p+8]
try:
amount = int( Decimal(s) * 100000000 )
except:
amount = None
else:
try:
amount = int( s )
except:
amount = None
entry.setText(s)
return amount
2012-02-14 00:52:03 -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-14 07:41:09 -08:00
class EnterButton(QPushButton):
def __init__(self, text, func):
QPushButton.__init__(self, text)
self.func = func
self.clicked.connect(func)
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Return:
apply(self.func,())
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 07:41:09 -08:00
class QRCodeWidget(QWidget):
def __init__(self, addr):
super(QRCodeWidget, self).__init__()
self.setGeometry(300, 300, 350, 350)
self.set_addr(addr)
def set_addr(self, addr):
self.addr = addr
self.qr = pyqrnative.QRCode(4, pyqrnative.QRErrorCorrectLevel.L)
2012-02-14 07:41:09 -08:00
self.qr.addData(addr)
self.qr.make()
def paintEvent(self, e):
qp = QtGui.QPainter()
qp.begin(self)
boxsize = 7
size = self.qr.getModuleCount()*boxsize
k = self.qr.getModuleCount()
black = QColor(0, 0, 0, 255)
white = QColor(255, 255, 255, 255)
for r in range(k):
for c in range(k):
if self.qr.isDark(r, c):
qp.setBrush(black)
qp.setPen(black)
else:
qp.setBrush(white)
qp.setPen(white)
qp.drawRect(c*boxsize, r*boxsize, boxsize, boxsize)
qp.end()
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-04-07 06:13:18 -07:00
self.wallet.gui_callback = self.update_callback
2012-02-14 05:34:19 -08:00
self.funds_error = False
2012-02-11 13:19:22 -08:00
2012-02-13 08:16:02 -08:00
self.tabs = tabs = QTabWidget(self)
tabs.addTab(self.create_history_tab(), _('History') )
if self.wallet.seed:
tabs.addTab(self.create_send_tab(), _('Send') )
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-05-13 01:54:03 -07:00
title = 'Electrum ' + self.wallet.electrum_version + ' - ' + self.wallet.path
2012-05-13 02:09:31 -07:00
if not self.wallet.seed: title += ' [seedless]'
2012-05-13 01:54:03 -07:00
self.setWindowTitle( title )
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-04-07 06:13:18 -07:00
self.connect(self, QtCore.SIGNAL('updatesignal'), self.update_wallet)
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):
if self.wallet.seed:
self.connect(sender, QtCore.SIGNAL('timersignal'), self.check_recipient)
self.previous_payto_e=''
2012-02-14 05:05:58 -08:00
def check_recipient(self):
if self.payto_e.hasFocus():
return
2012-02-14 14:11:59 -08:00
r = unicode( self.payto_e.text() )
2012-02-14 05:05:58 -08:00
if r != self.previous_payto_e:
self.previous_payto_e = r
r = r.strip()
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', r):
try:
2012-02-15 02:35:22 -08:00
to_address = self.wallet.get_alias(r, True, self.show_message, self.question)
2012-02-14 05:05:58 -08:00
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-04-07 06:13:18 -07:00
def update_callback(self):
self.emit(QtCore.SIGNAL('updatesignal'))
2012-02-11 13:19:22 -08:00
def update_wallet(self):
if self.wallet.interface and self.wallet.interface.is_connected:
if self.wallet.blocks == -1:
text = _( "Connecting..." )
icon = QIcon(":icons/status_disconnected.png")
elif self.wallet.blocks == 0:
text = _( "Server not ready" )
2012-02-14 02:33:09 -08:00
icon = QIcon(":icons/status_disconnected.png")
elif not self.wallet.up_to_date:
text = _( "Synchronizing..." )
2012-03-18 04:38:40 -07:00
icon = QIcon(":icons/status_waiting.png")
2012-02-11 13:19:22 -08:00
else:
c, u = self.wallet.get_balance()
text = _( "Balance" ) + ": %s "%( format_satoshis(c,False,self.wallet.num_zeros) )
if u: text += "[%s unconfirmed]"%( format_satoshis(u,True,self.wallet.num_zeros).strip() )
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-14 05:34:19 -08:00
if self.funds_error:
text = _( "Not enough funds" )
2012-02-14 05:34:19 -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
2012-04-07 06:13:18 -07:00
if self.wallet.up_to_date:
self.textbox.setText( self.wallet.banner )
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()
self.update_completions()
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)
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.blocks - tx['height'] + 1
2012-03-30 01:48:32 -07:00
time_str = datetime.datetime.fromtimestamp( tx['timestamp']).isoformat(' ')[:-3]
2012-02-12 09:02:11 -08:00
else:
conf = 0
time_str = 'pending'
tx_details = _("Transaction Details") +"\n\n" \
2012-02-12 09:02:11 -08:00
+ "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)
2012-02-14 14:11:59 -08:00
text = unicode( 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
def edit_label(self, is_recv):
l = self.receive_list if is_recv else self.contacts_list
c = 2 if is_recv else 1
item = l.currentItem()
item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
l.editItem( item, c )
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
2012-06-07 07:07:49 -07:00
def address_label_clicked(self, item, column, l, column_addr, column_label):
if column==column_label and item.isSelected():
addr = unicode( item.text(column_addr) )
label = unicode( item.text(column_label) )
if label in self.wallet.aliases.keys():
2012-04-20 02:50:19 -07:00
return
2012-02-12 15:00:33 -08:00
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)
2012-06-07 07:07:49 -07:00
def address_label_changed(self, item, column, l, column_addr, column_label):
addr = unicode( item.text(column_addr) )
text = unicode( item.text(column_label) )
2012-02-12 15:00:33 -08:00
if text:
2012-06-09 03:39:59 -07:00
if text not in self.wallet.aliases.keys():
self.wallet.labels[addr] = text
else:
2012-06-09 03:39:59 -07:00
print "error: this is one of your aliases"
label = self.wallet.labels.get(addr,'')
item.setText(column_label, QString(label))
2012-02-12 15:00:33 -08:00
else:
s = self.wallet.labels.get(addr)
if s: self.wallet.labels.pop(addr)
2012-02-12 15:00:33 -08:00
self.update_history_tab()
self.update_completions()
2012-02-12 15:00:33 -08:00
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.blocks - tx['height'] + 1
2012-03-30 01:48:32 -07:00
time_str = datetime.datetime.fromtimestamp( tx['timestamp']).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-03-18 04:38:40 -07:00
icon = QIcon(":icons/unconfirmed.png")
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
item = QTreeWidgetItem( [ '', time_str, label, format_satoshis(v,True,self.wallet.num_zeros), format_satoshis(balance,False,self.wallet.num_zeros)] )
2012-03-30 14:44:54 -07:00
item.setFont(2, QFont(MONOSPACE_FONT))
item.setFont(3, QFont(MONOSPACE_FONT))
item.setFont(4, QFont(MONOSPACE_FONT))
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()
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
completer = QCompleter()
self.payto_e.setCompleter(completer)
self.completions = QStringListModel()
completer.setModel(self.completions)
2012-02-14 04:38:47 -08:00
self.message_e = QLineEdit()
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()
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()
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
b = EnterButton(_("Send"), self.do_send)
2012-02-13 07:49:20 -08:00
grid.addWidget(b, 5, 1)
2012-02-13 05:52:59 -08:00
b = EnterButton(_("Clear"),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)
2012-02-14 05:34:19 -08:00
def entry_changed( is_fee ):
self.funds_error = False
amount = numbify(self.amount_e)
fee = numbify(self.fee_e)
if not is_fee: fee = None
if amount is None:
return
inputs, total, fee = self.wallet.choose_tx_inputs( amount, fee )
if not is_fee:
self.fee_e.setText( str( Decimal( fee ) / 100000000 ) )
if inputs:
palette = QPalette()
palette.setColor(self.amount_e.foregroundRole(), QColor('black'))
else:
palette = QPalette()
palette.setColor(self.amount_e.foregroundRole(), QColor('red'))
self.funds_error = True
self.amount_e.setPalette(palette)
self.fee_e.setPalette(palette)
self.amount_e.textChanged.connect(lambda: entry_changed(False) )
self.fee_e.textChanged.connect(lambda: entry_changed(True) )
2012-02-11 22:27:32 -08:00
return w2
2012-02-11 08:02:28 -08:00
def update_completions(self):
l = []
for addr,label in self.wallet.labels.items():
if addr in self.wallet.addressbook:
l.append( label + ' <' + addr + '>')
l = l + self.wallet.aliases.keys()
self.completions.setStringList(l)
2012-02-14 04:38:47 -08:00
def do_send(self):
2012-02-13 07:49:20 -08:00
2012-02-14 14:11:59 -08:00
label = unicode( self.message_e.text() )
r = unicode( self.payto_e.text() )
2012-02-13 07:49:20 -08:00
r = r.strip()
# alias
m1 = re.match(ALIAS_REGEXP, r)
# label or alias, with address in brackets
m2 = re.match('(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
2012-02-13 07:49:20 -08:00
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(2)
2012-02-13 07:49:20 -08:00
else:
to_address = r
if not self.wallet.is_valid(to_address):
QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address') + ':\n' + to_address, _('OK'))
2012-02-13 07:49:20 -08:00
return
try:
2012-02-14 14:11:59 -08:00
amount = int( Decimal( unicode( self.amount_e.text())) * 100000000 )
2012-02-13 07:49:20 -08:00
except:
QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
2012-02-13 07:49:20 -08:00
return
try:
2012-02-14 14:11:59 -08:00
fee = int( Decimal( unicode( self.fee_e.text())) * 100000000 )
2012-02-13 07:49:20 -08:00
except:
QMessageBox.warning(self, _('Error'), _('Invalid Fee'), _('OK'))
2012-02-13 07:49:20 -08:00
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(str(e))
2012-02-13 07:49:20 -08:00
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-13 07:49:20 -08:00
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)
label = self.wallet.labels.get(payto)
if label:
self.payto_e.setText(label + ' <'+ payto+'>')
2012-02-14 04:38:47 -08:00
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-05-13 04:09:59 -07:00
def get_current_addr(self, is_recv):
if is_recv:
l = self.receive_list
2012-06-07 07:07:49 -07:00
n = 1
2012-05-13 04:09:59 -07:00
else:
l = self.contacts_list
2012-06-07 07:07:49 -07:00
n = 0
2012-05-13 04:09:59 -07:00
i = l.currentItem()
if i:
2012-06-07 07:07:49 -07:00
return unicode( i.text(n) )
2012-05-13 04:09:59 -07:00
else:
return ''
2012-02-11 08:02:28 -08:00
2012-05-05 02:33:53 -07:00
2012-06-07 08:36:39 -07:00
def toggle_freeze(self,addr):
if not addr: return
if addr in self.wallet.frozen_addresses:
self.wallet.unfreeze(addr)
else:
self.wallet.freeze(addr)
self.update_receive_tab()
def toggle_priority(self,addr):
if not addr: return
if addr in self.wallet.prioritized_addresses:
self.wallet.unprioritize(addr)
else:
self.wallet.prioritize(addr)
self.update_receive_tab()
2012-06-06 05:55:11 -07:00
def create_list_tab(self, headers):
"generic tab creatino method"
2012-02-12 02:26:38 -08:00
l = QTreeWidget(self)
2012-06-06 05:55:11 -07:00
l.setColumnCount( len(headers) )
l.setHeaderLabels( headers )
2012-02-12 01:58:38 -08:00
2012-05-05 02:33:53 -07:00
w = QWidget()
2012-02-13 10:02:48 -08:00
vbox = QVBoxLayout()
2012-05-05 02:33:53 -07:00
w.setLayout(vbox)
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-05-05 02:33:53 -07:00
buttons = QWidget()
vbox.addWidget(buttons)
2012-02-12 02:26:38 -08:00
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-12 02:26:38 -08:00
buttons.setLayout(hbox)
2012-06-06 05:55:11 -07:00
return l,w,hbox
2012-05-13 04:09:59 -07:00
2012-06-07 08:36:39 -07:00
2012-06-06 05:55:11 -07:00
def create_receive_tab(self):
2012-06-07 07:07:49 -07:00
l,w,hbox = self.create_list_tab([_('Flags'), _('Address'), _('Label'), _('Balance'), _('Tx')])
2012-06-07 08:36:39 -07:00
l.setContextMenuPolicy(Qt.CustomContextMenu)
l.customContextMenuRequested.connect(self.create_receive_menu)
2012-06-07 07:07:49 -07:00
self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,1,2))
self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,1,2))
2012-02-12 15:00:33 -08:00
self.receive_list = l
2012-05-05 02:51:06 -07:00
self.receive_buttons_hbox = hbox
2012-06-07 08:36:39 -07:00
2012-06-07 09:52:29 -07:00
self.new_address_button = EnterButton(_("New"), self.change_gap_limit_dialog)
2012-06-07 08:42:50 -07:00
self.new_address_button.setHidden(not self.wallet.expert_mode)
2012-06-07 08:36:39 -07:00
hbox.addWidget(self.new_address_button)
hbox.addStretch(1)
2012-05-13 04:09:59 -07:00
2012-02-12 15:00:33 -08:00
return w
2012-06-07 08:36:39 -07:00
2012-02-12 15:00:33 -08:00
def create_contacts_tab(self):
2012-06-06 05:55:11 -07:00
l,w,hbox = self.create_list_tab([_('Address'), _('Label'), _('Tx')])
2012-06-07 08:36:39 -07:00
l.setContextMenuPolicy(Qt.CustomContextMenu)
l.customContextMenuRequested.connect(self.create_contact_menu)
2012-02-12 15:00:33 -08:00
self.connect(l, SIGNAL('itemActivated(QTreeWidgetItem*, int)'), self.show_contact_details)
2012-06-07 07:07:49 -07:00
self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,0,1))
self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,0,1))
2012-02-12 15:00:33 -08:00
self.contacts_list = l
2012-05-05 02:51:06 -07:00
self.contacts_buttons_hbox = hbox
hbox.addWidget(EnterButton(_("New"), self.new_contact_dialog))
2012-06-07 08:36:39 -07:00
hbox.addStretch(1)
2012-02-12 02:26:38 -08:00
return w
2012-02-12 01:58:38 -08:00
2012-06-07 08:36:39 -07:00
def create_receive_menu(self, position):
# fixme: this function apparently has a side effect.
# if it is not called the menu pops up several times
self.receive_list.selectedIndexes()
addr = self.get_current_addr(True)
menu = QMenu()
menu.addAction(_("Copy to Clipboard"), lambda: self.app.clipboard().setText(addr))
menu.addAction(_("View QR code"),lambda: self.show_address_qrcode(addr))
menu.addAction(_("Edit label"), lambda: self.edit_label(True))
2012-06-07 08:42:50 -07:00
if self.wallet.expert_mode:
2012-06-07 08:36:39 -07:00
t = _("Unfreeze") if addr in self.wallet.frozen_addresses else _("Freeze")
menu.addAction(t, lambda: self.toggle_freeze(addr))
t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize")
menu.addAction(t, lambda: self.toggle_priority(addr))
menu.exec_(self.receive_list.viewport().mapToGlobal(position))
def payto(self, addr):
if not addr:return
self.tabs.setCurrentIndex(1)
self.payto_e.setText(addr)
self.amount_e.setFocus()
2012-06-09 08:32:52 -07:00
def delete_contact(self, addr, is_alias):
if self.question("Do you want to remove %s from your list of contacts?"%addr):
2012-06-09 08:32:52 -07:00
if not is_alias and addr in self.wallet.addressbook:
self.wallet.addressbook.remove(addr)
if addr in self.wallet.labels.keys():
self.wallet.labels.pop(addr)
elif is_alias and addr in self.wallet.aliases:
self.wallet.aliases.pop(addr)
self.update_history_tab()
self.update_contacts_tab()
self.update_completions()
2012-06-07 08:36:39 -07:00
def create_contact_menu(self, position):
# fixme: this function apparently has a side effect.
# if it is not called the menu pops up several times
self.contacts_list.selectedIndexes()
2012-06-07 08:36:39 -07:00
addr = self.get_current_addr(False)
menu = QMenu()
menu.addAction(_("Pay to"), lambda: self.payto(addr))
2012-06-07 08:36:39 -07:00
menu.addAction(_("Copy to Clipboard"), lambda: self.app.clipboard().setText(addr))
menu.addAction(_("View QR code"),lambda: self.show_address_qrcode(addr))
item = self.contacts_list.currentItem()
label = unicode( item.text(1) )
if label not in self.wallet.aliases.keys():
menu.addAction(_("Edit label"), lambda: self.edit_label(False))
2012-06-09 08:32:52 -07:00
menu.addAction(_("Delete"), lambda: self.delete_contact(addr,False))
else:
menu.addAction(_("Delete"), lambda: self.delete_contact(label,True))
menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
2012-06-07 08:36:39 -07:00
2012-02-11 22:45:18 -08:00
def update_receive_tab(self):
2012-06-07 07:07:49 -07:00
l = self.receive_list
l.clear()
2012-06-07 08:42:50 -07:00
l.setColumnHidden(0,not self.wallet.expert_mode)
l.setColumnHidden(3,not self.wallet.expert_mode)
l.setColumnHidden(4,not self.wallet.expert_mode)
2012-06-07 07:07:49 -07:00
l.setColumnWidth(0, 50)
l.setColumnWidth(1, 310)
l.setColumnWidth(2, 300)
l.setColumnWidth(3, 90)
2012-06-07 08:36:39 -07:00
l.setColumnWidth(4, 10)
2012-06-07 08:42:50 -07:00
self.new_address_button.setHidden(not self.wallet.expert_mode)
2012-06-07 08:36:39 -07:00
2012-06-07 08:42:50 -07:00
#self.prioritize_button.setHidden(not self.wallet.expert_mode)
#self.freeze_button.setHidden(not self.wallet.expert_mode)
2012-06-07 08:36:39 -07:00
gap = 0
2012-06-06 07:08:29 -07:00
is_red = False
2012-02-11 22:45:18 -08:00
for address in self.wallet.all_addresses():
2012-06-07 07:07:49 -07:00
2012-06-07 08:42:50 -07:00
if self.wallet.is_change(address) and not self.wallet.expert_mode:
2012-06-07 07:07:49 -07:00
continue
2012-06-06 05:55:11 -07:00
2012-02-11 22:45:18 -08:00
label = self.wallet.labels.get(address,'')
n = 0
h = self.wallet.history.get(address,[])
for item in h:
2012-03-30 01:48:32 -07:00
if not item['is_input'] : n=n+1
if n==0:
tx = "None"
if address in self.wallet.addresses:
gap += 1
2012-06-06 07:08:29 -07:00
if gap > self.wallet.gap_limit:
is_red = True
else:
tx = "%d"%n
if address in self.wallet.addresses:
gap = 0
2012-05-05 02:33:53 -07:00
c, u = self.wallet.get_addr_balance(address)
balance = format_satoshis( c + u, False, self.wallet.num_zeros )
2012-06-07 07:14:08 -07:00
flags = self.wallet.get_address_flags(address)
2012-06-07 07:07:49 -07:00
item = QTreeWidgetItem( [ flags, address, label, balance, tx] )
2012-06-07 07:14:08 -07:00
item.setFont(0, QFont(MONOSPACE_FONT))
2012-06-07 07:07:49 -07:00
item.setFont(1, QFont(MONOSPACE_FONT))
2012-05-05 02:33:53 -07:00
if address in self.wallet.frozen_addresses:
2012-06-07 07:07:49 -07:00
item.setBackgroundColor(1, QColor('lightblue'))
2012-06-06 06:40:57 -07:00
elif address in self.wallet.prioritized_addresses:
2012-06-07 07:07:49 -07:00
item.setBackgroundColor(1, QColor('lightgreen'))
if is_red and address in self.wallet.addresses:
2012-06-07 07:07:49 -07:00
item.setBackgroundColor(1, QColor('red'))
2012-06-07 07:07:49 -07:00
self.receive_list.addTopLevelItem(item)
2012-02-11 22:45:18 -08:00
2012-02-12 12:41:42 -08:00
def show_contact_details(self, item, column):
2012-02-14 14:11:59 -08:00
m = unicode(item.text(0))
2012-02-12 12:41:42 -08:00
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):
2012-06-07 07:07:49 -07:00
l = self.contacts_list
l.clear()
2012-06-07 08:42:50 -07:00
l.setColumnHidden(2, not self.wallet.expert_mode)
2012-06-07 08:36:39 -07:00
l.setColumnWidth(0, 350)
l.setColumnWidth(1, 330)
l.setColumnWidth(2, 100)
2012-05-05 02:51:06 -07:00
alias_targets = []
2012-02-11 22:45:18 -08:00
for alias, v in self.wallet.aliases.items():
s, target = v
alias_targets.append(target)
2012-04-20 02:50:19 -07:00
item = QTreeWidgetItem( [ target, alias, '-'] )
item.setBackgroundColor(1, QColor('lightgray'))
2012-02-11 22:45:18 -08:00
self.contacts_list.addTopLevelItem(item)
for address in self.wallet.addressbook:
if address in alias_targets: continue
2012-02-11 22:45:18 -08:00
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-03-30 14:44:54 -07:00
item.setFont(0, QFont(MONOSPACE_FONT))
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)
2012-03-30 14:44:54 -07:00
textbox.setFont(QFont(MONOSPACE_FONT))
2012-02-11 13:19:22 -08:00
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-05-13 01:54:03 -07:00
if self.wallet.seed:
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/lock.png"), "Password", lambda: self.change_password_dialog(self.wallet, self) ) )
2012-02-14 02:33:09 -08:00
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), "Preferences", self.settings_dialog ) )
2012-05-13 01:54:03 -07:00
if self.wallet.seed:
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), "Seed", lambda: self.show_seed_dialog(self.wallet, self) ) )
2012-02-14 02:33:09 -08:00
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)
def new_contact_dialog(self):
text, ok = QInputDialog.getText(self, _('New Contact'), _('Address') + ':')
2012-02-14 14:11:59 -08:00
address = unicode(text)
2012-02-12 15:00:33 -08:00
if ok:
if self.wallet.is_valid(address):
self.wallet.addressbook.append(address)
self.wallet.save()
self.update_contacts_tab()
self.update_history_tab()
self.update_completions()
2012-02-12 15:00:33 -08:00
else:
QMessageBox.warning(self, _('Error'), _('Invalid Address'), _('OK'))
2012-02-12 15:00:33 -08:00
2012-02-14 00:52:03 -08:00
@staticmethod
def show_seed_dialog(wallet, parent=None):
2012-05-12 15:43:22 -07:00
if not wallet.seed:
QMessageBox.information(parent, _('Message'), _('No seed'), _('OK'))
2012-05-12 15:43:22 -07:00
return
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-05-21 13:26:55 -07:00
QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
2012-02-13 06:11:31 -08:00
return
2012-02-12 15:00:33 -08:00
msg = _("Your wallet generation seed is") + ":\n\n" + seed + "\n\n"\
+ _("Please 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\"" \
2012-05-05 08:38:02 -07:00
+ ' '.join(mnemonic.mn_encode(seed)) + "\"\n\n\n"
2012-02-13 06:11:31 -08:00
d = QDialog(None)
d.setModal(1)
d.setWindowTitle(_("Seed"))
2012-05-05 08:38:02 -07:00
d.setMinimumSize(400, 270)
vbox = QVBoxLayout()
hbox = QHBoxLayout()
2012-05-05 08:38:02 -07:00
vbox2 = QVBoxLayout()
l = QLabel()
2012-05-05 08:38:02 -07:00
l.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
vbox2.addWidget(l)
vbox2.addStretch(1)
hbox.addLayout(vbox2)
hbox.addWidget(QLabel(msg))
vbox.addLayout(hbox)
hbox = QHBoxLayout()
hbox.addStretch(1)
if parent:
app = parent.app
else:
app = QApplication
b = QPushButton(_("Copy to Clipboard"))
b.clicked.connect(lambda: app.clipboard().setText(seed + ' "' + ' '.join(mnemonic.mn_encode(seed))+'"'))
hbox.addWidget(b)
b = QPushButton(_("View as QR Code"))
b.clicked.connect(lambda: ElectrumWindow.show_seed_qrcode(seed))
hbox.addWidget(b)
b = QPushButton(_("OK"))
b.clicked.connect(d.accept)
hbox.addWidget(b)
vbox.addLayout(hbox)
d.setLayout(vbox)
d.exec_()
2012-02-13 06:11:31 -08:00
2012-04-09 12:02:59 -07:00
@staticmethod
def show_seed_qrcode(seed):
if not seed: return
d = QDialog(None)
d.setModal(1)
d.setWindowTitle(_("Seed"))
d.setMinimumSize(270, 300)
vbox = QVBoxLayout()
vbox.addWidget(QRCodeWidget(seed))
hbox = QHBoxLayout()
hbox.addStretch(1)
b = QPushButton(_("OK"))
hbox.addWidget(b)
b.clicked.connect(d.accept)
vbox.addLayout(hbox)
d.setLayout(vbox)
d.exec_()
2012-06-07 08:36:39 -07:00
def show_address_qrcode(self,address):
2012-04-09 12:02:59 -07:00
if not address: return
2012-06-07 08:36:39 -07:00
d = QDialog(self)
2012-04-09 12:02:59 -07:00
d.setModal(1)
d.setWindowTitle(address)
d.setMinimumSize(270, 350)
2012-04-09 12:02:59 -07:00
vbox = QVBoxLayout()
qrw = QRCodeWidget(address)
vbox.addWidget(qrw)
hbox = QHBoxLayout()
amount_e = QLineEdit()
hbox.addWidget(QLabel(_('Amount')))
hbox.addWidget(amount_e)
vbox.addLayout(hbox)
#hbox = QHBoxLayout()
#label_e = QLineEdit()
#hbox.addWidget(QLabel('Label'))
#hbox.addWidget(label_e)
#vbox.addLayout(hbox)
def amount_changed():
amount = numbify(amount_e)
#label = str( label_e.getText() )
if amount is not None:
qrw.set_addr('bitcoin:%s?amount=%s'%(address,str( Decimal(amount) /100000000)))
else:
qrw.set_addr( address )
qrw.repaint()
def do_save():
bmp.save_qrcode(qrw.qr, "qrcode.bmp")
self.show_message(_("QR code saved to file") + " 'qrcode.bmp'")
amount_e.textChanged.connect( amount_changed )
hbox = QHBoxLayout()
hbox.addStretch(1)
b = QPushButton(_("Save"))
b.clicked.connect(do_save)
hbox.addWidget(b)
b = QPushButton(_("Close"))
hbox.addWidget(b)
b.clicked.connect(d.accept)
vbox.addLayout(hbox)
2012-04-09 12:02:59 -07:00
d.setLayout(vbox)
d.exec_()
2012-04-03 16:13:12 -07: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) == QMessageBox.Yes
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 00:52:03 -08:00
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()
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)
grid.addWidget(QLabel(_('Password')), 1, 0)
2012-02-13 06:11:31 -08:00
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
2012-02-14 14:11:59 -08:00
return unicode(pw.text())
2012-02-13 06:11:31 -08:00
2012-06-07 09:52:29 -07:00
def change_gap_limit_dialog(self):
d = QDialog(self)
d.setModal(1)
vbox = QVBoxLayout()
msg = _('In order to create more addresses, you need to raise your gap limit.') + '\n' \
+ _('Your current gap limit is ') + '%d'%self.wallet.gap_limit + '\n' \
+ _('The minimum for this wallet is: ') + '%d'%self.wallet.min_acceptable_gap() + '\n'
vbox.addWidget(QLabel(msg))
grid = QGridLayout()
grid.setSpacing(8)
grid.addWidget(QLabel(_('New gap limit: ')), 1, 0)
e = QLineEdit()
grid.addWidget(e, 1, 1)
vbox.addLayout(grid)
vbox.addLayout(ok_cancel_buttons(d))
d.setLayout(vbox)
if not d.exec_(): return
try:
n = int(e.text())
except:
2012-06-07 10:52:26 -07:00
QMessageBox.warning(self, _('Error'), _('Invalid Value'), _('OK'))
2012-06-07 09:52:29 -07:00
return
2012-06-07 10:52:26 -07:00
r = self.wallet.change_gap_limit(n)
if r:
self.update_receive_tab()
else:
QMessageBox.warning(self, _('Error'), _('Invalid Value'), _('OK'))
2012-06-07 09:52:29 -07:00
2012-02-14 00:52:03 -08:00
@staticmethod
def change_password_dialog( wallet, parent=None ):
2012-05-12 15:43:22 -07:00
if not wallet.seed:
QMessageBox.information(parent, _('Error'), _('No seed'), _('OK'))
2012-05-12 15:43:22 -07:00
return
2012-02-14 00:52:03 -08:00
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.')+'\n'+_('To disable wallet encryption, enter an empty new password.')) if wallet.use_encryption else _('Your wallet keys are not encrypted')
2012-02-14 01:05:38 -08:00
else:
msg = _("Please choose a password to encrypt your wallet keys.")+'\n'+_("Leave 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:
grid.addWidget(QLabel(_('Password')), 1, 0)
2012-02-13 05:56:31 -08:00
grid.addWidget(pw, 1, 1)
2012-02-13 05:52:59 -08:00
grid.addWidget(QLabel(_('New Password')), 2, 0)
2012-02-13 05:52:59 -08:00
grid.addWidget(new_pw, 2, 1)
grid.addWidget(QLabel(_('Confirm Password')), 3, 0)
2012-02-13 05:52:59 -08:00
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 14:11:59 -08:00
password = unicode(pw.text()) if wallet.use_encryption else None
new_password = unicode(new_pw.text())
new_password2 = unicode(conf_pw.text())
2012-02-13 05:52:59 -08:00
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:
QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
2012-02-13 05:52:59 -08:00
return
if new_password != new_password2:
QMessageBox.warning(parent, _('Error'), _('Passwords do not match'), _('OK'))
2012-02-13 05:52:59 -08:00
return
2012-05-16 23:32:49 -07:00
wallet.update_password(seed, password, new_password)
2012-02-14 00:52:03 -08:00
@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.")
2012-02-14 00:52:03 -08:00
vbox.addWidget(QLabel(msg))
grid = QGridLayout()
grid.setSpacing(8)
seed_e = QLineEdit()
grid.addWidget(QLabel(_('Seed or mnemonic')), 1, 0)
2012-02-14 00:52:03 -08:00
grid.addWidget(seed_e, 1, 1)
gap_e = QLineEdit()
gap_e.setText("5")
grid.addWidget(QLabel(_('Gap limit')), 2, 0)
2012-02-14 00:52:03 -08:00
grid.addWidget(gap_e, 2, 1)
2012-02-14 05:34:19 -08:00
gap_e.textChanged.connect(lambda: numbify(gap_e,True))
2012-02-14 00:52:03 -08:00
vbox.addLayout(grid)
vbox.addLayout(ok_cancel_buttons(d))
d.setLayout(vbox)
if not d.exec_(): return
try:
2012-02-14 14:11:59 -08:00
gap = int(unicode(gap_e.text()))
2012-02-14 00:52:03 -08:00
except:
QMessageBox.warning(None, _('Error'), 'error', 'OK')
2012-03-23 11:17:44 -07:00
sys.exit(0)
2012-02-14 00:52:03 -08:00
try:
2012-02-14 14:11:59 -08:00
seed = unicode(seed_e.text())
2012-02-14 00:52:03 -08:00
seed.decode('hex')
except:
print "not hex, trying decode"
2012-03-23 11:32:16 -07:00
try:
seed = mnemonic.mn_decode( seed.split(' ') )
except:
QMessageBox.warning(None, _('Error'), _('I cannot decode this'), _('OK'))
2012-03-23 11:32:16 -07:00
sys.exit(0)
2012-02-14 00:52:03 -08:00
if not seed:
QMessageBox.warning(None, _('Error'), _('No seed'), 'OK')
2012-03-23 11:17:44 -07:00
sys.exit(0)
2012-02-14 00:52:03 -08:00
2012-03-14 10:00:24 -07:00
wallet.seed = str(seed)
#print repr(wallet.seed)
2012-02-14 00:52:03 -08:00
wallet.gap_limit = gap
return True
2012-06-07 08:42:50 -07:00
def set_expert_mode(self, b):
self.wallet.expert_mode = b
self.wallet.save()
2012-06-07 07:07:49 -07:00
self.update_receive_tab()
self.update_contacts_tab()
2012-06-07 08:42:50 -07:00
2012-06-07 07:07:49 -07:00
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
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)
vbox.addLayout(grid)
2012-02-13 06:22:15 -08:00
2012-02-14 05:34:19 -08:00
fee_e = QLineEdit()
fee_e.setText("%s"% str( Decimal( self.wallet.fee)/100000000 ) )
grid.addWidget(QLabel(_('Fee per tx. input')), 2, 0)
2012-02-14 05:34:19 -08:00
grid.addWidget(fee_e, 2, 1)
fee_e.textChanged.connect(lambda: numbify(fee_e,False))
2012-02-13 06:22:15 -08:00
nz_e = QLineEdit()
nz_e.setText("%d"% self.wallet.num_zeros)
grid.addWidget(QLabel(_('Zeros displayed after decimal point')), 3, 0)
grid.addWidget(nz_e, 3, 1)
nz_e.textChanged.connect(lambda: numbify(nz_e,True))
2012-06-07 08:36:39 -07:00
cb = QCheckBox('Expert mode')
grid.addWidget(cb,4,0)
2012-06-07 08:42:50 -07:00
cb.setChecked(self.wallet.expert_mode)
2012-06-07 08:36:39 -07: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
2012-06-07 08:42:50 -07:00
self.set_expert_mode(cb.isChecked())
2012-06-07 08:36:39 -07:00
2012-02-14 14:11:59 -08:00
fee = unicode(fee_e.text())
2012-02-13 06:22:15 -08:00
try:
fee = int( 100000000 * Decimal(fee) )
except:
QMessageBox.warning(self, _('Error'), _('Invalid value') +': %s'%fee, _('OK'))
2012-02-13 06:22:15 -08:00
return
if self.wallet.fee != fee:
self.wallet.fee = fee
self.wallet.save()
nz = unicode(nz_e.text())
try:
nz = int( nz )
if nz>8: nz=8
except:
QMessageBox.warning(self, _('Error'), _('Invalid value')+':%s'%nz, _('OK'))
return
if self.wallet.num_zeros != nz:
self.wallet.num_zeros = nz
self.update_history_tab()
self.update_receive_tab()
self.wallet.save()
2012-02-13 06:22:15 -08:00
2012-02-14 00:52:03 -08:00
@staticmethod
def network_dialog(wallet, parent=None):
2012-03-14 08:08:23 -07:00
interface = wallet.interface
2012-02-14 01:05:38 -08:00
if parent:
2012-03-14 08:08:23 -07:00
if interface.is_connected:
status = _("Connected to")+" %s:%d\n%d blocks"%(interface.host, interface.port, wallet.blocks)
2012-02-13 06:44:16 -08:00
else:
status = _("Not connected")
2012-03-30 05:15:05 -07:00
server = wallet.server
2012-02-13 06:44:16 -08:00
else:
import random
status = _("Please choose a server.")
2012-03-31 05:20:25 -07:00
server = random.choice( DEFAULT_SERVERS )
2012-02-13 06:44:16 -08:00
if not wallet.interface.servers:
servers_list = []
for x in DEFAULT_SERVERS:
h,port,protocol = x.split(':')
servers_list.append( (h,[(protocol,port)] ) )
else:
servers_list = wallet.interface.servers
2012-03-31 05:03:30 -07:00
plist = {}
for item in servers_list:
2012-03-31 05:03:30 -07:00
host, pp = item
z = {}
for item2 in pp:
protocol, port = item2
z[protocol] = port
plist[host] = z
2012-02-14 00:52:03 -08:00
d = QDialog(parent)
2012-02-13 06:44:16 -08:00
d.setModal(1)
2012-05-24 01:04:16 -07:00
d.setWindowTitle(_('Server'))
2012-02-14 06:34:13 -08:00
d.setMinimumSize(375, 20)
2012-02-13 06:44:16 -08:00
2012-02-13 10:02:48 -08:00
vbox = QVBoxLayout()
2012-02-14 06:34:13 -08:00
vbox.setSpacing(20)
2012-02-13 10:02:48 -08:00
2012-02-14 06:34:13 -08:00
hbox = QHBoxLayout()
l = QLabel()
l.setPixmap(QPixmap(":icons/network.png"))
2012-03-19 07:57:47 -07:00
hbox.addWidget(l)
2012-02-14 06:34:13 -08:00
hbox.addWidget(QLabel(status))
2012-03-19 07:57:47 -07:00
2012-02-14 06:34:13 -08:00
vbox.addLayout(hbox)
hbox = QHBoxLayout()
2012-02-13 06:44:16 -08:00
host_line = QLineEdit()
2012-03-30 05:15:05 -07:00
host_line.setText(server)
2012-05-24 01:04:16 -07:00
hbox.addWidget(QLabel(_('Connect to') + ':'))
2012-02-14 06:34:13 -08:00
hbox.addWidget(host_line)
vbox.addLayout(hbox)
2012-02-13 06:44:16 -08:00
2012-03-31 05:03:30 -07:00
hbox = QHBoxLayout()
2012-05-24 01:04:16 -07:00
buttonGroup = QGroupBox(_("Protocol"))
2012-03-31 05:03:30 -07:00
radio1 = QRadioButton("tcp", buttonGroup)
radio2 = QRadioButton("http", buttonGroup)
def current_line():
return unicode(host_line.text()).split(':')
def set_button(protocol):
if protocol == 't':
radio1.setChecked(1)
elif protocol == 'h':
radio2.setChecked(1)
def set_protocol(protocol):
host = current_line()[0]
pp = plist[host]
if protocol not in pp.keys():
protocol = pp.keys()[0]
set_button(protocol)
port = pp[protocol]
host_line.setText( host + ':' + port + ':' + protocol)
radio1.clicked.connect(lambda x: set_protocol('t') )
radio2.clicked.connect(lambda x: set_protocol('h') )
set_button(current_line()[2])
2012-05-24 01:17:20 -07:00
hbox.addWidget(QLabel(_('Protocol')+':'))
2012-03-31 05:03:30 -07:00
hbox.addWidget(radio1)
hbox.addWidget(radio2)
vbox.addLayout(hbox)
2012-03-19 07:57:47 -07:00
if wallet.interface.servers:
label = _('Active Servers')
2012-03-19 07:57:47 -07:00
else:
label = _('Default Servers')
servers_list_widget = QTreeWidget(parent)
servers_list_widget.setHeaderLabels( [ label ] )
servers_list_widget.setMaximumHeight(150)
for host in plist.keys():
servers_list_widget.addTopLevelItem(QTreeWidgetItem( [ host ] ))
def do_set_line(x):
host = unicode(x.text(0))
pp = plist[host]
if 't' in pp.keys():
protocol = 't'
else:
protocol = pp.keys()[0]
port = pp[protocol]
host_line.setText( host + ':' + port + ':' + protocol)
set_button(protocol)
servers_list_widget.connect(servers_list_widget, SIGNAL('itemClicked(QTreeWidgetItem*, int)'), do_set_line)
vbox.addWidget(servers_list_widget)
2012-02-14 05:58:38 -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
2012-03-30 05:15:05 -07:00
server = unicode( host_line.text() )
2012-02-13 06:44:16 -08:00
try:
2012-04-03 07:52:15 -07:00
wallet.set_server(server)
2012-02-13 06:44:16 -08:00
except:
QMessageBox.information(None, _('Error'), 'error', _('OK'))
2012-02-13 06:44:16 -08:00
if parent == None:
sys.exit(1)
else:
return
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)
2012-03-30 09:35:26 -07:00
def waiting_dialog(self):
s = Timer()
s.start()
w = QDialog()
2012-03-30 09:55:19 -07:00
w.resize(200, 70)
2012-03-30 09:35:26 -07:00
w.setWindowTitle('Electrum')
2012-03-30 09:55:19 -07:00
l = QLabel('')
2012-03-30 09:35:26 -07:00
vbox = QVBoxLayout()
vbox.addWidget(l)
w.setLayout(vbox)
w.show()
def f():
2012-05-17 04:15:55 -07:00
if self.wallet.up_to_date:
w.close()
2012-03-30 09:35:26 -07:00
else:
2012-05-17 04:15:55 -07:00
l.setText("Please wait...\nAddresses generated: %d\nKilobytes received: %.1f"\
%(len(self.wallet.all_addresses()), self.wallet.interface.bytes_received/1024.))
2012-03-30 09:35:26 -07:00
w.connect(s, QtCore.SIGNAL('timersignal'), f)
self.wallet.interface.poke()
w.exec_()
w.destroy()
2012-02-14 00:52:03 -08:00
def restore_or_create(self):
msg = _("Wallet file not found.")+"\n"+_("Do you want to create a new wallet, or to restore an existing one?")
2012-05-24 01:11:00 -07:00
r = QMessageBox.question(None, _('Message'), msg, _('Create'), _('Restore'), _('Cancel'), 0, 2)
2012-02-14 00:52:03 -08:00
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)
wallet.init_mpk( wallet.seed )
wallet.up_to_date_event.clear()
2012-03-30 09:35:26 -07:00
wallet.up_to_date = False
self.waiting_dialog()
2012-02-14 00:52:03 -08:00
# 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-03-23 11:09:25 -07:00
wallet.init_mpk( wallet.seed )
wallet.up_to_date_event.clear()
2012-03-30 09:35:26 -07:00
wallet.up_to_date = False
self.waiting_dialog()
2012-02-14 00:52:03 -08:00
if wallet.is_found():
# history and addressbook
wallet.update_tx_history()
wallet.fill_addressbook()
print "recovery successful"
wallet.save()
else:
QMessageBox.information(None, _('Error'), _("No transactions found for this seed"), _('OK'))
2012-02-14 00:52:03 -08:00
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-04-07 06:13:18 -07:00
w.update_wallet()
2012-02-14 00:52:03 -08:00
self.app.exec_()