plugins dialog: show description and enable buttons in the same dialog
This commit is contained in:
@@ -1,20 +1,87 @@
|
|||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QComboBox, QLineEdit, QSpacerItem, QWidget, QHBoxLayout, QScrollArea, QCheckBox
|
from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QComboBox, QLineEdit, QSpacerItem, QWidget, QHBoxLayout, QScrollArea, QCheckBox, QFormLayout
|
||||||
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.gui import messages
|
from electrum.gui import messages
|
||||||
from electrum.plugin import run_hook, BasePlugin
|
from electrum.plugin import run_hook, BasePlugin
|
||||||
|
|
||||||
from . import util
|
from . import util
|
||||||
from .util import WindowModalDialog, Buttons, CloseButton, HelpButton
|
from .util import WindowModalDialog, Buttons, CloseButton, HelpButton, WWLabel
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .main_window import ElectrumWindow
|
from .main_window import ElectrumWindow
|
||||||
|
|
||||||
|
|
||||||
|
class PluginDialog(WindowModalDialog):
|
||||||
|
|
||||||
|
def __init__(self, name, metadata, cb: 'QCheckBox', window: 'ElectrumWindow', index:int):
|
||||||
|
display_name = metadata.get('display_name', '')
|
||||||
|
author = metadata.get('author', '')
|
||||||
|
description = metadata.get('description', '')
|
||||||
|
requires = metadata.get('requires')
|
||||||
|
version = metadata.get('version', 'n/a')
|
||||||
|
|
||||||
|
WindowModalDialog.__init__(self, window, 'Plugin')
|
||||||
|
self.setMinimumSize(400,250)
|
||||||
|
self.index = index
|
||||||
|
self.window = window
|
||||||
|
self.metadata = metadata
|
||||||
|
self.plugins = self.window.plugins
|
||||||
|
self.name = name
|
||||||
|
self.cb = cb
|
||||||
|
p = self.plugins.get(name) # is installed
|
||||||
|
vbox = QVBoxLayout(self)
|
||||||
|
form = QFormLayout(None)
|
||||||
|
form.addRow(QLabel(_('Name') + ':'), QLabel(display_name))
|
||||||
|
form.addRow(QLabel(_('Author') + ':'), QLabel(author))
|
||||||
|
form.addRow(QLabel(_('Description') + ':'), WWLabel(description))
|
||||||
|
form.addRow(QLabel(_('Version') + ':'), QLabel(version))
|
||||||
|
if requires:
|
||||||
|
msg = '\n'.join(map(lambda x: x[1], requires))
|
||||||
|
form.addRow(QLabel(_('Requires') + ':'), WWLabel(msg))
|
||||||
|
vbox.addLayout(form)
|
||||||
|
if name in self.plugins.internal_plugin_metadata:
|
||||||
|
text = _('Disable') if p else _('Enable')
|
||||||
|
else:
|
||||||
|
text = _('Remove') if p else _('Install')
|
||||||
|
toggle_button = QPushButton(text)
|
||||||
|
toggle_button.clicked.connect(partial(self.do_toggle, toggle_button, name))
|
||||||
|
close_button = CloseButton(self)
|
||||||
|
close_button.setText(_('Cancel'))
|
||||||
|
buttons = [toggle_button, close_button]
|
||||||
|
vbox.addLayout(Buttons(*buttons))
|
||||||
|
|
||||||
|
def do_toggle(self, button, name):
|
||||||
|
button.setEnabled(False)
|
||||||
|
if name in self.plugins.internal_plugin_metadata:
|
||||||
|
p = self.plugins.toggle(name)
|
||||||
|
self.cb.setChecked(bool(p))
|
||||||
|
else:
|
||||||
|
p = self.plugins.get(name)
|
||||||
|
if not p:
|
||||||
|
#if not self.window.window.question("Install plugin '%s'?"%name):
|
||||||
|
# return
|
||||||
|
coro = self.plugins.download_external_plugin(name)
|
||||||
|
def on_success(x):
|
||||||
|
self.plugins.enable(name)
|
||||||
|
p = self.plugins.get(name)
|
||||||
|
self.cb.setChecked(bool(p))
|
||||||
|
self.window.window.run_coroutine_from_thread(coro, "Downloading '%s' "%name, on_result=on_success)
|
||||||
|
else:
|
||||||
|
#if not self.window.window.question("Remove plugin '%s'?"%name):
|
||||||
|
# return
|
||||||
|
self.plugins.disable(name)
|
||||||
|
self.cb.setChecked(False)
|
||||||
|
self.plugins.remove_external_plugin(name)
|
||||||
|
|
||||||
|
self.close()
|
||||||
|
self.window.enable_settings_widget(name, self.index)
|
||||||
|
# note: all enabled plugins will receive this hook:
|
||||||
|
run_hook('init_qt', self.window.window.gui_object)
|
||||||
|
|
||||||
|
|
||||||
class PluginsDialog(WindowModalDialog):
|
class PluginsDialog(WindowModalDialog):
|
||||||
|
|
||||||
@@ -23,27 +90,24 @@ class PluginsDialog(WindowModalDialog):
|
|||||||
self.window = window
|
self.window = window
|
||||||
self.wallet = self.window.wallet
|
self.wallet = self.window.wallet
|
||||||
self.config = window.config
|
self.config = window.config
|
||||||
|
|
||||||
self.plugins = self.window.gui_object.plugins
|
self.plugins = self.window.gui_object.plugins
|
||||||
|
self.settings_widgets = {}
|
||||||
vbox = QVBoxLayout(self)
|
vbox = QVBoxLayout(self)
|
||||||
|
|
||||||
# plugins
|
|
||||||
scroll = QScrollArea()
|
scroll = QScrollArea()
|
||||||
scroll.setEnabled(True)
|
scroll.setEnabled(True)
|
||||||
scroll.setWidgetResizable(True)
|
scroll.setWidgetResizable(True)
|
||||||
scroll.setMinimumSize(400,250)
|
scroll.setMinimumSize(400,250)
|
||||||
self.scroll_w = QWidget()
|
scroll_w = QWidget()
|
||||||
scroll.setWidget(self.scroll_w)
|
scroll.setWidget(scroll_w)
|
||||||
vbox.addWidget(scroll)
|
|
||||||
|
|
||||||
vbox.addLayout(Buttons(CloseButton(self)))
|
|
||||||
self.settings_widgets = {}
|
|
||||||
self.grid = QGridLayout()
|
self.grid = QGridLayout()
|
||||||
self.grid.setColumnStretch(0,1)
|
self.grid.setColumnStretch(0,1)
|
||||||
self.scroll_w.setLayout(self.grid)
|
scroll_w.setLayout(self.grid)
|
||||||
|
vbox.addWidget(scroll)
|
||||||
|
vbox.addLayout(Buttons(CloseButton(self)))
|
||||||
self.show_list()
|
self.show_list()
|
||||||
|
|
||||||
def enable_settings_widget(self, p: Optional['BasePlugin'], name: str, i: int):
|
def enable_settings_widget(self, name: str, i: int):
|
||||||
|
p = self.plugins.get(name)
|
||||||
widget = self.settings_widgets.get(name) # type: Optional[QWidget]
|
widget = self.settings_widgets.get(name) # type: Optional[QWidget]
|
||||||
if widget and not p:
|
if widget and not p:
|
||||||
# plugin got disabled, rm widget
|
# plugin got disabled, rm widget
|
||||||
@@ -55,50 +119,34 @@ class PluginsDialog(WindowModalDialog):
|
|||||||
widget = self.settings_widgets[name] = p.settings_widget(self)
|
widget = self.settings_widgets[name] = p.settings_widget(self)
|
||||||
self.grid.addWidget(widget, i, 1)
|
self.grid.addWidget(widget, i, 1)
|
||||||
|
|
||||||
def do_toggle(self, cb, name, i):
|
|
||||||
if self.plugins.requires_download(name):
|
|
||||||
cb.setChecked(False)
|
|
||||||
self.download_plugin_dialog(cb, name, i)
|
|
||||||
return
|
|
||||||
p = self.plugins.toggle(name)
|
|
||||||
cb.setChecked(bool(p))
|
|
||||||
self.enable_settings_widget(p, name, i)
|
|
||||||
# note: all enabled plugins will receive this hook:
|
|
||||||
run_hook('init_qt', self.window.gui_object)
|
|
||||||
|
|
||||||
def download_plugin_dialog(self, cb, name, i):
|
|
||||||
import asyncio
|
|
||||||
if not self.window.question("Download plugin '%s'?"%name):
|
|
||||||
return
|
|
||||||
coro = self.plugins.download_external_plugin(name)
|
|
||||||
def on_success(x):
|
|
||||||
self.do_toggle(cb, name, i)
|
|
||||||
self.window.run_coroutine_dialog(coro, "Downloading '%s' "%name, on_result=on_success, on_cancelled=None)
|
|
||||||
|
|
||||||
def show_list(self):
|
def show_list(self):
|
||||||
descriptions = sorted(self.plugins.descriptions.items())
|
descriptions = self.plugins.descriptions
|
||||||
|
descriptions = sorted(descriptions.items())
|
||||||
|
grid = self.grid
|
||||||
i = 0
|
i = 0
|
||||||
for name, descr in descriptions:
|
for name, metadata in descriptions:
|
||||||
i += 1
|
i += 1
|
||||||
p = self.plugins.get(name)
|
p = self.plugins.get(name)
|
||||||
if descr.get('registers_keystore'):
|
if metadata.get('registers_keystore'):
|
||||||
continue
|
continue
|
||||||
try:
|
display_name = metadata.get('display_name')
|
||||||
cb = QCheckBox(descr['display_name'])
|
if not display_name:
|
||||||
plugin_is_loaded = p is not None
|
continue
|
||||||
cb_enabled = (not plugin_is_loaded and self.plugins.is_available(name, self.wallet)
|
#try:
|
||||||
or plugin_is_loaded and p.can_user_disable())
|
cb = QCheckBox(display_name)
|
||||||
cb.setEnabled(cb_enabled)
|
plugin_is_loaded = p is not None
|
||||||
cb.setChecked(plugin_is_loaded and p.is_enabled())
|
cb_enabled = (not plugin_is_loaded and self.plugins.is_available(name, self.wallet)
|
||||||
self.grid.addWidget(cb, i, 0)
|
or plugin_is_loaded and p.can_user_disable())
|
||||||
self.enable_settings_widget(p, name, i)
|
cb.setEnabled(cb_enabled)
|
||||||
cb.clicked.connect(partial(self.do_toggle, cb, name, i))
|
cb.setChecked(plugin_is_loaded and p.is_enabled())
|
||||||
msg = descr['description']
|
grid.addWidget(cb, i, 0)
|
||||||
if descr.get('requires'):
|
self.enable_settings_widget(name, i)
|
||||||
msg += '\n\n' + _('Requires') + ':\n' + '\n'.join(map(lambda x: x[1], descr.get('requires')))
|
cb.clicked.connect(partial(self.show_plugin_dialog, name, metadata, cb, i))
|
||||||
self.grid.addWidget(HelpButton(msg), i, 2)
|
|
||||||
except Exception:
|
|
||||||
self.window.logger.exception(f"cannot display plugin {name}")
|
|
||||||
|
|
||||||
self.grid.setRowStretch(len(descriptions), 1)
|
#grid.setRowStretch(len(descriptions), 1)
|
||||||
|
|
||||||
|
def show_plugin_dialog(self, name, metadata, cb, i):
|
||||||
|
p = self.plugins.get(name)
|
||||||
|
cb.setChecked(p is not None and p.is_enabled())
|
||||||
|
d = PluginDialog(name, metadata, cb, self, i)
|
||||||
|
d.exec()
|
||||||
|
|||||||
@@ -178,6 +178,10 @@ class Plugins(DaemonThread):
|
|||||||
os.unlink(filename)
|
os.unlink(filename)
|
||||||
raise Exception(f"wrong plugin hash {name}")
|
raise Exception(f"wrong plugin hash {name}")
|
||||||
|
|
||||||
|
def remove_external_plugin(self, name):
|
||||||
|
filename = self.external_plugin_path(name)
|
||||||
|
os.unlink(filename)
|
||||||
|
|
||||||
def load_external_plugin(self, name):
|
def load_external_plugin(self, name):
|
||||||
if name in self.plugins:
|
if name in self.plugins:
|
||||||
return self.plugins[name]
|
return self.plugins[name]
|
||||||
|
|||||||
Reference in New Issue
Block a user