##// END OF EJS Templates
Updated meson build files and force plugin unload when closing app...
Updated meson build files and force plugin unload when closing app Signed-off-by: Alexis Jeandet <alexis.jeandet@member.fsf.org>

File last commit:

r72:a0c89a70c83c
r72:a0c89a70c83c
Show More
PluginManager.cpp
154 lines | 4.5 KiB | text/x-c | CppLexer
#include <PluginManager/PluginManager.h>
#include <Plugin/IPlugin.h>
#include <QDir>
#include <QLibrary>
#include <QPluginLoader>
Q_LOGGING_CATEGORY(LOG_PluginManager, "PluginManager")
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");
/// 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;
};
} // namespace
struct PluginManager::PluginManagerPrivate {
/**
* 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);
LoadPluginState loadState{pluginPath};
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()) {
loadState.setError(QObject::tr("empty file name"));
}
else if (m_RegisteredPlugins.contains(pluginName)) {
loadState.setError(QObject::tr("name '%1' already registered").arg(pluginName));
}
else {
if (auto plugin = pluginLoader.instance()) {
qobject_cast<IPlugin *>(plugin)->initialize();
m_RegisteredPlugins.insert(pluginName, pluginPath);
m_LoadedPlugins.insert(pluginName, plugin);
}
else {
loadState.setError(QObject::tr("the file is not a Sciqlop plugin"));
}
}
}
else {
loadState.setError(QObject::tr("the file is not a library"));
}
// Log loading result
loadState.log();
}
void loadStaticPlugins()
{
for (QObject *plugin : QPluginLoader::staticInstances()) {
qobject_cast<IPlugin *>(plugin)->initialize();
m_RegisteredPlugins.insert(plugin->metaObject()->className(), "StaticPlugin");
m_LoadedPlugins.insert(plugin->metaObject()->className(), plugin);
}
}
void clearAllPlugins()
{
for(auto plugin:m_LoadedPlugins)
{
delete plugin;
}
m_LoadedPlugins.clear();
m_RegisteredPlugins.clear();
}
/// Registered plugins (key: plugin name, value: plugin path)
QHash<QString, QString> m_RegisteredPlugins;
QHash<QString,QObject*> m_LoadedPlugins;
};
PluginManager::PluginManager() : impl{spimpl::make_unique_impl<PluginManagerPrivate>()}
{
}
PluginManager::~PluginManager()
{
impl->clearAllPlugins();
}
void PluginManager::loadPlugins(const QDir &pluginDir)
{
// Load plugins
auto pluginInfoList
= pluginDir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
for (auto entryInfo : qAsConst(pluginInfoList)) {
if (entryInfo.isDir()) {
this->loadPlugins(QDir{entryInfo.absoluteFilePath()});
}
else if (QLibrary::isLibrary(entryInfo.absoluteFilePath())) {
impl->loadPlugin(entryInfo.absoluteFilePath());
}
}
}
void PluginManager::loadStaticPlugins()
{
impl->loadStaticPlugins();
}
int PluginManager::nbPluginsLoaded() const noexcept
{
return impl->m_RegisteredPlugins.size();
}