File indexing completed on 2024-04-21 04:52:00

0001 /*
0002     SPDX-FileCopyrightText: 2022 Julius Künzel <jk.kdedev@smartlab.uber.space>
0003 
0004     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #pragma once
0008 #include "kdenlivesettings.h"
0009 
0010 #include <KMessageWidget>
0011 #include <QObject>
0012 #include <QString>
0013 #include <QMap>
0014 #include <QPair>
0015 
0016 class KJob;
0017 
0018 class AbstractPythonInterface : public QObject
0019 {
0020     Q_OBJECT
0021 public:
0022     explicit AbstractPythonInterface(QObject *parent = nullptr);
0023     /** @brief Check if python and pip are installed, as well as all required scripts.
0024         If a check failed setupError() will be emitted with an error message that can be
0025         shown to the user.
0026         @returns wether all checks succeeded.
0027     */
0028     ~AbstractPythonInterface() override;
0029     /** @brief Check if python is found and use venv if requested. */
0030     bool checkPython(bool useVenv, bool calculateSize = false, bool forceInstall = false);
0031     bool checkSetup();
0032     /** @brief Check which versions of the dependencies are installed.
0033         @param Whether checkVersionsResult() will be emitted once the result is available.
0034     */
0035     void checkVersions(bool signalOnResult = true);
0036     void updateDependencies();
0037     /** @brief Returns a cached list of all missing dependencies
0038      *  To update the cache run checkDependencies().
0039      *  @param filter If this is empty all missing packages will be returned,
0040      *         otherwise only those of the filter (in case they are missing).
0041      */
0042     QStringList missingDependencies(const QStringList &filter = {});
0043     QString runScript(const QString &scriptpath, QStringList args = {}, const QString &firstarg = {}, bool concurrent = false, bool packageFeedback = false);
0044     QString pythonExec() { return KdenliveSettings::pythonPath(); };
0045     void proposeMaybeUpdate(const QString &dependency, const QString &minVersion);
0046     bool installDisabled() { return m_disableInstall; };
0047     void runConcurrentScript(const QString &script, QStringList args);
0048     /** @brief Delete the python venv folder. */
0049     bool removePythonVenv();
0050     /** @brief Python venv setup in progress. */
0051     bool installInProcess() const;
0052 
0053     friend class PythonDependencyMessage;
0054 
0055 public Q_SLOTS:
0056     /** @brief Check if all dependencies are installed.
0057         If everything is okay dependenciesAvailable() will be emitted,
0058         otherwise dependenciesMissing() with a message that can be shown
0059         to the user telling wich dependencies are missing.
0060         To get a list of all missing dependencies use missingDependencies
0061         @returns wether all checks succeeded.
0062     */
0063     void checkDependencies(bool force = false, bool async = true);
0064     void checkDependenciesConcurrently();
0065     void checkVersionsConcurrently();
0066 
0067 private:
0068     QMap<QString, QString> m_dependencies;
0069     QStringList m_missing;
0070     QMap<QString, QString> *m_versions;
0071     bool m_disableInstall;
0072     bool m_dependenciesChecked;
0073 
0074     void installMissingDependencies();
0075     QString locateScript(const QString &script);
0076     QString runPackageScript(const QString &mode, bool concurrent = false);
0077     int versionToInt(const QString &version);
0078     /** @brief Create a python virtualenv */
0079     bool setupVenv();
0080     void gotFolderSize(KJob *job);
0081     QString installPackage(const QStringList packageNames);
0082 
0083 protected:
0084     QMap<QString, QString> *m_scripts;
0085     void addDependency(const QString &pipname, const QString &purpose);
0086     void addScript(const QString &script);
0087     virtual QString featureName() { return {}; };
0088     bool m_installInProgress{false};
0089 
0090 Q_SIGNALS:
0091     void setupError(const QString &message);
0092     void setupMessage(const QString &message, int messageType);
0093     void checkVersionsResult(const QStringList &versions);
0094     void dependenciesMissing(const QStringList &messages);
0095     void dependenciesAvailable();
0096     void proposeUpdate(const QString &message);
0097     void scriptFeedback(const QStringList message);
0098     void installFeedback(const QString &message);
0099     void gotPythonSize(const QString &message);
0100     void scriptGpuCheckFinished();
0101     void scriptFinished();
0102     void scriptStarted();
0103     void abortScript();
0104     void venvSetupChanged();
0105 };
0106 
0107 class PythonDependencyMessage : public KMessageWidget {
0108     Q_OBJECT
0109 
0110 public:
0111     PythonDependencyMessage(QWidget *parent, AbstractPythonInterface *interface, bool setupErrorOnly = false);
0112 
0113 public Q_SLOTS:
0114     void checkAfterInstall();
0115     void doShowMessage(const QString &message, KMessageWidget::MessageType messageType = KMessageWidget::Information);
0116 
0117 private:
0118     AbstractPythonInterface * m_interface;
0119     QAction *m_installAction{nullptr};
0120     QAction *m_abortAction{nullptr};
0121     bool m_updated;
0122 
0123 };