File indexing completed on 2024-05-05 16:48:35

0001 /* This file is part of the KDE project
0002    Copyright (C) 2010 by Adam Pigg (adam@piggz.co.uk)
0003    Copyright (C) 2015-2016 Jarosław Staniek <staniek@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2.1 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KReportPluginManager.h"
0022 #include "KReportPluginManagerPrivate.h"
0023 #include "KReportPluginMetaData.h"
0024 #include "KReportJsonTrader_p.h"
0025 #include "KReportUtils_p.h"
0026 
0027 #include "kreport_debug.h"
0028 #include <QAction>
0029 
0030 //Include the static items
0031 #include "../items/label/KReportLabelPlugin.h"
0032 #include "../items/check/KReportCheckBoxPlugin.h"
0033 #include "../items/field/KReportFieldPlugin.h"
0034 #include "../items/image/KReportImagePlugin.h"
0035 #include "../items/text/KReportTextPlugin.h"
0036 
0037 KReportPluginManager::Private::Private(KReportPluginManager *qq)
0038     : q(qq), m_parent(new QObject), m_findPlugins(true)
0039 {
0040     Q_UNUSED(q)
0041 }
0042 
0043 // ---
0044 
0045 KReportPluginEntry::KReportPluginEntry()
0046     : m_loader(nullptr), m_interface(nullptr), m_metaData(nullptr)
0047 {
0048 }
0049 
0050 KReportPluginEntry::KReportPluginEntry(KReportPluginInterface *staticInterface)
0051     : m_loader(nullptr), m_interface(staticInterface), m_metaData(nullptr)
0052 {
0053 }
0054 
0055 KReportPluginEntry::~KReportPluginEntry()
0056 {
0057     delete m_metaData;
0058     delete m_interface;
0059 }
0060 
0061 KReportPluginInterface* KReportPluginEntry::plugin()
0062 {
0063     if (m_interface) {
0064         return m_interface;
0065     }
0066     if (!m_loader) {
0067         kreportWarning() << "No such plugin";
0068         return nullptr;
0069     }
0070     if (!m_loader->load()) {
0071         kreportWarning() << "Could not load plugin" << m_loader->fileName();
0072         return nullptr;
0073     }
0074     KPluginFactory *factory = qobject_cast<KPluginFactory*>(m_loader->instance());
0075     if (!factory) {
0076         kreportWarning() << "Could not create factory for plugin" << m_loader->fileName();
0077         return nullptr;
0078     }
0079     m_interface = factory->create<KReportPluginInterface>();
0080     if (!m_interface) {
0081         kreportWarning() << "Could not create instance of plugin" << m_loader->fileName();
0082         return nullptr;
0083     }
0084     m_interface->setMetaData(m_metaData);
0085     return m_interface;
0086 }
0087 
0088 void KReportPluginEntry::setBuiltIn(bool set)
0089 {
0090     m_metaData->setBuiltIn(set);
0091 }
0092 
0093 void KReportPluginEntry::setStatic(bool set)
0094 {
0095     m_metaData->setStatic(set);
0096 }
0097 
0098 const KReportPluginMetaData *KReportPluginEntry::metaData() const
0099 {
0100     return m_metaData;
0101 }
0102 
0103 void KReportPluginEntry::setMetaData(KReportPluginMetaData *metaData)
0104 {
0105     delete m_metaData;
0106     m_metaData = metaData;
0107     if (m_interface) {
0108         m_interface->setMetaData(m_metaData);
0109     }
0110 }
0111 
0112 void KReportPluginEntry::setMetaData(const QJsonObject &metaData)
0113 {
0114     setMetaData(new KReportPluginMetaData(metaData));
0115 }
0116 
0117 void KReportPluginEntry::setMetaData(QPluginLoader *loader)
0118 {
0119     m_loader = loader;
0120     setMetaData(new KReportPluginMetaData(*m_loader));
0121 }
0122 
0123 // ---
0124 
0125 KReportPluginManager::Private::~Private()
0126 {
0127     delete m_parent;
0128 }
0129 
0130 template<class PluginClass>
0131 void KReportPluginManager::Private::addBuiltInPlugin(const QJsonObject &json)
0132 {
0133     KReportPluginEntry *entry = new KReportPluginEntry(new PluginClass(m_parent));
0134     QJsonObject j = json.value(QLatin1String("MetaData")).toObject();
0135     //kreportDebug() << j;
0136     entry->setMetaData(j);
0137     entry->setBuiltIn(true);
0138     if (entry->metaData()->id().isEmpty()) {
0139         kreportWarning() << "Plugin" << entry->metaData()->name() << "has no identifier so won't be added to manager";
0140         delete entry;
0141         return;
0142     }
0143     entry->setStatic(true);
0144     m_plugins.insert(entry->metaData()->id(), entry);
0145     m_pluginsByLegacyName.insert(entry->metaData()->value(QLatin1String("X-KDE-PluginInfo-LegacyName"), entry->metaData()->id()), entry);
0146 }
0147 
0148 #define KREPORT_ADD_BUILTIN_PLUGIN(name) \
0149     addBuiltInPlugin<name>(KREPORT_STATIC_PLUGIN_METADATA(name))
0150 
0151 QMap<QString, KReportPluginEntry*>* KReportPluginManager::Private::plugins()
0152 {
0153     if (m_findPlugins) {
0154         findPlugins();
0155     }
0156     return &m_plugins;
0157 }
0158 
0159 QMap<QString, KReportPluginEntry*>* KReportPluginManager::Private::pluginsByLegacyName()
0160 {
0161     if (m_findPlugins) {
0162         findPlugins();
0163     }
0164     return &m_pluginsByLegacyName;
0165 }
0166 
0167 void KReportPluginManager::Private::findPlugins()
0168 {
0169     KREPORT_ADD_BUILTIN_PLUGIN(KReportLabelPlugin);
0170     KREPORT_ADD_BUILTIN_PLUGIN(KReportCheckBoxPlugin);
0171     KREPORT_ADD_BUILTIN_PLUGIN(KReportFieldPlugin);
0172     KREPORT_ADD_BUILTIN_PLUGIN(KReportImagePlugin);
0173     KREPORT_ADD_BUILTIN_PLUGIN(KReportTextPlugin);
0174 
0175     //kreportDebug() << "Load all plugins";
0176     const QList<QPluginLoader*> offers = KReportJsonTrader::self()->query(QLatin1String("KReport/Element"));
0177     const QString expectedVersion = QString::fromLatin1("%1.%2")
0178             .arg(KREPORT_STABLE_VERSION_MAJOR).arg(KREPORT_STABLE_VERSION_MINOR);
0179     foreach(QPluginLoader *loader, offers) {
0180         //QJsonObject json = loader->metaData();
0181         //kreportDebug() << json;
0182         //! @todo check version
0183         QScopedPointer<KReportPluginEntry> entry(new KReportPluginEntry);
0184         entry->setMetaData(loader);
0185         const KReportPluginMetaData *metaData = entry->metaData();
0186         if (metaData->version() != expectedVersion) {
0187             kreportWarning() << "KReport element plugin with ID" << metaData->id()
0188                              << "(" << metaData->fileName() << ")"
0189                              << "has version" << metaData->version() << "but expected version is"
0190                              << expectedVersion
0191                              << "-- skipping it";
0192             continue;
0193         }
0194         if (m_plugins.contains(metaData->id())) {
0195             kreportWarning() << "KReport element plugin with ID" << metaData->id()
0196                              << "already found at"
0197                              << m_plugins.value(metaData->id())->metaData()->fileName()
0198                              << "-- skipping another at" << metaData->fileName();
0199             continue;
0200         }
0201         if (!KReportPrivate::setupPrivateIconsResourceWithMessage(
0202             QLatin1String(KREPORT_BASE_NAME_LOWER),
0203             QString::fromLatin1("icons/%1_%2.rcc")
0204                 .arg(metaData->id()).arg(KReportPrivate::supportedIconTheme),
0205             QtWarningMsg,
0206             QString::fromLatin1(":/icons/%1").arg(metaData->id())))
0207         {
0208             continue;
0209         }
0210         addEntry(entry.take());
0211     }
0212     m_findPlugins = false;
0213 }
0214 
0215 void KReportPluginManager::Private::addEntry(KReportPluginEntry *entry)
0216 {
0217     m_plugins.insert(entry->metaData()->id(), entry);
0218     const QString legacyName(entry->metaData()->value(QLatin1String("X-KDE-PluginInfo-LegacyName"), entry->metaData()->id()));
0219     if (!legacyName.isEmpty() && entry->metaData()->id().startsWith(QLatin1String("org.kde.kreport"))) {
0220         m_pluginsByLegacyName.insert(legacyName, entry);
0221     }
0222 }
0223 
0224 // ---
0225 
0226 //! Class for access to KReportPluginManager constructor
0227 class KReportPluginManagerSingleton
0228 {
0229 public:
0230     KReportPluginManager object;
0231 };
0232 
0233 
0234 KReportPluginManager::KReportPluginManager()
0235     : d(new Private(this))
0236 {
0237     KReportPrivate::setupPrivateIconsResourceWithMessage(
0238         QLatin1String(KREPORT_BASE_NAME_LOWER),
0239         QString::fromLatin1("icons/kreport_%1.rcc").arg(KReportPrivate::supportedIconTheme), QtFatalMsg);
0240 }
0241 
0242 KReportPluginManager::~KReportPluginManager()
0243 {
0244     delete d;
0245 }
0246 
0247 Q_GLOBAL_STATIC(KReportPluginManagerSingleton, s_self)
0248 
0249 KReportPluginManager* KReportPluginManager::self()
0250 {
0251     return &s_self->object;
0252 }
0253 
0254 QStringList KReportPluginManager::pluginIds() const
0255 {
0256     return d->plugins()->keys();
0257 }
0258 
0259 const KReportPluginMetaData *KReportPluginManager::pluginMetaData(const QString& id) const
0260 {
0261     KReportPluginEntry *entry = d->plugins()->value(id);
0262     if (!entry) {
0263         return nullptr;
0264     }
0265     return entry->metaData();
0266 }
0267 
0268 KReportPluginInterface* KReportPluginManager::plugin(const QString& id) const
0269 {
0270     KReportPluginEntry *entry;
0271 
0272     entry = d->plugins()->value(id);
0273 
0274     if (!entry) {
0275         entry = d->pluginsByLegacyName()->value(id);
0276     }
0277 
0278     if (!entry) {
0279         return nullptr;
0280     }
0281     return entry->plugin();
0282 }
0283 
0284 QList<QAction*> KReportPluginManager::createActions(QObject *parent)
0285 {
0286     Q_ASSERT(parent);
0287     const QMap<QString, KReportPluginEntry*> *plugins = d->plugins();
0288     QList<QAction*> actList;
0289     foreach(KReportPluginEntry* plugin, *plugins) {
0290         const KReportPluginMetaData *metaData = plugin->metaData();
0291         if (metaData) {
0292             QAction *act = new QAction(QIcon::fromTheme(metaData->iconName()), metaData->name(), parent);
0293             act->setObjectName(metaData->id());
0294             act->setCheckable(true);
0295 
0296             //Store the order priority in the user data field
0297             act->setData(metaData->priority());
0298             actList << act;
0299         }
0300     }
0301     return actList;
0302 }