Don't enforce metadata.desktop, cleanup constructor

Makes it possible to use plugins that offer a metadata.json file.
Define the service type when falling back to the desktop file parser, so
the type system is proper.
Don't destroy a KPluginMetadata tuple to instanciate it right away.

REVIEW: 129102
This commit is contained in:
Aleix Pol 2016-10-10 16:27:50 +02:00
parent e06fe3ebdd
commit 0ebe2ca1fa
6 changed files with 81 additions and 58 deletions

View File

@ -60,6 +60,13 @@
namespace Plasma
{
static KPluginMetaData appletMetadataForDirectory(const QString &path)
{
return QFile::exists(path + QLatin1String("/metadata.json"))
? KPluginMetaData(path + QLatin1String("/metadata.json"))
: KPluginMetaData::fromDesktopFile(path + QLatin1String("/metadata.desktop"), { QStringLiteral("plasma-applet.desktop") });
}
Applet::Applet(const KPluginMetaData &info, QObject *parent, uint appletId)
: QObject(parent),
d(new AppletPrivate(info, appletId, this))
@ -88,14 +95,19 @@ Applet::Applet(QObject *parent, const QString &serviceID, uint appletId)
Applet::Applet(QObject *parentObject, const QVariantList &args)
: QObject(0),
d(new AppletPrivate(
KPluginMetaData(args.count() > 0 && args.first().canConvert<QString>() ? args[0].toString() : QString()),
args.count() > 1 ? args[1].toInt() : 0, this))
d(new AppletPrivate(KPluginMetaData(), args.count() > 1 ? args[1].toInt() : 0, this))
{
setParent(parentObject);
if (args.count() > 0 && args.first().canConvert<QVariantMap>()) {
d->appletDescription = KPluginInfo(args).toMetaData();
if (args.count() > 0) {
const QVariant first = args.first();
if (first.canConvert<QString>()) {
d->appletDescription = KPluginMetaData(first.toString());
} else if (first.canConvert<QVariantMap>()) {
auto metadata = first.toMap().value(QStringLiteral("MetaData")).toMap();
d->appletDescription = KPluginMetaData(QJsonObject::fromVariantMap(metadata), {});
}
}
d->icon = d->appletDescription.iconName();
if (args.contains("org.kde.plasma:force-create")) {
setProperty("org.kde.plasma:force-create", true);
@ -109,7 +121,7 @@ Applet::Applet(QObject *parentObject, const QVariantList &args)
Applet::Applet(const QString &packagePath, uint appletId)
: QObject(0),
d(new AppletPrivate(KPluginMetaData(packagePath + QStringLiteral("/metadata.desktop")), appletId, this))
d(new AppletPrivate(appletMetadataForDirectory(packagePath), appletId, this))
{
d->init(packagePath);
d->setupPackage();
@ -767,15 +779,14 @@ bool Applet::hasValidAssociatedApplication() const
Applet *Applet::loadPlasmoid(const QString &path, uint appletId)
{
const QString metadataPath = path + QLatin1String("/metadata.desktop");
if (QFile::exists(metadataPath)) {
KService service(metadataPath);
const QStringList &types = service.serviceTypes();
const KPluginMetaData md = appletMetadataForDirectory(path);
if (md.isValid()) {
QStringList types = md.serviceTypes();
if (types.contains(QStringLiteral("Plasma/Containment"))) {
return new Containment(path, appletId);
return new Containment(md, appletId);
} else {
return new Applet(path, appletId);
return new Applet(md, nullptr, appletId);
}
}

View File

@ -79,8 +79,8 @@ Containment::Containment(QObject *parent, const QVariantList &args)
setHasConfigurationInterface(true);
}
Containment::Containment(const QString &packagePath, uint appletId)
: Applet(packagePath, appletId),
Containment::Containment(const KPluginMetaData &md, uint appletId)
: Applet(md, nullptr, appletId),
d(new ContainmentPrivate(this))
{
// WARNING: do not access config() OR globalConfig() in this method!

View File

@ -330,7 +330,7 @@ private:
* @param parent a QObject parent; you probably want to pass in 0
* @since 4.3
*/
Containment(const QString &packagePath, uint appletId);
Containment(const KPluginMetaData &md, uint appletId);
Q_PRIVATE_SLOT(d, void appletDeleted(Plasma::Applet *))
Q_PRIVATE_SLOT(d, void triggerShowAddWidgets())

View File

@ -221,7 +221,7 @@ Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVari
p.setRequired("mainscript", false);
p.setPath(name);
KPluginMetaData md(p.filePath("metadata"));
const KPluginMetaData md(p.metadata());
const KPackage::Package fp = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), md.value(QStringLiteral("X-Plasma-RootPath")));
p.setFallbackPackage(fp);
@ -234,8 +234,7 @@ Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVari
if (!applet) {
//qCDebug(LOG_PLASMA) << name << "not a C++ applet: Falling back to an empty one";
QVariantList allArgs;
allArgs << p.metadata().fileName() << appletId << args;
QVariantList allArgs = { p.metadata().fileName(), appletId, args };
if (p.metadata().serviceTypes().contains(QStringLiteral("Plasma/Containment"))) {
return new Containment(0, allArgs);
@ -499,42 +498,22 @@ Package PluginLoader::loadPackage(const QString &packageFormat, const QString &s
return Package();
}
KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QString &parentApp)
QList<KPluginMetaData> PluginLoader::listAppletMetaData(const QString &category, const QString &parentApp)
{
KPluginInfo::List list;
if (!d->isDefaultLoader && (parentApp.isEmpty() || parentApp == QCoreApplication::instance()->applicationName())) {
list = internalAppletInfo(category);
}
//FIXME: this assumes we are always use packages.. no pure c++
std::function<bool(const KPluginMetaData&)> filter;
if (category.isEmpty()) { //use all but the excluded categories
KConfigGroup group(KSharedConfig::openConfig(), "General");
QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
auto filter = [&excluded, &parentApp](const KPluginMetaData &md) -> bool
filter = [excluded, parentApp](const KPluginMetaData &md) -> bool
{
const QString pa = md.value(QStringLiteral("X-KDE-ParentApp"));
return (pa.isEmpty() || pa == parentApp) && !excluded.contains(md.category());
};
//NOTE: it still produces kplugininfos from KServices because some user code expects
//info.sevice() to be valid and would crash ohtherwise
auto plugins = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
foreach (auto& md, plugins) {
auto pi = KPluginInfo(KService::serviceByStorageId(md.metaDataFileName()));
if (!pi.isValid()) {
qCWarning(LOG_PLASMA) << "Could not load plugin info for plugin :" << md.pluginId() << "skipping plugin";
continue;
}
list << pi;
}
return list;
} else { //specific category (this could be an excluded one - is that bad?)
auto filter = [&category, &parentApp](const KPluginMetaData &md) -> bool
filter = [category, parentApp](const KPluginMetaData &md) -> bool
{
const QString pa = md.value(QStringLiteral("X-KDE-ParentApp"));
if (category == QLatin1String("Miscellaneous")) {
@ -543,21 +522,31 @@ KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QS
return (pa.isEmpty() || pa == parentApp) && md.category() == category;
}
};
//NOTE: it still produces kplugininfos from KServices because some user code expects
//info.sevice() to be valid and would crash ohtherwise
const auto plugins = KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
foreach (auto& md, plugins) {
auto pi = KPluginInfo(KService::serviceByStorageId(md.metaDataFileName()));
if (!pi.isValid()) {
qCWarning(LOG_PLASMA) << "Could not load plugin info for plugin :" << md.pluginId() << "skipping plugin";
continue;
}
list << pi;
}
return list;
}
QList<KPluginMetaData> list;
if (!d->isDefaultLoader && (parentApp.isEmpty() || parentApp == QCoreApplication::instance()->applicationName())) {
list = KPluginInfo::toMetaData(internalAppletInfo(category)).toList();
}
return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Applet"), QString(), filter);
}
KPluginInfo::List PluginLoader::listAppletInfo(const QString &category, const QString &parentApp)
{
KPluginInfo::List list;
const auto plugins = listAppletMetaData(category, parentApp);
//NOTE: it still produces kplugininfos from KServices because some user code expects
//info.sevice() to be valid and would crash ohtherwise
foreach (auto& md, plugins) {
auto pi = md.metaDataFileName().endsWith(".json") ? KPluginInfo(md) : KPluginInfo(KService::serviceByStorageId(md.metaDataFileName()));
if (!pi.isValid()) {
qCWarning(LOG_PLASMA) << "Could not load plugin info for plugin :" << md.pluginId() << "skipping plugin";
continue;
}
list << pi;
}
return list;
}
KPluginInfo::List PluginLoader::listAppletInfoForMimeType(const QString &mimeType)

View File

@ -167,8 +167,31 @@ public:
* list containing only applets not specifically
* registered to an application.
* @return list of applets
*
* @deprecated use listAppletMetaData. Doesn't support metadata.json packages.
**/
KPluginInfo::List listAppletInfo(const QString &category, const QString &parentApp = QString());
PLASMA_DEPRECATED KPluginInfo::List listAppletInfo(const QString &category, const QString &parentApp = QString());
/**
* Returns a list of all known applets.
* This may skip applets based on security settings and ExcludeCategories in the application's config.
*
* @param category Only applets matchin this category will be returned.
* Useful in conjunction with knownCategories.
* If "Misc" is passed in, then applets without a
* Categories= entry are also returned.
* If an empty string is passed in, all applets are
* returned.
* @param parentApp the application to filter applets on. Uses the
* X-KDE-ParentApp entry (if any) in the plugin info.
* The default value of QString() will result in a
* list containing only applets not specifically
* registered to an application.
* @return list of applets
*
* @since 5.28
**/
QList<KPluginMetaData> listAppletMetaData(const QString &category, const QString &parentApp = QString());
/**
* Returns a list of all known applets associated with a certain mimetype.

View File

@ -57,7 +57,7 @@ AppletPrivate::AppletPrivate(const KPluginMetaData &info, int uniqueID, Applet *
immutability(Types::Mutable),
oldImmutability(Types::Mutable),
appletDescription(info),
icon(appletDescription.isValid() ? appletDescription.iconName() : QString()),
icon(appletDescription.iconName()),
mainConfig(0),
pendingConstraints(Types::NoConstraint),
script(0),