File indexing completed on 2024-05-19 09:32:17

0001 /*
0002  *   SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
0003  *   SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org>
0004  *
0005  *   SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include <KAuthorized>
0009 #include <KCModuleData>
0010 #include <KFileUtils>
0011 #include <KPluginFactory>
0012 #include <KPluginMetaData>
0013 #include <KService>
0014 #include <QGuiApplication>
0015 #include <QStandardPaths>
0016 
0017 #include <set>
0018 
0019 #include "../systemsettings_app_debug.h"
0020 
0021 enum MetaDataSource {
0022     SystemSettings = 1,
0023     KInfoCenter = 2,
0024     All = SystemSettings | KInfoCenter,
0025 };
0026 
0027 inline QList<KPluginMetaData> findExternalKCMModules(MetaDataSource source)
0028 {
0029     const auto findExternalModulesInFilesystem = [](const QString &sourceNamespace) {
0030         const QString sourceNamespaceDirName = QStringLiteral("plasma/%1/externalmodules").arg(sourceNamespace);
0031         const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, sourceNamespaceDirName, QStandardPaths::LocateDirectory);
0032         const QStringList files = KFileUtils::findAllUniqueFiles(dirs, QStringList{QStringLiteral("*.desktop")});
0033 
0034         QList<KPluginMetaData> metaDataList;
0035         for (const QString &file : files) {
0036             KService service(file);
0037             QJsonObject kplugin;
0038             kplugin.insert(QLatin1String("Name"), service.name());
0039             kplugin.insert(QLatin1String("Icon"), service.icon());
0040             kplugin.insert(QLatin1String("Description"), service.comment());
0041 
0042             QJsonObject root;
0043             root.insert(QLatin1String("KPlugin"), kplugin);
0044             root.insert(QLatin1String("X-KDE-Weight"), service.property<int>(QStringLiteral("X-KDE-Weight")));
0045             root.insert(QLatin1String("X-KDE-KInfoCenter-Category"), service.property<QString>(QStringLiteral("X-KDE-KInfoCenter-Category")));
0046             root.insert(QLatin1String("X-KDE-System-Settings-Category"), service.property<QString>(QStringLiteral("X-KDE-System-Settings-Category")));
0047             root.insert(QLatin1String("IsExternalApp"), true);
0048 
0049             metaDataList << KPluginMetaData(root, file);
0050         }
0051         return metaDataList;
0052     };
0053 
0054     QList<KPluginMetaData> metaDataList;
0055     if (source & SystemSettings) {
0056         metaDataList << findExternalModulesInFilesystem(QStringLiteral("systemsettings"));
0057     }
0058 
0059     if (source & KInfoCenter) {
0060         metaDataList << findExternalModulesInFilesystem(QStringLiteral("kinfocenter"));
0061     }
0062 
0063     return metaDataList;
0064 }
0065 
0066 inline QList<KPluginMetaData> findKCMsMetaData(MetaDataSource source)
0067 {
0068     QList<KPluginMetaData> modules;
0069     std::set<QString> uniquePluginIds;
0070 
0071     auto filter = [](const KPluginMetaData &data) {
0072         const auto supportedPlatforms = data.value(QStringLiteral("X-KDE-OnlyShowOnQtPlatforms"), QStringList());
0073         return supportedPlatforms.isEmpty() || supportedPlatforms.contains(qGuiApp->platformName());
0074     };
0075 
0076     // We need the exist calls because otherwise the trader language aborts if the property doesn't exist and the second part of the or is not evaluated
0077     QList<KPluginMetaData> metaDataList = KPluginMetaData::findPlugins(QStringLiteral("plasma/kcms"), filter);
0078     if (source & SystemSettings) {
0079         metaDataList << KPluginMetaData::findPlugins(QStringLiteral("plasma/kcms/systemsettings"), filter);
0080         metaDataList << KPluginMetaData::findPlugins(QStringLiteral("plasma/kcms/systemsettings_qwidgets"), filter);
0081     }
0082     if (source & KInfoCenter) {
0083         metaDataList << KPluginMetaData::findPlugins(QStringLiteral("plasma/kcms/kinfocenter"), filter);
0084     }
0085     for (const auto &m : std::as_const(metaDataList)) {
0086         // We check both since porting a module to loading view KPluginMetaData drops ".desktop" from the pluginId()
0087         if (!KAuthorized::authorizeControlModule(m.pluginId())) {
0088             continue;
0089         }
0090         modules << m;
0091         const bool inserted = uniquePluginIds.insert(m.pluginId()).second;
0092         if (!inserted) {
0093             qWarning() << "the plugin" << m.pluginId() << " was found in multiple namespaces";
0094         }
0095     }
0096     std::stable_sort(modules.begin(), modules.end(), [](const KPluginMetaData &m1, const KPluginMetaData &m2) {
0097         return QString::compare(m1.pluginId(), m2.pluginId(), Qt::CaseInsensitive) < 0;
0098     });
0099     return modules;
0100 }
0101 
0102 inline bool isKinfoCenterKcm(const KPluginMetaData &data)
0103 {
0104     // external module or a KCM in the namespace
0105     return data.fileName().contains(QLatin1String("/kinfocenter/"));
0106 }
0107 
0108 inline KCModuleData *loadModuleData(const KPluginMetaData &data)
0109 {
0110     if (auto factory = KPluginFactory::loadFactory(data).plugin) {
0111         return factory->create<KCModuleData>();
0112     }
0113     return nullptr;
0114 }