File indexing completed on 2024-05-12 16:39:56

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() : pluginPathFound(false)
0038     {
0039     }
0040     QString subDir;
0041     bool pluginPathFound;
0042     QStringList pluginPaths;
0043 };
0044 
0045 // ---
0046 
0047 KexiJsonTrader::KexiJsonTrader(const QString& subDir)
0048     : d(new Private)
0049 {
0050     Q_ASSERT(!subDir.isEmpty());
0051     Q_ASSERT(!subDir.contains(' '));
0052     d->subDir = subDir;
0053 }
0054 
0055 KexiJsonTrader::~KexiJsonTrader()
0056 {
0057     delete d;
0058 }
0059 
0060 //! @return true if at least one service type from @a serviceTypeNames exists in @a foundServiceTypes
0061 static bool supportsAtLeastServiceType(const QStringList &foundServiceTypes,
0062                                        const QStringList &serviceTypeNames)
0063 {
0064     foreach(const QString &serviceTypeName, serviceTypeNames) {
0065         if (foundServiceTypes.contains(serviceTypeName)) {
0066             return true;
0067         }
0068     }
0069     return false;
0070 }
0071 
0072 //static
0073 QJsonObject KexiJsonTrader::metaDataObjectForPluginLoader(const QPluginLoader &pluginLoader)
0074 {
0075     return pluginLoader.metaData().value(QLatin1String("MetaData")).toObject();
0076 }
0077 
0078 //static
0079 QJsonObject KexiJsonTrader::rootObjectForPluginLoader(const QPluginLoader &pluginLoader)
0080 {
0081     QJsonObject json = metaDataObjectForPluginLoader(pluginLoader);
0082     if (json.isEmpty()) {
0083         return QJsonObject();
0084     }
0085     return json.value(QLatin1String("KPlugin")).toObject();
0086 }
0087 
0088 //! Checks loader @a loader
0089 static bool checkLoader(QPluginLoader *loader, const QStringList &servicetypes,
0090                         const QString &mimetype)
0091 {
0092     const QJsonObject pluginData = KexiJsonTrader::rootObjectForPluginLoader(*loader);
0093     if (pluginData.isEmpty()) {
0094         //qDebug() << dirIter.filePath() << "has no json!";
0095         return false;
0096     }
0097     const QJsonArray foundServiceTypesAray = pluginData.value(QLatin1String("ServiceTypes")).toArray();
0098     if (foundServiceTypesAray.isEmpty()) {
0099         qWarning() << "No ServiceTypes defined for plugin" << loader->fileName() << "-- skipping!";
0100         return false;
0101     }
0102     QStringList foundServiceTypes = KexiUtils::convertTypesUsingMethod<QVariant, QString, &QVariant::toString>(foundServiceTypesAray.toVariantList());
0103     if (!supportsAtLeastServiceType(foundServiceTypes, servicetypes)) {
0104         return false;
0105     }
0106 
0107     if (!mimetype.isEmpty()) {
0108         QJsonObject json = KexiJsonTrader::metaDataObjectForPluginLoader(*loader);
0109         QStringList mimeTypes = json.value(QLatin1String("X-KDE-ExtraNativeMimeTypes"))
0110                 .toString().split(QLatin1Char(','));
0111         mimeTypes += json.value(QLatin1String("MimeType")).toString().split(QLatin1Char(';'));
0112         mimeTypes += json.value(QLatin1String("X-KDE-NativeMimeType")).toString();
0113         if (! mimeTypes.contains(mimetype)) {
0114             return false;
0115         }
0116     }
0117     return true;
0118 }
0119 
0120 static QList<QPluginLoader *> findPlugins(const QString &path, const QStringList &servicetypes,
0121                                           const QString &mimetype)
0122 {
0123     QList<QPluginLoader*> list;
0124     QDirIterator dirIter(path,
0125                          /* QDirIterator::Subdirectories -- Since 3.0.1: Don't look into subdirs
0126                                                             because there may be 3.x dirs from
0127                                                             future Kexi versions. We will look
0128                                                             into subdirs since 3.1 again. */
0129                          QDirIterator::FollowSymlinks);
0130     while (dirIter.hasNext()) {
0131         dirIter.next();
0132         if (dirIter.fileInfo().isFile()) {
0133             QPluginLoader *loader = new QPluginLoader(dirIter.filePath());
0134             if (checkLoader(loader, servicetypes, mimetype)) {
0135                 list.append(loader);
0136             } else {
0137                 delete loader;
0138             }
0139         }
0140     }
0141     return list;
0142 }
0143 
0144 QList<QPluginLoader *> KexiJsonTrader::query(const QStringList &servicetypes,
0145                                              const QString &mimetype)
0146 {
0147     if (!d->pluginPathFound) {
0148         QStringList searchDirs;
0149         searchDirs += QCoreApplication::libraryPaths();
0150         foreach(const QString &dir, searchDirs) {
0151             //qDebug() << dir;
0152             QString possiblePath = dir + QLatin1Char('/') + d->subDir;
0153             if (QDir(possiblePath).exists()) {
0154                 d->pluginPaths += possiblePath;
0155             }
0156         }
0157         d->pluginPathFound = true;
0158     }
0159 
0160     QList<QPluginLoader *> list;
0161     foreach(const QString &path, d->pluginPaths) {
0162         list += findPlugins(path, servicetypes, mimetype);
0163     }
0164     return list;
0165 }
0166 
0167 QList<QPluginLoader *> KexiJsonTrader::query(const QString &servicetype, const QString &mimetype)
0168 {
0169     QStringList servicetypes;
0170     servicetypes << servicetype;
0171     return query(servicetypes, mimetype);
0172 }