1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2018-07-30
7  * Description : manager to load external plugins at run-time
8  *
9  * Copyright (C) 2018-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  *
11  * This program is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation;
14  * either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 #include "dpluginloader_p.h"
25 
26 // Qt includes
27 
28 #include <QStringList>
29 
30 // Local includes
31 
32 #include "digikam_config.h"
33 #include "digikam_debug.h"
34 #include "dplugingeneric.h"
35 #include "dplugineditor.h"
36 #include "dpluginrawimport.h"
37 
38 namespace Digikam
39 {
40 
41 class Q_DECL_HIDDEN DPluginLoaderCreator
42 {
43 public:
44 
45     DPluginLoader object;
46 };
47 
Q_GLOBAL_STATIC(DPluginLoaderCreator,creator)48 Q_GLOBAL_STATIC(DPluginLoaderCreator, creator)
49 
50 // -----------------------------------------------------
51 
52 DPluginLoader::DPluginLoader()
53     : QObject(),
54       d      (new Private)
55 {
56 }
57 
~DPluginLoader()58 DPluginLoader::~DPluginLoader()
59 {
60     delete d;
61 }
62 
instance()63 DPluginLoader* DPluginLoader::instance()
64 {
65     return &creator->object;
66 }
67 
init()68 void DPluginLoader::init()
69 {
70     d->loadPlugins();
71 }
72 
cleanUp()73 void DPluginLoader::cleanUp()
74 {
75     foreach (DPlugin* const p, d->allPlugins)
76     {
77         p->cleanUp();
78     }
79 
80     d->allPlugins.clear();
81 }
82 
configGroupName() const83 QString DPluginLoader::configGroupName() const
84 {
85     return QLatin1String("EnabledDPlugins");
86 }
87 
allPlugins() const88 QList<DPlugin*> DPluginLoader::allPlugins() const
89 {
90     return d->allPlugins;
91 }
92 
pluginsActions(DPluginAction::ActionType type,QObject * const parent) const93 QList<DPluginAction*> DPluginLoader::pluginsActions(DPluginAction::ActionType type, QObject* const parent) const
94 {
95     QList<DPluginAction*> list;
96 
97     foreach (DPlugin* const p, d->allPlugins)
98     {
99         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(p);
100 
101         if (gene)
102         {
103             foreach (DPluginAction* const ac, gene->actions(parent))
104             {
105                 if (ac && (ac->actionType() == type))
106                 {
107                     list << ac;
108                 }
109             }
110         }
111     }
112 
113     if (list.isEmpty())
114     {
115         foreach (DPlugin* const p, d->allPlugins)
116         {
117             DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(p);
118 
119             if (edit)
120             {
121                 foreach (DPluginAction* const ac, edit->actions(parent))
122                 {
123                     if (ac && (ac->actionType() == type))
124                     {
125                         list << ac;
126                     }
127                 }
128             }
129         }
130     }
131 
132     std::sort(list.begin(), list.end(), DPluginAction::pluginActionLessThan);
133 
134     return list;
135 }
136 
pluginsActions(DPluginAction::ActionCategory cat,QObject * const parent) const137 QList<DPluginAction*> DPluginLoader::pluginsActions(DPluginAction::ActionCategory cat, QObject* const parent) const
138 {
139     QList<DPluginAction*> list;
140 
141     foreach (DPlugin* const p, d->allPlugins)
142     {
143         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(p);
144 
145         if (gene)
146         {
147             foreach (DPluginAction* const ac, gene->actions(parent))
148             {
149                 if (ac && (ac->actionCategory() == cat))
150                 {
151                     list << ac;
152                 }
153             }
154         }
155     }
156 
157     if (list.isEmpty())
158     {
159         foreach (DPlugin* const p, d->allPlugins)
160         {
161             DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(p);
162 
163             if (edit)
164             {
165                 foreach (DPluginAction* const ac, edit->actions(parent))
166                 {
167                     if (ac && (ac->actionCategory() == cat))
168                     {
169                         list << ac;
170                     }
171                 }
172             }
173         }
174     }
175 
176     std::sort(list.begin(), list.end(), DPluginAction::pluginActionLessThan);
177     return list;
178 }
179 
pluginActions(const QString & pluginIID,QObject * const parent) const180 QList<DPluginAction*> DPluginLoader::pluginActions(const QString& pluginIID, QObject* const parent) const
181 {
182     QList<DPluginAction*> list;
183 
184     foreach (DPlugin* const p, d->allPlugins)
185     {
186         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(p);
187 
188         if (gene)
189         {
190             if (p->iid() == pluginIID)
191             {
192                 foreach (DPluginAction* const ac, gene->actions(parent))
193                 {
194                     list << ac;
195                 }
196 
197                 break;
198             }
199         }
200     }
201 
202     if (list.isEmpty())
203     {
204         foreach (DPlugin* const p, d->allPlugins)
205         {
206             DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(p);
207 
208             if (edit)
209             {
210                 if (p->iid() == pluginIID)
211                 {
212                     foreach (DPluginAction* const ac, edit->actions(parent))
213                     {
214                         list << ac;
215                     }
216 
217                     break;
218                 }
219             }
220         }
221     }
222 
223     std::sort(list.begin(), list.end(), DPluginAction::pluginActionLessThan);
224     return list;
225 }
226 
pluginAction(const QString & actionName,QObject * const parent) const227 DPluginAction* DPluginLoader::pluginAction(const QString& actionName, QObject* const parent) const
228 {
229     foreach (DPlugin* const p, d->allPlugins)
230     {
231         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(p);
232 
233         if (gene)
234         {
235             foreach (DPluginAction* const ac, gene->actions(parent))
236             {
237                 if (ac && (ac->objectName() == actionName))
238                 {
239                     return ac;
240                 }
241             }
242         }
243 
244         DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(p);
245 
246         if (edit)
247         {
248             foreach (DPluginAction* const ac, edit->actions(parent))
249             {
250                 if (ac && (ac->objectName() == actionName))
251                 {
252                     return ac;
253                 }
254             }
255         }
256     }
257 
258     qCCritical(DIGIKAM_GENERAL_LOG) << "DPluginAction named" << actionName
259                                     << "not found in" << parent->objectName()
260                                     << "(" << parent << ")";
261 
262     return nullptr;
263 }
264 
pluginXmlSections(DPluginAction::ActionCategory cat,QObject * const parent) const265 QString DPluginLoader::pluginXmlSections(DPluginAction::ActionCategory cat, QObject* const parent) const
266 {
267     QString xml;
268 
269     foreach (DPluginAction* const ac, pluginsActions(cat, parent))
270     {
271         xml.append(ac->xmlSection());
272     }
273 
274     return xml;
275 }
276 
appendPluginToBlackList(const QString & filename)277 void DPluginLoader::appendPluginToBlackList(const QString& filename)
278 {
279     d->blacklist << filename;
280 }
281 
appendPluginToWhiteList(const QString & filename)282 void DPluginLoader::appendPluginToWhiteList(const QString& filename)
283 {
284     d->whitelist << filename;
285 }
286 
registerGenericPlugins(QObject * const parent)287 void DPluginLoader::registerGenericPlugins(QObject* const parent)
288 {
289     foreach (DPlugin* const plugin, d->allPlugins)
290     {
291         DPluginGeneric* const gene = dynamic_cast<DPluginGeneric*>(plugin);
292 
293         if (gene)
294         {
295             gene->setup(parent);
296             gene->setVisible(plugin->shouldLoaded());
297 
298             qCDebug(DIGIKAM_GENERAL_LOG) << "Generic plugin named" << gene->name()
299                                          << "registered to" << parent;
300         }
301     }
302 }
303 
registerEditorPlugins(QObject * const parent)304 void DPluginLoader::registerEditorPlugins(QObject* const parent)
305 {
306     foreach (DPlugin* const plugin, d->allPlugins)
307     {
308         DPluginEditor* const edit = dynamic_cast<DPluginEditor*>(plugin);
309 
310         if (edit)
311         {
312             edit->setup(parent);
313             edit->setVisible(plugin->shouldLoaded());
314 
315             qCDebug(DIGIKAM_GENERAL_LOG) << "Editor plugin named" << edit->name()
316                                          << "registered to" << parent;
317         }
318     }
319 }
320 
registerRawImportPlugins(QObject * const parent)321 void DPluginLoader::registerRawImportPlugins(QObject* const parent)
322 {
323     foreach (DPlugin* const plugin, d->allPlugins)
324     {
325         DPluginRawImport* const raw = dynamic_cast<DPluginRawImport*>(plugin);
326 
327         if (raw)
328         {
329             raw->setup(parent);
330             qCDebug(DIGIKAM_GENERAL_LOG) << "Raw Import plugin named" << raw->name()
331                                          << "registered to" << parent;
332         }
333     }
334 }
335 
336 } // namepace Digikam
337