Create a Plugins class
Encapsulates plugin logic and removes global variable ugliness.
This commit is contained in:
parent
2c67de8f64
commit
49797c3094
11
electrum
11
electrum
|
@ -79,7 +79,7 @@ if is_bundle or is_local or is_android:
|
|||
from electrum import util
|
||||
from electrum import SimpleConfig, Network, Wallet, WalletStorage
|
||||
from electrum.util import print_msg, print_error, print_stderr, print_json, set_verbosity, InvalidPassword
|
||||
from electrum.plugins import init_plugins, run_hook, always_hook
|
||||
from electrum.plugins import Plugins, run_hook, always_hook
|
||||
from electrum.commands import get_parser, known_commands, Commands, config_variables
|
||||
|
||||
|
||||
|
@ -97,12 +97,12 @@ def prompt_password(prompt, confirm=True):
|
|||
|
||||
|
||||
|
||||
def init_gui(config, network):
|
||||
def init_gui(config, network, plugins):
|
||||
gui_name = config.get('gui', 'qt')
|
||||
if gui_name in ['lite', 'classic']:
|
||||
gui_name = 'qt'
|
||||
gui = __import__('electrum_gui.' + gui_name, fromlist=['electrum_gui'])
|
||||
gui = gui.ElectrumGui(config, network)
|
||||
gui = gui.ElectrumGui(config, network, plugins)
|
||||
return gui
|
||||
|
||||
|
||||
|
@ -493,9 +493,10 @@ if __name__ == '__main__':
|
|||
sys.exit(1)
|
||||
|
||||
# initialize plugins.
|
||||
plugins = None
|
||||
if not is_android:
|
||||
gui_name = config.get('gui', 'qt') if cmd_name == 'gui' else 'cmdline'
|
||||
init_plugins(config, is_bundle or is_local or is_android, gui_name)
|
||||
plugins = Plugins(config, is_bundle or is_local or is_android, gui_name)
|
||||
|
||||
# get password if needed
|
||||
if cmd_name not in ['gui', 'daemon']:
|
||||
|
@ -527,7 +528,7 @@ if __name__ == '__main__':
|
|||
network.start()
|
||||
server = NetworkServer(config, network)
|
||||
server.start()
|
||||
server.gui = init_gui(config, network)
|
||||
server.gui = init_gui(config, network, plugins)
|
||||
server.gui.main()
|
||||
elif cmd_name == 'daemon':
|
||||
subcommand = config.get('subcommand')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# To create a new GUI, please add its code to this directory.
|
||||
# Two objects must be passed to the ElectrumGui: config and network
|
||||
# Three objects are passed to the ElectrumGui: config, network and plugins
|
||||
# The Wallet object is instanciated by the GUI
|
||||
|
||||
# Notifications about network events are sent to the GUI by using network.register_callback()
|
||||
|
|
|
@ -126,10 +126,10 @@ def protocol_dialog(host, protocol, z):
|
|||
def make_layout(s, scrollable = False):
|
||||
content = """
|
||||
|
||||
<LinearLayout
|
||||
<LinearLayout
|
||||
android:id="@+id/zz"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#ff222222">
|
||||
|
||||
<TextView
|
||||
|
@ -147,13 +147,13 @@ def make_layout(s, scrollable = False):
|
|||
|
||||
if scrollable:
|
||||
content = """
|
||||
<ScrollView
|
||||
<ScrollView
|
||||
android:id="@+id/scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
|
@ -167,12 +167,12 @@ def make_layout(s, scrollable = False):
|
|||
return """<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/background"
|
||||
android:orientation="vertical"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#ff000022">
|
||||
|
||||
%s
|
||||
%s
|
||||
</LinearLayout>"""%content
|
||||
|
||||
|
||||
|
@ -181,21 +181,21 @@ def make_layout(s, scrollable = False):
|
|||
def main_layout():
|
||||
h = get_history_layout(15)
|
||||
l = make_layout("""
|
||||
<TextView android:id="@+id/balanceTextView"
|
||||
<TextView android:id="@+id/balanceTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:text=""
|
||||
android:textColor="#ffffffff"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:padding="7dip"
|
||||
android:textSize="8pt"
|
||||
android:gravity="center_vertical|center_horizontal|left">
|
||||
</TextView>
|
||||
|
||||
<TextView android:id="@+id/historyTextView"
|
||||
<TextView android:id="@+id/historyTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Recent transactions"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:gravity="center_vertical|center_horizontal|center">
|
||||
</TextView>
|
||||
%s """%h,True)
|
||||
|
@ -250,18 +250,18 @@ def qr_layout(addr, amount, message):
|
|||
|
||||
payto_layout = make_layout("""
|
||||
|
||||
<TextView android:id="@+id/recipientTextView"
|
||||
<TextView android:id="@+id/recipientTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Pay to:"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:gravity="left">
|
||||
</TextView>
|
||||
|
||||
|
||||
<EditText android:id="@+id/recipient"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="Tag Me" android:inputType="text">
|
||||
</EditText>
|
||||
|
||||
|
@ -275,31 +275,31 @@ payto_layout = make_layout("""
|
|||
</LinearLayout>
|
||||
|
||||
|
||||
<TextView android:id="@+id/labelTextView"
|
||||
<TextView android:id="@+id/labelTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Message:"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:gravity="left">
|
||||
</TextView>
|
||||
|
||||
<EditText android:id="@+id/message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="Tag Me" android:inputType="text">
|
||||
</EditText>
|
||||
|
||||
<TextView android:id="@+id/amountLabelTextView"
|
||||
<TextView android:id="@+id/amountLabelTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Amount:"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:gravity="left">
|
||||
</TextView>
|
||||
|
||||
<EditText android:id="@+id/amount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="Tag Me" android:inputType="numberDecimal">
|
||||
</EditText>
|
||||
|
||||
|
@ -312,7 +312,7 @@ payto_layout = make_layout("""
|
|||
|
||||
|
||||
settings_layout = make_layout(""" <ListView
|
||||
android:id="@+id/myListView"
|
||||
android:id="@+id/myListView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />""")
|
||||
|
||||
|
@ -349,23 +349,23 @@ def get_history_layout(n):
|
|||
rows += """
|
||||
<TableRow>
|
||||
<TextView
|
||||
android:id="@+id/hl_%d_col1"
|
||||
android:id="@+id/hl_%d_col1"
|
||||
android:layout_column="0"
|
||||
android:text="%s"
|
||||
android:textColor="%s"
|
||||
android:padding="3" />
|
||||
<TextView
|
||||
android:id="@+id/hl_%d_col2"
|
||||
android:id="@+id/hl_%d_col2"
|
||||
android:layout_column="1"
|
||||
android:text="%s"
|
||||
android:padding="3" />
|
||||
<TextView
|
||||
android:id="@+id/hl_%d_col3"
|
||||
android:id="@+id/hl_%d_col3"
|
||||
android:layout_column="2"
|
||||
android:text="%s"
|
||||
android:padding="3" />
|
||||
<TextView
|
||||
android:id="@+id/hl_%d_col4"
|
||||
android:id="@+id/hl_%d_col4"
|
||||
android:layout_column="3"
|
||||
android:text="%s"
|
||||
android:padding="4" />
|
||||
|
@ -411,7 +411,7 @@ def update_layout():
|
|||
text = "Synchronizing..."
|
||||
else:
|
||||
c, u, x = wallet.get_balance()
|
||||
text = "Balance:"+format_satoshis(c)
|
||||
text = "Balance:"+format_satoshis(c)
|
||||
if u:
|
||||
text += ' [' + format_satoshis(u,True).strip() + ']'
|
||||
if x:
|
||||
|
@ -507,7 +507,7 @@ def main_loop():
|
|||
|
||||
event = droid.eventWait(1000).result
|
||||
if event is None:
|
||||
if do_refresh:
|
||||
if do_refresh:
|
||||
update_layout()
|
||||
do_refresh = False
|
||||
continue
|
||||
|
@ -522,7 +522,7 @@ def main_loop():
|
|||
if event["data"]["key"] == '4':
|
||||
if quitting:
|
||||
out = 'quit'
|
||||
else:
|
||||
else:
|
||||
quitting = True
|
||||
else: quitting = False
|
||||
|
||||
|
@ -555,7 +555,7 @@ def main_loop():
|
|||
out = None
|
||||
|
||||
return out
|
||||
|
||||
|
||||
|
||||
def payto_loop():
|
||||
global recipient
|
||||
|
@ -621,7 +621,7 @@ def payto_loop():
|
|||
else:
|
||||
modal_dialog('Error','cannot parse QR code\n'+data)
|
||||
|
||||
|
||||
|
||||
elif event["name"] in menu_commands:
|
||||
out = event["name"]
|
||||
|
||||
|
@ -729,7 +729,7 @@ def show_seed():
|
|||
if not password: return
|
||||
else:
|
||||
password = None
|
||||
|
||||
|
||||
try:
|
||||
seed = wallet.get_mnemonic(password)
|
||||
except Exception:
|
||||
|
@ -892,7 +892,7 @@ def make_bitmap(data):
|
|||
finally:
|
||||
droid.dialogDismiss()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
droid = android.Android()
|
||||
|
@ -904,7 +904,7 @@ config = None
|
|||
|
||||
class ElectrumGui:
|
||||
|
||||
def __init__(self, _config, _network):
|
||||
def __init__(self, _config, _network, plugins):
|
||||
global wallet, network, contacts, config
|
||||
network = _network
|
||||
config = _config
|
||||
|
@ -912,7 +912,7 @@ class ElectrumGui:
|
|||
network.register_callback('connected', update_callback)
|
||||
network.register_callback('disconnected', update_callback)
|
||||
network.register_callback('disconnecting', update_callback)
|
||||
|
||||
|
||||
contacts = util.StoreDict(config, 'contacts')
|
||||
|
||||
storage = WalletStorage(config.get_wallet_path())
|
||||
|
@ -1018,5 +1018,3 @@ class ElectrumGui:
|
|||
else:
|
||||
seed = modal_input('Mnemonic', 'please enter your code')
|
||||
return str(seed)
|
||||
|
||||
|
||||
|
|
76
gui/gtk.py
76
gui/gtk.py
|
@ -69,8 +69,8 @@ def show_seed_dialog(seed, parent):
|
|||
|
||||
dialog = Gtk.MessageDialog(
|
||||
parent = parent,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
buttons = Gtk.ButtonsType.OK,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
buttons = Gtk.ButtonsType.OK,
|
||||
message_format = "Your wallet generation seed is:\n\n" + '"' + seed + '"'\
|
||||
+ "\n\nPlease keep it in a safe place; if you lose it, you will not be able to restore your wallet.\n\n" )
|
||||
dialog.set_title("Seed")
|
||||
|
@ -80,9 +80,9 @@ def show_seed_dialog(seed, parent):
|
|||
|
||||
def restore_create_dialog():
|
||||
|
||||
# ask if the user wants to create a new wallet, or recover from a seed.
|
||||
# ask if the user wants to create a new wallet, or recover from a seed.
|
||||
# if he wants to recover, and nothing is found, do not create wallet
|
||||
dialog = Gtk.Dialog("electrum", parent=None,
|
||||
dialog = Gtk.Dialog("electrum", parent=None,
|
||||
flags=Gtk.DialogFlags.MODAL,
|
||||
buttons= ("create", 0, "restore",1, "cancel",2) )
|
||||
|
||||
|
@ -102,7 +102,7 @@ def run_recovery_dialog():
|
|||
message = "Please enter your wallet seed or the corresponding mnemonic list of words, and the gap limit of your wallet."
|
||||
dialog = Gtk.MessageDialog(
|
||||
parent = None,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
buttons = Gtk.ButtonsType.OK_CANCEL,
|
||||
message_format = message)
|
||||
|
||||
|
@ -121,7 +121,7 @@ def run_recovery_dialog():
|
|||
seed_box.pack_start(seed_entry, False, False, 10)
|
||||
add_help_button(seed_box, '.')
|
||||
seed_box.show()
|
||||
vbox.pack_start(seed_box, False, False, 5)
|
||||
vbox.pack_start(seed_box, False, False, 5)
|
||||
|
||||
dialog.show()
|
||||
r = dialog.run()
|
||||
|
@ -142,10 +142,10 @@ def run_recovery_dialog():
|
|||
def run_settings_dialog(self):
|
||||
|
||||
message = "Here are the settings of your wallet. For more explanations, click on the question mark buttons next to each input field."
|
||||
|
||||
|
||||
dialog = Gtk.MessageDialog(
|
||||
parent = self.window,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
buttons = Gtk.ButtonsType.OK_CANCEL,
|
||||
message_format = message)
|
||||
|
||||
|
@ -171,7 +171,7 @@ def run_settings_dialog(self):
|
|||
add_help_button(fee, 'Fee per kilobyte of transaction. Recommended value:0.0001')
|
||||
fee.show()
|
||||
vbox.pack_start(fee, False,False, 5)
|
||||
|
||||
|
||||
nz = Gtk.HBox()
|
||||
nz_entry = Gtk.Entry()
|
||||
nz_label = Gtk.Label(label='Display zeros:')
|
||||
|
@ -185,12 +185,12 @@ def run_settings_dialog(self):
|
|||
add_help_button(nz, "Number of zeros displayed after the decimal point.\nFor example, if this number is 2, then '5.' is displayed as '5.00'")
|
||||
nz.show()
|
||||
vbox.pack_start(nz, False,False, 5)
|
||||
|
||||
|
||||
dialog.show()
|
||||
r = dialog.run()
|
||||
fee = fee_entry.get_text()
|
||||
nz = nz_entry.get_text()
|
||||
|
||||
|
||||
dialog.destroy()
|
||||
if r==Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
@ -238,7 +238,7 @@ def run_network_dialog( network, parent ):
|
|||
dialog.set_title("Server")
|
||||
dialog.set_image(image)
|
||||
image.show()
|
||||
|
||||
|
||||
vbox = dialog.vbox
|
||||
host_box = Gtk.HBox()
|
||||
host_label = Gtk.Label(label='Connect to:')
|
||||
|
@ -291,11 +291,11 @@ def run_network_dialog( network, parent ):
|
|||
combobox.connect("changed", lambda x:set_protocol('tshg'[combobox.get_active()]))
|
||||
if network.is_connected():
|
||||
set_combobox(protocol)
|
||||
|
||||
|
||||
server_list = Gtk.ListStore(str)
|
||||
for host in servers.keys():
|
||||
server_list.append([host])
|
||||
|
||||
|
||||
treeview = Gtk.TreeView(model=server_list)
|
||||
treeview.show()
|
||||
|
||||
|
@ -354,8 +354,8 @@ def run_network_dialog( network, parent ):
|
|||
def show_message(message, parent=None):
|
||||
dialog = Gtk.MessageDialog(
|
||||
parent = parent,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
buttons = Gtk.ButtonsType.CLOSE,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
buttons = Gtk.ButtonsType.CLOSE,
|
||||
message_format = message )
|
||||
dialog.show()
|
||||
dialog.run()
|
||||
|
@ -418,7 +418,7 @@ def change_password_dialog(is_encrypted, parent):
|
|||
new_password = password_entry.get_text()
|
||||
new_password2 = password2_entry.get_text()
|
||||
dialog.destroy()
|
||||
if result == Gtk.ResponseType.CANCEL:
|
||||
if result == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
if new_password != new_password2:
|
||||
|
@ -480,7 +480,7 @@ class ElectrumWindow:
|
|||
self.create_about_tab()
|
||||
self.notebook.show()
|
||||
vbox.pack_start(self.notebook, True, True, 2)
|
||||
|
||||
|
||||
self.status_bar = Gtk.Statusbar()
|
||||
vbox.pack_start(self.status_bar, False, False, 0)
|
||||
|
||||
|
@ -578,7 +578,7 @@ class ElectrumWindow:
|
|||
if to_address:
|
||||
s = r + ' <' + to_address + '>'
|
||||
GObject.idle_add( lambda: self.payto_entry.set_text(s) )
|
||||
|
||||
|
||||
|
||||
thread.start_new_thread(update_status_bar_thread, ())
|
||||
if self.wallet.seed:
|
||||
|
@ -618,7 +618,7 @@ class ElectrumWindow:
|
|||
|
||||
|
||||
def create_send_tab(self):
|
||||
|
||||
|
||||
page = vbox = Gtk.VBox()
|
||||
page.show()
|
||||
|
||||
|
@ -678,7 +678,7 @@ class ElectrumWindow:
|
|||
payto_sig_id = Gtk.Label(label='')
|
||||
payto_sig.pack_start(payto_sig_id, False, False, 0)
|
||||
vbox.pack_start(payto_sig, True, True, 5)
|
||||
|
||||
|
||||
|
||||
self.user_fee = False
|
||||
|
||||
|
@ -709,7 +709,7 @@ class ElectrumWindow:
|
|||
fee_entry.modify_text(Gtk.StateType.NORMAL, Gdk.color_parse("#cc0000"))
|
||||
|
||||
amount_entry.connect('changed', entry_changed, False)
|
||||
fee_entry.connect('changed', entry_changed, True)
|
||||
fee_entry.connect('changed', entry_changed, True)
|
||||
|
||||
self.payto_entry = payto_entry
|
||||
self.payto_fee_entry = fee_entry
|
||||
|
@ -776,7 +776,7 @@ class ElectrumWindow:
|
|||
|
||||
m1 = re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', r)
|
||||
m2 = re.match('(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+) \<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
|
||||
|
||||
|
||||
if m1:
|
||||
to_address = self.wallet.get_alias(r, True, self.show_message, self.question)
|
||||
if not to_address:
|
||||
|
@ -821,8 +821,8 @@ class ElectrumWindow:
|
|||
self.show_message( "This transaction requires a higher fee, or it will not be propagated by the network." )
|
||||
return
|
||||
|
||||
|
||||
if label:
|
||||
|
||||
if label:
|
||||
self.wallet.labels[tx.hash()] = label
|
||||
|
||||
status, msg = self.wallet.sendtx( tx )
|
||||
|
@ -854,7 +854,7 @@ class ElectrumWindow:
|
|||
# s = "self-signed"
|
||||
# msg = 'Alias: '+ m + '\nTarget address: '+ a[1] + '\n\nSigned by: ' + s + '\nSigning address:' + a[0]
|
||||
# self.show_message(msg)
|
||||
|
||||
|
||||
|
||||
def treeview_key_press(self, treeview, event):
|
||||
c = treeview.get_cursor()[0]
|
||||
|
@ -1134,7 +1134,7 @@ class ElectrumWindow:
|
|||
self.network_button.set_tooltip_text("Not connected.")
|
||||
text = "Not connected"
|
||||
|
||||
self.status_bar.pop(self.context_id)
|
||||
self.status_bar.pop(self.context_id)
|
||||
self.status_bar.push(self.context_id, text)
|
||||
|
||||
if self.wallet.up_to_date and self.wallet_updated:
|
||||
|
@ -1214,7 +1214,7 @@ class ElectrumWindow:
|
|||
+ "Transaction ID:\n" + tx_hash + "\n\n" \
|
||||
+ "Status: %d confirmations\n"%conf
|
||||
if is_mine:
|
||||
if fee:
|
||||
if fee:
|
||||
tx_details += "Amount sent: %s\n"% format_satoshis(v-fee, False) \
|
||||
+ "Transaction fee: %s\n"% format_satoshis(fee, False)
|
||||
else:
|
||||
|
@ -1233,8 +1233,8 @@ class ElectrumWindow:
|
|||
|
||||
def newaddress_dialog(self, w):
|
||||
|
||||
title = "New Contact"
|
||||
dialog = Gtk.Dialog(title, parent=self.window,
|
||||
title = "New Contact"
|
||||
dialog = Gtk.Dialog(title, parent=self.window,
|
||||
flags=Gtk.DialogFlags.MODAL,
|
||||
buttons= ("cancel", 0, "ok",1) )
|
||||
dialog.show()
|
||||
|
@ -1260,7 +1260,7 @@ class ElectrumWindow:
|
|||
address.pack_start(address_entry, True, True, 0)
|
||||
address.show()
|
||||
dialog.vbox.pack_start(address, False, True, 5)
|
||||
|
||||
|
||||
result = dialog.run()
|
||||
address = address_entry.get_text()
|
||||
label = label_entry.get_text()
|
||||
|
@ -1273,18 +1273,18 @@ class ElectrumWindow:
|
|||
else:
|
||||
errorDialog = Gtk.MessageDialog(
|
||||
parent=self.window,
|
||||
flags=Gtk.DialogFlags.MODAL,
|
||||
buttons= Gtk.ButtonsType.CLOSE,
|
||||
flags=Gtk.DialogFlags.MODAL,
|
||||
buttons= Gtk.ButtonsType.CLOSE,
|
||||
message_format = "Invalid address")
|
||||
errorDialog.show()
|
||||
errorDialog.run()
|
||||
errorDialog.destroy()
|
||||
|
||||
|
||||
|
||||
|
||||
class ElectrumGui():
|
||||
|
||||
def __init__(self, config, network):
|
||||
def __init__(self, config, network, plugins):
|
||||
self.network = network
|
||||
self.config = config
|
||||
|
||||
|
@ -1321,7 +1321,7 @@ class ElectrumGui():
|
|||
wallet.add_seed(seed, password)
|
||||
wallet.create_master_keys(password)
|
||||
wallet.create_main_account(password)
|
||||
|
||||
|
||||
else:
|
||||
exit()
|
||||
else:
|
||||
|
@ -1351,8 +1351,8 @@ class ElectrumGui():
|
|||
|
||||
dialog = Gtk.MessageDialog(
|
||||
parent = None,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
buttons = Gtk.ButtonsType.CANCEL,
|
||||
flags = Gtk.DialogFlags.MODAL,
|
||||
buttons = Gtk.ButtonsType.CANCEL,
|
||||
message_format = "Please wait..." )
|
||||
dialog.show()
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class RequestHandler(SimpleJSONRPCRequestHandler):
|
|||
self.end_headers()
|
||||
|
||||
def end_headers(self):
|
||||
self.send_header("Access-Control-Allow-Headers",
|
||||
self.send_header("Access-Control-Allow-Headers",
|
||||
"Origin, X-Requested-With, Content-Type, Accept")
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
SimpleJSONRPCRequestHandler.end_headers(self)
|
||||
|
@ -45,7 +45,7 @@ class RequestHandler(SimpleJSONRPCRequestHandler):
|
|||
|
||||
class ElectrumGui:
|
||||
|
||||
def __init__(self, config, network):
|
||||
def __init__(self, config, network, plugins):
|
||||
self.network = network
|
||||
self.config = config
|
||||
storage = WalletStorage(self.config.get_wallet_path())
|
||||
|
|
|
@ -58,10 +58,11 @@ class OpenFileEventFilter(QObject):
|
|||
|
||||
class ElectrumGui:
|
||||
|
||||
def __init__(self, config, network):
|
||||
def __init__(self, config, network, plugins):
|
||||
set_language(config.get('language'))
|
||||
self.network = network
|
||||
self.config = config
|
||||
self.plugins = plugins
|
||||
self.windows = []
|
||||
self.efilter = OpenFileEventFilter(self.windows)
|
||||
self.app = QApplication(sys.argv)
|
||||
|
|
|
@ -2811,12 +2811,12 @@ class ElectrumWindow(QMainWindow):
|
|||
|
||||
|
||||
def plugins_dialog(self):
|
||||
from electrum.plugins import plugins, descriptions, is_available, loader
|
||||
|
||||
self.pluginsdialog = d = QDialog(self)
|
||||
d.setWindowTitle(_('Electrum Plugins'))
|
||||
d.setModal(1)
|
||||
|
||||
plugins = self.gui_object.plugins
|
||||
|
||||
vbox = QVBoxLayout(d)
|
||||
|
||||
# plugins
|
||||
|
@ -2828,40 +2828,34 @@ class ElectrumWindow(QMainWindow):
|
|||
|
||||
w = QWidget()
|
||||
scroll.setWidget(w)
|
||||
w.setMinimumHeight(len(plugins)*35)
|
||||
w.setMinimumHeight(plugins.count() * 35)
|
||||
|
||||
grid = QGridLayout()
|
||||
grid.setColumnStretch(0,1)
|
||||
w.setLayout(grid)
|
||||
|
||||
def do_toggle(cb, name, w):
|
||||
p = plugins.get(name)
|
||||
p = plugins.toggle_enabled(self.config, name)
|
||||
if p:
|
||||
p.disable()
|
||||
p.close()
|
||||
plugins.pop(name)
|
||||
else:
|
||||
module = loader(name)
|
||||
plugins[name] = p = module.Plugin(self.config, name)
|
||||
p.enable()
|
||||
# FIXME: this is hosed for multiple windows
|
||||
p.wallet = self.wallet
|
||||
p.load_wallet(self.wallet, self)
|
||||
p.init_qt(self.gui_object)
|
||||
r = p.is_enabled()
|
||||
cb.setChecked(r)
|
||||
if w: w.setEnabled(r)
|
||||
enabled = p is not None
|
||||
cb.setChecked(enabled)
|
||||
if w: w.setEnabled(enabled)
|
||||
|
||||
def mk_toggle(cb, name, w):
|
||||
return lambda: do_toggle(cb, name, w)
|
||||
|
||||
for i, descr in enumerate(descriptions):
|
||||
for i, descr in enumerate(plugins.descriptions):
|
||||
name = descr['name']
|
||||
p = plugins.get(name)
|
||||
if descr.get('registers_wallet_type'):
|
||||
continue
|
||||
try:
|
||||
cb = QCheckBox(descr['fullname'])
|
||||
cb.setEnabled(is_available(name, self.wallet))
|
||||
cb.setEnabled(plugins.is_available(name, self.wallet))
|
||||
cb.setChecked(p is not None and p.is_enabled())
|
||||
grid.addWidget(cb, i, 0)
|
||||
if p and p.requires_settings():
|
||||
|
|
20
gui/stdio.py
20
gui/stdio.py
|
@ -12,7 +12,7 @@ import sys, getpass, datetime
|
|||
|
||||
class ElectrumGui:
|
||||
|
||||
def __init__(self, config, network):
|
||||
def __init__(self, config, network, plugins):
|
||||
self.network = network
|
||||
self.config = config
|
||||
storage = WalletStorage(config.get_wallet_path())
|
||||
|
@ -33,7 +33,7 @@ class ElectrumGui:
|
|||
self.wallet = Wallet(storage)
|
||||
self.wallet.start_threads(network)
|
||||
self.contacts = StoreDict(self.config, 'contacts')
|
||||
|
||||
|
||||
self.wallet.network.register_callback('updated', self.updated)
|
||||
self.wallet.network.register_callback('connected', self.connected)
|
||||
self.wallet.network.register_callback('disconnected', self.disconnected)
|
||||
|
@ -97,7 +97,7 @@ class ElectrumGui:
|
|||
delta = (80 - sum(width) - 4)/3
|
||||
format_str = "%"+"%d"%width[0]+"s"+"%"+"%d"%(width[1]+delta)+"s"+"%" \
|
||||
+ "%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"
|
||||
b = 0
|
||||
b = 0
|
||||
messages = []
|
||||
|
||||
for item in self.wallet.get_history():
|
||||
|
@ -123,7 +123,7 @@ class ElectrumGui:
|
|||
if self.wallet.network.is_connected():
|
||||
if not self.wallet.up_to_date:
|
||||
msg = _( "Synchronizing..." )
|
||||
else:
|
||||
else:
|
||||
c, u, x = self.wallet.get_balance()
|
||||
msg = _("Balance")+": %f "%(Decimal(c) / COIN)
|
||||
if u:
|
||||
|
@ -132,7 +132,7 @@ class ElectrumGui:
|
|||
msg += " [%f unmatured]"%(Decimal(x) / COIN)
|
||||
else:
|
||||
msg = _( "Not connected" )
|
||||
|
||||
|
||||
return(msg)
|
||||
|
||||
|
||||
|
@ -169,7 +169,7 @@ class ElectrumGui:
|
|||
msg = list[i] if i < len(list) else ""
|
||||
print(msg)
|
||||
|
||||
|
||||
|
||||
def main(self):
|
||||
while self.done == 0: self.main_command()
|
||||
|
||||
|
@ -205,8 +205,8 @@ class ElectrumGui:
|
|||
except Exception as e:
|
||||
print(str(e))
|
||||
return
|
||||
|
||||
if self.str_description:
|
||||
|
||||
if self.str_description:
|
||||
self.wallet.labels[tx.hash()] = self.str_description
|
||||
|
||||
h = self.wallet.send_tx(tx)
|
||||
|
@ -232,7 +232,7 @@ class ElectrumGui:
|
|||
|
||||
def password_dialog(self):
|
||||
return getpass.getpass()
|
||||
|
||||
|
||||
|
||||
# XXX unused
|
||||
|
||||
|
@ -240,6 +240,6 @@ class ElectrumGui:
|
|||
#if c == 10:
|
||||
# out = self.run_popup('Address', ["Edit label", "Freeze", "Prioritize"])
|
||||
return
|
||||
|
||||
|
||||
def run_contacts_tab(self, c):
|
||||
pass
|
||||
|
|
41
gui/text.py
41
gui/text.py
|
@ -12,7 +12,7 @@ import tty, sys
|
|||
|
||||
class ElectrumGui:
|
||||
|
||||
def __init__(self, config, network):
|
||||
def __init__(self, config, network, plugins):
|
||||
|
||||
self.config = config
|
||||
self.network = network
|
||||
|
@ -51,8 +51,8 @@ class ElectrumGui:
|
|||
self.str_amount = ""
|
||||
self.str_fee = ""
|
||||
self.history = None
|
||||
|
||||
if self.network:
|
||||
|
||||
if self.network:
|
||||
self.network.register_callback('updated', self.update)
|
||||
self.network.register_callback('connected', self.refresh)
|
||||
self.network.register_callback('disconnected', self.refresh)
|
||||
|
@ -73,7 +73,7 @@ class ElectrumGui:
|
|||
|
||||
def verify_seed(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_string(self, y, x):
|
||||
self.set_cursor(1)
|
||||
curses.echo()
|
||||
|
@ -85,7 +85,7 @@ class ElectrumGui:
|
|||
|
||||
def update(self):
|
||||
self.update_history()
|
||||
if self.tab == 0:
|
||||
if self.tab == 0:
|
||||
self.print_history()
|
||||
self.refresh()
|
||||
|
||||
|
@ -105,7 +105,7 @@ class ElectrumGui:
|
|||
delta = (self.maxx - sum(width) - 4)/3
|
||||
format_str = "%"+"%d"%width[0]+"s"+"%"+"%d"%(width[1]+delta)+"s"+"%"+"%d"%(width[2]+delta)+"s"+"%"+"%d"%(width[3]+delta)+"s"
|
||||
|
||||
b = 0
|
||||
b = 0
|
||||
self.history = []
|
||||
|
||||
for item in self.wallet.get_history():
|
||||
|
@ -130,7 +130,7 @@ class ElectrumGui:
|
|||
elif self.network.is_connected():
|
||||
if not self.wallet.up_to_date:
|
||||
msg = _("Synchronizing...")
|
||||
else:
|
||||
else:
|
||||
c, u, x = self.wallet.get_balance()
|
||||
msg = _("Balance")+": %f "%(Decimal(c) / COIN)
|
||||
if u:
|
||||
|
@ -139,12 +139,12 @@ class ElectrumGui:
|
|||
msg += " [%f unmatured]"%(Decimal(x) / COIN)
|
||||
else:
|
||||
msg = _("Not connected")
|
||||
|
||||
|
||||
self.stdscr.addstr( self.maxy -1, 3, msg)
|
||||
|
||||
for i in range(self.num_tabs):
|
||||
self.stdscr.addstr( 0, 2 + 2*i + len(''.join(self.tab_names[0:i])), ' '+self.tab_names[i]+' ', curses.A_BOLD if self.tab == i else 0)
|
||||
|
||||
|
||||
self.stdscr.addstr( self.maxy -1, self.maxx-30, ' '.join([_("Settings"), _("Network"), _("Quit")]))
|
||||
|
||||
|
||||
|
@ -221,7 +221,7 @@ class ElectrumGui:
|
|||
def run_history_tab(self, c):
|
||||
if c == 10:
|
||||
out = self.run_popup('',["blah","foo"])
|
||||
|
||||
|
||||
|
||||
def edit_str(self, target, c, is_num=False):
|
||||
# detect backspace
|
||||
|
@ -246,11 +246,11 @@ class ElectrumGui:
|
|||
elif self.pos%6==5:
|
||||
if c == 10: self.do_clear()
|
||||
|
||||
|
||||
|
||||
def run_receive_tab(self, c):
|
||||
if c == 10:
|
||||
out = self.run_popup('Address', ["Edit label", "Freeze", "Prioritize"])
|
||||
|
||||
|
||||
def run_contacts_tab(self, c):
|
||||
if c == 10 and self.contacts:
|
||||
out = self.run_popup('Adress', ["Copy", "Pay to", "Edit label", "Delete"]).get('button')
|
||||
|
@ -263,7 +263,7 @@ class ElectrumGui:
|
|||
s = self.get_string(6 + self.pos, 18)
|
||||
if s:
|
||||
self.wallet.labels[address] = s
|
||||
|
||||
|
||||
def run_banner_tab(self, c):
|
||||
self.show_message(repr(c))
|
||||
pass
|
||||
|
@ -318,8 +318,8 @@ class ElectrumGui:
|
|||
except Exception as e:
|
||||
self.show_message(str(e))
|
||||
return
|
||||
|
||||
if self.str_description:
|
||||
|
||||
if self.str_description:
|
||||
self.wallet.labels[tx.hash()] = self.str_description
|
||||
|
||||
h = self.wallet.send_tx(tx)
|
||||
|
@ -375,7 +375,7 @@ class ElectrumGui:
|
|||
proxy = None
|
||||
|
||||
self.network.set_parameters(host, port, protocol, proxy, auto_connect)
|
||||
|
||||
|
||||
|
||||
|
||||
def settings_dialog(self):
|
||||
|
@ -396,11 +396,11 @@ class ElectrumGui:
|
|||
{'label':'Password', 'type':'password', 'value':''}
|
||||
], buttons = 1)
|
||||
return out.get('Password')
|
||||
|
||||
|
||||
|
||||
def run_dialog(self, title, items, interval=2, buttons=None, y_pos=3):
|
||||
self.popup_pos = 0
|
||||
|
||||
|
||||
self.w = curses.newwin( 5 + len(items)*interval + (2 if buttons else 0), 50, y_pos, 5)
|
||||
w = self.w
|
||||
out = {}
|
||||
|
@ -441,7 +441,7 @@ class ElectrumGui:
|
|||
if buttons:
|
||||
w.addstr( 5+interval*i, 10, "[ ok ]", curses.A_REVERSE if self.popup_pos%numpos==(numpos-2) else curses.color_pair(2))
|
||||
w.addstr( 5+interval*i, 25, "[cancel]", curses.A_REVERSE if self.popup_pos%numpos==(numpos-1) else curses.color_pair(2))
|
||||
|
||||
|
||||
w.refresh()
|
||||
|
||||
c = self.stdscr.getch()
|
||||
|
@ -480,10 +480,9 @@ class ElectrumGui:
|
|||
new_choice = choices[(j + 1)% len(choices)]
|
||||
item['value'] = new_choice
|
||||
out[item.get('label')] = item.get('value')
|
||||
|
||||
|
||||
elif _type == 'button':
|
||||
out['button'] = item.get('label')
|
||||
break
|
||||
|
||||
return out
|
||||
|
||||
|
|
150
lib/plugins.py
150
lib/plugins.py
|
@ -26,70 +26,93 @@ from util import *
|
|||
from i18n import _
|
||||
from util import print_error, profiler
|
||||
|
||||
plugins = {}
|
||||
descriptions = []
|
||||
loader = None
|
||||
class Plugins:
|
||||
|
||||
def is_available(name, w):
|
||||
for d in descriptions:
|
||||
if d.get('name') == name:
|
||||
break
|
||||
else:
|
||||
return False
|
||||
deps = d.get('requires', [])
|
||||
for dep, s in deps:
|
||||
@profiler
|
||||
def __init__(self, config, is_local, gui_name):
|
||||
if is_local:
|
||||
find = imp.find_module('plugins')
|
||||
plugins = imp.load_module('electrum_plugins', *find)
|
||||
self.pathname = find[1]
|
||||
else:
|
||||
plugins = __import__('electrum_plugins')
|
||||
self.pathname = None
|
||||
|
||||
self.plugins = {}
|
||||
self.descriptions = plugins.descriptions
|
||||
for item in self.descriptions:
|
||||
name = item['name']
|
||||
if gui_name not in item.get('available_for', []):
|
||||
continue
|
||||
x = item.get('registers_wallet_type')
|
||||
if x:
|
||||
self.register_wallet_type(name, x)
|
||||
if config.get('use_' + name):
|
||||
self.load_plugin(config, name)
|
||||
|
||||
def print_error(self, *msg):
|
||||
print_error("[%s]" % self.__class__.__name__, *msg)
|
||||
|
||||
def get(self, name):
|
||||
return self.plugins.get(name)
|
||||
|
||||
def count(self):
|
||||
return len(self.plugins)
|
||||
|
||||
def load_plugin(self, config, name):
|
||||
full_name = 'electrum_plugins.' + name
|
||||
try:
|
||||
__import__(dep)
|
||||
except ImportError:
|
||||
return False
|
||||
wallet_types = d.get('requires_wallet_type')
|
||||
if wallet_types:
|
||||
if w.wallet_type not in wallet_types:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def plugin_loader(config, name):
|
||||
global plugins
|
||||
if plugins.get(name) is None:
|
||||
print_error(_("Loading plugin by constructor:"), name)
|
||||
p = loader(name)
|
||||
plugins[name] = p.Plugin(config, name)
|
||||
return plugins[name]
|
||||
|
||||
@profiler
|
||||
def init_plugins(config, is_local, gui_name):
|
||||
global plugins, descriptions, loader
|
||||
if is_local:
|
||||
fp, pathname, description = imp.find_module('plugins')
|
||||
electrum_plugins = imp.load_module('electrum_plugins', fp, pathname, description)
|
||||
loader = lambda name: imp.load_source('electrum_plugins.' + name, os.path.join(pathname, name + '.py'))
|
||||
else:
|
||||
electrum_plugins = __import__('electrum_plugins')
|
||||
loader = lambda name: __import__('electrum_plugins.' + name, fromlist=['electrum_plugins'])
|
||||
|
||||
def register_wallet_type(name, x):
|
||||
import wallet
|
||||
x += (lambda: plugin_loader(config, name),)
|
||||
wallet.wallet_types.append(x)
|
||||
|
||||
descriptions = electrum_plugins.descriptions
|
||||
for item in descriptions:
|
||||
name = item['name']
|
||||
if gui_name not in item.get('available_for', []):
|
||||
continue
|
||||
x = item.get('registers_wallet_type')
|
||||
if x:
|
||||
register_wallet_type(name, x)
|
||||
if not config.get('use_' + name):
|
||||
continue
|
||||
try:
|
||||
p = loader(name)
|
||||
plugins[name] = p.Plugin(config, name)
|
||||
if self.pathname: # local
|
||||
path = os.path.join(self.pathname, name + '.py')
|
||||
p = imp.load_source(full_name, path)
|
||||
else:
|
||||
p = __import__(full_name, fromlist=['electrum_plugins'])
|
||||
plugin = p.Plugin(config, name)
|
||||
self.plugins[name] = plugin
|
||||
self.print_error("loaded", name)
|
||||
return plugin
|
||||
except Exception:
|
||||
print_msg(_("Error: cannot initialize plugin"), name)
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
return None
|
||||
|
||||
def toggle_enabled(self, config, name):
|
||||
p = self.get(name)
|
||||
config.set_key('use_' + name, p is None, True)
|
||||
if p:
|
||||
self.plugins.pop(name)
|
||||
p.close()
|
||||
self.print_error("closed", name)
|
||||
return None
|
||||
return self.load_plugin(config, name)
|
||||
|
||||
def is_available(self, name, w):
|
||||
for d in self.descriptions:
|
||||
if d.get('name') == name:
|
||||
break
|
||||
else:
|
||||
return False
|
||||
deps = d.get('requires', [])
|
||||
for dep, s in deps:
|
||||
try:
|
||||
__import__(dep)
|
||||
except ImportError:
|
||||
return False
|
||||
wallet_types = d.get('requires_wallet_type')
|
||||
if wallet_types:
|
||||
if w.wallet_type not in wallet_types:
|
||||
return False
|
||||
return True
|
||||
|
||||
def wallet_plugin_loader(self, config, name):
|
||||
if self.plugins.get(name) is None:
|
||||
self.load_plugin(config, name)
|
||||
return self.plugins[name]
|
||||
|
||||
def register_wallet_type(self, name, x):
|
||||
import wallet
|
||||
x += (lambda: self.wallet_plugin_loader(config, name),)
|
||||
wallet.wallet_types.append(x)
|
||||
|
||||
hook_names = set()
|
||||
hooks = {}
|
||||
|
@ -157,14 +180,6 @@ class BasePlugin:
|
|||
def requires_settings(self):
|
||||
return False
|
||||
|
||||
def enable(self):
|
||||
self.set_enabled(True)
|
||||
return True
|
||||
|
||||
def disable(self):
|
||||
self.set_enabled(False)
|
||||
return True
|
||||
|
||||
@hook
|
||||
def load_wallet(self, wallet, window): pass
|
||||
|
||||
|
@ -179,8 +194,5 @@ class BasePlugin:
|
|||
def is_available(self):
|
||||
return True
|
||||
|
||||
def set_enabled(self, enabled):
|
||||
self.config.set_key('use_'+self.name, enabled, True)
|
||||
|
||||
def settings_dialog(self):
|
||||
pass
|
||||
|
|
Loading…
Reference in New Issue