Browse Source

plugins dialog: show description and enable buttons in the same dialog

master
ThomasV 1 year ago
parent
commit
7c6ff6757c
  1. 158
      electrum/gui/qt/plugins_dialog.py
  2. 4
      electrum/plugin.py

158
electrum/gui/qt/plugins_dialog.py

@ -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: #grid.setRowStretch(len(descriptions), 1)
self.window.logger.exception(f"cannot display plugin {name}")
def show_plugin_dialog(self, name, metadata, cb, i):
self.grid.setRowStretch(len(descriptions), 1) p = self.plugins.get(name)
cb.setChecked(p is not None and p.is_enabled())
d = PluginDialog(name, metadata, cb, self, i)
d.exec()

4
electrum/plugin.py

@ -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]

Loading…
Cancel
Save