qml: add serverlistmodel.py, add server list to ServerConfigDialog.qml
This commit is contained in:
@@ -154,6 +154,7 @@ Pane {
|
||||
text: qsTr('disabled');
|
||||
visible: !Config.useGossip
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,14 +30,44 @@ ElDialog {
|
||||
height: parent.height
|
||||
spacing: 0
|
||||
|
||||
ServerConfig {
|
||||
id: serverconfig
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: constants.paddingLarge
|
||||
Layout.rightMargin: constants.paddingLarge
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true; Layout.preferredWidth: 1 }
|
||||
ServerConfig {
|
||||
id: serverconfig
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('Servers')
|
||||
font.pixelSize: constants.fontSizeLarge
|
||||
color: Material.accentColor
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: Material.accentColor
|
||||
}
|
||||
|
||||
Frame {
|
||||
background: PaneInsetBackground { baseColor: Material.dialogColor }
|
||||
|
||||
verticalPadding: 0
|
||||
horizontalPadding: 0
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
model: Network.serverListModel
|
||||
delegate: ServerDelegate { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlatButton {
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -2,25 +2,26 @@ import QtQuick 2.6
|
||||
import QtQuick.Controls.Material 2.0
|
||||
|
||||
Rectangle {
|
||||
property color baseColor: Material.background
|
||||
Rectangle {
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
height: 1
|
||||
color: Qt.darker(Material.background, 1.50)
|
||||
color: Qt.darker(baseColor, 1.50)
|
||||
}
|
||||
Rectangle {
|
||||
anchors { left: parent.left; top: parent.top; bottom: parent.bottom }
|
||||
width: 1
|
||||
color: Qt.darker(Material.background, 1.50)
|
||||
color: Qt.darker(baseColor, 1.50)
|
||||
}
|
||||
Rectangle {
|
||||
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||
height: 1
|
||||
color: Qt.lighter(Material.background, 1.50)
|
||||
color: Qt.lighter(baseColor, 1.50)
|
||||
}
|
||||
Rectangle {
|
||||
anchors { right: parent.right; top: parent.top; bottom: parent.bottom }
|
||||
width: 1
|
||||
color: Qt.lighter(Material.background, 1.50)
|
||||
color: Qt.lighter(baseColor, 1.50)
|
||||
}
|
||||
color: Qt.darker(Material.background, 1.15)
|
||||
color: Qt.darker(baseColor, 1.15)
|
||||
}
|
||||
|
||||
29
electrum/gui/qml/components/controls/ServerDelegate.qml
Normal file
29
electrum/gui/qml/components/controls/ServerDelegate.qml
Normal file
@@ -0,0 +1,29 @@
|
||||
import QtQuick 2.6
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Controls.Material 2.0
|
||||
|
||||
import org.electrum 1.0
|
||||
|
||||
ItemDelegate {
|
||||
id: root
|
||||
height: itemLayout.height
|
||||
width: ListView.view.width
|
||||
|
||||
GridLayout {
|
||||
id: itemLayout
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: constants.paddingSmall
|
||||
rightMargin: constants.paddingSmall
|
||||
}
|
||||
columns: 2
|
||||
Label {
|
||||
text: model.address
|
||||
}
|
||||
Label {
|
||||
text: model.chain
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,14 @@ from electrum import constants
|
||||
from electrum.interface import ServerAddr
|
||||
|
||||
from .util import QtEventListener, event_listener
|
||||
from .qeserverlistmodel import QEServerListModel
|
||||
|
||||
class QENetwork(QObject, QtEventListener):
|
||||
def __init__(self, network, qeconfig, parent=None):
|
||||
super().__init__(parent)
|
||||
self.network = network
|
||||
self._qeconfig = qeconfig
|
||||
self._serverListModel = None
|
||||
self._height = network.get_local_height() # init here, update event can take a while
|
||||
self.register_callbacks()
|
||||
|
||||
@@ -186,3 +188,10 @@ class QENetwork(QObject, QtEventListener):
|
||||
'db_channels': self._gossipDbChannels ,
|
||||
'db_policies': self._gossipDbPolicies
|
||||
}
|
||||
|
||||
serverListModelChanged = pyqtSignal()
|
||||
@pyqtProperty(QEServerListModel, notify=serverListModelChanged)
|
||||
def serverListModel(self):
|
||||
if self._serverListModel is None:
|
||||
self._serverListModel = QEServerListModel(self.network)
|
||||
return self._serverListModel
|
||||
|
||||
133
electrum/gui/qml/qeserverlistmodel.py
Normal file
133
electrum/gui/qml/qeserverlistmodel.py
Normal file
@@ -0,0 +1,133 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.logging import get_logger
|
||||
from electrum.util import Satoshis, format_time
|
||||
from electrum.interface import ServerAddr, PREFERRED_NETWORK_PROTOCOL
|
||||
from electrum import blockchain
|
||||
|
||||
from .util import QtEventListener, qt_event_listener, event_listener
|
||||
|
||||
class QEServerListModel(QAbstractListModel, QtEventListener):
|
||||
_logger = get_logger(__name__)
|
||||
_chaintips = 0
|
||||
|
||||
# define listmodel rolemap
|
||||
_ROLE_NAMES=('name', 'address', 'is_connected', 'is_primary', 'is_tor', 'chain', 'height')
|
||||
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
|
||||
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
|
||||
_ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
|
||||
|
||||
def __init__(self, network, parent=None):
|
||||
super().__init__(parent)
|
||||
self.network = network
|
||||
self.init_model()
|
||||
self.register_callbacks()
|
||||
self.destroyed.connect(lambda: self.unregister_callbacks())
|
||||
|
||||
@event_listener
|
||||
def on_event_network_updated(self):
|
||||
self._logger.info(f'network updated')
|
||||
self.init_model()
|
||||
|
||||
@event_listener
|
||||
def on_event_blockchain_updated(self):
|
||||
self._logger.info(f'blockchain updated')
|
||||
self.init_model()
|
||||
|
||||
@event_listener
|
||||
def on_event_default_server_changed(self):
|
||||
self._logger.info(f'default server changed')
|
||||
self.init_model()
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self.servers)
|
||||
|
||||
def roleNames(self):
|
||||
return self._ROLE_MAP
|
||||
|
||||
def data(self, index, role):
|
||||
server = self.servers[index.row()]
|
||||
role_index = role - Qt.UserRole
|
||||
value = server[self._ROLE_NAMES[role_index]]
|
||||
|
||||
if isinstance(value, (bool, list, int, str)) or value is None:
|
||||
return value
|
||||
if isinstance(value, Satoshis):
|
||||
return value.value
|
||||
return str(value)
|
||||
|
||||
def clear(self):
|
||||
self.beginResetModel()
|
||||
self.servers = []
|
||||
self.endResetModel()
|
||||
|
||||
chaintipsChanged = pyqtSignal()
|
||||
@pyqtProperty(int, notify=chaintipsChanged)
|
||||
def chaintips(self):
|
||||
return self._chaintips
|
||||
|
||||
def get_chains(self):
|
||||
chains = self.network.get_blockchains()
|
||||
n_chains = len(chains)
|
||||
if n_chains != self._chaintips:
|
||||
self._chaintips = n_chains
|
||||
self.chaintipsChanged.emit()
|
||||
return chains
|
||||
|
||||
@pyqtSlot()
|
||||
def init_model(self):
|
||||
self.clear()
|
||||
|
||||
chains = self.get_chains()
|
||||
|
||||
for chain_id, interfaces in chains.items():
|
||||
self._logger.debug(f'chain {chain_id} has {len(interfaces)} interfaces')
|
||||
b = blockchain.blockchains.get(chain_id)
|
||||
if b is None:
|
||||
continue
|
||||
|
||||
name = b.get_name()
|
||||
|
||||
self._logger.debug(f'chain {chain_id} has name={name}, max_forkpoint=@{b.get_max_forkpoint()}, height={b.height()}')
|
||||
|
||||
for i in interfaces:
|
||||
server = {}
|
||||
server['chain'] = name
|
||||
server['chain_height'] = b.height()
|
||||
server['is_primary'] = i == self.network.interface
|
||||
server['is_connected'] = True
|
||||
server['name'] = str(i.server)
|
||||
server['address'] = i.server.to_friendly_name()
|
||||
server['height'] = i.tip
|
||||
|
||||
self._logger.debug(f'adding server: {repr(server)}')
|
||||
self.servers.append(server)
|
||||
|
||||
# disconnected servers
|
||||
all_servers = self.network.get_servers()
|
||||
connected_hosts = set([iface.host for ifaces in chains.values() for iface in ifaces])
|
||||
protocol = PREFERRED_NETWORK_PROTOCOL
|
||||
use_tor = True
|
||||
for _host, d in sorted(all_servers.items()):
|
||||
if _host in connected_hosts:
|
||||
continue
|
||||
if _host.endswith('.onion') and not use_tor:
|
||||
continue
|
||||
port = d.get(protocol)
|
||||
if port:
|
||||
s = ServerAddr(_host, port, protocol=protocol)
|
||||
server = {}
|
||||
server['chain'] = ''
|
||||
server['chain_height'] = 0
|
||||
server['height'] = 0
|
||||
server['is_primary'] = False
|
||||
server['is_connected'] = False
|
||||
server['name'] = s.net_addr_str()
|
||||
server['address'] = server['name']
|
||||
|
||||
self.servers.append(server)
|
||||
|
||||
Reference in New Issue
Block a user