commit 853f42dbbb8a7fb9506e11740c039c5b78b921b2
parent bf223470ce607a762700f144a6a0f4cb0205cf54
Author: ThomasV <thomasv@electrum.org>
Date: Sat, 25 Apr 2020 10:33:55 +0200
Merge pull request #6114 from SomberNight/202004_qt_network_dialog
qt network dialog: merge "Overview" and "Servers" tabs
Diffstat:
1 file changed, 79 insertions(+), 121 deletions(-)
diff --git a/electrum/gui/qt/network_dialog.py b/electrum/gui/qt/network_dialog.py
@@ -56,7 +56,7 @@ class NetworkDialog(QDialog):
def __init__(self, network, config, network_updated_signal_obj):
QDialog.__init__(self)
self.setWindowTitle(_('Network'))
- self.setMinimumSize(500, 300)
+ self.setMinimumSize(500, 500)
self.nlayout = NetworkChoiceLayout(network, config)
self.network_updated_signal_obj = network_updated_signal_obj
vbox = QVBoxLayout(self)
@@ -79,12 +79,18 @@ class NodesListWidget(QTreeWidget):
SERVER_ADDR_ROLE = Qt.UserRole + 100
CHAIN_ID_ROLE = Qt.UserRole + 101
- IS_SERVER_ROLE = Qt.UserRole + 102
+ ITEMTYPE_ROLE = Qt.UserRole + 102
+
+ class ItemType(IntEnum):
+ CHAIN = 0
+ CONNECTED_SERVER = 1
+ DISCONNECTED_SERVER = 2
+ TOPLEVEL = 3
def __init__(self, parent):
QTreeWidget.__init__(self)
self.parent = parent # type: NetworkChoiceLayout
- self.setHeaderLabels([_('Connected node'), _('Height')])
+ self.setHeaderLabels([_('Server'), _('Height')])
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.create_menu)
@@ -92,14 +98,22 @@ class NodesListWidget(QTreeWidget):
item = self.currentItem()
if not item:
return
- is_server = bool(item.data(0, self.IS_SERVER_ROLE))
+ item_type = item.data(0, self.ITEMTYPE_ROLE)
menu = QMenu()
- if is_server:
+ if item_type == self.ItemType.CONNECTED_SERVER:
server = item.data(0, self.SERVER_ADDR_ROLE) # type: ServerAddr
menu.addAction(_("Use as server"), lambda: self.parent.follow_server(server))
- else:
+ elif item_type == self.ItemType.DISCONNECTED_SERVER:
+ server = item.data(0, self.SERVER_ADDR_ROLE) # type: ServerAddr
+ def func():
+ self.parent.server_e.setText(server.net_addr_str())
+ self.parent.set_server()
+ menu.addAction(_("Use as server"), func)
+ elif item_type == self.ItemType.CHAIN:
chain_id = item.data(0, self.CHAIN_ID_ROLE)
menu.addAction(_("Follow this branch"), lambda: self.parent.follow_branch(chain_id))
+ else:
+ return
menu.exec_(self.viewport().mapToGlobal(position))
def keyPressEvent(self, event):
@@ -114,9 +128,12 @@ class NodesListWidget(QTreeWidget):
pt.setX(50)
self.customContextMenuRequested.emit(pt)
- def update(self, network: Network):
+ def update(self, *, network: Network, servers: dict, use_tor: bool):
self.clear()
- self.addChild = self.addTopLevelItem
+
+ # connected servers
+ connected_servers_item = QTreeWidgetItem([_("Connected nodes"), ''])
+ connected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL)
chains = network.get_blockchains()
n_chains = len(chains)
for chain_id, interfaces in chains.items():
@@ -125,87 +142,51 @@ class NodesListWidget(QTreeWidget):
name = b.get_name()
if n_chains > 1:
x = QTreeWidgetItem([name + '@%d'%b.get_max_forkpoint(), '%d'%b.height()])
- x.setData(0, self.IS_SERVER_ROLE, 0)
+ x.setData(0, self.ITEMTYPE_ROLE, self.ItemType.CHAIN)
x.setData(0, self.CHAIN_ID_ROLE, b.get_id())
else:
- x = self
+ x = connected_servers_item
for i in interfaces:
star = ' *' if i == network.interface else ''
- item = QTreeWidgetItem([i.host + star, '%d'%i.tip])
- item.setData(0, self.IS_SERVER_ROLE, 1)
+ item = QTreeWidgetItem([f"{i.server.net_addr_str()}" + star, '%d'%i.tip])
+ item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.CONNECTED_SERVER)
item.setData(0, self.SERVER_ADDR_ROLE, i.server)
item.setToolTip(0, str(i.server))
x.addChild(item)
if n_chains > 1:
- self.addTopLevelItem(x)
- x.setExpanded(True)
+ connected_servers_item.addChild(x)
- h = self.header()
- h.setStretchLastSection(False)
- h.setSectionResizeMode(0, QHeaderView.Stretch)
- h.setSectionResizeMode(1, QHeaderView.ResizeToContents)
-
- super().update()
-
-
-class ServerListWidget(QTreeWidget):
- """List of all known servers."""
-
- class Columns(IntEnum):
- HOST = 0
- PORT = 1
-
- SERVER_ADDR_ROLE = Qt.UserRole + 100
-
- def __init__(self, parent):
- QTreeWidget.__init__(self)
- self.parent = parent # type: NetworkChoiceLayout
- self.setHeaderLabels([_('Host'), _('Port')])
- self.setContextMenuPolicy(Qt.CustomContextMenu)
- self.customContextMenuRequested.connect(self.create_menu)
-
- def create_menu(self, position):
- item = self.currentItem()
- if not item:
- return
- menu = QMenu()
- server = item.data(self.Columns.HOST, self.SERVER_ADDR_ROLE)
- menu.addAction(_("Use as server"), lambda: self.set_server(server))
- menu.exec_(self.viewport().mapToGlobal(position))
-
- def set_server(self, server: ServerAddr):
- self.parent.server_e.setText(server.net_addr_str())
- self.parent.set_server()
-
- def keyPressEvent(self, event):
- if event.key() in [ Qt.Key_F2, Qt.Key_Return ]:
- self.on_activated(self.currentItem(), self.currentColumn())
- else:
- QTreeWidget.keyPressEvent(self, event)
-
- def on_activated(self, item, column):
- # on 'enter' we show the menu
- pt = self.visualItemRect(item).bottomLeft()
- pt.setX(50)
- self.customContextMenuRequested.emit(pt)
-
- def update(self, servers, use_tor):
- self.clear()
+ # disconnected servers
+ disconnected_servers_item = QTreeWidgetItem([_("Other known servers"), ""])
+ disconnected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL)
+ connected_hosts = set([iface.host for ifaces in chains.values() for iface in ifaces])
protocol = PREFERRED_NETWORK_PROTOCOL
for _host, d in sorted(servers.items()):
+ if _host in connected_hosts:
+ continue
if _host.endswith('.onion') and not use_tor:
continue
port = d.get(protocol)
if port:
- x = QTreeWidgetItem([_host, port])
server = ServerAddr(_host, port, protocol=protocol)
- x.setData(self.Columns.HOST, self.SERVER_ADDR_ROLE, server)
- self.addTopLevelItem(x)
+ item = QTreeWidgetItem([server.net_addr_str(), ""])
+ item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.DISCONNECTED_SERVER)
+ item.setData(0, self.SERVER_ADDR_ROLE, server)
+ disconnected_servers_item.addChild(item)
+
+ self.addTopLevelItem(connected_servers_item)
+ self.addTopLevelItem(disconnected_servers_item)
+
+ connected_servers_item.setExpanded(True)
+ for i in range(connected_servers_item.childCount()):
+ connected_servers_item.child(i).setExpanded(True)
+ disconnected_servers_item.setExpanded(True)
+ # headers
h = self.header()
h.setStretchLastSection(False)
- h.setSectionResizeMode(self.Columns.HOST, QHeaderView.Stretch)
- h.setSectionResizeMode(self.Columns.PORT, QHeaderView.ResizeToContents)
+ h.setSectionResizeMode(0, QHeaderView.Stretch)
+ h.setSectionResizeMode(1, QHeaderView.ResizeToContents)
super().update()
@@ -218,44 +199,14 @@ class NetworkChoiceLayout(object):
self.tor_proxy = None
self.tabs = tabs = QTabWidget()
- server_tab = QWidget()
proxy_tab = QWidget()
blockchain_tab = QWidget()
tabs.addTab(blockchain_tab, _('Overview'))
- tabs.addTab(server_tab, _('Server'))
tabs.addTab(proxy_tab, _('Proxy'))
fixed_width_hostname = 24 * char_width_in_lineedit()
fixed_width_port = 6 * char_width_in_lineedit()
- # server tab
- grid = QGridLayout(server_tab)
- grid.setSpacing(8)
-
- self.server_e = QLineEdit()
- self.server_e.setFixedWidth(fixed_width_hostname + fixed_width_port)
- self.autoconnect_cb = QCheckBox(_('Select server automatically'))
- self.autoconnect_cb.setEnabled(self.config.is_modifiable('auto_connect'))
-
- self.server_e.editingFinished.connect(self.set_server)
- self.autoconnect_cb.clicked.connect(self.set_server)
- self.autoconnect_cb.clicked.connect(self.update)
-
- msg = ' '.join([
- _("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.")
- ])
- grid.addWidget(self.autoconnect_cb, 0, 0, 1, 3)
- grid.addWidget(HelpButton(msg), 0, 4)
-
- grid.addWidget(QLabel(_('Server') + ':'), 1, 0)
- grid.addWidget(self.server_e, 1, 1, 1, 3)
-
- label = _('Server peers') if network.is_connected() else _('Default Servers')
- grid.addWidget(QLabel(label), 2, 0, 1, 5)
- self.servers_list = ServerListWidget(self)
- grid.addWidget(self.servers_list, 3, 0, 1, 5)
-
# Proxy tab
grid = QGridLayout(proxy_tab)
grid.setSpacing(8)
@@ -315,23 +266,36 @@ class NetworkChoiceLayout(object):
grid.addWidget(self.status_label, 0, 1, 1, 3)
grid.addWidget(HelpButton(msg), 0, 4)
- self.server_label = QLabel('')
- msg = _("Electrum sends your wallet addresses to a single server, in order to receive your transaction history.")
- grid.addWidget(QLabel(_('Server') + ':'), 1, 0)
- grid.addWidget(self.server_label, 1, 1, 1, 3)
+ self.autoconnect_cb = QCheckBox(_('Select server automatically'))
+ self.autoconnect_cb.setEnabled(self.config.is_modifiable('auto_connect'))
+ self.autoconnect_cb.clicked.connect(self.set_server)
+ self.autoconnect_cb.clicked.connect(self.update)
+ msg = ' '.join([
+ _("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.")
+ ])
+ grid.addWidget(self.autoconnect_cb, 1, 0, 1, 3)
grid.addWidget(HelpButton(msg), 1, 4)
+ self.server_e = QLineEdit()
+ 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.")
+ grid.addWidget(QLabel(_('Server') + ':'), 2, 0)
+ grid.addWidget(self.server_e, 2, 1, 1, 3)
+ grid.addWidget(HelpButton(msg), 2, 4)
+
self.height_label = QLabel('')
msg = _('This is the height of your local copy of the blockchain.')
- grid.addWidget(QLabel(_('Blockchain') + ':'), 2, 0)
- grid.addWidget(self.height_label, 2, 1)
- grid.addWidget(HelpButton(msg), 2, 4)
+ grid.addWidget(QLabel(_('Blockchain') + ':'), 3, 0)
+ grid.addWidget(self.height_label, 3, 1)
+ grid.addWidget(HelpButton(msg), 3, 4)
self.split_label = QLabel('')
- grid.addWidget(self.split_label, 3, 0, 1, 3)
+ grid.addWidget(self.split_label, 4, 0, 1, 3)
self.nodes_list_widget = NodesListWidget(self)
- grid.addWidget(self.nodes_list_widget, 5, 0, 1, 5)
+ grid.addWidget(self.nodes_list_widget, 6, 0, 1, 5)
vbox = QVBoxLayout()
vbox.addWidget(tabs)
@@ -354,27 +318,18 @@ class NetworkChoiceLayout(object):
if self.config.is_modifiable('server'):
enabled = not self.autoconnect_cb.isChecked()
self.server_e.setEnabled(enabled)
- self.servers_list.setEnabled(enabled)
else:
- for w in [self.autoconnect_cb, self.server_e, self.servers_list]:
+ for w in [self.autoconnect_cb, self.server_e, self.nodes_list_widget]:
w.setEnabled(False)
def update(self):
net_params = self.network.get_parameters()
server = net_params.server
- proxy_config, auto_connect = net_params.proxy, net_params.auto_connect
+ auto_connect = net_params.auto_connect
if not self.server_e.hasFocus():
self.server_e.setText(server.net_addr_str())
self.autoconnect_cb.setChecked(auto_connect)
- interface = self.network.interface
- host = interface.host if interface else _('None')
- self.server_label.setText(host)
-
- self.servers = self.network.get_servers()
- self.servers_list.update(self.servers, self.tor_cb.isChecked())
- self.enable_set_server()
-
height_str = "%d "%(self.network.get_local_height()) + _('blocks')
self.height_label.setText(height_str)
n = len(self.network.get_interfaces())
@@ -391,7 +346,10 @@ class NetworkChoiceLayout(object):
else:
msg = ''
self.split_label.setText(msg)
- self.nodes_list_widget.update(self.network)
+ self.nodes_list_widget.update(network=self.network,
+ servers=self.network.get_servers(),
+ use_tor=self.tor_cb.isChecked())
+ self.enable_set_server()
def fill_in_proxy_settings(self):
proxy_config = self.network.get_parameters().proxy