File indexing completed on 2024-05-12 15:59:03

0001 /*
0002  * SPDX-FileCopyrightText: 2006-2016 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "KoPluginLoader.h"
0008 
0009 #include <KoJsonTrader.h>
0010 
0011 #include <QJsonObject>
0012 #include <QPluginLoader>
0013 
0014 #include "kis_debug.h"
0015 
0016 #include <kis_debug.h>
0017 
0018 #include <KConfig>
0019 #include <KSharedConfig>
0020 #include <KConfigGroup>
0021 #include <KPluginFactory>
0022 
0023 class Q_DECL_HIDDEN KoPluginLoader::Private
0024 {
0025 public:
0026     QStringList loadedServiceTypes;
0027 };
0028 
0029 KoPluginLoader::KoPluginLoader()
0030         : d(new Private())
0031 {
0032 }
0033 
0034 KoPluginLoader::~KoPluginLoader()
0035 {
0036     delete d;
0037 }
0038 
0039 Q_GLOBAL_STATIC(KoPluginLoader, pluginLoaderInstance)
0040 
0041 KoPluginLoader* KoPluginLoader::instance()
0042 {
0043     return pluginLoaderInstance();
0044 }
0045 
0046 void KoPluginLoader::load(const QString & serviceType, const QString & versionString, const PluginsConfig &config, QObject* owner, bool cache)
0047 {
0048 
0049     // Don't load the same plugins again
0050     if (cache && d->loadedServiceTypes.contains(serviceType)) {
0051         return;
0052     }
0053     d->loadedServiceTypes << serviceType;
0054     QString query = QString::fromLatin1("(Type == 'Service')");
0055     if (!versionString.isEmpty()) {
0056         query += QString::fromLatin1(" and (%1)").arg(versionString);
0057     }
0058 
0059     QList<KoJsonTrader::Plugin> offers = KoJsonTrader::instance()->query(serviceType, QString());
0060 
0061     QList<KoJsonTrader::Plugin> plugins;
0062 
0063     bool configChanged = false;
0064     QList<QString> blacklist; // what we will save out afterwards
0065     if (config.whiteList && config.blacklist && config.group) {
0066         dbgPlugins << "Loading" << serviceType << "with checking the config";
0067         KConfigGroup configGroup(KSharedConfig::openConfig(), config.group);
0068         QList<QString> whiteList = configGroup.readEntry(config.whiteList, config.defaults);
0069         QList<QString> knownList;
0070 
0071         // if there was no list of defaults; all plugins are loaded.
0072         const bool firstStart = !config.defaults.isEmpty() && !configGroup.hasKey(config.whiteList);
0073         knownList = configGroup.readEntry(config.blacklist, knownList);
0074         if (firstStart) {
0075             configChanged = true;
0076         }
0077         Q_FOREACH (const KoJsonTrader::Plugin &loader, offers) {
0078             QJsonObject json = loader.metaData().value("MetaData").toObject();
0079             if (json.contains("KPlugin")) {
0080                 json = json.value("KPlugin").toObject();
0081             }
0082             const QString pluginName = json.value("Id").toString();
0083             if (pluginName.isEmpty()) {
0084                 qWarning() << "Loading plugin" << loader.fileName() << "failed, has no X-KDE-PluginInfo-Name.";
0085                 continue;
0086             }
0087 
0088             if (whiteList.contains(pluginName)) {
0089                 plugins.append(loader);
0090             }
0091             else if (!firstStart && !knownList.contains(pluginName)) { // also load newly installed plugins.
0092                 plugins.append(loader);
0093                 configChanged = true;
0094             }
0095             else {
0096                 blacklist << pluginName;
0097             }
0098         }
0099     } else {
0100         plugins = offers;
0101     }
0102 
0103     QMap<QString, KoJsonTrader::Plugin> serviceNames;
0104     Q_FOREACH (const KoJsonTrader::Plugin &loader, plugins) {
0105         if (serviceNames.contains(loader.fileName())) { // duplicate
0106             QJsonObject json2 = loader.metaData().value("MetaData").toObject();
0107             QVariant pluginVersion2 = json2.value("X-Flake-PluginVersion").toVariant();
0108             if (pluginVersion2.isNull()) { // just take the first one found...
0109                 continue;
0110             }
0111             KoJsonTrader::Plugin currentLoader = serviceNames.value(loader.fileName());
0112             QJsonObject json = currentLoader.metaData().value("MetaData").toObject();
0113             QVariant pluginVersion = json.value("X-Flake-PluginVersion").toVariant();
0114             if (!(pluginVersion.isNull() || pluginVersion.toInt() < pluginVersion2.toInt())) {
0115                 continue; // replace the old one with this one, since its newer.
0116             }
0117         }
0118         serviceNames.insert(loader.fileName(), loader);
0119     }
0120 
0121     QList<QString> whiteList;
0122     Q_FOREACH (const QString &serviceName, serviceNames.keys()) {
0123         dbgPlugins << "loading" << serviceName;
0124         KoJsonTrader::Plugin loader = serviceNames[serviceName];
0125         KPluginFactory *factory = qobject_cast<KPluginFactory *>(loader.instance());
0126         QObject *plugin = 0;
0127         if (factory) {
0128             plugin = factory->create<QObject>(owner ? owner : this, QVariantList());
0129         }
0130         if (plugin) {
0131             QJsonObject json = loader.metaData().value("MetaData").toObject();
0132             json = json.value("KPlugin").toObject();
0133             const QString pluginName = json.value("Id").toString();
0134             whiteList << pluginName;
0135             dbgPlugins << "\tLoaded plugin" << loader.fileName() << owner;
0136             if (!owner) {
0137                 delete plugin;
0138             }
0139         } else {
0140             qWarning() << "Loading plugin" << loader.fileName() << "failed, " << loader.errorString();
0141         }
0142     }
0143 
0144     if (configChanged && config.whiteList && config.blacklist && config.group) {
0145         KConfigGroup configGroup(KSharedConfig::openConfig(), config.group);
0146         configGroup.writeEntry(config.whiteList, whiteList);
0147         configGroup.writeEntry(config.blacklist, blacklist);
0148     }
0149 }