1
mirror of https://invent.kde.org/network/falkon.git synced 2024-11-11 01:22:10 +01:00

added support to load/unload QML plugins

Following methods are exposed to qml 1) init 2) unload 3) testPlugin. Also logic to load QML plugins is implemented.
This commit is contained in:
Anmol Gautam 2018-05-15 16:34:57 +05:30
parent 3760a9ffd1
commit 30cc7a8b89
7 changed files with 309 additions and 1 deletions

View File

@ -154,6 +154,8 @@ set(SRCS ${SRCS}
plugins/pluginproxy.cpp
plugins/plugins.cpp
plugins/speeddial.cpp
plugins/qml/qmlplugins.cpp
plugins/qml/qmlplugininterface.cpp
popupwindow/popuplocationbar.cpp
popupwindow/popupstatusbarmessage.cpp
popupwindow/popupwebview.cpp

View File

@ -24,10 +24,13 @@
#include "adblock/adblockplugin.h"
#include "../config.h"
#include "desktopfile.h"
#include "qml/qmlplugins.h"
#include <iostream>
#include <QPluginLoader>
#include <QDir>
#include <QQmlEngine>
#include <QQmlComponent>
Plugins::Plugins(QObject* parent)
: QObject(parent)
@ -39,6 +42,8 @@ Plugins::Plugins(QObject* parent)
if (!MainApplication::isTestModeEnabled()) {
loadPythonSupport();
}
loadQmlSupport();
}
QList<Plugins::Plugin> Plugins::getAvailablePlugins()
@ -113,6 +118,7 @@ PluginSpec Plugins::createSpec(const DesktopFile &metaData)
spec.description = metaData.comment();
spec.version = metaData.value(QSL("X-Falkon-Version")).toString();
spec.author = QSL("%1 <%2>").arg(metaData.value(QSL("X-Falkon-Author")).toString(), metaData.value(QSL("X-Falkon-Email")).toString());
spec.entryPoint = metaData.value(QSL("X-Falkon-EntryPoint")).toString();
spec.hasSettings = metaData.value(QSL("X-Falkon-Settings")).toBool();
const QString iconName = metaData.icon();
@ -204,6 +210,24 @@ void Plugins::loadAvailablePlugins()
}
}
}
// QmlPlugin
for (QString dir: dirs) {
// qml plugins will be loaded from subdirectory qml
dir.append(QSL("/qml"));
const auto qmlDirs = QDir(dir).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &info : qmlDirs) {
Plugin plugin = loadQmlPlugin(info.absoluteFilePath());
if (plugin.type == Plugin::Invalid) {
continue;
}
if (plugin.pluginSpec.name.isEmpty()) {
qWarning() << "Invalid plugin spec of" << info.absoluteFilePath() << "plugin";
continue;
}
registerAvailablePlugin(plugin);
}
}
}
void Plugins::registerAvailablePlugin(const Plugin &plugin)
@ -244,6 +268,11 @@ void Plugins::loadPythonSupport()
}
}
void Plugins::loadQmlSupport()
{
QmlPlugins::registerQmlTypes();
}
Plugins::Plugin Plugins::loadPlugin(const QString &id)
{
QString name;
@ -258,6 +287,8 @@ Plugins::Plugin Plugins::loadPlugin(const QString &id)
type = Plugin::SharedLibraryPlugin;
} else if (t == QL1S("python")) {
type = Plugin::PythonPlugin;
} else if (t == QL1S("qml")) {
type = Plugin::QmlPlugin;
}
name = id.mid(colon + 1);
} else {
@ -275,6 +306,9 @@ Plugins::Plugin Plugins::loadPlugin(const QString &id)
case Plugin::PythonPlugin:
return loadPythonPlugin(name);
case Plugin::QmlPlugin:
return loadQmlPlugin(name);
default:
return Plugin();
}
@ -340,6 +374,36 @@ Plugins::Plugin Plugins::loadPythonPlugin(const QString &name)
return f(name);
}
Plugins::Plugin Plugins::loadQmlPlugin(const QString &name)
{
QString fullPath;
if (QFileInfo(name).isAbsolute()) {
fullPath = name;
} else {
fullPath = DataPaths::locate(DataPaths::Plugins, QSL("qml/") + name);
if (fullPath.isEmpty()) {
qWarning() << "Plugin" << name << "not found";
return Plugin();
}
}
Plugin plugin;
plugin.type = Plugin::QmlPlugin;
plugin.pluginId = QSL("qml:%1").arg(QFileInfo(name).fileName());
plugin.pluginSpec = createSpec(DesktopFile(fullPath + QSL("/metadata.desktop")));
QQmlEngine* engine = new QQmlEngine();
QQmlComponent component(engine, QDir(fullPath).filePath(plugin.pluginSpec.entryPoint));
plugin.qmlComponentInstance = qobject_cast<QmlPluginInterface*>(component.create());
if (!plugin.qmlComponentInstance) {
qWarning() << "Loading" << fullPath << "failed:" << component.errorString();
return Plugin();
}
return plugin;
}
bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin)
{
if (!plugin) {
@ -359,6 +423,10 @@ bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin)
initPythonPlugin(plugin);
break;
case Plugin::QmlPlugin:
initQmlPlugin(plugin);
break;
default:
return false;
}
@ -409,3 +477,11 @@ void Plugins::initPythonPlugin(Plugin *plugin)
f(plugin);
}
void Plugins::initQmlPlugin(Plugin *plugin)
{
Q_ASSERT(plugin->type == Plugin::QmlPlugin);
plugin->qmlComponentInstance->setName(plugin->pluginSpec.name);
plugin->instance = qobject_cast<PluginInterface*>(plugin->qmlComponentInstance);
}

View File

@ -24,6 +24,7 @@
#include "qzcommon.h"
#include "plugininterface.h"
#include "qml/qmlplugininterface.h"
class QLibrary;
class QPluginLoader;
@ -36,6 +37,7 @@ struct PluginSpec {
QString author;
QString version;
QPixmap icon;
QString entryPoint;
bool hasSettings = false;
bool operator==(const PluginSpec &other) const {
@ -55,7 +57,8 @@ public:
Invalid = 0,
InternalPlugin,
SharedLibraryPlugin,
PythonPlugin
PythonPlugin,
QmlPlugin
};
Type type = Invalid;
QString pluginId;
@ -69,6 +72,9 @@ public:
QString libraryPath;
QPluginLoader *pluginLoader = nullptr;
// QmlPlugin
QmlPluginInterface *qmlComponentInstance = nullptr;
// Other
QVariant data;
@ -109,14 +115,17 @@ Q_SIGNALS:
private:
void loadPythonSupport();
void loadQmlSupport();
Plugin loadPlugin(const QString &id);
Plugin loadInternalPlugin(const QString &name);
Plugin loadSharedLibraryPlugin(const QString &name);
Plugin loadPythonPlugin(const QString &name);
Plugin loadQmlPlugin(const QString &name);
bool initPlugin(PluginInterface::InitState state, Plugin *plugin);
void initInternalPlugin(Plugin *plugin);
void initSharedLibraryPlugin(Plugin *plugin);
void initPythonPlugin(Plugin *plugin);
void initQmlPlugin(Plugin *plugin);
void registerAvailablePlugin(const Plugin &plugin);

View File

@ -0,0 +1,100 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "qmlplugininterface.h"
#include <QDebug>
QmlPluginInterface::QmlPluginInterface()
{
}
void QmlPluginInterface::init(InitState state, const QString &settingsPath)
{
if (m_jsInit.isCallable()) {
QJSValueList args;
args.append(state);
args.append(settingsPath);
m_jsInit.call(args);
} else {
qWarning() << "Unable to call init on" << m_name << "plugin";
}
}
DesktopFile QmlPluginInterface::metaData() const
{
return DesktopFile();
}
void QmlPluginInterface::unload()
{
if (m_jsUnload.isCallable()) {
m_jsUnload.call();
} else {
qWarning() << "Unable to call unload on" << m_name << "plugin";
}
}
bool QmlPluginInterface::testPlugin()
{
if (m_jsTestPlugin.isCallable()) {
QJSValue ret = m_jsTestPlugin.call();
return ret.toBool();
} else {
qWarning() << "Unable to call testPlugin on" << m_name << "plugin";
return false;
}
}
QString QmlPluginInterface::name()
{
return m_name;
}
void QmlPluginInterface::setName(const QString &name)
{
m_name = name;
}
QJSValue QmlPluginInterface::jsInit()
{
return m_jsInit;
}
void QmlPluginInterface::setJsInit(const QJSValue &init)
{
m_jsInit = init;
}
QJSValue QmlPluginInterface::jsUnload()
{
return m_jsUnload;
}
void QmlPluginInterface::setJsUnload(const QJSValue &unload)
{
m_jsUnload = unload;
}
QJSValue QmlPluginInterface::jsTestPlugin()
{
return m_jsTestPlugin;
}
void QmlPluginInterface::setJsTestPlugin(const QJSValue &testPlugin)
{
m_jsTestPlugin = testPlugin;
}

View File

@ -0,0 +1,60 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef QMLPLUGININTERFACE_H
#define QMLPLUGININTERFACE_H
#include <QJSValue>
#include <QObject>
#include "desktopfile.h"
#include "plugininterface.h"
class QmlPluginInterface : public QObject, public PluginInterface
{
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_ENUMS(InitState)
Q_PROPERTY(QString __name__ READ name CONSTANT)
Q_PROPERTY(QJSValue init READ jsInit WRITE setJsInit)
Q_PROPERTY(QJSValue unload READ jsUnload WRITE setJsUnload)
Q_PROPERTY(QJSValue testPlugin READ jsTestPlugin WRITE setJsTestPlugin)
public:
explicit QmlPluginInterface();
DesktopFile metaData() const;
void init(InitState state, const QString &settingsPath);
void unload();
bool testPlugin();
QString name();
void setName(const QString &name);
QJSValue jsInit();
void setJsInit(const QJSValue &init);
QJSValue jsUnload();
void setJsUnload(const QJSValue &unload);
QJSValue jsTestPlugin();
void setJsTestPlugin(const QJSValue &testPlugin);
private:
QString m_name;
QJSValue m_jsInit;
QJSValue m_jsUnload;
QJSValue m_jsTestPlugin;
};
#endif // QMLPLUGININTERFACE_H

View File

@ -0,0 +1,33 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "qmlplugins.h"
#include "qmlplugininterface.h"
#include <QQmlEngine>
// static
void QmlPlugins::registerQmlTypes()
{
registerQmlPluginInterface();
}
// private static
void QmlPlugins::registerQmlPluginInterface()
{
qmlRegisterType<QmlPluginInterface>("org.kde.falkon", 1, 0, "PluginInterface");
}

View File

@ -0,0 +1,28 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef QMLPLUGINS_H
#define QMLPLUGINS_H
class QmlPlugins
{
static void registerQmlPluginInterface();
public:
static void registerQmlTypes();
};
#endif // QMLPLUGINS_H