Plasma-framework

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 KPluginMetaData plugin(QStringLiteral("plasma/applets/") + name, KPluginMetaData::AllowEmptyMetaData);
54 const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), name);
55
56 if (!p.isValid()) {
57 qWarning(LOG_PLASMA) << "Applet invalid: Cannot find a package for" << name;
58 }
59
60 // If the applet is using another applet package, search for the plugin of the other applet
61 if (!plugin.isValid()) {
62 const QString parentPlugin = p.metadata().value(QStringLiteral("X-Plasma-RootPath"));
63 if (!parentPlugin.isEmpty()) {
64 plugin = KPluginMetaData(QStringLiteral("plasma/applets/") + parentPlugin, KPluginMetaData::AllowEmptyMetaData);
65 }
66 }
67
68 if (plugin.isValid()) {
69 QVariantList allArgs = QVariantList{QVariant::fromValue(p), appletId} << args;
70 if (KPluginFactory *factory = KPluginFactory::loadFactory(plugin).plugin) {
71 if (factory->metaData().rawData().isEmpty()) {
72 factory->setMetaData(p.metadata());
73 }
74 applet = factory->create<Plasma::Applet>(nullptr, allArgs);
75 }
76 }
77 if (applet) {
78 return applet;
79 }
80
81 QVariantList allArgs;
82 allArgs << QVariant::fromValue(p) << appletId << args;
83
84 if (isContainmentMetaData(p.metadata())) {
85 applet = new Containment(nullptr, p.metadata(), allArgs);
86 } else {
87 applet = new Applet(nullptr, p.metadata(), allArgs);
88 }
89
90 const QString localePath = p.filePath("translations");
91 if (!localePath.isEmpty()) {
92 KLocalizedString::addDomainLocaleDir(QByteArray("plasma_applet_") + name.toLatin1(), localePath);
93 }
94 return applet;
95}
96
97ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, const QString &name, const QVariantList &args)
98{
99 if (name.isEmpty()) {
100 return nullptr;
101 }
102
103 KPluginMetaData plugin(QStringLiteral("plasma/containmentactions/") + name, KPluginMetaData::AllowEmptyMetaData);
104
105 if (plugin.isValid()) {
106 if (auto res = KPluginFactory::instantiatePlugin<Plasma::ContainmentActions>(plugin, nullptr, {QVariant::fromValue(plugin)})) {
107 return res.plugin;
108 }
109 }
110
111 return nullptr;
112}
113
115{
116 auto platforms = KRuntimePlatform::runtimePlatform();
117 // For now desktop always lists everything
118 if (platforms.contains(QStringLiteral("desktop"))) {
119 platforms.clear();
120 }
121
122 // FIXME: this assumes we are always use packages.. no pure c++
123 std::function<bool(const KPluginMetaData &)> filter;
124 if (category.isEmpty()) { // use all but the excluded categories
125 KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("General"));
126 QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
127
128 filter = [excluded, platforms](const KPluginMetaData &md) -> bool {
129 if (!platforms.isEmpty() && !md.formFactors().isEmpty()) {
130 bool found = false;
131 for (const auto &plat : platforms) {
132 if (md.formFactors().contains(plat)) {
133 found = true;
134 break;
135 }
136 }
137
138 if (!found) {
139 return false;
140 }
141 }
142
143 return !excluded.contains(md.category());
144 };
145 } else { // specific category (this could be an excluded one - is that bad?)
146
147 filter = [category, platforms](const KPluginMetaData &md) -> bool {
148 if (!platforms.isEmpty() && !md.formFactors().isEmpty()) {
149 bool found = false;
150 for (const auto &plat : platforms) {
151 if (md.formFactors().contains(plat)) {
152 found = true;
153 break;
154 }
155 }
156
157 if (!found) {
158 return false;
159 }
160 }
161
162 if (category == QLatin1String("Miscellaneous")) {
163 return md.category() == category || md.category().isEmpty();
164 } else {
165 return md.category() == category;
166 }
167 };
168 }
169
170 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
171}
172
174{
175 auto filter = [&mimeType](const KPluginMetaData &md) -> bool {
176 return md.value(QStringLiteral("X-Plasma-DropMimeTypes"), QStringList()).contains(mimeType);
177 };
178 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
179}
180
182{
183 auto filter = [](const KPluginMetaData &md) -> bool {
184 return !md.value(QStringLiteral("X-Plasma-DropUrlPatterns"), QStringList()).isEmpty();
185 };
186 const QList<KPluginMetaData> allApplets = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
187
188 QList<KPluginMetaData> filtered;
189 for (const KPluginMetaData &md : allApplets) {
190 const QStringList urlPatterns = md.value(QStringLiteral("X-Plasma-DropUrlPatterns"), QStringList());
191 for (const QString &glob : urlPatterns) {
193 if (rx.match(url.toString()).hasMatch()) {
194 filtered << md;
195 }
196 }
197 }
198
199 return filtered;
200}
201
203{
204 auto ownFilter = [filter](const KPluginMetaData &md) -> bool {
205 return isContainmentMetaData(md) && filter(md);
206 };
207
208 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), ownFilter);
209}
210
212{
213 auto filter = [type](const KPluginMetaData &md) -> bool {
214 return md.value(QStringLiteral("X-Plasma-ContainmentType")) == type;
215 };
216
217 return listContainmentsMetaData(filter);
218}
219
221{
222 auto filter = [&parentApp](const KPluginMetaData &md) -> bool {
223 return md.value(QStringLiteral("X-KDE-ParentApp")) == parentApp;
224 };
225
227 if (parentApp.isEmpty()) {
228 plugins = KPluginMetaData::findPlugins(QStringLiteral("plasma/containmentactions"));
229 } else {
230 plugins = KPluginMetaData::findPlugins(QStringLiteral("plasma/containmentactions"), filter);
231 }
232
233 return plugins;
234}
235
236} // 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 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
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 May 3 2024 11:46:04 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.