move network dialog in a new class; simplify interface.get_servers
This commit is contained in:
parent
7d1075d85d
commit
86fd728a47
2
electrum
2
electrum
@ -219,7 +219,7 @@ if __name__ == '__main__':
|
|||||||
w_host, w_port, w_protocol = server.split(':')
|
w_host, w_port, w_protocol = server.split(':')
|
||||||
host = raw_input("server (default:%s):"%w_host)
|
host = raw_input("server (default:%s):"%w_host)
|
||||||
port = raw_input("port (default:%s):"%w_port)
|
port = raw_input("port (default:%s):"%w_port)
|
||||||
protocol = raw_input("protocol [t=tcp;h=http;n=native] (default:%s):"%w_protocol)
|
protocol = raw_input("protocol [t=tcp;h=http] (default:%s):"%w_protocol)
|
||||||
fee = raw_input("fee (default:%s):"%( str(Decimal(wallet.fee)/100000000)) )
|
fee = raw_input("fee (default:%s):"%( str(Decimal(wallet.fee)/100000000)) )
|
||||||
gap = raw_input("gap limit (default 5):")
|
gap = raw_input("gap limit (default 5):")
|
||||||
if host: w_host = host
|
if host: w_host = host
|
||||||
|
|||||||
@ -688,9 +688,9 @@ def contacts_loop():
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def server_dialog(plist):
|
def server_dialog(servers):
|
||||||
droid.dialogCreateAlert("Public servers")
|
droid.dialogCreateAlert("Public servers")
|
||||||
droid.dialogSetItems( plist.keys() )
|
droid.dialogSetItems( servers.keys() )
|
||||||
droid.dialogSetPositiveButtonText('Private server')
|
droid.dialogSetPositiveButtonText('Private server')
|
||||||
droid.dialogShow()
|
droid.dialogShow()
|
||||||
response = droid.dialogGetResponse().result
|
response = droid.dialogGetResponse().result
|
||||||
@ -702,7 +702,7 @@ def server_dialog(plist):
|
|||||||
|
|
||||||
i = response.get('item')
|
i = response.get('item')
|
||||||
if i is not None:
|
if i is not None:
|
||||||
response = plist.keys()[i]
|
response = servers.keys()[i]
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@ -774,7 +774,7 @@ def settings_loop():
|
|||||||
if event == 'OK': continue
|
if event == 'OK': continue
|
||||||
if not event: continue
|
if not event: continue
|
||||||
|
|
||||||
plist, servers_list = interface.get_servers_list()
|
servers = interface.get_servers()
|
||||||
name = event.get("name")
|
name = event.get("name")
|
||||||
if not name: continue
|
if not name: continue
|
||||||
|
|
||||||
@ -783,9 +783,9 @@ def settings_loop():
|
|||||||
host, port, protocol = interface.server.split(':')
|
host, port, protocol = interface.server.split(':')
|
||||||
|
|
||||||
if pos == "0": #server
|
if pos == "0": #server
|
||||||
host = server_dialog(plist)
|
host = server_dialog(servers)
|
||||||
if host:
|
if host:
|
||||||
p = plist[host]
|
p = servers[host]
|
||||||
port = p['t']
|
port = p['t']
|
||||||
srv = host + ':' + port + ':t'
|
srv = host + ':' + port + ':t'
|
||||||
wallet.config.set_key("server", srv, True)
|
wallet.config.set_key("server", srv, True)
|
||||||
@ -796,8 +796,8 @@ def settings_loop():
|
|||||||
set_listview()
|
set_listview()
|
||||||
|
|
||||||
elif pos == "1": #protocol
|
elif pos == "1": #protocol
|
||||||
if host in plist:
|
if host in servers:
|
||||||
srv = protocol_dialog(host, protocol, plist[host])
|
srv = protocol_dialog(host, protocol, servers[host])
|
||||||
if srv:
|
if srv:
|
||||||
wallet.config.set_key("server", srv, True)
|
wallet.config.set_key("server", srv, True)
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import sys, time, datetime, re, threading
|
|||||||
from i18n import _, set_language
|
from i18n import _, set_language
|
||||||
from electrum.util import print_error, print_msg
|
from electrum.util import print_error, print_msg
|
||||||
import os.path, json, ast, traceback
|
import os.path, json, ast, traceback
|
||||||
from qrcodewidget import QRCodeWidget
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import PyQt4
|
import PyQt4
|
||||||
@ -30,8 +30,7 @@ except:
|
|||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
import PyQt4.QtCore as QtCore
|
import PyQt4.QtCore as QtCore
|
||||||
import PyQt4.QtGui as QtGui
|
|
||||||
from electrum.interface import DEFAULT_SERVERS, DEFAULT_PORTS
|
|
||||||
from electrum.bitcoin import MIN_RELAY_TX_FEE
|
from electrum.bitcoin import MIN_RELAY_TX_FEE
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -48,6 +47,8 @@ import bmp, pyqrnative
|
|||||||
import exchange_rate
|
import exchange_rate
|
||||||
|
|
||||||
from amountedit import AmountEdit
|
from amountedit import AmountEdit
|
||||||
|
from network_dialog import NetworkDialog
|
||||||
|
from qrcodewidget import QRCodeWidget
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
@ -67,9 +68,11 @@ else:
|
|||||||
from electrum import ELECTRUM_VERSION
|
from electrum import ELECTRUM_VERSION
|
||||||
import re
|
import re
|
||||||
|
|
||||||
class UpdateLabel(QtGui.QLabel):
|
from qt_util import *
|
||||||
|
|
||||||
|
class UpdateLabel(QLabel):
|
||||||
def __init__(self, config, parent=None):
|
def __init__(self, config, parent=None):
|
||||||
QtGui.QLabel.__init__(self, parent)
|
QLabel.__init__(self, parent)
|
||||||
self.new_version = False
|
self.new_version = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -225,33 +228,8 @@ def waiting_dialog(f):
|
|||||||
w.destroy()
|
w.destroy()
|
||||||
|
|
||||||
|
|
||||||
def ok_cancel_buttons(dialog, ok_label=_("OK") ):
|
|
||||||
hbox = QHBoxLayout()
|
|
||||||
hbox.addStretch(1)
|
|
||||||
b = QPushButton(_("Cancel"))
|
|
||||||
hbox.addWidget(b)
|
|
||||||
b.clicked.connect(dialog.reject)
|
|
||||||
b = QPushButton(ok_label)
|
|
||||||
hbox.addWidget(b)
|
|
||||||
b.clicked.connect(dialog.accept)
|
|
||||||
b.setDefault(True)
|
|
||||||
return hbox
|
|
||||||
|
|
||||||
|
|
||||||
def text_dialog(parent, title, label, ok_label):
|
|
||||||
dialog = QDialog(parent)
|
|
||||||
dialog.setMinimumWidth(500)
|
|
||||||
dialog.setWindowTitle(title)
|
|
||||||
dialog.setModal(1)
|
|
||||||
l = QVBoxLayout()
|
|
||||||
dialog.setLayout(l)
|
|
||||||
l.addWidget(QLabel(label))
|
|
||||||
txt = QTextEdit()
|
|
||||||
l.addWidget(txt)
|
|
||||||
l.addLayout(ok_cancel_buttons(dialog, ok_label))
|
|
||||||
if dialog.exec_():
|
|
||||||
return unicode(txt.toPlainText())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default_column_widths = { "history":[40,140,350,140], "contacts":[350,330], "receive":[[370], [370,200,130]] }
|
default_column_widths = { "history":[40,140,350,140], "contacts":[350,330], "receive":[[370], [370,200,130]] }
|
||||||
@ -1234,7 +1212,7 @@ class ElectrumWindow(QMainWindow):
|
|||||||
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), _("Preferences"), self.settings_dialog ) )
|
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), _("Preferences"), self.settings_dialog ) )
|
||||||
if self.wallet.seed:
|
if self.wallet.seed:
|
||||||
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), self.show_seed_dialog ) )
|
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), self.show_seed_dialog ) )
|
||||||
self.status_button = StatusBarButton( QIcon(":icons/status_disconnected.png"), _("Network"), lambda: self.network_dialog(self.wallet, self) )
|
self.status_button = StatusBarButton( QIcon(":icons/status_disconnected.png"), _("Network"), self.run_network_dialog )
|
||||||
sb.addPermanentWidget( self.status_button )
|
sb.addPermanentWidget( self.status_button )
|
||||||
|
|
||||||
self.run_hook('create_status_bar', (sb,))
|
self.run_hook('create_status_bar', (sb,))
|
||||||
@ -2008,7 +1986,7 @@ class ElectrumWindow(QMainWindow):
|
|||||||
grid_plugins = QGridLayout()
|
grid_plugins = QGridLayout()
|
||||||
grid_plugins.setColumnStretch(0,1)
|
grid_plugins.setColumnStretch(0,1)
|
||||||
|
|
||||||
w = QtGui.QWidget()
|
w = QWidget()
|
||||||
w.setLayout(grid_plugins)
|
w.setLayout(grid_plugins)
|
||||||
tab5.setWidget(w)
|
tab5.setWidget(w)
|
||||||
tab5.setMaximumSize(tab3.size()) # optional
|
tab5.setMaximumSize(tab3.size()) # optional
|
||||||
@ -2112,177 +2090,8 @@ class ElectrumWindow(QMainWindow):
|
|||||||
|
|
||||||
self.receive_tab_set_mode(expert_cb.isChecked())
|
self.receive_tab_set_mode(expert_cb.isChecked())
|
||||||
|
|
||||||
|
def run_network_dialog(self):
|
||||||
@staticmethod
|
NetworkDialog(self.wallet.interface, self.config, self).do_exec()
|
||||||
def network_dialog(wallet, parent=None):
|
|
||||||
interface = wallet.interface
|
|
||||||
if parent:
|
|
||||||
if interface.is_connected:
|
|
||||||
status = _("Connected to")+" %s\n%d "%(interface.host, wallet.verifier.height)+_("blocks")
|
|
||||||
else:
|
|
||||||
status = _("Not connected")
|
|
||||||
server = interface.server
|
|
||||||
else:
|
|
||||||
import random
|
|
||||||
status = _("Please choose a server.") + "\n" + _("Select 'Cancel' if you are offline.")
|
|
||||||
server = interface.server
|
|
||||||
|
|
||||||
plist, servers_list = interface.get_servers_list()
|
|
||||||
|
|
||||||
d = QDialog(parent)
|
|
||||||
d.setModal(1)
|
|
||||||
d.setWindowTitle(_('Server'))
|
|
||||||
d.setMinimumSize(375, 20)
|
|
||||||
|
|
||||||
vbox = QVBoxLayout()
|
|
||||||
vbox.setSpacing(30)
|
|
||||||
|
|
||||||
hbox = QHBoxLayout()
|
|
||||||
l = QLabel()
|
|
||||||
l.setPixmap(QPixmap(":icons/network.png"))
|
|
||||||
hbox.addStretch(10)
|
|
||||||
hbox.addWidget(l)
|
|
||||||
hbox.addWidget(QLabel(status))
|
|
||||||
hbox.addStretch(50)
|
|
||||||
vbox.addLayout(hbox)
|
|
||||||
|
|
||||||
|
|
||||||
# grid layout
|
|
||||||
grid = QGridLayout()
|
|
||||||
grid.setSpacing(8)
|
|
||||||
vbox.addLayout(grid)
|
|
||||||
|
|
||||||
# server
|
|
||||||
server_protocol = QComboBox()
|
|
||||||
server_host = QLineEdit()
|
|
||||||
server_host.setFixedWidth(200)
|
|
||||||
server_port = QLineEdit()
|
|
||||||
server_port.setFixedWidth(60)
|
|
||||||
|
|
||||||
protocol_names = ['TCP', 'HTTP', 'SSL', 'HTTPS']
|
|
||||||
protocol_letters = 'thsg'
|
|
||||||
server_protocol.addItems(protocol_names)
|
|
||||||
|
|
||||||
grid.addWidget(QLabel(_('Server') + ':'), 0, 0)
|
|
||||||
grid.addWidget(server_protocol, 0, 1)
|
|
||||||
grid.addWidget(server_host, 0, 2)
|
|
||||||
grid.addWidget(server_port, 0, 3)
|
|
||||||
|
|
||||||
def change_protocol(p):
|
|
||||||
protocol = protocol_letters[p]
|
|
||||||
host = unicode(server_host.text())
|
|
||||||
pp = plist.get(host,DEFAULT_PORTS)
|
|
||||||
if protocol not in pp.keys():
|
|
||||||
protocol = pp.keys()[0]
|
|
||||||
port = pp[protocol]
|
|
||||||
server_host.setText( host )
|
|
||||||
server_port.setText( port )
|
|
||||||
|
|
||||||
server_protocol.connect(server_protocol, SIGNAL('currentIndexChanged(int)'), change_protocol)
|
|
||||||
|
|
||||||
label = _('Active Servers') if wallet.interface.servers else _('Default Servers')
|
|
||||||
servers_list_widget = QTreeWidget(parent)
|
|
||||||
servers_list_widget.setHeaderLabels( [ label, _('Limit') ] )
|
|
||||||
servers_list_widget.setMaximumHeight(150)
|
|
||||||
servers_list_widget.setColumnWidth(0, 240)
|
|
||||||
for _host in servers_list.keys():
|
|
||||||
pruning_level = servers_list[_host].get('pruning','')
|
|
||||||
servers_list_widget.addTopLevelItem(QTreeWidgetItem( [ _host, pruning_level ] ))
|
|
||||||
servers_list_widget.setColumnHidden(1, not parent.expert_mode if parent else True)
|
|
||||||
|
|
||||||
def change_server(host, protocol=None):
|
|
||||||
pp = plist.get(host,DEFAULT_PORTS)
|
|
||||||
if protocol:
|
|
||||||
port = pp.get(protocol)
|
|
||||||
if not port: protocol = None
|
|
||||||
|
|
||||||
if not protocol:
|
|
||||||
if 's' in pp.keys():
|
|
||||||
protocol = 's'
|
|
||||||
port = pp.get(protocol)
|
|
||||||
else:
|
|
||||||
protocol = pp.keys()[0]
|
|
||||||
port = pp.get(protocol)
|
|
||||||
|
|
||||||
server_host.setText( host )
|
|
||||||
server_port.setText( port )
|
|
||||||
server_protocol.setCurrentIndex(protocol_letters.index(protocol))
|
|
||||||
|
|
||||||
if not plist: return
|
|
||||||
for p in protocol_letters:
|
|
||||||
i = protocol_letters.index(p)
|
|
||||||
j = server_protocol.model().index(i,0)
|
|
||||||
if p not in pp.keys() and interface.is_connected:
|
|
||||||
server_protocol.model().setData(j, QtCore.QVariant(0), QtCore.Qt.UserRole-1)
|
|
||||||
else:
|
|
||||||
server_protocol.model().setData(j, QtCore.QVariant(33), QtCore.Qt.UserRole-1)
|
|
||||||
|
|
||||||
if server:
|
|
||||||
host, port, protocol = server.split(':')
|
|
||||||
change_server(host,protocol)
|
|
||||||
|
|
||||||
servers_list_widget.connect(servers_list_widget, SIGNAL('currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)'),
|
|
||||||
lambda x,y: change_server(unicode(x.text(0))))
|
|
||||||
grid.addWidget(servers_list_widget, 1, 1, 1, 3)
|
|
||||||
|
|
||||||
if not wallet.config.is_modifiable('server'):
|
|
||||||
for w in [server_host, server_port, server_protocol, servers_list_widget]: w.setEnabled(False)
|
|
||||||
|
|
||||||
# auto cycle
|
|
||||||
autocycle_cb = QCheckBox(_('Try random servers if disconnected'))
|
|
||||||
autocycle_cb.setChecked(wallet.config.get('auto_cycle', True))
|
|
||||||
grid.addWidget(autocycle_cb, 3, 1, 3, 2)
|
|
||||||
if not wallet.config.is_modifiable('auto_cycle'): autocycle_cb.setEnabled(False)
|
|
||||||
|
|
||||||
# proxy setting
|
|
||||||
proxy_mode = QComboBox()
|
|
||||||
proxy_host = QLineEdit()
|
|
||||||
proxy_host.setFixedWidth(200)
|
|
||||||
proxy_port = QLineEdit()
|
|
||||||
proxy_port.setFixedWidth(60)
|
|
||||||
proxy_mode.addItems(['NONE', 'SOCKS4', 'SOCKS5', 'HTTP'])
|
|
||||||
|
|
||||||
def check_for_disable(index = False):
|
|
||||||
if proxy_mode.currentText() != 'NONE':
|
|
||||||
proxy_host.setEnabled(True)
|
|
||||||
proxy_port.setEnabled(True)
|
|
||||||
else:
|
|
||||||
proxy_host.setEnabled(False)
|
|
||||||
proxy_port.setEnabled(False)
|
|
||||||
|
|
||||||
check_for_disable()
|
|
||||||
proxy_mode.connect(proxy_mode, SIGNAL('currentIndexChanged(int)'), check_for_disable)
|
|
||||||
|
|
||||||
if not wallet.config.is_modifiable('proxy'):
|
|
||||||
for w in [proxy_host, proxy_port, proxy_mode]: w.setEnabled(False)
|
|
||||||
|
|
||||||
proxy_config = interface.proxy if interface.proxy else { "mode":"none", "host":"localhost", "port":"8080"}
|
|
||||||
proxy_mode.setCurrentIndex(proxy_mode.findText(str(proxy_config.get("mode").upper())))
|
|
||||||
proxy_host.setText(proxy_config.get("host"))
|
|
||||||
proxy_port.setText(proxy_config.get("port"))
|
|
||||||
|
|
||||||
grid.addWidget(QLabel(_('Proxy') + ':'), 2, 0)
|
|
||||||
grid.addWidget(proxy_mode, 2, 1)
|
|
||||||
grid.addWidget(proxy_host, 2, 2)
|
|
||||||
grid.addWidget(proxy_port, 2, 3)
|
|
||||||
|
|
||||||
# buttons
|
|
||||||
vbox.addLayout(ok_cancel_buttons(d))
|
|
||||||
d.setLayout(vbox)
|
|
||||||
|
|
||||||
if not d.exec_(): return
|
|
||||||
|
|
||||||
server = unicode( server_host.text() ) + ':' + unicode( server_port.text() ) + ':' + (protocol_letters[server_protocol.currentIndex()])
|
|
||||||
if proxy_mode.currentText() != 'NONE':
|
|
||||||
proxy = { u'mode':unicode(proxy_mode.currentText()).lower(), u'host':unicode(proxy_host.text()), u'port':unicode(proxy_port.text()) }
|
|
||||||
else:
|
|
||||||
proxy = None
|
|
||||||
|
|
||||||
wallet.config.set_key("proxy", proxy, True)
|
|
||||||
wallet.config.set_key("server", server, True)
|
|
||||||
interface.set_server(server, proxy)
|
|
||||||
wallet.config.set_key('auto_cycle', autocycle_cb.isChecked(), True)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
g = self.geometry()
|
g = self.geometry()
|
||||||
@ -2292,6 +2101,9 @@ class ElectrumWindow(QMainWindow):
|
|||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ElectrumGui:
|
class ElectrumGui:
|
||||||
|
|
||||||
def __init__(self, wallet, config, app=None):
|
def __init__(self, wallet, config, app=None):
|
||||||
@ -2379,7 +2191,7 @@ class ElectrumGui:
|
|||||||
|
|
||||||
|
|
||||||
def network_dialog(self):
|
def network_dialog(self):
|
||||||
return ElectrumWindow.network_dialog( self.wallet, parent=None )
|
return NetworkDialog(self.wallet.interface, self.config, None).do_exec()
|
||||||
|
|
||||||
|
|
||||||
def show_seed(self):
|
def show_seed(self):
|
||||||
|
|||||||
@ -282,7 +282,7 @@ def run_network_dialog( wallet, parent ):
|
|||||||
status = "Please choose a server.\nSelect cancel if you are offline."
|
status = "Please choose a server.\nSelect cancel if you are offline."
|
||||||
|
|
||||||
server = interface.server
|
server = interface.server
|
||||||
plist, servers_list = interface.get_servers_list()
|
servers = interface.get_servers()
|
||||||
|
|
||||||
dialog = gtk.MessageDialog( parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
dialog = gtk.MessageDialog( parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||||
gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, status)
|
gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, status)
|
||||||
@ -331,7 +331,7 @@ def run_network_dialog( wallet, parent ):
|
|||||||
|
|
||||||
def set_protocol(protocol):
|
def set_protocol(protocol):
|
||||||
host = current_line()[0]
|
host = current_line()[0]
|
||||||
pp = plist[host]
|
pp = servers[host]
|
||||||
if protocol not in pp.keys():
|
if protocol not in pp.keys():
|
||||||
protocol = pp.keys()[0]
|
protocol = pp.keys()[0]
|
||||||
set_button(protocol)
|
set_button(protocol)
|
||||||
@ -342,7 +342,7 @@ def run_network_dialog( wallet, parent ):
|
|||||||
radio2.connect("toggled", lambda x,y:set_protocol('h'), "radio button 1")
|
radio2.connect("toggled", lambda x,y:set_protocol('h'), "radio button 1")
|
||||||
|
|
||||||
server_list = gtk.ListStore(str)
|
server_list = gtk.ListStore(str)
|
||||||
for host in plist.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)
|
||||||
@ -372,7 +372,7 @@ def run_network_dialog( wallet, parent ):
|
|||||||
path, view_column = treeview.get_cursor()
|
path, view_column = treeview.get_cursor()
|
||||||
host = server_list.get_value( server_list.get_iter(path), 0)
|
host = server_list.get_value( server_list.get_iter(path), 0)
|
||||||
|
|
||||||
pp = plist[host]
|
pp = servers[host]
|
||||||
if 't' in pp.keys():
|
if 't' in pp.keys():
|
||||||
protocol = 't'
|
protocol = 't'
|
||||||
else:
|
else:
|
||||||
|
|||||||
231
gui/network_dialog.py
Normal file
231
gui/network_dialog.py
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Electrum - lightweight Bitcoin client
|
||||||
|
# Copyright (C) 2012 thomasv@gitorious
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sys, time, datetime, re, threading
|
||||||
|
from i18n import _
|
||||||
|
from electrum.util import print_error, print_msg
|
||||||
|
import os.path, json, ast, traceback
|
||||||
|
|
||||||
|
from PyQt4.QtGui import *
|
||||||
|
from PyQt4.QtCore import *
|
||||||
|
from electrum.interface import DEFAULT_SERVERS, DEFAULT_PORTS
|
||||||
|
|
||||||
|
from qt_util import *
|
||||||
|
|
||||||
|
protocol_names = ['TCP', 'HTTP', 'SSL', 'HTTPS']
|
||||||
|
protocol_letters = 'thsg'
|
||||||
|
|
||||||
|
class NetworkDialog(QDialog):
|
||||||
|
def __init__(self, interface, config, parent):
|
||||||
|
|
||||||
|
QDialog.__init__(self,parent)
|
||||||
|
self.setModal(1)
|
||||||
|
self.setWindowTitle(_('Server'))
|
||||||
|
self.setMinimumSize(375, 20)
|
||||||
|
|
||||||
|
self.interface = interface
|
||||||
|
self.config = config
|
||||||
|
self.protocol = None
|
||||||
|
|
||||||
|
if parent:
|
||||||
|
if interface.is_connected:
|
||||||
|
status = _("Connected to")+" %s"%(interface.host) #, wallet.verifier.height)+_("blocks")
|
||||||
|
else:
|
||||||
|
status = _("Not connected")
|
||||||
|
server = interface.server
|
||||||
|
else:
|
||||||
|
import random
|
||||||
|
status = _("Please choose a server.") + "\n" + _("Select 'Cancel' if you are offline.")
|
||||||
|
server = interface.server
|
||||||
|
|
||||||
|
self.servers = interface.get_servers()
|
||||||
|
|
||||||
|
vbox = QVBoxLayout()
|
||||||
|
vbox.setSpacing(30)
|
||||||
|
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
l = QLabel()
|
||||||
|
l.setPixmap(QPixmap(":icons/network.png"))
|
||||||
|
hbox.addStretch(10)
|
||||||
|
hbox.addWidget(l)
|
||||||
|
hbox.addWidget(QLabel(status))
|
||||||
|
hbox.addStretch(50)
|
||||||
|
vbox.addLayout(hbox)
|
||||||
|
|
||||||
|
# grid layout
|
||||||
|
grid = QGridLayout()
|
||||||
|
grid.setSpacing(8)
|
||||||
|
vbox.addLayout(grid)
|
||||||
|
|
||||||
|
# server
|
||||||
|
self.server_protocol = QComboBox()
|
||||||
|
self.server_host = QLineEdit()
|
||||||
|
self.server_host.setFixedWidth(200)
|
||||||
|
self.server_port = QLineEdit()
|
||||||
|
self.server_port.setFixedWidth(60)
|
||||||
|
|
||||||
|
self.server_protocol.addItems(protocol_names)
|
||||||
|
|
||||||
|
grid.addWidget(QLabel(_('Server') + ':'), 0, 0)
|
||||||
|
grid.addWidget(self.server_protocol, 0, 1)
|
||||||
|
grid.addWidget(self.server_host, 0, 2)
|
||||||
|
grid.addWidget(self.server_port, 0, 3)
|
||||||
|
|
||||||
|
self.server_protocol.connect(self.server_protocol, SIGNAL('currentIndexChanged(int)'), self.change_protocol)
|
||||||
|
|
||||||
|
label = _('Active Servers') if interface.servers else _('Default Servers')
|
||||||
|
self.servers_list_widget = QTreeWidget(parent)
|
||||||
|
self.servers_list_widget.setHeaderLabels( [ label, _('Limit') ] )
|
||||||
|
self.servers_list_widget.setMaximumHeight(150)
|
||||||
|
self.servers_list_widget.setColumnWidth(0, 240)
|
||||||
|
|
||||||
|
if server:
|
||||||
|
host, port, protocol = server.split(':')
|
||||||
|
self.set_protocol(protocol)
|
||||||
|
self.change_server(host, protocol)
|
||||||
|
else:
|
||||||
|
self.set_protocol('s')
|
||||||
|
|
||||||
|
self.servers_list_widget.connect(self.servers_list_widget,
|
||||||
|
SIGNAL('currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)'),
|
||||||
|
lambda x,y: self.server_changed(x))
|
||||||
|
grid.addWidget(self.servers_list_widget, 1, 1, 1, 3)
|
||||||
|
|
||||||
|
if not config.is_modifiable('server'):
|
||||||
|
for w in [self.server_host, self.server_port, self.server_protocol, self.servers_list_widget]: w.setEnabled(False)
|
||||||
|
|
||||||
|
# auto cycle
|
||||||
|
self.autocycle_cb = QCheckBox(_('Try random servers if disconnected'))
|
||||||
|
self.autocycle_cb.setChecked(self.config.get('auto_cycle', True))
|
||||||
|
grid.addWidget(self.autocycle_cb, 3, 1, 3, 2)
|
||||||
|
if not self.config.is_modifiable('auto_cycle'): self.autocycle_cb.setEnabled(False)
|
||||||
|
|
||||||
|
# proxy setting
|
||||||
|
self.proxy_mode = QComboBox()
|
||||||
|
self.proxy_host = QLineEdit()
|
||||||
|
self.proxy_host.setFixedWidth(200)
|
||||||
|
self.proxy_port = QLineEdit()
|
||||||
|
self.proxy_port.setFixedWidth(60)
|
||||||
|
self.proxy_mode.addItems(['NONE', 'SOCKS4', 'SOCKS5', 'HTTP'])
|
||||||
|
|
||||||
|
def check_for_disable(index = False):
|
||||||
|
if self.proxy_mode.currentText() != 'NONE':
|
||||||
|
self.proxy_host.setEnabled(True)
|
||||||
|
self.proxy_port.setEnabled(True)
|
||||||
|
else:
|
||||||
|
self.proxy_host.setEnabled(False)
|
||||||
|
self.proxy_port.setEnabled(False)
|
||||||
|
|
||||||
|
check_for_disable()
|
||||||
|
self.proxy_mode.connect(self.proxy_mode, SIGNAL('currentIndexChanged(int)'), check_for_disable)
|
||||||
|
|
||||||
|
if not self.config.is_modifiable('proxy'):
|
||||||
|
for w in [self.proxy_host, self.proxy_port, self.proxy_mode]: w.setEnabled(False)
|
||||||
|
|
||||||
|
proxy_config = interface.proxy if interface.proxy else { "mode":"none", "host":"localhost", "port":"8080"}
|
||||||
|
self.proxy_mode.setCurrentIndex(self.proxy_mode.findText(str(proxy_config.get("mode").upper())))
|
||||||
|
self.proxy_host.setText(proxy_config.get("host"))
|
||||||
|
self.proxy_port.setText(proxy_config.get("port"))
|
||||||
|
|
||||||
|
grid.addWidget(QLabel(_('Proxy') + ':'), 2, 0)
|
||||||
|
grid.addWidget(self.proxy_mode, 2, 1)
|
||||||
|
grid.addWidget(self.proxy_host, 2, 2)
|
||||||
|
grid.addWidget(self.proxy_port, 2, 3)
|
||||||
|
|
||||||
|
# buttons
|
||||||
|
vbox.addLayout(ok_cancel_buttons(self))
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
|
|
||||||
|
def init_servers_list(self):
|
||||||
|
self.servers_list_widget.clear()
|
||||||
|
for _host, d in self.servers.items():
|
||||||
|
if d.get(self.protocol):
|
||||||
|
pruning_level = d.get('pruning','')
|
||||||
|
self.servers_list_widget.addTopLevelItem(QTreeWidgetItem( [ _host, pruning_level ] ))
|
||||||
|
|
||||||
|
|
||||||
|
def set_protocol(self, protocol):
|
||||||
|
if protocol != self.protocol:
|
||||||
|
self.protocol = protocol
|
||||||
|
self.init_servers_list()
|
||||||
|
|
||||||
|
def change_protocol(self, index):
|
||||||
|
p = protocol_letters[index]
|
||||||
|
host = unicode(self.server_host.text())
|
||||||
|
pp = self.servers.get(host)
|
||||||
|
if p not in pp.keys():
|
||||||
|
p = pp.keys()[0]
|
||||||
|
port = pp[p]
|
||||||
|
self.server_host.setText( host )
|
||||||
|
self.server_port.setText( port )
|
||||||
|
self.set_protocol(p)
|
||||||
|
|
||||||
|
def server_changed(self, x):
|
||||||
|
if x:
|
||||||
|
self.change_server(str(x.text(0)), self.protocol)
|
||||||
|
|
||||||
|
def change_server(self, host, protocol):
|
||||||
|
|
||||||
|
pp = self.servers.get(host, DEFAULT_PORTS)
|
||||||
|
if protocol:
|
||||||
|
port = pp.get(protocol)
|
||||||
|
if not port: protocol = None
|
||||||
|
|
||||||
|
if not protocol:
|
||||||
|
if 's' in pp.keys():
|
||||||
|
protocol = 's'
|
||||||
|
port = pp.get(protocol)
|
||||||
|
else:
|
||||||
|
protocol = pp.keys()[0]
|
||||||
|
port = pp.get(protocol)
|
||||||
|
|
||||||
|
self.server_host.setText( host )
|
||||||
|
self.server_port.setText( port )
|
||||||
|
self.server_protocol.setCurrentIndex(protocol_letters.index(protocol))
|
||||||
|
|
||||||
|
if not self.servers: return
|
||||||
|
for p in protocol_letters:
|
||||||
|
i = protocol_letters.index(p)
|
||||||
|
j = self.server_protocol.model().index(i,0)
|
||||||
|
#if p not in pp.keys(): # and self.interface.is_connected:
|
||||||
|
# self.server_protocol.model().setData(j, QVariant(0), Qt.UserRole-1)
|
||||||
|
#else:
|
||||||
|
# self.server_protocol.model().setData(j, QVariant(33), Qt.UserRole-1)
|
||||||
|
|
||||||
|
|
||||||
|
def do_exec(self):
|
||||||
|
|
||||||
|
if not self.exec_(): return
|
||||||
|
|
||||||
|
server = ':'.join([str( self.server_host.text() ),
|
||||||
|
str( self.server_port.text() ),
|
||||||
|
(protocol_letters[self.server_protocol.currentIndex()]) ])
|
||||||
|
|
||||||
|
if self.proxy_mode.currentText() != 'NONE':
|
||||||
|
proxy = { 'mode':str(self.proxy_mode.currentText()).lower(),
|
||||||
|
'host':str(self.proxy_host.text()),
|
||||||
|
'port':str(self.proxy_port.text()) }
|
||||||
|
else:
|
||||||
|
proxy = None
|
||||||
|
|
||||||
|
self.config.set_key("proxy", proxy, True)
|
||||||
|
self.config.set_key("server", server, True)
|
||||||
|
self.interface.set_server(server, proxy)
|
||||||
|
self.config.set_key('auto_cycle', self.autocycle_cb.isChecked(), True)
|
||||||
|
return True
|
||||||
30
gui/qt_util.py
Normal file
30
gui/qt_util.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from i18n import _
|
||||||
|
from PyQt4.QtGui import *
|
||||||
|
from PyQt4.QtCore import *
|
||||||
|
|
||||||
|
def ok_cancel_buttons(dialog, ok_label=_("OK") ):
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
hbox.addStretch(1)
|
||||||
|
b = QPushButton(_("Cancel"))
|
||||||
|
hbox.addWidget(b)
|
||||||
|
b.clicked.connect(dialog.reject)
|
||||||
|
b = QPushButton(ok_label)
|
||||||
|
hbox.addWidget(b)
|
||||||
|
b.clicked.connect(dialog.accept)
|
||||||
|
b.setDefault(True)
|
||||||
|
return hbox
|
||||||
|
|
||||||
|
def text_dialog(parent, title, label, ok_label):
|
||||||
|
dialog = QDialog(parent)
|
||||||
|
dialog.setMinimumWidth(500)
|
||||||
|
dialog.setWindowTitle(title)
|
||||||
|
dialog.setModal(1)
|
||||||
|
l = QVBoxLayout()
|
||||||
|
dialog.setLayout(l)
|
||||||
|
l.addWidget(QLabel(label))
|
||||||
|
txt = QTextEdit()
|
||||||
|
l.addWidget(txt)
|
||||||
|
l.addLayout(ok_cancel_buttons(dialog, ok_label))
|
||||||
|
if dialog.exec_():
|
||||||
|
return unicode(txt.toPlainText())
|
||||||
|
|
||||||
111
lib/interface.py
111
lib/interface.py
@ -26,34 +26,39 @@ from util import print_error, print_msg
|
|||||||
|
|
||||||
DEFAULT_TIMEOUT = 5
|
DEFAULT_TIMEOUT = 5
|
||||||
DEFAULT_PORTS = {'t':'50001', 's':'50002', 'h':'8081', 'g':'8082'}
|
DEFAULT_PORTS = {'t':'50001', 's':'50002', 'h':'8081', 'g':'8082'}
|
||||||
DEFAULT_SERVERS = [
|
|
||||||
'electrum.bitcoin.cz:50002:s',
|
|
||||||
'electrum.novit.ro:50002:s',
|
|
||||||
'electrum.be:50002:s',
|
|
||||||
'electrum.bysh.me:50002:s',
|
|
||||||
'electrum.pdmc.net:50002:s',
|
|
||||||
'electrum.no-ip.org:50002:s',
|
|
||||||
'ecdsa.org:50002:s',
|
|
||||||
'electra.datemas.de:50002:s',
|
|
||||||
'electrum.datemas.de:50002:s',
|
|
||||||
'electrum.mooo.com:50002:s',
|
|
||||||
'btcback.com:50002:s',
|
|
||||||
'electrum.bitcoins.sk:50002:s',
|
|
||||||
'btc.stytt.com:50002:s',
|
|
||||||
'electrum.stepkrav.pw:50002:s',
|
|
||||||
'btc.it-zone.org:110:s'
|
|
||||||
]
|
|
||||||
|
|
||||||
# add only port 80 servers here
|
DEFAULT_SERVERS = {
|
||||||
DEFAULT_HTTP_SERVERS = [
|
'electrum.thecoinwillprevail.com': {'h': '8081', 's': '50002', 't': '50001'},
|
||||||
'electrum.no-ip.org:80:h'
|
'the9ull.homelinux.org': {'h': '8082', 't': '50001'},
|
||||||
]
|
'electra.datemas.de': {'h': '8081', 's': '50002', 't': '50001', 'g': '808'},
|
||||||
|
'electrum.datemas.de': {'h': '8081', 's': '50002', 't': '50001', 'g': '8082'},
|
||||||
|
'ecdsa.org': {'h': '8081', 's': '50002', 't': '50001', 'g': '8082'},
|
||||||
|
'electrum.mooo.com': {'h': '8081', 't': '50001'},
|
||||||
|
'btcback.com': {'h': '8081', 's': '50002', 't': '50001', 'g': '8082'},
|
||||||
|
'electrum.bitcoins.sk': {'h': '8081', 's': '50002', 't': '50001', 'g': '8'},
|
||||||
|
'electrum.no-ip.org': {'h': '80', 's': '50002', 't': '50001', 'g': '443'},
|
||||||
|
'electrum.drollette.com': {'h': '8081', 's': '50002', 't': '50001', 'g': '8082'},
|
||||||
|
'btc.it-zone.org': {'h': '80', 's': '110', 't': '50001', 'g': '443'},
|
||||||
|
'electrum.yacoin.com': {'h': '8081', 's': '50002', 't': '50001', 'g': '8082'},
|
||||||
|
'electrum.be': {'h': '8081', 's': '50002', 't': '50001', 'g': '8082'}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def filter_protocol(servers, p):
|
||||||
|
l = []
|
||||||
|
for k, protocols in servers.items():
|
||||||
|
if p in protocols:
|
||||||
|
l.append( ':'.join([k, protocols[p], p]) )
|
||||||
|
return l
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proxy_modes = ['socks4', 'socks5', 'http']
|
proxy_modes = ['socks4', 'socks5', 'http']
|
||||||
|
|
||||||
|
|
||||||
def pick_random_server():
|
def pick_random_server():
|
||||||
return random.choice( DEFAULT_SERVERS )
|
return random.choice( filter_protocol(DEFAULT_SERVERS,'s') )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -119,9 +124,10 @@ class Interface(threading.Thread):
|
|||||||
elif method == 'server.peers.subscribe':
|
elif method == 'server.peers.subscribe':
|
||||||
servers = {}
|
servers = {}
|
||||||
for item in result:
|
for item in result:
|
||||||
s = []
|
|
||||||
host = item[1]
|
host = item[1]
|
||||||
ports = []
|
out = {}
|
||||||
|
|
||||||
version = None
|
version = None
|
||||||
pruning_level = '-'
|
pruning_level = '-'
|
||||||
if len(item) > 2:
|
if len(item) > 2:
|
||||||
@ -129,7 +135,7 @@ class Interface(threading.Thread):
|
|||||||
if re.match("[stgh]\d*", v):
|
if re.match("[stgh]\d*", v):
|
||||||
protocol, port = v[0], v[1:]
|
protocol, port = v[0], v[1:]
|
||||||
if port == '': port = DEFAULT_PORTS[protocol]
|
if port == '': port = DEFAULT_PORTS[protocol]
|
||||||
ports.append((protocol, port))
|
out[protocol] = port
|
||||||
elif re.match("v(.?)+", v):
|
elif re.match("v(.?)+", v):
|
||||||
version = v[1:]
|
version = v[1:]
|
||||||
elif re.match("p\d*", v):
|
elif re.match("p\d*", v):
|
||||||
@ -139,8 +145,11 @@ class Interface(threading.Thread):
|
|||||||
is_recent = float(version)>=float(PROTOCOL_VERSION)
|
is_recent = float(version)>=float(PROTOCOL_VERSION)
|
||||||
except:
|
except:
|
||||||
is_recent = False
|
is_recent = False
|
||||||
if ports and is_recent:
|
|
||||||
servers[host] = {'ports':ports, 'pruning':pruning_level}
|
if out and is_recent:
|
||||||
|
out['pruning'] = pruning_level
|
||||||
|
servers[host] = out
|
||||||
|
|
||||||
self.servers = servers
|
self.servers = servers
|
||||||
self.trigger_callback('peers')
|
self.trigger_callback('peers')
|
||||||
|
|
||||||
@ -309,26 +318,28 @@ class Interface(threading.Thread):
|
|||||||
s.setproxy(proxy_modes.index(self.proxy["mode"]) + 1, self.proxy["host"], int(self.proxy["port"]) )
|
s.setproxy(proxy_modes.index(self.proxy["mode"]) + 1, self.proxy["host"], int(self.proxy["port"]) )
|
||||||
|
|
||||||
if self.use_ssl:
|
if self.use_ssl:
|
||||||
s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23)
|
s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, do_handshake_on_connect=True)
|
||||||
|
|
||||||
s.settimeout(2)
|
s.settimeout(2)
|
||||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
s.connect(( self.host.encode('ascii'), int(self.port)))
|
s.connect(( self.host.encode('ascii'), int(self.port)))
|
||||||
s.settimeout(60)
|
|
||||||
self.s = s
|
|
||||||
self.is_connected = True
|
|
||||||
except:
|
except:
|
||||||
|
traceback.print_exc(file=sys.stdout)
|
||||||
self.is_connected = False
|
self.is_connected = False
|
||||||
self.s = None
|
self.s = None
|
||||||
|
return
|
||||||
|
|
||||||
|
s.settimeout(60)
|
||||||
|
self.s = s
|
||||||
|
self.is_connected = True
|
||||||
|
|
||||||
def run_tcp(self):
|
def run_tcp(self):
|
||||||
try:
|
try:
|
||||||
|
#if self.use_ssl: self.s.do_handshake()
|
||||||
out = ''
|
out = ''
|
||||||
while self.is_connected:
|
while self.is_connected:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
timeout = False
|
timeout = False
|
||||||
msg = self.s.recv(1024)
|
msg = self.s.recv(1024)
|
||||||
@ -395,7 +406,7 @@ class Interface(threading.Thread):
|
|||||||
|
|
||||||
|
|
||||||
def __init__(self, config=None, loop=False):
|
def __init__(self, config=None, loop=False):
|
||||||
self.server = random.choice(DEFAULT_SERVERS[:])
|
self.server = random.choice(filter_protocol(DEFAULT_SERVERS, 's'))
|
||||||
self.proxy = None
|
self.proxy = None
|
||||||
|
|
||||||
if config is None:
|
if config is None:
|
||||||
@ -431,16 +442,10 @@ class Interface(threading.Thread):
|
|||||||
|
|
||||||
if not self.is_connected and self.config.get('auto_cycle'):
|
if not self.is_connected and self.config.get('auto_cycle'):
|
||||||
print_msg("Using random server...")
|
print_msg("Using random server...")
|
||||||
servers_tcp = DEFAULT_SERVERS[:]
|
servers = filter_protocol(DEFAULT_SERVERS, 's')
|
||||||
servers_http = DEFAULT_HTTP_SERVERS[:]
|
while servers:
|
||||||
while servers_tcp or servers_http:
|
server = random.choice( servers )
|
||||||
if servers_tcp:
|
servers.remove(server)
|
||||||
server = random.choice( servers_tcp )
|
|
||||||
servers_tcp.remove(server)
|
|
||||||
else:
|
|
||||||
# try HTTP if we can't get a TCP connection
|
|
||||||
server = random.choice( servers_http )
|
|
||||||
servers_http.remove(server)
|
|
||||||
print server
|
print server
|
||||||
self.config.set_key('server', server, False)
|
self.config.set_key('server', server, False)
|
||||||
self.init_with_server(self.config)
|
self.init_with_server(self.config)
|
||||||
@ -559,25 +564,11 @@ class Interface(threading.Thread):
|
|||||||
self.s.close()
|
self.s.close()
|
||||||
|
|
||||||
|
|
||||||
def get_servers_list(self):
|
def get_servers(self):
|
||||||
plist = {}
|
|
||||||
if not self.servers:
|
if not self.servers:
|
||||||
servers_list = {}
|
return DEFAULT_SERVERS
|
||||||
for x in DEFAULT_SERVERS:
|
|
||||||
h,port,protocol = x.split(':')
|
|
||||||
servers_list[h] = {'ports':[(protocol,port)]}
|
|
||||||
else:
|
else:
|
||||||
servers_list = self.servers
|
return self.servers
|
||||||
|
|
||||||
for _host, v in servers_list.items():
|
|
||||||
pp = v['ports']
|
|
||||||
z = {}
|
|
||||||
for item2 in pp:
|
|
||||||
_protocol, _port = item2
|
|
||||||
z[_protocol] = _port
|
|
||||||
plist[_host] = z
|
|
||||||
|
|
||||||
return plist, servers_list
|
|
||||||
|
|
||||||
|
|
||||||
def is_empty(self, channel):
|
def is_empty(self, channel):
|
||||||
|
|||||||
2
setup.py
2
setup.py
@ -73,6 +73,8 @@ setup(name = "Electrum",
|
|||||||
'electrum_gui.qrcodewidget',
|
'electrum_gui.qrcodewidget',
|
||||||
'electrum_gui.history_widget',
|
'electrum_gui.history_widget',
|
||||||
'electrum_gui.receiving_widget',
|
'electrum_gui.receiving_widget',
|
||||||
|
'electrum_gui.qt_util',
|
||||||
|
'electrum_gui.network_dialog',
|
||||||
'electrum_gui.bmp',
|
'electrum_gui.bmp',
|
||||||
'electrum_gui.i18n',
|
'electrum_gui.i18n',
|
||||||
'electrum_gui.plugins',
|
'electrum_gui.plugins',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user