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