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"