KParts

partloader.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "partloader.h"
9
10#include "kparts_logging.h"
11
12#include <KConfigGroup>
13#include <KLocalizedString>
14#include <KService>
15#include <KSharedConfig>
16
17#include <QJsonArray>
18#include <QMetaEnum>
19#include <QMimeDatabase>
20#include <QMimeType>
21
22static QList<KPluginMetaData> partsFromUserPreference(const QString &mimeType)
23{
24 auto config = KSharedConfig::openConfig(QStringLiteral("kpartsrc"), KConfig::NoGlobals);
25 const QStringList pluginIds = config->group(QStringLiteral("Added KDE Part Associations")).readXdgListEntry(mimeType);
27 plugins.reserve(pluginIds.size());
28 for (const QString &pluginId : pluginIds) {
29 if (KPluginMetaData data(QLatin1String("kf6/parts/") + pluginId); data.isValid()) {
30 plugins << data;
31 }
32 }
33 return plugins;
34}
35
36// A plugin can support N mimetypes. Pick the one that is closest to @parent in the inheritance tree
37// and return how far it is from that parent (0 = same mimetype, 1 = direct child, etc.)
38static int pluginDistanceToMimeType(const KPluginMetaData &md, const QString &parent)
39{
41 auto distanceToMimeType = [&](const QString &mime) {
42 if (mime == parent) {
43 return 0;
44 }
45 const QStringList ancestors = db.mimeTypeForName(mime).allAncestors();
46 const int dist = ancestors.indexOf(parent);
47 return dist == -1 ? 50 : dist + 1;
48 };
49 const QStringList mimes = md.mimeTypes();
50 int minDistance = 50;
51 for (const QString &mime : mimes) {
52 minDistance = std::min(minDistance, distanceToMimeType(mime));
53 }
54 return minDistance;
55}
56
58{
59 QJsonValue capsArrayRaw = data.rawData().value(QLatin1String("KParts")).toObject().value(QLatin1String("Capabilities"));
60 KParts::PartCapabilities parsedCapabilties = {};
62 QJsonArray capabilities = capsArrayRaw.toArray();
63 for (const QJsonValue &capability : capabilities) {
64 bool ok = true;
65 PartCapability parsedCapability = (PartCapability)metaEnum.keyToValue(capability.toString().toLocal8Bit().constData(), &ok);
66 if (ok) {
67 parsedCapabilties |= parsedCapability;
68 } else {
69 qCWarning(KPARTSLOG) << "Could not find capability value" << capability.toString().toLocal8Bit().constData();
70 }
71 }
72
73 // Don't bother looking at fallback API
74 if (!capsArrayRaw.isUndefined()) {
75 return parsedCapabilties;
76 }
77
78 static QMap<QString, KParts::PartCapability> capabilityMapping = {
79 {QStringLiteral("KParts/ReadOnlyPart"), PartCapability::ReadOnly},
80 {QStringLiteral("KParts/ReadWritePart"), PartCapability::ReadWrite},
81 {QStringLiteral("Browser/View"), PartCapability::BrowserView},
82 };
83 const auto serviceTypes = data.rawData().value(QLatin1String("KPlugin")).toObject().value(QLatin1String("ServiceTypes")).toVariant().toStringList();
84 if (!serviceTypes.isEmpty()) {
85 qCWarning(KPARTSLOG) << data
86 << "still defined ServiceTypes - this is deprecated in favor of providing a "
87 " \"Capabilities\" list in the \"KParts\" object in the root of the metadata";
88 for (const QString &serviceType : serviceTypes) {
89 auto it = capabilityMapping.find(serviceType);
90 if (it == capabilityMapping.cend()) {
91 qCWarning(KPARTSLOG) << "ServiceType" << serviceType << "from" << data
92 << "is not a known value that can be mapped to new Capability enum values";
93 } else {
94 parsedCapabilties |= *it;
95 }
96 }
97 }
98 return parsedCapabilties;
99}
100
102{
103 auto supportsMime = [&mimeType](const KPluginMetaData &md) {
104 if (md.supportsMimeType(mimeType)) {
105 return true;
106 }
107 auto pluginJson = md.rawData();
108 auto pluginNamespace = pluginJson.value(QLatin1String("KParts")).toObject().value(QLatin1String("PluginNamespace")).toString();
109 if (pluginNamespace.isEmpty()) {
110 return false;
111 }
112 auto plugins = KPluginMetaData::findPlugins(pluginNamespace, [&mimeType](const KPluginMetaData &pluginMd) {
113 return pluginMd.supportsMimeType(mimeType);
114 });
115 return !plugins.isEmpty();
116 };
117 QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf6/parts"), supportsMime);
118 auto orderPredicate = [&](const KPluginMetaData &left, const KPluginMetaData &right) {
119 // We filtered based on "supports mimetype", but this didn't order from most-specific to least-specific.
120 const int leftDistance = pluginDistanceToMimeType(left, mimeType);
121 const int rightDistance = pluginDistanceToMimeType(right, mimeType);
122 if (leftDistance < rightDistance) {
123 return true;
124 }
125 if (leftDistance > rightDistance) {
126 return false;
127 }
128 // Plugins who support the same mimetype are then sorted by initial preference
129 const auto getInitialPreference = [](const KPluginMetaData &data) {
130 const QJsonObject obj = data.rawData();
131 if (const QJsonValue initialPref = obj.value(QLatin1String("KParts")).toObject().value(QLatin1String("InitialPreference")); !initialPref.isNull()) {
132 return initialPref.toInt();
133 }
134 return data.rawData().value(QLatin1String("KPlugin")).toObject().value(QLatin1String("InitialPreference")).toInt();
135 };
136 return getInitialPreference(left) > getInitialPreference(right);
137 };
138 std::sort(plugins.begin(), plugins.end(), orderPredicate);
139
140 const QList<KPluginMetaData> userParts = partsFromUserPreference(mimeType);
141 if (!userParts.isEmpty()) {
142 plugins = userParts;
143 }
144 return plugins;
145}
146
147void KParts::PartLoader::Private::getErrorStrings(QString *errorString, QString *errorText, const QString &argument, ErrorType type)
148{
149 switch (type) {
150 case CouldNotLoadPlugin:
151 *errorString = i18n("KPluginFactory could not load the plugin: %1", argument);
152 *errorText = QStringLiteral("KPluginFactory could not load the plugin: %1").arg(argument);
153 break;
154 case NoPartFoundForMimeType:
155 *errorString = i18n("No part was found for mimeType %1", argument);
156 *errorText = QStringLiteral("No part was found for mimeType %1").arg(argument);
157 break;
158 case NoPartInstantiatedForMimeType:
159 *errorString = i18n("No part could be instantiated for mimeType %1", argument);
160 *errorText = QStringLiteral("No part could be instantiated for mimeType %1").arg(argument);
161 break;
162 default:
163 qCWarning(KPARTSLOG) << "PartLoader::Private::getErrorStrings got unexpected error type" << type;
164 break;
165 }
166};
167
168#include "moc_partloader.cpp"
QStringList mimeTypes() const
QJsonObject rawData() const
static QList< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter={}, KPluginMetaDataOptions options={})
bool isValid() const
bool supportsMimeType(const QString &mimeType) const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18n(const char *text, const TYPE &arg...)
KPARTS_EXPORT PartCapabilities partCapabilities(const KPluginMetaData &data)
Parses the associated capabilities from the KPart.
KPARTS_EXPORT QList< KPluginMetaData > partsForMimeType(const QString &mimeType)
Locate all available KParts using KPluginMetaData::findPlugins for a mimetype.
PartCapability
Enum for standardized capabilities of KParts.
Definition partloader.h:38
QJsonValue value(QLatin1StringView key) const const
bool isNull() const const
bool isUndefined() const const
QJsonArray toArray() const const
QJsonObject toObject() const const
QVariant toVariant() const const
iterator begin()
iterator end()
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
const_iterator cend() const const
iterator find(const Key &key)
QMetaEnum fromType()
int keyToValue(const char *key, bool *ok) const const
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
QString arg(Args &&... args) const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
QStringList toStringList() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:51:08 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.