]> Some of my projects - aniplayer.git/commitdiff
Extend PluginManager to manage more than one plugin at a time
authorAPTX <marek321@gmail.com>
Sun, 26 Feb 2017 20:24:26 +0000 (21:24 +0100)
committerAPTX <marek321@gmail.com>
Sun, 26 Feb 2017 20:24:26 +0000 (21:24 +0100)
Currently errorString always returns an empty
string as there is more than one potential error.
This method should be removed in the future.

core/player.cpp
core/pluginmanager.cpp
core/pluginmanager.h

index a2b3317bd48c310f72fd46a08a50e411a4d1fbe2..b20b42ceb4453ed89a170140ce8b64eb981b0d55 100644 (file)
@@ -212,8 +212,9 @@ void Player::loadBackend() {
 #endif
   m_pluginManager.setPluginDirectories(pluginPaths);
   m_pluginManager.setPluginPrefix("backend");
-  m_pluginManager.loadDefaultPlugin();
-  m_plugin = m_pluginManager.instance<BackendPluginBase>();
+  m_pluginManager.setPreferredPlugins({"mpv"});
+  m_pluginManager.loadBestPlugin();
+  m_plugin = m_pluginManager.bestInstance<BackendPluginBase>();
   if (!m_plugin)
     throw std::runtime_error{std::string("Failed to load backend: ") +
                              qPrintable(m_pluginManager.errorString())};
index 34328d7fa9e15345be45877c55f16bc7ab4e873a..bc8645dd1c17ffc18784a2eaf577378cf7db013e 100644 (file)
@@ -4,9 +4,11 @@
 
 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;
@@ -14,6 +16,10 @@ QStringList PluginManager::pluginDirectories() const {
 
 QString PluginManager::pluginPrefix() const { return m_pluginPrefix; }
 
+QStringList PluginManager::preferredPlugins() const {
+  return m_preferredPlugins;
+}
+
 void PluginManager::setPluginDirectories(QStringList pluginDirectories) {
   if (m_pluginDirectories == pluginDirectories)
     return;
@@ -30,34 +36,85 @@ void PluginManager::setPluginPrefix(QString pluginPrefix) {
   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;
+}
index 7c65b1717786abe04e31ca046b37df81e2a42a92..5ba288ce4073643d927112531b695d2608dcf476 100644 (file)
@@ -4,6 +4,7 @@
 #include <QObject>
 #include <QPluginLoader>
 #include <QStringList>
+#include <QMap>
 
 class PluginManager : public QObject {
   Q_OBJECT
@@ -11,35 +12,48 @@ class PluginManager : public QObject {
                  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