commit f5c58c5e19fdc7098197f33cb3cf3e7d86080f1c
parent db60634774edb1fe7f44ed909ad6c511d944c121
Author: ThomasV <thomasv@electrum.org>
Date: Tue, 7 May 2019 09:10:23 +0200
lightning network dialog
Diffstat:
5 files changed, 159 insertions(+), 157 deletions(-)
diff --git a/electrum/gui/qt/__init__.py b/electrum/gui/qt/__init__.py
@@ -55,6 +55,7 @@ from .util import get_default_language, read_QIcon, ColorScheme, custom_message_
from .main_window import ElectrumWindow
from .network_dialog import NetworkDialog
from .stylesheet_patcher import patch_qt_stylesheet
+from .lightning_dialog import LightningDialog
class OpenFileEventFilter(QObject):
@@ -107,8 +108,8 @@ class ElectrumGui(Logger):
self.timer.setSingleShot(False)
self.timer.setInterval(500) # msec
- self.nd = None
- self.watchtower_window = None
+ self.network_dialog = None
+ self.lightning_dialog = None
self.network_updated_signal_obj = QNetworkUpdatedSignalObject()
self._num_wizards_in_progress = 0
self._num_wizards_lock = threading.Lock()
@@ -148,7 +149,7 @@ class ElectrumGui(Logger):
m = self.tray.contextMenu()
m.clear()
if self.config.get('lightning'):
- m.addAction(_("Watchtower"), self.show_watchtower_dialog)
+ m.addAction(_("Lightning"), self.show_lightning_dialog)
for window in self.windows:
name = window.wallet.basename()
submenu = m.addMenu(name)
@@ -181,33 +182,32 @@ class ElectrumGui(Logger):
def close(self):
for window in self.windows:
window.close()
- if self.nd:
- self.nd.close()
- if self.watchtower_window:
- self.watchtower_window.close()
+ if self.network_dialog:
+ self.network_dialog.close()
+ if self.lightning_dialog:
+ self.lightning_dialog.close()
def new_window(self, path, uri=None):
# Use a signal as can be called from daemon thread
self.app.new_window_signal.emit(path, uri)
- def show_watchtower_dialog(self, parent=None):
- from .watchtower_window import WatchTowerWindow
- if not self.watchtower_window:
- self.watchtower_window = WatchTowerWindow(self)
- self.watchtower_window.bring_to_top()
+ def show_lightning_dialog(self):
+ if not self.lightning_dialog:
+ self.lightning_dialog = LightningDialog(self)
+ self.lightning_dialog.bring_to_top()
def show_network_dialog(self, parent):
if not self.daemon.network:
parent.show_warning(_('You are using Electrum in offline mode; restart Electrum if you want to get connected'), title=_('Offline'))
return
- if self.nd:
- self.nd.on_update()
- self.nd.show()
- self.nd.raise_()
+ if self.network_dialog:
+ self.network_dialog.on_update()
+ self.network_dialog.show()
+ self.network_dialog.raise_()
return
- self.nd = NetworkDialog(self.daemon.network, self.config,
+ self.network_dialog = NetworkDialog(self.daemon.network, self.config,
self.network_updated_signal_obj)
- self.nd.show()
+ self.network_dialog.show()
def _create_window_for_wallet(self, wallet):
w = ElectrumWindow(self, wallet)
diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py
@@ -23,7 +23,6 @@ class ChannelsList(MyTreeView):
self.main_window = parent
self.update_rows.connect(self.do_update_rows)
self.update_single_row.connect(self.do_update_single_row)
- self.status = QLabel('')
def format_fields(self, chan):
labels = {}
@@ -98,19 +97,10 @@ class ChannelsList(MyTreeView):
def get_toolbar(self):
h = QHBoxLayout()
- h.addWidget(self.status)
h.addStretch()
h.addWidget(EnterButton(_('Open Channel'), self.new_channel_dialog))
return h
- def update_status(self):
- network = self.parent.network
- if network.lngossip is None:
- return
- channel_db = self.parent.network.channel_db
- num_peers = sum([p.initialized.is_set() for p in network.lngossip.peers.values()])
- msg = _('{} peers, {} nodes, {} channels.').format(num_peers, channel_db.num_nodes, channel_db.num_channels)
- self.status.setText(msg)
def statistics_dialog(self):
channel_db = self.parent.network.channel_db
diff --git a/electrum/gui/qt/lightning_dialog.py b/electrum/gui/qt/lightning_dialog.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+#
+# Electrum - lightweight Bitcoin client
+# Copyright (C) 2012 thomasv@gitorious
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import socket
+
+from PyQt5.QtGui import *
+from PyQt5.QtCore import *
+from PyQt5.QtWidgets import *
+import PyQt5.QtCore as QtCore
+
+from electrum.i18n import _
+from .util import *
+
+help_about = _("""The local watchtower will persist on this computer after you close
+your wallet, but it requires to be online regularly.""")
+
+help_remote = _(""" To setup a remote watchtower, configure a remote electrum daemon
+with 'watchtower_host' and 'watchtower_port' """)
+
+class WatcherList(MyTreeView):
+ def __init__(self, parent):
+ super().__init__(parent, self.create_menu, stretch_column=0, editable_columns=[])
+ self.setModel(QStandardItemModel(self))
+ self.setSortingEnabled(True)
+ self.update()
+
+ def create_menu(self, x):
+ pass
+
+ def update(self):
+ if self.parent.lnwatcher is None:
+ return
+ self.model().clear()
+ self.update_headers({0:_('Outpoint'), 1:_('Tx'), 2:_('Status')})
+ sweepstore = self.parent.lnwatcher.sweepstore
+ for outpoint in sweepstore.list_sweep_tx():
+ n = sweepstore.get_num_tx(outpoint)
+ status = self.parent.lnwatcher.get_channel_status(outpoint)
+ items = [QStandardItem(e) for e in [outpoint, "%d"%n, status]]
+ self.model().insertRow(self.model().rowCount(), items)
+
+
+class LightningDialog(QDialog):
+
+ def __init__(self, gui_object):
+ QDialog.__init__(self)
+ self.gui_object = gui_object
+ self.config = gui_object.config
+ self.network = gui_object.daemon.network
+ self.lnwatcher = self.network.lnwatcher
+ self.setWindowTitle(_('Lightning'))
+ self.setMinimumSize(600, 20)
+ watchtower_url = self.config.get('watchtower_url')
+ self.watchtower_e = QLineEdit(watchtower_url)
+ self.watcher_list = WatcherList(self)
+ # channel_db
+ network_w = QWidget()
+ network_vbox = QVBoxLayout(network_w)
+ self.status = QLabel('')
+ network_vbox.addWidget(self.status)
+ # local
+ local_w = QWidget()
+ vbox_local = QVBoxLayout(local_w)
+ vbox_local.addWidget(WWLabel(help_about))
+ vbox_local.addWidget(self.watcher_list)
+ # remote
+ remote_w = QWidget()
+ vbox_remote = QVBoxLayout(remote_w)
+ vbox_remote.addWidget(WWLabel(help_remote))
+ g = QGridLayout(remote_w)
+ g.addWidget(QLabel(_('URL') + ':'), 1, 0)
+ g.addWidget(self.watchtower_e, 1, 1)
+ vbox_remote.addLayout(g)
+ vbox_remote.addStretch(1)
+ # tabs
+ tabs = QTabWidget()
+ tabs.addTab(network_w, _('Network'))
+ tabs.addTab(local_w, _('Watchtower'))
+ tabs.addTab(remote_w, _('Settings'))
+ vbox = QVBoxLayout(self)
+ vbox.addWidget(tabs)
+ b = QPushButton(_('Close'))
+ b.clicked.connect(self.on_close)
+ vbox.addLayout(Buttons(b))
+ self.watcher_list.update()
+ self.gui_object.timer.timeout.connect(self.update_status)
+
+ def update_status(self):
+ if self.network.lngossip is None:
+ return
+ channel_db = self.network.channel_db
+ num_peers = sum([p.initialized.is_set() for p in self.network.lngossip.peers.values()])
+ msg = _('{} peers, {} nodes, {} channels.').format(num_peers, channel_db.num_nodes, channel_db.num_channels)
+ self.status.setText(msg)
+
+ def on_close(self):
+ url = self.watchtower_e.text()
+ if url:
+ self.lnwatcher.set_remote_watchtower()
+ self.hide()
+
+ def is_hidden(self):
+ return self.isMinimized() or self.isHidden()
+
+ def show_or_hide(self):
+ if self.is_hidden():
+ self.bring_to_top()
+ else:
+ self.hide()
+
+ def bring_to_top(self):
+ self.show()
+ self.raise_()
+
+ def closeEvent(self, event):
+ self.gui_object.watchtower_window = None
+ event.accept()
diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
@@ -157,8 +157,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self.create_status_bar()
self.need_update = threading.Event()
- self.need_update_ln = threading.Event()
-
self.decimal_point = config.get('decimal_point', DECIMAL_POINT_DEFAULT)
try:
decimal_point_to_base_unit_name(self.decimal_point)
@@ -224,7 +222,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
interests = ['wallet_updated', 'network_updated', 'blockchain_updated',
'new_transaction', 'status',
'banner', 'verified', 'fee', 'fee_histogram', 'on_quotes',
- 'on_history', 'channel', 'channels', 'ln_status', 'ln_message',
+ 'on_history', 'channel', 'channels', 'ln_message',
'ln_payment_completed']
# To avoid leaking references to "self" that prevent the
# window from being GC-ed when closed, callbacks should be
@@ -374,8 +372,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
elif event == 'channel':
self.channels_list.update_single_row.emit(*args)
self.update_status()
- elif event == 'ln_status':
- self.need_update_ln.set()
elif event == 'ln_payment_completed':
# FIXME it is really inefficient to force update the whole GUI
# just for a single LN payment. individual rows in lists should be updated instead.
@@ -638,7 +634,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
tools_menu.addAction(_("Electrum preferences") if sys.platform == 'darwin' else _("Preferences"), self.settings_dialog)
tools_menu.addAction(_("&Network"), lambda: self.gui_object.show_network_dialog(self))
if self.config.get('lightning'):
- tools_menu.addAction(_("&Watchtower"), lambda: self.gui_object.show_watchtower_dialog(self))
+ tools_menu.addAction(_("&Lightning"), self.gui_object.show_lightning_dialog)
tools_menu.addAction(_("&Plugins"), self.plugins_dialog)
tools_menu.addSeparator()
tools_menu.addAction(_("&Sign/verify message"), self.sign_verify_message)
diff --git a/electrum/gui/qt/watchtower_window.py b/electrum/gui/qt/watchtower_window.py
@@ -1,123 +0,0 @@
-#!/usr/bin/env python
-#
-# Electrum - lightweight Bitcoin client
-# Copyright (C) 2012 thomasv@gitorious
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import socket
-
-from PyQt5.QtGui import *
-from PyQt5.QtCore import *
-from PyQt5.QtWidgets import *
-import PyQt5.QtCore as QtCore
-
-from electrum.i18n import _
-from .util import *
-
-help_about = _("""The local watchtower will persist on this computer after you close
-your wallet, but it requires to be online regularly.""")
-
-help_remote = _(""" To setup a remote watchtower, configure a remote electrum daemon
-with 'watchtower_host' and 'watchtower_port' """)
-
-class WatcherList(MyTreeView):
- def __init__(self, parent):
- super().__init__(parent, self.create_menu, stretch_column=0, editable_columns=[])
- self.setModel(QStandardItemModel(self))
- self.setSortingEnabled(True)
- self.update()
-
- def create_menu(self, x):
- pass
-
- def update(self):
- if self.parent.lnwatcher is None:
- return
- self.model().clear()
- self.update_headers({0:_('Outpoint'), 1:_('Tx'), 2:_('Status')})
- sweepstore = self.parent.lnwatcher.sweepstore
- for outpoint in sweepstore.list_sweep_tx():
- n = sweepstore.get_num_tx(outpoint)
- status = self.parent.lnwatcher.get_channel_status(outpoint)
- items = [QStandardItem(e) for e in [outpoint, "%d"%n, status]]
- self.model().insertRow(self.model().rowCount(), items)
-
-
-class WatchTowerWindow(QDialog):
-
- def __init__(self, gui_object):
- QDialog.__init__(self)
- self.gui_object = gui_object
- self.config = gui_object.config
- self.lnwatcher = gui_object.daemon.network.lnwatcher
- self.setWindowTitle(_('Watchtower'))
- self.setMinimumSize(600, 20)
- watchtower_url = self.config.get('watchtower_url')
- self.watchtower_e = QLineEdit(watchtower_url)
- self.channel_list = WatcherList(self)
- # local
- local_w = QWidget()
- vbox_local = QVBoxLayout(local_w)
- vbox_local.addWidget(WWLabel(help_about))
- vbox_local.addWidget(self.channel_list)
- # remote
- remote_w = QWidget()
- vbox_remote = QVBoxLayout(remote_w)
- vbox_remote.addWidget(WWLabel(help_remote))
- g = QGridLayout(remote_w)
- g.addWidget(QLabel(_('URL') + ':'), 1, 0)
- g.addWidget(self.watchtower_e, 1, 1)
- vbox_remote.addLayout(g)
- vbox_remote.addStretch(1)
- # tabs
- tabs = QTabWidget()
- tabs.addTab(local_w, _('Local'))
- tabs.addTab(remote_w, _('Remote'))
- vbox = QVBoxLayout(self)
- vbox.addWidget(tabs)
- b = QPushButton(_('Close'))
- b.clicked.connect(self.on_close)
- vbox.addLayout(Buttons(b))
- self.channel_list.update()
-
- def on_close(self):
- url = self.watchtower_e.text()
- if url:
- self.lnwatcher.set_remote_watchtower()
- self.hide()
-
- def is_hidden(self):
- return self.isMinimized() or self.isHidden()
-
- def show_or_hide(self):
- if self.is_hidden():
- self.bring_to_top()
- else:
- self.hide()
-
- def bring_to_top(self):
- self.show()
- self.raise_()
-
- def closeEvent(self, event):
- self.gui_object.watchtower_window = None
- event.accept()