Q_LOGGING_CATEGORY(pluginManagerCategory, "PluginManager")
-PluginManager::PluginManager() {}
+PluginManager::PluginManager(QObject *parent) : QObject{parent} {}
-QString PluginManager::errorString() const { return m_loader.errorString(); }
+PluginManager::~PluginManager() { qDeleteAll(m_plugins); }
+
+QString PluginManager::errorString() const { return ""; }
QStringList PluginManager::pluginDirectories() const {
return m_pluginDirectories;
QString PluginManager::pluginPrefix() const { return m_pluginPrefix; }
+QStringList PluginManager::preferredPlugins() const {
+ return m_preferredPlugins;
+}
+
void PluginManager::setPluginDirectories(QStringList pluginDirectories) {
if (m_pluginDirectories == pluginDirectories)
return;
emit pluginPrefixChanged(pluginPrefix);
}
+void PluginManager::setPreferredPlugins(QStringList preferredPlugins) {
+ if (m_preferredPlugins == preferredPlugins)
+ return;
+
+ m_preferredPlugins = preferredPlugins;
+ emit preferredPluginsChanged(preferredPlugins);
+}
+
bool PluginManager::load(const QString &plugin) {
- if (m_loader.isLoaded())
- if (!m_loader.unload())
- return false;
+
+ const auto it = m_plugins.find(plugin);
+
+ if (it != m_plugins.end()) {
+ return true;
+ }
+
+ auto loader = new QPluginLoader{this};
for (const auto &path : m_pluginDirectories) {
const QString pluginPath =
QString{"%1/%2_%3"}.arg(path).arg(m_pluginPrefix).arg(plugin);
qCInfo(pluginManagerCategory) << "Trying to load plugin" << pluginPath;
- m_loader.setFileName(pluginPath);
+ loader->setFileName(pluginPath);
- if (m_loader.load()) {
- qCInfo(pluginManagerCategory) << "Load successful";
+ if (loader->load()) {
+ qCInfo(pluginManagerCategory)
+ << "Plugin" << plugin << "successfully loaded from" << pluginPath;
break;
+ } else {
+ qCDebug(pluginManagerCategory)
+ << "Failed to load plugin" << plugin << "from path" << pluginPath
+ << "due to error:" << loader->errorString();
}
}
- if (!m_loader.isLoaded())
+ if (!loader->isLoaded()) {
qCCritical(pluginManagerCategory) << "Failed to load plugin" << plugin;
-
- return m_loader.isLoaded();
+ delete loader;
+ loader = nullptr;
+ return false;
+ }
+ m_plugins.insert(plugin, loader);
+ return true;
}
-QObject *PluginManager::qObjectInstance() {
- if (!m_loader.isLoaded())
+QObject *PluginManager::qObjectInstance(const QString &plugin) {
+ const auto it = m_plugins.find(plugin);
+
+ if (it == m_plugins.end())
+ return nullptr;
+
+ if (!it.value()->isLoaded())
return nullptr;
- return m_loader.instance();
+ return it.value()->instance();
}
-void PluginManager::loadDefaultPlugin() { load("mpv"); }
+bool PluginManager::loadBestPlugin() {
+ for (const auto &plugin : m_preferredPlugins) {
+ if (load(plugin)) {
+ qCInfo(pluginManagerCategory) << "Loaded best plugin:" << plugin;
+ return true;
+ }
+ }
+ qCWarning(pluginManagerCategory)
+ << "No plugin could be loaded as best plugin";
+ return false;
+}
+
+QObject *PluginManager::bestQObjectInstance() {
+ for (const auto &plugin : m_preferredPlugins) {
+ auto instance = qObjectInstance(plugin);
+ if (instance) {
+ qCInfo(pluginManagerCategory)
+ << "Returning instance of best loaded plugin:" << plugin;
+ return instance;
+ }
+ }
+ qCWarning(pluginManagerCategory)
+ << "No plugin instance could be created as best plugin instance";
+ return nullptr;
+}
#include <QObject>
#include <QPluginLoader>
#include <QStringList>
+#include <QMap>
class PluginManager : public QObject {
Q_OBJECT
setPluginDirectories NOTIFY pluginDirectoriesChanged)
Q_PROPERTY(QString pluginPrefix READ pluginPrefix WRITE setPluginPrefix NOTIFY
pluginPrefixChanged)
+ Q_PROPERTY(QStringList preferredPlugins READ preferredPlugins WRITE
+ setPreferredPlugins NOTIFY preferredPluginsChanged)
public:
- PluginManager();
+ PluginManager(QObject *parent = nullptr);
+ ~PluginManager() override;
QString errorString() const;
QStringList pluginDirectories() const;
QString pluginPrefix() const;
+ QStringList preferredPlugins() const;
- template <typename Interface> Interface *instance() {
- return qobject_cast<Interface *>(qObjectInstance());
+ template <typename Interface> Interface *instance(const QString &plugin) {
+ return qobject_cast<Interface *>(qObjectInstance(plugin));
+ }
+
+ template <typename Interface> Interface *bestInstance() {
+ return qobject_cast<Interface *>(bestQObjectInstance());
}
public slots:
void setPluginDirectories(QStringList pluginDirectories);
void setPluginPrefix(QString pluginPrefix);
+ void setPreferredPlugins(QStringList preferredPlugins);
bool load(const QString &plugin);
- QObject *qObjectInstance();
+ QObject *qObjectInstance(const QString &plugin);
- void loadDefaultPlugin();
+ bool loadBestPlugin();
+ QObject *bestQObjectInstance();
signals:
void pluginDirectoriesChanged(QStringList pluginDirectories);
void pluginPrefixChanged(QString pluginPrefix);
+ void preferredPluginsChanged(QStringList preferredPlugins);
+
private:
QStringList m_pluginDirectories;
QString m_pluginPrefix;
- QPluginLoader m_loader;
+ QStringList m_preferredPlugins;
+ QMap<QString, QPluginLoader *> m_plugins;
};
#endif // PLUGINMANAGER_H