File indexing completed on 2024-04-28 04:58:11

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 1999 Simon Hausmann <hausmann@kde.org>
0004     SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "konq_kpart_plugin.h"
0010 
0011 #include <KConfigGroup>
0012 #include <KPluginFactory>
0013 #include <KPluginMetaData>
0014 #include <KService>
0015 #include <KSharedConfig>
0016 #include <KXMLGUIFactory>
0017 
0018 #include <QDir>
0019 #include <QFile>
0020 #include <QFileInfo>
0021 #include <QStandardPaths>
0022 
0023 namespace KonqParts
0024 {
0025 
0026 class PluginPrivate
0027 {
0028 public:
0029     QString m_parentInstance;
0030     QString m_pluginId;
0031 };
0032 
0033 Plugin::Plugin(QObject *parent)
0034     : QObject(parent)
0035     , d(new PluginPrivate())
0036 {
0037 }
0038 
0039 Plugin::~Plugin() = default;
0040 
0041 QString Plugin::xmlFile() const
0042 {
0043     QString path = KXMLGUIClient::xmlFile();
0044 
0045     if (d->m_parentInstance.isEmpty() || (!path.isEmpty() && QDir::isAbsolutePath(path))) {
0046         return path;
0047     }
0048 
0049     QString absPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, d->m_parentInstance + QLatin1Char('/') + path);
0050     Q_ASSERT(!absPath.isEmpty());
0051     return absPath;
0052 }
0053 
0054 QString Plugin::localXMLFile() const
0055 {
0056     QString path = KXMLGUIClient::xmlFile();
0057 
0058     if (d->m_parentInstance.isEmpty() || (!path.isEmpty() && QDir::isAbsolutePath(path))) {
0059         return path;
0060     }
0061 
0062     QString absPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + d->m_parentInstance + QLatin1Char('/') + path;
0063     return absPath;
0064 }
0065 
0066 // static
0067 QList<Plugin::PluginInfo> Plugin::pluginInfos(const QString &componentName)
0068 {
0069     QList<PluginInfo> plugins;
0070 
0071     QVector<KPluginMetaData> metaDataList = KPluginMetaData::findPlugins(componentName + QStringLiteral("/kpartplugins"));
0072     std::sort(metaDataList.begin(), metaDataList.end(), [](const KPluginMetaData &d1, const KPluginMetaData &d2) {
0073         return d1.pluginId() < d2.pluginId();
0074     });
0075 
0076     for (const KPluginMetaData &data : metaDataList) {
0077         PluginInfo info;
0078         info.m_metaData = data;
0079         QString doc;
0080         const QString fullComponentName = QStringLiteral("konqueror/partsrcfiles/") + QFileInfo(data.fileName()).baseName();
0081         const auto files = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, fullComponentName + QLatin1String(".rc"));
0082         info.m_absXMLFileName = KXMLGUIClient::findMostRecentXMLFile(files, doc);
0083         doc = KXMLGUIFactory::readConfigFile(info.m_absXMLFileName);
0084         if (info.m_absXMLFileName.isEmpty()) {
0085             continue;
0086         }
0087 
0088         info.m_document.setContent(doc);
0089         if (info.m_document.documentElement().isNull()) {
0090             continue;
0091         }
0092 
0093         const QString tryExec = data.value(QStringLiteral("TryExec"));
0094         if (!tryExec.isEmpty() && QStandardPaths::findExecutable(tryExec).isEmpty()) {
0095             continue;
0096         }
0097 
0098         plugins.append(info);
0099     }
0100 
0101     return plugins;
0102 }
0103 
0104 void Plugin::loadPlugins(QObject *parent, const QList<PluginInfo> &pluginInfos, const QString &componentName)
0105 {
0106     for (const auto &pluginInfo : pluginInfos) {
0107         if (hasPlugin(parent, pluginInfo.m_metaData.pluginId())) {
0108             continue;
0109         }
0110 
0111         Plugin *plugin = loadPlugin(parent, pluginInfo.m_metaData);
0112 
0113         if (plugin) {
0114             plugin->d->m_parentInstance = componentName;
0115             plugin->setXMLFile(pluginInfo.m_absXMLFileName, false, false);
0116             plugin->setDOMDocument(pluginInfo.m_document);
0117         }
0118     }
0119 }
0120 
0121 // static
0122 Plugin *Plugin::loadPlugin(QObject *parent, const KPluginMetaData &data)
0123 {
0124     auto pluginResult = KPluginFactory::instantiatePlugin<Plugin>(data, parent);
0125     if (pluginResult) {
0126         pluginResult.plugin->d->m_pluginId = data.pluginId();
0127     }
0128     return pluginResult.plugin;
0129 }
0130 
0131 QList<KonqParts::Plugin *> Plugin::pluginObjects(QObject *parent)
0132 {
0133     QList<KonqParts::Plugin *> objects;
0134 
0135     if (!parent) {
0136         return objects;
0137     }
0138 
0139     objects = parent->findChildren<Plugin *>(QString(), Qt::FindDirectChildrenOnly);
0140     return objects;
0141 }
0142 
0143 bool Plugin::hasPlugin(QObject *parent, const QString &pluginId)
0144 {
0145     const QObjectList plugins = parent->children();
0146 
0147     return std::any_of(plugins.begin(), plugins.end(), [&pluginId](QObject *p) {
0148         Plugin *plugin = qobject_cast<Plugin *>(p);
0149         return (plugin && plugin->d->m_pluginId == pluginId);
0150     });
0151 }
0152 
0153 
0154 void Plugin::setMetaData(const KPluginMetaData &metaData)
0155 {
0156     // backward-compatible registration, usage deprecated
0157     KXMLGUIClient::setComponentName(metaData.pluginId(), metaData.name());
0158 }
0159 
0160 void Plugin::loadPlugins(QObject *parent, KXMLGUIClient *parentGUIClient, const QString &componentName)
0161 {
0162     KConfigGroup cfgGroup(KSharedConfig::openConfig(componentName + QLatin1String("rc")), "KParts Plugins");
0163     const QList<PluginInfo> plugins = pluginInfos(componentName) << pluginInfos("konqueror");
0164     for (const auto &pluginInfo : plugins) {
0165         QDomElement docElem = pluginInfo.m_document.documentElement();
0166 
0167         bool pluginEnabled = pluginInfo.m_metaData.isEnabled(cfgGroup);
0168         // search through already present plugins
0169         const QObjectList pluginList = parent->children();
0170 
0171         bool pluginFound = false;
0172         for (auto *p : pluginList) {
0173             Plugin *plugin = qobject_cast<Plugin *>(p);
0174             if (plugin && plugin->d->m_pluginId == pluginInfo.m_metaData.pluginId()) {
0175                 // delete and unload disabled plugins
0176                 if (!pluginEnabled) {
0177                     // qDebug() << "remove plugin " << name;
0178                     KXMLGUIFactory *factory = plugin->factory();
0179                     if (factory) {
0180                         factory->removeClient(plugin);
0181                     }
0182                     delete plugin;
0183                 }
0184 
0185                 pluginFound = true;
0186                 break;
0187             }
0188         }
0189 
0190         // if the plugin is already loaded or if it's disabled in the
0191         // configuration do nothing
0192         if (pluginFound || !pluginEnabled) {
0193             continue;
0194         }
0195 
0196         // qDebug() << "load plugin " << name << " " << library << " " << keyword;
0197         Plugin *plugin = loadPlugin(parent, pluginInfo.m_metaData);
0198 
0199         if (plugin) {
0200             plugin->d->m_parentInstance = componentName;
0201             plugin->setXMLFile(pluginInfo.m_absXMLFileName, false, false);
0202             plugin->setDOMDocument(pluginInfo.m_document);
0203             parentGUIClient->insertChildClient(plugin);
0204         }
0205     }
0206 }
0207 }
0208