Libplasma

pluginloader.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Ryan Rix <ry@n.rix.si>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "pluginloader.h"
8
9#include <QDebug>
10#include <QRegularExpression>
11
12#include <KConfigGroup>
13#include <KLocalizedString>
14#include <KPackage/PackageLoader>
15#include <KPluginFactory>
16#include <KRuntimePlatform>
17#include <KSharedConfig>
18
19#include "applet.h"
20#include "containment.h"
21#include "containmentactions.h"
22#include "debug_p.h"
23#include "private/applet_p.h"
24
25namespace Plasma
26{
27inline bool isContainmentMetaData(const KPluginMetaData &md)
28{
29 return md.rawData().contains(QStringLiteral("X-Plasma-ContainmentType"));
30}
31
32PluginLoader *PluginLoader::self()
33{
34 static PluginLoader self;
35 return &self;
36}
37
38Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVariantList &args)
39{
40 if (name.isEmpty()) {
41 return nullptr;
42 }
43
44 Applet *applet = nullptr;
45
46 if (appletId == 0) {
47 appletId = ++AppletPrivate::s_maxAppletId;
48 }
49
50 // name can be either an actual applet name or an absolute path, in the
51 // latter case, ensure we only use the name part of the path.
52 const QString pluginName = name.section(QLatin1Char('/'), -1);
53
54 KPluginMetaData plugin(QStringLiteral("plasma/applets/") + pluginName, KPluginMetaData::AllowEmptyMetaData);
55 const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), name);
56
57 if (!p.isValid()) {
58 qWarning(LOG_PLASMA) << "Applet invalid: Cannot find a package for" << name;
59 }
60
61 // If the applet is using another applet package, search for the plugin of the other applet
62 if (!plugin.isValid()) {
63 const QString parentPlugin = p.metadata().value(u"X-Plasma-RootPath");
64 if (!parentPlugin.isEmpty()) {
65 plugin = KPluginMetaData(QStringLiteral("plasma/applets/") + parentPlugin, KPluginMetaData::AllowEmptyMetaData);
66 }
67 }
68
69 if (plugin.isValid()) {
70 QVariantList allArgs = QVariantList{QVariant::fromValue(p), appletId} << args;
71 if (KPluginFactory *factory = KPluginFactory::loadFactory(plugin).plugin) {
72 if (factory->metaData().rawData().isEmpty()) {
73 factory->setMetaData(p.metadata());
74 }
75 applet = factory->create<Plasma::Applet>(nullptr, allArgs);
76 }
77 }
78 if (applet) {
79 return applet;
80 }
81
82 QVariantList allArgs;
83 allArgs << QVariant::fromValue(p) << appletId << args;
84
85 if (isContainmentMetaData(p.metadata())) {
86 applet = new Containment(nullptr, p.metadata(), allArgs);
87 } else {
88 KPluginMetaData metadata = p.metadata();
89 if (metadata.pluginId().isEmpty()) {
90 // Add fake extension to parse completeBaseName() as pluginId
91 // without having to construct a fake JSON metadata object.
92 // This would help with better error messages which would
93 // at least show the missing applet's ID.
94 const QString fakeFileName = name + u'.';
95 metadata = KPluginMetaData(QJsonObject(), fakeFileName);
96 }
97 applet = new Applet(nullptr, metadata, allArgs);
98 }
99
100 const QString localePath = p.filePath("translations");
101 if (!localePath.isEmpty()) {
102 KLocalizedString::addDomainLocaleDir(QByteArray("plasma_applet_") + name.toLatin1(), localePath);
103 }
104 return applet;
105}
106
107ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, const QString &name, const QVariantList &args)
108{
109 Q_UNUSED(parent)
110 Q_UNUSED(args)
111 if (name.isEmpty()) {
112 return nullptr;
113 }
114
115 KPluginMetaData plugin(QStringLiteral("plasma/containmentactions/") + name, KPluginMetaData::AllowEmptyMetaData);
116
117 if (plugin.isValid()) {
118 if (auto res = KPluginFactory::instantiatePlugin<Plasma::ContainmentActions>(plugin, nullptr, {QVariant::fromValue(plugin)})) {
119 return res.plugin;
120 }
121 }
122
123 return nullptr;
124}
125
127{
128 auto platforms = KRuntimePlatform::runtimePlatform();
129 // For now desktop always lists everything
130 if (platforms.contains(QStringLiteral("desktop"))) {
131 platforms.clear();
132 }
133
134 // FIXME: this assumes we are always use packages.. no pure c++
135 std::function<bool(const KPluginMetaData &)> filter;
136 if (category.isEmpty()) { // use all but the excluded categories
137 KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("General"));
138 QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
139
140 filter = [excluded, platforms](const KPluginMetaData &md) -> bool {
141 if (!platforms.isEmpty() && !md.formFactors().isEmpty()) {
142 bool found = false;
143 for (const auto &plat : platforms) {
144 if (md.formFactors().contains(plat)) {
145 found = true;
146 break;
147 }
148 }
149
150 if (!found) {
151 return false;
152 }
153 }
154
155 return !excluded.contains(md.category());
156 };
157 } else { // specific category (this could be an excluded one - is that bad?)
158
159 filter = [category, platforms](const KPluginMetaData &md) -> bool {
160 if (!platforms.isEmpty() && !md.formFactors().isEmpty()) {
161 bool found = false;
162 for (const auto &plat : platforms) {
163 if (md.formFactors().contains(plat)) {
164 found = true;
165 break;
166 }
167 }
168
169 if (!found) {
170 return false;
171 }
172 }
173
174 if (category == QLatin1String("Miscellaneous")) {
175 return md.category() == category || md.category().isEmpty();
176 } else {
177 return md.category() == category;
178 }
179 };
180 }
181
182 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
183}
184
186{
187 auto filter = [&mimeType](const KPluginMetaData &md) -> bool {
188 return md.value(u"X-Plasma-DropMimeTypes", QStringList()).contains(mimeType);
189 };
190 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
191}
192
194{
195 auto filter = [](const KPluginMetaData &md) -> bool {
196 return !md.value(u"X-Plasma-DropUrlPatterns", QStringList()).isEmpty();
197 };
198 const QList<KPluginMetaData> allApplets = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
199
200 QList<KPluginMetaData> filtered;
201 for (const KPluginMetaData &md : allApplets) {
202 const QStringList urlPatterns = md.value(u"X-Plasma-DropUrlPatterns", QStringList());
203 for (const QString &glob : urlPatterns) {
205 if (rx.match(url.toString()).hasMatch()) {
206 filtered << md;
207 }
208 }
209 }
210
211 return filtered;
212}
213
215{
216 auto ownFilter = [filter](const KPluginMetaData &md) -> bool {
217 return isContainmentMetaData(md) && filter(md);
218 };
219
220 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), ownFilter);
221}
222
224{
225 auto filter = [type](const KPluginMetaData &md) -> bool {
226 return md.value(u"X-Plasma-ContainmentType") == type;
227 };
228
229 return listContainmentsMetaData(filter);
230}
231
233{
234 auto filter = [&parentApp](const KPluginMetaData &md) -> bool {
235 return md.value(u"X-KDE-ParentApp") == parentApp;
236 };
237
239 if (parentApp.isEmpty()) {
240 plugins = KPluginMetaData::findPlugins(QStringLiteral("plasma/containmentactions"));
241 } else {
242 plugins = KPluginMetaData::findPlugins(QStringLiteral("plasma/containmentactions"), filter);
243 }
244
245 return plugins;
246}
247
248} // Plasma Namespace
QString readEntry(const char *key, const char *aDefault=nullptr) const
static void addDomainLocaleDir(const QByteArray &domain, const QString &path)
QList< KPluginMetaData > findPackages(const QString &packageFormat, const QString &packageRoot=QString(), std::function< bool(const KPluginMetaData &)> filter=std::function< bool(const KPluginMetaData &)>())
Package loadPackage(const QString &packageFormat, const QString &packagePath=QString())
static PackageLoader * self()
bool isValid() const
QString filePath(const QByteArray &key, const QString &filename=QString()) const
KPluginMetaData metadata() const
QString pluginId() const
QString category() const
bool value(QStringView key, bool defaultValue) const
QJsonObject rawData() const
static QList< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter={}, KPluginMetaDataOptions options={})
bool isValid() const
QStringList formFactors() const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
The base Applet class.
Definition applet.h:64
The base ContainmentActions class.
The base class for plugins that provide backgrounds and applet grouping containers.
Definition containment.h:47
QList< KPluginMetaData > listAppletMetaDataForUrl(const QUrl &url)
Returns a list of all known applets associated with a certain URL.
static QList< KPluginMetaData > listContainmentsMetaDataOfType(const QString &type)
Returns a list of containments of the specified type.
static QList< KPluginMetaData > listContainmentsMetaData(std::function< bool(const KPluginMetaData &)> filter={})
Returns a list of all known containments.
ContainmentActions * loadContainmentActions(Containment *parent, const QString &containmentActionsName, const QVariantList &args=QVariantList())
Load a ContainmentActions plugin.
Applet * loadApplet(const QString &name, uint appletId=0, const QVariantList &args=QVariantList())
Load an Applet plugin.
QList< KPluginMetaData > listContainmentActionsMetaData(const QString &parentApp)
Returns a list of all known ContainmentActions.
QList< KPluginMetaData > listAppletMetaData(const QString &category)
Returns a list of all known applets.
QList< KPluginMetaData > listAppletMetaDataForMimeType(const QString &mimetype)
Returns a list of all known applets associated with a certain mimetype.
static PluginLoader * self()
Return the active plugin loader.
KCOREADDONS_EXPORT QStringList runtimePlatform()
Namespace for everything in libplasma.
bool contains(QLatin1StringView key) const const
bool isEmpty() const const
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
QString anchoredPattern(QStringView expression)
QString wildcardToRegularExpression(QStringView pattern, WildcardConversionOptions options)
bool hasMatch() const const
bool isEmpty() const const
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
QByteArray toLatin1() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QString toString(FormattingOptions options) const const
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:48:23 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.