File indexing completed on 2024-12-15 04:01:20

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #pragma once
0008 
0009 #include <memory>
0010 
0011 #include <QDir>
0012 
0013 #include "app/log/log.hpp"
0014 #include "plugin/service.hpp"
0015 
0016 namespace app::scripting {
0017 
0018 class ScriptEngine;
0019 
0020 } // namespace app::scripting
0021 
0022 namespace glaxnimate::plugin {
0023 
0024 struct PluginData
0025 {
0026     QDir dir;
0027     QString id;
0028 
0029     int version = 0;
0030     const app::scripting::ScriptEngine* engine = nullptr;
0031     QString engine_name;
0032     QString name;
0033     QString author;
0034     QString icon;
0035     QString description;
0036     std::vector<std::unique_ptr<PluginService>> services;
0037 };
0038 
0039 class Plugin
0040 {
0041 public:
0042     Plugin(PluginData data, bool user_installed)
0043         : data_(std::move(data)), user_installed_(user_installed)
0044         {
0045             icon_ = QIcon::fromTheme("libreoffice-extension");
0046             icon_ = make_icon(data_.icon);
0047             for ( const auto& ps : data_.services )
0048                 ps->set_plugin(this);
0049         }
0050 
0051     const PluginData& data() const { return data_; }
0052 
0053     QString file(const QString& path) const
0054     {
0055         if ( !QDir::isRelativePath(path) )
0056             return {};
0057 
0058         if ( !data_.dir.exists(path) )
0059             return {};
0060 
0061         return data_.dir.cleanPath(path);
0062     }
0063 
0064     QIcon make_icon(const QString& icon) const
0065     {
0066         if ( !icon.isEmpty() )
0067         {
0068             if ( icon.startsWith("theme:") )
0069                 return QIcon::fromTheme(icon.mid(6));
0070             if ( data_.dir.exists(icon) )
0071                 return QIcon(data_.dir.absoluteFilePath(icon));
0072         }
0073         return icon_;
0074     }
0075 
0076     bool available() const
0077     {
0078         return data_.engine;
0079     }
0080 
0081     bool can_enable() const
0082     {
0083         return !enabled_ && data_.engine;
0084     }
0085 
0086     bool can_disable() const
0087     {
0088         return enabled_;
0089     }
0090 
0091     void enable()
0092     {
0093         if ( !can_enable() )
0094             return;
0095 
0096         for ( const auto& svc : data_.services )
0097             svc->enable();
0098 
0099         enabled_ = true;
0100     }
0101 
0102     void disable()
0103     {
0104         if ( !can_disable() )
0105             return;
0106 
0107         for ( const auto& svc : data_.services )
0108             svc->disable();
0109 
0110         enabled_ = false;
0111     }
0112 
0113     bool user_installed() const
0114     {
0115         return user_installed_;
0116     }
0117 
0118     const QIcon& icon() const
0119     {
0120         return icon_;
0121     }
0122 
0123     bool run_script(const PluginScript& script, const QVariantList& args) const;
0124 
0125     bool enabled() const { return enabled_; }
0126 
0127     app::log::Log logger() const
0128     {
0129         return {"Plugins", data_.name};
0130     }
0131 
0132 private:
0133     PluginData data_;
0134     bool enabled_ = false;
0135     bool user_installed_ = false;
0136     QIcon icon_;
0137 };
0138 
0139 class Executor;
0140 
0141 
0142 class PluginRegistry : public QObject
0143 {
0144     Q_OBJECT
0145 
0146 public:
0147     static PluginRegistry& instance()
0148     {
0149         static PluginRegistry instance;
0150         return instance;
0151     }
0152 
0153     void load();
0154 
0155     const std::vector<std::unique_ptr<Plugin>>& plugins() const { return plugins_; }
0156 
0157     bool load_plugin(const QString& path, bool user_installed);
0158 
0159     Plugin* plugin(const QString& id) const;
0160 
0161     Executor* executor() const;
0162     void set_executor(Executor* exec);
0163     QVariant global_parameter(const QString& name) const;
0164 
0165 Q_SIGNALS:
0166     void loaded();
0167 
0168 private:
0169     PluginRegistry() = default;
0170     PluginRegistry(const PluginRegistry&) = delete;
0171     ~PluginRegistry() = default;
0172 
0173     void load_service(const QJsonObject& jobj, PluginData& data) const;
0174     PluginScript load_script(const QJsonObject& jobj) const;
0175     void load_setting(const QJsonObject& jobj, PluginScript& script) const;
0176     QVariantMap load_choices(const QJsonValue& val) const;
0177 
0178     std::vector<std::unique_ptr<Plugin>> plugins_;
0179     Executor* executor_ = nullptr;
0180     QMap<QString, int> names;
0181     app::log::Log logger{"Plugins"};
0182 };
0183 
0184 } // namespace glaxnimate::plugin