Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# SPDX-FileCopyrightText: 2022 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_library(KF6KCMUtilsQuick
|
||||
kquickconfigmodule.cpp
|
||||
kquickmanagedconfigmodule.cpp
|
||||
sharedqmlengine.cpp
|
||||
kquickconfigmoduleloader.cpp
|
||||
)
|
||||
|
||||
qt_extract_metatypes(KF6KCMUtilsQuick)
|
||||
|
||||
ecm_generate_export_header(KF6KCMUtilsQuick
|
||||
BASE_NAME KCMUtilsQuick
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF_VERSION}
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
)
|
||||
target_include_directories(KF6KCMUtilsQuick INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KCMUtilsQuick>")
|
||||
|
||||
target_link_libraries(KF6KCMUtilsQuick
|
||||
PUBLIC
|
||||
KF6::CoreAddons
|
||||
KF6::ConfigCore
|
||||
Qt6::Qml
|
||||
KF6KCMUtilsCore
|
||||
PRIVATE
|
||||
KF6::I18n
|
||||
KF6::ConfigGui
|
||||
Qt6::Quick
|
||||
kcmutils_logging_STATIC
|
||||
)
|
||||
|
||||
if(TARGET KF6::I18nQml)
|
||||
target_link_libraries(KF6KCMUtilsQuick PRIVATE
|
||||
KF6::I18nQml
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(KF6KCMUtilsQuick PROPERTIES
|
||||
VERSION ${KCMUTILS_VERSION}
|
||||
SOVERSION ${KCMUTILS_SOVERSION}
|
||||
EXPORT_NAME KCMUtilsQuick)
|
||||
ecm_generate_headers(KCMUtilsQuick_HEADERS
|
||||
HEADER_NAMES
|
||||
KQuickConfigModule
|
||||
KQuickManagedConfigModule
|
||||
KQuickConfigModuleLoader
|
||||
|
||||
REQUIRED_HEADERS KCMUtilsQuick_HEADERS
|
||||
)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/kcmutilsquick_export.h
|
||||
${KCMUtilsQuick_HEADERS}
|
||||
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KCMUtilsQuick COMPONENT Devel
|
||||
)
|
||||
|
||||
install(TARGETS KF6KCMUtilsQuick EXPORT KF6KCMUtilsTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
|
||||
SPDX-FileCopyrightText: 2001 Michael Goffioul <kdeprint@swing.be>
|
||||
SPDX-FileCopyrightText: 2004 Frans Englich <frans.englich@telia.com>
|
||||
SPDX-FileCopyrightText: 2009 Dario Freddi <drf@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
||||
SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kquickconfigmodule.h"
|
||||
#include "kabstractconfigmodule.h"
|
||||
#include "kcmutils_debug.h"
|
||||
#include "sharedqmlengine_p.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlFileSelector>
|
||||
#include <QQuickItem>
|
||||
#include <QResource>
|
||||
#include <QUrl>
|
||||
|
||||
#include <KLocalizedContext>
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class KQuickConfigModulePrivate
|
||||
{
|
||||
public:
|
||||
KQuickConfigModulePrivate(KQuickConfigModule *module)
|
||||
: q(module)
|
||||
{
|
||||
}
|
||||
|
||||
KQuickConfigModule *q;
|
||||
SharedQmlEngine *engine = nullptr;
|
||||
std::shared_ptr<QQmlEngine> passedInEngine;
|
||||
QList<QQuickItem *> subPages;
|
||||
int columnWidth = -1;
|
||||
int currentIndex = 0;
|
||||
QString errorString;
|
||||
|
||||
static QHash<QQmlContext *, KQuickConfigModule *> rootObjects;
|
||||
|
||||
QString getResourcePath(const QString &file)
|
||||
{
|
||||
return QLatin1String("/kcm/") + q->metaData().pluginId() + QLatin1String("/") + file;
|
||||
}
|
||||
QUrl getResourceUrl(const QString &resourcePath)
|
||||
{
|
||||
return QUrl(QLatin1String("qrc:") + resourcePath);
|
||||
}
|
||||
};
|
||||
|
||||
QHash<QQmlContext *, KQuickConfigModule *> KQuickConfigModulePrivate::rootObjects = QHash<QQmlContext *, KQuickConfigModule *>();
|
||||
|
||||
KQuickConfigModule::KQuickConfigModule(QObject *parent, const KPluginMetaData &metaData)
|
||||
: KAbstractConfigModule(parent, metaData)
|
||||
, d(new KQuickConfigModulePrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
void KQuickConfigModule::setInternalEngine(const std::shared_ptr<QQmlEngine> &engine)
|
||||
{
|
||||
d->passedInEngine = engine;
|
||||
}
|
||||
|
||||
KQuickConfigModule::~KQuickConfigModule()
|
||||
{
|
||||
// in case mainUi was never called
|
||||
if (d->engine) {
|
||||
// delete the mainUi before removing the root object.
|
||||
// Otherwise, we get lots of console errors about trying to read properties of null objects
|
||||
delete d->engine->rootObject();
|
||||
KQuickConfigModulePrivate::rootObjects.remove(d->engine->rootContext());
|
||||
}
|
||||
}
|
||||
|
||||
KQuickConfigModule *KQuickConfigModule::qmlAttachedProperties(QObject *object)
|
||||
{
|
||||
// at the moment of the attached object creation, the root item is the only one that hasn't a parent
|
||||
// only way to avoid creation of this attached for everybody but the root item
|
||||
const QQmlEngine *engine = qmlEngine(object);
|
||||
QQmlContext *ctx = qmlContext(object);
|
||||
|
||||
// Search the qml context that is the "root" for the sharedqmlobject,
|
||||
// which is an ancestor of qmlContext(object) and the direct child of the
|
||||
// engine's root context: we can do this assumption on the internals as
|
||||
// we are distributed on the same repo.
|
||||
while (ctx->parentContext() && ctx->parentContext() != engine->rootContext()) {
|
||||
ctx = ctx->parentContext();
|
||||
}
|
||||
|
||||
if (!object->parent() && KQuickConfigModulePrivate::rootObjects.contains(ctx)) {
|
||||
return KQuickConfigModulePrivate::rootObjects.value(ctx);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
QQuickItem *KQuickConfigModule::mainUi()
|
||||
{
|
||||
Q_ASSERT(d->passedInEngine);
|
||||
if (d->engine) {
|
||||
return qobject_cast<QQuickItem *>(d->engine->rootObject());
|
||||
}
|
||||
|
||||
d->errorString.clear();
|
||||
d->engine = new SharedQmlEngine(d->passedInEngine, this);
|
||||
|
||||
const QString componentName = metaData().pluginId();
|
||||
KQuickConfigModulePrivate::rootObjects[d->engine->rootContext()] = this;
|
||||
d->engine->setTranslationDomain(componentName);
|
||||
d->engine->setInitializationDelayed(true);
|
||||
|
||||
const QString resourcePath = d->getResourcePath(QStringLiteral("main.qml"));
|
||||
if (QResource r(resourcePath); !r.isValid()) {
|
||||
d->errorString = i18n("Could not find resource '%1'", resourcePath);
|
||||
qCWarning(KCMUTILS_LOG) << "Could not find resource" << resourcePath;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
new QQmlFileSelector(d->engine->engine().get(), this);
|
||||
d->engine->setSource(d->getResourceUrl(resourcePath));
|
||||
d->engine->rootContext()->setContextProperty(QStringLiteral("kcm"), this);
|
||||
d->engine->completeInitialization();
|
||||
|
||||
if (d->engine->isError()) {
|
||||
d->errorString = d->engine->errorString();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Q_EMIT mainUiReady();
|
||||
|
||||
return qobject_cast<QQuickItem *>(d->engine->rootObject());
|
||||
}
|
||||
|
||||
void KQuickConfigModule::push(const QString &fileName, const QVariantMap &initialProperties)
|
||||
{
|
||||
// ensure main ui is created
|
||||
if (!mainUi()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString resourcePath = d->getResourcePath(fileName);
|
||||
if (QResource r(resourcePath); !r.isValid()) {
|
||||
qCWarning(KCMUTILS_LOG) << "Requested resource" << resourcePath << "does not exist";
|
||||
}
|
||||
QObject *object = d->engine->createObjectFromSource(d->getResourceUrl(resourcePath), d->engine->rootContext(), initialProperties);
|
||||
|
||||
QQuickItem *item = qobject_cast<QQuickItem *>(object);
|
||||
if (!item) {
|
||||
if (object) {
|
||||
object->deleteLater();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
d->subPages << item;
|
||||
Q_EMIT pagePushed(item);
|
||||
Q_EMIT depthChanged(depth());
|
||||
setCurrentIndex(d->currentIndex + 1);
|
||||
}
|
||||
|
||||
void KQuickConfigModule::push(QQuickItem *item)
|
||||
{
|
||||
// ensure main ui is created
|
||||
if (!mainUi()) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->subPages << item;
|
||||
Q_EMIT pagePushed(item);
|
||||
Q_EMIT depthChanged(depth());
|
||||
setCurrentIndex(d->currentIndex + 1);
|
||||
}
|
||||
|
||||
void KQuickConfigModule::pop()
|
||||
{
|
||||
if (QQuickItem *page = takeLast()) {
|
||||
page->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
QQuickItem *KQuickConfigModule::takeLast()
|
||||
{
|
||||
if (d->subPages.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
QQuickItem *page = d->subPages.takeLast();
|
||||
Q_EMIT pageRemoved();
|
||||
Q_EMIT depthChanged(depth());
|
||||
setCurrentIndex(qMin(d->currentIndex, depth() - 1));
|
||||
return page;
|
||||
}
|
||||
|
||||
int KQuickConfigModule::columnWidth() const
|
||||
{
|
||||
return d->columnWidth;
|
||||
}
|
||||
|
||||
void KQuickConfigModule::setColumnWidth(int width)
|
||||
{
|
||||
if (d->columnWidth == width) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->columnWidth = width;
|
||||
Q_EMIT columnWidthChanged(width);
|
||||
}
|
||||
|
||||
int KQuickConfigModule::depth() const
|
||||
{
|
||||
return d->subPages.count() + 1;
|
||||
}
|
||||
|
||||
void KQuickConfigModule::setCurrentIndex(int index)
|
||||
{
|
||||
if (index < 0 || index > d->subPages.count() || index == d->currentIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->currentIndex = index;
|
||||
|
||||
Q_EMIT currentIndexChanged(index);
|
||||
}
|
||||
|
||||
int KQuickConfigModule::currentIndex() const
|
||||
{
|
||||
return d->currentIndex;
|
||||
}
|
||||
|
||||
std::shared_ptr<QQmlEngine> KQuickConfigModule::engine() const
|
||||
{
|
||||
return d->engine->engine();
|
||||
}
|
||||
|
||||
QString KQuickConfigModule::errorString() const
|
||||
{
|
||||
return d->errorString;
|
||||
}
|
||||
|
||||
QQuickItem *KQuickConfigModule::subPage(int index) const
|
||||
{
|
||||
return d->subPages[index];
|
||||
}
|
||||
|
||||
#include "moc_kquickconfigmodule.cpp"
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
|
||||
SPDX-FileCopyrightText: 2001 Michael Goffioul <kdeprint@swing.be>
|
||||
SPDX-FileCopyrightText: 2004 Frans Englich <frans.englich@telia.com>
|
||||
SPDX-FileCopyrightText: 2009 Dario Freddi <drf@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
||||
SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KQUICKCONFIGMODULE_H
|
||||
#define KQUICKCONFIGMODULE_H
|
||||
|
||||
#include "kcmutilsquick_export.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlComponent>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
#include <KPluginFactory>
|
||||
#include <KPluginMetaData>
|
||||
|
||||
#include <memory>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
#include "kabstractconfigmodule.h"
|
||||
#include "kquickconfigmoduleloader.h"
|
||||
|
||||
class QQuickItem;
|
||||
class QQmlEngine;
|
||||
class KQuickConfigModulePrivate;
|
||||
|
||||
/**
|
||||
* @class KQuickConfigModule kquickconfigmodule.h KQuickConfigModule
|
||||
*
|
||||
* The base class for QtQuick configuration modules.
|
||||
* Configuration modules are realized as plugins that are dynamically loaded.
|
||||
*
|
||||
* All the necessary glue logic and the GUI bells and whistles
|
||||
* are provided by the control center and must not concern
|
||||
* the module author.
|
||||
*
|
||||
* To write a config module, you have to create a C++ plugin
|
||||
* and an accompaning QML user interface.
|
||||
*
|
||||
* To allow KCMUtils to load your ConfigModule subclass, you must create a KPluginFactory implementation.
|
||||
*
|
||||
* \code
|
||||
* #include <KPluginFactory>
|
||||
*
|
||||
* K_PLUGIN_CLASS_WITH_JSON(MyConfigModule, "yourmetadata.json")
|
||||
* \endcode
|
||||
*
|
||||
* The constructor of the ConfigModule then looks like this:
|
||||
* \code
|
||||
* YourConfigModule::YourConfigModule(QObject *parent, const KPluginMetaData &metaData)
|
||||
* : KQuickConfigModule(parent, metaData)
|
||||
* {
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* The QML part must be in the KPackage format, installed under share/kpackage/kcms.
|
||||
* @see KPackage::Package
|
||||
*
|
||||
* The package must have the same name as the plugin filename, to be installed
|
||||
* by CMake with the command:
|
||||
* \code
|
||||
* kpackage_install_package(packagedir kcm_yourconfigmodule kcms)
|
||||
* \endcode
|
||||
* The "packagedir" is the subdirectory in the source tree where the package sources are
|
||||
* located, and "kcm_yourconfigmodule" is id of the plugin.
|
||||
* Finally "kcms" is the literal string "kcms", so that the package is
|
||||
* installed as a configuration module (and not some other kind of package).
|
||||
*
|
||||
* The QML part can access all the properties of ConfigModule (together with the properties
|
||||
* defined in its subclass) by accessing to the global object "kcm", or with the
|
||||
* import of "org.kde.kcmutils" the ConfigModule attached property.
|
||||
*
|
||||
* \code
|
||||
* import QtQuick
|
||||
* import QtQuick.Controls as QQC2
|
||||
* import org.kde.kcmutils as KCMUtils
|
||||
* import org.kde.kirigami as Kirigami
|
||||
*
|
||||
* Item {
|
||||
* // implicit size will be used as initial size when loaded in kcmshell6
|
||||
* implicitWidth: Kirigami.Units.gridUnit * 30
|
||||
* implicitHeight: Kirigami.Units.gridUnit * 30
|
||||
*
|
||||
* KCMUtils.ConfigModule.buttons: KCMUtils.ConfigModule.Help | KCMUtils.ConfigModule.Apply
|
||||
*
|
||||
* QQC2.Label {
|
||||
* // The following two bindings are equivalent:
|
||||
* text: kcm.needsSave
|
||||
* enabled: KCMUtils.ConfigModule.needsSave
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* See https://develop.kde.org/docs/extend/kcm/ for more detailed documentation.
|
||||
* @since 6.0
|
||||
*/
|
||||
class KCMUTILSQUICK_EXPORT KQuickConfigModule : public KAbstractConfigModule
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QQuickItem *mainUi READ mainUi CONSTANT)
|
||||
Q_PROPERTY(int columnWidth READ columnWidth WRITE setColumnWidth NOTIFY columnWidthChanged)
|
||||
Q_PROPERTY(int depth READ depth NOTIFY depthChanged)
|
||||
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
|
||||
|
||||
QML_NAMED_ELEMENT(ConfigModule)
|
||||
QML_ATTACHED(KQuickConfigModule)
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destroys the module.
|
||||
*/
|
||||
~KQuickConfigModule() override;
|
||||
|
||||
/**
|
||||
* @return the qml engine that built the main config UI
|
||||
*/
|
||||
std::shared_ptr<QQmlEngine> engine() const;
|
||||
|
||||
/**
|
||||
* The error string in case the mainUi failed to load.
|
||||
*/
|
||||
QString errorString() const;
|
||||
|
||||
// QML property accessors
|
||||
|
||||
/**
|
||||
* @return The main UI for this configuration module. It's a QQuickItem coming from
|
||||
* the QML package named the same as the KAboutData's component name for
|
||||
* this config module
|
||||
*/
|
||||
QQuickItem *mainUi();
|
||||
|
||||
/*
|
||||
* @return a subpage at a given depth
|
||||
* @note This does not include the mainUi. i.e a depth of 2 is a mainUi and one subPage
|
||||
* at index 0
|
||||
*/
|
||||
QQuickItem *subPage(int index) const;
|
||||
|
||||
/**
|
||||
* returns the width the kcm wants in column mode.
|
||||
* If a columnWidth is valid ( > 0 ) and less than the systemsettings' view width,
|
||||
* more than one will be visible at once, and the first page will be a sidebar to the last page pushed.
|
||||
* As default, this is -1 which will make the shell always show only one page at a time.
|
||||
*/
|
||||
int columnWidth() const;
|
||||
|
||||
/**
|
||||
* Sets the column width we want.
|
||||
*/
|
||||
void setColumnWidth(int width);
|
||||
|
||||
/**
|
||||
* @returns how many pages this kcm has.
|
||||
* It is guaranteed to be at least 1 (the main ui) plus how many times a new page has been pushed without pop
|
||||
*/
|
||||
int depth() const;
|
||||
|
||||
/**
|
||||
* Sets the current page index this kcm should display
|
||||
*/
|
||||
void setCurrentIndex(int index);
|
||||
|
||||
/**
|
||||
* @returns the index of the page this kcm should display
|
||||
*/
|
||||
int currentIndex() const;
|
||||
|
||||
static KQuickConfigModule *qmlAttachedProperties(QObject *object);
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Push a new sub page in the KCM hierarchy: pages will be seen as a Kirigami PageRow
|
||||
*/
|
||||
void push(const QString &fileName, const QVariantMap &initialProperties = QVariantMap());
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void push(QQuickItem *item);
|
||||
|
||||
/**
|
||||
* pop the last page of the KCM hierarchy, the page is destroyed
|
||||
*/
|
||||
void pop();
|
||||
|
||||
/**
|
||||
* remove and return the last page of the KCM hierarchy:
|
||||
* the popped page won't be deleted, it's the caller's responsibility to manage the lifetime of the returned item
|
||||
* @returns the last page if any, nullptr otherwise
|
||||
*/
|
||||
QQuickItem *takeLast();
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
// QML NOTIFY signaling
|
||||
|
||||
/**
|
||||
* Emitted when a new sub page is pushed
|
||||
*/
|
||||
void pagePushed(QQuickItem *page);
|
||||
|
||||
/**
|
||||
* Emitted when a sub page is popped
|
||||
*/
|
||||
// RFC: page argument?
|
||||
void pageRemoved();
|
||||
|
||||
/**
|
||||
* Emitted when the wanted column width of the kcm changes
|
||||
*/
|
||||
void columnWidthChanged(int width);
|
||||
|
||||
/**
|
||||
* Emitted when the current page changed
|
||||
*/
|
||||
void currentIndexChanged(int index);
|
||||
|
||||
/**
|
||||
* Emitted when the number of pages changed
|
||||
*/
|
||||
void depthChanged(int index);
|
||||
|
||||
/**
|
||||
* Emitted when the main Ui has loaded successfully and `mainUi()` is available
|
||||
*/
|
||||
void mainUiReady();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Base class for all QtQuick config modules.
|
||||
* Use KQuickConfigModuleLoader to instantiate this class
|
||||
*
|
||||
* @note do not emit changed signals here, since they are not yet connected to any slot.
|
||||
*/
|
||||
explicit KQuickConfigModule(QObject *parent, const KPluginMetaData &metaData);
|
||||
|
||||
private:
|
||||
void setInternalEngine(const std::shared_ptr<QQmlEngine> &engine);
|
||||
friend KPluginFactory::Result<KQuickConfigModule>
|
||||
KQuickConfigModuleLoader::loadModule(const KPluginMetaData &metaData, QObject *parent, const QVariantList &args, const std::shared_ptr<QQmlEngine> &engine);
|
||||
const std::unique_ptr<KQuickConfigModulePrivate> d;
|
||||
};
|
||||
|
||||
#endif // KQUICKCONFIGMODULE_H
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kquickconfigmoduleloader.h"
|
||||
|
||||
#include "kcmutils_debug.h"
|
||||
|
||||
#include <KPluginFactory>
|
||||
#include <QJsonArray>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "kquickconfigmodule.h"
|
||||
|
||||
std::weak_ptr<QQmlEngine> s_kcmutilsCreatedEngine;
|
||||
|
||||
KPluginFactory::Result<KQuickConfigModule>
|
||||
KQuickConfigModuleLoader::loadModule(const KPluginMetaData &metaData, QObject *parent, const QVariantList &args, const std::shared_ptr<QQmlEngine> &engineArg)
|
||||
{
|
||||
const auto factoryResult = KPluginFactory::loadFactory(metaData);
|
||||
KPluginFactory::Result<KQuickConfigModule> result;
|
||||
if (!factoryResult) {
|
||||
result.errorReason = factoryResult.errorReason;
|
||||
result.errorString = factoryResult.errorString;
|
||||
result.errorText = factoryResult.errorText;
|
||||
return result;
|
||||
}
|
||||
KPluginFactory *factory = factoryResult.plugin;
|
||||
|
||||
factory->setMetaData(KPluginMetaData(metaData));
|
||||
|
||||
const QVariantList pluginArgs = QVariantList(args) << metaData.rawData().value(QLatin1String("X-KDE-KCM-Args")).toArray().toVariantList();
|
||||
if (const auto kcm = factory->create<KQuickConfigModule>(parent, pluginArgs)) {
|
||||
const std::shared_ptr<QQmlEngine> engine =
|
||||
engineArg ? engineArg : (s_kcmutilsCreatedEngine.expired() ? std::make_shared<QQmlEngine>() : s_kcmutilsCreatedEngine.lock());
|
||||
|
||||
if (!engineArg && s_kcmutilsCreatedEngine.expired()) {
|
||||
s_kcmutilsCreatedEngine = engine;
|
||||
}
|
||||
kcm->setInternalEngine(engine);
|
||||
|
||||
result.plugin = kcm;
|
||||
qCDebug(KCMUTILS_LOG) << "loaded QML KCM" << metaData.fileName();
|
||||
} else {
|
||||
result.errorReason = KPluginFactory::INVALID_KPLUGINFACTORY_INSTANTIATION;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KQUICKCONFIGMODULELOADER_H
|
||||
#define KQUICKCONFIGMODULELOADER_H
|
||||
|
||||
#include "kcmutilsquick_export.h"
|
||||
|
||||
#include <KPluginFactory>
|
||||
#include <memory>
|
||||
|
||||
class QQmlEngine;
|
||||
class KQuickConfigModule;
|
||||
|
||||
namespace KQuickConfigModuleLoader
|
||||
{
|
||||
/**
|
||||
* Loads a QML KCM from the given plugin metadata.
|
||||
* @param engine The QQmlEngine to use, if not set, an internal engine will be created. If your application has an exisiting engine, this must be passed in.
|
||||
*/
|
||||
KCMUTILSQUICK_EXPORT KPluginFactory::Result<KQuickConfigModule>
|
||||
loadModule(const KPluginMetaData &metaData, QObject *parent = nullptr, const QVariantList &args = {}, const std::shared_ptr<QQmlEngine> &engine = {});
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2019 Kevin Ottens <kevin.ottens@enioka.com>
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kquickmanagedconfigmodule.h"
|
||||
|
||||
#include <KCoreConfigSkeleton>
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
|
||||
class KQuickManagedConfigModulePrivate
|
||||
{
|
||||
public:
|
||||
KQuickManagedConfigModulePrivate(KQuickManagedConfigModule *mod)
|
||||
{
|
||||
QTimer::singleShot(0, mod, [mod]() {
|
||||
const auto skeletons = mod->findChildren<KCoreConfigSkeleton *>();
|
||||
for (auto *skeleton : skeletons) {
|
||||
mod->registerSettings(skeleton);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QList<QPointer<KCoreConfigSkeleton>> _skeletons;
|
||||
};
|
||||
|
||||
KQuickManagedConfigModule::KQuickManagedConfigModule(QObject *parent, const KPluginMetaData &metaData)
|
||||
: KQuickConfigModule(parent, metaData)
|
||||
, d(new KQuickManagedConfigModulePrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
KQuickManagedConfigModule::~KQuickManagedConfigModule() = default;
|
||||
|
||||
void KQuickManagedConfigModule::load()
|
||||
{
|
||||
for (const auto &skeleton : std::as_const(d->_skeletons)) {
|
||||
if (skeleton) {
|
||||
skeleton->load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KQuickManagedConfigModule::save()
|
||||
{
|
||||
for (const auto &skeleton : std::as_const(d->_skeletons)) {
|
||||
if (skeleton) {
|
||||
skeleton->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KQuickManagedConfigModule::defaults()
|
||||
{
|
||||
for (const auto &skeleton : std::as_const(d->_skeletons)) {
|
||||
if (skeleton) {
|
||||
skeleton->setDefaults();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool KQuickManagedConfigModule::isSaveNeeded() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KQuickManagedConfigModule::isDefaults() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void KQuickManagedConfigModule::settingsChanged()
|
||||
{
|
||||
bool needsSave = false;
|
||||
bool representsDefaults = true;
|
||||
for (const auto &skeleton : std::as_const(d->_skeletons)) {
|
||||
if (skeleton) {
|
||||
needsSave |= skeleton->isSaveNeeded();
|
||||
representsDefaults &= skeleton->isDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
if (!needsSave) {
|
||||
needsSave = isSaveNeeded();
|
||||
}
|
||||
|
||||
if (representsDefaults) {
|
||||
representsDefaults = isDefaults();
|
||||
}
|
||||
|
||||
setRepresentsDefaults(representsDefaults);
|
||||
setNeedsSave(needsSave);
|
||||
}
|
||||
|
||||
void KQuickManagedConfigModule::registerSettings(KCoreConfigSkeleton *skeleton)
|
||||
{
|
||||
if (!skeleton || d->_skeletons.contains(skeleton)) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->_skeletons.append(skeleton);
|
||||
|
||||
auto settingsChangedSlotIndex = metaObject()->indexOfMethod("settingsChanged()");
|
||||
auto settingsChangedSlot = metaObject()->method(settingsChangedSlotIndex);
|
||||
|
||||
QObject::connect(skeleton, &KCoreConfigSkeleton::configChanged, this, &KQuickManagedConfigModule::settingsChanged);
|
||||
|
||||
const auto items = skeleton->items();
|
||||
for (auto item : items) {
|
||||
const auto itemHasSignals = dynamic_cast<KConfigCompilerSignallingItem *>(item) || dynamic_cast<KPropertySkeletonItem *>(item);
|
||||
if (!itemHasSignals) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto name = item->name();
|
||||
if (name.at(0).isUpper()) {
|
||||
name[0] = name[0].toLower();
|
||||
}
|
||||
|
||||
const auto metaObject = skeleton->metaObject();
|
||||
const auto propertyIndex = metaObject->indexOfProperty(name.toUtf8().constData());
|
||||
const auto property = metaObject->property(propertyIndex);
|
||||
if (!property.hasNotifySignal()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto changedSignal = property.notifySignal();
|
||||
QObject::connect(skeleton, changedSignal, this, settingsChangedSlot);
|
||||
}
|
||||
|
||||
auto toRemove = std::remove_if(d->_skeletons.begin(), d->_skeletons.end(), [](const QPointer<KCoreConfigSkeleton> &value) {
|
||||
return value.isNull();
|
||||
});
|
||||
d->_skeletons.erase(toRemove, d->_skeletons.end());
|
||||
|
||||
QMetaObject::invokeMethod(this, "settingsChanged", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
#include "moc_kquickmanagedconfigmodule.cpp"
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2019 Kevin Ottens <kevin.ottens@enioka.com>
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef MANAGEDCONFIGMODULE_H
|
||||
#define MANAGEDCONFIGMODULE_H
|
||||
|
||||
#include "kquickconfigmodule.h"
|
||||
#include <memory>
|
||||
|
||||
class KCoreConfigSkeleton;
|
||||
|
||||
class KQuickManagedConfigModulePrivate;
|
||||
|
||||
/**
|
||||
* @class KQuickManagedConfigModule managedconfigmodule.h KQuickAddons/ManagedConfigModule
|
||||
*
|
||||
* The base class for configuration modules using KConfigXT settings.
|
||||
*
|
||||
* We are assuming here that SettingsObject is a class generated from a kcfg file
|
||||
* and that it will be somehow exposed as a constant property to be used from the QML side.
|
||||
* It will be automatically discovered by ManagedConfigModule which will update
|
||||
* the saveNeeded and defaults inherited properties by itself. Thus by inheriting from
|
||||
* this class you shall not try to manage those properties yourselves.
|
||||
* By passing in "this" as a parent, we prevent memory leaks and allow KQuickManagedConfigModule to
|
||||
* automatically find the created settings object.
|
||||
*
|
||||
* The constructor of the ConfigModule then looks like this:
|
||||
* \code
|
||||
* YourConfigModule::YourConfigModule(QObject *parent, const KPluginMetaData &metaData)
|
||||
* : ManagedConfigModule(parent, metaData)
|
||||
* , m_settingsObject(new SettingsObject(this))
|
||||
* {
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
class KCMUTILSQUICK_EXPORT KQuickManagedConfigModule : public KQuickConfigModule
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destroys the module.
|
||||
*/
|
||||
~KQuickManagedConfigModule() override;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Load the configuration data into the module.
|
||||
*
|
||||
* This method is invoked whenever the module should read its configuration
|
||||
* (most of the times from a config file) and update the user interface.
|
||||
* This happens when the user clicks the "Reset" button in the control
|
||||
* center, to undo all of his changes and restore the currently valid
|
||||
* settings. It is also called right after construction.
|
||||
*
|
||||
* By default this will load the settings from the child setting objects
|
||||
* of this module.
|
||||
*/
|
||||
void load() override;
|
||||
|
||||
/**
|
||||
* Save the configuration data.
|
||||
*
|
||||
* The save method stores the config information as shown
|
||||
* in the user interface in the config files.
|
||||
* It is called when the user clicks "Apply" or "Ok".
|
||||
*
|
||||
* By default this will save the child setting objects
|
||||
* of this module.
|
||||
*/
|
||||
void save() override;
|
||||
|
||||
/**
|
||||
* Sets the configuration to sensible default values.
|
||||
*
|
||||
* This method is called when the user clicks the "Default"
|
||||
* button. It should set the display to useful values.
|
||||
*
|
||||
* By default this will reset to defaults the child setting objects
|
||||
* of this module.
|
||||
*/
|
||||
void defaults() override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
/**
|
||||
* Forces the module to reevaluate the saveNeeded and
|
||||
* representsDefault state.
|
||||
*
|
||||
* This is required for some modules which might have
|
||||
* some settings managed outside of KConfigXT objects.
|
||||
*/
|
||||
void settingsChanged();
|
||||
|
||||
/**
|
||||
* Allow to register manually settings class generated from a kcfg file.
|
||||
* Used by derived class when automatic discovery is not possible.
|
||||
* After skeleton is registered it will automatically call settingsChanged().
|
||||
*/
|
||||
void registerSettings(KCoreConfigSkeleton *skeleton);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Base class for all KControlModules.
|
||||
* Use KQuickConfigModuleLoader to instantiate this class
|
||||
*
|
||||
* @note do not emit changed signals here, since they are not yet connected to any slot.
|
||||
*/
|
||||
explicit KQuickManagedConfigModule(QObject *parent, const KPluginMetaData &metaData);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Allows to indicate if the module requires saving.
|
||||
*
|
||||
* By default this returns false, it needs to be overridden only
|
||||
* if the module has state outside of the settings declared in
|
||||
* the KConfigXT classes it uses.
|
||||
*/
|
||||
virtual bool isSaveNeeded() const;
|
||||
|
||||
/**
|
||||
* Allows to indicate if the module state is representing its defaults.
|
||||
*
|
||||
* By default this returns true, it needs to be overridden only
|
||||
* if the module has state outside of the settings declared in
|
||||
* the KConfigXT classes it uses.
|
||||
*/
|
||||
virtual bool isDefaults() const;
|
||||
|
||||
const std::unique_ptr<KQuickManagedConfigModulePrivate> d;
|
||||
friend class KQuickManagedConfigModulePrivate;
|
||||
};
|
||||
|
||||
#endif // MANAGEDCONFIGMODULE_H
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
|
||||
SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "sharedqmlengine_p.h"
|
||||
|
||||
#include <KLocalizedQmlContext>
|
||||
#include <QDebug>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlIncubator>
|
||||
#include <QQmlNetworkAccessManagerFactory>
|
||||
#include <QQuickItem>
|
||||
#include <QResource>
|
||||
#include <QTimer>
|
||||
|
||||
#include "kcmutils_debug.h"
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
class SharedQmlEnginePrivate
|
||||
{
|
||||
public:
|
||||
SharedQmlEnginePrivate(const std::shared_ptr<QQmlEngine> &engine, SharedQmlEngine *parent)
|
||||
: q(parent)
|
||||
, component(nullptr)
|
||||
, delay(false)
|
||||
, m_engine(engine)
|
||||
{
|
||||
executionEndTimer.setInterval(0);
|
||||
executionEndTimer.setSingleShot(true);
|
||||
QObject::connect(&executionEndTimer, &QTimer::timeout, q, [this]() {
|
||||
scheduleExecutionEnd();
|
||||
});
|
||||
}
|
||||
|
||||
~SharedQmlEnginePrivate()
|
||||
{
|
||||
delete incubator.object();
|
||||
}
|
||||
|
||||
void errorPrint(QQmlComponent *component, QQmlIncubator *incubator = nullptr);
|
||||
void execute(const QUrl &source);
|
||||
void scheduleExecutionEnd();
|
||||
void minimumWidthChanged();
|
||||
void minimumHeightChanged();
|
||||
void maximumWidthChanged();
|
||||
void maximumHeightChanged();
|
||||
void preferredWidthChanged();
|
||||
void preferredHeightChanged();
|
||||
void checkInitializationCompleted();
|
||||
|
||||
SharedQmlEngine *q;
|
||||
|
||||
QUrl source;
|
||||
|
||||
QQmlIncubator incubator;
|
||||
QQmlComponent *component;
|
||||
QTimer executionEndTimer;
|
||||
KLocalizedQmlContext *context{nullptr};
|
||||
QQmlContext *rootContext;
|
||||
bool delay;
|
||||
std::shared_ptr<QQmlEngine> m_engine;
|
||||
};
|
||||
|
||||
void SharedQmlEnginePrivate::errorPrint(QQmlComponent *component, QQmlIncubator *incubator)
|
||||
{
|
||||
QList<QQmlError> errors;
|
||||
if (component && component->isError()) {
|
||||
errors = component->errors();
|
||||
} else if (incubator && incubator->isError()) {
|
||||
errors = incubator->errors();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
qCWarning(KCMUTILS_LOG).noquote() << "Error loading QML file" << component->url().toString();
|
||||
for (const auto &error : errors) {
|
||||
constexpr const QLatin1String indent(" ");
|
||||
qCWarning(KCMUTILS_LOG).noquote().nospace() << indent << error;
|
||||
}
|
||||
}
|
||||
|
||||
void SharedQmlEnginePrivate::execute(const QUrl &source)
|
||||
{
|
||||
Q_ASSERT(!source.isEmpty());
|
||||
delete component;
|
||||
component = new QQmlComponent(m_engine.get(), q);
|
||||
delete incubator.object();
|
||||
|
||||
m_engine->addImportPath(QStringLiteral("qrc:/"));
|
||||
component->loadUrl(source);
|
||||
|
||||
if (delay) {
|
||||
executionEndTimer.start(0);
|
||||
} else {
|
||||
scheduleExecutionEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void SharedQmlEnginePrivate::scheduleExecutionEnd()
|
||||
{
|
||||
if (component->isReady() || component->isError()) {
|
||||
q->completeInitialization();
|
||||
} else {
|
||||
QObject::connect(component, &QQmlComponent::statusChanged, q, [this]() {
|
||||
q->completeInitialization();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
SharedQmlEngine::SharedQmlEngine(const std::shared_ptr<QQmlEngine> &engine, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new SharedQmlEnginePrivate(engine, this))
|
||||
{
|
||||
d->rootContext = new QQmlContext(engine.get());
|
||||
d->rootContext->setParent(this); // Delete the context when deleting the shared engine
|
||||
|
||||
d->context = new KLocalizedQmlContext(d->rootContext);
|
||||
d->rootContext->setContextObject(d->context);
|
||||
}
|
||||
|
||||
SharedQmlEngine::~SharedQmlEngine() = default;
|
||||
|
||||
void SharedQmlEngine::setTranslationDomain(const QString &translationDomain)
|
||||
{
|
||||
d->context->setTranslationDomain(translationDomain);
|
||||
}
|
||||
|
||||
QString SharedQmlEngine::translationDomain() const
|
||||
{
|
||||
return d->context->translationDomain();
|
||||
}
|
||||
|
||||
void SharedQmlEngine::setSource(const QUrl &source)
|
||||
{
|
||||
d->source = source;
|
||||
d->execute(source);
|
||||
}
|
||||
|
||||
QUrl SharedQmlEngine::source() const
|
||||
{
|
||||
return d->source;
|
||||
}
|
||||
|
||||
void SharedQmlEngine::setInitializationDelayed(const bool delay)
|
||||
{
|
||||
d->delay = delay;
|
||||
}
|
||||
|
||||
bool SharedQmlEngine::isInitializationDelayed() const
|
||||
{
|
||||
return d->delay;
|
||||
}
|
||||
|
||||
std::shared_ptr<QQmlEngine> SharedQmlEngine::engine()
|
||||
{
|
||||
return d->m_engine;
|
||||
}
|
||||
|
||||
QObject *SharedQmlEngine::rootObject() const
|
||||
{
|
||||
if (d->incubator.isLoading()) {
|
||||
qCWarning(KCMUTILS_LOG) << "Trying to use rootObject before initialization is completed, whilst using setInitializationDelayed. Forcing completion";
|
||||
d->incubator.forceCompletion();
|
||||
}
|
||||
return d->incubator.object();
|
||||
}
|
||||
|
||||
QQmlComponent *SharedQmlEngine::mainComponent() const
|
||||
{
|
||||
return d->component;
|
||||
}
|
||||
|
||||
QQmlContext *SharedQmlEngine::rootContext() const
|
||||
{
|
||||
return d->rootContext;
|
||||
}
|
||||
|
||||
bool SharedQmlEngine::isError() const
|
||||
{
|
||||
return !d->m_engine || !d->component || d->component->isError() || d->incubator.isError();
|
||||
}
|
||||
|
||||
static QString qmlErrorsToString(const QList<QQmlError> &errors)
|
||||
{
|
||||
QString ret;
|
||||
for (const auto &e : errors) {
|
||||
ret += e.url().toString() + QLatin1Char(':') + QString::number(e.line()) + QLatin1Char(' ') + e.description() + QLatin1Char('\n');
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString SharedQmlEngine::errorString() const
|
||||
{
|
||||
if (d->component && d->component->isError()) {
|
||||
return d->component->errorString();
|
||||
} else if (d->incubator.isError()) {
|
||||
return qmlErrorsToString(d->incubator.errors());
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void SharedQmlEnginePrivate::checkInitializationCompleted()
|
||||
{
|
||||
if (!incubator.isReady() && !incubator.isError()) {
|
||||
QTimer::singleShot(0, q, [this]() {
|
||||
checkInitializationCompleted();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!incubator.object()) {
|
||||
errorPrint(component, &incubator);
|
||||
}
|
||||
|
||||
Q_EMIT q->finished();
|
||||
}
|
||||
|
||||
void SharedQmlEngine::completeInitialization(const QVariantMap &initialProperties)
|
||||
{
|
||||
d->executionEndTimer.stop();
|
||||
if (d->incubator.object()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->component) {
|
||||
qCWarning(KCMUTILS_LOG) << "No component for" << source();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->component->isReady()) {
|
||||
d->errorPrint(d->component);
|
||||
return;
|
||||
}
|
||||
|
||||
d->incubator.setInitialProperties(initialProperties);
|
||||
d->component->create(d->incubator, d->rootContext);
|
||||
|
||||
if (d->delay) {
|
||||
d->checkInitializationCompleted();
|
||||
} else {
|
||||
d->incubator.forceCompletion();
|
||||
|
||||
if (!d->incubator.object()) {
|
||||
d->errorPrint(d->component, &d->incubator);
|
||||
}
|
||||
Q_EMIT finished();
|
||||
}
|
||||
}
|
||||
|
||||
QObject *SharedQmlEngine::createObjectFromSource(const QUrl &source, QQmlContext *context, const QVariantMap &initialProperties)
|
||||
{
|
||||
QQmlComponent *component = new QQmlComponent(d->m_engine.get(), this);
|
||||
component->loadUrl(source);
|
||||
|
||||
return createObjectFromComponent(component, context, initialProperties);
|
||||
}
|
||||
|
||||
QObject *SharedQmlEngine::createObjectFromComponent(QQmlComponent *component, QQmlContext *context, const QVariantMap &initialProperties)
|
||||
{
|
||||
QObject *object = component->createWithInitialProperties(initialProperties, context ? context : d->rootContext);
|
||||
|
||||
if (!component->isError() && object) {
|
||||
// memory management
|
||||
const auto root = rootObject();
|
||||
object->setParent(root);
|
||||
component->setParent(object);
|
||||
|
||||
// visually reparent to root object if wasn't specified otherwise by initialProperties
|
||||
if (!initialProperties.contains(QLatin1String("parent")) && root && root->isQuickItemType()) {
|
||||
object->setProperty("parent", QVariant::fromValue(root));
|
||||
}
|
||||
return object;
|
||||
} else {
|
||||
d->errorPrint(component);
|
||||
delete object;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_sharedqmlengine_p.cpp"
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
|
||||
SPDX-FileCopyrightText:
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef PLASMA_SHAREDQMLENGINE_H
|
||||
#define PLASMA_SHAREDQMLENGINE_H
|
||||
|
||||
#include "ki18n_version.h"
|
||||
#include <QObject>
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QQmlComponent;
|
||||
class QQmlEngine;
|
||||
class KLocalizedQmlContext;
|
||||
class SharedQmlEnginePrivate;
|
||||
|
||||
|
||||
/**
|
||||
* @class Plasma::SharedQmlEngine Plasma/sharedqmlengine.h Plasma/SharedQmlEngine
|
||||
*
|
||||
* @short An object that instantiates an entire QML context, with its own declarative engine
|
||||
*
|
||||
* Plasma::SharedQmlEngine provides a class to conveniently use QML based
|
||||
* declarative user interfaces.
|
||||
* A SharedQmlEngine corresponds to one QML file (which can include others).
|
||||
* It will a shared QQmlEngine with a single root object, described in the QML file.
|
||||
*/
|
||||
class SharedQmlEngine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QUrl source READ source WRITE setSource)
|
||||
Q_PROPERTY(QString translationDomain READ translationDomain WRITE setTranslationDomain)
|
||||
Q_PROPERTY(bool initializationDelayed READ isInitializationDelayed WRITE setInitializationDelayed)
|
||||
Q_PROPERTY(QObject *rootObject READ rootObject)
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new Plasma::SharedQmlEngine
|
||||
*
|
||||
* @param parent The QObject parent for this object.
|
||||
*/
|
||||
explicit SharedQmlEngine(const std::shared_ptr<QQmlEngine> &engine, QObject *parent = nullptr);
|
||||
|
||||
~SharedQmlEngine() override;
|
||||
|
||||
/**
|
||||
* Call this method before calling setupBindings to install a translation domain for all
|
||||
* i18n global functions. If a translation domain is set all i18n calls delegate to the
|
||||
* matching i18nd calls with the provided translation domain.
|
||||
*
|
||||
* The translationDomain affects all i18n calls including those from imports. Because of
|
||||
* that modules intended to be used as imports should prefer the i18nd variants and set
|
||||
* the translation domain explicitly in each call.
|
||||
*
|
||||
* This method is only required if your declarative usage is inside a library. If it's
|
||||
* in an application there is no need to set the translation domain as the application's
|
||||
* domain can be used.
|
||||
*
|
||||
* @param translationDomain The translation domain to be used for i18n calls.
|
||||
*/
|
||||
void setTranslationDomain(const QString &translationDomain);
|
||||
|
||||
/**
|
||||
* @return the translation domain for the i18n calls done in this QML engine
|
||||
*/
|
||||
QString translationDomain() const;
|
||||
|
||||
/**
|
||||
* Sets the path of the QML file to parse and execute
|
||||
*
|
||||
* @param path the absolute path of a QML file
|
||||
*/
|
||||
void setSource(const QUrl &source);
|
||||
|
||||
/**
|
||||
* @return the absolute path of the current QML file
|
||||
*/
|
||||
QUrl source() const;
|
||||
|
||||
/**
|
||||
* Sets whether the execution of the QML file has to be delayed later in the event loop. It has to be called before setQmlPath().
|
||||
* In this case it will be possible to assign new objects in the main engine context
|
||||
* before the main component gets initialized.
|
||||
* In that case it will be possible to access it immediately from the QML code.
|
||||
* The initialization will either be completed automatically asynchronously
|
||||
* or explicitly by calling completeInitialization()
|
||||
*
|
||||
* @param delay if true the initialization of the QML file will be delayed
|
||||
* at the end of the event loop
|
||||
*/
|
||||
void setInitializationDelayed(const bool delay);
|
||||
|
||||
/**
|
||||
* @return true if the initialization of the QML file will be delayed
|
||||
* at the end of the event loop
|
||||
*/
|
||||
bool isInitializationDelayed() const;
|
||||
|
||||
/**
|
||||
* @return the declarative engine that runs the qml file assigned to this widget.
|
||||
*/
|
||||
std::shared_ptr<QQmlEngine> engine();
|
||||
|
||||
/**
|
||||
* @return the root object of the declarative object tree
|
||||
*/
|
||||
QObject *rootObject() const;
|
||||
|
||||
/**
|
||||
* @return the main QQmlComponent of the engine
|
||||
*/
|
||||
QQmlComponent *mainComponent() const;
|
||||
|
||||
/**
|
||||
* The component's creation context.
|
||||
*/
|
||||
QQmlContext *rootContext() const;
|
||||
|
||||
/*
|
||||
* The component's or incubator's error status.
|
||||
*/
|
||||
bool isError() const;
|
||||
|
||||
/*
|
||||
* The component's or incubator's error string.
|
||||
*/
|
||||
QString errorString() const;
|
||||
|
||||
/**
|
||||
* Creates and returns an object based on the provided url to a Qml file
|
||||
* with the same QQmlEngine and the same root context as the main object,
|
||||
* that will be the parent of the newly created object
|
||||
* @param source url where the QML file is located
|
||||
* @param context The QQmlContext in which we will create the object,
|
||||
* if 0 it will use the engine's root context
|
||||
* @param initialProperties optional properties that will be set on
|
||||
* the object when created (and before Component.onCompleted
|
||||
* gets emitted
|
||||
*/
|
||||
QObject *createObjectFromSource(const QUrl &source, QQmlContext *context = nullptr, const QVariantMap &initialProperties = QVariantMap());
|
||||
|
||||
/**
|
||||
* Creates and returns an object based on the provided QQmlComponent
|
||||
* with the same QQmlEngine and the same root context as the admin object,
|
||||
* that will be the parent of the newly created object
|
||||
* @param component the component we want to instantiate
|
||||
* @param context The QQmlContext in which we will create the object,
|
||||
* if 0 it will use the engine's root context
|
||||
* @param initialProperties optional properties that will be set on
|
||||
* the object when created (and before Component.onCompleted
|
||||
* gets emitted
|
||||
*/
|
||||
QObject *createObjectFromComponent(QQmlComponent *component, QQmlContext *context = nullptr, const QVariantMap &initialProperties = QVariantMap());
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Finishes the process of initialization.
|
||||
* If isInitializationDelayed() is false, calling this will have no effect.
|
||||
* @param initialProperties optional properties that will be set on
|
||||
* the object when created (and before Component.onCompleted
|
||||
* gets emitted
|
||||
*/
|
||||
void completeInitialization(const QVariantMap &initialProperties = QVariantMap());
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the parsing and execution of the QML file is terminated
|
||||
*/
|
||||
void finished();
|
||||
|
||||
private:
|
||||
const std::unique_ptr<SharedQmlEnginePrivate> d;
|
||||
};
|
||||
|
||||
#endif // multiple inclusion guard
|
||||
Reference in New Issue
Block a user