File indexing completed on 2025-02-09 06:41:25
0001 /* 0002 SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org> 0003 SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "configmodel.h" 0009 #include "Plasma/Applet" 0010 #include "Plasma/Containment" 0011 #include "configview.h" 0012 #include "debug_p.h" 0013 #include "private/configcategory_p.h" 0014 #include "sharedqmlengine.h" 0015 0016 #include <QDebug> 0017 #include <QDir> 0018 #include <QQmlComponent> 0019 #include <QQmlContext> 0020 #include <QQmlEngine> 0021 #include <QQuickItem> 0022 0023 #include <KLocalizedString> 0024 #include <KPackage/Package> 0025 #include <KQuickConfigModule> 0026 #include <KQuickConfigModuleLoader> 0027 0028 #include <Plasma/Corona> 0029 #include <Plasma/PluginLoader> 0030 #include <kquickconfigmoduleloader.h> 0031 0032 namespace PlasmaQuick 0033 { 0034 //////////////////////////////ConfigModel 0035 0036 class ConfigModelPrivate 0037 { 0038 public: 0039 ConfigModelPrivate(ConfigModel *model); 0040 ~ConfigModelPrivate(); 0041 0042 ConfigModel *q; 0043 QList<ConfigCategory *> categories; 0044 QPointer<Plasma::Applet> appletInterface; 0045 QHash<QString, KQuickConfigModule *> kcms; 0046 0047 void appendCategory(ConfigCategory *c); 0048 void removeCategory(ConfigCategory *c); 0049 void removeCategoryAt(int index); 0050 void clear(); 0051 QVariant get(int row) const; 0052 0053 static ConfigCategory *categories_at(QQmlListProperty<ConfigCategory> *prop, qsizetype index); 0054 static qsizetype categories_count(QQmlListProperty<ConfigCategory> *prop); 0055 static void categories_append(QQmlListProperty<ConfigCategory> *prop, ConfigCategory *o); 0056 static void categories_clear(QQmlListProperty<ConfigCategory> *prop); 0057 }; 0058 0059 ConfigModelPrivate::ConfigModelPrivate(ConfigModel *model) 0060 : q(model) 0061 { 0062 } 0063 0064 ConfigModelPrivate::~ConfigModelPrivate() 0065 { 0066 } 0067 0068 ConfigCategory *ConfigModelPrivate::categories_at(QQmlListProperty<ConfigCategory> *prop, qsizetype index) 0069 { 0070 ConfigModel *model = qobject_cast<ConfigModel *>(prop->object); 0071 if (!model || index >= model->d->categories.count() || index < 0) { 0072 return nullptr; 0073 } else { 0074 return model->d->categories.at(index); 0075 } 0076 } 0077 0078 void ConfigModelPrivate::categories_append(QQmlListProperty<ConfigCategory> *prop, ConfigCategory *o) 0079 { 0080 ConfigModel *model = qobject_cast<ConfigModel *>(prop->object); 0081 if (!o || !model) { 0082 return; 0083 } 0084 0085 if (o->parent() == prop->object) { 0086 o->setParent(nullptr); 0087 } 0088 0089 o->setParent(prop->object); 0090 model->d->appendCategory(o); 0091 } 0092 0093 qsizetype ConfigModelPrivate::categories_count(QQmlListProperty<ConfigCategory> *prop) 0094 { 0095 ConfigModel *model = qobject_cast<ConfigModel *>(prop->object); 0096 if (model) { 0097 return model->d->categories.count(); 0098 } else { 0099 return 0; 0100 } 0101 } 0102 0103 void ConfigModelPrivate::categories_clear(QQmlListProperty<ConfigCategory> *prop) 0104 { 0105 ConfigModel *model = qobject_cast<ConfigModel *>(prop->object); 0106 if (!model) { 0107 return; 0108 } 0109 0110 model->clear(); 0111 } 0112 0113 void ConfigModelPrivate::clear() 0114 { 0115 q->beginResetModel(); 0116 while (!categories.isEmpty()) { 0117 categories.first()->setParent(nullptr); 0118 categories.pop_front(); 0119 } 0120 q->endResetModel(); 0121 Q_EMIT q->countChanged(); 0122 } 0123 0124 void ConfigModelPrivate::appendCategory(ConfigCategory *c) 0125 { 0126 if (!c) { 0127 return; 0128 } 0129 0130 q->beginInsertRows(QModelIndex(), categories.size(), categories.size()); 0131 categories.append(c); 0132 0133 auto emitChange = [this, c] { 0134 const int row = categories.indexOf(c); 0135 if (row > -1) { 0136 QModelIndex modelIndex = q->index(row); 0137 Q_EMIT q->dataChanged(modelIndex, modelIndex); 0138 } 0139 }; 0140 0141 QObject::connect(c, &ConfigCategory::nameChanged, q, emitChange); 0142 QObject::connect(c, &ConfigCategory::iconChanged, q, emitChange); 0143 QObject::connect(c, &ConfigCategory::sourceChanged, q, emitChange); 0144 QObject::connect(c, &ConfigCategory::pluginNameChanged, q, emitChange); 0145 QObject::connect(c, &ConfigCategory::visibleChanged, q, emitChange); 0146 0147 q->endInsertRows(); 0148 Q_EMIT q->countChanged(); 0149 } 0150 0151 void ConfigModelPrivate::removeCategory(ConfigCategory *c) 0152 { 0153 const int index = categories.indexOf(c); 0154 if (index > -1) { 0155 removeCategoryAt(index); 0156 } 0157 } 0158 0159 void ConfigModelPrivate::removeCategoryAt(int index) 0160 { 0161 if (index < 0 || index >= categories.count()) { 0162 return; 0163 } 0164 0165 q->beginRemoveRows(QModelIndex(), index, index); 0166 0167 ConfigCategory *c = categories.takeAt(index); 0168 if (c->parent() == q) { 0169 c->deleteLater(); 0170 } 0171 0172 q->endRemoveRows(); 0173 Q_EMIT q->countChanged(); 0174 } 0175 0176 QVariant ConfigModelPrivate::get(int row) const 0177 { 0178 QVariantMap value; 0179 if (row < 0 || row >= categories.count()) { 0180 return value; 0181 } 0182 0183 value[QStringLiteral("name")] = categories.at(row)->name(); 0184 value[QStringLiteral("icon")] = categories.at(row)->icon(); 0185 value[QStringLiteral("pluginName")] = categories.at(row)->pluginName(); 0186 value[QStringLiteral("source")] = q->data(q->index(row, 0), ConfigModel::SourceRole); 0187 value[QStringLiteral("includeMargins")] = categories.at(row)->includeMargins(); 0188 value[QStringLiteral("visible")] = categories.at(row)->visible(); 0189 value[QStringLiteral("kcm")] = q->data(q->index(row, 0), ConfigModel::KCMRole); 0190 0191 return value; 0192 } 0193 0194 ConfigModel::ConfigModel(QObject *parent) 0195 : QAbstractListModel(parent) 0196 , d(new ConfigModelPrivate(this)) 0197 { 0198 } 0199 0200 ConfigModel::~ConfigModel() 0201 { 0202 delete d; 0203 } 0204 0205 int ConfigModel::rowCount(const QModelIndex &index) const 0206 { 0207 if (index.column() > 0) { 0208 return 0; 0209 } 0210 return d->categories.count(); 0211 } 0212 0213 QVariant ConfigModel::data(const QModelIndex &index, int role) const 0214 { 0215 if (index.row() < 0 || index.row() >= d->categories.count()) { 0216 return QVariant(); 0217 } 0218 switch (role) { 0219 case NameRole: 0220 return d->categories.at(index.row())->name(); 0221 case IconRole: 0222 return d->categories.at(index.row())->icon(); 0223 case SourceRole: { 0224 const QString source = d->categories.at(index.row())->source(); 0225 // Quick check if source is an absolute path or not 0226 if (d->appletInterface && !source.isEmpty() && !(source.startsWith(QLatin1Char('/')) && source.endsWith(QLatin1String("qml")))) { 0227 if (!d->appletInterface.data()->kPackage().isValid()) { 0228 qWarning() << "wrong applet" << d->appletInterface.data()->pluginMetaData().name(); 0229 } 0230 return d->appletInterface.data()->kPackage().fileUrl("ui", source); 0231 } else { 0232 return source; 0233 } 0234 } 0235 case PluginNameRole: 0236 return d->categories.at(index.row())->pluginName(); 0237 case IncludeMarginsRole: 0238 return d->categories.at(index.row())->includeMargins(); 0239 case VisibleRole: 0240 return d->categories.at(index.row())->visible(); 0241 case KCMRole: { 0242 const QString pluginName = d->categories.at(index.row())->pluginName(); 0243 // no kcm is registered for this row, it's a normal qml-only entry 0244 if (pluginName.isEmpty()) { 0245 return QVariant(); 0246 } 0247 0248 if (d->kcms.contains(pluginName)) { 0249 return QVariant::fromValue(d->kcms.value(pluginName)); 0250 } 0251 auto parent = const_cast<ConfigModel *>(this); 0252 auto engine = new PlasmaQuick::SharedQmlEngine(parent); 0253 auto cmResult = KQuickConfigModuleLoader::loadModule(KPluginMetaData(pluginName), parent, QVariantList(), engine->engine()); 0254 if (KQuickConfigModule *cm = cmResult.plugin) { 0255 if (QQmlContext *ctx = QQmlEngine::contextForObject(this)) { 0256 // assign the ConfigModule the same QML context as we have so it can use the same QML engine as we do 0257 QQmlEngine::setContextForObject(cmResult.plugin, ctx); 0258 } 0259 0260 d->kcms[pluginName] = cm; 0261 return QVariant::fromValue(cm); 0262 } else { 0263 qCDebug(LOG_PLASMAQUICK) << "Error loading KCM:" << cmResult.errorText; 0264 return QVariant(); 0265 } 0266 } 0267 default: 0268 return QVariant(); 0269 } 0270 } 0271 0272 QHash<int, QByteArray> ConfigModel::roleNames() const 0273 { 0274 return { 0275 {NameRole, "name"}, 0276 {IconRole, "icon"}, 0277 {SourceRole, "source"}, 0278 {PluginNameRole, "pluginName"}, 0279 {IncludeMarginsRole, "includeMargins"}, 0280 {VisibleRole, "visible"}, 0281 {KCMRole, "kcm"}, 0282 }; 0283 } 0284 0285 QVariant ConfigModel::get(int row) const 0286 { 0287 return d->get(row); 0288 } 0289 0290 void ConfigModel::appendCategory(const QString &iconName, const QString &name, const QString &path, const QString &pluginName) 0291 { 0292 ConfigCategory *cat = new ConfigCategory(this); 0293 cat->setIcon(iconName); 0294 cat->setName(name); 0295 cat->setSource(path); 0296 cat->setPluginName(pluginName); 0297 d->appendCategory(cat); 0298 } 0299 0300 void ConfigModel::appendCategory(const QString &iconName, const QString &name, const QString &path, const QString &pluginName, bool visible) 0301 { 0302 ConfigCategory *cat = new ConfigCategory(this); 0303 cat->setIcon(iconName); 0304 cat->setName(name); 0305 cat->setSource(path); 0306 cat->setPluginName(pluginName); 0307 cat->setVisible(visible); 0308 d->appendCategory(cat); 0309 } 0310 0311 void ConfigModel::appendCategory(ConfigCategory *category) 0312 { 0313 d->appendCategory(category); 0314 } 0315 0316 void ConfigModel::removeCategory(ConfigCategory *category) 0317 { 0318 d->removeCategory(category); 0319 } 0320 0321 void ConfigModel::removeCategoryAt(int index) 0322 { 0323 d->removeCategoryAt(index); 0324 } 0325 0326 void ConfigModel::clear() 0327 { 0328 d->clear(); 0329 } 0330 0331 void ConfigModel::setApplet(Plasma::Applet *interface) 0332 { 0333 d->appletInterface = interface; 0334 } 0335 0336 Plasma::Applet *ConfigModel::applet() const 0337 { 0338 return d->appletInterface.data(); 0339 } 0340 0341 QQmlListProperty<ConfigCategory> ConfigModel::categories() 0342 { 0343 return QQmlListProperty<ConfigCategory>(this, 0344 nullptr, 0345 ConfigModelPrivate::categories_append, 0346 ConfigModelPrivate::categories_count, 0347 ConfigModelPrivate::categories_at, 0348 ConfigModelPrivate::categories_clear); 0349 } 0350 0351 } 0352 0353 #include "moc_configmodel.cpp"