qml: clean up, generalize plugin gui base, enumerate plugins in gui
(still quite crude impl, dynamic enable/disable plugin gui is misaligned with backend)
This commit is contained in:
@@ -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 })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
Normal file
40
electrum/gui/qml/plugins.py
Normal file
@@ -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()
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user