from typing import TYPE_CHECKING, Optional from functools import partial from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QWidget, QScrollArea, QCheckBox, QFormLayout from electrum.i18n import _ from electrum.plugin import run_hook from .util import WindowModalDialog, Buttons, CloseButton, WWLabel, insert_spaces 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') zip_hash = metadata.get('zip_hash_sha256', None) 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 zip_hash: form.addRow(QLabel('Hash [sha256]:'), WWLabel(insert_spaces(zip_hash, 8))) if requires: msg = '\n'.join(map(lambda x: x[1], requires)) form.addRow(QLabel(_('Requires') + ':'), WWLabel(msg)) vbox.addLayout(form) text = _('Disable') if p else _('Enable') 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) p = self.plugins.toggle(name) self.cb.setChecked(bool(p)) 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): def __init__(self, window: 'ElectrumWindow'): WindowModalDialog.__init__(self, window, _('Electrum Plugins')) 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) scroll = QScrollArea() scroll.setEnabled(True) scroll.setWidgetResizable(True) scroll.setMinimumSize(400,250) scroll_w = QWidget() scroll.setWidget(scroll_w) self.grid = QGridLayout() self.grid.setColumnStretch(0,1) scroll_w.setLayout(self.grid) vbox.addWidget(scroll) vbox.addLayout(Buttons(CloseButton(self))) self.show_list() 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 self.grid.removeWidget(widget) widget.setParent(None) self.settings_widgets.pop(name) elif widget is None and p and p.requires_settings() and p.is_enabled(): # plugin got enabled, add widget widget = self.settings_widgets[name] = p.settings_widget(self) self.grid.addWidget(widget, i, 1) def show_list(self): descriptions = self.plugins.descriptions descriptions = sorted(descriptions.items()) grid = self.grid i = 0 for name, metadata in descriptions: i += 1 p = self.plugins.get(name) if metadata.get('registers_keystore'): continue display_name = metadata.get('display_name') if not display_name: continue #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, cb, i)) #grid.setRowStretch(len(descriptions), 1) def show_plugin_dialog(self, name, cb, i): p = self.plugins.get(name) metadata = self.plugins.descriptions[name] cb.setChecked(p is not None and p.is_enabled()) d = PluginDialog(name, metadata, cb, self, i) d.exec()