Libplasma

configmodel.cpp
1/*
2 SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
3 SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "configmodel.h"
9#include "Plasma/Applet"
10#include "Plasma/Containment"
11#include "configcategory_p.h"
12#include "configview.h"
13#include "debug_p.h"
14#include "sharedqmlengine.h"
15
16#include <QDebug>
17#include <QDir>
18#include <QQmlComponent>
19#include <QQmlContext>
20#include <QQmlEngine>
21#include <QQuickItem>
22
23#include <KLocalizedString>
24#include <KQuickConfigModule>
25#include <KQuickConfigModuleLoader>
26
27#include <Plasma/Corona>
28#include <Plasma/PluginLoader>
29#include <kquickconfigmoduleloader.h>
30
31namespace PlasmaQuick
32{
33//////////////////////////////ConfigModel
34
35class ConfigModelPrivate
36{
37public:
38 ConfigModelPrivate(ConfigModel *model);
39 ~ConfigModelPrivate();
40
41 ConfigModel *q;
42 QList<ConfigCategory *> categories;
43 QPointer<Plasma::Applet> appletInterface;
45
46 void appendCategory(ConfigCategory *c);
47 void removeCategory(ConfigCategory *c);
48 void removeCategoryAt(int index);
49 void clear();
50 QVariant get(int row) const;
51
52 static ConfigCategory *categories_at(QQmlListProperty<ConfigCategory> *prop, qsizetype index);
53 static qsizetype categories_count(QQmlListProperty<ConfigCategory> *prop);
54 static void categories_append(QQmlListProperty<ConfigCategory> *prop, ConfigCategory *o);
55 static void categories_clear(QQmlListProperty<ConfigCategory> *prop);
56};
57
58ConfigModelPrivate::ConfigModelPrivate(ConfigModel *model)
59 : q(model)
60{
61}
62
63ConfigModelPrivate::~ConfigModelPrivate()
64{
65}
66
67ConfigCategory *ConfigModelPrivate::categories_at(QQmlListProperty<ConfigCategory> *prop, qsizetype index)
68{
69 ConfigModel *model = qobject_cast<ConfigModel *>(prop->object);
70 if (!model || index >= model->d->categories.count() || index < 0) {
71 return nullptr;
72 } else {
73 return model->d->categories.at(index);
74 }
75}
76
77void ConfigModelPrivate::categories_append(QQmlListProperty<ConfigCategory> *prop, ConfigCategory *o)
78{
79 ConfigModel *model = qobject_cast<ConfigModel *>(prop->object);
80 if (!o || !model) {
81 return;
82 }
83
84 if (o->parent() == prop->object) {
85 o->setParent(nullptr);
86 }
87
88 o->setParent(prop->object);
89 model->d->appendCategory(o);
90}
91
92qsizetype ConfigModelPrivate::categories_count(QQmlListProperty<ConfigCategory> *prop)
93{
94 ConfigModel *model = qobject_cast<ConfigModel *>(prop->object);
95 if (model) {
96 return model->d->categories.count();
97 } else {
98 return 0;
99 }
100}
101
102void ConfigModelPrivate::categories_clear(QQmlListProperty<ConfigCategory> *prop)
103{
104 ConfigModel *model = qobject_cast<ConfigModel *>(prop->object);
105 if (!model) {
106 return;
107 }
108
109 model->clear();
110}
111
112void ConfigModelPrivate::clear()
113{
114 q->beginResetModel();
115 while (!categories.isEmpty()) {
116 categories.first()->setParent(nullptr);
117 categories.pop_front();
118 }
119 q->endResetModel();
120 Q_EMIT q->countChanged();
121}
122
123void ConfigModelPrivate::appendCategory(ConfigCategory *c)
124{
125 if (!c) {
126 return;
127 }
128
129 q->beginInsertRows(QModelIndex(), categories.size(), categories.size());
130 categories.append(c);
131
132 auto emitChange = [this, c] {
133 const int row = categories.indexOf(c);
134 if (row > -1) {
135 QModelIndex modelIndex = q->index(row);
136 Q_EMIT q->dataChanged(modelIndex, modelIndex);
137 }
138 };
139
140 QObject::connect(c, &ConfigCategory::nameChanged, q, emitChange);
141 QObject::connect(c, &ConfigCategory::iconChanged, q, emitChange);
142 QObject::connect(c, &ConfigCategory::sourceChanged, q, emitChange);
143 QObject::connect(c, &ConfigCategory::pluginNameChanged, q, emitChange);
144 QObject::connect(c, &ConfigCategory::visibleChanged, q, emitChange);
145
146 q->endInsertRows();
147 Q_EMIT q->countChanged();
148}
149
150void ConfigModelPrivate::removeCategory(ConfigCategory *c)
151{
152 const int index = categories.indexOf(c);
153 if (index > -1) {
154 removeCategoryAt(index);
155 }
156}
157
158void ConfigModelPrivate::removeCategoryAt(int index)
159{
160 if (index < 0 || index >= categories.count()) {
161 return;
162 }
163
164 q->beginRemoveRows(QModelIndex(), index, index);
165
166 ConfigCategory *c = categories.takeAt(index);
167 if (c->parent() == q) {
168 c->deleteLater();
169 }
170
171 q->endRemoveRows();
172 Q_EMIT q->countChanged();
173}
174
175QVariant ConfigModelPrivate::get(int row) const
176{
177 QVariantMap value;
178 if (row < 0 || row >= categories.count()) {
179 return value;
180 }
181
182 value[QStringLiteral("name")] = categories.at(row)->name();
183 value[QStringLiteral("icon")] = categories.at(row)->icon();
184 value[QStringLiteral("pluginName")] = categories.at(row)->pluginName();
185 value[QStringLiteral("source")] = q->data(q->index(row, 0), ConfigModel::SourceRole);
186 value[QStringLiteral("includeMargins")] = categories.at(row)->includeMargins();
187 value[QStringLiteral("visible")] = categories.at(row)->visible();
188 value[QStringLiteral("kcm")] = q->data(q->index(row, 0), ConfigModel::KCMRole);
189
190 return value;
191}
192
193ConfigModel::ConfigModel(QObject *parent)
194 : QAbstractListModel(parent)
195 , d(new ConfigModelPrivate(this))
196{
197}
198
199ConfigModel::~ConfigModel()
200{
201 delete d;
202}
203
204int ConfigModel::rowCount(const QModelIndex &index) const
205{
206 if (index.column() > 0) {
207 return 0;
208 }
209 return d->categories.count();
210}
211
212QVariant ConfigModel::data(const QModelIndex &index, int role) const
213{
214 if (index.row() < 0 || index.row() >= d->categories.count()) {
215 return QVariant();
216 }
217 switch (role) {
218 case NameRole:
219 return d->categories.at(index.row())->name();
220 case IconRole:
221 return d->categories.at(index.row())->icon();
222 case SourceRole: {
223 const QString source = d->categories.at(index.row())->source();
224 // Quick check if source is an absolute path or not
225 if (d->appletInterface && !source.isEmpty() && !(source.startsWith(QLatin1Char('/')) && source.endsWith(QLatin1String("qml")))) {
226 return d->appletInterface.data()->fileUrl("ui", source);
227 } else {
228 return source;
229 }
230 }
231 case PluginNameRole:
232 return d->categories.at(index.row())->pluginName();
233 case IncludeMarginsRole:
234 return d->categories.at(index.row())->includeMargins();
235 case VisibleRole:
236 return d->categories.at(index.row())->visible();
237 case KCMRole: {
238 const QString pluginName = d->categories.at(index.row())->pluginName();
239 // no kcm is registered for this row, it's a normal qml-only entry
240 if (pluginName.isEmpty()) {
241 return QVariant();
242 }
243
244 if (d->kcms.contains(pluginName)) {
245 return QVariant::fromValue(d->kcms.value(pluginName));
246 }
247 auto parent = const_cast<ConfigModel *>(this);
248 auto engine = new PlasmaQuick::SharedQmlEngine(parent);
249 auto cmResult = KQuickConfigModuleLoader::loadModule(KPluginMetaData(pluginName), parent, QVariantList(), engine->engine());
250 if (KQuickConfigModule *cm = cmResult.plugin) {
251 if (QQmlContext *ctx = QQmlEngine::contextForObject(this)) {
252 // assign the ConfigModule the same QML context as we have so it can use the same QML engine as we do
253 QQmlEngine::setContextForObject(cmResult.plugin, ctx);
254 }
255
256 d->kcms[pluginName] = cm;
257 return QVariant::fromValue(cm);
258 } else {
259 qCDebug(LOG_PLASMAQUICK) << "Error loading KCM:" << cmResult.errorText;
260 return QVariant();
261 }
262 }
263 default:
264 return QVariant();
265 }
266}
267
268QHash<int, QByteArray> ConfigModel::roleNames() const
269{
270 return {
271 {NameRole, "name"},
272 {IconRole, "icon"},
273 {SourceRole, "source"},
274 {PluginNameRole, "pluginName"},
275 {IncludeMarginsRole, "includeMargins"},
276 {VisibleRole, "visible"},
277 {KCMRole, "kcm"},
278 };
279}
280
281QVariant ConfigModel::get(int row) const
282{
283 return d->get(row);
284}
285
286void ConfigModel::appendCategory(const QString &iconName, const QString &name, const QString &path, const QString &pluginName)
287{
288 ConfigCategory *cat = new ConfigCategory(this);
289 cat->setIcon(iconName);
290 cat->setName(name);
291 cat->setSource(path);
292 cat->setPluginName(pluginName);
293 d->appendCategory(cat);
294}
295
296void ConfigModel::appendCategory(const QString &iconName, const QString &name, const QString &path, const QString &pluginName, bool visible)
297{
298 ConfigCategory *cat = new ConfigCategory(this);
299 cat->setIcon(iconName);
300 cat->setName(name);
301 cat->setSource(path);
302 cat->setPluginName(pluginName);
303 cat->setVisible(visible);
304 d->appendCategory(cat);
305}
306
307void ConfigModel::appendCategory(ConfigCategory *category)
308{
309 d->appendCategory(category);
310}
311
312void ConfigModel::removeCategory(ConfigCategory *category)
313{
314 d->removeCategory(category);
315}
316
317void ConfigModel::removeCategoryAt(int index)
318{
319 d->removeCategoryAt(index);
320}
321
322void ConfigModel::clear()
323{
324 d->clear();
325}
326
327void ConfigModel::setApplet(Plasma::Applet *interface)
328{
329 d->appletInterface = interface;
330}
331
332Plasma::Applet *ConfigModel::applet() const
333{
334 return d->appletInterface.data();
335}
336
337QQmlListProperty<ConfigCategory> ConfigModel::categories()
338{
340 nullptr,
341 ConfigModelPrivate::categories_append,
342 ConfigModelPrivate::categories_count,
343 ConfigModelPrivate::categories_at,
344 ConfigModelPrivate::categories_clear);
345}
346
347}
348
349#include "moc_configmodel.cpp"
An object that instantiates an entire QML context, with its own declarative engine.
The base Applet class.
Definition applet.h:64
The EdgeEventForwarder class This class forwards edge events to be replayed within the given margin T...
Definition action.h:20
int column() const const
int row() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QQmlContext * contextForObject(const QObject *object)
void setContextForObject(QObject *object, QQmlContext *context)
const QChar at(qsizetype position) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
void * data()
QVariant fromValue(T &&value)
T & get(QVariant &v)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:01:35 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.