mirror of
https://invent.kde.org/network/falkon.git
synced 2024-12-19 18:26:34 +01:00
WIP: Shared QML engine for plugins
This commit is contained in:
parent
ee4dbad676
commit
7ddb3b8985
@ -157,11 +157,10 @@ set(SRCS ${SRCS}
|
||||
plugins/plugins.cpp
|
||||
plugins/speeddial.cpp
|
||||
plugins/ocssupport.cpp
|
||||
plugins/qml/qmlplugincontext.cpp
|
||||
plugins/qml/qmlpluginloader.cpp
|
||||
plugins/qml/qmlplugin.cpp
|
||||
plugins/qml/qmlplugins.cpp
|
||||
plugins/qml/qmlplugininterface.cpp
|
||||
plugins/qml/qmlengine.cpp
|
||||
plugins/qml/qmlstaticdata.cpp
|
||||
plugins/qml/api/bookmarks/qmlbookmarktreenode.cpp
|
||||
plugins/qml/api/bookmarks/qmlbookmarks.cpp
|
||||
|
@ -25,7 +25,8 @@
|
||||
#include "../config.h"
|
||||
#include "desktopfile.h"
|
||||
#include "qml/qmlplugins.h"
|
||||
#include "qml/qmlplugin.h"
|
||||
#include "qml/qmlpluginloader.h"
|
||||
#include "qml/qmlplugininterface.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@ -61,6 +62,7 @@ Plugins::Plugins(QObject* parent)
|
||||
if (!MainApplication::isTestModeEnabled()) {
|
||||
loadPythonSupport();
|
||||
}
|
||||
QmlPlugins::registerQmlTypes();
|
||||
}
|
||||
|
||||
QList<Plugins::Plugin> Plugins::availablePlugins()
|
||||
@ -279,7 +281,7 @@ void Plugins::loadAvailablePlugins()
|
||||
plugin = loadPythonPlugin(pluginPath);
|
||||
} else if (type == QL1S("Extension/Qml")) {
|
||||
// QmlPlugin
|
||||
plugin = QmlPlugin::loadPlugin(pluginPath);
|
||||
plugin = loadQmlPlugin(pluginPath);
|
||||
} else {
|
||||
qWarning() << "Invalid type" << type << "of" << pluginPath << "plugin";
|
||||
}
|
||||
@ -370,7 +372,7 @@ Plugins::Plugin Plugins::loadPlugin(const QString &id)
|
||||
return loadPythonPlugin(name);
|
||||
|
||||
case Plugin::QmlPlugin:
|
||||
return QmlPlugin::loadPlugin(name);
|
||||
return loadQmlPlugin(name);
|
||||
|
||||
default:
|
||||
return Plugin();
|
||||
@ -429,6 +431,29 @@ 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, name);
|
||||
if (fullPath.isEmpty()) {
|
||||
qWarning() << "QML plugin" << name << "not found";
|
||||
return Plugins::Plugin();
|
||||
}
|
||||
}
|
||||
|
||||
Plugins::Plugin plugin;
|
||||
plugin.type = Plugins::Plugin::QmlPlugin;
|
||||
plugin.pluginId = QSL("qml:%1").arg(QFileInfo(name).fileName());
|
||||
plugin.pluginPath = fullPath;
|
||||
DesktopFile desktopFile(fullPath + QSL("/metadata.desktop"));
|
||||
plugin.pluginSpec = Plugins::createSpec(desktopFile);
|
||||
plugin.data = QVariant::fromValue(new QmlPluginLoader(plugin));
|
||||
return plugin;
|
||||
}
|
||||
|
||||
bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin)
|
||||
{
|
||||
if (!plugin) {
|
||||
@ -449,7 +474,7 @@ bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin)
|
||||
break;
|
||||
|
||||
case Plugin::QmlPlugin:
|
||||
QmlPlugin::initPlugin(plugin);
|
||||
initQmlPlugin(plugin);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -508,3 +533,24 @@ void Plugins::initPythonPlugin(Plugin *plugin)
|
||||
|
||||
f(plugin);
|
||||
}
|
||||
|
||||
void Plugins::initQmlPlugin(Plugin *plugin)
|
||||
{
|
||||
Q_ASSERT(plugin->type == Plugins::Plugin::QmlPlugin);
|
||||
|
||||
const QString name = plugin->pluginSpec.name;
|
||||
|
||||
auto qmlPluginLoader = plugin->data.value<QmlPluginLoader*>();
|
||||
if (!qmlPluginLoader) {
|
||||
qWarning() << "Failed to cast from data";
|
||||
return;
|
||||
}
|
||||
|
||||
qmlPluginLoader->createComponent();
|
||||
if (!qmlPluginLoader->instance()) {
|
||||
qWarning() << "Failed to create component for" << name << "plugin:" << qmlPluginLoader->errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
plugin->instance = qobject_cast<PluginInterface*>(qmlPluginLoader->instance());
|
||||
}
|
||||
|
@ -114,10 +114,12 @@ private:
|
||||
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);
|
||||
|
||||
|
@ -21,10 +21,11 @@
|
||||
#include "statusbar.h"
|
||||
#include "pluginproxy.h"
|
||||
#include "qml/api/fileutils/qmlfileutils.h"
|
||||
#include "qml/qmlengine.h"
|
||||
#include "qml/qmlplugincontext.h"
|
||||
#include "qml/qmlstaticdata.h"
|
||||
|
||||
#include <QQuickWidget>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
|
||||
QmlBrowserAction::QmlBrowserAction(QObject *parent)
|
||||
: QObject(parent)
|
||||
@ -217,13 +218,10 @@ void QmlBrowserActionButton::setIcon(const QString &icon)
|
||||
if (!m_popup) {
|
||||
return;
|
||||
}
|
||||
auto qmlEngine = qobject_cast<QmlEngine*>(m_popup->creationContext()->engine());
|
||||
if (!qmlEngine) {
|
||||
return;
|
||||
}
|
||||
const QString pluginPath = qmlEngine->extensionPath();
|
||||
QIcon qicon = QmlStaticData::instance().getIcon(m_iconUrl, pluginPath);
|
||||
#if 0
|
||||
QIcon qicon = QmlStaticData::instance().getIcon(m_iconUrl, QmlPluginContext::contextForObject(this)->pluginPath());
|
||||
AbstractButtonInterface::setIcon(qicon);
|
||||
#endif
|
||||
}
|
||||
|
||||
void QmlBrowserActionButton::setBadgeText(const QString &badgeText)
|
||||
|
@ -18,30 +18,24 @@
|
||||
#include "qmlaction.h"
|
||||
#include "qztools.h"
|
||||
#include "qml/api/fileutils/qmlfileutils.h"
|
||||
#include "qml/qmlengine.h"
|
||||
#include "qml/qmlplugincontext.h"
|
||||
#include "qml/qmlstaticdata.h"
|
||||
#include <QQmlEngine>
|
||||
|
||||
QmlAction::QmlAction(QAction *action, QmlEngine *engine, QObject *parent)
|
||||
QmlAction::QmlAction(QAction *action, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_action(action)
|
||||
{
|
||||
QmlEngine *qmlEngine = qobject_cast<QmlEngine*>(engine);
|
||||
m_pluginPath = qmlEngine->extensionPath();
|
||||
Q_ASSERT(m_action);
|
||||
connect(m_action, &QAction::triggered, this, &QmlAction::triggered);
|
||||
}
|
||||
|
||||
void QmlAction::setProperties(const QVariantMap &map)
|
||||
{
|
||||
if (!m_action) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it = map.cbegin(); it != map.cend(); it++) {
|
||||
const QString key = it.key();
|
||||
if (key == QSL("icon")) {
|
||||
QString iconPath = map.value(key).toString();
|
||||
QIcon icon = QmlStaticData::instance().getIcon(iconPath, m_pluginPath);
|
||||
QIcon icon = QmlStaticData::instance().getIcon(iconPath, QmlPluginContext::contextForObject(this)->pluginPath());
|
||||
m_action->setIcon(icon);
|
||||
} else if (key == QSL("shortcut")) {
|
||||
m_action->setShortcut(QKeySequence(map.value(key).toString()));
|
||||
@ -51,7 +45,7 @@ void QmlAction::setProperties(const QVariantMap &map)
|
||||
}
|
||||
}
|
||||
|
||||
void QmlAction::update(const QVariantMap &map)
|
||||
void QmlAction::update(const QVariantMap &map)
|
||||
{
|
||||
setProperties(map);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <QAction>
|
||||
#include <QVariantMap>
|
||||
|
||||
class QmlEngine;
|
||||
class QQmlEngine;
|
||||
|
||||
/**
|
||||
* @brief The class exposing Action API to QML
|
||||
@ -30,7 +30,7 @@ class QmlAction : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlAction(QAction *action, QmlEngine *engine, QObject *parent = nullptr);
|
||||
explicit QmlAction(QAction *action, QObject *parent = nullptr);
|
||||
void setProperties(const QVariantMap &map);
|
||||
/**
|
||||
* @brief Updates the properties of the action
|
||||
@ -46,5 +46,4 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
QAction *m_action = nullptr;
|
||||
QString m_pluginPath;
|
||||
};
|
||||
|
@ -18,61 +18,51 @@
|
||||
#include "qmlmenu.h"
|
||||
#include "qztools.h"
|
||||
#include "qml/api/fileutils/qmlfileutils.h"
|
||||
#include "qml/qmlengine.h"
|
||||
#include "qml/qmlplugincontext.h"
|
||||
#include "qml/qmlstaticdata.h"
|
||||
|
||||
QmlMenu::QmlMenu(QMenu *menu, QQmlEngine *engine, QObject *parent)
|
||||
#include <QQmlEngine>
|
||||
|
||||
QmlMenu::QmlMenu(QMenu *menu, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_menu(menu)
|
||||
{
|
||||
QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
|
||||
m_engine = qobject_cast<QmlEngine*>(engine);
|
||||
m_pluginPath = m_engine->extensionPath();
|
||||
Q_ASSERT(m_menu);
|
||||
connect(m_menu, &QMenu::triggered, this, &QmlMenu::triggered);
|
||||
}
|
||||
|
||||
QmlAction *QmlMenu::addAction(const QVariantMap &map)
|
||||
QJSValue QmlMenu::addAction(const QVariantMap &map)
|
||||
{
|
||||
if (!m_menu) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QAction *action = new QAction();
|
||||
QmlAction *qmlAction = new QmlAction(action, m_engine, this);
|
||||
QmlAction *qmlAction = new QmlAction(action, this);
|
||||
QQmlEngine::setContextForObject(qmlAction, QmlPluginContext::contextForObject(this));
|
||||
action->setParent(qmlAction);
|
||||
qmlAction->setProperties(map);
|
||||
m_menu->addAction(action);
|
||||
|
||||
return qmlAction;
|
||||
return qmlEngine(this)->newQObject(qmlAction);
|
||||
}
|
||||
|
||||
QmlMenu *QmlMenu::addMenu(const QVariantMap &map)
|
||||
QJSValue QmlMenu::addMenu(const QVariantMap &map)
|
||||
{
|
||||
if (!m_menu) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMenu *newMenu = new QMenu();
|
||||
for (auto it = map.cbegin(); it != map.cend(); it++) {
|
||||
const QString key = it.key();
|
||||
if (key == QSL("icon")) {
|
||||
const QString iconPath = map.value(key).toString();
|
||||
const QIcon icon = QmlStaticData::instance().getIcon(iconPath, m_pluginPath);
|
||||
const QIcon icon = QmlStaticData::instance().getIcon(iconPath, QmlPluginContext::contextForObject(this)->pluginPath());
|
||||
newMenu->setIcon(icon);
|
||||
continue;
|
||||
}
|
||||
newMenu->setProperty(key.toUtf8(), map.value(key));
|
||||
}
|
||||
m_menu->addMenu(newMenu);
|
||||
QmlMenu *newQmlMenu = new QmlMenu(newMenu, m_engine, this);
|
||||
return newQmlMenu;
|
||||
QmlMenu *newQmlMenu = new QmlMenu(newMenu, this);
|
||||
QQmlEngine::setContextForObject(newQmlMenu, QmlPluginContext::contextForObject(this));
|
||||
connect(newQmlMenu, &QObject::destroyed, newMenu, &QObject::deleteLater);
|
||||
return qmlEngine(this)->newQObject(newQmlMenu);
|
||||
}
|
||||
|
||||
void QmlMenu::addSeparator()
|
||||
{
|
||||
if (!m_menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_menu->addSeparator();
|
||||
}
|
||||
|
@ -18,10 +18,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "qmlaction.h"
|
||||
#include <QMenu>
|
||||
#include <QQmlEngine>
|
||||
|
||||
class QmlEngine;
|
||||
#include <QMenu>
|
||||
#include <QJSValue>
|
||||
|
||||
/**
|
||||
* @brief The class exposing WebView contextmenu to QML as Menu API
|
||||
@ -30,7 +29,7 @@ class QmlMenu : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlMenu(QMenu *menu, QQmlEngine *engine, QObject *parent = nullptr);
|
||||
explicit QmlMenu(QMenu *menu, QObject *parent = nullptr);
|
||||
/**
|
||||
* @brief Adds action to menu
|
||||
* @param A JavaScript object containing properties for action.
|
||||
@ -38,14 +37,14 @@ public:
|
||||
* and shortcut in form string.
|
||||
* @return action of type [QmlAction](@ref QmlAction)
|
||||
*/
|
||||
Q_INVOKABLE QmlAction *addAction(const QVariantMap &map);
|
||||
Q_INVOKABLE QJSValue addAction(const QVariantMap &map);
|
||||
/**
|
||||
* @brief Adds sub-menu to menu
|
||||
* @param A JavaScript object containing properties of menu.
|
||||
* The icon property must be in form of url of the path.
|
||||
* @return menu of type [QmlMenu](@ref QmlMenu)
|
||||
*/
|
||||
Q_INVOKABLE QmlMenu *addMenu(const QVariantMap &map);
|
||||
Q_INVOKABLE QJSValue addMenu(const QVariantMap &map);
|
||||
/**
|
||||
* @brief Adds a separator to menu
|
||||
*/
|
||||
@ -59,6 +58,4 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
QMenu *m_menu = nullptr;
|
||||
QString m_pluginPath;
|
||||
QmlEngine *m_engine = nullptr;
|
||||
};
|
||||
|
@ -20,11 +20,12 @@
|
||||
#include "qztools.h"
|
||||
#include "sidebar.h"
|
||||
#include "qml/api/fileutils/qmlfileutils.h"
|
||||
#include "qml/qmlengine.h"
|
||||
#include "qml/qmlplugincontext.h"
|
||||
#include "qml/qmlstaticdata.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QQuickWidget>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
|
||||
QmlSideBar::QmlSideBar(QObject *parent)
|
||||
: QObject(parent)
|
||||
@ -137,13 +138,10 @@ QAction *QmlSideBarHelper::createMenuAction()
|
||||
if (!m_item) {
|
||||
return action;
|
||||
}
|
||||
auto qmlEngine = qobject_cast<QmlEngine*>(m_item->creationContext()->engine());
|
||||
if (qmlEngine) {
|
||||
return action;
|
||||
}
|
||||
const QString pluginPath = qmlEngine->extensionPath();
|
||||
const QIcon icon = QmlStaticData::instance().getIcon(m_iconUrl, pluginPath);
|
||||
#if 0
|
||||
const QIcon icon = QmlStaticData::instance().getIcon(m_iconUrl, QmlPluginContext::contextForObject(this)->pluginPath());
|
||||
action->setIcon(icon);
|
||||
#endif
|
||||
return action;
|
||||
}
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
/* ============================================================
|
||||
* 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 "qmlengine.h"
|
||||
|
||||
QmlEngine::QmlEngine(QObject *parent)
|
||||
: QQmlEngine(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString QmlEngine::extensionName()
|
||||
{
|
||||
return m_extensionName;
|
||||
}
|
||||
|
||||
void QmlEngine::setExtensionName(const QString &name)
|
||||
{
|
||||
m_extensionName = name;
|
||||
}
|
||||
|
||||
QString QmlEngine::extensionPath()
|
||||
{
|
||||
return m_extensionPath;
|
||||
}
|
||||
|
||||
void QmlEngine::setExtensionPath(const QString &path)
|
||||
{
|
||||
m_extensionPath = path;
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/* ============================================================
|
||||
* 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 "qmlplugin.h"
|
||||
#include "qmlplugins.h"
|
||||
#include "qmlpluginloader.h"
|
||||
#include "datapaths.h"
|
||||
#include "desktopfile.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
|
||||
QmlPlugin::QmlPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
Plugins::Plugin QmlPlugin::loadPlugin(const QString &name)
|
||||
{
|
||||
static bool qmlSupportLoaded = false;
|
||||
if (!qmlSupportLoaded) {
|
||||
QmlPlugins::registerQmlTypes();
|
||||
qmlSupportLoaded = true;
|
||||
}
|
||||
|
||||
QString fullPath;
|
||||
if (QFileInfo(name).isAbsolute()) {
|
||||
fullPath = name;
|
||||
} else {
|
||||
fullPath = DataPaths::locate(DataPaths::Plugins, name);
|
||||
if (fullPath.isEmpty()) {
|
||||
qWarning() << "QML plugin" << name << "not found";
|
||||
return Plugins::Plugin();
|
||||
}
|
||||
}
|
||||
|
||||
Plugins::Plugin plugin;
|
||||
plugin.type = Plugins::Plugin::QmlPlugin;
|
||||
plugin.pluginId = QSL("qml:%1").arg(QFileInfo(name).fileName());
|
||||
plugin.pluginPath = fullPath;
|
||||
DesktopFile desktopFile(fullPath + QSL("/metadata.desktop"));
|
||||
plugin.pluginSpec = Plugins::createSpec(desktopFile);
|
||||
plugin.data = QVariant::fromValue(new QmlPluginLoader(plugin.pluginSpec.name, fullPath));
|
||||
return plugin;
|
||||
}
|
||||
|
||||
void QmlPlugin::initPlugin(Plugins::Plugin *plugin)
|
||||
{
|
||||
Q_ASSERT(plugin->type == Plugins::Plugin::QmlPlugin);
|
||||
|
||||
const QString name = plugin->pluginSpec.name;
|
||||
|
||||
auto qmlPluginLoader = plugin->data.value<QmlPluginLoader*>();
|
||||
if (!qmlPluginLoader) {
|
||||
qWarning() << "Failed to cast from data";
|
||||
return;
|
||||
}
|
||||
qmlPluginLoader->createComponent();
|
||||
if (!qmlPluginLoader->instance()) {
|
||||
qWarning().noquote() << "Failed to create component for" << name << "plugin:" << qmlPluginLoader->component()->errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
plugin->instance = qobject_cast<PluginInterface*>(qmlPluginLoader->instance());
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
/* ============================================================
|
||||
* 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/>.
|
||||
* ============================================================ */
|
||||
#pragma once
|
||||
|
||||
#include "plugins.h"
|
||||
|
||||
class QmlPlugin
|
||||
{
|
||||
public:
|
||||
explicit QmlPlugin();
|
||||
static Plugins::Plugin loadPlugin(const QString &name);
|
||||
static void initPlugin(Plugins::Plugin *plugin);
|
||||
};
|
58
src/lib/plugins/qml/qmlplugincontext.cpp
Normal file
58
src/lib/plugins/qml/qmlplugincontext.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/* ============================================================
|
||||
* Falkon - Qt web browser
|
||||
* Copyright (C) 2019 David Rosca <nowrep@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 "qmlplugincontext.h"
|
||||
|
||||
#include <QtQml>
|
||||
#include <QFileInfo>
|
||||
|
||||
QmlPluginContext::QmlPluginContext(const Plugins::Plugin &plugin, QQmlEngine *engine, QObject *parent)
|
||||
: QQmlContext(engine, parent)
|
||||
, m_plugin(plugin)
|
||||
{
|
||||
}
|
||||
|
||||
QString QmlPluginContext::pluginPath() const
|
||||
{
|
||||
return m_plugin.pluginPath;
|
||||
}
|
||||
|
||||
QString QmlPluginContext::pluginName() const
|
||||
{
|
||||
return QFileInfo(m_plugin.pluginPath).fileName();
|
||||
}
|
||||
|
||||
Plugins::Plugin QmlPluginContext::plugin() const
|
||||
{
|
||||
return m_plugin;
|
||||
}
|
||||
|
||||
// static
|
||||
QmlPluginContext *QmlPluginContext::contextForObject(const QObject *object)
|
||||
{
|
||||
QQmlContext *c = qmlContext(object);
|
||||
while (c) {
|
||||
QmlPluginContext *p = qobject_cast<QmlPluginContext*>(c);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
c = c->parentContext();
|
||||
}
|
||||
qCritical() << "Failed to get plugin context for object" << object;
|
||||
Q_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/* ============================================================
|
||||
* Falkon - Qt web browser
|
||||
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
|
||||
* Copyright (C) 2019 David Rosca <nowrep@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
|
||||
@ -17,18 +17,24 @@
|
||||
* ============================================================ */
|
||||
#pragma once
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
class QmlEngine : public QQmlEngine
|
||||
#include "plugins.h"
|
||||
|
||||
class QmlPluginContext : public QQmlContext
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QmlEngine(QObject *parent = nullptr);
|
||||
QString extensionName();
|
||||
void setExtensionName(const QString &name);
|
||||
QString extensionPath();
|
||||
void setExtensionPath(const QString &path);
|
||||
explicit QmlPluginContext(const Plugins::Plugin &plugin, QQmlEngine *engine, QObject *parent = nullptr);
|
||||
|
||||
QString pluginPath() const;
|
||||
QString pluginName() const;
|
||||
|
||||
Plugins::Plugin plugin() const;
|
||||
|
||||
static QmlPluginContext *contextForObject(const QObject *object);
|
||||
|
||||
private:
|
||||
QString m_extensionName;
|
||||
QString m_extensionPath;
|
||||
Plugins::Plugin m_plugin;
|
||||
};
|
@ -31,15 +31,18 @@
|
||||
#include "api/tabs/qmltab.h"
|
||||
#include "webpage.h"
|
||||
#include "qztools.h"
|
||||
#include "qml/qmlengine.h"
|
||||
#include "qml/qmlplugincontext.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QQuickWidget>
|
||||
#include <QDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QQmlEngine>
|
||||
|
||||
QmlPluginInterface::QmlPluginInterface()
|
||||
: m_qmlReusableTab(new QmlTab())
|
||||
{
|
||||
// QQmlEngine::setContextForObject(m_qmlReusableTab, QmlPluginContext::contextForObject(this));
|
||||
}
|
||||
|
||||
QmlPluginInterface::~QmlPluginInterface()
|
||||
@ -95,11 +98,13 @@ void QmlPluginInterface::populateWebViewMenu(QMenu *menu, WebView *webview, cons
|
||||
return;
|
||||
}
|
||||
|
||||
QmlMenu *qmlMenu = new QmlMenu(menu, m_engine);
|
||||
QmlMenu *qmlMenu = new QmlMenu(menu);
|
||||
QQmlEngine::setContextForObject(qmlMenu, QmlPluginContext::contextForObject(this));
|
||||
QmlWebHitTestResult *qmlWebHitTestResult = new QmlWebHitTestResult(webHitTestResult);
|
||||
QQmlEngine::setContextForObject(qmlWebHitTestResult, QmlPluginContext::contextForObject(this));
|
||||
QJSValueList args;
|
||||
args.append(m_engine->newQObject(qmlMenu));
|
||||
args.append(m_engine->newQObject(qmlWebHitTestResult));
|
||||
args.append(qmlEngine(this)->newQObject(qmlMenu));
|
||||
args.append(qmlEngine(this)->newQObject(qmlWebHitTestResult));
|
||||
m_populateWebViewMenu.call(args);
|
||||
menu->addSeparator();
|
||||
}
|
||||
@ -125,9 +130,10 @@ bool QmlPluginInterface::mouseDoubleClick(Qz::ObjectName type, QObject *obj, QMo
|
||||
return false;
|
||||
}
|
||||
auto qmlMouseEvent = new QmlMouseEvent(event);
|
||||
QQmlEngine::setContextForObject(qmlMouseEvent, QmlPluginContext::contextForObject(this));
|
||||
QJSValueList args;
|
||||
args.append(QmlQzObjects::ObjectName(type));
|
||||
args.append(m_engine->newQObject(qmlMouseEvent));
|
||||
args.append(qmlEngine(this)->newQObject(qmlMouseEvent));
|
||||
m_mouseDoubleClick.call(args);
|
||||
qmlMouseEvent->clear();
|
||||
return false;
|
||||
@ -140,9 +146,10 @@ bool QmlPluginInterface::mousePress(Qz::ObjectName type, QObject *obj, QMouseEve
|
||||
return false;
|
||||
}
|
||||
auto qmlMouseEvent = new QmlMouseEvent(event);
|
||||
QQmlEngine::setContextForObject(qmlMouseEvent, QmlPluginContext::contextForObject(this));
|
||||
QJSValueList args;
|
||||
args.append(QmlQzObjects::ObjectName(type));
|
||||
args.append(m_engine->newQObject(qmlMouseEvent));
|
||||
args.append(qmlEngine(this)->newQObject(qmlMouseEvent));
|
||||
m_mousePress.call(args);
|
||||
qmlMouseEvent->clear();
|
||||
return false;
|
||||
@ -155,9 +162,10 @@ bool QmlPluginInterface::mouseRelease(Qz::ObjectName type, QObject *obj, QMouseE
|
||||
return false;
|
||||
}
|
||||
auto qmlMouseEvent = new QmlMouseEvent(event);
|
||||
QQmlEngine::setContextForObject(qmlMouseEvent, QmlPluginContext::contextForObject(this));
|
||||
QJSValueList args;
|
||||
args.append(QmlQzObjects::ObjectName(type));
|
||||
args.append(m_engine->newQObject(qmlMouseEvent));
|
||||
args.append(qmlEngine(this)->newQObject(qmlMouseEvent));
|
||||
m_mouseRelease.call(args);
|
||||
qmlMouseEvent->clear();
|
||||
return false;
|
||||
@ -170,9 +178,10 @@ bool QmlPluginInterface::mouseMove(Qz::ObjectName type, QObject *obj, QMouseEven
|
||||
return false;
|
||||
}
|
||||
auto qmlMouseEvent = new QmlMouseEvent(event);
|
||||
QQmlEngine::setContextForObject(qmlMouseEvent, QmlPluginContext::contextForObject(this));
|
||||
QJSValueList args;
|
||||
args.append(QmlQzObjects::ObjectName(type));
|
||||
args.append(m_engine->newQObject(qmlMouseEvent));
|
||||
args.append(qmlEngine(this)->newQObject(qmlMouseEvent));
|
||||
m_mouseMove.call(args);
|
||||
qmlMouseEvent->clear();
|
||||
return false;
|
||||
@ -185,9 +194,10 @@ bool QmlPluginInterface::wheelEvent(Qz::ObjectName type, QObject *obj, QWheelEve
|
||||
return false;
|
||||
}
|
||||
auto qmlWheelEvent = new QmlWheelEvent(event);
|
||||
QQmlEngine::setContextForObject(qmlWheelEvent, QmlPluginContext::contextForObject(this));
|
||||
QJSValueList args;
|
||||
args.append(QmlQzObjects::ObjectName(type));
|
||||
args.append(m_engine->newQObject(qmlWheelEvent));
|
||||
args.append(qmlEngine(this)->newQObject(qmlWheelEvent));
|
||||
m_wheelEvent.call(args);
|
||||
qmlWheelEvent->clear();
|
||||
return false;
|
||||
@ -200,9 +210,10 @@ bool QmlPluginInterface::keyPress(Qz::ObjectName type, QObject *obj, QKeyEvent *
|
||||
return false;
|
||||
}
|
||||
auto qmlKeyEvent = new QmlKeyEvent(event);
|
||||
QQmlEngine::setContextForObject(qmlKeyEvent, QmlPluginContext::contextForObject(this));
|
||||
QJSValueList args;
|
||||
args.append(QmlQzObjects::ObjectName(type));
|
||||
args.append(m_engine->newQObject(qmlKeyEvent));
|
||||
args.append(qmlEngine(this)->newQObject(qmlKeyEvent));
|
||||
m_keyPress.call(args);
|
||||
qmlKeyEvent->clear();
|
||||
return false;
|
||||
@ -215,9 +226,10 @@ bool QmlPluginInterface::keyRelease(Qz::ObjectName type, QObject *obj, QKeyEvent
|
||||
return false;
|
||||
}
|
||||
auto qmlKeyEvent = new QmlKeyEvent(event);
|
||||
QQmlEngine::setContextForObject(qmlKeyEvent, QmlPluginContext::contextForObject(this));
|
||||
QJSValueList args;
|
||||
args.append(QmlQzObjects::ObjectName(type));
|
||||
args.append(m_engine->newQObject(qmlKeyEvent));
|
||||
args.append(qmlEngine(this)->newQObject(qmlKeyEvent));
|
||||
m_keyRelease.call(args);
|
||||
qmlKeyEvent->clear();
|
||||
return false;
|
||||
@ -230,7 +242,7 @@ bool QmlPluginInterface::acceptNavigationRequest(WebPage *page, const QUrl &url,
|
||||
}
|
||||
m_qmlReusableTab->setWebPage(page);
|
||||
QJSValueList args;
|
||||
args.append(m_engine->newQObject(m_qmlReusableTab));
|
||||
args.append(qmlEngine(this)->newQObject(m_qmlReusableTab));
|
||||
args.append(QString::fromUtf8(url.toEncoded()));
|
||||
args.append(type);
|
||||
args.append(isMainFrame);
|
||||
@ -267,16 +279,6 @@ void QmlPluginInterface::setTestPlugin(const QJSValue &testPlugin)
|
||||
m_testPlugin = testPlugin;
|
||||
}
|
||||
|
||||
void QmlPluginInterface::setEngine(QQmlEngine *engine)
|
||||
{
|
||||
m_engine = engine;
|
||||
}
|
||||
|
||||
void QmlPluginInterface::setName(const QString &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
QJSValue QmlPluginInterface::readPopulateWebViewMenu() const
|
||||
{
|
||||
return m_populateWebViewMenu;
|
||||
|
@ -53,8 +53,6 @@ public:
|
||||
void init(InitState state, const QString &settingsPath) override;
|
||||
void unload() override;
|
||||
bool testPlugin() override;
|
||||
void setEngine(QQmlEngine *engine);
|
||||
void setName(const QString &name);
|
||||
void populateWebViewMenu(QMenu *menu, WebView *webview, const WebHitTestResult &webHitTestResult) override;
|
||||
void showSettings(QWidget *parent = nullptr) override;
|
||||
|
||||
@ -74,7 +72,6 @@ Q_SIGNALS:
|
||||
void qmlPluginUnloaded();
|
||||
|
||||
private:
|
||||
QQmlEngine *m_engine = nullptr;
|
||||
QString m_name;
|
||||
QJSValue m_init;
|
||||
QJSValue m_unload;
|
||||
|
@ -16,42 +16,30 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#include "qmlpluginloader.h"
|
||||
#include "qmlengine.h"
|
||||
#include <QQmlContext>
|
||||
#include <QDir>
|
||||
#include "qmlplugincontext.h"
|
||||
#include "qmlplugininterface.h"
|
||||
#include "../config.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlComponent>
|
||||
|
||||
#if HAVE_LIBINTL
|
||||
#include "qml/api/i18n/qmli18n.h"
|
||||
#endif
|
||||
|
||||
QmlPluginLoader::QmlPluginLoader(const QString &name, const QString &path)
|
||||
Q_GLOBAL_STATIC(QQmlEngine, s_engine)
|
||||
|
||||
QmlPluginLoader::QmlPluginLoader(const Plugins::Plugin &plugin)
|
||||
: QObject()
|
||||
, m_plugin(plugin)
|
||||
{
|
||||
m_name = name;
|
||||
m_path = path;
|
||||
initEngineAndComponent();
|
||||
}
|
||||
|
||||
void QmlPluginLoader::createComponent()
|
||||
QString QmlPluginLoader::errorString() const
|
||||
{
|
||||
m_interface = qobject_cast<QmlPluginInterface*>(m_component->create(m_component->creationContext()));
|
||||
|
||||
if (!m_interface) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_interface->setEngine(m_engine);
|
||||
m_interface->setName(m_name);
|
||||
connect(m_interface, &QmlPluginInterface::qmlPluginUnloaded, this, [this] {
|
||||
delete m_component;
|
||||
delete m_engine;
|
||||
initEngineAndComponent();
|
||||
});
|
||||
}
|
||||
|
||||
QQmlComponent *QmlPluginLoader::component() const
|
||||
{
|
||||
return m_component;
|
||||
return m_component ? m_component->errorString() : QString();
|
||||
}
|
||||
|
||||
QmlPluginInterface *QmlPluginLoader::instance() const
|
||||
@ -59,19 +47,39 @@ QmlPluginInterface *QmlPluginLoader::instance() const
|
||||
return m_interface;
|
||||
}
|
||||
|
||||
void QmlPluginLoader::createComponent()
|
||||
{
|
||||
initEngineAndComponent();
|
||||
|
||||
m_interface = qobject_cast<QmlPluginInterface*>(m_component->create(m_context));
|
||||
if (!m_interface) {
|
||||
qWarning() << "Failed to create QmlPluginInterface!";
|
||||
return;
|
||||
}
|
||||
|
||||
connect(m_interface, &QmlPluginInterface::qmlPluginUnloaded, this, [this] {
|
||||
m_component->deleteLater();
|
||||
m_component = nullptr;
|
||||
m_context->deleteLater();
|
||||
m_context = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
void QmlPluginLoader::initEngineAndComponent()
|
||||
{
|
||||
m_engine = new QmlEngine();
|
||||
m_component = new QQmlComponent(m_engine, QDir(m_path).filePath(QStringLiteral("main.qml")));
|
||||
m_engine->setExtensionPath(m_path);
|
||||
m_engine->setExtensionName(m_name);
|
||||
if (m_component) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_component = new QQmlComponent(s_engine(), QDir(m_plugin.pluginPath).filePath(QStringLiteral("main.qml")), this);
|
||||
m_context = new QmlPluginContext(m_plugin, s_engine(), this);
|
||||
#if HAVE_LIBINTL
|
||||
auto i18n = new QmlI18n(m_name);
|
||||
m_engine->globalObject().setProperty(QSL("__falkon_i18n"), m_engine->newQObject(i18n));
|
||||
m_engine->evaluate(QSL("i18n = function (s) { return __falkon_i18n.i18n(s) };"));
|
||||
m_engine->evaluate(QSL("i18np = function (s1, s2) { return __falkon_i18n.i18np(s1, s2) }"));
|
||||
auto i18n = new QmlI18n(QFileInfo(m_plugin.pluginPath).fileName());
|
||||
s_engine()->globalObject().setProperty(QSL("__falkon_i18n"), s_engine()->newQObject(i18n));
|
||||
s_engine()->evaluate(QSL("i18n = function (s) { return __falkon_i18n.i18n(s) };"));
|
||||
s_engine()->evaluate(QSL("i18np = function (s1, s2) { return __falkon_i18n.i18np(s1, s2) }"));
|
||||
#else
|
||||
m_engine->evaluate(QSL("i18n = function (s) { return s; };"));
|
||||
m_engine->evaluate(QSL("i18np = function (s1, s2) { return s1; }"));
|
||||
s_engine()->evaluate(QSL("i18n = function (s) { return s; };"));
|
||||
s_engine()->evaluate(QSL("i18np = function (s1, s2) { return s1; }"));
|
||||
#endif
|
||||
}
|
||||
|
@ -17,30 +17,33 @@
|
||||
* ============================================================ */
|
||||
#pragma once
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlComponent>
|
||||
#include <QObject>
|
||||
|
||||
#include "qmlplugininterface.h"
|
||||
#include "plugins.h"
|
||||
|
||||
class QmlEngine;
|
||||
class QQmlComponent;
|
||||
|
||||
class QmlPluginContext;
|
||||
class QmlPluginInterface;
|
||||
|
||||
class QmlPluginLoader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlPluginLoader(const QString &name, const QString &path);
|
||||
void createComponent();
|
||||
QQmlComponent *component() const;
|
||||
explicit QmlPluginLoader(const Plugins::Plugin &plugin);
|
||||
|
||||
QString errorString() const;
|
||||
QmlPluginInterface *instance() const;
|
||||
|
||||
void createComponent();
|
||||
|
||||
private:
|
||||
QString m_path;
|
||||
QString m_name;
|
||||
QmlEngine *m_engine = nullptr;
|
||||
void initEngineAndComponent();
|
||||
|
||||
Plugins::Plugin m_plugin;
|
||||
QmlPluginContext *m_context = nullptr;
|
||||
QQmlComponent *m_component = nullptr;
|
||||
QmlPluginInterface *m_interface = nullptr;
|
||||
|
||||
void initEngineAndComponent();
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QmlPluginLoader *)
|
||||
|
@ -17,7 +17,7 @@
|
||||
* ============================================================ */
|
||||
#include "qmlplugins.h"
|
||||
#include "qmlplugininterface.h"
|
||||
#include "qmlengine.h"
|
||||
#include "qmlplugincontext.h"
|
||||
#include "api/bookmarks/qmlbookmarktreenode.h"
|
||||
#include "api/bookmarks/qmlbookmarks.h"
|
||||
#include "api/topsites/qmlmostvisitedurl.h"
|
||||
@ -116,15 +116,17 @@ void QmlPlugins::registerQmlTypes()
|
||||
qmlRegisterSingletonType<QmlNotifications>(url, majorVersion, minorVersion, "Notifications", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(scriptEngine)
|
||||
|
||||
QmlEngine *qmlEngine = qobject_cast<QmlEngine*>(engine);
|
||||
#if 0
|
||||
auto context = qobject_cast<QmlEngine*>(engine);
|
||||
if (!qmlEngine) {
|
||||
qWarning() << "Unable to cast QQmlEngine * to QmlEngine *";
|
||||
return nullptr;
|
||||
}
|
||||
QString filePath = qmlEngine->extensionPath();
|
||||
#endif
|
||||
|
||||
auto *object = new QmlNotifications();
|
||||
object->setPluginPath(filePath);
|
||||
object->setPluginPath(QString());
|
||||
return object;
|
||||
});
|
||||
|
||||
@ -202,13 +204,15 @@ void QmlPlugins::registerQmlTypes()
|
||||
qmlRegisterSingletonType<QmlFileUtils>(url, majorVersion, minorVersion, "FileUtils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(scriptEngine)
|
||||
|
||||
#if 0
|
||||
QmlEngine *qmlEngine = qobject_cast<QmlEngine*>(engine);
|
||||
if (!qmlEngine) {
|
||||
qWarning() << "Unable to cast QQmlEngine * to QmlEngine *";
|
||||
return nullptr;
|
||||
}
|
||||
QString filePath = qmlEngine->extensionPath();
|
||||
return new QmlFileUtils(filePath);
|
||||
#endif
|
||||
return new QmlFileUtils(QString());
|
||||
});
|
||||
|
||||
qmlRegisterUncreatableType<QmlEnums>(url, majorVersion, minorVersion, "Enums", QSL("Unable to register type: Enums"));
|
||||
|
Loading…
Reference in New Issue
Block a user