File indexing completed on 2024-05-19 12:54:43

0001 /* This file is part of the KDE project
0002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
0003    Copyright (C) 2007 David Faure <faure@kde.org>
0004    Copyright (C) 2015 Jarosław Staniek <staniek@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "KexiJsonTrader.h"
0023 #include "utils.h"
0024 
0025 #include <QDebug>
0026 #include <QList>
0027 #include <QPluginLoader>
0028 #include <QJsonObject>
0029 #include <QJsonArray>
0030 #include <QDirIterator>
0031 #include <QDir>
0032 #include <QCoreApplication>
0033 
0034 class Q_DECL_HIDDEN KexiJsonTrader::Private
0035 {
0036 public:
0037     Private(const QString &subDir) : m_subDir(subDir)
0038     {
0039     }
0040 
0041     QStringList pluginPaths()
0042     {
0043         if (!m_pluginPathFound) {
0044             QStringList searchDirs;
0045             searchDirs += QCoreApplication::libraryPaths();
0046             for (const QString &dir : searchDirs) {
0047                 const QString possiblePath = dir + QLatin1Char('/') + m_subDir;
0048                 if (QDir(possiblePath).exists()) {
0049                     m_pluginPaths += possiblePath;
0050                 }
0051             }
0052             m_pluginPathFound = true;
0053         }
0054         return m_pluginPaths;
0055     }
0056 
0057 private:
0058     QString m_subDir;
0059     QStringList m_pluginPaths;
0060     bool m_pluginPathFound = false;
0061 };
0062 
0063 // ---
0064 
0065 KexiJsonTrader::KexiJsonTrader(const QString& subDir)
0066     : d(new Private(subDir))
0067 {
0068 }
0069 
0070 KexiJsonTrader::~KexiJsonTrader()
0071 {
0072     delete d;
0073 }
0074 
0075 //! @return true if at least one service type from @a serviceTypeNames exists in @a foundServiceTypes
0076 static bool supportsAtLeastServiceType(const QStringList &foundServiceTypes,
0077                                        const QStringList &serviceTypeNames)
0078 {
0079     foreach(const QString &serviceTypeName, serviceTypeNames) {
0080         if (foundServiceTypes.contains(serviceTypeName)) {
0081             return true;
0082         }
0083     }
0084     return false;
0085 }
0086 
0087 //static
0088 QJsonObject KexiJsonTrader::metaDataObjectForPluginLoader(const QPluginLoader &pluginLoader)
0089 {
0090     return pluginLoader.metaData().value(QLatin1String("MetaData")).toObject();
0091 }
0092 
0093 //static
0094 QJsonObject KexiJsonTrader::rootObjectForPluginLoader(const QPluginLoader &pluginLoader)
0095 {
0096     QJsonObject json = metaDataObjectForPluginLoader(pluginLoader);
0097     if (json.isEmpty()) {
0098         return QJsonObject();
0099     }
0100     return json.value(QLatin1String("KPlugin")).toObject();
0101 }
0102 
0103 //! Checks loader @a loader
0104 static bool checkLoader(QPluginLoader *loader, const QStringList &servicetypes,
0105                         const QString &mimetype)
0106 {
0107     const QJsonObject pluginData = KexiJsonTrader::rootObjectForPluginLoader(*loader);
0108     if (pluginData.isEmpty()) {
0109         //qDebug() << dirIter.filePath() << "has no json!";
0110         return false;
0111     }
0112     const QJsonArray foundServiceTypesAray = pluginData.value(QLatin1String("ServiceTypes")).toArray();
0113     if (foundServiceTypesAray.isEmpty()) {
0114         qWarning() << "No ServiceTypes defined for plugin" << loader->fileName() << "-- skipping!";
0115         return false;
0116     }
0117     QStringList foundServiceTypes = KexiUtils::convertTypesUsingMethod<QVariant, QString, &QVariant::toString>(foundServiceTypesAray.toVariantList());
0118     if (!supportsAtLeastServiceType(foundServiceTypes, servicetypes)) {
0119         return false;
0120     }
0121 
0122     if (!mimetype.isEmpty()) {
0123         QJsonObject json = KexiJsonTrader::metaDataObjectForPluginLoader(*loader);
0124         QStringList mimeTypes = json.value(QLatin1String("X-KDE-ExtraNativeMimeTypes"))
0125                 .toString().split(QLatin1Char(','));
0126         mimeTypes += json.value(QLatin1String("MimeType")).toString().split(QLatin1Char(';'));
0127         mimeTypes += json.value(QLatin1String("X-KDE-NativeMimeType")).toString();
0128         if (! mimeTypes.contains(mimetype)) {
0129             return false;
0130         }
0131     }
0132     return true;
0133 }
0134 
0135 static QList<QPluginLoader *> findPlugins(const QString &path, const QStringList &servicetypes,
0136                                           const QString &mimetype)
0137 {
0138     QList<QPluginLoader*> list;
0139     QDirIterator dirIter(path,
0140                          /* QDirIterator::Subdirectories -- Since 3.0.1: Don't look into subdirs
0141                                                             because there may be 3.x dirs from
0142                                                             future Kexi versions. We will look
0143                                                             into subdirs since 3.1 again. */
0144                          QDirIterator::FollowSymlinks);
0145     while (dirIter.hasNext()) {
0146         dirIter.next();
0147         if (dirIter.fileInfo().isFile()) {
0148             QPluginLoader *loader = new QPluginLoader(dirIter.filePath());
0149             if (checkLoader(loader, servicetypes, mimetype)) {
0150                 list.append(loader);
0151             } else {
0152                 delete loader;
0153             }
0154         }
0155     }
0156     return list;
0157 }
0158 
0159 QList<QPluginLoader *> KexiJsonTrader::query(const QStringList &servicetypes,
0160                                              const QString &mimetype)
0161 {
0162     QList<QPluginLoader *> list;
0163     foreach(const QString &path, d->pluginPaths()) {
0164         list += findPlugins(path, servicetypes, mimetype);
0165     }
0166     return list;
0167 }
0168 
0169 QList<QPluginLoader *> KexiJsonTrader::query(const QString &servicetype, const QString &mimetype)
0170 {
0171     QStringList servicetypes;
0172     servicetypes << servicetype;
0173     return query(servicetypes, mimetype);
0174 }
0175 
0176 QStringList KexiJsonTrader::pluginPaths() const
0177 {
0178     return d->pluginPaths();
0179 }