mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-16 02:06:08 +08:00
refs #442 Add CPluginManagerSimulator class
This commit is contained in:
committed by
Mathew Sutcliffe
parent
2c55fe2306
commit
15cc23a43c
@@ -13,7 +13,7 @@
|
||||
#include "context_settings.h"
|
||||
#include "context_application.h"
|
||||
#include "context_network_impl.h"
|
||||
#include "plugin_manager.h"
|
||||
#include "plugin_manager_simulator.h"
|
||||
#include "context_runtime.h"
|
||||
#include "blackcore/blackcorefreefunctions.h"
|
||||
#include "blackmisc/propertyindexvariantmap.h"
|
||||
@@ -36,10 +36,11 @@ using namespace BlackMisc::Simulation::Settings;
|
||||
namespace BlackCore
|
||||
{
|
||||
CContextSimulator::CContextSimulator(CRuntimeConfig::ContextMode mode, CRuntime *runtime) :
|
||||
IContextSimulator(mode, runtime)
|
||||
IContextSimulator(mode, runtime),
|
||||
m_plugins(new CPluginManagerSimulator(this))
|
||||
{
|
||||
this->setObjectName("CContextSimulator");
|
||||
findSimulatorPlugins();
|
||||
m_plugins->collectPlugins();
|
||||
}
|
||||
|
||||
CContextSimulator::~CContextSimulator()
|
||||
@@ -47,59 +48,6 @@ namespace BlackCore
|
||||
this->gracefulShutdown();
|
||||
}
|
||||
|
||||
ISimulatorFactory *CContextSimulator::getSimulatorFactory(const CSimulatorPluginInfo &simulator)
|
||||
{
|
||||
PluginData *plugin = findPlugin(simulator);
|
||||
if (!plugin) { return nullptr; }
|
||||
|
||||
if (!plugin->factory)
|
||||
{
|
||||
CPluginManager *pm = CPluginManager::getInstance();
|
||||
ISimulatorFactory *factory = qobject_cast<ISimulatorFactory *>(pm->getPluginById(plugin->identifier));
|
||||
if (factory)
|
||||
{
|
||||
plugin->factory = factory;
|
||||
CLogMessage(this).info("Loaded driver: %1") << plugin->info.toQString();
|
||||
}
|
||||
}
|
||||
|
||||
return plugin->factory;
|
||||
}
|
||||
|
||||
CVariant CContextSimulator::getPluginData(const QObject *obj, const QString &key) const
|
||||
{
|
||||
const QObject *p = obj;
|
||||
while (p && !p->inherits("BlackCore::ISimulatorFactory"))
|
||||
{
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
if (!p) return CVariant();
|
||||
auto it = std::find_if(m_simulatorPlugins.begin(), m_simulatorPlugins.end(), [p](const PluginData & plugin)
|
||||
{
|
||||
return plugin.factory == qobject_cast<ISimulatorFactory *>(p);
|
||||
});
|
||||
Q_ASSERT(it != m_simulatorPlugins.end());
|
||||
return it->m_storage.value(key);
|
||||
}
|
||||
|
||||
void CContextSimulator::setPluginData(const QObject *obj, const QString &key, const CVariant &value)
|
||||
{
|
||||
const QObject *p = obj;
|
||||
while (p && !p->inherits("BlackCore::ISimulatorFactory"))
|
||||
{
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
if (!p) { return; }
|
||||
auto it = std::find_if(m_simulatorPlugins.begin(), m_simulatorPlugins.end(), [p](const PluginData & plugin)
|
||||
{
|
||||
return plugin.factory == qobject_cast<ISimulatorFactory *>(p);
|
||||
});
|
||||
Q_ASSERT(it != m_simulatorPlugins.end());
|
||||
it->m_storage.insert(key, value);
|
||||
}
|
||||
|
||||
void CContextSimulator::gracefulShutdown()
|
||||
{
|
||||
this->disconnect();
|
||||
@@ -108,12 +56,7 @@ namespace BlackCore
|
||||
|
||||
CSimulatorPluginInfoList CContextSimulator::getAvailableSimulatorPlugins() const
|
||||
{
|
||||
CSimulatorPluginInfoList list;
|
||||
std::for_each(m_simulatorPlugins.begin(), m_simulatorPlugins.end(), [&list](const PluginData & driver)
|
||||
{
|
||||
list.push_back(driver.info);
|
||||
});
|
||||
return list;
|
||||
return m_plugins->getAvailableSimulatorPlugins();
|
||||
}
|
||||
|
||||
bool CContextSimulator::startSimulatorPlugin(const CSimulatorPluginInfo &simulatorInfo)
|
||||
@@ -129,107 +72,107 @@ namespace BlackCore
|
||||
int CContextSimulator::getSimulatorStatus() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return 0; }
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return 0; }
|
||||
|
||||
Q_ASSERT_X(m_simulatorPlugin->simulator, Q_FUNC_INFO, "Missing simulator");
|
||||
return m_simulatorPlugin->simulator->getSimulatorStatus();
|
||||
Q_ASSERT_X(m_simulatorPlugin.second, Q_FUNC_INFO, "Missing simulator");
|
||||
return m_simulatorPlugin.second->getSimulatorStatus();
|
||||
}
|
||||
|
||||
BlackMisc::Simulation::CSimulatorPluginInfo CContextSimulator::getSimulatorPluginInfo() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return BlackMisc::Simulation::CSimulatorPluginInfo(); }
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return BlackMisc::Simulation::CSimulatorPluginInfo(); }
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->info;
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.first;
|
||||
}
|
||||
|
||||
CSimulatorSetup CContextSimulator::getSimulatorSetup() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
return BlackMisc::Simulation::CSimulatorSetup();
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->getSimulatorSetup();
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getSimulatorSetup();
|
||||
}
|
||||
|
||||
CAirportList CContextSimulator::getAirportsInRange() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
// If no ISimulator object is available, return a dummy.
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
return CAirportList();
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->getAirportsInRange();
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getAirportsInRange();
|
||||
}
|
||||
|
||||
CAircraftModelList CContextSimulator::getInstalledModels() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
// If no ISimulator object is available, return a dummy.
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
return CAircraftModelList();
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->getInstalledModels();
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getInstalledModels();
|
||||
}
|
||||
|
||||
int CContextSimulator::getInstalledModelsCount() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return 0; }
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return 0; }
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return this->m_simulatorPlugin->simulator->getInstalledModels().size();
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getInstalledModels().size();
|
||||
}
|
||||
|
||||
CAircraftModelList CContextSimulator::getInstalledModelsStartingWith(const QString modelString) const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << modelString; }
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
return CAircraftModelList();
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->getInstalledModels().findModelsStartingWith(modelString);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getInstalledModels().findModelsStartingWith(modelString);
|
||||
}
|
||||
|
||||
void CContextSimulator::reloadInstalledModels()
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
m_simulatorPlugin->simulator->reloadInstalledModels();
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
m_simulatorPlugin.second->reloadInstalledModels();
|
||||
}
|
||||
|
||||
CAircraftIcaoData CContextSimulator::getIcaoForModelString(const QString &modelString) const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << modelString; }
|
||||
if (!m_simulatorPlugin) { return CAircraftIcaoData(); }
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return CAircraftIcaoData(); }
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->getIcaoForModelString(modelString);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getIcaoForModelString(modelString);
|
||||
}
|
||||
|
||||
bool CContextSimulator::setTimeSynchronization(bool enable, const CTime &offset)
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return false; }
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return false; }
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
bool c = m_simulatorPlugin->simulator->setTimeSynchronization(enable, offset);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
bool c = m_simulatorPlugin.second->setTimeSynchronization(enable, offset);
|
||||
if (!c) { return false; }
|
||||
|
||||
CLogMessage(this).info(enable ? QStringLiteral("Set time syncronization to %1").arg(offset.toQString()) : QStringLiteral("Disabled time syncrhonization"));
|
||||
@@ -239,53 +182,53 @@ namespace BlackCore
|
||||
bool CContextSimulator::isTimeSynchronized() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return false; }
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return false; }
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->isTimeSynchronized();
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->isTimeSynchronized();
|
||||
}
|
||||
|
||||
int CContextSimulator::getMaxRenderedAircraft() const
|
||||
{
|
||||
if (m_debugEnabled) {CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return 0; }
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->getMaxRenderedAircraft();
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return 0; }
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getMaxRenderedAircraft();
|
||||
}
|
||||
|
||||
void CContextSimulator::setMaxRenderedAircraft(int number)
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << number; }
|
||||
if (!m_simulatorPlugin) { return; }
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
m_simulatorPlugin->simulator->setMaxRenderedAircraft(number);
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return; }
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
m_simulatorPlugin.second->setMaxRenderedAircraft(number);
|
||||
|
||||
}
|
||||
|
||||
void CContextSimulator::setMaxRenderedDistance(const CLength &distance)
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << distance; }
|
||||
if (!m_simulatorPlugin) { return; }
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
this->m_simulatorPlugin->simulator->setMaxRenderedDistance(distance);
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return; }
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
m_simulatorPlugin.second->setMaxRenderedDistance(distance);
|
||||
}
|
||||
|
||||
QString CContextSimulator::getRenderRestrictionText() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return ""; }
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return ""; }
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
if (!m_simulatorPlugin->simulator->isRenderingRestricted()) { return "none"; }
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
if (!m_simulatorPlugin.second->isRenderingRestricted()) { return "none"; }
|
||||
QString rt;
|
||||
if (m_simulatorPlugin->simulator->isMaxAircraftRestricted())
|
||||
if (m_simulatorPlugin.second->isMaxAircraftRestricted())
|
||||
{
|
||||
rt.append(QString::number(m_simulatorPlugin->simulator->getMaxRenderedAircraft())).append(" A/C");
|
||||
rt.append(QString::number(m_simulatorPlugin.second->getMaxRenderedAircraft())).append(" A/C");
|
||||
}
|
||||
if (m_simulatorPlugin->simulator->isMaxDistanceRestricted())
|
||||
if (m_simulatorPlugin.second->isMaxDistanceRestricted())
|
||||
{
|
||||
if (!rt.isEmpty()) { rt.append(" ");}
|
||||
rt.append(m_simulatorPlugin->simulator->getMaxRenderedDistance().valueRoundedWithUnit(CLengthUnit::NM(), 0));
|
||||
rt.append(m_simulatorPlugin.second->getMaxRenderedDistance().valueRoundedWithUnit(CLengthUnit::NM(), 0));
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
@@ -293,54 +236,54 @@ namespace BlackCore
|
||||
CLength CContextSimulator::getMaxRenderedDistance() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return CLength(0, CLengthUnit::nullUnit()); }
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return this->m_simulatorPlugin->simulator->getMaxRenderedDistance();
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return CLength(0, CLengthUnit::nullUnit()); }
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getMaxRenderedDistance();
|
||||
}
|
||||
|
||||
CLength CContextSimulator::getRenderedDistanceBoundary() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
return CLength(20.0, CLengthUnit::NM());
|
||||
}
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return this->m_simulatorPlugin->simulator->getRenderedDistanceBoundary();
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getRenderedDistanceBoundary();
|
||||
}
|
||||
|
||||
void CContextSimulator::deleteAllRenderingRestrictions()
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (m_simulatorPlugin)
|
||||
if (!m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
this->m_simulatorPlugin->simulator->deleteAllRenderingRestrictions();
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
m_simulatorPlugin.second->deleteAllRenderingRestrictions();
|
||||
}
|
||||
}
|
||||
|
||||
bool CContextSimulator::isRenderingRestricted() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return false; }
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return this->m_simulatorPlugin->simulator->isRenderingRestricted();
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return false; }
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->isRenderingRestricted();
|
||||
}
|
||||
|
||||
bool CContextSimulator::isRenderingEnabled() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return false; }
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return this->m_simulatorPlugin->simulator->isRenderingEnabled();
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return false; }
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->isRenderingEnabled();
|
||||
}
|
||||
|
||||
CTime CContextSimulator::getTimeSynchronizationOffset() const
|
||||
{
|
||||
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
||||
if (!m_simulatorPlugin) { return CTime(0, CTimeUnit::hrmin()); }
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return this->m_simulatorPlugin->simulator->getTimeSynchronizationOffset();
|
||||
if (m_simulatorPlugin.first.isUnspecified()) { return CTime(0, CTimeUnit::hrmin()); }
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->getTimeSynchronizationOffset();
|
||||
}
|
||||
|
||||
bool CContextSimulator::loadSimulatorPlugin(const CSimulatorPluginInfo &simulatorInfo, bool withListener)
|
||||
@@ -350,16 +293,9 @@ namespace BlackCore
|
||||
Q_ASSERT(!simulatorInfo.isUnspecified());
|
||||
Q_ASSERT(BlackCore::isCurrentThreadApplicationThread()); // only run in main thread
|
||||
|
||||
// error if we do not have any plugins
|
||||
if (m_simulatorPlugins.isEmpty())
|
||||
{
|
||||
CLogMessage(this).error("No simulator plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is the plugin already loaded?
|
||||
if (m_simulatorPlugin &&
|
||||
(m_simulatorPlugin->info == simulatorInfo || simulatorInfo.isAuto()))
|
||||
if (!m_simulatorPlugin.first.isUnspecified() &&
|
||||
(m_simulatorPlugin.first == simulatorInfo || simulatorInfo.isAuto()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -388,7 +324,7 @@ namespace BlackCore
|
||||
return false;
|
||||
}
|
||||
|
||||
ISimulatorFactory *factory = getSimulatorFactory(simulatorInfo);
|
||||
ISimulatorFactory *factory = m_plugins->getFactory(simulatorInfo.getIdentifier());
|
||||
Q_ASSERT_X(factory, Q_FUNC_INFO, "no factory");
|
||||
|
||||
// We assume we run in the same process as the own aircraft context
|
||||
@@ -397,30 +333,26 @@ namespace BlackCore
|
||||
Q_ASSERT(this->getIContextNetwork()->isUsingImplementingObject());
|
||||
IOwnAircraftProvider *ownAircraftProvider = this->getRuntime()->getCContextOwnAircraft();
|
||||
IRemoteAircraftProvider *renderedAircraftProvider = this->getRuntime()->getCContextNetwork();
|
||||
ISimulator *newSimulator = factory->create(simulatorInfo, ownAircraftProvider, renderedAircraftProvider, this);
|
||||
Q_ASSERT_X(newSimulator, Q_FUNC_INFO, "no simulator driver can be created");
|
||||
ISimulator *simulator = factory->create(simulatorInfo, ownAircraftProvider, renderedAircraftProvider, m_plugins);
|
||||
Q_ASSERT_X(simulator, Q_FUNC_INFO, "no simulator driver can be created");
|
||||
|
||||
PluginData *plugin = findPlugin(simulatorInfo);
|
||||
plugin->simulator = newSimulator;
|
||||
m_simulatorPlugin = plugin;
|
||||
|
||||
bool c = connect(m_simulatorPlugin->simulator, &ISimulator::simulatorStatusChanged, this, &CContextSimulator::ps_onSimulatorStatusChanged);
|
||||
bool c = connect(simulator, &ISimulator::simulatorStatusChanged, this, &CContextSimulator::ps_onSimulatorStatusChanged);
|
||||
Q_ASSERT(c);
|
||||
c = connect(m_simulatorPlugin->simulator, &ISimulator::ownAircraftModelChanged, this, &IContextSimulator::ownAircraftModelChanged);
|
||||
c = connect(simulator, &ISimulator::ownAircraftModelChanged, this, &IContextSimulator::ownAircraftModelChanged);
|
||||
Q_ASSERT(c);
|
||||
c = connect(m_simulatorPlugin->simulator, &ISimulator::modelMatchingCompleted, this, &IContextSimulator::modelMatchingCompleted);
|
||||
c = connect(simulator, &ISimulator::modelMatchingCompleted, this, &IContextSimulator::modelMatchingCompleted);
|
||||
Q_ASSERT(c);
|
||||
c = connect(m_simulatorPlugin->simulator, &ISimulator::installedAircraftModelsChanged, this, &IContextSimulator::installedAircraftModelsChanged);
|
||||
c = connect(simulator, &ISimulator::installedAircraftModelsChanged, this, &IContextSimulator::installedAircraftModelsChanged);
|
||||
Q_ASSERT(c);
|
||||
c = connect(m_simulatorPlugin->simulator, &ISimulator::renderRestrictionsChanged, this, &IContextSimulator::renderRestrictionsChanged);
|
||||
c = connect(simulator, &ISimulator::renderRestrictionsChanged, this, &IContextSimulator::renderRestrictionsChanged);
|
||||
Q_ASSERT(c);
|
||||
c = connect(m_simulatorPlugin->simulator, &ISimulator::airspaceSnapshotHandled, this, &IContextSimulator::airspaceSnapshotHandled);
|
||||
c = connect(simulator, &ISimulator::airspaceSnapshotHandled, this, &IContextSimulator::airspaceSnapshotHandled);
|
||||
Q_ASSERT(c);
|
||||
|
||||
// log from context to simulator
|
||||
c = connect(CLogHandler::instance(), &CLogHandler::localMessageLogged, m_simulatorPlugin->simulator, &ISimulator::displayStatusMessage);
|
||||
c = connect(CLogHandler::instance(), &CLogHandler::localMessageLogged, simulator, &ISimulator::displayStatusMessage);
|
||||
Q_ASSERT(c);
|
||||
c = connect(CLogHandler::instance(), &CLogHandler::remoteMessageLogged, m_simulatorPlugin->simulator, &ISimulator::displayStatusMessage);
|
||||
c = connect(CLogHandler::instance(), &CLogHandler::remoteMessageLogged, simulator, &ISimulator::displayStatusMessage);
|
||||
Q_ASSERT(c);
|
||||
Q_UNUSED(c);
|
||||
|
||||
@@ -433,13 +365,17 @@ namespace BlackCore
|
||||
for (const CSimulatedAircraft &simulatedAircraft : networkContext->getAircraftInRange())
|
||||
{
|
||||
Q_ASSERT(!simulatedAircraft.getCallsign().isEmpty());
|
||||
m_simulatorPlugin->simulator->logicallyAddRemoteAircraft(simulatedAircraft);
|
||||
simulator->logicallyAddRemoteAircraft(simulatedAircraft);
|
||||
}
|
||||
|
||||
// when everything is set up connected, update the current plugin info
|
||||
m_simulatorPlugin.first = simulatorInfo;
|
||||
m_simulatorPlugin.second = simulator;
|
||||
|
||||
// try to connect to simulator
|
||||
m_simulatorPlugin->simulator->connectTo();
|
||||
emit simulatorPluginChanged(this->m_simulatorPlugin->info);
|
||||
CLogMessage(this).info("Simulator plugin loaded: %1") << this->m_simulatorPlugin->info.toQString(true);
|
||||
simulator->connectTo();
|
||||
emit simulatorPluginChanged(simulatorInfo);
|
||||
CLogMessage(this).info("Simulator plugin loaded: %1") << simulatorInfo.toQString(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -450,57 +386,42 @@ namespace BlackCore
|
||||
Q_ASSERT(this->getIContextApplication()->isUsingImplementingObject());
|
||||
Q_ASSERT(!simulatorInfo.isUnspecified());
|
||||
|
||||
// warning if we do not have any plugins
|
||||
if (m_simulatorPlugins.isEmpty())
|
||||
{
|
||||
CLogMessage(this).error("No simulator drivers available");
|
||||
return;
|
||||
}
|
||||
|
||||
ISimulator::SimulatorStatus simStatus = getSimulatorStatusEnum();
|
||||
if (this->m_simulatorPlugin && this->m_simulatorPlugin->info == simulatorInfo && simStatus.testFlag(ISimulator::Connected))
|
||||
if (!m_simulatorPlugin.first.isUnspecified() &&
|
||||
m_simulatorPlugin.first == simulatorInfo && simStatus.testFlag(ISimulator::Connected))
|
||||
{
|
||||
// the simulator is already connected and running
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->m_simulatorPlugin)
|
||||
if (!m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
// wrong or disconnected plugin, we start from the scratch
|
||||
this->unloadSimulatorPlugin();
|
||||
}
|
||||
|
||||
PluginData *plugin = findPlugin(simulatorInfo);
|
||||
if (!plugin)
|
||||
if (!m_listenersThread.isRunning())
|
||||
{
|
||||
CLogMessage(this).error("Driver not found for '%1'") << simulatorInfo.toQString();
|
||||
return;
|
||||
m_listenersThread.setObjectName("CContextSimulator:Thread for listeners");
|
||||
m_listenersThread.start(QThread::LowPriority);
|
||||
}
|
||||
|
||||
if (!plugin->listener)
|
||||
ISimulatorListener *listener = m_plugins->getListener(simulatorInfo.getIdentifier());
|
||||
Q_ASSERT_X(listener, Q_FUNC_INFO, "No listener");
|
||||
|
||||
if (!listener->property("isInitialized").isValid() || listener->property("isInitialized").toBool() == false)
|
||||
{
|
||||
if (!m_listenersThread.isRunning())
|
||||
{
|
||||
m_listenersThread.setObjectName("CContextSimulator:Thread for listeners");
|
||||
m_listenersThread.start(QThread::LowPriority);
|
||||
}
|
||||
|
||||
ISimulatorFactory *factory = getSimulatorFactory(simulatorInfo);
|
||||
Q_ASSERT_X(factory, Q_FUNC_INFO, "No simulator factory");
|
||||
|
||||
plugin->listener = factory->createListener(simulatorInfo);
|
||||
bool c = connect(plugin->listener, &ISimulatorListener::simulatorStarted, this, &CContextSimulator::ps_simulatorStarted);
|
||||
bool c = connect(listener, &ISimulatorListener::simulatorStarted, this, &CContextSimulator::ps_simulatorStarted);
|
||||
if (!c)
|
||||
{
|
||||
CLogMessage(this).error("Unable to use '%1'") << simulatorInfo.toQString();
|
||||
return;
|
||||
}
|
||||
Q_ASSERT_X(!plugin->listener->parent(), Q_FUNC_INFO, "Objects with parent cannot be moved to thread");
|
||||
plugin->listener->moveToThread(&m_listenersThread);
|
||||
}
|
||||
Q_ASSERT_X(!listener->parent(), Q_FUNC_INFO, "Objects with parent cannot be moved to thread");
|
||||
listener->moveToThread(&m_listenersThread);
|
||||
|
||||
ISimulatorListener *listener = plugin->listener;
|
||||
Q_ASSERT_X(listener, Q_FUNC_INFO, "No listener");
|
||||
listener->setProperty("isInitialized", true);
|
||||
}
|
||||
|
||||
bool s = QMetaObject::invokeMethod(listener, "start", Qt::QueuedConnection);
|
||||
Q_ASSERT_X(s, Q_FUNC_INFO, "cannot invoke method");
|
||||
@@ -512,7 +433,8 @@ namespace BlackCore
|
||||
auto plugins = getAvailableSimulatorPlugins();
|
||||
for (const CSimulatorPluginInfo &p : plugins)
|
||||
{
|
||||
if (p.isUnspecified()) { continue; }
|
||||
Q_ASSERT(!p.isUnspecified());
|
||||
|
||||
if (p.isValid())
|
||||
{
|
||||
listenForSimulator(p);
|
||||
@@ -522,10 +444,11 @@ namespace BlackCore
|
||||
|
||||
void CContextSimulator::unloadSimulatorPlugin()
|
||||
{
|
||||
if (m_simulatorPlugin)
|
||||
if (!m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
ISimulator *sim = this->m_simulatorPlugin->simulator;
|
||||
m_simulatorPlugin = nullptr;
|
||||
ISimulator *sim = m_simulatorPlugin.second;
|
||||
m_simulatorPlugin.second = nullptr;
|
||||
m_simulatorPlugin.first = CSimulatorPluginInfo();
|
||||
|
||||
Q_ASSERT(this->getIContextNetwork());
|
||||
Q_ASSERT(this->getIContextNetwork()->isLocalObject());
|
||||
@@ -547,30 +470,30 @@ namespace BlackCore
|
||||
// todo:
|
||||
// This was previously an assert and it should be one again in the future.
|
||||
// This slot should not even be called when no simulator is available.
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
// Do something if no simulator is running
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
Q_ASSERT(!remoteAircraft.getCallsign().isEmpty());
|
||||
|
||||
m_simulatorPlugin->simulator->logicallyAddRemoteAircraft(remoteAircraft);
|
||||
m_simulatorPlugin.second->logicallyAddRemoteAircraft(remoteAircraft);
|
||||
}
|
||||
|
||||
void CContextSimulator::ps_removedRemoteAircraft(const CCallsign &callsign)
|
||||
{
|
||||
// \fixme: This was previously an assert and it should be one again in the future.
|
||||
// This slot should not even be called when no simulator is available.
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
// Do something if no simulator is running
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
m_simulatorPlugin->simulator->logicallyRemoveRemoteAircraft(callsign);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
m_simulatorPlugin.second->logicallyRemoveRemoteAircraft(callsign);
|
||||
}
|
||||
|
||||
void CContextSimulator::ps_onSimulatorStatusChanged(int status)
|
||||
@@ -589,16 +512,16 @@ namespace BlackCore
|
||||
// todo:
|
||||
// This was previously an assert and it should be one again in the future.
|
||||
// This slot should not even be called when no simulator is available.
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
// Do something if no simulator is running
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
for (const auto &tm : textMessages)
|
||||
{
|
||||
m_simulatorPlugin->simulator->displayTextMessage(tm);
|
||||
m_simulatorPlugin.second->displayTextMessage(tm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,14 +533,14 @@ namespace BlackCore
|
||||
|
||||
void CContextSimulator::ps_changedRemoteAircraftModel(const CSimulatedAircraft &aircraft, const CIdentifier &originator)
|
||||
{
|
||||
Q_ASSERT(this->m_simulatorPlugin);
|
||||
this->m_simulatorPlugin->simulator->changeRemoteAircraftModel(aircraft, originator);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
m_simulatorPlugin.second->changeRemoteAircraftModel(aircraft, originator);
|
||||
}
|
||||
|
||||
void CContextSimulator::ps_changedRemoteAircraftEnabled(const CSimulatedAircraft &aircraft, const CIdentifier &originator)
|
||||
{
|
||||
Q_ASSERT(this->m_simulatorPlugin);
|
||||
this->m_simulatorPlugin->simulator->changeRemoteAircraftEnabled(aircraft, originator);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
m_simulatorPlugin.second->changeRemoteAircraftEnabled(aircraft, originator);
|
||||
}
|
||||
|
||||
void CContextSimulator::ps_updateSimulatorCockpitFromContext(const CAircraft &ownAircraft, const CIdentifier &originator)
|
||||
@@ -625,19 +548,19 @@ namespace BlackCore
|
||||
// todo:
|
||||
// This was previously an assert and it should be one again in the future.
|
||||
// This slot should not even be called when no simulator is available.
|
||||
if (!m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
// Do something if no simulator is running
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
|
||||
// avoid loops
|
||||
if (originator.getName().isEmpty() || originator == IContextSimulator::InterfaceName()) { return; }
|
||||
|
||||
// update
|
||||
this->m_simulatorPlugin->simulator->updateOwnSimulatorCockpit(ownAircraft, originator);
|
||||
m_simulatorPlugin.second->updateOwnSimulatorCockpit(ownAircraft, originator);
|
||||
}
|
||||
|
||||
void CContextSimulator::settingsChanged(uint type)
|
||||
@@ -650,30 +573,30 @@ namespace BlackCore
|
||||
|
||||
CPixmap CContextSimulator::iconForModel(const QString &modelString) const
|
||||
{
|
||||
if (!this->m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
return CPixmap();
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->iconForModel(modelString);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->iconForModel(modelString);
|
||||
}
|
||||
|
||||
void CContextSimulator::enableDebugMessages(bool driver, bool interpolator)
|
||||
{
|
||||
if (!this->m_simulatorPlugin)
|
||||
if (m_simulatorPlugin.first.isUnspecified())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
return m_simulatorPlugin->simulator->enableDebugMessages(driver, interpolator);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
return m_simulatorPlugin.second->enableDebugMessages(driver, interpolator);
|
||||
}
|
||||
|
||||
void CContextSimulator::highlightAircraft(const CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const CTime &displayTime)
|
||||
{
|
||||
Q_ASSERT(m_simulatorPlugin->simulator);
|
||||
this->m_simulatorPlugin->simulator->highlightAircraft(aircraftToHighlight, enableHighlight, displayTime);
|
||||
Q_ASSERT(m_simulatorPlugin.second);
|
||||
m_simulatorPlugin.second->highlightAircraft(aircraftToHighlight, enableHighlight, displayTime);
|
||||
}
|
||||
|
||||
void CContextSimulator::ps_simulatorStarted(const CSimulatorPluginInfo &info)
|
||||
@@ -682,48 +605,13 @@ namespace BlackCore
|
||||
loadSimulatorPlugin(info, false);
|
||||
}
|
||||
|
||||
void CContextSimulator::findSimulatorPlugins()
|
||||
{
|
||||
CPluginManager *pm = CPluginManager::getInstance();
|
||||
auto plugins = pm->plugins("org.swift-project.blackcore.simulatorinterface");
|
||||
|
||||
std::for_each(plugins.begin(), plugins.end(), [this](const QJsonObject &json)
|
||||
{
|
||||
QString identifier = json.value("MetaData").toObject().value("identifier").toString();
|
||||
Q_ASSERT(!identifier.isEmpty());
|
||||
CSimulatorPluginInfo info;
|
||||
info.convertFromJson(json);
|
||||
if (info.isValid())
|
||||
{
|
||||
m_simulatorPlugins << PluginData { info, nullptr, nullptr, nullptr, identifier };
|
||||
CLogMessage(this).debug() << "Found simulator driver: " << info.toQString();
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).warning("Simulator driver in %1 is invalid") << identifier;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CContextSimulator::stopSimulatorListeners()
|
||||
{
|
||||
std::for_each(m_simulatorPlugins.begin(), m_simulatorPlugins.end(), [](PluginData & plugin)
|
||||
for (const auto &info: getAvailableSimulatorPlugins())
|
||||
{
|
||||
if (plugin.listener)
|
||||
{
|
||||
QMetaObject::invokeMethod(plugin.listener, "stop");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CContextSimulator::PluginData *CContextSimulator::findPlugin(const CSimulatorPluginInfo &info)
|
||||
{
|
||||
auto it = std::find_if(m_simulatorPlugins.begin(), m_simulatorPlugins.end(), [&info](PluginData & plugin)
|
||||
{
|
||||
return plugin.info == info;
|
||||
});
|
||||
|
||||
return &(*it);
|
||||
ISimulatorListener *listener = m_plugins->getListener(info.getIdentifier());
|
||||
QMetaObject::invokeMethod(listener, "stop");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "blackmisc/network/textmessagelist.h"
|
||||
#include "blackmisc/pixmap.h"
|
||||
#include "blackmisc/simulation/simulatedaircraftlist.h"
|
||||
#include "blackmisc/pluginstorageprovider.h"
|
||||
#include "blackmisc/variant.h"
|
||||
#include <QTimer>
|
||||
#include <QDir>
|
||||
@@ -28,10 +27,11 @@
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
class CPluginManagerSimulator;
|
||||
|
||||
//! Network simulator concrete implementation
|
||||
class BLACKCORE_EXPORT CContextSimulator :
|
||||
public IContextSimulator,
|
||||
public BlackMisc::IPluginStorageProvider
|
||||
public IContextSimulator
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTSIMULATOR_INTERFACENAME)
|
||||
@@ -42,12 +42,6 @@ namespace BlackCore
|
||||
//! Destructor
|
||||
virtual ~CContextSimulator();
|
||||
|
||||
//! \copydoc IPluginStorageProvider::getPluginData
|
||||
virtual BlackMisc::CVariant getPluginData(const QObject *obj, const QString &key) const;
|
||||
|
||||
//! \copydoc IPluginStorageProvider::setPluginData
|
||||
virtual void setPluginData(const QObject *obj, const QString &key, const BlackMisc::CVariant &value);
|
||||
|
||||
//! Gracefully shut down, e.g. for plugin unloading
|
||||
void gracefulShutdown();
|
||||
|
||||
@@ -178,34 +172,12 @@ namespace BlackCore
|
||||
void ps_updateSimulatorCockpitFromContext(const BlackMisc::Aviation::CAircraft &ownAircraft, const BlackMisc::CIdentifier &originator);
|
||||
|
||||
private:
|
||||
//! A simple struct containing all info about the plugin.
|
||||
//! \todo Would we want to use m_member style here?
|
||||
struct PluginData
|
||||
{
|
||||
PluginData(const BlackMisc::Simulation::CSimulatorPluginInfo &info, ISimulatorFactory *factory, ISimulatorListener *listener, ISimulator *simulator, const QString &identifier) :
|
||||
info(info), factory(factory), listener(listener), simulator(simulator), identifier(identifier) {}
|
||||
|
||||
BlackMisc::Simulation::CSimulatorPluginInfo info;
|
||||
ISimulatorFactory *factory = nullptr; //!< Lazy-loaded, nullptr by default
|
||||
ISimulatorListener *listener = nullptr; //!< Listener instance, nullptr by default
|
||||
ISimulator *simulator = nullptr; //!< The simulator itself (always nullptr unless it is the currently working one)
|
||||
QString identifier = QString(); //!< The plugin identifier
|
||||
QHash<QString, BlackMisc::CVariant> m_storage; //!< Permanent plugin storage - data stored here will be kept even when plugin is unloaded
|
||||
};
|
||||
|
||||
//! Lazy-loads the driver, instantiates the factory and returns it.
|
||||
//! \return nullptr if no corresponding driver was found or an error occured during loading it.
|
||||
ISimulatorFactory *getSimulatorFactory(const BlackMisc::Simulation::CSimulatorPluginInfo &simulator);
|
||||
|
||||
//! Load plugin, if required start listeners before
|
||||
bool loadSimulatorPlugin(const BlackMisc::Simulation::CSimulatorPluginInfo &simulatorInfo, bool withListeners);
|
||||
|
||||
//! Unload plugin, if desired restart listeners
|
||||
void unloadSimulatorPlugin();
|
||||
|
||||
//! Find and catalog all simulator plugins
|
||||
void findSimulatorPlugins();
|
||||
|
||||
//! Load plugin from settings
|
||||
bool loadSimulatorPluginFromSettings();
|
||||
|
||||
@@ -218,12 +190,8 @@ namespace BlackCore
|
||||
//! Call stop() on all loaded listeners
|
||||
void stopSimulatorListeners();
|
||||
|
||||
//! Locate PluginData (linear search)
|
||||
PluginData *findPlugin(const BlackMisc::Simulation::CSimulatorPluginInfo &info);
|
||||
|
||||
QDir m_pluginsDir;
|
||||
QList<PluginData> m_simulatorPlugins;
|
||||
PluginData *m_simulatorPlugin = nullptr; //!< Currently loaded simulator plugin
|
||||
QPair<BlackMisc::Simulation::CSimulatorPluginInfo, ISimulator *> m_simulatorPlugin; //!< Currently loaded simulator plugin
|
||||
CPluginManagerSimulator *m_plugins = nullptr;
|
||||
BlackMisc::CRegularThread m_listenersThread;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,14 +17,93 @@
|
||||
|
||||
using namespace BlackMisc;
|
||||
|
||||
namespace BlackCore {
|
||||
namespace BlackCore
|
||||
{
|
||||
|
||||
BlackMisc::CSequence<QJsonObject> CPluginManager::plugins(const QString &iid) const
|
||||
IPluginManager::IPluginManager(QObject *parent) : QObject(parent)
|
||||
{
|
||||
return m_metadatas.values(iid);
|
||||
|
||||
}
|
||||
|
||||
QObject *CPluginManager::getPluginById(const QString &identifier)
|
||||
void IPluginManager::collectPlugins()
|
||||
{
|
||||
QDir pluginDir(pluginDirectory());
|
||||
if (!pluginDir.exists())
|
||||
{
|
||||
CLogMessage(this).warning("No such directory: %1") << pluginDir.path();
|
||||
return;
|
||||
}
|
||||
|
||||
QDirIterator it(pluginDir, QDirIterator::FollowSymlinks);
|
||||
while (it.hasNext())
|
||||
{
|
||||
if (!QLibrary::isLibrary(it.next()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CLogMessage(this).debug() << "Loading plugin: " << it.filePath();
|
||||
QPluginLoader loader(it.filePath());
|
||||
QJsonObject json = loader.metaData();
|
||||
if (!isValid(json))
|
||||
{
|
||||
CLogMessage(this).warning("Plugin %1 invalid, not loading it") << it.filePath();
|
||||
continue;
|
||||
}
|
||||
|
||||
QString identifier = pluginIdentifier(json);
|
||||
m_paths.insert(identifier, it.filePath());
|
||||
m_metadatas.push_back(json);
|
||||
}
|
||||
}
|
||||
|
||||
QString IPluginManager::pluginDirectory() const
|
||||
{
|
||||
return qApp->applicationDirPath() % QStringLiteral("/plugins");
|
||||
}
|
||||
|
||||
bool IPluginManager::isValid(const QJsonObject &metadata) const
|
||||
{
|
||||
if (!metadata.contains("IID") || !metadata["IID"].isString())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!metadata["MetaData"].isObject())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject data = metadata["MetaData"].toObject();
|
||||
if (!data.contains("identifier") || !data["identifier"].isString())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto iids = acceptedIids();
|
||||
for (const QString &iid : iids)
|
||||
{
|
||||
if (metadata["IID"].toString() == iid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString IPluginManager::pluginIdentifier(const QJsonObject &metadata) const
|
||||
{
|
||||
Q_ASSERT(isValid(metadata));
|
||||
return metadata.value("MetaData").toObject().value("identifier").toString();
|
||||
}
|
||||
|
||||
QString IPluginManager::getIdByPlugin(const QObject *instance) const
|
||||
{
|
||||
return m_instanceIds.value(instance, QString());
|
||||
}
|
||||
|
||||
QObject *IPluginManager::getPluginByIdImpl(const QString &identifier)
|
||||
{
|
||||
if (m_instances.contains(identifier))
|
||||
{
|
||||
@@ -43,6 +122,7 @@ namespace BlackCore {
|
||||
if (instance)
|
||||
{
|
||||
m_instances.insert(identifier, instance);
|
||||
m_instanceIds.insert(instance, identifier);
|
||||
return instance;
|
||||
}
|
||||
else
|
||||
@@ -52,80 +132,4 @@ namespace BlackCore {
|
||||
}
|
||||
}
|
||||
|
||||
CPluginManager *CPluginManager::getInstance()
|
||||
{
|
||||
static CPluginManager *instance = nullptr;
|
||||
if (!instance)
|
||||
{
|
||||
instance = new CPluginManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
CPluginManager::CPluginManager(QObject *parent) : QObject(parent)
|
||||
{
|
||||
collectPlugins();
|
||||
|
||||
connect(qApp, &QCoreApplication::aboutToQuit, this, &CPluginManager::deleteLater);
|
||||
}
|
||||
|
||||
void CPluginManager::collectPlugins()
|
||||
{
|
||||
QDir pluginDir(qApp->applicationDirPath().append("/plugins"));
|
||||
if (!pluginDir.exists())
|
||||
{
|
||||
CLogMessage(this).warning("No plugins directory: %1") << pluginDir.path();
|
||||
return;
|
||||
}
|
||||
|
||||
QDirIterator it(pluginDir, QDirIterator::Subdirectories);
|
||||
while (it.hasNext())
|
||||
{
|
||||
if (!QLibrary::isLibrary(it.next()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CLogMessage(this).debug() << "Loading plugin: " << it.filePath();
|
||||
QPluginLoader loader(it.filePath());
|
||||
QJsonObject json = loader.metaData();
|
||||
QString identifier = pluginIdentifier(json);
|
||||
if (identifier.isEmpty())
|
||||
{
|
||||
CLogMessage(this).warning("Plugin %1 invalid, not loading it") << it.filePath();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_paths.insert(identifier, it.filePath());
|
||||
m_metadatas.insert(json["IID"].toString(), json);
|
||||
}
|
||||
}
|
||||
|
||||
QString CPluginManager::pluginIdentifier(const QJsonObject &metadata)
|
||||
{
|
||||
if (!metadata.contains("IID") || !metadata["IID"].isString())
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
if (!metadata["MetaData"].isObject())
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QJsonObject data = metadata["MetaData"].toObject();
|
||||
if (!data.contains("identifier"))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QJsonValue identifier = data["identifier"];
|
||||
if (!identifier.isString())
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
return identifier.toString();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef CPLUGINMANAGER_H
|
||||
#define CPLUGINMANAGER_H
|
||||
#ifndef BLACKCORE_PLUGIN_MANAGER_H
|
||||
#define BLACKCORE_PLUGIN_MANAGER_H
|
||||
|
||||
#include "blackcoreexport.h"
|
||||
#include "blackmisc/sequence.h"
|
||||
#include <QObject>
|
||||
#include <QMultiMap>
|
||||
@@ -21,45 +22,67 @@ namespace BlackCore
|
||||
{
|
||||
|
||||
/*!
|
||||
* \brief Manages all installed plugins, provides easy access to all of them.
|
||||
* Plugin loading works as follows:
|
||||
* 1. Collect all interesting plugins by their IID (\ref plugins());
|
||||
* all plugins are guaranteed to be valid, i.e. they have valid IID and identifier.
|
||||
* 2. Load specified plugin (\ref getPluginById()).
|
||||
* Base class for all contexts that provide plugin support.
|
||||
* It is responsible for locating, validating and loading plugins.
|
||||
*/
|
||||
class CPluginManager : public QObject
|
||||
class BLACKCORE_EXPORT IPluginManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//! Retrieves plugin metadata list for the given IID.
|
||||
//! If no implementations are found, the empty list is returned.
|
||||
BlackMisc::CSequence<QJsonObject> plugins(const QString &iid) const;
|
||||
//! Constructor
|
||||
IPluginManager(QObject *parent = nullptr);
|
||||
|
||||
//! Loads the given plugin (if necessary) and returns its instance.
|
||||
//! Returns _nullptr_ on failure.
|
||||
QObject *getPluginById(const QString &identifier);
|
||||
|
||||
//! Gets the singleton
|
||||
static CPluginManager *getInstance();
|
||||
//! Looks for all available plugins
|
||||
virtual void collectPlugins();
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
explicit CPluginManager(QObject *parent = nullptr);
|
||||
//! Returns the list of valid IIDs for the implementation
|
||||
virtual BlackMisc::CSequence<QString> acceptedIids() const = 0;
|
||||
|
||||
//! Where to look for plugins, absolute path.
|
||||
//! Default implementation returns `plugins` in the application dir.
|
||||
virtual QString pluginDirectory() const;
|
||||
|
||||
//! Defines whether the given plugin is valid or not, based on its metadata.
|
||||
//! The default implementation checks if all values common for all plugins
|
||||
//! (i.e. MetaData and identifier) are present and valid. It also checks
|
||||
//! if each plugin meets one of the specified in \ref acceptedIids() IIDs.
|
||||
//! Override custom plugin validation in the subclass if needed.
|
||||
virtual bool isValid(const QJsonObject &metadata) const;
|
||||
|
||||
//! Gets the plugin identifier from the metadata.
|
||||
QString pluginIdentifier(const QJsonObject &metadata) const;
|
||||
|
||||
//! Gets plugin identifier by its instance
|
||||
QString getIdByPlugin(const QObject *instance) const;
|
||||
|
||||
//! Loads the given plugin (if necessary), casts it to the desired
|
||||
//! type and returns its instance. Returns `nullptr` on failure.
|
||||
template <class T>
|
||||
T *getPluginById(const QString &identifier)
|
||||
{
|
||||
return qobject_cast<T *>(getPluginByIdImpl(identifier));
|
||||
}
|
||||
|
||||
//! Gets direct access to all plugins' metadata
|
||||
const BlackMisc::CSequence<QJsonObject> &getPlugins()
|
||||
{
|
||||
return m_metadatas;
|
||||
}
|
||||
|
||||
private:
|
||||
//! Looks (recursively) for all installed plugins
|
||||
void collectPlugins();
|
||||
|
||||
//! Checks whether the provided metadata is valid
|
||||
//! \return The plugin identifier
|
||||
QString pluginIdentifier(const QJsonObject &metadata);
|
||||
//! Loads the given plugin (if necessary) and returns its instance.
|
||||
//! Returns `nullptr` on failure.
|
||||
QObject *getPluginByIdImpl(const QString &identifier);
|
||||
|
||||
QMultiMap<QString, QJsonObject> m_metadatas; //!< IID <-> metadata pairs
|
||||
BlackMisc::CSequence<QJsonObject> m_metadatas;
|
||||
QMap<QString, QString> m_paths; //!< identifier <-> file path pairs
|
||||
QMap<QString, QObject*> m_instances; //!< identifier <-> instance pairs
|
||||
QMap<QString, QObject *> m_instances; //!< identifier <-> instance pairs
|
||||
QMap<const QObject *, QString> m_instanceIds; //!< instance <-> identifier pairs
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CPLUGINMANAGER_H
|
||||
#endif // BLACKCORE_PLUGIN_MANAGER_H
|
||||
|
||||
113
src/blackcore/plugin_manager_simulator.cpp
Normal file
113
src/blackcore/plugin_manager_simulator.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "plugin_manager_simulator.h"
|
||||
#include "simulator.h"
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
|
||||
using namespace BlackMisc;
|
||||
using namespace BlackMisc::Simulation;
|
||||
|
||||
CPluginManagerSimulator::CPluginManagerSimulator(QObject *parent) : IPluginManager(parent)
|
||||
{
|
||||
}
|
||||
|
||||
CVariant CPluginManagerSimulator::getPluginData(const QObject *obj, const QString &key) const
|
||||
{
|
||||
const QObject *p = obj;
|
||||
while (p && !p->inherits("BlackCore::ISimulatorFactory"))
|
||||
{
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
if (!p) return CVariant();
|
||||
|
||||
QString id = getIdByPlugin(p);
|
||||
Q_ASSERT(!id.isEmpty());
|
||||
const PluginExtended &pe = m_plugins[id];
|
||||
return pe.storage.value(key);
|
||||
}
|
||||
|
||||
void CPluginManagerSimulator::setPluginData(const QObject *obj, const QString &key, const CVariant &value)
|
||||
{
|
||||
const QObject *p = obj;
|
||||
while (p && !p->inherits("BlackCore::ISimulatorFactory"))
|
||||
{
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
if (!p) return;
|
||||
|
||||
QString id = getIdByPlugin(p);
|
||||
Q_ASSERT(!id.isEmpty());
|
||||
PluginExtended &pe = m_plugins[id];
|
||||
pe.storage.insert(key, value);
|
||||
}
|
||||
|
||||
ISimulatorFactory *CPluginManagerSimulator::getFactory(const QString &pluginId)
|
||||
{
|
||||
return getPluginById<ISimulatorFactory>(pluginId);
|
||||
}
|
||||
|
||||
ISimulatorListener *CPluginManagerSimulator::getListener(const QString &pluginId)
|
||||
{
|
||||
if (!m_plugins.contains(pluginId))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PluginExtended &plugin = m_plugins[pluginId];
|
||||
if (!plugin.listener)
|
||||
{
|
||||
ISimulatorFactory *factory = getPluginById<ISimulatorFactory>(pluginId);
|
||||
Q_ASSERT(factory);
|
||||
|
||||
ISimulatorListener *listener = factory->createListener(plugin.info);
|
||||
connect(qApp, &QCoreApplication::aboutToQuit, listener, &QObject::deleteLater);
|
||||
plugin.listener = listener;
|
||||
}
|
||||
|
||||
return plugin.listener;
|
||||
}
|
||||
|
||||
CSimulatorPluginInfoList CPluginManagerSimulator::getAvailableSimulatorPlugins() const
|
||||
{
|
||||
CSimulatorPluginInfoList list;
|
||||
for (const auto &i : m_plugins.values())
|
||||
{
|
||||
list.push_back(i.info);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void CPluginManagerSimulator::collectPlugins()
|
||||
{
|
||||
IPluginManager::collectPlugins();
|
||||
|
||||
const CSequence<QJsonObject> &plugins = getPlugins();
|
||||
for (const QJsonObject &json : plugins)
|
||||
{
|
||||
auto it = m_plugins.insert(pluginIdentifier(json), {});
|
||||
it->info.convertFromJson(json);
|
||||
}
|
||||
}
|
||||
|
||||
BlackMisc::CSequence<QString> CPluginManagerSimulator::acceptedIids() const
|
||||
{
|
||||
return { QStringLiteral("org.swift-project.blackcore.simulatorinterface") };
|
||||
}
|
||||
|
||||
QString CPluginManagerSimulator::pluginDirectory() const
|
||||
{
|
||||
return qApp->applicationDirPath() % QStringLiteral("/plugins/simulator");
|
||||
}
|
||||
|
||||
}
|
||||
83
src/blackcore/plugin_manager_simulator.h
Normal file
83
src/blackcore/plugin_manager_simulator.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKCORE_PLUGIN_MANAGER_SIMULATOR_H
|
||||
#define BLACKCORE_PLUGIN_MANAGER_SIMULATOR_H
|
||||
|
||||
#include "blackcoreexport.h"
|
||||
#include "plugin_manager.h"
|
||||
#include "blackmisc/pluginstorageprovider.h"
|
||||
#include "blackmisc/simulation/simulatorplugininfo.h"
|
||||
#include "blackmisc/simulation/simulatorplugininfolist.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
class ISimulatorFactory;
|
||||
class ISimulatorListener;
|
||||
class ISimulator;
|
||||
|
||||
/*!
|
||||
* Manages plugins for the simulator context.
|
||||
*/
|
||||
class BLACKCORE_EXPORT CPluginManagerSimulator :
|
||||
public BlackCore::IPluginManager,
|
||||
public BlackMisc::IPluginStorageProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//! Ctor
|
||||
CPluginManagerSimulator(QObject *parent = nullptr);
|
||||
|
||||
//! \copydoc BlackMisc::IPluginStorageProvider::getPluginData
|
||||
virtual BlackMisc::CVariant getPluginData(const QObject *obj, const QString &key) const override;
|
||||
|
||||
//! \copydoc BlackMisc::IPluginStorageProvider::setPluginData
|
||||
virtual void setPluginData(const QObject *obj, const QString &key, const BlackMisc::CVariant &value) override;
|
||||
|
||||
//! Get simulator factory from the plugin
|
||||
ISimulatorFactory *getFactory(const QString &pluginId);
|
||||
|
||||
//! Get simulator listener from the plugin
|
||||
ISimulatorListener *getListener(const QString &pluginId);
|
||||
|
||||
//! Get all simulator driver plugins
|
||||
BlackMisc::Simulation::CSimulatorPluginInfoList getAvailableSimulatorPlugins() const;
|
||||
|
||||
//! \copydoc BlackCore::IPluginManager::collectPlugins()
|
||||
virtual void collectPlugins() override;
|
||||
|
||||
protected:
|
||||
//! \copydoc BlackCore::IPluginManager::acceptedIids()
|
||||
virtual BlackMisc::CSequence<QString> acceptedIids() const override;
|
||||
|
||||
//! \copydoc BlackCore::IPluginManager::pluginDirectory()
|
||||
virtual QString pluginDirectory() const override;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* Extended data for plugin
|
||||
*/
|
||||
struct PluginExtended
|
||||
{
|
||||
BlackMisc::Simulation::CSimulatorPluginInfo info;
|
||||
ISimulatorListener *listener = nullptr;
|
||||
QHash<QString, BlackMisc::CVariant> storage; //!< Permanent plugin storage - data stored here will be kept even when plugin is unloaded
|
||||
};
|
||||
|
||||
QMap<QString, PluginExtended> m_plugins; //!< Id <-> extended data pairs
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // BLACKCORE_PLUGIN_MANAGER_SIMULATOR_H
|
||||
Reference in New Issue
Block a user