Warning, file /office/calligra/libs/plugin/KoPluginLoader.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
0003  * Copyright (c) 2007 Thomas Zander <zander@kde.org>
0004  * Copyright (c) 2016 Friedrich W. H. Kossebau <kossebau@kde.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "KoPluginLoader.h"
0023 
0024 #include <KoConfig.h> // CALLIGRA_OLD_PLUGIN_METADATA
0025 
0026 #include <KConfig>
0027 #include <KSharedConfig>
0028 #include <KConfigGroup>
0029 #include <KPluginFactory>
0030 #include <KPluginLoader>
0031 
0032 #include <QCoreApplication>
0033 #include <QJsonObject>
0034 #include <QPluginLoader>
0035 #include <QLoggingCategory>
0036 #include <QDebug>
0037 
0038 
0039 const QLoggingCategory &PLUGIN_LOG()
0040 {
0041     static const QLoggingCategory category("calligra.lib.plugin");
0042     return category;
0043 }
0044 
0045 #define debugPlugin qCDebug(PLUGIN_LOG)
0046 #define warnPlugin qCWarning(PLUGIN_LOG)
0047 
0048 
0049 class KoPluginLoaderImpl : public QObject
0050 {
0051 Q_OBJECT
0052 public:
0053     QStringList loadedDirectories;
0054 };
0055 
0056 
0057 
0058 Q_GLOBAL_STATIC(KoPluginLoaderImpl, pluginLoaderInstance)
0059 
0060 
0061 void KoPluginLoader::load(const QString & directory, const PluginsConfig &config, QObject* owner)
0062 {
0063     // Don't load the same plugins again
0064     if (pluginLoaderInstance->loadedDirectories.contains(directory)) {
0065         return;
0066     }
0067     pluginLoaderInstance->loadedDirectories << directory;
0068 
0069     QList<QPluginLoader *> offers = KoPluginLoader::pluginLoaders(directory);
0070     QList<QPluginLoader *> plugins;
0071     bool configChanged = false;
0072     QList<QString> blacklist; // what we will save out afterwards
0073     if (config.whiteList && config.blacklist && config.group) {
0074         debugPlugin << "Loading" << directory << "with checking the config";
0075         KConfigGroup configGroup(KSharedConfig::openConfig(), config.group);
0076         QList<QString> whiteList = configGroup.readEntry(config.whiteList, config.defaults);
0077         QList<QString> knownList;
0078 
0079         // if there was no list of defaults; all plugins are loaded.
0080         const bool firstStart = !config.defaults.isEmpty() && !configGroup.hasKey(config.whiteList);
0081         knownList = configGroup.readEntry(config.blacklist, knownList);
0082         if (firstStart) {
0083             configChanged = true;
0084         }
0085         foreach(QPluginLoader *loader, offers) {
0086             QJsonObject json = loader->metaData().value("MetaData").toObject();
0087             json = json.value("KPlugin").toObject();
0088             const QString pluginName = json.value("Id").toString();
0089             if (pluginName.isEmpty()) {
0090                 warnPlugin << "Loading plugin" << loader->fileName() << "failed, has no X-KDE-PluginInfo-Name.";
0091                 continue;
0092             }
0093             if (whiteList.contains(pluginName)) {
0094                 plugins.append(loader);
0095             } else if (!firstStart && !knownList.contains(pluginName)) { // also load newly installed plugins.
0096                 plugins.append(loader);
0097                 configChanged = true;
0098             } else {
0099                 blacklist << pluginName;
0100             }
0101         }
0102     } else {
0103         plugins = offers;
0104     }
0105 
0106     QMap<QString, QPluginLoader *> serviceNames;
0107     foreach(QPluginLoader *loader, plugins) {
0108         if (serviceNames.contains(loader->fileName())) { // duplicate
0109             QJsonObject json2 = loader->metaData().value("MetaData").toObject();
0110             QVariant pluginVersion2 = json2.value("X-Flake-PluginVersion").toVariant();
0111             if (pluginVersion2.isNull()) { // just take the first one found...
0112                 continue;
0113             }
0114             QPluginLoader *currentLoader = serviceNames.value(loader->fileName());
0115             QJsonObject json = currentLoader->metaData().value("MetaData").toObject();
0116             QVariant pluginVersion = json.value("X-Flake-PluginVersion").toVariant();
0117             if (!(pluginVersion.isNull() || pluginVersion.toInt() < pluginVersion2.toInt())) {
0118                 continue; // replace the old one with this one, since its newer.
0119             }
0120         }
0121         serviceNames.insert(loader->fileName(), loader);
0122     }
0123 
0124     QList<QString> whiteList;
0125     foreach(QPluginLoader *loader, serviceNames) {
0126         KPluginFactory *factory = qobject_cast<KPluginFactory *>(loader->instance());
0127         QObject *plugin = factory->create<QObject>(owner ? owner : pluginLoaderInstance, QVariantList());
0128         if (plugin) {
0129             QJsonObject json = loader->metaData().value("MetaData").toObject();
0130             json = json.value("KPlugin").toObject();
0131             const QString pluginName = json.value("Id").toString();
0132             whiteList << pluginName;
0133             debugPlugin << "Loaded plugin" << loader->fileName() << owner;
0134             if (!owner) {
0135                 delete plugin;
0136             }
0137         } else {
0138             warnPlugin << "Loading plugin" << loader->fileName() << "failed, " << loader->errorString();
0139         }
0140     }
0141 
0142     if (configChanged && config.whiteList && config.blacklist && config.group) {
0143         KConfigGroup configGroup(KSharedConfig::openConfig(), config.group);
0144         configGroup.writeEntry(config.whiteList, whiteList);
0145         configGroup.writeEntry(config.blacklist, blacklist);
0146     }
0147 
0148     qDeleteAll(offers);
0149 }
0150 
0151 QList<KPluginFactory *> KoPluginLoader::instantiatePluginFactories(const QString & directory)
0152 {
0153     QList<KPluginFactory *> pluginFactories;
0154 
0155     const QList<QPluginLoader *> offers = KoPluginLoader::pluginLoaders(directory);
0156 
0157     foreach(QPluginLoader *pluginLoader, offers) {
0158         QObject* pluginInstance = pluginLoader->instance();
0159         if (!pluginInstance) {
0160             warnPlugin << "Loading plugin" << pluginLoader->fileName() << "failed, " << pluginLoader->errorString();
0161             continue;
0162         }
0163         KPluginFactory *factory = qobject_cast<KPluginFactory *>(pluginInstance);
0164         if (factory == 0) {
0165             warnPlugin << "Expected a KPluginFactory, got a" << pluginInstance->metaObject()->className();
0166             delete pluginInstance;
0167             continue;
0168         }
0169 
0170         pluginFactories.append(factory);
0171     }
0172     qDeleteAll(offers);
0173 
0174     return pluginFactories;
0175 }
0176 
0177 QList<QPluginLoader *> KoPluginLoader::pluginLoaders(const QString &directory, const QString &mimeType)
0178 {
0179     QList<QPluginLoader *>list;
0180     KPluginLoader::forEachPlugin(directory, [&](const QString &pluginPath) {
0181         debugPlugin << "Trying to load" << pluginPath;
0182         QPluginLoader *loader = new QPluginLoader(pluginPath);
0183         QJsonObject metaData = loader->metaData().value("MetaData").toObject();
0184 
0185         if (metaData.isEmpty()) {
0186             debugPlugin << pluginPath << "has no MetaData!";
0187             return;
0188         }
0189 
0190         if (!mimeType.isEmpty()) {
0191 #ifdef CALLIGRA_OLD_PLUGIN_METADATA
0192             QStringList mimeTypes = metaData.value("MimeType").toString().split(';');
0193             mimeTypes += metaData.value("X-KDE-ExtraNativeMimeTypes").toString().split(QLatin1Char(','));
0194 #else
0195             QJsonObject pluginData = metaData.value("KPlugin").toObject();
0196             QStringList mimeTypes = pluginData.value("MimeTypes").toVariant().toStringList();
0197             mimeTypes += metaData.value("X-KDE-ExtraNativeMimeTypes").toVariant().toStringList();
0198 #endif
0199             mimeTypes += metaData.value("X-KDE-NativeMimeType").toString();
0200             if (! mimeTypes.contains(mimeType)) {
0201                 return;
0202             }
0203         }
0204 
0205         list.append(loader);
0206     });
0207 
0208     return list;
0209 }
0210 #include "KoPluginLoader.moc"