Akonadi

pluginloader.cpp
1/* -*- c++ -*-
2 SPDX-FileCopyrightText: 2008 Tobias Koenig <tokoe@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "akonadicore_debug.h"
8#include "pluginloader_p.h"
9#include "private/standarddirs_p.h"
10#include <KConfig>
11#include <KConfigGroup>
12#include <KLocalizedString>
13#include <QDir>
14#include <QPluginLoader>
15#include <QStandardPaths>
16
17using namespace Akonadi;
18
19PluginMetaData::PluginMetaData()
20 : loaded(false)
21{
22}
23
24PluginMetaData::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
33PluginLoader *PluginLoader::mSelf = nullptr;
34
35PluginLoader::PluginLoader()
36{
37 scan();
38}
39
40PluginLoader::~PluginLoader()
41{
42 qDeleteAll(mPluginLoaders);
43 mPluginLoaders.clear();
44}
45
46PluginLoader *PluginLoader::self()
47{
48 if (!mSelf) {
49 mSelf = new PluginLoader();
50 }
51
52 return mSelf;
53}
54
55QStringList PluginLoader::names() const
56{
57 return mPluginInfos.keys();
58}
59
60QObject *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 (QLatin1StringView(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
103PluginMetaData PluginLoader::infoForName(const QString &name) const
104{
105 return mPluginInfos.value(name, PluginMetaData());
106}
107
108void 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;
115 KConfig config(entry, KConfig::SimpleConfig);
116 if (config.hasGroup(QLatin1StringView("Misc")) && config.hasGroup(QLatin1StringView("Plugin"))) {
117 KConfigGroup group(&config, QStringLiteral("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, QStringLiteral("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
159 const QStringList mimeTypes = type.split(QLatin1Char(','), Qt::SkipEmptyParts);
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...)
Helper integration between Akonadi and Qt.
QString name(GameStandardAction id)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT QString dir(const QString &fileClass)
PRISONSCANNER_EXPORT ScanResult scan(const QImage &image, Format::BarcodeFormats formats={})
KEDUVOCDOCUMENT_EXPORT QStringList fileNames(const QString &language=QString())
QStringList entryList(Filters filters, SortFlags sort) const const
bool isEmpty() const const
QString errorString() const const
QObject * instance()
QObjectList staticInstances()
bool isEmpty() const const
SkipEmptyParts
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 22 2024 12:03:33 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.