KCMUtils

kquickconfigmodule.cpp
1/*
2 SPDX-FileCopyrightText: 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
3 SPDX-FileCopyrightText: 2001 Michael Goffioul <kdeprint@swing.be>
4 SPDX-FileCopyrightText: 2004 Frans Englich <frans.englich@telia.com>
5 SPDX-FileCopyrightText: 2009 Dario Freddi <drf@kde.org>
6 SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
7 SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
8
9 SPDX-License-Identifier: LGPL-2.0-or-later
10*/
11
12#include "kquickconfigmodule.h"
13#include "kabstractconfigmodule.h"
14#include "kcmutils_debug.h"
15#include "sharedqmlengine_p.h"
16
17#include <QDebug>
18#include <QQmlContext>
19#include <QQmlEngine>
20#include <QQmlFileSelector>
21#include <QQuickItem>
22#include <QResource>
23#include <QUrl>
24
25#include <KLocalizedContext>
26#include <KLocalizedString>
27
28#include <memory>
29
30class KQuickConfigModulePrivate
31{
32public:
33 KQuickConfigModulePrivate(KQuickConfigModule *module)
34 : q(module)
35 {
36 }
37
39 SharedQmlEngine *engine = nullptr;
40 std::shared_ptr<QQmlEngine> passedInEngine;
41 QList<QQuickItem *> subPages;
42 int columnWidth = -1;
43 int currentIndex = 0;
44 QString errorString;
45
47
48 QString getResourcePath(const QString &file)
49 {
50 return QLatin1String("/kcm/") + q->metaData().pluginId() + QLatin1String("/") + file;
51 }
52 QUrl getResourceUrl(const QString &resourcePath)
53 {
54 return QUrl(QLatin1String("qrc:") + resourcePath);
55 }
56};
57
59
61 : KAbstractConfigModule(parent, metaData)
62 , d(new KQuickConfigModulePrivate(this))
63{
64}
65
66void KQuickConfigModule::setInternalEngine(const std::shared_ptr<QQmlEngine> &engine)
67{
68 d->passedInEngine = engine;
69}
70
72{
73 // in case mainUi was never called
74 if (d->engine) {
75 // delete the mainUi before removing the root object.
76 // Otherwise, we get lots of console errors about trying to read properties of null objects
77 delete d->engine->rootObject();
78 KQuickConfigModulePrivate::rootObjects.remove(d->engine->rootContext());
79 }
80}
81
82KQuickConfigModule *KQuickConfigModule::qmlAttachedProperties(QObject *object)
83{
84 // at the moment of the attached object creation, the root item is the only one that hasn't a parent
85 // only way to avoid creation of this attached for everybody but the root item
86 const QQmlEngine *engine = qmlEngine(object);
87 QQmlContext *ctx = qmlContext(object);
88
89 // Search the qml context that is the "root" for the sharedqmlobject,
90 // which is an ancestor of qmlContext(object) and the direct child of the
91 // engine's root context: we can do this assumption on the internals as
92 // we are distributed on the same repo.
93 while (ctx->parentContext() && ctx->parentContext() != engine->rootContext()) {
94 ctx = ctx->parentContext();
95 }
96
97 if (!object->parent() && KQuickConfigModulePrivate::rootObjects.contains(ctx)) {
98 return KQuickConfigModulePrivate::rootObjects.value(ctx);
99 } else {
100 return nullptr;
101 }
102}
103
104QQuickItem *KQuickConfigModule::mainUi()
105{
106 Q_ASSERT(d->passedInEngine);
107 if (d->engine) {
108 return qobject_cast<QQuickItem *>(d->engine->rootObject());
109 }
110
111 d->errorString.clear();
112 d->engine = new SharedQmlEngine(d->passedInEngine, this);
113
114 const QString componentName = metaData().pluginId();
115 KQuickConfigModulePrivate::rootObjects[d->engine->rootContext()] = this;
116 d->engine->setTranslationDomain(componentName);
117 d->engine->setInitializationDelayed(true);
118
119 const QString resourcePath = d->getResourcePath(QStringLiteral("main.qml"));
120 if (QResource r(resourcePath); !r.isValid()) {
121 d->errorString = i18n("Could not find resource '%1'", resourcePath);
122 qCWarning(KCMUTILS_LOG) << "Could not find resource" << resourcePath;
123 return nullptr;
124 }
125
126 new QQmlFileSelector(d->engine->engine().get(), this);
127 d->engine->setSource(d->getResourceUrl(resourcePath));
128 d->engine->rootContext()->setContextProperty(QStringLiteral("kcm"), this);
129 d->engine->completeInitialization();
130
131 if (d->engine->isError()) {
132 d->errorString = d->engine->errorString();
133 return nullptr;
134 }
135
137
138 return qobject_cast<QQuickItem *>(d->engine->rootObject());
139}
140
141void KQuickConfigModule::push(const QString &fileName, const QVariantMap &initialProperties)
142{
143 // ensure main ui is created
144 if (!mainUi()) {
145 return;
146 }
147
148 const QString resourcePath = d->getResourcePath(fileName);
149 if (QResource r(resourcePath); !r.isValid()) {
150 qCWarning(KCMUTILS_LOG) << "Requested resource" << resourcePath << "does not exist";
151 }
152 QObject *object = d->engine->createObjectFromSource(d->getResourceUrl(resourcePath), d->engine->rootContext(), initialProperties);
153
155 if (!item) {
156 if (object) {
157 object->deleteLater();
158 }
159 return;
160 }
161
162 d->subPages << item;
163 Q_EMIT pagePushed(item);
164 Q_EMIT depthChanged(depth());
165 setCurrentIndex(d->currentIndex + 1);
166}
167
169{
170 // ensure main ui is created
171 if (!mainUi()) {
172 return;
173 }
174
175 d->subPages << item;
176 Q_EMIT pagePushed(item);
177 Q_EMIT depthChanged(depth());
178 setCurrentIndex(d->currentIndex + 1);
179}
180
182{
183 if (QQuickItem *page = takeLast()) {
184 page->deleteLater();
185 }
186}
187
189{
190 if (d->subPages.isEmpty()) {
191 return nullptr;
192 }
193 QQuickItem *page = d->subPages.takeLast();
195 Q_EMIT depthChanged(depth());
196 setCurrentIndex(qMin(d->currentIndex, depth() - 1));
197 return page;
198}
199
200int KQuickConfigModule::columnWidth() const
201{
202 return d->columnWidth;
203}
204
206{
207 if (d->columnWidth == width) {
208 return;
209 }
210
211 d->columnWidth = width;
213}
214
215int KQuickConfigModule::depth() const
216{
217 return d->subPages.count() + 1;
218}
219
221{
222 if (index < 0 || index > d->subPages.count() || index == d->currentIndex) {
223 return;
224 }
225
226 d->currentIndex = index;
227
229}
230
231int KQuickConfigModule::currentIndex() const
232{
233 return d->currentIndex;
234}
235
236std::shared_ptr<QQmlEngine> KQuickConfigModule::engine() const
237{
238 return d->engine->engine();
239}
240
242{
243 return d->errorString;
244}
245
246QQuickItem *KQuickConfigModule::subPage(int index) const
247{
248 return d->subPages[index];
249}
250
251#include "moc_kquickconfigmodule.cpp"
Base class for QML and QWidgets config modules.
KPluginMetaData metaData() const
Returns the metaData that was used when instantiating the plugin.
QString pluginId() const
The base class for QtQuick configuration modules.
void mainUiReady()
Emitted when the main Ui has loaded successfully and mainUi() is available.
void setColumnWidth(int width)
Sets the column width we want.
void columnWidthChanged(int width)
Emitted when the wanted column width of the kcm changes.
KQuickConfigModule(QObject *parent, const KPluginMetaData &metaData)
Base class for all QtQuick config modules.
void depthChanged(int index)
Emitted when the number of pages changed.
void pop()
pop the last page of the KCM hierarchy, the page is destroyed
void setCurrentIndex(int index)
Sets the current page index this kcm should display.
void currentIndexChanged(int index)
Emitted when the current page changed.
void pagePushed(QQuickItem *page)
Emitted when a new sub page is pushed.
QString errorString() const
The error string in case the mainUi failed to load.
~KQuickConfigModule() override
Destroys the module.
std::shared_ptr< QQmlEngine > engine() const
void pageRemoved()
Emitted when a sub page is popped.
void push(const QString &fileName, const QVariantMap &initialProperties=QVariantMap())
Push a new sub page in the KCM hierarchy: pages will be seen as a Kirigami PageRow.
QQuickItem * takeLast()
remove and return the last page of the KCM hierarchy: the popped page won't be deleted,...
QString i18n(const char *text, const TYPE &arg...)
bool remove(const Key &key)
T value(const Key &key) const const
Q_EMITQ_EMIT
QList< T > findChildren(Qt::FindChildOptions options) const const
QObject * parent() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:48:44 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.