derive plugins from BasePlugin class
This commit is contained in:
parent
93b98e1176
commit
bd1cdc9bfb
|
@ -1 +1,2 @@
|
|||
# do not remove this file
|
||||
from plugins import BasePlugin
|
||||
|
|
|
@ -339,7 +339,7 @@ class ElectrumWindow(QMainWindow):
|
|||
self.console.showMessage(self.wallet.banner)
|
||||
|
||||
# plugins that need to change the GUI do it here
|
||||
self.run_hook('init')
|
||||
self.run_hook('init_gui')
|
||||
|
||||
|
||||
# plugins
|
||||
|
@ -350,36 +350,33 @@ class ElectrumWindow(QMainWindow):
|
|||
plugin_names = [name for a, name, b in pkgutil.iter_modules([pathname])]
|
||||
plugin_names = filter( lambda name: os.path.exists(os.path.join(pathname,name+'.py')), plugin_names)
|
||||
imp.load_module('electrum_plugins', fp, pathname, description)
|
||||
self.plugins = map(lambda name: imp.load_source('electrum_plugins.'+name, os.path.join(pathname,name+'.py')), plugin_names)
|
||||
plugins = map(lambda name: imp.load_source('electrum_plugins.'+name, os.path.join(pathname,name+'.py')), plugin_names)
|
||||
else:
|
||||
import electrum_plugins
|
||||
plugin_names = [name for a, name, b in pkgutil.iter_modules(electrum_plugins.__path__)]
|
||||
self.plugins = [ __import__('electrum_plugins.'+name, fromlist=['electrum_plugins']) for name in plugin_names]
|
||||
plugins = [ __import__('electrum_plugins.'+name, fromlist=['electrum_plugins']) for name in plugin_names]
|
||||
|
||||
self.plugin_hooks = {}
|
||||
for p in self.plugins:
|
||||
self.plugins = []
|
||||
for p in plugins:
|
||||
try:
|
||||
p.init(self)
|
||||
self.plugins.append( p.Plugin(self) )
|
||||
except:
|
||||
print_msg("Error:cannot initialize plugin",p)
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
|
||||
def set_hook(self, name, callback):
|
||||
h = self.plugin_hooks.get(name, [])
|
||||
h.append(callback)
|
||||
self.plugin_hooks[name] = h
|
||||
|
||||
def unset_hook(self, name, callback):
|
||||
h = self.plugin_hooks.get(name,[])
|
||||
if callback in h: h.remove(callback)
|
||||
self.plugin_hooks[name] = h
|
||||
|
||||
def run_hook(self, name, *args):
|
||||
args = (self,) + args
|
||||
for cb in self.plugin_hooks.get(name,[]):
|
||||
apply(cb, args)
|
||||
|
||||
for p in self.plugins:
|
||||
if not p.is_enabled():
|
||||
continue
|
||||
try:
|
||||
f = eval('p.'+name)
|
||||
except:
|
||||
continue
|
||||
apply(f, args)
|
||||
return
|
||||
|
||||
|
||||
def set_label(self, name, text = None):
|
||||
changed = False
|
||||
old_text = self.wallet.labels.get(name)
|
||||
|
@ -2002,7 +1999,7 @@ class ElectrumWindow(QMainWindow):
|
|||
grid_plugins.setColumnStretch(0,1)
|
||||
tabs.addTab(tab5, _('Plugins') )
|
||||
def mk_toggle(cb, p):
|
||||
return lambda: cb.setChecked(p.toggle(self))
|
||||
return lambda: cb.setChecked(p.toggle())
|
||||
for i, p in enumerate(self.plugins):
|
||||
try:
|
||||
name, description = p.get_info()
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
|
||||
class BasePlugin:
|
||||
|
||||
def get_info(self):
|
||||
return self.fullname, self.description
|
||||
|
||||
def __init__(self, gui, name, fullname, description):
|
||||
self.name = name
|
||||
self.fullname = fullname
|
||||
self.description = description
|
||||
self.gui = gui
|
||||
self.config = gui.config
|
||||
|
||||
def toggle(self):
|
||||
enabled = not self.is_enabled()
|
||||
self.set_enabled(enabled)
|
||||
self.init_gui()
|
||||
return enabled
|
||||
|
||||
def init_gui(self):
|
||||
pass
|
||||
|
||||
def is_enabled(self):
|
||||
return self.is_available() and self.config.get('use_'+self.name) is True
|
||||
|
||||
def is_available(self):
|
||||
return True
|
||||
|
||||
def set_enabled(self, enabled):
|
||||
self.config.set_key('use_'+self.name, enabled, True)
|
||||
|
|
@ -15,217 +15,185 @@ from electrum_gui.i18n import _
|
|||
ALIAS_REGEXP = '^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$'
|
||||
|
||||
|
||||
config = {}
|
||||
|
||||
def get_info():
|
||||
return 'Aliases', _('Retrieve aliases using http.')
|
||||
from electrum_gui import BasePlugin
|
||||
class Plugin(BasePlugin):
|
||||
|
||||
def init(self):
|
||||
global config
|
||||
config = self.config
|
||||
self.aliases = config.get('aliases', {}) # aliases for addresses
|
||||
self.authorities = config.get('authorities', {}) # trusted addresses
|
||||
self.receipts = config.get('receipts',{}) # signed URIs
|
||||
do_enable(self, is_enabled())
|
||||
|
||||
def is_enabled():
|
||||
return config.get('use_aliases') is True
|
||||
|
||||
def is_available():
|
||||
return True
|
||||
def __init__(self, gui):
|
||||
BasePlugin.__init__(self, gui, 'aliases', 'Aliases', _('Retrieve aliases using http.'))
|
||||
self.aliases = self.config.get('aliases', {}) # aliases for addresses
|
||||
self.authorities = self.config.get('authorities', {}) # trusted addresses
|
||||
self.receipts = self.config.get('receipts',{}) # signed URIs
|
||||
|
||||
|
||||
def toggle(gui):
|
||||
enabled = not is_enabled()
|
||||
config.set_key('use_aliases', enabled, True)
|
||||
do_enable(gui, enabled)
|
||||
return enabled
|
||||
def timer_actions(self):
|
||||
if self.gui.payto_e.hasFocus():
|
||||
return
|
||||
r = unicode( self.gui.payto_e.text() )
|
||||
if r != self.gui.previous_payto_e:
|
||||
self.gui.previous_payto_e = r
|
||||
r = r.strip()
|
||||
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', r):
|
||||
try:
|
||||
to_address = self.get_alias(r, True, self.gui.show_message, self.gui.question)
|
||||
except:
|
||||
return
|
||||
if to_address:
|
||||
s = r + ' <' + to_address + '>'
|
||||
self.gui.payto_e.setText(s)
|
||||
|
||||
|
||||
def do_enable(gui, enabled):
|
||||
if enabled:
|
||||
gui.set_hook('timer_actions', timer_actions)
|
||||
gui.set_hook('set_url', set_url_hook)
|
||||
gui.set_hook('update_contacts_tab', update_contacts_tab_hook)
|
||||
gui.set_hook('update_completions', update_completions_hook)
|
||||
gui.set_hook('create_contact_menu', create_contact_menu_hook)
|
||||
else:
|
||||
gui.unset_hook('timer_actions', timer_actions)
|
||||
gui.unset_hook('set_url', set_url_hook)
|
||||
gui.unset_hook('update_contacts_tab', update_contacts_tab_hook)
|
||||
gui.unset_hook('update_completions', update_completions_hook)
|
||||
gui.unset_hook('create_contact_menu', create_contact_menu_hook)
|
||||
def get_alias(self, alias, interactive = False, show_message=None, question = None):
|
||||
try:
|
||||
target, signing_address, auth_name = read_alias(self, alias)
|
||||
except BaseException, e:
|
||||
# raise exception if verify fails (verify the chain)
|
||||
if interactive:
|
||||
show_message("Alias error: " + str(e))
|
||||
return
|
||||
|
||||
print target, signing_address, auth_name
|
||||
|
||||
def timer_actions(self):
|
||||
if self.payto_e.hasFocus():
|
||||
return
|
||||
r = unicode( 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 = get_alias(self, r, True, self.show_message, self.question)
|
||||
except:
|
||||
return
|
||||
if to_address:
|
||||
s = r + ' <' + to_address + '>'
|
||||
self.payto_e.setText(s)
|
||||
|
||||
|
||||
def get_alias(self, alias, interactive = False, show_message=None, question = None):
|
||||
try:
|
||||
target, signing_address, auth_name = read_alias(self, alias)
|
||||
except BaseException, e:
|
||||
# raise exception if verify fails (verify the chain)
|
||||
if interactive:
|
||||
show_message("Alias error: " + str(e))
|
||||
return
|
||||
|
||||
print target, signing_address, auth_name
|
||||
|
||||
if auth_name is None:
|
||||
a = self.aliases.get(alias)
|
||||
if not a:
|
||||
msg = "Warning: the alias '%s' is self-signed.\nThe signing address is %s.\n\nDo you want to add this alias to your list of contacts?"%(alias,signing_address)
|
||||
if interactive and question( msg ):
|
||||
self.aliases[alias] = (signing_address, target)
|
||||
else:
|
||||
target = None
|
||||
else:
|
||||
if signing_address != a[0]:
|
||||
msg = "Warning: the key of alias '%s' has changed since your last visit! It is possible that someone is trying to do something nasty!!!\nDo you accept to change your trusted key?"%alias
|
||||
if auth_name is None:
|
||||
a = self.aliases.get(alias)
|
||||
if not a:
|
||||
msg = "Warning: the alias '%s' is self-signed.\nThe signing address is %s.\n\nDo you want to add this alias to your list of contacts?"%(alias,signing_address)
|
||||
if interactive and question( msg ):
|
||||
self.aliases[alias] = (signing_address, target)
|
||||
else:
|
||||
target = None
|
||||
else:
|
||||
if signing_address not in self.authorities.keys():
|
||||
msg = "The alias: '%s' links to %s\n\nWarning: this alias was signed by an unknown key.\nSigning authority: %s\nSigning address: %s\n\nDo you want to add this key to your list of trusted keys?"%(alias,target,auth_name,signing_address)
|
||||
if interactive and question( msg ):
|
||||
self.authorities[signing_address] = auth_name
|
||||
else:
|
||||
target = None
|
||||
if signing_address != a[0]:
|
||||
msg = "Warning: the key of alias '%s' has changed since your last visit! It is possible that someone is trying to do something nasty!!!\nDo you accept to change your trusted key?"%alias
|
||||
if interactive and question( msg ):
|
||||
self.aliases[alias] = (signing_address, target)
|
||||
else:
|
||||
target = None
|
||||
else:
|
||||
if signing_address not in self.authorities.keys():
|
||||
msg = "The alias: '%s' links to %s\n\nWarning: this alias was signed by an unknown key.\nSigning authority: %s\nSigning address: %s\n\nDo you want to add this key to your list of trusted keys?"%(alias,target,auth_name,signing_address)
|
||||
if interactive and question( msg ):
|
||||
self.authorities[signing_address] = auth_name
|
||||
else:
|
||||
target = None
|
||||
|
||||
if target:
|
||||
self.aliases[alias] = (signing_address, target)
|
||||
if target:
|
||||
self.aliases[alias] = (signing_address, target)
|
||||
|
||||
return target
|
||||
return target
|
||||
|
||||
|
||||
|
||||
def read_alias(self, alias):
|
||||
import urllib
|
||||
def read_alias(self, alias):
|
||||
import urllib
|
||||
|
||||
m1 = re.match('([\w\-\.]+)@((\w[\w\-]+\.)+[\w\-]+)', alias)
|
||||
m2 = re.match('((\w[\w\-]+\.)+[\w\-]+)', alias)
|
||||
if m1:
|
||||
url = 'https://' + m1.group(2) + '/bitcoin.id/' + m1.group(1)
|
||||
elif m2:
|
||||
url = 'https://' + alias + '/bitcoin.id'
|
||||
else:
|
||||
return ''
|
||||
try:
|
||||
lines = urllib.urlopen(url).readlines()
|
||||
except:
|
||||
return ''
|
||||
|
||||
# line 0
|
||||
line = lines[0].strip().split(':')
|
||||
if len(line) == 1:
|
||||
auth_name = None
|
||||
target = signing_addr = line[0]
|
||||
else:
|
||||
target, auth_name, signing_addr, signature = line
|
||||
msg = "alias:%s:%s:%s"%(alias,target,auth_name)
|
||||
print msg, signature
|
||||
EC_KEY.verify_message(signing_addr, signature, msg)
|
||||
|
||||
# other lines are signed updates
|
||||
for line in lines[1:]:
|
||||
line = line.strip()
|
||||
if not line: continue
|
||||
line = line.split(':')
|
||||
previous = target
|
||||
print repr(line)
|
||||
target, signature = line
|
||||
EC_KEY.verify_message(previous, signature, "alias:%s:%s"%(alias,target))
|
||||
|
||||
if not is_valid(target):
|
||||
raise ValueError("Invalid bitcoin address")
|
||||
|
||||
return target, signing_addr, auth_name
|
||||
|
||||
|
||||
def set_url_hook(self, url, show_message, question):
|
||||
payto, amount, label, message, signature, identity, url = util.parse_url(url)
|
||||
if signature:
|
||||
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', identity):
|
||||
signing_address = get_alias(identity, True, show_message, question)
|
||||
elif is_valid(identity):
|
||||
signing_address = identity
|
||||
m1 = re.match('([\w\-\.]+)@((\w[\w\-]+\.)+[\w\-]+)', alias)
|
||||
m2 = re.match('((\w[\w\-]+\.)+[\w\-]+)', alias)
|
||||
if m1:
|
||||
url = 'https://' + m1.group(2) + '/bitcoin.id/' + m1.group(1)
|
||||
elif m2:
|
||||
url = 'https://' + alias + '/bitcoin.id'
|
||||
else:
|
||||
signing_address = None
|
||||
if not signing_address:
|
||||
return
|
||||
return ''
|
||||
try:
|
||||
EC_KEY.verify_message(signing_address, signature, url )
|
||||
self.receipt = (signing_address, signature, url)
|
||||
lines = urllib.urlopen(url).readlines()
|
||||
except:
|
||||
show_message('Warning: the URI contains a bad signature.\nThe identity of the recipient cannot be verified.')
|
||||
address = amount = label = identity = message = ''
|
||||
return ''
|
||||
|
||||
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', address):
|
||||
payto_address = get_alias(address, True, show_message, question)
|
||||
if payto_address:
|
||||
address = address + ' <' + payto_address + '>'
|
||||
|
||||
return address, amount, label, message, signature, identity, url
|
||||
|
||||
|
||||
|
||||
def update_contacts_tab_hook(self, l):
|
||||
alias_targets = []
|
||||
for alias, v in self.aliases.items():
|
||||
s, target = v
|
||||
alias_targets.append(target)
|
||||
item = QTreeWidgetItem( [ target, alias, '-'] )
|
||||
item.setBackgroundColor(0, QColor('lightgray'))
|
||||
l.insertTopLevelItem(0,item)
|
||||
item.setData(0,32,False)
|
||||
item.setData(0,33,alias + ' <' + target + '>')
|
||||
|
||||
|
||||
|
||||
def update_completions_hook(self, l):
|
||||
l[:] = l + self.aliases.keys()
|
||||
|
||||
|
||||
def create_contact_menu_hook(self, menu, item):
|
||||
label = unicode(item.text(1))
|
||||
if label in self.aliases.keys():
|
||||
addr = unicode(item.text(0))
|
||||
label = unicode(item.text(1))
|
||||
menu.addAction(_("View alias details"), lambda: show_contact_details(self, label))
|
||||
menu.addAction(_("Delete alias"), lambda: delete_alias(self, label))
|
||||
|
||||
|
||||
def show_contact_details(self, m):
|
||||
a = self.aliases.get(m)
|
||||
if a:
|
||||
if a[0] in self.authorities.keys():
|
||||
s = self.authorities.get(a[0])
|
||||
# line 0
|
||||
line = lines[0].strip().split(':')
|
||||
if len(line) == 1:
|
||||
auth_name = None
|
||||
target = signing_addr = line[0]
|
||||
else:
|
||||
s = "self-signed"
|
||||
msg = _('Alias:')+' '+ m + '\n'+_('Target address:')+' '+ a[1] + '\n\n'+_('Signed by:')+' ' + s + '\n'+_('Signing address:')+' ' + a[0]
|
||||
QMessageBox.information(self, 'Alias', msg, 'OK')
|
||||
target, auth_name, signing_addr, signature = line
|
||||
msg = "alias:%s:%s:%s"%(alias,target,auth_name)
|
||||
print msg, signature
|
||||
EC_KEY.verify_message(signing_addr, signature, msg)
|
||||
|
||||
# other lines are signed updates
|
||||
for line in lines[1:]:
|
||||
line = line.strip()
|
||||
if not line: continue
|
||||
line = line.split(':')
|
||||
previous = target
|
||||
print repr(line)
|
||||
target, signature = line
|
||||
EC_KEY.verify_message(previous, signature, "alias:%s:%s"%(alias,target))
|
||||
|
||||
if not is_valid(target):
|
||||
raise ValueError("Invalid bitcoin address")
|
||||
|
||||
return target, signing_addr, auth_name
|
||||
|
||||
|
||||
def delete_alias(self, x):
|
||||
if self.question(_("Do you want to remove")+" %s "%x +_("from your list of contacts?")):
|
||||
if x in self.aliases:
|
||||
self.aliases.pop(x)
|
||||
self.update_history_tab()
|
||||
self.update_contacts_tab()
|
||||
self.update_completions()
|
||||
def set_url(self, url, show_message, question):
|
||||
payto, amount, label, message, signature, identity, url = util.parse_url(url)
|
||||
if signature:
|
||||
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', identity):
|
||||
signing_address = get_alias(identity, True, show_message, question)
|
||||
elif is_valid(identity):
|
||||
signing_address = identity
|
||||
else:
|
||||
signing_address = None
|
||||
if not signing_address:
|
||||
return
|
||||
try:
|
||||
EC_KEY.verify_message(signing_address, signature, url )
|
||||
self.receipt = (signing_address, signature, url)
|
||||
except:
|
||||
show_message('Warning: the URI contains a bad signature.\nThe identity of the recipient cannot be verified.')
|
||||
address = amount = label = identity = message = ''
|
||||
|
||||
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', address):
|
||||
payto_address = get_alias(address, True, show_message, question)
|
||||
if payto_address:
|
||||
address = address + ' <' + payto_address + '>'
|
||||
|
||||
return address, amount, label, message, signature, identity, url
|
||||
|
||||
|
||||
|
||||
def update_contacts_tab(self, l):
|
||||
alias_targets = []
|
||||
for alias, v in self.aliases.items():
|
||||
s, target = v
|
||||
alias_targets.append(target)
|
||||
item = QTreeWidgetItem( [ target, alias, '-'] )
|
||||
item.setBackgroundColor(0, QColor('lightgray'))
|
||||
item.setData(0,32,False)
|
||||
item.setData(0,33,alias + ' <' + target + '>')
|
||||
l.insertTopLevelItem(0,item)
|
||||
|
||||
|
||||
def update_completions(self, l):
|
||||
l[:] = l + self.aliases.keys()
|
||||
|
||||
|
||||
def create_contact_menu(self, menu, item):
|
||||
label = unicode(item.text(1))
|
||||
if label in self.aliases.keys():
|
||||
addr = unicode(item.text(0))
|
||||
label = unicode(item.text(1))
|
||||
menu.addAction(_("View alias details"), lambda: self.show_contact_details(label))
|
||||
menu.addAction(_("Delete alias"), lambda: delete_alias(self, label))
|
||||
|
||||
|
||||
def show_contact_details(self, m):
|
||||
a = self.aliases.get(m)
|
||||
if a:
|
||||
if a[0] in self.authorities.keys():
|
||||
s = self.authorities.get(a[0])
|
||||
else:
|
||||
s = "self-signed"
|
||||
msg = _('Alias:')+' '+ m + '\n'+_('Target address:')+' '+ a[1] + '\n\n'+_('Signed by:')+' ' + s + '\n'+_('Signing address:')+' ' + a[0]
|
||||
QMessageBox.information(self.gui, 'Alias', msg, 'OK')
|
||||
|
||||
|
||||
def delete_alias(self, x):
|
||||
if self.gui.question(_("Do you want to remove")+" %s "%x +_("from your list of contacts?")):
|
||||
if x in self.aliases:
|
||||
self.aliases.pop(x)
|
||||
self.update_history_tab()
|
||||
self.update_contacts_tab()
|
||||
self.update_completions()
|
||||
|
|
|
@ -8,8 +8,7 @@ import PyQt4.QtCore as QtCore
|
|||
import PyQt4.QtGui as QtGui
|
||||
|
||||
from electrum_gui.qrcodewidget import QRCodeWidget
|
||||
from electrum_gui import bmp, pyqrnative
|
||||
|
||||
from electrum_gui import bmp, pyqrnative, BasePlugin
|
||||
from electrum_gui.i18n import _
|
||||
|
||||
|
||||
|
@ -89,98 +88,95 @@ class QR_Window(QWidget):
|
|||
|
||||
self.qrw.set_addr( msg )
|
||||
|
||||
|
||||
|
||||
|
||||
config = {}
|
||||
|
||||
def get_info():
|
||||
return 'Point of Sale', _('Show QR code window and amounts requested for each address. Add menu item to request amount.')
|
||||
|
||||
def init(gui):
|
||||
global config
|
||||
config = gui.config
|
||||
gui.requested_amounts = config.get('requested_amounts',{})
|
||||
gui.merchant_name = config.get('merchant_name', 'Invoice')
|
||||
gui.qr_window = None
|
||||
do_enable(gui, is_enabled())
|
||||
|
||||
def is_enabled():
|
||||
return config.get('pointofsale') is True
|
||||
|
||||
def is_available():
|
||||
return True
|
||||
|
||||
|
||||
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.set_hook('item_changed', item_changed)
|
||||
gui.set_hook('current_item_changed', recv_changed)
|
||||
gui.set_hook('receive_menu', receive_menu)
|
||||
gui.set_hook('update_receive_item', update_receive_item)
|
||||
gui.set_hook('timer_actions', timer_actions)
|
||||
gui.set_hook('close_main_window', close_main_window)
|
||||
gui.set_hook('init', update_gui)
|
||||
else:
|
||||
gui.unset_hook('item_changed', item_changed)
|
||||
gui.unset_hook('current_item_changed', recv_changed)
|
||||
gui.unset_hook('receive_menu', receive_menu)
|
||||
gui.unset_hook('update_receive_item', update_receive_item)
|
||||
gui.unset_hook('timer_actions', timer_actions)
|
||||
gui.unset_hook('close_main_window', close_main_window)
|
||||
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')])
|
||||
class Plugin(BasePlugin):
|
||||
|
||||
toggle_QR_window(gui, enabled)
|
||||
def __init__(self, gui):
|
||||
BasePlugin.__init__(self, gui, 'pointofsale', 'Point of Sale',
|
||||
_('Show QR code window and amounts requested for each address. Add menu item to request amount.') )
|
||||
self.qr_window = None
|
||||
self.requested_amounts = self.config.get('requested_amounts',{})
|
||||
self.merchant_name = self.config.get('merchant_name', 'Invoice')
|
||||
|
||||
|
||||
def init_gui(self):
|
||||
enabled = self.is_enabled()
|
||||
if enabled:
|
||||
self.gui.expert_mode = True
|
||||
self.gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Request')])
|
||||
else:
|
||||
self.gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Tx')])
|
||||
|
||||
self.toggle_QR_window(enabled)
|
||||
|
||||
|
||||
def close_main_window(self):
|
||||
if self.qr_window:
|
||||
self.qr_window.close()
|
||||
self.qr_window = None
|
||||
|
||||
def toggle_QR_window(self, show):
|
||||
if show and not self.qr_window:
|
||||
self.qr_window = QR_Window(self.exchanger)
|
||||
self.qr_window.setVisible(True)
|
||||
self.qr_window_geometry = self.qr_window.geometry()
|
||||
item = self.receive_list.currentItem()
|
||||
if item:
|
||||
address = str(item.text(1))
|
||||
label = self.wallet.labels.get(address)
|
||||
|
||||
def timer_actions(self):
|
||||
if self.qr_window:
|
||||
self.qr_window.qrw.update_qr()
|
||||
|
||||
|
||||
def toggle_QR_window(self, show):
|
||||
if show and not self.qr_window:
|
||||
self.qr_window = QR_Window(self.gui.exchanger)
|
||||
self.qr_window.setVisible(True)
|
||||
self.qr_window_geometry = self.qr_window.geometry()
|
||||
item = self.gui.receive_list.currentItem()
|
||||
if item:
|
||||
address = str(item.text(1))
|
||||
label = self.gui.wallet.labels.get(address)
|
||||
amount, currency = self.requested_amounts.get(address, (None, None))
|
||||
self.qr_window.set_content( address, label, amount, currency )
|
||||
|
||||
elif show and self.qr_window and not self.qr_window.isVisible():
|
||||
self.qr_window.setVisible(True)
|
||||
self.qr_window.setGeometry(self.qr_window_geometry)
|
||||
|
||||
elif not show and self.qr_window and self.qr_window.isVisible():
|
||||
self.qr_window_geometry = self.qr_window.geometry()
|
||||
self.qr_window.setVisible(False)
|
||||
|
||||
|
||||
|
||||
def update_receive_item(self, address, item):
|
||||
try:
|
||||
amount, currency = self.requested_amounts.get(address, (None, None))
|
||||
except:
|
||||
print "cannot get requested amount", address, self.requested_amounts.get(address)
|
||||
amount, currency = None, None
|
||||
self.requested_amounts.pop(address)
|
||||
|
||||
amount_str = amount + (' ' + currency if currency else '') if amount is not None else ''
|
||||
item.setData(column_index,0,amount_str)
|
||||
|
||||
|
||||
|
||||
def current_item_changed(self, a):
|
||||
if a is not None and self.qr_window and self.qr_window.isVisible():
|
||||
address = str(a.text(0))
|
||||
label = self.gui.wallet.labels.get(address)
|
||||
try:
|
||||
amount, currency = self.requested_amounts.get(address, (None, None))
|
||||
except:
|
||||
amount, currency = None, None
|
||||
self.qr_window.set_content( address, label, amount, currency )
|
||||
|
||||
elif show and self.qr_window and not self.qr_window.isVisible():
|
||||
self.qr_window.setVisible(True)
|
||||
self.qr_window.setGeometry(self.qr_window_geometry)
|
||||
|
||||
elif not show and self.qr_window and self.qr_window.isVisible():
|
||||
self.qr_window_geometry = self.qr_window.geometry()
|
||||
self.qr_window.setVisible(False)
|
||||
|
||||
|
||||
|
||||
|
||||
def item_changed(self, item, column):
|
||||
if column == column_index:
|
||||
|
||||
def item_changed(self, item, column):
|
||||
if column != column_index:
|
||||
return
|
||||
address = str( item.text(0) )
|
||||
text = str( item.text(column) )
|
||||
try:
|
||||
seq = self.wallet.get_address_index(address)
|
||||
seq = self.gui.wallet.get_address_index(address)
|
||||
index = seq[-1]
|
||||
except:
|
||||
print "cannot get index"
|
||||
|
@ -198,9 +194,9 @@ def item_changed(self, item, column):
|
|||
currency = currency.upper()
|
||||
|
||||
self.requested_amounts[address] = (amount, currency)
|
||||
self.wallet.config.set_key('requested_amounts', self.requested_amounts, True)
|
||||
self.gui.wallet.config.set_key('requested_amounts', self.requested_amounts, True)
|
||||
|
||||
label = self.wallet.labels.get(address)
|
||||
label = self.gui.wallet.labels.get(address)
|
||||
if label is None:
|
||||
label = self.merchant_name + ' - %04d'%(index+1)
|
||||
self.wallet.labels[address] = label
|
||||
|
@ -213,50 +209,20 @@ def item_changed(self, item, column):
|
|||
if address in self.requested_amounts:
|
||||
self.requested_amounts.pop(address)
|
||||
|
||||
self.update_receive_item(self.receive_list.currentItem())
|
||||
|
||||
|
||||
def recv_changed(self, a):
|
||||
if a is not None and self.qr_window and self.qr_window.isVisible():
|
||||
address = str(a.text(0))
|
||||
label = self.wallet.labels.get(address)
|
||||
try:
|
||||
amount, currency = self.requested_amounts.get(address, (None, None))
|
||||
except:
|
||||
amount, currency = None, None
|
||||
self.qr_window.set_content( address, label, amount, currency )
|
||||
self.gui.update_receive_item(self.gui.receive_list.currentItem())
|
||||
|
||||
|
||||
|
||||
def edit_amount(self):
|
||||
l = self.receive_list
|
||||
item = l.currentItem()
|
||||
item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
|
||||
l.editItem( item, column_index )
|
||||
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
|
||||
|
||||
def receive_menu(self, menu):
|
||||
menu.addAction(_("Request amount"), lambda: edit_amount(self))
|
||||
def edit_amount(self):
|
||||
l = self.gui.receive_list
|
||||
item = l.currentItem()
|
||||
item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
|
||||
l.editItem( item, column_index )
|
||||
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
|
||||
|
||||
|
||||
def receive_menu(self, menu):
|
||||
menu.addAction(_("Request amount"), self.edit_amount)
|
||||
|
||||
|
||||
def update_receive_item(self, address, item):
|
||||
try:
|
||||
amount, currency = self.requested_amounts.get(address, (None, None))
|
||||
except:
|
||||
print "cannot get requested amount", address, self.requested_amounts.get(address)
|
||||
amount, currency = None, None
|
||||
self.requested_amounts.pop(address)
|
||||
|
||||
amount_str = amount + (' ' + currency if currency else '') if amount is not None else ''
|
||||
item.setData(column_index,0,amount_str)
|
||||
|
||||
|
||||
def close_main_window(self):
|
||||
if self.qr_window:
|
||||
self.qr_window.close()
|
||||
self.qr_window = None
|
||||
|
||||
|
||||
def timer_actions(self):
|
||||
if self.qr_window:
|
||||
self.qr_window.qrw.update_qr()
|
||||
|
|
|
@ -8,55 +8,62 @@ try:
|
|||
except ImportError:
|
||||
zbar = None
|
||||
|
||||
from electrum_gui import BasePlugin
|
||||
class Plugin(BasePlugin):
|
||||
|
||||
def __init__(self, gui):
|
||||
BasePlugin.__init__(self, gui, 'qrscans', 'QR scans', "QR Scans.\nInstall the zbar package to enable this plugin")
|
||||
|
||||
def is_available(self):
|
||||
if not zbar:
|
||||
return False
|
||||
try:
|
||||
proc = zbar.Processor()
|
||||
proc.init()
|
||||
except zbar.SystemError:
|
||||
# Cannot open video device
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def init(gui):
|
||||
if is_enabled():
|
||||
gui.set_hook('create_send_tab', create_send_tab)
|
||||
else:
|
||||
gui.unset_hook('create_send_tab', create_send_tab)
|
||||
|
||||
def get_info():
|
||||
return 'QR scans', "QR Scans.\nInstall the zbar package to enable this plugin"
|
||||
|
||||
def is_enabled():
|
||||
return is_available()
|
||||
|
||||
def toggle(gui):
|
||||
return is_enabled()
|
||||
def create_send_tab(self, grid):
|
||||
b = QPushButton(_("Scan QR code"))
|
||||
b.clicked.connect(self.fill_from_qr)
|
||||
grid.addWidget(b, 1, 5)
|
||||
|
||||
|
||||
def is_available():
|
||||
if not zbar:
|
||||
return False
|
||||
|
||||
try:
|
||||
def scan_qr(self):
|
||||
proc = zbar.Processor()
|
||||
proc.init()
|
||||
except zbar.SystemError:
|
||||
# Cannot open video device
|
||||
return False
|
||||
proc.visible = True
|
||||
|
||||
return True
|
||||
while True:
|
||||
try:
|
||||
proc.process_one()
|
||||
except:
|
||||
# User closed the preview window
|
||||
return {}
|
||||
|
||||
def scan_qr():
|
||||
proc = zbar.Processor()
|
||||
proc.init()
|
||||
proc.visible = True
|
||||
|
||||
while True:
|
||||
try:
|
||||
proc.process_one()
|
||||
except:
|
||||
# User closed the preview window
|
||||
return {}
|
||||
|
||||
for r in proc.results:
|
||||
if str(r.type) != 'QRCODE':
|
||||
continue
|
||||
|
||||
return parse_uri(r.data)
|
||||
for r in proc.results:
|
||||
if str(r.type) != 'QRCODE':
|
||||
continue
|
||||
return parse_uri(r.data)
|
||||
|
||||
|
||||
def fill_from_qr(self):
|
||||
qrcode = self.scan_qr()
|
||||
if 'address' in qrcode:
|
||||
self.gui.payto_e.setText(qrcode['address'])
|
||||
if 'amount' in qrcode:
|
||||
self.gui.amount_e.setText(str(qrcode['amount']))
|
||||
if 'label' in qrcode:
|
||||
self.gui.message_e.setText(qrcode['label'])
|
||||
if 'message' in qrcode:
|
||||
self.gui.message_e.setText("%s (%s)" % (self.gui.message_e.text(), qrcode['message']))
|
||||
|
||||
|
||||
|
||||
|
||||
def parse_uri(uri):
|
||||
if ':' not in uri:
|
||||
# It's just an address (not BIP21)
|
||||
|
@ -82,24 +89,6 @@ def parse_uri(uri):
|
|||
|
||||
|
||||
|
||||
def fill_from_qr(self):
|
||||
qrcode = scan_qr()
|
||||
if 'address' in qrcode:
|
||||
self.payto_e.setText(qrcode['address'])
|
||||
if 'amount' in qrcode:
|
||||
self.amount_e.setText(str(qrcode['amount']))
|
||||
if 'label' in qrcode:
|
||||
self.message_e.setText(qrcode['label'])
|
||||
if 'message' in qrcode:
|
||||
self.message_e.setText("%s (%s)" % (self.message_e.text(), qrcode['message']))
|
||||
|
||||
|
||||
def create_send_tab(gui, grid):
|
||||
if is_available():
|
||||
b = QPushButton(_("Scan QR code"))
|
||||
b.clicked.connect(lambda: fill_from_qr(gui))
|
||||
grid.addWidget(b, 1, 5)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in New Issue