Akonadi

pluginloader.cpp
1 /* -*- c++ -*-
2  Copyright (c) 2008 Tobias Koenig <[email protected]>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "pluginloader_p.h"
21 #include "akonadicore_debug.h"
22 #include <private/standarddirs_p.h>
23 #include <KConfigGroup>
24 #include <KLocalizedString>
25 #include <KConfig>
26 #include <QDir>
27 #include <QStandardPaths>
28 #include <QPluginLoader>
29 
30 using namespace Akonadi;
31 
32 PluginMetaData::PluginMetaData()
33  : loaded(false)
34 {
35 }
36 
37 PluginMetaData::PluginMetaData(const QString &lib, const QString &name, const QString &comment, const QString &cname)
38  : library(lib)
39  , nameLabel(name)
40  , descriptionLabel(comment)
41  , className(cname)
42  , loaded(false)
43 {
44 }
45 
46 PluginLoader *PluginLoader::mSelf = nullptr;
47 
48 PluginLoader::PluginLoader()
49 {
50  scan();
51 }
52 
53 PluginLoader::~PluginLoader()
54 {
55  qDeleteAll(mPluginLoaders);
56  mPluginLoaders.clear();
57 }
58 
59 PluginLoader *PluginLoader::self()
60 {
61  if (!mSelf) {
62  mSelf = new PluginLoader();
63  }
64 
65  return mSelf;
66 }
67 
68 QStringList PluginLoader::names() const
69 {
70  return mPluginInfos.keys();
71 }
72 
73 QObject *PluginLoader::createForName(const QString &name)
74 {
75  if (!mPluginInfos.contains(name)) {
76  qCWarning(AKONADICORE_LOG) << "plugin name \"" << name << "\" is unknown to the plugin loader.";
77  return nullptr;
78  }
79 
80  PluginMetaData &info = mPluginInfos[name];
81 
82  //First try to load it staticly
83  const auto instances = QPluginLoader::staticInstances();
84  for (auto *plugin : instances) {
85  if (QLatin1String(plugin->metaObject()->className()) == info.className) {
86  info.loaded = true;
87  return plugin;
88  }
89  }
90 
91  if (!info.loaded) {
92  QPluginLoader *loader = new QPluginLoader(info.library);
93  if (loader->fileName().isEmpty()) {
94  qCWarning(AKONADICORE_LOG) << "Error loading" << info.library << ":" << loader->errorString();
95  delete loader;
96  return nullptr;
97  }
98 
99  mPluginLoaders.insert(name, loader);
100  info.loaded = true;
101  }
102 
103  QPluginLoader *loader = mPluginLoaders.value(name);
104  Q_ASSERT(loader);
105 
106  QObject *object = loader->instance();
107  if (!object) {
108  qCWarning(AKONADICORE_LOG) << "unable to load plugin" << info.library << "for plugin name" << name << ".";
109  qCWarning(AKONADICORE_LOG) << "Error was:\"" << loader->errorString() << "\".";
110  return nullptr;
111  }
112 
113  return object;
114 }
115 
116 PluginMetaData PluginLoader::infoForName(const QString &name) const
117 {
118  return mPluginInfos.value(name, PluginMetaData());
119 }
120 
121 void PluginLoader::scan()
122 {
123  const auto dirs = StandardDirs::locateAllResourceDirs(QStringLiteral("akonadi/plugins/serializer/"));
124  for (const QString &dir : dirs) {
125  const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop"));
126  for (const QString &file : fileNames) {
127  const QString entry = dir + QLatin1Char('/') + file;
129  if (config.hasGroup("Misc") && config.hasGroup("Plugin")) {
130  KConfigGroup group(&config, "Plugin");
131 
132  const QString type = group.readEntry("Type").toLower();
133  if (type.isEmpty()) {
134  qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]Type value in" << entry << "- skipping";
135  continue;
136  }
137 
138  // read Class entry as a list so that types like QPair<A,B> are
139  // properly escaped and don't end up being split into QPair<A
140  // and B>.
141  const QStringList classes = group.readXdgListEntry("X-Akonadi-Class");
142  if (classes.isEmpty()) {
143  qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]X-Akonadi-Class value in" << entry << "- skipping";
144  continue;
145  }
146 
147  const QString library = group.readEntry("X-KDE-Library");
148  if (library.isEmpty()) {
149  qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]X-KDE-Library value in" << entry << "- skipping";
150  continue;
151  }
152 
153  KConfigGroup group2(&config, "Misc");
154 
155  QString name = group2.readEntry("Name");
156  if (name.isEmpty()) {
157  qCWarning(AKONADICORE_LOG) << "missing or empty [Misc]Name value in \"" << entry << "\" - inserting default name";
158  name = i18n("Unnamed plugin");
159  }
160 
161  QString comment = group2.readEntry("Comment");
162  if (comment.isEmpty()) {
163  qCWarning(AKONADICORE_LOG) << "missing or empty [Misc]Comment value in \"" << entry << "\" - inserting default name";
164  comment = i18n("No description available");
165  }
166 
167  QString cname = group.readEntry("X-KDE-ClassName");
168  if (cname.isEmpty()) {
169  qCWarning(AKONADICORE_LOG) << "missing or empty X-KDE-ClassName value in \"" << entry << "\"";
170  }
171 
172  const QStringList mimeTypes = type.split(QLatin1Char(','), QString::SkipEmptyParts);
173 
174  qCDebug(AKONADICORE_LOG) << "registering Desktop file" << entry << "for" << mimeTypes << '@' << classes;
175  for (const QString &mimeType : mimeTypes) {
176  for (const QString &classType : classes) {
177  mPluginInfos.insert(mimeType + QLatin1Char('@') + classType, PluginMetaData(library, name, comment, cname));
178  }
179  }
180 
181  } else {
182  qCWarning(AKONADICORE_LOG) << "Desktop file \"" << entry << "\" doesn't seem to describe a plugin " << "(misses Misc and/or Plugin group)";
183  }
184  }
185  }
186 }
QByteArray toLower() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
virtual QByteArray type() const =0
Returns the type of the attribute.
KSharedConfigPtr config()
QObjectList staticInstances()
bool isEmpty() const const
bool isEmpty() const const
QObject * instance()
QString errorString() const const
QStringList mimeTypes(Types)
QString i18n(const char *text, const TYPE &arg...)
KIOFILEWIDGETS_EXPORT QString dir(const QString &fileClass)
void insert(int i, const T &value)
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
Helper integration between Akonadi and Qt.
KStandardDirs * dirs()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:55 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.