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 <QGuiApplication>
11#include <QPluginLoader>
12#include <QPointer>
13#include <QRegularExpression>
14#include <QStandardPaths>
15
16#include <KLazyLocalizedString>
17#include <KPackage/PackageLoader>
18#include <KRuntimePlatform>
19
20#include "config-plasma.h"
21
22#include "applet.h"
23#include "containment.h"
24#include "containmentactions.h"
25#include "debug_p.h"
26#include "private/applet_p.h"
27
28namespace Plasma
29{
30inline bool isContainmentMetaData(const KPluginMetaData &md)
31{
32 return md.rawData().contains(QStringLiteral("X-Plasma-ContainmentType"));
33}
34
36{
37 static PluginLoader self;
38 return &self;
39}
40
41Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVariantList &args)
42{
43 if (name.isEmpty()) {
44 return nullptr;
45 }
46
47 Applet *applet = nullptr;
48
49 if (appletId == 0) {
50 appletId = ++AppletPrivate::s_maxAppletId;
51 }
52
53 // name can be either an actual applet name or an absolute path, in the
54 // latter case, ensure we only use the name part of the path.
55 const QString pluginName = name.section(QLatin1Char('/'), -1);
56
57 KPluginMetaData plugin(QStringLiteral("plasma/applets/") + pluginName, KPluginMetaData::AllowEmptyMetaData);
58 const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), name);
59
60 if (!p.isValid()) {
61 qWarning(LOG_PLASMA) << "Applet invalid: Cannot find a package for" << name;
62 }
63
64 // If the applet is using another applet package, search for the plugin of the other applet
65 if (!plugin.isValid()) {
66 const QString parentPlugin = p.metadata().value(QStringLiteral("X-Plasma-RootPath"));
67 if (!parentPlugin.isEmpty()) {
68 plugin = KPluginMetaData(QStringLiteral("plasma/applets/") + parentPlugin, KPluginMetaData::AllowEmptyMetaData);
69 }
70 }
71
72 if (plugin.isValid()) {
73 QVariantList allArgs = QVariantList{QVariant::fromValue(p), appletId} << args;
74 if (KPluginFactory *factory = KPluginFactory::loadFactory(plugin).plugin) {
75 if (factory->metaData().rawData().isEmpty()) {
76 factory->setMetaData(p.metadata());
77 }
78 applet = factory->create<Plasma::Applet>(nullptr, allArgs);
79 }
80 }
81 if (applet) {
82 return applet;
83 }
84
85 QVariantList allArgs;
86 allArgs << QVariant::fromValue(p) << appletId << args;
87
88 if (isContainmentMetaData(p.metadata())) {
89 applet = new Containment(nullptr, p.metadata(), allArgs);
90 } else {
91 KPluginMetaData metadata = p.metadata();
92 if (metadata.pluginId().isEmpty()) {
93 // Add fake extension to parse completeBaseName() as pluginId
94 // without having to construct a fake JSON metadata object.
95 // This would help with better error messages which would
96 // at least show the missing applet's ID.
97 const QString fakeFileName = name + u'.';
98 metadata = KPluginMetaData(QJsonObject(), fakeFileName);
99 }
100 applet = new Applet(nullptr, metadata, allArgs);
101 }
102
103 const QString localePath = p.filePath("translations");
104 if (!localePath.isEmpty()) {
105 KLocalizedString::addDomainLocaleDir(QByteArray("plasma_applet_") + name.toLatin1(), localePath);
106 }
107 return applet;
108}
109
110ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, const QString &name, const QVariantList &args)
111{
112 Q_UNUSED(parent)
113 Q_UNUSED(args)
114 if (name.isEmpty()) {
115 return nullptr;
116 }
117
118 KPluginMetaData plugin(QStringLiteral("plasma/containmentactions/") + name, KPluginMetaData::AllowEmptyMetaData);
119
120 if (plugin.isValid()) {
121 if (auto res = KPluginFactory::instantiatePlugin<Plasma::ContainmentActions>(plugin, nullptr, {QVariant::fromValue(plugin)})) {
122 return res.plugin;
123 }
124 }
125
126 return nullptr;
127}
128
130{
131 auto platforms = KRuntimePlatform::runtimePlatform();
132 // For now desktop always lists everything
133 if (platforms.contains(QStringLiteral("desktop"))) {
134 platforms.clear();
135 }
136
137 // FIXME: this assumes we are always use packages.. no pure c++
138 std::function<bool(const KPluginMetaData &)> filter;
139 if (category.isEmpty()) { // use all but the excluded categories
140 KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("General"));
141 QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
142
143 filter = [excluded, platforms](const KPluginMetaData &md) -> bool {
144 if (!platforms.isEmpty() && !md.formFactors().isEmpty()) {
145 bool found = false;
146 for (const auto &plat : platforms) {
147 if (md.formFactors().contains(plat)) {
148 found = true;
149 break;
150 }
151 }
152
153 if (!found) {
154 return false;
155 }
156 }
157
158 return !excluded.contains(md.category());
159 };
160 } else { // specific category (this could be an excluded one - is that bad?)
161
162 filter = [category, platforms](const KPluginMetaData &md) -> bool {
163 if (!platforms.isEmpty() && !md.formFactors().isEmpty()) {
164 bool found = false;
165 for (const auto &plat : platforms) {
166 if (md.formFactors().contains(plat)) {
167 found = true;
168 break;
169 }
170 }
171
172 if (!found) {
173 return false;
174 }
175 }
176
177 if (category == QLatin1String("Miscellaneous")) {
178 return md.category() == category || md.category().isEmpty();
179 } else {
180 return md.category() == category;
181 }
182 };
183 }
184
185 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
186}
187
189{
190 auto filter = [&mimeType](const KPluginMetaData &md) -> bool {
191 return md.value(QStringLiteral("X-Plasma-DropMimeTypes"), QStringList()).contains(mimeType);
192 };
193 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
194}
195
197{
198 auto filter = [](const KPluginMetaData &md) -> bool {
199 return !md.value(QStringLiteral("X-Plasma-DropUrlPatterns"), QStringList()).isEmpty();
200 };
201 const QList<KPluginMetaData> allApplets = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
202
203 QList<KPluginMetaData> filtered;
204 for (const KPluginMetaData &md : allApplets) {
205 const QStringList urlPatterns = md.value(QStringLiteral("X-Plasma-DropUrlPatterns"), QStringList());
206 for (const QString &glob : urlPatterns) {
208 if (rx.match(url.toString()).hasMatch()) {
209 filtered << md;
210 }
211 }
212 }
213
214 return filtered;
215}
216
218{
219 auto ownFilter = [filter](const KPluginMetaData &md) -> bool {
220 return isContainmentMetaData(md) && filter(md);
221 };
222
223 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), ownFilter);
224}
225
227{
228 auto filter = [type](const KPluginMetaData &md) -> bool {
229 return md.value(QStringLiteral("X-Plasma-ContainmentType")) == type;
230 };
231
232 return listContainmentsMetaData(filter);
233}
234
236{
237 auto filter = [&parentApp](const KPluginMetaData &md) -> bool {
238 return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp;
239 };
240
242 if (parentApp.isEmpty()) {
243 plugins = KPluginMetaData::findPlugins(QStringLiteral("plasma/containmentactions"));
244 } else {
245 plugins = KPluginMetaData::findPlugins(QStringLiteral("plasma/containmentactions"), filter);
246 }
247
248 return plugins;
249}
250
251} // 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
QJsonObject rawData() const
bool value(const QString &key, bool defaultValue) 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
This is an abstract base class which defines an interface to which Plasma's Applet Loading logic can ...
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-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:09:37 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.