mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 14:55:36 +08:00
592 lines
23 KiB
C++
592 lines
23 KiB
C++
/* 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 "contextsimulatorimpl.h"
|
|
#include "contextownaircraftimpl.h"
|
|
#include "contextownaircraft.h"
|
|
#include "contextapplication.h"
|
|
#include "contextnetworkimpl.h"
|
|
#include "pluginmanagersimulator.h"
|
|
#include "contextruntime.h"
|
|
#include "blackcore/registermetadata.h"
|
|
#include "blackmisc/propertyindexvariantmap.h"
|
|
#include "blackmisc/logmessage.h"
|
|
#include "blackmisc/loghandler.h"
|
|
#include "blackmisc/threadutils.h"
|
|
#include <QPluginLoader>
|
|
#include <QLibrary>
|
|
|
|
using namespace BlackMisc;
|
|
using namespace BlackMisc::PhysicalQuantities;
|
|
using namespace BlackMisc::Aviation;
|
|
using namespace BlackMisc::Network;
|
|
using namespace BlackMisc::Simulation;
|
|
using namespace BlackMisc::Geo;
|
|
using namespace BlackMisc::Simulation;
|
|
|
|
namespace BlackCore
|
|
{
|
|
CContextSimulator::CContextSimulator(CRuntimeConfig::ContextMode mode, CRuntime *runtime) :
|
|
IContextSimulator(mode, runtime),
|
|
m_plugins(new CPluginManagerSimulator(this))
|
|
{
|
|
this->setObjectName("CContextSimulator");
|
|
m_plugins->collectPlugins();
|
|
}
|
|
|
|
CContextSimulator::~CContextSimulator()
|
|
{
|
|
this->gracefulShutdown();
|
|
}
|
|
|
|
void CContextSimulator::gracefulShutdown()
|
|
{
|
|
this->disconnect();
|
|
this->unloadSimulatorPlugin();
|
|
}
|
|
|
|
CSimulatorPluginInfoList CContextSimulator::getAvailableSimulatorPlugins() const
|
|
{
|
|
return m_plugins->getAvailableSimulatorPlugins();
|
|
}
|
|
|
|
bool CContextSimulator::startSimulatorPlugin(const CSimulatorPluginInfo &simulatorInfo)
|
|
{
|
|
return this->loadSimulatorPlugin(simulatorInfo, true);
|
|
}
|
|
|
|
void CContextSimulator::stopSimulatorPlugin(const CSimulatorPluginInfo &simulatorInfo)
|
|
{
|
|
if (!m_simulatorPlugin.first.isUnspecified() && m_simulatorPlugin.first == simulatorInfo)
|
|
{
|
|
this->unloadSimulatorPlugin();
|
|
}
|
|
|
|
ISimulatorListener *listener = m_plugins->getListener(simulatorInfo.getIdentifier());
|
|
QMetaObject::invokeMethod(listener, "stop");
|
|
}
|
|
|
|
int CContextSimulator::getSimulatorStatus() const
|
|
{
|
|
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
|
if (m_simulatorPlugin.first.isUnspecified()) { return 0; }
|
|
|
|
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.first.isUnspecified()) { return BlackMisc::Simulation::CSimulatorPluginInfo(); }
|
|
|
|
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.first.isUnspecified())
|
|
{
|
|
return BlackMisc::Simulation::CSimulatorSetup();
|
|
}
|
|
|
|
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.first.isUnspecified())
|
|
{
|
|
return CAirportList();
|
|
}
|
|
|
|
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.first.isUnspecified())
|
|
{
|
|
return CAircraftModelList();
|
|
}
|
|
|
|
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.first.isUnspecified()) { return 0; }
|
|
|
|
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.first.isUnspecified())
|
|
{
|
|
return CAircraftModelList();
|
|
}
|
|
|
|
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.first.isUnspecified())
|
|
{
|
|
return;
|
|
}
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
m_simulatorPlugin.second->reloadInstalledModels();
|
|
}
|
|
|
|
bool CContextSimulator::setTimeSynchronization(bool enable, const CTime &offset)
|
|
{
|
|
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
|
if (m_simulatorPlugin.first.isUnspecified()) { return false; }
|
|
|
|
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"));
|
|
return true;
|
|
}
|
|
|
|
bool CContextSimulator::isTimeSynchronized() const
|
|
{
|
|
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
|
if (m_simulatorPlugin.first.isUnspecified()) { return false; }
|
|
|
|
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.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.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.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.first.isUnspecified()) { return ""; }
|
|
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
if (!m_simulatorPlugin.second->isRenderingRestricted()) { return "none"; }
|
|
QString rt;
|
|
if (m_simulatorPlugin.second->isMaxAircraftRestricted())
|
|
{
|
|
rt.append(QString::number(m_simulatorPlugin.second->getMaxRenderedAircraft())).append(" A/C");
|
|
}
|
|
if (m_simulatorPlugin.second->isMaxDistanceRestricted())
|
|
{
|
|
if (!rt.isEmpty()) { rt.append(" ");}
|
|
rt.append(m_simulatorPlugin.second->getMaxRenderedDistance().valueRoundedWithUnit(CLengthUnit::NM(), 0));
|
|
}
|
|
return rt;
|
|
}
|
|
|
|
CLength CContextSimulator::getMaxRenderedDistance() const
|
|
{
|
|
if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; }
|
|
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.first.isUnspecified())
|
|
{
|
|
return CLength(20.0, CLengthUnit::NM());
|
|
}
|
|
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.first.isUnspecified())
|
|
{
|
|
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.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.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.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)
|
|
{
|
|
Q_ASSERT(getIContextApplication());
|
|
Q_ASSERT(getIContextApplication()->isUsingImplementingObject());
|
|
Q_ASSERT(!simulatorInfo.isUnspecified());
|
|
Q_ASSERT(CThreadUtils::isCurrentThreadApplicationThread()); // only run in main thread
|
|
|
|
if (!simulatorInfo.isValid())
|
|
{
|
|
CLogMessage(this).error("Illegal plugin");
|
|
return false;
|
|
}
|
|
|
|
// Is the plugin already loaded?
|
|
if (!m_simulatorPlugin.first.isUnspecified())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
unloadSimulatorPlugin(); // old plugin unloaded
|
|
|
|
// now we have a state where no driver is loaded
|
|
if (withListener)
|
|
{
|
|
this->listenForSimulator(simulatorInfo);
|
|
return false; // not a plugin yet, just listener
|
|
}
|
|
|
|
if (!simulatorInfo.isValid() || simulatorInfo.isUnspecified())
|
|
{
|
|
CLogMessage(this).error("Illegal plugin");
|
|
return false;
|
|
}
|
|
|
|
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
|
|
// Hence we pass in memory reference to own aircraft object
|
|
Q_ASSERT(this->getIContextOwnAircraft()->isUsingImplementingObject());
|
|
Q_ASSERT(this->getIContextNetwork()->isUsingImplementingObject());
|
|
IOwnAircraftProvider *ownAircraftProvider = this->getRuntime()->getCContextOwnAircraft();
|
|
IRemoteAircraftProvider *renderedAircraftProvider = this->getRuntime()->getCContextNetwork();
|
|
ISimulator *simulator = factory->create(simulatorInfo, ownAircraftProvider, renderedAircraftProvider, m_plugins);
|
|
Q_ASSERT_X(simulator, Q_FUNC_INFO, "no simulator driver can be created");
|
|
|
|
bool c = connect(simulator, &ISimulator::simulatorStatusChanged, this, &CContextSimulator::ps_onSimulatorStatusChanged);
|
|
Q_ASSERT(c);
|
|
c = connect(simulator, &ISimulator::ownAircraftModelChanged, this, &IContextSimulator::ownAircraftModelChanged);
|
|
Q_ASSERT(c);
|
|
c = connect(simulator, &ISimulator::modelMatchingCompleted, this, &IContextSimulator::modelMatchingCompleted);
|
|
Q_ASSERT(c);
|
|
c = connect(simulator, &ISimulator::installedAircraftModelsChanged, this, &IContextSimulator::installedAircraftModelsChanged);
|
|
Q_ASSERT(c);
|
|
c = connect(simulator, &ISimulator::renderRestrictionsChanged, this, &IContextSimulator::renderRestrictionsChanged);
|
|
Q_ASSERT(c);
|
|
c = connect(simulator, &ISimulator::airspaceSnapshotHandled, this, &IContextSimulator::airspaceSnapshotHandled);
|
|
Q_ASSERT(c);
|
|
|
|
// log from context to simulator
|
|
c = connect(CLogHandler::instance(), &CLogHandler::localMessageLogged, simulator, &ISimulator::displayStatusMessage);
|
|
Q_ASSERT(c);
|
|
c = connect(CLogHandler::instance(), &CLogHandler::remoteMessageLogged, simulator, &ISimulator::displayStatusMessage);
|
|
Q_ASSERT(c);
|
|
Q_UNUSED(c);
|
|
|
|
// use network to initally add aircraft
|
|
IContextNetwork *networkContext = this->getIContextNetwork();
|
|
Q_ASSERT(networkContext);
|
|
Q_ASSERT(networkContext->isLocalObject());
|
|
|
|
// initially add aircraft
|
|
for (const CSimulatedAircraft &simulatedAircraft : networkContext->getAircraftInRange())
|
|
{
|
|
Q_ASSERT(!simulatedAircraft.getCallsign().isEmpty());
|
|
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
|
|
simulator->connectTo();
|
|
emit simulatorPluginChanged(simulatorInfo);
|
|
CLogMessage(this).info("Simulator plugin loaded: %1") << simulatorInfo.toQString(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
void CContextSimulator::listenForSimulator(const CSimulatorPluginInfo &simulatorInfo)
|
|
{
|
|
Q_ASSERT(this->getIContextApplication());
|
|
Q_ASSERT(this->getIContextApplication()->isUsingImplementingObject());
|
|
Q_ASSERT(!simulatorInfo.isUnspecified());
|
|
|
|
ISimulator::SimulatorStatus simStatus = getSimulatorStatusEnum();
|
|
if (!m_simulatorPlugin.first.isUnspecified() &&
|
|
m_simulatorPlugin.first == simulatorInfo && simStatus.testFlag(ISimulator::Connected))
|
|
{
|
|
// the simulator is already connected and running
|
|
return;
|
|
}
|
|
|
|
if (!m_simulatorPlugin.first.isUnspecified())
|
|
{
|
|
// wrong or disconnected plugin, we start from the scratch
|
|
this->unloadSimulatorPlugin();
|
|
}
|
|
|
|
if (!m_listenersThread.isRunning())
|
|
{
|
|
m_listenersThread.setObjectName("CContextSimulator:Thread for listeners");
|
|
m_listenersThread.start(QThread::LowPriority);
|
|
}
|
|
|
|
ISimulatorListener *listener = m_plugins->getListener(simulatorInfo.getIdentifier());
|
|
Q_ASSERT_X(listener, Q_FUNC_INFO, "No listener");
|
|
|
|
if (listener->thread() != &m_listenersThread)
|
|
{
|
|
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(!listener->parent(), Q_FUNC_INFO, "Objects with parent cannot be moved to thread");
|
|
listener->setProperty("isInitialized", true);
|
|
listener->moveToThread(&m_listenersThread);
|
|
}
|
|
|
|
bool s = QMetaObject::invokeMethod(listener, "start", Qt::QueuedConnection);
|
|
Q_ASSERT_X(s, Q_FUNC_INFO, "cannot invoke method");
|
|
Q_UNUSED(s);
|
|
}
|
|
|
|
void CContextSimulator::listenForAllSimulators()
|
|
{
|
|
auto plugins = getAvailableSimulatorPlugins();
|
|
for (const CSimulatorPluginInfo &p : plugins)
|
|
{
|
|
Q_ASSERT(!p.isUnspecified());
|
|
|
|
if (p.isValid())
|
|
{
|
|
listenForSimulator(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CContextSimulator::unloadSimulatorPlugin()
|
|
{
|
|
if (!m_simulatorPlugin.first.isUnspecified())
|
|
{
|
|
ISimulator *sim = m_simulatorPlugin.second;
|
|
m_simulatorPlugin.second = nullptr;
|
|
m_simulatorPlugin.first = CSimulatorPluginInfo();
|
|
|
|
Q_ASSERT(this->getIContextNetwork());
|
|
Q_ASSERT(this->getIContextNetwork()->isLocalObject());
|
|
|
|
// unload and disconnect
|
|
if (sim)
|
|
{
|
|
// disconnect signals and delete
|
|
sim->unload();
|
|
this->disconnect(sim);
|
|
sim->deleteLater();
|
|
emit simulatorPluginChanged(CSimulatorPluginInfo());
|
|
}
|
|
}
|
|
}
|
|
|
|
void CContextSimulator::ps_addRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
|
|
{
|
|
// 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.first.isUnspecified())
|
|
{
|
|
// Do something if no simulator is running
|
|
return;
|
|
}
|
|
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
Q_ASSERT(!remoteAircraft.getCallsign().isEmpty());
|
|
|
|
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.first.isUnspecified())
|
|
{
|
|
// Do something if no simulator is running
|
|
return;
|
|
}
|
|
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
m_simulatorPlugin.second->logicallyRemoveRemoteAircraft(callsign);
|
|
}
|
|
|
|
void CContextSimulator::ps_onSimulatorStatusChanged(int status)
|
|
{
|
|
ISimulator::SimulatorStatus statusEnum = ISimulator::statusToEnum(status);
|
|
if (!statusEnum.testFlag(ISimulator::Connected))
|
|
{
|
|
// we got disconnected, plugin no longer needed
|
|
unloadSimulatorPlugin();
|
|
}
|
|
emit simulatorStatusChanged(status);
|
|
}
|
|
|
|
void CContextSimulator::ps_textMessagesReceived(const Network::CTextMessageList &textMessages)
|
|
{
|
|
// 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.first.isUnspecified())
|
|
{
|
|
// Do something if no simulator is running
|
|
return;
|
|
}
|
|
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
for (const auto &tm : textMessages)
|
|
{
|
|
m_simulatorPlugin.second->displayTextMessage(tm);
|
|
}
|
|
}
|
|
|
|
void CContextSimulator::ps_cockpitChangedFromSimulator(const CSimulatedAircraft &ownAircraft)
|
|
{
|
|
Q_ASSERT(getIContextOwnAircraft());
|
|
getIContextOwnAircraft()->changedAircraftCockpit(ownAircraft, IContextSimulator::InterfaceName());
|
|
}
|
|
|
|
void CContextSimulator::ps_changedRemoteAircraftModel(const CSimulatedAircraft &aircraft, const CIdentifier &originator)
|
|
{
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
m_simulatorPlugin.second->changeRemoteAircraftModel(aircraft, originator);
|
|
}
|
|
|
|
void CContextSimulator::ps_changedRemoteAircraftEnabled(const CSimulatedAircraft &aircraft, const CIdentifier &originator)
|
|
{
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
m_simulatorPlugin.second->changeRemoteAircraftEnabled(aircraft, originator);
|
|
}
|
|
|
|
void CContextSimulator::ps_updateSimulatorCockpitFromContext(const CSimulatedAircraft &ownAircraft, const CIdentifier &originator)
|
|
{
|
|
// 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.first.isUnspecified())
|
|
{
|
|
// Do something if no simulator is running
|
|
return;
|
|
}
|
|
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
|
|
// avoid loops
|
|
if (originator.getName().isEmpty() || originator == IContextSimulator::InterfaceName()) { return; }
|
|
|
|
// update
|
|
m_simulatorPlugin.second->updateOwnSimulatorCockpit(ownAircraft, originator);
|
|
}
|
|
|
|
CPixmap CContextSimulator::iconForModel(const QString &modelString) const
|
|
{
|
|
if (m_simulatorPlugin.first.isUnspecified()) { return CPixmap(); }
|
|
Q_ASSERT_X(m_simulatorPlugin.second, Q_FUNC_INFO, "Missing simulator");
|
|
return m_simulatorPlugin.second->iconForModel(modelString);
|
|
}
|
|
|
|
void CContextSimulator::enableDebugMessages(bool driver, bool interpolator)
|
|
{
|
|
if (m_simulatorPlugin.first.isUnspecified()) { return; }
|
|
Q_ASSERT_X(m_simulatorPlugin.second, Q_FUNC_INFO, "Missing simulator");
|
|
return m_simulatorPlugin.second->enableDebugMessages(driver, interpolator);
|
|
}
|
|
|
|
void CContextSimulator::highlightAircraft(const CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const CTime &displayTime)
|
|
{
|
|
Q_ASSERT(m_simulatorPlugin.second);
|
|
m_simulatorPlugin.second->highlightAircraft(aircraftToHighlight, enableHighlight, displayTime);
|
|
}
|
|
|
|
void CContextSimulator::ps_simulatorStarted(const CSimulatorPluginInfo &info)
|
|
{
|
|
stopSimulatorListeners();
|
|
loadSimulatorPlugin(info, false);
|
|
}
|
|
|
|
void CContextSimulator::stopSimulatorListeners()
|
|
{
|
|
for (const auto &info : getAvailableSimulatorPlugins())
|
|
{
|
|
ISimulatorListener *listener = m_plugins->getListener(info.getIdentifier());
|
|
QMetaObject::invokeMethod(listener, "stop");
|
|
}
|
|
}
|
|
|
|
} // namespace
|