Browse Source

qml: clean up, generalize plugin gui base, enumerate plugins in gui

(still quite crude impl, dynamic enable/disable plugin gui is misaligned
with backend)
patch-4
Sander van Grieken 2 years ago
parent
commit
27999a9583
  1. 35
      electrum/gui/qml/components/Preferences.qml
  2. 1
      electrum/gui/qml/components/main.qml
  3. 40
      electrum/gui/qml/plugins.py
  4. 33
      electrum/gui/qml/qeapp.py
  5. 27
      electrum/plugins/labels/qml.py

35
electrum/gui/qml/components/Preferences.qml

@ -217,6 +217,7 @@ Pane {
Pane { Pane {
ColumnLayout { ColumnLayout {
x: constants.paddingXXLarge
id: pluginsRootLayout id: pluginsRootLayout
} }
} }
@ -232,12 +233,23 @@ Pane {
Component { Component {
id: pluginHeader id: pluginHeader
RowLayout { RowLayout {
property QtObject plugin Layout.leftMargin: -constants.paddingXXLarge
property string name
property string fullname
property bool pluginEnabled
Switch { Switch {
checked: plugin.pluginEnabled checked: pluginEnabled
onCheckedChanged: {
if (activeFocus)
pluginEnabled = checked
}
} }
Label { Label {
text: plugin.name text: fullname
}
onPluginEnabledChanged: {
console.log('!')
AppController.setPluginEnabled(name, pluginEnabled)
} }
} }
} }
@ -252,13 +264,16 @@ Pane {
spendUnconfirmed.checked = Config.spendUnconfirmed spendUnconfirmed.checked = Config.spendUnconfirmed
lnRoutingType.currentIndex = Config.useGossip ? 0 : 1 lnRoutingType.currentIndex = Config.useGossip ? 0 : 1
var labelsPlugin = AppController.plugin('labels') var plugins = AppController.plugins
if (labelsPlugin) { for (var i=0; i<plugins.length; i++) {
pluginHeader.createObject(pluginsRootLayout, { plugin: labelsPlugin }) var p = plugins[i]
// console.log(Qt.resolvedUrl(labelsPlugin.settingsComponent())) pluginHeader.createObject(pluginsRootLayout, { name: p['name'], fullname: p['fullname'], pluginEnabled: p['enabled'] })
if (labelsPlugin.settingsComponent()) { var labelsPlugin = AppController.plugin(p['name'])
var component = Qt.createComponent(Qt.resolvedUrl(labelsPlugin.settingsComponent())) if (labelsPlugin) {
component.createObject(pluginsRootLayout, {plugin: labelsPlugin}) if (labelsPlugin.settingsComponent()) {
var component = Qt.createComponent(Qt.resolvedUrl(labelsPlugin.settingsComponent()))
component.createObject(pluginsRootLayout, { plugin: labelsPlugin })
}
} }
} }
} }

1
electrum/gui/qml/components/main.qml

@ -349,7 +349,6 @@ ApplicationWindow
property bool _lockDialogShown: false property bool _lockDialogShown: false
onActiveChanged: { onActiveChanged: {
console.log('active='+active)
if (!active) { if (!active) {
// deactivated // deactivated
_lastActive = Date.now() _lastActive = Date.now()

40
electrum/gui/qml/plugins.py

@ -0,0 +1,40 @@
from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, QObject
from electrum.i18n import _
from electrum.logging import get_logger
class PluginQObject(QObject):
logger = get_logger(__name__)
pluginChanged = pyqtSignal()
busyChanged = pyqtSignal()
pluginEnabledChanged = pyqtSignal()
_busy = False
def __init__(self, plugin, parent: 'ElectrumGuiApplication'):
super().__init__(parent)
self.plugin = plugin
self.app = parent
@pyqtProperty(str, notify=pluginChanged)
def name(self): return self._name
@pyqtProperty(bool, notify=busyChanged)
def busy(self): return self._busy
@pyqtProperty(bool, notify=pluginEnabledChanged)
def pluginEnabled(self): return self.plugin.is_enabled()
@pluginEnabled.setter
def pluginEnabled(self, enabled):
if enabled != self.plugin.is_enabled():
self.logger.debug(f'can {self.plugin.can_user_disable()}, {self.plugin.is_available()}')
if not self.plugin.can_user_disable() and not enabled:
return
if enabled:
self.app.plugins.enable(self.plugin.name)
else:
self.app.plugins.disable(self.plugin.name)
self.pluginEnabledChanged.emit()

33
electrum/gui/qml/qeapp.py

@ -3,7 +3,7 @@ import queue
import time import time
import os import os
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QUrl, QLocale, qInstallMessageHandler, QTimer from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty, QObject, QUrl, QLocale, qInstallMessageHandler, QTimer
from PyQt5.QtGui import QGuiApplication, QFontDatabase from PyQt5.QtGui import QGuiApplication, QFontDatabase
from PyQt5.QtQml import qmlRegisterType, qmlRegisterUncreatableType, QQmlApplicationEngine from PyQt5.QtQml import qmlRegisterType, qmlRegisterUncreatableType, QQmlApplicationEngine
@ -34,6 +34,8 @@ notification = None
class QEAppController(QObject): class QEAppController(QObject):
userNotify = pyqtSignal(str) userNotify = pyqtSignal(str)
_dummy = pyqtSignal()
def __init__(self, qedaemon, plugins): def __init__(self, qedaemon, plugins):
super().__init__() super().__init__()
self.logger = get_logger(__name__) self.logger = get_logger(__name__)
@ -134,15 +136,37 @@ class QEAppController(QObject):
@pyqtSlot(str, result=QObject) @pyqtSlot(str, result=QObject)
def plugin(self, plugin_name): def plugin(self, plugin_name):
self.logger.warning(f'now {self._plugins.count()} plugins loaded') self.logger.debug(f'now {self._plugins.count()} plugins loaded')
plugin = self._plugins.get(plugin_name) plugin = self._plugins.get(plugin_name)
self.logger.debug(f'plugin with name {plugin_name} is {str(type(plugin))}') self.logger.debug(f'plugin with name {plugin_name} is {str(type(plugin))}')
if plugin: if plugin and hasattr(plugin,'so'):
return plugin.so return plugin.so
else: else:
self.logger.debug('None!') self.logger.debug('None!')
return None return None
@pyqtProperty('QVariant', notify=_dummy)
def plugins(self):
s = []
for item in self._plugins.descriptions:
self.logger.info(item)
s.append({
'name': item,
'fullname': self._plugins.descriptions[item]['fullname'],
'enabled': bool(self._plugins.get(item))
})
self.logger.debug(f'{str(s)}')
return s
@pyqtSlot(str, bool)
def setPluginEnabled(self, plugin, enabled):
if enabled:
self._plugins.enable(plugin)
else:
self._plugins.disable(plugin)
class ElectrumQmlApplication(QGuiApplication): class ElectrumQmlApplication(QGuiApplication):
_valid = True _valid = True
@ -190,10 +214,11 @@ class ElectrumQmlApplication(QGuiApplication):
self.fixedFont = 'Monospace' # hope for the best self.fixedFont = 'Monospace' # hope for the best
self.context = self.engine.rootContext() self.context = self.engine.rootContext()
self.plugins = plugins
self._qeconfig = QEConfig(config) self._qeconfig = QEConfig(config)
self._qenetwork = QENetwork(daemon.network, self._qeconfig) self._qenetwork = QENetwork(daemon.network, self._qeconfig)
self.daemon = QEDaemon(daemon) self.daemon = QEDaemon(daemon)
self.appController = QEAppController(self.daemon, plugins) self.appController = QEAppController(self.daemon, self.plugins)
self._maxAmount = QEAmount(is_max=True) self._maxAmount = QEAmount(is_max=True)
self.context.setContextProperty('AppController', self.appController) self.context.setContextProperty('AppController', self.appController)
self.context.setContextProperty('Config', self._qeconfig) self.context.setContextProperty('Config', self._qeconfig)

27
electrum/plugins/labels/qml.py

@ -6,35 +6,23 @@ from electrum.i18n import _
from electrum.plugin import hook from electrum.plugin import hook
from electrum.gui.qml.qewallet import QEWallet from electrum.gui.qml.qewallet import QEWallet
from electrum.gui.qml.plugins import PluginQObject
from .labels import LabelsPlugin from .labels import LabelsPlugin
class Plugin(LabelsPlugin): class Plugin(LabelsPlugin):
class QSignalObject(QObject): class QSignalObject(PluginQObject):
pluginChanged = pyqtSignal()
pluginEnabledChanged = pyqtSignal()
labelsChanged = pyqtSignal() labelsChanged = pyqtSignal()
busyChanged = pyqtSignal()
uploadSuccess = pyqtSignal() uploadSuccess = pyqtSignal()
uploadFailed = pyqtSignal() uploadFailed = pyqtSignal()
downloadSuccess = pyqtSignal() downloadSuccess = pyqtSignal()
downloadFailed = pyqtSignal() downloadFailed = pyqtSignal()
_busy = False _name = _('LabelSync Plugin')
def __init__(self, plugin, parent = None): def __init__(self, plugin, parent):
super().__init__(parent) super().__init__(plugin, parent)
self.plugin = plugin
@pyqtProperty(str, notify=pluginChanged)
def name(self): return _('Labels Plugin')
@pyqtProperty(bool, notify=busyChanged)
def busy(self): return self._busy
@pyqtProperty(bool, notify=pluginEnabledChanged)
def pluginEnabled(self): return self.plugin.is_enabled()
@pyqtSlot(result=str) @pyqtSlot(result=str)
def settingsComponent(self): return '../../../plugins/labels/Labels.qml' def settingsComponent(self): return '../../../plugins/labels/Labels.qml'
@ -78,7 +66,7 @@ class Plugin(LabelsPlugin):
@hook @hook
def load_wallet(self, wallet): def load_wallet(self, wallet):
self.logger.info(f'load_wallet hook for wallet {str(type(wallet))}') self.logger.debug(f'plugin enabled for wallet "{str(wallet)}"')
self.start_wallet(wallet) self.start_wallet(wallet)
def push_async(self): def push_async(self):
@ -130,8 +118,7 @@ class Plugin(LabelsPlugin):
@hook @hook
def init_qml(self, gui: 'ElectrumGui'): def init_qml(self, gui: 'ElectrumGui'):
self.logger.debug('init_qml hook called') self.logger.debug(f'init_qml hook called, gui={str(type(gui))}')
self.logger.debug(f'gui={str(type(gui))}')
self._app = gui.app self._app = gui.app
# important: QSignalObject needs to be parented, as keeping a ref # important: QSignalObject needs to be parented, as keeping a ref
# in the plugin is not enough to avoid gc # in the plugin is not enough to avoid gc

Loading…
Cancel
Save