Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
gruve-p committed Oct 2, 2024
2 parents abbbeff + 7c6ff67 commit d674c14
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 57 deletions.
157 changes: 103 additions & 54 deletions electrum_grs/gui/qt/plugins_dialog.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,87 @@
from typing import TYPE_CHECKING, Optional
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_grs.i18n import _
from electrum_grs.gui import messages
from electrum_grs.plugin import run_hook, BasePlugin

from . import util
from .util import WindowModalDialog, Buttons, CloseButton, HelpButton
from .util import WindowModalDialog, Buttons, CloseButton, HelpButton, WWLabel


if TYPE_CHECKING:
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):

Expand All @@ -23,27 +90,24 @@ def __init__(self, window: 'ElectrumWindow'):
self.window = window
self.wallet = self.window.wallet
self.config = window.config

self.plugins = self.window.gui_object.plugins
self.settings_widgets = {}
vbox = QVBoxLayout(self)

# plugins
scroll = QScrollArea()
scroll.setEnabled(True)
scroll.setWidgetResizable(True)
scroll.setMinimumSize(400,250)
self.scroll_w = QWidget()
scroll.setWidget(self.scroll_w)
vbox.addWidget(scroll)

vbox.addLayout(Buttons(CloseButton(self)))
self.settings_widgets = {}
scroll_w = QWidget()
scroll.setWidget(scroll_w)
self.grid = QGridLayout()
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()

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]
if widget and not p:
# plugin got disabled, rm widget
Expand All @@ -55,49 +119,34 @@ def enable_settings_widget(self, p: Optional['BasePlugin'], name: str, i: int):
widget = self.settings_widgets[name] = p.settings_widget(self)
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):
descriptions = sorted(self.plugins.descriptions.items())
descriptions = self.plugins.descriptions
descriptions = sorted(descriptions.items())
grid = self.grid
i = 0
for name, descr in descriptions:
for name, metadata in descriptions:
i += 1
p = self.plugins.get(name)
if descr.get('registers_keystore'):
if metadata.get('registers_keystore'):
continue
display_name = metadata.get('display_name')
if not display_name:
continue
try:
cb = QCheckBox(descr['display_name'])
plugin_is_loaded = p is not None
cb_enabled = (not plugin_is_loaded and self.plugins.is_available(name, self.wallet)
or plugin_is_loaded and p.can_user_disable())
cb.setEnabled(cb_enabled)
cb.setChecked(plugin_is_loaded and p.is_enabled())
self.grid.addWidget(cb, i, 0)
self.enable_settings_widget(p, name, i)
cb.clicked.connect(partial(self.do_toggle, cb, name, i))
msg = descr['description']
if descr.get('requires'):
msg += '\n\n' + _('Requires') + ':\n' + '\n'.join(map(lambda x: x[1], descr.get('requires')))
self.grid.addWidget(HelpButton(msg), i, 2)
except Exception:
self.window.logger.exception(f"cannot display plugin {name}")

self.grid.setRowStretch(len(descriptions), 1)
#try:
cb = QCheckBox(display_name)
plugin_is_loaded = p is not None
cb_enabled = (not plugin_is_loaded and self.plugins.is_available(name, self.wallet)
or plugin_is_loaded and p.can_user_disable())
cb.setEnabled(cb_enabled)
cb.setChecked(plugin_is_loaded and p.is_enabled())
grid.addWidget(cb, i, 0)
self.enable_settings_widget(name, i)
cb.clicked.connect(partial(self.show_plugin_dialog, name, metadata, cb, i))

#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()
6 changes: 5 additions & 1 deletion electrum_grs/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ async def download_external_plugin(self, name):
os.unlink(filename)
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):
if name in self.plugins:
return self.plugins[name]
Expand Down Expand Up @@ -240,7 +244,7 @@ def find_external_plugins(self):

def load_external_plugins(self):
for name, d in self.external_plugin_metadata.items():
if not d.get('requires_wallet_type') and self.config.get('use_' + name):
if not d.get('requires_wallet_type') and self.config.get('enable_plugin_' + name):
try:
self.load_external_plugin(name)
except BaseException as e:
Expand Down
4 changes: 2 additions & 2 deletions electrum_grs/plugins.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"virtualkeyboard": {
"hash": "4ab551ec5226e7bb26e21991b33c75387e8de66bd9c5bc402e940e6f8a17050b",
"hash": "6c9478657abc7765c067aba7a1d8905a67dad7860b6b5d53f5d4e376fa43eef7",
"description": "Add an optional virtual keyboard to the password dialog.\nWarning: do not use this if it makes you pick a weaker password.",
"display_name": "Virtual Keyboard",
"available_for": [
Expand All @@ -11,4 +11,4 @@
"licence": "MIT",
"version": "0.0.1"
}
}
}

0 comments on commit d674c14

Please sign in to comment.