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 <QMimeDatabase>
18 #include <QMimeType>
19 
20 static QList<KPluginMetaData> partsFromUserPreference(const QString &mimeType)
21 {
22  auto config = KSharedConfig::openConfig(QStringLiteral("kpartsrc"), KConfig::NoGlobals);
23  const QStringList pluginIds = config->group(QStringLiteral("Added KDE Part Associations")).readXdgListEntry(mimeType);
24  QList<KPluginMetaData> plugins;
25  plugins.reserve(pluginIds.size());
26  for (const QString &pluginId : pluginIds) {
27  if (KPluginMetaData data(QLatin1String("kf6/parts/") + pluginId); data.isValid()) {
28  plugins << data;
29  }
30  }
31  return plugins;
32 }
33 
34 // A plugin can support N mimetypes. Pick the one that is closest to @parent in the inheritance tree
35 // and return how far it is from that parent (0 = same mimetype, 1 = direct child, etc.)
36 static int pluginDistanceToMimeType(const KPluginMetaData &md, const QString &parent)
37 {
38  QMimeDatabase db;
39  auto distanceToMimeType = [&](const QString &mime) {
40  if (mime == parent) {
41  return 0;
42  }
43  const QStringList ancestors = db.mimeTypeForName(mime).allAncestors();
44  const int dist = ancestors.indexOf(parent);
45  return dist == -1 ? 50 : dist + 1;
46  };
47  const QStringList mimes = md.mimeTypes();
48  int minDistance = 50;
49  for (const QString &mime : mimes) {
50  minDistance = std::min(minDistance, distanceToMimeType(mime));
51  }
52  return minDistance;
53 }
54 
56 {
57  auto supportsMime = [&mimeType](const KPluginMetaData &md) {
58  if (md.supportsMimeType(mimeType)) {
59  return true;
60  }
61  auto pluginJson = md.rawData();
62  auto pluginNamespace = pluginJson.value(QLatin1String("KParts")).toObject().value(QLatin1String("PluginNamespace")).toString();
63  if (pluginNamespace.isEmpty()) {
64  return false;
65  }
66  auto plugins = KPluginMetaData::findPlugins(pluginNamespace, [&mimeType](const KPluginMetaData &pluginMd) {
67  return pluginMd.supportsMimeType(mimeType);
68  });
69  return !plugins.isEmpty();
70  };
71  QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf6/parts"), supportsMime);
72  auto orderPredicate = [&](const KPluginMetaData &left, const KPluginMetaData &right) {
73  // We filtered based on "supports mimetype", but this didn't order from most-specific to least-specific.
74  const int leftDistance = pluginDistanceToMimeType(left, mimeType);
75  const int rightDistance = pluginDistanceToMimeType(right, mimeType);
76  if (leftDistance < rightDistance) {
77  return true;
78  }
79  if (leftDistance > rightDistance) {
80  return false;
81  }
82  // Plugins who support the same mimetype are then sorted by initial preference
83  const auto getInitialPreference = [](const KPluginMetaData &data) {
84  return data.rawData().value(QLatin1String("KPlugin")).toObject().value(QLatin1String("InitialPreference")).toInt();
85  };
86  return getInitialPreference(left) > getInitialPreference(right);
87  };
88  std::sort(plugins.begin(), plugins.end(), orderPredicate);
89 
90  const QList<KPluginMetaData> userParts = partsFromUserPreference(mimeType);
91  if (!userParts.isEmpty()) {
92  plugins = userParts;
93  }
94 
95  // for (const KPluginMetaData &plugin : plugins) {
96  // qDebug() << plugin.fileName() << plugin.initialPreference();
97  //}
98  return plugins;
99 }
100 
101 void KParts::PartLoader::Private::getErrorStrings(QString *errorString, QString *errorText, const QString &argument, ErrorType type)
102 {
103  switch (type) {
104  case CouldNotLoadPlugin:
105  *errorString = i18n("KPluginFactory could not load the plugin: %1", argument);
106  *errorText = QStringLiteral("KPluginFactory could not load the plugin: %1").arg(argument);
107  break;
108  case NoPartFoundForMimeType:
109  *errorString = i18n("No part was found for mimeType %1", argument);
110  *errorText = QStringLiteral("No part was found for mimeType %1").arg(argument);
111  break;
112  case NoPartInstantiatedForMimeType:
113  *errorString = i18n("No part could be instantiated for mimeType %1", argument);
114  *errorText = QStringLiteral("No part could be instantiated for mimeType %1").arg(argument);
115  break;
116  default:
117  qCWarning(KPARTSLOG) << "PartLoader::Private::getErrorStrings got unexpected error type" << type;
118  break;
119  }
120 };
QJsonObject rawData() const
bool isValid() const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void reserve(int alloc)
int size() const const
QString i18n(const char *text, const TYPE &arg...)
QStringList mimeTypes() const
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
static QList< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter={}, KPluginMetaDataOptions options={})
bool isEmpty() const const
QJsonValue value(const QString &key) const const
int indexOf(QStringView str, int from) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool supportsMimeType(const QString &mimeType) const
QList::iterator begin()
QList::iterator end()
KPARTS_EXPORT QList< KPluginMetaData > partsForMimeType(const QString &mimeType)
Locate all available KParts using KPluginMetaData::findPlugins for a mimetype.
Definition: partloader.cpp:55
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 03:48:58 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.