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"));
132 !initialPref.isUndefined()) {
133 return initialPref.toInt();
134 }
135 return data.rawData().value(QLatin1String("KPlugin")).toObject().value(QLatin1String("InitialPreference")).toInt();
136 };
137 return getInitialPreference(left) > getInitialPreference(right);
138 };
139 std::sort(plugins.begin(), plugins.end(), orderPredicate);
140
141 const QList<KPluginMetaData> userParts = partsFromUserPreference(mimeType);
142 if (!userParts.isEmpty()) {
143 plugins = userParts;
144 }
145 return plugins;
146}
147
148void KParts::PartLoader::Private::getErrorStrings(QString *errorString, QString *errorText, const QString &argument, ErrorType type)
149{
150 switch (type) {
151 case CouldNotLoadPlugin:
152 *errorString = i18n("KPluginFactory could not load the plugin: %1", argument);
153 *errorText = QStringLiteral("KPluginFactory could not load the plugin: %1").arg(argument);
154 break;
155 case NoPartFoundForMimeType:
156 *errorString = i18n("No part was found for mimeType %1", argument);
157 *errorText = QStringLiteral("No part was found for mimeType %1").arg(argument);
158 break;
159 case NoPartInstantiatedForMimeType:
160 *errorString = i18n("No part could be instantiated for mimeType %1", argument);
161 *errorText = QStringLiteral("No part could be instantiated for mimeType %1").arg(argument);
162 break;
163 default:
164 qCWarning(KPARTSLOG) << "PartLoader::Private::getErrorStrings got unexpected error type" << type;
165 break;
166 }
167};
168
169#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 isUndefined() const const
QJsonArray toArray() const const
int toInt(int defaultValue) const const
QJsonObject toObject() const const
QString toString() 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 Mon Nov 18 2024 12:11:50 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.