KParts

plugin.cpp
1 /*
2  This file is part of the KDE project
3  SPDX-FileCopyrightText: 1999 Simon Hausmann <[email protected]>
4  SPDX-FileCopyrightText: 1999 David Faure <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "plugin.h"
10 
11 #include "part.h"
12 
13 #include <KConfigGroup>
14 #include <KDesktopFile>
15 #include <KLocalizedString>
16 #include <KPluginFactory>
17 #include <KPluginLoader>
18 #include <KPluginMetaData>
19 #include <KSharedConfig>
20 #include <KXMLGUIFactory>
21 #if !KPARTS_BUILD_DEPRECATED_SINCE(5, 77) || KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 76)
22 #include <KAboutData>
23 #endif
24 
25 #include <QDir>
26 #include <QFile>
27 #include <QFileInfo>
28 #include <QStandardPaths>
29 
30 using namespace KParts;
31 
32 class KParts::PluginPrivate
33 {
34 public:
35  QString m_parentInstance;
36  QString m_library; // filename of the library
37 };
38 
40  : QObject(parent)
41  , d(new PluginPrivate())
42 {
43  // qDebug() << className();
44 }
45 
46 Plugin::~Plugin() = default;
47 
49 {
51 
52  if (d->m_parentInstance.isEmpty() || (!path.isEmpty() && QDir::isAbsolutePath(path))) {
53  return path;
54  }
55 
56  QString absPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, d->m_parentInstance + QLatin1Char('/') + path);
57  Q_ASSERT(!absPath.isEmpty());
58  return absPath;
59 }
60 
62 {
64 
65  if (d->m_parentInstance.isEmpty() || (!path.isEmpty() && QDir::isAbsolutePath(path))) {
66  return path;
67  }
68 
69  QString absPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + d->m_parentInstance + QLatin1Char('/') + path;
70  return absPath;
71 }
72 
73 // static
74 QList<Plugin::PluginInfo> Plugin::pluginInfos(const QString &componentName)
75 {
76  QList<PluginInfo> plugins;
77 
78  QMap<QString, QStringList> sortedPlugins;
79 
80  const QStringList dirs =
82  for (const QString &dir : dirs) {
83  const auto rcfiles = QDir(dir).entryList(QStringList(QStringLiteral("*.rc")));
84  for (const QString &file : rcfiles) {
85  const QFileInfo fInfo(dir + QLatin1Char('/') + file);
86  QMap<QString, QStringList>::Iterator mapIt = sortedPlugins.find(fInfo.fileName());
87  if (mapIt == sortedPlugins.end()) {
88  mapIt = sortedPlugins.insert(fInfo.fileName(), QStringList());
89  }
90  mapIt.value().append(fInfo.absoluteFilePath());
91  }
92  }
93 
95  QMap<QString, QStringList>::ConstIterator mapEnd = sortedPlugins.constEnd();
96  for (; mapIt != mapEnd; ++mapIt) {
97  PluginInfo info;
98  QString doc;
99  info.m_absXMLFileName = KXMLGUIClient::findMostRecentXMLFile(mapIt.value(), doc);
100  if (info.m_absXMLFileName.isEmpty()) {
101  continue;
102  }
103 
104  // qDebug() << "found KParts Plugin : " << info.m_absXMLFileName;
105  info.m_relXMLFileName = QLatin1String("kpartplugins/") + mapIt.key();
106 
107  info.m_document.setContent(doc);
108  if (info.m_document.documentElement().isNull()) {
109  continue;
110  }
111 
112  plugins.append(info);
113  }
114 
115  return plugins;
116 }
117 
118 void Plugin::loadPlugins(QObject *parent, const QString &componentName)
119 {
120  loadPlugins(parent, pluginInfos(componentName), componentName);
121 }
122 
123 void Plugin::loadPlugins(QObject *parent, const QList<PluginInfo> &pluginInfos, const QString &componentName)
124 {
125  for (const auto &pluginInfo : pluginInfos) {
126  const QString library = pluginInfo.m_document.documentElement().attribute(QStringLiteral("library"));
127 
128  if (library.isEmpty() || hasPlugin(parent, library)) {
129  continue;
130  }
131 
132  Plugin *plugin = loadPlugin(parent, library, pluginInfo.m_document.documentElement().attribute(QStringLiteral("X-KDE-PluginKeyword")));
133 
134  if (plugin) {
135  plugin->d->m_parentInstance = componentName;
136  plugin->setXMLFile(pluginInfo.m_relXMLFileName, false, false);
137  plugin->setDOMDocument(pluginInfo.m_document);
138  }
139  }
140 }
141 
143 {
144  loadPlugins(parent, pluginInfos, QString());
145 }
146 
147 // static
148 Plugin *Plugin::loadPlugin(QObject *parent, const QString &libname, const QString &keyword)
149 {
150  KPluginLoader loader(libname);
151  KPluginFactory *factory = loader.factory();
152 
153  if (!factory) {
154  return nullptr;
155  }
156 
157  Plugin *plugin = factory->create<Plugin>(keyword, parent);
158  if (!plugin) {
159  return nullptr;
160  }
161  plugin->d->m_library = libname;
162  return plugin;
163 }
164 
166 {
167  QList<KParts::Plugin *> objects;
168 
169  if (!parent) {
170  return objects;
171  }
172 
173  objects = parent->findChildren<Plugin *>(QString(), Qt::FindDirectChildrenOnly);
174  return objects;
175 }
176 
177 bool Plugin::hasPlugin(QObject *parent, const QString &library)
178 {
179  const QObjectList plugins = parent->children();
180 
181  return std::any_of(plugins.begin(), plugins.end(), [&library](QObject *p) {
182  Plugin *plugin = qobject_cast<Plugin *>(p);
183  return (plugin && plugin->d->m_library == library);
184  });
185 }
186 
187 #if KPARTS_BUILD_DEPRECATED_SINCE(5, 77)
188 void Plugin::setComponentData(const KAboutData &pluginData)
189 {
190  // backward-compatible registration, usage deprecated
191 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 76)
192  QT_WARNING_PUSH
193  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
194  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
195  KAboutData::registerPluginData(pluginData);
196  QT_WARNING_POP
197 #endif
198 
199  KXMLGUIClient::setComponentName(pluginData.componentName(), pluginData.displayName());
200 }
201 #endif
202 
204 {
205  // backward-compatible registration, usage deprecated
206 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 76)
207  QT_WARNING_PUSH
208  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
209  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
211  QT_WARNING_POP
212 #endif
213 
214  KXMLGUIClient::setComponentName(metaData.pluginId(), metaData.name());
215 }
216 
218  KXMLGUIClient *parentGUIClient,
219  const QString &componentName,
220  bool enableNewPluginsByDefault,
221  int interfaceVersionRequired)
222 {
223  KConfigGroup cfgGroup(KSharedConfig::openConfig(componentName + QLatin1String("rc")), "KParts Plugins");
224  const QList<PluginInfo> plugins = pluginInfos(componentName);
225  for (const auto &pluginInfo : plugins) {
226  QDomElement docElem = pluginInfo.m_document.documentElement();
227  QString library = docElem.attribute(QStringLiteral("library"));
228  QString keyword;
229 
230  if (library.isEmpty()) {
231  continue;
232  }
233 
234  // Check configuration
235  const QString name = docElem.attribute(QStringLiteral("name"));
236 
237  bool pluginEnabled = enableNewPluginsByDefault;
238  if (cfgGroup.hasKey(name + QLatin1String("Enabled"))) {
239  pluginEnabled = cfgGroup.readEntry(name + QLatin1String("Enabled"), false);
240  } else { // no user-setting, load plugin default setting
241  QString relPath = componentName + QLatin1Char('/') + pluginInfo.m_relXMLFileName;
242  relPath.truncate(relPath.lastIndexOf(QLatin1Char('.'))); // remove extension
243  relPath += QLatin1String(".desktop");
244  // qDebug() << "looking for " << relPath;
246  if (!desktopfile.isEmpty()) {
247  // qDebug() << "loadPlugins found desktop file for " << name << ": " << desktopfile;
248  KDesktopFile _desktop(desktopfile);
249  const KConfigGroup desktop = _desktop.desktopGroup();
250  keyword = desktop.readEntry("X-KDE-PluginKeyword", "");
251  pluginEnabled = desktop.readEntry("X-KDE-PluginInfo-EnabledByDefault", enableNewPluginsByDefault);
252  if (interfaceVersionRequired != 0) {
253  const int version = desktop.readEntry("X-KDE-InterfaceVersion", 1);
254  if (version != interfaceVersionRequired) {
255  // qDebug() << "Discarding plugin " << name << ", interface version " << version << ", expected " << interfaceVersionRequired;
256  pluginEnabled = false;
257  }
258  }
259  } else {
260  // qDebug() << "loadPlugins no desktop file found in " << relPath;
261  }
262  }
263 
264  // search through already present plugins
265  const QObjectList pluginList = parent->children();
266 
267  bool pluginFound = false;
268  for (auto *p : pluginList) {
269  Plugin *plugin = qobject_cast<Plugin *>(p);
270  if (plugin && plugin->d->m_library == library) {
271  // delete and unload disabled plugins
272  if (!pluginEnabled) {
273  // qDebug() << "remove plugin " << name;
274  KXMLGUIFactory *factory = plugin->factory();
275  if (factory) {
276  factory->removeClient(plugin);
277  }
278  delete plugin;
279  }
280 
281  pluginFound = true;
282  break;
283  }
284  }
285 
286  // if the plugin is already loaded or if it's disabled in the
287  // configuration do nothing
288  if (pluginFound || !pluginEnabled) {
289  continue;
290  }
291 
292  // qDebug() << "load plugin " << name << " " << library << " " << keyword;
293  Plugin *plugin = loadPlugin(parent, library, keyword);
294 
295  if (plugin) {
296  plugin->d->m_parentInstance = componentName;
297  plugin->setXMLFile(pluginInfo.m_relXMLFileName, false, false);
298  plugin->setDOMDocument(pluginInfo.m_document);
299  parentGUIClient->insertChildClient(plugin);
300  }
301  }
302 }
FindDirectChildrenOnly
void truncate(int position)
QString xmlFile() const override
Reimplemented for internal reasons.
Definition: plugin.cpp:48
QString writableLocation(QStandardPaths::StandardLocation type)
QString name() const
QStringList locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
QString componentName() const
QString attribute(const QString &name, const QString &defValue) const const
void removeClient(KXMLGUIClient *client)
void setMetaData(const KPluginMetaData &metaData)
Definition: plugin.cpp:203
~Plugin() override
Destructor.
T * create(QObject *parent=nullptr, const QVariantList &args=QVariantList())
QMap::const_iterator constBegin() const const
const QObjectList & children() const const
virtual void setXMLFile(const QString &file, bool merge=false, bool setXMLDoc=true)
KXMLGUIFactory * factory() const
virtual QString componentName() const
virtual QString xmlFile() const
virtual void setDOMDocument(const QDomDocument &document, bool merge=false)
const QLatin1String name
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
static void registerPluginData(const KAboutData &aboutData)
QList< T > findChildren(const QString &name, Qt::FindChildOptions options) const const
void append(const T &value)
QString fileName() const const
QString absoluteFilePath() const const
bool isEmpty() const const
QMap::const_iterator constEnd() const const
static void loadPlugins(QObject *parent, const QString &instance)
Load the plugin libraries from the directories appropriate to instance and make the Plugin objects ch...
Definition: plugin.cpp:118
QMap::iterator end()
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static KAboutData fromPluginMetaData(const KPluginMetaData &plugin)
bool hasKey(const QString &key) const
const Key key(const T &value, const Key &defaultKey) const const
KPluginFactory * factory()
virtual void setComponentName(const QString &componentName, const QString &componentDisplayName)
QString displayName() const
bool isAbsolutePath(const QString &path)
static QList< Plugin * > pluginObjects(QObject *parent)
Returns a list of plugin objects loaded for parent.
Definition: plugin.cpp:165
QString localXMLFile() const override
Reimplemented for internal reasons.
Definition: plugin.cpp:61
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
Plugin(QObject *parent=nullptr)
Construct a new KParts plugin.
Definition: plugin.cpp:39
QMap::iterator insert(const Key &key, const T &value)
void insertChildClient(KXMLGUIClient *child)
T qobject_cast(QObject *object)
QObject * parent() const const
The KParts namespace,.
A plugin is the way to add actions to an existing KParts application, or to a Part.
Definition: plugin.h:46
T readEntry(const QString &key, const T &aDefault) const
QMap::iterator find(const Key &key)
QString pluginId() const
typedef QObjectList
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
const T value(const Key &key, const T &defaultValue) const const
virtual void setComponentData(const KAboutData &pluginData)
Definition: plugin.cpp:188
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Nov 29 2021 22:49:22 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.