Merge branch 'master' of git://github.com/spesmilo/electrum

This commit is contained in:
ecdsa 2013-03-12 19:24:55 +01:00
commit 4f27d8ce0f
9 changed files with 93 additions and 62 deletions

View File

@ -34,8 +34,10 @@ except ImportError:
sys.exit("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'") sys.exit("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'")
is_android = 'ANDROID_DATA' in os.environ
# load local module as electrum # load local module as electrum
if os.path.exists("lib"): if os.path.exists("lib") or is_android:
import imp import imp
fp, pathname, description = imp.find_module('lib') fp, pathname, description = imp.find_module('lib')
imp.load_module('electrum', fp, pathname, description) imp.load_module('electrum', fp, pathname, description)
@ -89,8 +91,8 @@ if __name__ == '__main__':
set_verbosity(options.verbose) set_verbosity(options.verbose)
# config is an object passed to the various constructors (wallet, interface, gui) # config is an object passed to the various constructors (wallet, interface, gui)
if 'ANDROID_DATA' in os.environ: if is_android:
config_options = {'wallet_path':"/sdcard/electrum.dat", 'portable':True, 'verbose':True, 'gui':'android'} config_options = {'wallet_path':"/sdcard/electrum.dat", 'portable':True, 'verbose':True, 'gui':'android', 'auto_cycle':True}
else: else:
config_options = eval(str(options)) config_options = eval(str(options))
for k, v in config_options.items(): for k, v in config_options.items():

View File

@ -325,6 +325,9 @@ class ElectrumWindow(QMainWindow):
# set initial message # set initial message
self.console.showMessage(self.wallet.banner) self.console.showMessage(self.wallet.banner)
# plugins that need to change the GUI do it here
self.run_hook('init')
# plugins # plugins
def init_plugins(self): def init_plugins(self):
@ -357,11 +360,27 @@ class ElectrumWindow(QMainWindow):
if callback in h: h.remove(callback) if callback in h: h.remove(callback)
self.plugin_hooks[name] = h self.plugin_hooks[name] = h
def run_hook(self, name, args): def run_hook(self, name, args = ()):
args = (self,) + args
for cb in self.plugin_hooks.get(name,[]): for cb in self.plugin_hooks.get(name,[]):
apply(cb, args) apply(cb, args)
def set_label(self, name, text = None):
changed = False
old_text = self.wallet.labels.get(name)
if text:
if old_text != text:
self.wallet.labels[name] = text
changed = True
else:
if old_text:
self.wallet.labels.pop(name)
changed = True
self.run_hook('set_label', (name, text, changed))
return changed
# custom wrappers for getOpenFileName and getSaveFileName, that remember the path selected by the user # custom wrappers for getOpenFileName and getSaveFileName, that remember the path selected by the user
def getOpenFileName(self, title, filter = None): def getOpenFileName(self, title, filter = None):
directory = self.config.get('io_dir', os.path.expanduser('~')) directory = self.config.get('io_dir', os.path.expanduser('~'))
@ -382,14 +401,14 @@ class ElectrumWindow(QMainWindow):
def close(self): def close(self):
QMainWindow.close(self) QMainWindow.close(self)
self.run_hook('close_main_window', (self,)) self.run_hook('close_main_window')
def connect_slots(self, sender): def connect_slots(self, sender):
self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions) self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions)
self.previous_payto_e='' self.previous_payto_e=''
def timer_actions(self): def timer_actions(self):
self.run_hook('timer_actions', (self,)) self.run_hook('timer_actions')
if self.payto_e.hasFocus(): if self.payto_e.hasFocus():
return return
@ -534,13 +553,11 @@ class ElectrumWindow(QMainWindow):
self.is_edit=True self.is_edit=True
tx_hash = str(item.data(0, Qt.UserRole).toString()) tx_hash = str(item.data(0, Qt.UserRole).toString())
tx = self.wallet.transactions.get(tx_hash) tx = self.wallet.transactions.get(tx_hash)
s = self.wallet.labels.get(tx_hash)
text = unicode( item.text(2) ) text = unicode( item.text(2) )
self.set_label(tx_hash, text)
if text: if text:
self.wallet.labels[tx_hash] = text
item.setForeground(2, QBrush(QColor('black'))) item.setForeground(2, QBrush(QColor('black')))
else: else:
if s: self.wallet.labels.pop(tx_hash)
text = self.wallet.get_default_label(tx_hash) text = self.wallet.get_default_label(tx_hash)
item.setText(2, text) item.setText(2, text)
item.setForeground(2, QBrush(QColor('gray'))) item.setForeground(2, QBrush(QColor('gray')))
@ -574,33 +591,23 @@ class ElectrumWindow(QMainWindow):
text = unicode( item.text(column_label) ) text = unicode( item.text(column_label) )
changed = False changed = False
if text: if text in self.wallet.aliases.keys():
if text not in self.wallet.aliases.keys(): print_error("Error: This is one of your aliases")
old_addr = self.wallet.labels.get(text) label = self.wallet.labels.get(addr,'')
if old_addr != addr: item.setText(column_label, QString(label))
self.wallet.labels[addr] = text
changed = True
else:
print_error("Error: This is one of your aliases")
label = self.wallet.labels.get(addr,'')
item.setText(column_label, QString(label))
else: else:
s = self.wallet.labels.get(addr) changed = self.set_label(addr, text)
if s: if changed:
self.wallet.labels.pop(addr) self.update_history_tab()
changed = True self.update_completions()
if changed:
self.update_history_tab()
self.update_completions()
self.current_item_changed(item) self.current_item_changed(item)
self.run_hook('item_changed',(self, item, column)) self.run_hook('item_changed', (item, column))
def current_item_changed(self, a): def current_item_changed(self, a):
self.run_hook('current_item_changed',(self, a)) self.run_hook('current_item_changed', (a,))
@ -746,7 +753,7 @@ class ElectrumWindow(QMainWindow):
self.amount_e.textChanged.connect(lambda: entry_changed(False) ) self.amount_e.textChanged.connect(lambda: entry_changed(False) )
self.fee_e.textChanged.connect(lambda: entry_changed(True) ) self.fee_e.textChanged.connect(lambda: entry_changed(True) )
self.run_hook('create_send_tab',(self,grid)) self.run_hook('create_send_tab', (grid,))
return w2 return w2
@ -806,10 +813,10 @@ class ElectrumWindow(QMainWindow):
self.show_message(str(e)) self.show_message(str(e))
return return
self.run_hook('send_tx', (self.wallet, self, tx)) self.run_hook('send_tx', (tx,))
if label: if label:
self.wallet.labels[tx.hash()] = label self.set_label(tx.hash(), label)
if tx.is_complete: if tx.is_complete:
h = self.wallet.send_tx(tx) h = self.wallet.send_tx(tx)
@ -1002,7 +1009,7 @@ class ElectrumWindow(QMainWindow):
t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize") t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize")
menu.addAction(t, lambda: self.toggle_priority(addr)) menu.addAction(t, lambda: self.toggle_priority(addr))
self.run_hook('receive_menu', (self, menu,)) self.run_hook('receive_menu', (menu,))
menu.exec_(self.receive_list.viewport().mapToGlobal(position)) menu.exec_(self.receive_list.viewport().mapToGlobal(position))
@ -1023,8 +1030,7 @@ class ElectrumWindow(QMainWindow):
if self.question(_("Do you want to remove")+" %s "%x +_("from your list of contacts?")): if self.question(_("Do you want to remove")+" %s "%x +_("from your list of contacts?")):
if not is_alias and x in self.wallet.addressbook: if not is_alias and x in self.wallet.addressbook:
self.wallet.addressbook.remove(x) self.wallet.addressbook.remove(x)
if x in self.wallet.labels.keys(): self.set_label(x, None)
self.wallet.labels.pop(x)
elif is_alias and x in self.wallet.aliases: elif is_alias and x in self.wallet.aliases:
self.wallet.aliases.pop(x) self.wallet.aliases.pop(x)
self.update_history_tab() self.update_history_tab()
@ -1060,7 +1066,7 @@ class ElectrumWindow(QMainWindow):
label = self.wallet.labels.get(address,'') label = self.wallet.labels.get(address,'')
item.setData(1,0,label) item.setData(1,0,label)
self.run_hook('update_receive_item', (self, address, item)) self.run_hook('update_receive_item', (address, item))
c, u = self.wallet.get_addr_balance(address) c, u = self.wallet.get_addr_balance(address)
balance = format_satoshis( c + u, False, self.wallet.num_zeros ) balance = format_satoshis( c + u, False, self.wallet.num_zeros )
@ -1679,7 +1685,7 @@ class ElectrumWindow(QMainWindow):
if not tx_dict["complete"]: if not tx_dict["complete"]:
assert "input_info" in tx_dict.keys() assert "input_info" in tx_dict.keys()
except: except:
QMessageBox.critical(None, "Unable to parse transaction", _("Electrum was unable to parse your transaction:")) QMessageBox.critical(None, "Unable to parse transaction", _("Electrum was unable to parse your transaction"))
return None return None
return tx_dict return tx_dict
@ -1706,7 +1712,7 @@ class ElectrumWindow(QMainWindow):
if fileName: if fileName:
with open(fileName, "w+") as f: with open(fileName, "w+") as f:
f.write(json.dumps(tx.as_dict(),indent=4) + '\n') f.write(json.dumps(tx.as_dict(),indent=4) + '\n')
self.show_message(_("Transaction saved succesfully")) self.show_message(_("Transaction saved successfully"))
if dialog: if dialog:
dialog.done(0) dialog.done(0)
except BaseException, e: except BaseException, e:
@ -1716,7 +1722,7 @@ class ElectrumWindow(QMainWindow):
def send_raw_transaction(self, raw_tx, dialog = ""): def send_raw_transaction(self, raw_tx, dialog = ""):
result, result_message = self.wallet.sendtx( raw_tx ) result, result_message = self.wallet.sendtx( raw_tx )
if result: if result:
self.show_message("Transaction succesfully sent: %s" % (result_message)) self.show_message("Transaction successfully sent: %s" % (result_message))
if dialog: if dialog:
dialog.done(0) dialog.done(0)
else: else:
@ -1759,7 +1765,7 @@ class ElectrumWindow(QMainWindow):
l = QGridLayout() l = QGridLayout()
dialog.setLayout(l) dialog.setLayout(l)
l.addWidget(QLabel(_("Transaction status: ")), 3,0) l.addWidget(QLabel(_("Transaction status:")), 3,0)
l.addWidget(QLabel(_("Actions")), 4,0) l.addWidget(QLabel(_("Actions")), 4,0)
if tx_dict["complete"] == False: if tx_dict["complete"] == False:

View File

@ -44,10 +44,12 @@ languages = {
'es':_('Spanish'), 'es':_('Spanish'),
'fr':_('French'), 'fr':_('French'),
'it':_('Italian'), 'it':_('Italian'),
'ja':_('Japanese'),
'lv':_('Latvian'), 'lv':_('Latvian'),
'nl':_('Dutch'), 'nl':_('Dutch'),
'ru':_('Russian'), 'ru':_('Russian'),
'sl':_('Slovenian'), 'sl':_('Slovenian'),
'ta':_('Tamil'),
'vi':_('Vietnamese'), 'vi':_('Vietnamese'),
'zh':_('Chinese') 'zh':_('Chinese')
} }

View File

@ -1,12 +1,19 @@
# source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget # source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget
import sys, os, re import sys, os, re
import traceback import traceback, platform
from PyQt4 import QtCore from PyQt4 import QtCore
from PyQt4 import QtGui from PyQt4 import QtGui
from electrum import util from electrum import util
if platform.system() == 'Windows':
MONOSPACE_FONT = 'Lucida Console'
elif platform.system() == 'Darwin':
MONOSPACE_FONT = 'Monaco'
else:
MONOSPACE_FONT = 'monospace'
class Console(QtGui.QPlainTextEdit): class Console(QtGui.QPlainTextEdit):
def __init__(self, prompt='>> ', startup_message='', parent=None): def __init__(self, prompt='>> ', startup_message='', parent=None):
@ -20,7 +27,7 @@ class Console(QtGui.QPlainTextEdit):
self.setGeometry(50, 75, 600, 400) self.setGeometry(50, 75, 600, 400)
self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)
self.setUndoRedoEnabled(False) self.setUndoRedoEnabled(False)
self.document().setDefaultFont(QtGui.QFont("monospace", 10, QtGui.QFont.Normal)) self.document().setDefaultFont(QtGui.QFont(MONOSPACE_FONT, 10, QtGui.QFont.Normal))
self.showMessage(startup_message) self.showMessage(startup_message)
self.updateNamespace({'run':self.run_script}) self.updateNamespace({'run':self.run_script})

View File

@ -825,7 +825,7 @@ class Transaction:
for i in self.inputs: for i in self.inputs:
e = { 'txid':i['tx_hash'], 'vout':i['index'], e = { 'txid':i['tx_hash'], 'vout':i['index'],
'scriptPubKey':i.get('raw_output_script'), 'scriptPubKey':i.get('raw_output_script'),
'electrumKeyID':i.get('electrumKeyID'), 'KeyID':i.get('KeyID'),
'redeemScript':i.get('redeemScript'), 'redeemScript':i.get('redeemScript'),
'signatures':i.get('signatures'), 'signatures':i.get('signatures'),
'pubkeys':i.get('pubkeys'), 'pubkeys':i.get('pubkeys'),

View File

@ -1,4 +1,4 @@
ELECTRUM_VERSION = "1.7" # version of the client package ELECTRUM_VERSION = "1.7" # version of the client package
PROTOCOL_VERSION = '0.6' # protocol version requested PROTOCOL_VERSION = '0.6' # protocol version requested
SEED_VERSION = 4 # bump this every time the seed generation is modified SEED_VERSION = 4 # bump this every time the seed generation is modified
TRANSLATION_ID = 3958 # version of the wiki page TRANSLATION_ID = 3992 # version of the wiki page

View File

@ -256,7 +256,7 @@ class Wallet:
if item.get('txid') == txin['tx_hash'] and item.get('vout') == txin['index']: if item.get('txid') == txin['tx_hash'] and item.get('vout') == txin['index']:
txin['raw_output_script'] = item['scriptPubKey'] txin['raw_output_script'] = item['scriptPubKey']
txin['redeemScript'] = item.get('redeemScript') txin['redeemScript'] = item.get('redeemScript')
txin['electrumKeyID'] = item.get('electrumKeyID') txin['KeyID'] = item.get('KeyID')
break break
else: else:
for item in unspent_coins: for item in unspent_coins:
@ -268,8 +268,9 @@ class Wallet:
raise raise
# find the address: # find the address:
if txin.get('electrumKeyID'): if txin.get('KeyID'):
account, sequence = txin.get('electrumKeyID') account, name, sequence = txin.get('KeyID')
if name != 'Electrum': continue
sec = self.sequences[account].get_private_key(sequence, seed) sec = self.sequences[account].get_private_key(sequence, seed)
addr = self.sequences[account].get_address(sequence) addr = self.sequences[account].get_address(sequence)
txin['address'] = addr txin['address'] = addr
@ -771,7 +772,7 @@ class Wallet:
pk_addresses.append(address) pk_addresses.append(address)
continue continue
account, sequence = self.get_address_index(address) account, sequence = self.get_address_index(address)
txin['electrumKeyID'] = (account, sequence) # used by the server to find the key txin['KeyID'] = (account, 'Electrum', sequence) # used by the server to find the key
pk_addr, redeemScript = self.sequences[account].get_input_info(sequence) pk_addr, redeemScript = self.sequences[account].get_input_info(sequence)
if redeemScript: txin['redeemScript'] = redeemScript if redeemScript: txin['redeemScript'] = redeemScript
pk_addresses.append(pk_addr) pk_addresses.append(pk_addr)
@ -1197,9 +1198,6 @@ class WalletSynchronizer(threading.Thread):
while not self.interface.is_connected: while not self.interface.is_connected:
time.sleep(1) time.sleep(1)
# request banner, because 'connected' event happens before this thread is started
self.interface.send([('server.banner',[])],'synchronizer')
# subscriptions # subscriptions
self.subscribe_to_addresses(self.wallet.addresses(True)) self.subscribe_to_addresses(self.wallet.addresses(True))

View File

@ -20,10 +20,13 @@ if __name__ == '__main__':
# android # android
os.system('rm -rf dist/e4a-%s'%version) os.system('rm -rf dist/e4a-%s'%version)
os.mkdir('dist/e4a-%s'%version) os.mkdir('dist/e4a-%s'%version)
shutil.copyfile("electrum",'dist/e4a-%s/electrum.py'%version) shutil.copyfile("electrum",'dist/e4a-%s/e4a.py'%version)
shutil.copytree("ecdsa",'dist/e4a-%s/ecdsa'%version) shutil.copytree("ecdsa",'dist/e4a-%s/ecdsa'%version)
shutil.copytree("aes",'dist/e4a-%s/aes'%version) shutil.copytree("aes",'dist/e4a-%s/aes'%version)
shutil.copytree("lib",'dist/e4a-%s/electrum'%version) shutil.copytree("lib",'dist/e4a-%s/lib'%version)
os.mkdir('dist/e4a-%s/gui'%version)
shutil.copy("gui/gui_android.py",'dist/e4a-%s/gui'%version)
shutil.copy("gui/__init__.py",'dist/e4a-%s/gui'%version)
os.chdir("dist") os.chdir("dist")
# create the zip file # create the zip file

View File

@ -103,6 +103,7 @@ def init(gui):
gui.requested_amounts = config.get('requested_amounts',{}) gui.requested_amounts = config.get('requested_amounts',{})
gui.merchant_name = config.get('merchant_name', 'Invoice') gui.merchant_name = config.get('merchant_name', 'Invoice')
gui.qr_window = None gui.qr_window = None
do_enable(gui, is_enabled())
def is_enabled(): def is_enabled():
return config.get('pointofsale') is True return config.get('pointofsale') is True
@ -110,32 +111,44 @@ def is_enabled():
def is_available(): def is_available():
return True return True
def toggle(gui):
if not is_enabled(): def toggle(gui):
enabled = not is_enabled()
config.set_key('pointofsale', enabled, True)
do_enable(gui, enabled)
update_gui(gui)
return enabled
def do_enable(gui, enabled):
if enabled:
gui.expert_mode = True gui.expert_mode = True
gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Request')])
gui.set_hook('item_changed', item_changed) gui.set_hook('item_changed', item_changed)
gui.set_hook('current_item_changed', recv_changed) gui.set_hook('current_item_changed', recv_changed)
gui.set_hook('receive_menu', receive_menu) gui.set_hook('receive_menu', receive_menu)
gui.set_hook('update_receive_item', update_receive_item) gui.set_hook('update_receive_item', update_receive_item)
gui.set_hook('timer_actions', timer_actions) gui.set_hook('timer_actions', timer_actions)
gui.set_hook('close_main_window', close_main_window) gui.set_hook('close_main_window', close_main_window)
enabled = True gui.set_hook('init', update_gui)
else: else:
gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Tx')])
gui.unset_hook('item_changed', item_changed) gui.unset_hook('item_changed', item_changed)
gui.unset_hook('current_item_changed', recv_changed) gui.unset_hook('current_item_changed', recv_changed)
gui.unset_hook('receive_menu', receive_menu) gui.unset_hook('receive_menu', receive_menu)
gui.unset_hook('update_receive_item', update_receive_item) gui.unset_hook('update_receive_item', update_receive_item)
gui.unset_hook('timer_actions', timer_actions) gui.unset_hook('timer_actions', timer_actions)
gui.unset_hook('close_main_window', close_main_window) gui.unset_hook('close_main_window', close_main_window)
enabled = False gui.unset_hook('init', update_gui)
def update_gui(gui):
enabled = is_enabled()
if enabled:
gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Request')])
else:
gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Tx')])
config.set_key('pointofsale', enabled, True)
toggle_QR_window(gui, enabled) toggle_QR_window(gui, enabled)
return enabled