File indexing completed on 2024-04-28 11:20:44

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com>
0004 */
0005 
0006 #include <vector>
0007 
0008 #include "backend.h"
0009 #include "extension.h"
0010 
0011 #include <QCoreApplication>
0012 #include <QDir>
0013 #include <QPluginLoader>
0014 #include <QProcess>
0015 #include <QRegularExpression>
0016 #include <QStandardPaths>
0017 #include <QUrl>
0018 
0019 #include <KPluginFactory>
0020 #include <KPluginMetaData>
0021 #include <KPluginFactory>
0022 #include <KLocalizedString>
0023 
0024 using namespace Cantor;
0025 
0026 class Cantor::BackendPrivate
0027 {
0028   public:
0029     QString name;
0030     QString comment;
0031     QString icon;
0032     QString url;
0033     bool enabled{true};
0034     QList<GraphicPackage> supportedGraphicPackagesCache;
0035 };
0036 
0037 Backend::Backend(QObject* parent, const QList<QVariant>& args) : QObject(parent),
0038                                                                 d(new BackendPrivate)
0039 {
0040     Q_UNUSED(args)
0041 }
0042 
0043 Backend::~Backend()
0044 {
0045     delete d;
0046 }
0047 
0048 QString Backend::name() const
0049 {
0050     return d->name;
0051 }
0052 
0053 QString Backend::comment() const
0054 {
0055     return d->comment;
0056 }
0057 
0058 QString Backend::description() const
0059 {
0060     return comment();
0061 }
0062 
0063 QString Backend::icon() const
0064 {
0065     return d->icon;
0066 }
0067 
0068 QString Backend::url() const
0069 {
0070     return d->url;
0071 }
0072 
0073 QString Backend::defaultHelp() const
0074 {
0075     return QString();
0076 }
0077 
0078 bool Backend::isEnabled() const
0079 {
0080     return d->enabled && requirementsFullfilled();
0081 }
0082 
0083 void Backend::setEnabled(bool enabled)
0084 {
0085     d->enabled = enabled;
0086 }
0087 
0088 QStringList Backend::listAvailableBackends()
0089 {
0090     QStringList l;
0091     for (Backend* b : availableBackends())
0092     {
0093         if(b->isEnabled())
0094             l<<b->name();
0095     }
0096 
0097     return l;
0098 }
0099 
0100 QList<Backend*> Backend::availableBackends()
0101 {
0102     static QList<Backend*> backendCache;
0103     //if we already have all backends Cached, just return the cache.
0104     //otherwise create the available backends
0105     if(!backendCache.isEmpty())
0106     {
0107         return backendCache;
0108     }
0109 
0110     const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("cantor/backends"));
0111 
0112     for (const KPluginMetaData &plugin : plugins) {
0113 
0114         const auto result = KPluginFactory::instantiatePlugin<Backend>(plugin, QCoreApplication::instance());
0115 
0116         if (!result) {
0117             qDebug() << "Error while loading backend: " << result.errorText;
0118             continue;
0119         }
0120 
0121         Backend *backend = result.plugin;
0122 
0123         backend->d->name = plugin.name();
0124         backend->d->comment = plugin.description();
0125         backend->d->icon = plugin.iconName();
0126         backend->d->url = plugin.website();
0127         backendCache << backend;
0128     }
0129 
0130     return backendCache;
0131 }
0132 
0133 Backend* Backend::getBackend(const QString& name)
0134 {
0135     for (Backend* b : availableBackends())
0136     {
0137         if(b->name().toLower()==name.toLower() || b->id().toLower()==name.toLower())
0138             return b;
0139     }
0140 
0141     return nullptr;
0142 }
0143 
0144 QStringList Backend::extensions() const
0145 {
0146     QList<Extension*> extensions = findChildren<Extension*>(QRegularExpression(QLatin1String(".*Extension")));
0147     QStringList names;
0148     for (Extension* e : extensions)
0149         names << e->objectName();
0150     return names;
0151 }
0152 
0153 Extension* Backend::extension(const QString& name) const
0154 {
0155     return findChild<Extension*>(name);
0156 }
0157 
0158 bool Backend::checkExecutable(const QString& name, const QString& path, QString* reason)
0159 {
0160     if (path.isEmpty())
0161     {
0162         if (reason)
0163             *reason = i18n("No path for the %1 executable specified. "
0164                         "Please provide the correct path in the application settings and try again.",
0165                         name);
0166         return false;
0167     }
0168 
0169     QFileInfo info(path);
0170     if (!info.exists())
0171     {
0172         if (reason)
0173             *reason = i18n("The specified file '%1' for the %2 executable doesn't exist. "
0174                         "Please provide the correct path in the application settings and try again.",
0175                         path, name);
0176         return false;
0177     }
0178 
0179     if (!info.isExecutable())
0180     {
0181         if (reason)
0182             *reason = i18n("The specified file '%1' doesn't point to an executable. "
0183                         "Please provide the correct path in the application settings and try again.",
0184                         path);
0185         return false;
0186     }
0187 
0188     return true;
0189 }
0190 
0191 bool Cantor::Backend::testProgramWritable(const QString& program, const QStringList& args, const QString& filename, const QString& expectedContent, QString* reason, int timeOut)
0192 {
0193     QProcess process;
0194     process.setProgram(program);
0195     process.setArguments(args);
0196     process.start();
0197 
0198     if (process.waitForFinished(timeOut) == false)
0199     {
0200         if (reason)
0201             *reason = i18n("The program %1 didn't finish the execution after %2 milliseconds during the plot integration test.", QFileInfo(program).fileName(), timeOut);
0202 
0203         return false;
0204     }
0205 
0206     QFile file(filename);
0207     if (!file.open(QIODevice::ReadOnly))
0208     {
0209         if (reason)
0210             *reason = i18n("Failed to open the file %1 during the plot integration test.", filename);
0211         return false;
0212     }
0213 
0214     QString fileContent = QString::fromLocal8Bit(file.readAll());
0215     if (fileContent.trimmed() != expectedContent)
0216     {
0217         if (reason)
0218             *reason = i18n("Failed to parse the result during the plot integration test.");
0219         return false;
0220     }
0221 
0222     file.close();
0223     file.remove();
0224 
0225     return true;
0226 }
0227 
0228 QList<GraphicPackage> Backend::availableGraphicPackages() const
0229 {
0230     if (d->supportedGraphicPackagesCache.size() != 0)
0231         return d->supportedGraphicPackagesCache;
0232 
0233     if (!(capabilities() & Capability::IntegratedPlots))
0234         return QList<GraphicPackage>(); // because this cache is empty
0235 
0236     QString packagesFile = id() + QLatin1String("/graphic_packages.xml");
0237     QString filename = QStandardPaths::locate(QStandardPaths::AppDataLocation, packagesFile, QStandardPaths::LocateFile);
0238 
0239     if (filename.isEmpty())
0240         filename = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("cantor/") + packagesFile, QStandardPaths::LocateFile);
0241 
0242     if (filename.isEmpty())
0243         return QList<GraphicPackage>();
0244 
0245     d->supportedGraphicPackagesCache = GraphicPackage::loadFromFile(filename);
0246 
0247     return d->supportedGraphicPackagesCache;
0248 }