Akonadi

pluginloader.cpp
1 /* -*- c++ -*-
2  SPDX-FileCopyrightText: 2008 Tobias Koenig <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "akonadicore_debug.h"
8 #include "pluginloader_p.h"
9 #include <KConfig>
10 #include <KConfigGroup>
11 #include <KLocalizedString>
12 #include <QDir>
13 #include <QPluginLoader>
14 #include <QStandardPaths>
15 #include <private/standarddirs_p.h>
16 
17 using namespace Akonadi;
18 
19 PluginMetaData::PluginMetaData()
20  : loaded(false)
21 {
22 }
23 
24 PluginMetaData::PluginMetaData(const QString &lib, const QString &name, const QString &comment, const QString &cname)
25  : library(lib)
26  , nameLabel(name)
27  , descriptionLabel(comment)
28  , className(cname)
29  , loaded(false)
30 {
31 }
32 
33 PluginLoader *PluginLoader::mSelf = nullptr;
34 
35 PluginLoader::PluginLoader()
36 {
37  scan();
38 }
39 
40 PluginLoader::~PluginLoader()
41 {
42  qDeleteAll(mPluginLoaders);
43  mPluginLoaders.clear();
44 }
45 
46 PluginLoader *PluginLoader::self()
47 {
48  if (!mSelf) {
49  mSelf = new PluginLoader();
50  }
51 
52  return mSelf;
53 }
54 
55 QStringList PluginLoader::names() const
56 {
57  return mPluginInfos.keys();
58 }
59 
60 QObject *PluginLoader::createForName(const QString &name)
61 {
62  if (!mPluginInfos.contains(name)) {
63  qCWarning(AKONADICORE_LOG) << "plugin name \"" << name << "\" is unknown to the plugin loader.";
64  return nullptr;
65  }
66 
67  PluginMetaData &info = mPluginInfos[name];
68 
69  // First try to load it statically
70  const auto instances = QPluginLoader::staticInstances();
71  for (auto plugin : instances) {
72  if (QLatin1String(plugin->metaObject()->className()) == info.className) {
73  info.loaded = true;
74  return plugin;
75  }
76  }
77 
78  if (!info.loaded) {
79  auto loader = new QPluginLoader(info.library);
80  if (loader->fileName().isEmpty()) {
81  qCWarning(AKONADICORE_LOG) << "Error loading" << info.library << ":" << loader->errorString();
82  delete loader;
83  return nullptr;
84  }
85 
86  mPluginLoaders.insert(name, loader);
87  info.loaded = true;
88  }
89 
90  QPluginLoader *loader = mPluginLoaders.value(name);
91  Q_ASSERT(loader);
92 
93  QObject *object = loader->instance();
94  if (!object) {
95  qCWarning(AKONADICORE_LOG) << "unable to load plugin" << info.library << "for plugin name" << name << ".";
96  qCWarning(AKONADICORE_LOG) << "Error was:\"" << loader->errorString() << "\".";
97  return nullptr;
98  }
99 
100  return object;
101 }
102 
103 PluginMetaData PluginLoader::infoForName(const QString &name) const
104 {
105  return mPluginInfos.value(name, PluginMetaData());
106 }
107 
108 void PluginLoader::scan()
109 {
110  const auto dirs = StandardDirs::locateAllResourceDirs(QStringLiteral("akonadi/plugins/serializer/"));
111  for (const QString &dir : dirs) {
112  const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop"));
113  for (const QString &file : fileNames) {
114  const QString entry = dir + QLatin1Char('/') + file;
116  if (config.hasGroup("Misc") && config.hasGroup("Plugin")) {
117  KConfigGroup group(&config, "Plugin");
118 
119  const QString type = group.readEntry("Type").toLower();
120  if (type.isEmpty()) {
121  qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]Type value in" << entry << "- skipping";
122  continue;
123  }
124 
125  // read Class entry as a list so that types like QPair<A,B> are
126  // properly escaped and don't end up being split into QPair<A
127  // and B>.
128  const QStringList classes = group.readXdgListEntry("X-Akonadi-Class");
129  if (classes.isEmpty()) {
130  qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]X-Akonadi-Class value in" << entry << "- skipping";
131  continue;
132  }
133 
134  const QString library = group.readEntry("X-KDE-Library");
135  if (library.isEmpty()) {
136  qCWarning(AKONADICORE_LOG) << "missing or empty [Plugin]X-KDE-Library value in" << entry << "- skipping";
137  continue;
138  }
139 
140  KConfigGroup group2(&config, "Misc");
141 
142  QString name = group2.readEntry("Name");
143  if (name.isEmpty()) {
144  qCWarning(AKONADICORE_LOG) << "missing or empty [Misc]Name value in \"" << entry << "\" - inserting default name";
145  name = i18n("Unnamed plugin");
146  }
147 
148  QString comment = group2.readEntry("Comment");
149  if (comment.isEmpty()) {
150  qCWarning(AKONADICORE_LOG) << "missing or empty [Misc]Comment value in \"" << entry << "\" - inserting default name";
151  comment = i18n("No description available");
152  }
153 
154  QString cname = group.readEntry("X-KDE-ClassName");
155  if (cname.isEmpty()) {
156  qCWarning(AKONADICORE_LOG) << "missing or empty X-KDE-ClassName value in \"" << entry << "\"";
157  }
158 
160 
161  qCDebug(AKONADICORE_LOG) << "registering Desktop file" << entry << "for" << mimeTypes << '@' << classes;
162  for (const QString &mimeType : mimeTypes) {
163  for (const QString &classType : classes) {
164  mPluginInfos.insert(mimeType + QLatin1Char('@') + classType, PluginMetaData(library, name, comment, cname));
165  }
166  }
167 
168  } else {
169  qCWarning(AKONADICORE_LOG) << "Desktop file \"" << entry << "\" doesn't seem to describe a plugin "
170  << "(misses Misc and/or Plugin group)";
171  }
172  }
173  }
174 }
QString i18n(const char *text, const TYPE &arg...)
QObjectList staticInstances()
SkipEmptyParts
bool isEmpty() const const
bool isEmpty() const const
KSharedConfigPtr config()
void insert(int i, const T &value)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOFILEWIDGETS_EXPORT QString dir(const QString &fileClass)
QString name(StandardShortcut id)
KStandardDirs * dirs()
QStringList mimeTypes(Mode mode=Writing)
QObject * instance()
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
QString errorString() const const
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jun 30 2022 03:51:46 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.