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#ifndef KQUICKCONFIGMODULE_H
13#define KQUICKCONFIGMODULE_H
14
15#include "kcmutilsquick_export.h"
16
17#include <QObject>
18#include <QQmlComponent>
19#include <QStringList>
20#include <QVariant>
21
22#include <KPluginFactory>
23#include <KPluginMetaData>
24
25#include <memory>
26#include <qqmlintegration.h>
27
28#include "kabstractconfigmodule.h"
29#include "kquickconfigmoduleloader.h"
30
31class QQuickItem;
32class QQmlEngine;
33class KQuickConfigModulePrivate;
34
35/**
36 * @class KQuickConfigModule kquickconfigmodule.h KQuickConfigModule
37 *
38 * The base class for QtQuick configuration modules.
39 * Configuration modules are realized as plugins that are dynamically loaded.
40 *
41 * All the necessary glue logic and the GUI bells and whistles
42 * are provided by the control center and must not concern
43 * the module author.
44 *
45 * To write a config module, you have to create a C++ plugin
46 * and an accompaning QML user interface.
47 *
48 * To allow KCMUtils to load your ConfigModule subclass, you must create a KPluginFactory implementation.
49 *
50 * \code
51 * #include <KPluginFactory>
52 *
53 * K_PLUGIN_CLASS_WITH_JSON(MyConfigModule, "yourmetadata.json")
54 * \endcode
55 *
56 * The constructor of the ConfigModule then looks like this:
57 * \code
58 * YourConfigModule::YourConfigModule(QObject *parent, const KPluginMetaData &metaData)
59 * : KQuickConfigModule(parent, metaData)
60 * {
61 * }
62 * \endcode
63 *
64 * The QML part must be in the KPackage format, installed under share/kpackage/kcms.
65 * @see KPackage::Package
66 *
67 * The package must have the same name as the plugin filename, to be installed
68 * by CMake with the command:
69 * \code
70 * kpackage_install_package(packagedir kcm_yourconfigmodule kcms)
71 * \endcode
72 * The "packagedir" is the subdirectory in the source tree where the package sources are
73 * located, and "kcm_yourconfigmodule" is id of the plugin.
74 * Finally "kcms" is the literal string "kcms", so that the package is
75 * installed as a configuration module (and not some other kind of package).
76 *
77 * The QML part can access all the properties of ConfigModule (together with the properties
78 * defined in its subclass) by accessing to the global object "kcm", or with the
79 * import of "org.kde.kcmutils" the ConfigModule attached property.
80 *
81 * \code
82 * import QtQuick
83 * import QtQuick.Controls as QQC2
84 * import org.kde.kcmutils as KCMUtils
85 * import org.kde.kirigami as Kirigami
86 *
87 * Item {
88 * // implicit size will be used as initial size when loaded in kcmshell6
89 * implicitWidth: Kirigami.Units.gridUnit * 30
90 * implicitHeight: Kirigami.Units.gridUnit * 30
91 *
92 * KCMUtils.ConfigModule.buttons: KCMUtils.ConfigModule.Help | KCMUtils.ConfigModule.Apply
93 *
94 * QQC2.Label {
95 * // The following two bindings are equivalent:
96 * text: kcm.needsSave
97 * enabled: KCMUtils.ConfigModule.needsSave
98 * }
99 * }
100 * \endcode
101 *
102 * See https://develop.kde.org/docs/extend/kcm/ for more detailed documentation.
103 * @since 6.0
104 */
105class KCMUTILSQUICK_EXPORT KQuickConfigModule : public KAbstractConfigModule
106{
107 Q_OBJECT
108
109 Q_PROPERTY(QQuickItem *mainUi READ mainUi CONSTANT)
110 Q_PROPERTY(int columnWidth READ columnWidth WRITE setColumnWidth NOTIFY columnWidthChanged)
111 Q_PROPERTY(int depth READ depth NOTIFY depthChanged)
112 Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
113
114 QML_NAMED_ELEMENT(ConfigModule)
115
116public:
117 /**
118 * Destroys the module.
119 */
120 ~KQuickConfigModule() override;
121
122 /**
123 * @return the qml engine that built the main config UI
124 */
125 std::shared_ptr<QQmlEngine> engine() const;
126
127 /**
128 * The error string in case the mainUi failed to load.
129 */
130 QString errorString() const;
131
132 // QML property accessors
133
134 /**
135 * @return The main UI for this configuration module. It's a QQuickItem coming from
136 * the QML package named the same as the KAboutData's component name for
137 * this config module
138 */
139 QQuickItem *mainUi();
140
141 /*
142 * @return a subpage at a given depth
143 * @note This does not include the mainUi. i.e a depth of 2 is a mainUi and one subPage
144 * at index 0
145 */
146 QQuickItem *subPage(int index) const;
147
148 /**
149 * returns the width the kcm wants in column mode.
150 * If a columnWidth is valid ( > 0 ) and less than the systemsettings' view width,
151 * more than one will be visible at once, and the first page will be a sidebar to the last page pushed.
152 * As default, this is -1 which will make the shell always show only one page at a time.
153 */
154 int columnWidth() const;
155
156 /**
157 * Sets the column width we want.
158 */
159 void setColumnWidth(int width);
160
161 /**
162 * @returns how many pages this kcm has.
163 * It is guaranteed to be at least 1 (the main ui) plus how many times a new page has been pushed without pop
164 */
165 int depth() const;
166
167 /**
168 * Sets the current page index this kcm should display
169 */
170 void setCurrentIndex(int index);
171
172 /**
173 * @returns the index of the page this kcm should display
174 */
175 int currentIndex() const;
176
177 static KQuickConfigModule *qmlAttachedProperties(QObject *object);
178
179public Q_SLOTS:
180 /**
181 * Push a new sub page in the KCM hierarchy: pages will be seen as a Kirigami PageRow
182 */
183 void push(const QString &fileName, const QVariantMap &initialProperties = QVariantMap());
184
185 /**
186 *
187 */
188 void push(QQuickItem *item);
189
190 /**
191 * pop the last page of the KCM hierarchy, the page is destroyed
192 */
193 void pop();
194
195 /**
196 * remove and return the last page of the KCM hierarchy:
197 * the popped page won't be deleted, it's the caller's responsibility to manage the lifetime of the returned item
198 * @returns the last page if any, nullptr otherwise
199 */
200 QQuickItem *takeLast();
201
202Q_SIGNALS:
203
204 // QML NOTIFY signaling
205
206 /**
207 * Emitted when a new sub page is pushed
208 */
209 void pagePushed(QQuickItem *page);
210
211 /**
212 * Emitted when a sub page is popped
213 */
214 // RFC: page argument?
215 void pageRemoved();
216
217 /**
218 * Emitted when the wanted column width of the kcm changes
219 */
220 void columnWidthChanged(int width);
221
222 /**
223 * Emitted when the current page changed
224 */
225 void currentIndexChanged(int index);
226
227 /**
228 * Emitted when the number of pages changed
229 */
230 void depthChanged(int index);
231
232 /**
233 * Emitted when the main Ui has loaded successfully and `mainUi()` is available
234 */
235 void mainUiReady();
236
237protected:
238 /**
239 * Base class for all QtQuick config modules.
240 * Use KQuickConfigModuleLoader to instantiate this class
241 *
242 * @note do not emit changed signals here, since they are not yet connected to any slot.
243 */
244 explicit KQuickConfigModule(QObject *parent, const KPluginMetaData &metaData);
245
246private:
247 void setInternalEngine(const std::shared_ptr<QQmlEngine> &engine);
248 friend KPluginFactory::Result<KQuickConfigModule>
249 KQuickConfigModuleLoader::loadModule(const KPluginMetaData &metaData, QObject *parent, const QVariantList &args, const std::shared_ptr<QQmlEngine> &engine);
250 const std::unique_ptr<KQuickConfigModulePrivate> d;
251};
252
253QML_DECLARE_TYPEINFO(KQuickConfigModule, QML_HAS_ATTACHED_PROPERTIES)
254
255#endif // KQUICKCONFIGMODULE_H
256

source code of kcmutils/src/qml/kquickconfigmodule.h