|
|
|
@ -95,9 +95,12 @@ class NodesListWidget(QTreeWidget): |
|
|
|
DISCONNECTED_SERVER = 2 |
|
|
|
DISCONNECTED_SERVER = 2 |
|
|
|
TOPLEVEL = 3 |
|
|
|
TOPLEVEL = 3 |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, parent): |
|
|
|
followServer = pyqtSignal([object], arguments=['server']) |
|
|
|
|
|
|
|
followChain = pyqtSignal([str], arguments=['chain_id']) |
|
|
|
|
|
|
|
setServer = pyqtSignal([str], arguments=['server']) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self): |
|
|
|
QTreeWidget.__init__(self) |
|
|
|
QTreeWidget.__init__(self) |
|
|
|
self.parent = parent # type: NetworkChoiceLayout |
|
|
|
|
|
|
|
self.setHeaderLabels([_('Server'), _('Height')]) |
|
|
|
self.setHeaderLabels([_('Server'), _('Height')]) |
|
|
|
self.setContextMenuPolicy(Qt.CustomContextMenu) |
|
|
|
self.setContextMenuPolicy(Qt.CustomContextMenu) |
|
|
|
self.customContextMenuRequested.connect(self.create_menu) |
|
|
|
self.customContextMenuRequested.connect(self.create_menu) |
|
|
|
@ -110,16 +113,19 @@ class NodesListWidget(QTreeWidget): |
|
|
|
menu = QMenu() |
|
|
|
menu = QMenu() |
|
|
|
if item_type == self.ItemType.CONNECTED_SERVER: |
|
|
|
if item_type == self.ItemType.CONNECTED_SERVER: |
|
|
|
server = item.data(0, self.SERVER_ADDR_ROLE) # type: ServerAddr |
|
|
|
server = item.data(0, self.SERVER_ADDR_ROLE) # type: ServerAddr |
|
|
|
menu.addAction(_("Use as server"), lambda: self.parent.follow_server(server)) |
|
|
|
def do_follow_server(): |
|
|
|
|
|
|
|
self.followServer.emit(server) |
|
|
|
|
|
|
|
menu.addAction(_("Use as server"), do_follow_server) |
|
|
|
elif item_type == self.ItemType.DISCONNECTED_SERVER: |
|
|
|
elif item_type == self.ItemType.DISCONNECTED_SERVER: |
|
|
|
server = item.data(0, self.SERVER_ADDR_ROLE) # type: ServerAddr |
|
|
|
server = item.data(0, self.SERVER_ADDR_ROLE) # type: ServerAddr |
|
|
|
def func(): |
|
|
|
def do_set_server(): |
|
|
|
self.parent.server_e.setText(str(server)) |
|
|
|
self.setServer.emit(str(server)) |
|
|
|
self.parent.set_server() |
|
|
|
menu.addAction(_("Use as server"), do_set_server) |
|
|
|
menu.addAction(_("Use as server"), func) |
|
|
|
|
|
|
|
elif item_type == self.ItemType.CHAIN: |
|
|
|
elif item_type == self.ItemType.CHAIN: |
|
|
|
chain_id = item.data(0, self.CHAIN_ID_ROLE) |
|
|
|
chain_id = item.data(0, self.CHAIN_ID_ROLE) |
|
|
|
menu.addAction(_("Follow this branch"), lambda: self.parent.follow_branch(chain_id)) |
|
|
|
def do_follow_chain(): |
|
|
|
|
|
|
|
self.followChain.emit(chain_id) |
|
|
|
|
|
|
|
menu.addAction(_("Follow this branch"), do_follow_chain) |
|
|
|
else: |
|
|
|
else: |
|
|
|
return |
|
|
|
return |
|
|
|
menu.exec_(self.viewport().mapToGlobal(position)) |
|
|
|
menu.exec_(self.viewport().mapToGlobal(position)) |
|
|
|
@ -136,9 +142,11 @@ class NodesListWidget(QTreeWidget): |
|
|
|
pt.setX(50) |
|
|
|
pt.setX(50) |
|
|
|
self.customContextMenuRequested.emit(pt) |
|
|
|
self.customContextMenuRequested.emit(pt) |
|
|
|
|
|
|
|
|
|
|
|
def update(self, *, network: Network, servers: dict, use_tor: bool): |
|
|
|
def update(self, *, network: Network, servers: dict): |
|
|
|
self.clear() |
|
|
|
self.clear() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use_tor = network.tor_proxy |
|
|
|
|
|
|
|
|
|
|
|
# connected servers |
|
|
|
# connected servers |
|
|
|
connected_servers_item = QTreeWidgetItem([_("Connected nodes"), '']) |
|
|
|
connected_servers_item = QTreeWidgetItem([_("Connected nodes"), '']) |
|
|
|
connected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL) |
|
|
|
connected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL) |
|
|
|
@ -146,7 +154,8 @@ class NodesListWidget(QTreeWidget): |
|
|
|
n_chains = len(chains) |
|
|
|
n_chains = len(chains) |
|
|
|
for chain_id, interfaces in chains.items(): |
|
|
|
for chain_id, interfaces in chains.items(): |
|
|
|
b = blockchain.blockchains.get(chain_id) |
|
|
|
b = blockchain.blockchains.get(chain_id) |
|
|
|
if b is None: continue |
|
|
|
if b is None: |
|
|
|
|
|
|
|
continue |
|
|
|
name = b.get_name() |
|
|
|
name = b.get_name() |
|
|
|
if n_chains > 1: |
|
|
|
if n_chains > 1: |
|
|
|
x = QTreeWidgetItem([name + '@%d'%b.get_max_forkpoint(), '%d'%b.height()]) |
|
|
|
x = QTreeWidgetItem([name + '@%d'%b.get_max_forkpoint(), '%d'%b.height()]) |
|
|
|
@ -201,7 +210,9 @@ class NodesListWidget(QTreeWidget): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NetworkChoiceLayout(object): |
|
|
|
class NetworkChoiceLayout(object): |
|
|
|
|
|
|
|
# TODO consolidate to ProxyWidget+ServerWidget |
|
|
|
|
|
|
|
# TODO TorDetector is unnecessary, Network tests socks5 peer and detects Tor |
|
|
|
|
|
|
|
# TODO apply on editingFinished is not ideal, separate Apply button and on Close? |
|
|
|
def __init__(self, network: Network, config: 'SimpleConfig', wizard=False): |
|
|
|
def __init__(self, network: Network, config: 'SimpleConfig', wizard=False): |
|
|
|
self.network = network |
|
|
|
self.network = network |
|
|
|
self.config = config |
|
|
|
self.config = config |
|
|
|
@ -304,7 +315,14 @@ class NetworkChoiceLayout(object): |
|
|
|
self.split_label = QLabel('') |
|
|
|
self.split_label = QLabel('') |
|
|
|
grid.addWidget(self.split_label, 4, 0, 1, 3) |
|
|
|
grid.addWidget(self.split_label, 4, 0, 1, 3) |
|
|
|
|
|
|
|
|
|
|
|
self.nodes_list_widget = NodesListWidget(self) |
|
|
|
self.nodes_list_widget = NodesListWidget() |
|
|
|
|
|
|
|
self.nodes_list_widget.followServer.connect(self.follow_server) |
|
|
|
|
|
|
|
self.nodes_list_widget.followChain.connect(self.follow_branch) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def do_set_server(server): |
|
|
|
|
|
|
|
self.server_e.setText(server) |
|
|
|
|
|
|
|
self.set_server() |
|
|
|
|
|
|
|
self.nodes_list_widget.setServer.connect(do_set_server) |
|
|
|
grid.addWidget(self.nodes_list_widget, 6, 0, 1, 5) |
|
|
|
grid.addWidget(self.nodes_list_widget, 6, 0, 1, 5) |
|
|
|
|
|
|
|
|
|
|
|
vbox = QVBoxLayout() |
|
|
|
vbox = QVBoxLayout() |
|
|
|
@ -361,8 +379,7 @@ class NetworkChoiceLayout(object): |
|
|
|
msg = '' |
|
|
|
msg = '' |
|
|
|
self.split_label.setText(msg) |
|
|
|
self.split_label.setText(msg) |
|
|
|
self.nodes_list_widget.update(network=self.network, |
|
|
|
self.nodes_list_widget.update(network=self.network, |
|
|
|
servers=self.network.get_servers(), |
|
|
|
servers=self.network.get_servers()) |
|
|
|
use_tor=self.tor_cb.isChecked()) |
|
|
|
|
|
|
|
self.enable_set_server() |
|
|
|
self.enable_set_server() |
|
|
|
|
|
|
|
|
|
|
|
def fill_in_proxy_settings(self): |
|
|
|
def fill_in_proxy_settings(self): |
|
|
|
@ -499,13 +516,11 @@ class ProxyWidget(QWidget): |
|
|
|
grid = QGridLayout(self) |
|
|
|
grid = QGridLayout(self) |
|
|
|
grid.setSpacing(8) |
|
|
|
grid.setSpacing(8) |
|
|
|
|
|
|
|
|
|
|
|
# proxy setting |
|
|
|
# proxy setting. |
|
|
|
self.proxy_cb = QCheckBox(_('Use proxy')) |
|
|
|
self.proxy_cb = QCheckBox(_('Use proxy')) |
|
|
|
# self.proxy_cb.clicked.connect(self.check_disable_proxy) |
|
|
|
|
|
|
|
# self.proxy_cb.clicked.connect(self.set_proxy) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.proxy_mode = QComboBox() |
|
|
|
self.proxy_mode = QComboBox() |
|
|
|
self.proxy_mode.addItems(['SOCKS4', 'SOCKS5']) |
|
|
|
self.proxy_mode.addItems(['SOCKS4', 'SOCKS5']) |
|
|
|
|
|
|
|
self.proxy_mode.setCurrentIndex(1) |
|
|
|
self.proxy_host = QLineEdit() |
|
|
|
self.proxy_host = QLineEdit() |
|
|
|
self.proxy_host.setFixedWidth(fixed_width_hostname) |
|
|
|
self.proxy_host.setFixedWidth(fixed_width_hostname) |
|
|
|
self.proxy_port = QLineEdit() |
|
|
|
self.proxy_port = QLineEdit() |
|
|
|
@ -516,43 +531,37 @@ class ProxyWidget(QWidget): |
|
|
|
self.proxy_password.setPlaceholderText(_("Password")) |
|
|
|
self.proxy_password.setPlaceholderText(_("Password")) |
|
|
|
self.proxy_password.setFixedWidth(fixed_width_port) |
|
|
|
self.proxy_password.setFixedWidth(fixed_width_port) |
|
|
|
|
|
|
|
|
|
|
|
# self.proxy_mode.currentIndexChanged.connect(self.set_proxy) |
|
|
|
grid.addWidget(self.proxy_cb, 0, 0, 1, 3) |
|
|
|
# self.proxy_host.editingFinished.connect(self.set_proxy) |
|
|
|
grid.addWidget(HelpButton(_('Proxy settings apply to all connections: with Electrum servers, but also with third-party services.')), 0, 4) |
|
|
|
# self.proxy_port.editingFinished.connect(self.set_proxy) |
|
|
|
grid.addWidget(self.proxy_mode, 1, 1) |
|
|
|
# self.proxy_user.editingFinished.connect(self.set_proxy) |
|
|
|
grid.addWidget(self.proxy_host, 1, 2) |
|
|
|
# self.proxy_password.editingFinished.connect(self.set_proxy) |
|
|
|
grid.addWidget(self.proxy_port, 1, 3) |
|
|
|
|
|
|
|
grid.addWidget(self.proxy_user, 2, 2) |
|
|
|
# self.proxy_mode.currentIndexChanged.connect(self.proxy_settings_changed) |
|
|
|
grid.addWidget(self.proxy_password, 2, 3) |
|
|
|
# self.proxy_host.textEdited.connect(self.proxy_settings_changed) |
|
|
|
|
|
|
|
# self.proxy_port.textEdited.connect(self.proxy_settings_changed) |
|
|
|
def get_proxy_settings(self): |
|
|
|
# self.proxy_user.textEdited.connect(self.proxy_settings_changed) |
|
|
|
return { |
|
|
|
# self.proxy_password.textEdited.connect(self.proxy_settings_changed) |
|
|
|
'enabled': self.proxy_cb.isChecked(), |
|
|
|
|
|
|
|
'mode': ['socks4', 'socks5'][self.proxy_mode.currentIndex()], |
|
|
|
self.tor_cb = QCheckBox(_("Use Tor Proxy")) |
|
|
|
'host': self.proxy_host.text(), |
|
|
|
self.tor_cb.setIcon(read_QIcon("tor_logo.png")) |
|
|
|
'port': self.proxy_port.text(), |
|
|
|
self.tor_cb.hide() |
|
|
|
'user': self.proxy_user.text(), |
|
|
|
# self.tor_cb.clicked.connect(self.use_tor_proxy) |
|
|
|
'password': self.proxy_password.text() |
|
|
|
|
|
|
|
} |
|
|
|
grid.addWidget(self.tor_cb, 1, 0, 1, 3) |
|
|
|
|
|
|
|
grid.addWidget(self.proxy_cb, 2, 0, 1, 3) |
|
|
|
|
|
|
|
grid.addWidget(HelpButton(_('Proxy settings apply to all connections: with Electrum servers, but also with third-party services.')), 2, 4) |
|
|
|
class ServerWidget(QWidget, QtEventListener): |
|
|
|
grid.addWidget(self.proxy_mode, 4, 1) |
|
|
|
def __init__(self, network, parent=None): |
|
|
|
grid.addWidget(self.proxy_host, 4, 2) |
|
|
|
|
|
|
|
grid.addWidget(self.proxy_port, 4, 3) |
|
|
|
|
|
|
|
grid.addWidget(self.proxy_user, 5, 2) |
|
|
|
|
|
|
|
grid.addWidget(self.proxy_password, 5, 3) |
|
|
|
|
|
|
|
grid.setRowStretch(7, 1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ServerWidget(QWidget): |
|
|
|
|
|
|
|
def __init__(self, parent=None): |
|
|
|
|
|
|
|
super().__init__(parent) |
|
|
|
super().__init__(parent) |
|
|
|
|
|
|
|
self.network = network |
|
|
|
|
|
|
|
self.config = network.config |
|
|
|
|
|
|
|
|
|
|
|
fixed_width_hostname = 24 * char_width_in_lineedit() |
|
|
|
fixed_width_hostname = 24 * char_width_in_lineedit() |
|
|
|
fixed_width_port = 6 * char_width_in_lineedit() |
|
|
|
fixed_width_port = 6 * char_width_in_lineedit() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.setLayout(QVBoxLayout()) |
|
|
|
|
|
|
|
|
|
|
|
grid = QGridLayout(self) |
|
|
|
grid = QGridLayout(self) |
|
|
|
# self.setLayout(grid) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg = ' '.join([ |
|
|
|
msg = ' '.join([ |
|
|
|
_("Electrum connects to several nodes in order to download block headers and find out the longest blockchain."), |
|
|
|
_("Electrum connects to several nodes in order to download block headers and find out the longest blockchain."), |
|
|
|
@ -564,9 +573,7 @@ class ServerWidget(QWidget): |
|
|
|
grid.addWidget(HelpButton(msg), 0, 4) |
|
|
|
grid.addWidget(HelpButton(msg), 0, 4) |
|
|
|
|
|
|
|
|
|
|
|
self.autoconnect_cb = QCheckBox(_('Select server automatically')) |
|
|
|
self.autoconnect_cb = QCheckBox(_('Select server automatically')) |
|
|
|
# self.autoconnect_cb.setEnabled(self.config.cv.NETWORK_AUTO_CONNECT.is_modifiable()) |
|
|
|
self.autoconnect_cb.setEnabled(self.config.cv.NETWORK_AUTO_CONNECT.is_modifiable()) |
|
|
|
# self.autoconnect_cb.clicked.connect(self.set_server) |
|
|
|
|
|
|
|
# self.autoconnect_cb.clicked.connect(self.update) |
|
|
|
|
|
|
|
msg = ' '.join([ |
|
|
|
msg = ' '.join([ |
|
|
|
_("If auto-connect is enabled, Electrum will always use a server that is on the longest blockchain."), |
|
|
|
_("If auto-connect is enabled, Electrum will always use a server that is on the longest blockchain."), |
|
|
|
_("If it is disabled, you have to choose a server you want to use. Electrum will warn you if your server is lagging.") |
|
|
|
_("If it is disabled, you have to choose a server you want to use. Electrum will warn you if your server is lagging.") |
|
|
|
@ -576,7 +583,6 @@ class ServerWidget(QWidget): |
|
|
|
|
|
|
|
|
|
|
|
self.server_e = QLineEdit() |
|
|
|
self.server_e = QLineEdit() |
|
|
|
self.server_e.setFixedWidth(fixed_width_hostname + fixed_width_port) |
|
|
|
self.server_e.setFixedWidth(fixed_width_hostname + fixed_width_port) |
|
|
|
# self.server_e.editingFinished.connect(self.set_server) |
|
|
|
|
|
|
|
msg = _("Electrum sends your wallet addresses to a single server, in order to receive your transaction history.") |
|
|
|
msg = _("Electrum sends your wallet addresses to a single server, in order to receive your transaction history.") |
|
|
|
grid.addWidget(QLabel(_('Server') + ':'), 2, 0) |
|
|
|
grid.addWidget(QLabel(_('Server') + ':'), 2, 0) |
|
|
|
grid.addWidget(self.server_e, 2, 1, 1, 3) |
|
|
|
grid.addWidget(self.server_e, 2, 1, 1, 3) |
|
|
|
@ -591,16 +597,46 @@ class ServerWidget(QWidget): |
|
|
|
self.split_label = QLabel('') |
|
|
|
self.split_label = QLabel('') |
|
|
|
grid.addWidget(self.split_label, 4, 0, 1, 3) |
|
|
|
grid.addWidget(self.split_label, 4, 0, 1, 3) |
|
|
|
|
|
|
|
|
|
|
|
self.nodes_list_widget = NodesListWidget(self) |
|
|
|
self.layout().addLayout(grid) |
|
|
|
grid.addWidget(self.nodes_list_widget, 6, 0, 1, 5) |
|
|
|
|
|
|
|
|
|
|
|
self.nodes_list_widget = NodesListWidget() |
|
|
|
|
|
|
|
self.nodes_list_widget.followServer.connect(self.follow_server) |
|
|
|
|
|
|
|
self.nodes_list_widget.followChain.connect(self.follow_branch) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def do_set_server(server): |
|
|
|
|
|
|
|
self.server_e.setText(server) |
|
|
|
|
|
|
|
self.set_server() |
|
|
|
|
|
|
|
self.nodes_list_widget.setServer.connect(do_set_server) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.layout().addWidget(self.nodes_list_widget) |
|
|
|
|
|
|
|
self.nodes_list_widget.update(network=self.network, |
|
|
|
|
|
|
|
servers=self.network.get_servers()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.register_callbacks() |
|
|
|
|
|
|
|
self.destroyed.connect(lambda: self.unregister_callbacks()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@qt_event_listener |
|
|
|
|
|
|
|
def on_event_network_updated(self): |
|
|
|
|
|
|
|
self.nodes_list_widget.update(network=self.network, servers=self.network.get_servers()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def follow_branch(self, chain_id): |
|
|
|
|
|
|
|
self.network.run_from_another_thread(self.network.follow_chain_given_id(chain_id)) |
|
|
|
|
|
|
|
self.update() |
|
|
|
|
|
|
|
|
|
|
|
# vbox = QVBoxLayout() |
|
|
|
def follow_server(self, server: ServerAddr): |
|
|
|
# vbox.addWidget(tabs) |
|
|
|
self.server_e.setText(str(server)) |
|
|
|
# self.layout_ = vbox |
|
|
|
self.network.run_from_another_thread(self.network.follow_chain_given_server(server)) |
|
|
|
# # tor detector |
|
|
|
self.update() |
|
|
|
# self.td = td = TorDetector() |
|
|
|
|
|
|
|
# td.found_proxy.connect(self.suggest_proxy) |
|
|
|
|
|
|
|
# td.start() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# self.fill_in_proxy_settings() |
|
|
|
def set_server(self): |
|
|
|
# self.update() |
|
|
|
net_params = self.network.get_parameters() |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
server = ServerAddr.from_str_with_inference(str(self.server_e.text())) |
|
|
|
|
|
|
|
if not server: |
|
|
|
|
|
|
|
raise Exception("failed to parse server") |
|
|
|
|
|
|
|
except Exception: |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
net_params = net_params._replace(server=server, |
|
|
|
|
|
|
|
auto_connect=self.autoconnect_cb.isChecked()) |
|
|
|
|
|
|
|
self.network.run_from_another_thread(self.network.set_parameters(net_params)) |
|
|
|
|