File indexing completed on 2025-01-19 03:55:36

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2018-07-30
0007  * Description : manager to load external plugins at run-time
0008  *
0009  * SPDX-FileCopyrightText: 2018-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "dpluginloader_p.h"
0016 
0017 // Qt includes
0018 
0019 #include <QStringList>
0020 
0021 // Local includes
0022 
0023 #include "digikam_config.h"
0024 #include "digikam_debug.h"
0025 #include "dplugingeneric.h"
0026 #include "dplugineditor.h"
0027 #include "dplugindimg.h"
0028 #include "dpluginrawimport.h"
0029 
0030 namespace Digikam
0031 {
0032 
0033 class Q_DECL_HIDDEN DPluginLoaderCreator
0034 {
0035 public:
0036 
0037     DPluginLoader object;
0038 };
0039 
0040 Q_GLOBAL_STATIC(DPluginLoaderCreator, creator)
0041 
0042 // -----------------------------------------------------
0043 
0044 DPluginLoader::DPluginLoader()
0045     : QObject(),
0046       d      (new Private)
0047 {
0048 }
0049 
0050 DPluginLoader::~DPluginLoader()
0051 {
0052     delete d;
0053 }
0054 
0055 DPluginLoader* DPluginLoader::instance()
0056 {
0057     return &creator->object;
0058 }
0059 
0060 void DPluginLoader::init()
0061 {
0062     d->loadPlugins();
0063 }
0064 
0065 void DPluginLoader::cleanUp()
0066 {
0067     Q_FOREACH (DPlugin* const p, d->allPlugins)
0068     {
0069         p->cleanUp();
0070     }
0071 
0072     d->allPlugins.clear();
0073 }
0074 
0075 QString DPluginLoader::configGroupName() const
0076 {
0077     return QLatin1String("EnabledDPlugins");
0078 }
0079 
0080 QList<DPlugin*> DPluginLoader::allPlugins() const
0081 {
0082     return d->allPlugins;
0083 }
0084 
0085 QList<DPluginAction*> DPluginLoader::pluginsActions(DPluginAction::ActionType type, QObject* const parent) const
0086 {
0087     QList<DPluginAction*> list;
0088 
0089     Q_FOREACH (DPlugin* const p, d->allPlugins)
0090     {
0091         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(p);
0092 
0093         if (gene)
0094         {
0095             Q_FOREACH (DPluginAction* const ac, gene->actions(parent))
0096             {
0097                 if (ac && (ac->actionType() == type))
0098                 {
0099                     list << ac;
0100                 }
0101             }
0102         }
0103     }
0104 
0105     if (list.isEmpty())
0106     {
0107         Q_FOREACH (DPlugin* const p, d->allPlugins)
0108         {
0109             DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(p);
0110 
0111             if (edit)
0112             {
0113                 Q_FOREACH (DPluginAction* const ac, edit->actions(parent))
0114                 {
0115                     if (ac && (ac->actionType() == type))
0116                     {
0117                         list << ac;
0118                     }
0119                 }
0120             }
0121         }
0122     }
0123 
0124     std::sort(list.begin(), list.end(), DPluginAction::pluginActionLessThan);
0125 
0126     return list;
0127 }
0128 
0129 QList<DPluginAction*> DPluginLoader::pluginsActions(DPluginAction::ActionCategory cat, QObject* const parent) const
0130 {
0131     QList<DPluginAction*> list;
0132 
0133     Q_FOREACH (DPlugin* const p, d->allPlugins)
0134     {
0135         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(p);
0136 
0137         if (gene)
0138         {
0139             Q_FOREACH (DPluginAction* const ac, gene->actions(parent))
0140             {
0141                 if (ac && (ac->actionCategory() == cat))
0142                 {
0143                     list << ac;
0144                 }
0145             }
0146         }
0147     }
0148 
0149     if (list.isEmpty())
0150     {
0151         Q_FOREACH (DPlugin* const p, d->allPlugins)
0152         {
0153             DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(p);
0154 
0155             if (edit)
0156             {
0157                 Q_FOREACH (DPluginAction* const ac, edit->actions(parent))
0158                 {
0159                     if (ac && (ac->actionCategory() == cat))
0160                     {
0161                         list << ac;
0162                     }
0163                 }
0164             }
0165         }
0166     }
0167 
0168     std::sort(list.begin(), list.end(), DPluginAction::pluginActionLessThan);
0169     return list;
0170 }
0171 
0172 QList<DPluginAction*> DPluginLoader::pluginActions(const QString& pluginIID, QObject* const parent) const
0173 {
0174     QList<DPluginAction*> list;
0175 
0176     Q_FOREACH (DPlugin* const p, d->allPlugins)
0177     {
0178         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(p);
0179 
0180         if (gene)
0181         {
0182             if (p->iid() == pluginIID)
0183             {
0184                 Q_FOREACH (DPluginAction* const ac, gene->actions(parent))
0185                 {
0186                     list << ac;
0187                 }
0188 
0189                 break;
0190             }
0191         }
0192     }
0193 
0194     if (list.isEmpty())
0195     {
0196         Q_FOREACH (DPlugin* const p, d->allPlugins)
0197         {
0198             DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(p);
0199 
0200             if (edit)
0201             {
0202                 if (p->iid() == pluginIID)
0203                 {
0204                     Q_FOREACH (DPluginAction* const ac, edit->actions(parent))
0205                     {
0206                         list << ac;
0207                     }
0208 
0209                     break;
0210                 }
0211             }
0212         }
0213     }
0214 
0215     std::sort(list.begin(), list.end(), DPluginAction::pluginActionLessThan);
0216     return list;
0217 }
0218 
0219 DPluginAction* DPluginLoader::pluginAction(const QString& actionName, QObject* const parent) const
0220 {
0221     Q_FOREACH (DPlugin* const p, d->allPlugins)
0222     {
0223         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(p);
0224 
0225         if (gene)
0226         {
0227             Q_FOREACH (DPluginAction* const ac, gene->actions(parent))
0228             {
0229                 if (ac && (ac->objectName() == actionName))
0230                 {    // cppcheck-suppress useStlAlgorithm
0231                     return ac;
0232                 }
0233             }
0234         }
0235 
0236         DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(p);
0237 
0238         if (edit)
0239         {
0240             Q_FOREACH (DPluginAction* const ac, edit->actions(parent))
0241             {
0242                 if (ac && (ac->objectName() == actionName))
0243                 {   // cppcheck-suppress useStlAlgorithm
0244                     return ac;
0245                 }
0246             }
0247         }
0248     }
0249 
0250     qCCritical(DIGIKAM_GENERAL_LOG) << "DPluginAction named" << actionName
0251                                     << "not found in" << parent->objectName()
0252                                     << "(" << parent << ")";
0253 
0254     return nullptr;
0255 }
0256 
0257 QString DPluginLoader::pluginXmlSections(DPluginAction::ActionCategory cat, QObject* const parent) const
0258 {
0259     QString xml;
0260 
0261     Q_FOREACH (DPluginAction* const ac, pluginsActions(cat, parent))
0262     {
0263         xml.append(ac->xmlSection());
0264     }
0265 
0266     return xml;
0267 }
0268 
0269 void DPluginLoader::appendPluginToBlackList(const QString& filename)
0270 {
0271     d->blacklist << filename;
0272 }
0273 
0274 void DPluginLoader::appendPluginToWhiteList(const QString& filename)
0275 {
0276     d->whitelist << filename;
0277 }
0278 
0279 void DPluginLoader::registerGenericPlugins(QObject* const parent)
0280 {
0281     Q_FOREACH (DPlugin* const plugin, d->allPlugins)
0282     {
0283         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(plugin);
0284 
0285         if (gene)
0286         {
0287             gene->setup(parent);
0288             gene->setVisible(plugin->shouldLoaded());
0289 /*
0290             qCDebug(DIGIKAM_GENERAL_LOG) << "Generic plugin named" << gene->name()
0291                                          << "registered to" << parent;
0292 */
0293         }
0294     }
0295 }
0296 
0297 void DPluginLoader::registerEditorPlugins(QObject* const parent)
0298 {
0299     Q_FOREACH (DPlugin* const plugin, d->allPlugins)
0300     {
0301         DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(plugin);
0302 
0303         if (edit)
0304         {
0305             edit->setup(parent);
0306             edit->setVisible(plugin->shouldLoaded());
0307 /*
0308             qCDebug(DIGIKAM_GENERAL_LOG) << "Editor plugin named" << edit->name()
0309                                          << "registered to" << parent;
0310 */
0311         }
0312     }
0313 }
0314 
0315 void DPluginLoader::registerRawImportPlugins(QObject* const parent)
0316 {
0317     Q_FOREACH (DPlugin* const plugin, d->allPlugins)
0318     {
0319         DPluginRawImport* const raw = dynamic_cast<DPluginRawImport*>(plugin);
0320 
0321         if (raw)
0322         {
0323             raw->setup(parent);
0324 /*
0325             qCDebug(DIGIKAM_GENERAL_LOG) << "Raw Import plugin named" << raw->name()
0326                                          << "registered to" << parent;
0327 */
0328         }
0329     }
0330 }
0331 
0332 DImgLoaderSettings* DPluginLoader::exportWidget(const QString& format) const
0333 {
0334     Q_FOREACH (DPlugin* const plugin, d->allPlugins)
0335     {
0336         DPluginDImg* const dimg = dynamic_cast<DPluginDImg*>(plugin);
0337 
0338         if (dimg)
0339         {
0340             DImgLoaderSettings* const widget = dimg->exportWidget(format);
0341 
0342             if (widget)
0343             {
0344                 return widget;
0345             }
0346         }
0347     }
0348 
0349     return nullptr;
0350 }
0351 
0352 bool DPluginLoader::canImport(const QString& format) const
0353 {
0354     Q_FOREACH (DPlugin* const plugin, d->allPlugins)
0355     {
0356         DPluginDImg* const dimg = dynamic_cast<DPluginDImg*>(plugin);
0357 
0358         if (dimg && dimg->canRead(QFileInfo(QString::fromLatin1("foo.%1").arg(format)), true))
0359         {
0360             return true;
0361         }
0362     }
0363 
0364     return false;
0365 }
0366 
0367 bool DPluginLoader::canExport(const QString& format) const
0368 {
0369     Q_FOREACH (DPlugin* const plugin, d->allPlugins)
0370     {
0371         DPluginDImg* const dimg = dynamic_cast<DPluginDImg*>(plugin);
0372 
0373         if (dimg && dimg->canWrite(format))
0374         {
0375             return true;
0376         }
0377     }
0378 
0379     return false;
0380 }
0381 
0382 } // namespace Digikam
0383 
0384 #include "moc_dpluginloader.cpp"