PluginManager.cpp
119 lines
| 3.5 KiB
| text/x-c
|
CppLexer
|
r66 | #include <Plugin/PluginManager.h> | ||
#include <Plugin/IPlugin.h> | ||||
#include <QDir> | ||||
|
r67 | #include <QLibrary> | ||
#include <QPluginLoader> | ||||
|
r66 | |||
Q_LOGGING_CATEGORY(LOG_PluginManager, "PluginManager") | ||||
|
r67 | namespace { | ||
/// Key for retrieving metadata of the plugin | ||||
const auto PLUGIN_METADATA_KEY = QStringLiteral("MetaData"); | ||||
/// Key for retrieving the name of the plugin in its metadata | ||||
const auto PLUGIN_NAME_KEY = QStringLiteral("name"); | ||||
|
r68 | /// Helper to state the plugin loading operation | ||
struct LoadPluginState { | ||||
explicit LoadPluginState(const QString &pluginPath) | ||||
: m_PluginPath{pluginPath}, m_Valid{true}, m_ErrorMessage{} | ||||
{ | ||||
} | ||||
void log() const | ||||
{ | ||||
if (m_Valid) { | ||||
qCDebug(LOG_PluginManager()) | ||||
<< QObject::tr("File '%1' has been loaded as a plugin").arg(m_PluginPath); | ||||
} | ||||
else { | ||||
qCWarning(LOG_PluginManager()) | ||||
<< QObject::tr("File '%1' can't be loaded as a plugin: %2") | ||||
.arg(m_PluginPath) | ||||
.arg(m_ErrorMessage); | ||||
} | ||||
} | ||||
void setError(const QString &errorMessage) | ||||
{ | ||||
m_Valid = false; | ||||
m_ErrorMessage = errorMessage; | ||||
} | ||||
QString m_PluginPath; | ||||
bool m_Valid; | ||||
QString m_ErrorMessage; | ||||
}; | ||||
|
r67 | } // namespace | ||
|
r66 | struct PluginManager::PluginManagerPrivate { | ||
|
r67 | /** | ||
* Loads a single plugin into SciQlop. The method has no effect if the plugin is malformed (e.g. | ||||
* wrong library type, missing metadata, etc.) | ||||
* @param pluginPath the path to the plugin library. | ||||
*/ | ||||
void loadPlugin(const QString &pluginPath) | ||||
{ | ||||
qCDebug(LOG_PluginManager()) | ||||
<< QObject::tr("Attempting to load file '%1' as a plugin").arg(pluginPath); | ||||
|
r68 | LoadPluginState loadState{pluginPath}; | ||
|
r67 | if (QLibrary::isLibrary(pluginPath)) { | ||
QPluginLoader pluginLoader{pluginPath}; | ||||
// Retrieving the plugin name to check if it can be loaded (i.e. no plugin with the same | ||||
// name has been registered yet) | ||||
auto metadata = pluginLoader.metaData().value(PLUGIN_METADATA_KEY).toObject(); | ||||
auto pluginName = metadata.value(PLUGIN_NAME_KEY).toString(); | ||||
if (pluginName.isEmpty()) { | ||||
|
r68 | loadState.setError(QObject::tr("empty file name")); | ||
|
r67 | } | ||
else if (m_RegisteredPlugins.contains(pluginName)) { | ||||
|
r68 | loadState.setError(QObject::tr("name '%1' already registered").arg(pluginName)); | ||
|
r67 | } | ||
else { | ||||
if (auto pluginInstance = qobject_cast<IPlugin *>(pluginLoader.instance())) { | ||||
pluginInstance->initialize(); | ||||
m_RegisteredPlugins.insert(pluginName, pluginPath); | ||||
} | ||||
else { | ||||
|
r68 | loadState.setError(QObject::tr("the file is not a Sciqlop plugin")); | ||
|
r67 | } | ||
} | ||||
} | ||||
else { | ||||
|
r68 | loadState.setError(QObject::tr("the file is not a library")); | ||
|
r67 | } | ||
|
r68 | |||
// Log loading result | ||||
loadState.log(); | ||||
|
r67 | } | ||
/// Registered plugins (key: plugin name, value: plugin path) | ||||
QHash<QString, QString> m_RegisteredPlugins; | ||||
|
r66 | }; | ||
PluginManager::PluginManager() : impl{spimpl::make_unique_impl<PluginManagerPrivate>()} | ||||
{ | ||||
} | ||||
void PluginManager::loadPlugins(const QDir &pluginDir) | ||||
{ | ||||
// Load plugins | ||||
auto pluginInfoList = pluginDir.entryInfoList(QDir::Files, QDir::Name); | ||||
for (auto pluginInfo : qAsConst(pluginInfoList)) { | ||||
|
r67 | impl->loadPlugin(pluginInfo.absoluteFilePath()); | ||
|
r66 | } | ||
} | ||||
int PluginManager::nbPluginsLoaded() const noexcept | ||||
{ | ||||
/// @todo ALX | ||||
return 0; | ||||
} | ||||