[xswiftbus] Make xswiftbus completely Qt free

This commit is contained in:
Roland Winklmeier
2018-03-25 16:10:54 +02:00
parent b0a8fcaa45
commit 6a8ae67e06
13 changed files with 525 additions and 429 deletions

View File

@@ -97,8 +97,10 @@ namespace BlackSimPlugin
m_slowTimer.setObjectName(this->objectName().append(":m_slowTimer"));
connect(&m_fastTimer, &QTimer::timeout, this, &CSimulatorXPlane::fastTimerTimeout);
connect(&m_slowTimer, &QTimer::timeout, this, &CSimulatorXPlane::slowTimerTimeout);
connect(&m_airportUpdater, &QTimer::timeout, this, &CSimulatorXPlane::updateAirportsInRange);
m_fastTimer.start(100);
m_slowTimer.start(1000);
m_airportUpdater.start(60000);
this->setDefaultModel({ "Jets A320_a A320_a_Austrian_Airlines A320_a_Austrian_Airlines", CAircraftModel::TypeModelMatchingDefaultModel,
"A320 AUA", CAircraftIcaoCode("A320", "L2J")});
@@ -793,6 +795,11 @@ namespace BlackSimPlugin
this->rememberElevationAndCG(callsign, elevation, CLength(modelVerticalOffsetMeters, CLengthUnit::m()));
}
void CSimulatorXPlane::updateAirportsInRange()
{
if (this->isConnected()) { m_serviceProxy->updateAirportsInRange(); }
}
BlackCore::ISimulator *CSimulatorXPlaneFactory::create(const CSimulatorPluginInfo &info,
IOwnAircraftProvider *ownAircraftProvider,
IRemoteAircraftProvider *remoteAircraftProvider,

View File

@@ -190,6 +190,7 @@ namespace BlackSimPlugin
void requestRemoteAircraftDataFromXPlane();
void updateRemoteAircraftFromSimulator(const QString &callsign, double latitudeDeg, double longitudeDeg, double elevationMeters, double modelVerticalOffsetMeters);
void updateAirportsInRange();
static constexpr int GuessRemoteAircraftPartsCycle = 20; //!< guess every n-th cycle
@@ -201,6 +202,7 @@ namespace BlackSimPlugin
CXSwiftBusWeatherProxy *m_weatherProxy { nullptr };
QTimer m_fastTimer;
QTimer m_slowTimer;
QTimer m_airportUpdater;
BlackMisc::Aviation::CAirportList m_airportsInRange; //!< aiports in range of own aircraft
BlackMisc::CData<BlackMisc::Simulation::Data::TModelSetCacheXP> m_modelSet { this };

View File

@@ -20,17 +20,6 @@
#define XPLM_MSG_LIVERY_LOADED 108
#endif
// Change QSharedPointer<QCoreApplication> to QSharedPointer<QApplication> below
// in case you want to have Qt Gui components inside a X-Plane plugin. The current
// default was used since QApplication causes an infinite loop in X-Plane on MacOS
// platforms. X-Plane is allocating an NSApplication but never calling run(), rather
// it controls the main loop itself and pumps the event Q as needed. This causes
// unusual start conditions for QCocoaEventDispatcher and ends up in the infinite
// loop. Since QCoreApplication is not using QCocoaEventDispatcher it works fine
// and is used as a workaround.
// See https://dev.vatsim-germany.org/issues/293 for more information.
QSharedPointer<QCoreApplication> g_qApp;
XSwiftBus::CPlugin *g_plugin;
PLUGIN_API int XPluginStart(char *o_name, char *o_sig, char *o_desc)
@@ -54,10 +43,6 @@ PLUGIN_API void XPluginStop()
PLUGIN_API int XPluginEnable()
{
QXPlaneMessageHandler::install();
g_qApp = QSharedApplication::sharedInstance();
QXPlaneEventLoop::exec();
g_plugin = new XSwiftBus::CPlugin;
return 1;
}
@@ -65,7 +50,6 @@ PLUGIN_API int XPluginEnable()
PLUGIN_API void XPluginDisable()
{
delete g_plugin;
g_qApp.reset();
}
PLUGIN_API void XPluginReceiveMessage(XPLMPluginID from, long msg, void *param)

View File

@@ -13,7 +13,6 @@
#include "weather.h"
#include "utils.h"
#include "XPLM/XPLMProcessing.h"
#include <QTimer>
#include <functional>
#include <thread>
@@ -71,6 +70,8 @@ namespace XSwiftBus
m_service = new CService(m_dbusConnection.get());
m_traffic = new CTraffic(m_dbusConnection.get());
m_weather = new CWeather(m_dbusConnection.get());
INFO_LOG("XSwiftBus started.");
}
void CPlugin::onAircraftModelChanged()

View File

@@ -22,8 +22,6 @@
#endif
#include "dbusconnection.h"
#include "menus.h"
#include <QObject>
#include <QVector>
#include <memory>
#include <thread>
@@ -36,10 +34,8 @@ namespace XSwiftBus
/*!
* Main plugin class
*/
class CPlugin : public QObject
class CPlugin
{
Q_OBJECT
public:
//! Constructor
CPlugin();

View File

@@ -10,11 +10,8 @@
#include "service.h"
#include <XPLM/XPLMPlanes.h>
#include <XPLM/XPLMUtilities.h>
#include <QDebug>
#include <QTimer>
#include <QRegularExpression>
#include <QStringBuilder>
#include <QDir>
#include <fstream>
#include "utils.h"
// clazy:excludeall=reserve-candidates
@@ -25,9 +22,6 @@ namespace XSwiftBus
{
registerDBusObjectPath(XSWIFTBUS_SERVICE_INTERFACENAME, XSWIFTBUS_SERVICE_OBJECTPATH);
m_messages.addMessage( { "xswiftbus started.", 0, 255, 255 } );
m_airportUpdater = new QTimer();
m_airportUpdater->start(60000);
QObject::connect(m_airportUpdater, &QTimer::timeout, [this] () { updateAirportsInRange(); });
updateAirportsInRange();
}
@@ -36,35 +30,38 @@ namespace XSwiftBus
char filename[256];
char path[512];
XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
const auto model = extractAcfProperties(path, QFileInfo(path));
const auto model = extractAcfProperties(path);
emitAircraftModelChanged(path, filename, getAircraftLivery(), getAircraftIcaoCode(), model.getModelString(), model.getName(), getAircraftDescription());
}
void CService::addTextMessage(const QString &text, double red, double green, double blue)
void CService::addTextMessage(const std::string &text, double red, double green, double blue)
{
if (text.isEmpty()) { return; }
int lineLength = m_messages.maxLineLength() - 1;
QStringList wrappedLines;
for (int i = 0; i < text.size(); i += lineLength)
if (text.empty()) { return; }
static const std::string ellipsis = "...";
int lineLength = m_messages.maxLineLength() - ellipsis.size();
std::vector<std::string> wrappedLines;
for (size_t i = 0; i < text.size(); i += lineLength)
{
static const QChar ellipsis = 0x2026;
wrappedLines.push_back(text.mid(i, lineLength) + ellipsis);
// static const QChar ellipsis = 0x2026;
// wrappedLines.push_back(QString::fromStdString(text).mid(i, lineLength) + ellipsis);
wrappedLines.push_back(text.substr(i, lineLength) + ellipsis);
}
wrappedLines.back().chop(1);
if (wrappedLines.back().isEmpty()) { wrappedLines.pop_back(); }
else if (wrappedLines.back().size() == 1 && wrappedLines.size() > 1)
wrappedLines.back().erase(wrappedLines.back().size() - 3);
if (wrappedLines.back().empty()) { wrappedLines.pop_back(); }
else if (wrappedLines.back().size() == ellipsis.size() && wrappedLines.size() > 1)
{
(wrappedLines.end() - 2)->chop(1);
(wrappedLines.end() - 2)->append(wrappedLines.back());
auto secondLastLine = wrappedLines.end() - 2;
secondLastLine->erase(wrappedLines.back().size() - 3);
secondLastLine->append(wrappedLines.back());
wrappedLines.pop_back();
}
for (const auto &line : wrappedLines)
{
m_messages.addMessage({ line.toStdString(), static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue) });
m_messages.addMessage({ line, static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue) });
}
}
QString CService::getAircraftModelPath() const
std::string CService::getAircraftModelPath() const
{
char filename[256];
char path[512];
@@ -72,7 +69,7 @@ namespace XSwiftBus
return path;
}
QString CService::getAircraftModelFilename() const
std::string CService::getAircraftModelFilename() const
{
char filename[256];
char path[512];
@@ -80,21 +77,21 @@ namespace XSwiftBus
return filename;
}
QString CService::getAircraftModelString() const
std::string CService::getAircraftModelString() const
{
char filename[256];
char path[512];
XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
const auto model = extractAcfProperties(path, QFileInfo(path));
const auto model = extractAcfProperties(path);
return model.getModelString();
}
QString CService::getAircraftName() const
std::string CService::getAircraftName() const
{
char filename[256];
char path[512];
XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path);
const auto model = extractAcfProperties(path, QFileInfo(path));
const auto model = extractAcfProperties(path);
return model.getName();
}
@@ -114,14 +111,14 @@ namespace XSwiftBus
return version % 100;
}
QString CService::getXPlaneInstallationPath() const
std::string CService::getXPlaneInstallationPath() const
{
char path[512];
XPLMGetSystemPath(path);
return path;
}
QString CService::getXPlanePreferencesPath() const
std::string CService::getXPlanePreferencesPath() const
{
char path[512];
XPLMGetPrefsPath(path);
@@ -206,7 +203,7 @@ namespace XSwiftBus
queueDBusCall([=]()
{
addTextMessage(QString::fromStdString(text), red, green, blue);
addTextMessage(text, red, green, blue);
});
}
else if (message.getMethodName() == "getOwnAircraftSituationData")
@@ -246,49 +243,49 @@ namespace XSwiftBus
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getAircraftModelPath().toStdString());
sendDBusReply(sender, serial, getAircraftModelPath());
});
}
else if (message.getMethodName() == "getAircraftModelFilename")
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getAircraftModelFilename().toStdString());
sendDBusReply(sender, serial, getAircraftModelFilename());
});
}
else if (message.getMethodName() == "getAircraftModelString")
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getAircraftModelString().toStdString());
sendDBusReply(sender, serial, getAircraftModelString());
});
}
else if (message.getMethodName() == "getAircraftName")
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getAircraftName().toStdString());
sendDBusReply(sender, serial, getAircraftName());
});
}
else if (message.getMethodName() == "getAircraftLivery")
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getAircraftLivery().toStdString());
sendDBusReply(sender, serial, getAircraftLivery());
});
}
else if (message.getMethodName() == "getAircraftIcaoCode")
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getAircraftIcaoCode().toStdString());
sendDBusReply(sender, serial, getAircraftIcaoCode());
});
}
else if (message.getMethodName() == "getAircraftDescription")
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getAircraftDescription().toStdString());
sendDBusReply(sender, serial, getAircraftDescription());
});
}
else if (message.getMethodName() == "getXPlaneVersionMajor")
@@ -309,14 +306,14 @@ namespace XSwiftBus
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getXPlaneInstallationPath().toStdString());
sendDBusReply(sender, serial, getXPlaneInstallationPath());
});
}
else if (message.getMethodName() == "getXPlanePreferencesPath")
{
queueDBusCall([=]()
{
sendDBusReply(sender, serial, getXPlanePreferencesPath().toStdString());
sendDBusReply(sender, serial, getXPlanePreferencesPath());
});
}
else if (message.getMethodName() == "isPaused")
@@ -599,7 +596,7 @@ namespace XSwiftBus
{
queueDBusCall([=]()
{
std::vector<double> array = getEngineN1Percentage().toVector().toStdVector();
std::vector<double> array = getEngineN1Percentage();
sendDBusReply(sender, serial, array);
});
}
@@ -633,19 +630,19 @@ namespace XSwiftBus
return 1;
}
void CService::emitAircraftModelChanged(const QString &path, const QString &filename, const QString &livery,
const QString &icao, const QString &modelString, const QString &name,
const QString &description)
void CService::emitAircraftModelChanged(const std::string &path, const std::string &filename, const std::string &livery,
const std::string &icao, const std::string &modelString, const std::string &name,
const std::string &description)
{
CDBusMessage signalAircraftModelChanged = CDBusMessage::createSignal(XSWIFTBUS_SERVICE_OBJECTPATH, XSWIFTBUS_SERVICE_INTERFACENAME, "aircraftModelChanged");
signalAircraftModelChanged.beginArgumentWrite();
signalAircraftModelChanged.appendArgument(path.toStdString());
signalAircraftModelChanged.appendArgument(filename.toStdString());
signalAircraftModelChanged.appendArgument(livery.toStdString());
signalAircraftModelChanged.appendArgument(icao.toStdString());
signalAircraftModelChanged.appendArgument(modelString.toStdString());
signalAircraftModelChanged.appendArgument(name.toStdString());
signalAircraftModelChanged.appendArgument(description.toStdString());
signalAircraftModelChanged.appendArgument(path);
signalAircraftModelChanged.appendArgument(filename);
signalAircraftModelChanged.appendArgument(livery);
signalAircraftModelChanged.appendArgument(icao);
signalAircraftModelChanged.appendArgument(modelString);
signalAircraftModelChanged.appendArgument(name);
signalAircraftModelChanged.appendArgument(description);
sendDBusMessage(signalAircraftModelChanged);
}
@@ -676,105 +673,115 @@ namespace XSwiftBus
return closestAirports;
}
QString descriptionForFlyableModel(const CAircraftModel &model)
//! Qt free version of BlackMisc::Simulation::XPlane::descriptionForFlyableModel()
std::string descriptionForFlyableModel(const CAircraftModel &model)
{
if (!model.getName().isEmpty())
if (!model.getName().empty())
{
if (model.getDistributor().hasDescription() && !model.getName().contains(model.getDistributor().getDescription()))
if (model.getDistributor().hasDescription() && model.getName().find(model.getDistributor().getDescription()) == std::string::npos)
{
return QStringLiteral("[ACF] ") % model.getName() % QStringLiteral(" by ") % model.getDistributor().getDescription();
return std::string("[ACF] ") + model.getName() + " by " + model.getDistributor().getDescription();
}
else
{
return QStringLiteral("[ACF] ") % model.getName();
return std::string("[ACF] ") + model.getName();
}
}
else if (model.hasAircraftDesignator())
{
if (model.getDistributor().hasDescription())
{
return QStringLiteral("[ACF] ") % model.getAircraftIcaoCodeDesignator() % QStringLiteral(" by ") % model.getDistributor().getDescription();
return std::string("[ACF] ") + model.getAircraftIcaoCodeDesignator() + " by " + model.getDistributor().getDescription();
}
else
{
return QStringLiteral("[ACF] ") % model.getAircraftIcaoCodeDesignator();
return std::string("[ACF] ") + model.getAircraftIcaoCodeDesignator();
}
}
return QStringLiteral("[ACF]");
return std::string("[ACF]");
}
QString stringForFlyableModel(const CAircraftModel &model, const QFileInfo &acfFile)
//! Qt free version of BlackMisc::Simulation::XPlane::stringForFlyableModel()
std::string stringForFlyableModel(const CAircraftModel &model, const std::string &acfFile)
{
if (model.getDistributor().hasDescription())
{
if (!model.getName().isEmpty())
if (!model.getName().empty())
{
if (model.getName().contains(model.getDistributor().getDescription()))
if (model.getName().find(model.getDistributor().getDescription()) != std::string::npos)
{
return model.getName();
}
else
{
return model.getDistributor().getDescription() % ' ' % model.getName();
return model.getDistributor().getDescription() + ' ' + model.getName();
}
}
else if (model.hasAircraftDesignator())
{
return model.getDistributor().getDescription() % ' ' % model.getAircraftIcaoCodeDesignator();
return model.getDistributor().getDescription() + ' ' + model.getAircraftIcaoCodeDesignator();
}
}
return acfFile.dir().dirName() % ' ' % acfFile.baseName();
return getDirName(acfFile) + ' ' + getBaseName(acfFile);
}
CAircraftModel CService::extractAcfProperties(const QString &filePath, const QFileInfo &fileInfo)
CAircraftModel CService::extractAcfProperties(const std::string &filePath)
{
CAircraftModel model;
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return model; }
QTextStream ts(&file);
if (ts.readLine() == "I" && ts.readLine().contains("version") && ts.readLine() == "ACF")
std::ifstream fs(filePath, std::ios::in | std::ios::binary);
if(!fs.is_open()) { return model; }
std::string i;
std::string version;
std::string acf;
std::getline(fs, i);
std::getline(fs, version);
std::getline(fs, acf);
if (i == "I" && version.find("version") != std::string::npos && acf == "ACF")
{
while (!ts.atEnd())
std::string line;
while (std::getline(fs, line))
{
const QString line = ts.readLine();
QVector<QStringRef> tokens = line.splitRef(' ', QString::SkipEmptyParts);
if (tokens.size() < 3 || tokens.at(0) != QLatin1String("P")) { continue; }
if (tokens.at(1) == QLatin1String("acf/_ICAO"))
auto tokens = split(line, 2);
if (tokens.size() < 3 || tokens.at(0) != "P") { continue; }
if (tokens.at(1) == "acf/_ICAO")
{
const QString icao(tokens.at(2).toString());
const std::string icao(tokens.at(2));
model.setAircraftIcaoCode(icao);
}
else if (tokens.at(1) == QLatin1String("acf/_descrip"))
else if (tokens.at(1) == "acf/_descrip")
{
const QString desc(line.mid(tokens.at(2).position()));
model.setDescription("[ACF] " % desc);
const std::string desc(tokens.at(2));
model.setDescription("[ACF] " + desc);
}
else if (tokens.at(1) == QLatin1String("acf/_name"))
else if (tokens.at(1) == "acf/_name")
{
const QString name(line.mid(tokens.at(2).position()));
const std::string name(tokens.at(2));
model.setName(name);
}
else if (tokens.at(1) == QLatin1String("acf/_studio"))
else if (tokens.at(1) == "acf/_studio")
{
const CDistributor dist(line.mid(tokens.at(2).position()));
const CDistributor dist(tokens.at(2));
model.setDistributor(dist);
}
else if (tokens.at(1) == QLatin1String("acf/_author"))
else if (tokens.at(1) == "acf/_author")
{
if (model.getDistributor().hasDescription()) { continue; }
thread_local const QRegularExpression end("\\W\\s", QRegularExpression::UseUnicodePropertiesOption);
QString author = line.mid(tokens.at(2).position());
author = author.left(author.indexOf(end)).trimmed();
if (author.isEmpty()) { continue; }
std::string author = tokens.at(2);
size_t pos = author.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_");
author = author.substr(0, pos);
if (author.empty()) { continue; }
const CDistributor dist(author);
model.setDistributor(dist);
}
}
}
file.close();
model.setModelString(stringForFlyableModel(model, fileInfo));
fs.close();
model.setModelString(stringForFlyableModel(model, filePath));
if (!model.hasDescription()) { model.setDescription(descriptionForFlyableModel(model)); }
return model;
}

View File

@@ -21,12 +21,7 @@
#include "messages.h"
#include "navdatareference.h"
#include <XPLM/XPLMNavigation.h>
#include <QStringList>
#include <QObject>
#include <QList>
#include <QFileInfo>
class QTimer;
#include <string>
//! \cond PRIVATE
#define XSWIFTBUS_SERVICE_INTERFACENAME "org.swift_project.xswiftbus.service"
@@ -40,15 +35,20 @@ namespace XSwiftBus
class CDistributor
{
public:
//! Default constructor
CDistributor() = default;
CDistributor(const QString &distributor) : m_distributor(distributor) {}
bool hasDescription() const { return !m_description.isEmpty(); }
QString getDescription() const { return m_description; }
//! Constructor
CDistributor(const std::string &description) : m_description(description) {}
//! \copydoc BlackMisc::Simulation::CDistributor::hasDescription
bool hasDescription() const { return !m_description.empty(); }
//! \copydoc BlackMisc::Simulation::CDistributor::getDescription
std::string getDescription() const { return m_description; }
private:
QString m_distributor;
QString m_description;
std::string m_description;
};
//! Simplified implementation of \sa BlackMisc::Simulation::CAircraftModel
@@ -58,44 +58,44 @@ namespace XSwiftBus
CAircraftModel() = default;
//! \copydoc BlackMisc::Simulation::CAircraftModel::hasDescription
bool hasDescription() const { return !m_description.isEmpty(); }
bool hasDescription() const { return !m_description.empty(); }
//! \copydoc BlackMisc::Simulation::CAircraftModel::hasAircraftDesignator
bool hasAircraftDesignator() const { return !m_icao.isEmpty(); }
bool hasAircraftDesignator() const { return !m_icao.empty(); }
//! \copydoc BlackMisc::Simulation::CAircraftModel::getName
QString getName() const { return m_name; }
std::string getName() const { return m_name; }
//! \copydoc BlackMisc::Simulation::CAircraftModel::getDistributor
CDistributor getDistributor() const { return m_distributor; }
//! \copydoc BlackMisc::Simulation::CAircraftModel::getAircraftIcaoCodeDesignator
QString getAircraftIcaoCodeDesignator() const { return m_icao; }
std::string getAircraftIcaoCodeDesignator() const { return m_icao; }
//! \copydoc BlackMisc::Simulation::CAircraftModel::getModelString
QString getModelString() const { return m_modelString; }
std::string getModelString() const { return m_modelString; }
//! \copydoc BlackMisc::Simulation::CAircraftModel::setAircraftIcaoCode
void setAircraftIcaoCode(const QString &icao) { m_icao = icao; }
void setAircraftIcaoCode(const std::string &icao) { m_icao = icao; }
//! \copydoc BlackMisc::Simulation::CAircraftModel::setDescription
void setDescription(const QString &description) { m_description = description; }
void setDescription(const std::string &description) { m_description = description; }
//! \copydoc BlackMisc::Simulation::CAircraftModel::setName
void setName(const QString &name) { m_name = name; }
void setName(const std::string &name) { m_name = name; }
//! \copydoc BlackMisc::Simulation::CAircraftModel::setDistributor
void setDistributor(const CDistributor &distributor) { m_distributor = distributor; }
//! \copydoc BlackMisc::Simulation::CAircraftModel::setModelString
void setModelString(const QString &modelString) { m_modelString = modelString; }
void setModelString(const std::string &modelString) { m_modelString = modelString; }
private:
QString m_name;
QString m_icao;
QString m_description;
std::string m_name;
std::string m_icao;
std::string m_description;
CDistributor m_distributor;
QString m_modelString;
std::string m_modelString;
};
/*!
@@ -111,16 +111,16 @@ namespace XSwiftBus
~CService() override = default;
//! DBus interface name
static const QString &InterfaceName()
static const std::string &InterfaceName()
{
static const QString s(XSWIFTBUS_SERVICE_INTERFACENAME);
static const std::string s(XSWIFTBUS_SERVICE_INTERFACENAME);
return s;
}
//! DBus object path
static const QString &ObjectPath()
static const std::string &ObjectPath()
{
static const QString s(XSWIFTBUS_SERVICE_OBJECTPATH);
static const std::string s(XSWIFTBUS_SERVICE_OBJECTPATH);
return s;
}
@@ -128,31 +128,31 @@ namespace XSwiftBus
void onAircraftModelChanged();
//! Add a text message to the on-screen display, with RGB components in the range [0,1]
void addTextMessage(const QString &text, double red, double green, double blue);
void addTextMessage(const std::string &text, double red, double green, double blue);
//! Called by newly connected client to cause airportsInRangeUpdated to be emitted.
void updateAirportsInRange();
//! Get full path to current aircraft model
QString getAircraftModelPath() const;
std::string getAircraftModelPath() const;
//! Get base filename of current aircraft model
QString getAircraftModelFilename() const;
std::string getAircraftModelFilename() const;
//! Get canonical swift model string of current aircraft model
QString getAircraftModelString() const;
std::string getAircraftModelString() const;
//! Get name of current aircraft model
QString getAircraftName() const;
std::string getAircraftName() const;
//! Get path to current aircraft livery
QString getAircraftLivery() const { return m_liveryPath.get().c_str(); }
std::string getAircraftLivery() const { return m_liveryPath.get(); }
//! Get the ICAO code of the current aircraft model
QString getAircraftIcaoCode() const { return m_icao.get().c_str(); }
std::string getAircraftIcaoCode() const { return m_icao.get(); }
//! Get the description of the current aircraft model
QString getAircraftDescription() const { return m_descrip.get().c_str(); }
std::string getAircraftDescription() const { return m_descrip.get(); }
//! Get major version number
int getXPlaneVersionMajor() const;
@@ -161,10 +161,10 @@ namespace XSwiftBus
int getXPlaneVersionMinor() const;
//! Get root of X-Plane install path
QString getXPlaneInstallationPath() const;
std::string getXPlaneInstallationPath() const;
//! Get full path to X-Plane preferences file
QString getXPlanePreferencesPath() const;
std::string getXPlanePreferencesPath() const;
//! True if sim is paused
bool isPaused() const { return m_paused.get(); }
@@ -275,14 +275,14 @@ namespace XSwiftBus
int getNumberOfEngines() const { return m_numberOfEngines.get(); }
//! Get the N1 speed as percent of max (per engine)
QList<double> getEngineN1Percentage() const
std::vector<double> getEngineN1Percentage() const
{
QList<double> list;
const int number = getNumberOfEngines();
std::vector<double> list;
const auto number = static_cast<unsigned int>(getNumberOfEngines());
list.reserve(number);
for (int engineNumber = 0; engineNumber < number; ++engineNumber)
for (unsigned int engineNumber = 0; engineNumber < number; ++engineNumber)
{
list.append(m_enginesN1Percentage.getAt(engineNumber));
list.push_back(m_enginesN1Percentage.getAt(engineNumber));
}
return list;
}
@@ -299,21 +299,20 @@ namespace XSwiftBus
DBusHandlerResult dbusMessageHandler(const CDBusMessage &message) override;
private:
void emitAircraftModelChanged(const QString &path, const QString &filename, const QString &livery,
const QString &icao, const QString &modelString, const QString &name,
const QString &description);
void emitAircraftModelChanged(const std::string &path, const std::string &filename, const std::string &livery,
const std::string &icao, const std::string &modelString, const std::string &name,
const std::string &description);
void emitAirportsInRangeUpdated(const std::vector<std::string> &icaoCodes, const std::vector<std::string> &names,
const std::vector<double> &lats, const std::vector<double> &lons, const std::vector<double> &alts);
CMessageBoxControl m_messages { 128, 128, 16 };
std::vector<CNavDataReference> m_airports;
QTimer *m_airportUpdater = nullptr;
void readAirportsDatabase();
std::vector<CNavDataReference> findClosestAirports(int number, double latitude, double longitude);
static CAircraftModel extractAcfProperties(const QString &filePath, const QFileInfo &fileInfo);
static CAircraftModel extractAcfProperties(const std::string &filePath);
StringDataRef<xplane::data::sim::aircraft::view::acf_livery_path> m_liveryPath;
StringDataRef<xplane::data::sim::aircraft::view::acf_ICAO> m_icao;

View File

@@ -18,18 +18,17 @@
#include "XPMPPlaneRenderer.h"
#include <XPLM/XPLMProcessing.h>
#include <XPLM/XPLMUtilities.h>
#include <QDateTime>
#include <QDebug>
#include <QStringList>
#include <cassert>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
// clazy:excludeall=reserve-candidates
namespace XSwiftBus
{
CTraffic::Plane::Plane(void *id_, QString callsign_, QString aircraftIcao_, QString airlineIcao_, QString livery_, QString modelName_)
CTraffic::Plane::Plane(void *id_, const std::string &callsign_, const std::string &aircraftIcao_, const std::string &airlineIcao_, const std::string &livery_, const std::string &modelName_)
: id(id_), callsign(callsign_), aircraftIcao(aircraftIcao_), airlineIcao(airlineIcao_), livery(livery_), modelName(modelName_)
{
std::memset(static_cast<void *>(&surfaces), 0, sizeof(surfaces));
@@ -38,8 +37,9 @@ namespace XSwiftBus
surfaces.size = sizeof(surfaces);
xpdr.size = sizeof(xpdr);
std::strncpy(label, qPrintable(callsign), sizeof(label));
surfaces.lights.timeOffset = static_cast<quint16>(qrand() % 0xffff);
std::strncpy(label, callsign.c_str(), sizeof(label));
std::srand(static_cast<unsigned int>(std::time(nullptr)));
surfaces.lights.timeOffset = static_cast<uint16_t>(std::rand() % 0xffff);
}
CTraffic::CTraffic(CDBusConnection *dbusConnection) :
@@ -60,8 +60,12 @@ namespace XSwiftBus
initXPlanePath();
auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep + "LegacyData" + g_sep;
auto err = XPMPMultiplayerInitLegacyData(qPrintable(dir + "CSL"), qPrintable(dir + "related.txt"),
qPrintable(dir + "lights.png"), qPrintable(dir + "Doc8643.txt"), "C172", preferences, preferences);
std::string csl = dir + "CSL";
std::string related = dir + "related.txt";
std::string doc8643 = dir + "Doc8643.txt";
std::string lights = dir + "lights.png";
auto err = XPMPMultiplayerInitLegacyData(csl.c_str(), related.c_str(), lights.c_str(), doc8643.c_str(),
"C172", preferences, preferences);
if (*err) { s_legacyDataOK = false; }
}
@@ -70,7 +74,7 @@ namespace XSwiftBus
if (! s_legacyDataOK) { return false; }
auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep;
auto err = XPMPMultiplayerInit(preferences, preferences, qPrintable(dir));
auto err = XPMPMultiplayerInit(preferences, preferences, dir.c_str());
if (*err) { cleanup(); return false; }
m_initialized = true;
@@ -104,11 +108,11 @@ namespace XSwiftBus
sendDBusSignal("simFrame");
}
void CTraffic::emitRemoteAircraftData(const QString &callsign, double latitude, double longitude, double elevation, double modelVerticalOffset)
void CTraffic::emitRemoteAircraftData(const std::string &callsign, double latitude, double longitude, double elevation, double modelVerticalOffset)
{
CDBusMessage signalRemoteAircraftData = CDBusMessage::createSignal(XSWIFTBUS_TRAFFIC_OBJECTPATH, XSWIFTBUS_TRAFFIC_INTERFACENAME, "remoteAircraftData");
signalRemoteAircraftData.beginArgumentWrite();
signalRemoteAircraftData.appendArgument(callsign.toStdString());
signalRemoteAircraftData.appendArgument(callsign);
signalRemoteAircraftData.appendArgument(latitude);
signalRemoteAircraftData.appendArgument(longitude);
signalRemoteAircraftData.appendArgument(elevation);
@@ -141,19 +145,21 @@ namespace XSwiftBus
return def;
}
bool CTraffic::loadPlanesPackage(const QString &path)
bool CTraffic::loadPlanesPackage(const std::string &path)
{
initXPlanePath();
auto dir = g_xplanePath + "Resources" + g_sep + "plugins" + g_sep + "xswiftbus" + g_sep + "LegacyData" + g_sep;
auto err = XPMPLoadCSLPackage(qPrintable(path), qPrintable(dir + "related.txt"), qPrintable(dir + "Doc8643.txt"));
std::string related = dir + "related.txt";
std::string doc8643 = dir + "Doc8643.txt";
auto err = XPMPLoadCSLPackage(path.c_str(), related.c_str(), doc8643.c_str());
if (*err) { return false; }
return true;
}
void CTraffic::setDefaultIcao(const QString &defaultIcao)
void CTraffic::setDefaultIcao(const std::string &defaultIcao)
{
XPMPSetDefaultPlaneICAO(qPrintable(defaultIcao));
XPMPSetDefaultPlaneICAO(defaultIcao.c_str());
}
void CTraffic::setDrawingLabels(bool drawing)
@@ -183,16 +189,16 @@ namespace XSwiftBus
g_drawDistance = static_cast<float>(nauticalMiles);
}
void CTraffic::addPlane(const QString &callsign, const QString &modelName, const QString &aircraftIcao, const QString &airlineIcao, const QString &livery)
void CTraffic::addPlane(const std::string &callsign, const std::string &modelName, const std::string &aircraftIcao, const std::string &airlineIcao, const std::string &livery)
{
XPMPPlaneID id = nullptr;
if (modelName.isEmpty())
if (modelName.empty())
{
id = XPMPCreatePlane(qPrintable(aircraftIcao), qPrintable(airlineIcao), qPrintable(livery), getPlaneData, static_cast<void *>(this));
id = XPMPCreatePlane(aircraftIcao.c_str(), airlineIcao.c_str(), livery.c_str(), getPlaneData, static_cast<void *>(this));
}
else
{
id = XPMPCreatePlaneWithModelName(qPrintable(modelName), qPrintable(aircraftIcao), qPrintable(airlineIcao), qPrintable(livery), getPlaneData, static_cast<void *>(this));
id = XPMPCreatePlaneWithModelName(modelName.c_str(), aircraftIcao.c_str(), airlineIcao.c_str(), livery.c_str(), getPlaneData, static_cast<void *>(this));
}
if (id)
@@ -203,21 +209,23 @@ namespace XSwiftBus
}
}
void CTraffic::removePlane(const QString &callsign)
void CTraffic::removePlane(const std::string &callsign)
{
Plane *plane = m_planesByCallsign.value(callsign, nullptr);
if (!plane) { return; }
m_planesByCallsign.remove(callsign);
m_planesById.remove(plane->id);
auto planeIt = m_planesByCallsign.find(callsign);
if (planeIt == m_planesByCallsign.end()) { return; }
Plane *plane = planeIt->second;
m_planesByCallsign.erase(callsign);
m_planesById.erase(plane->id);
XPMPDestroyPlane(plane->id);
delete plane;
}
void CTraffic::removeAllPlanes()
{
const QList<Plane *> planes = m_planesByCallsign.values();
for (Plane *plane : planes)
for (const auto &kv : m_planesByCallsign)
{
Plane *plane = kv.second;
assert(plane);
XPMPDestroyPlane(plane->id);
delete plane;
@@ -226,9 +234,12 @@ namespace XSwiftBus
m_planesById.clear();
}
void CTraffic::setPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading)
void CTraffic::setPlanePosition(const std::string &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading)
{
Plane *plane = m_planesByCallsign.value(callsign, nullptr);
auto planeIt = m_planesByCallsign.find(callsign);
if (planeIt == m_planesByCallsign.end()) { return; }
Plane *plane = planeIt->second;
if (!plane) { return; }
plane->position.lat = latitude;
plane->position.lon = longitude;
@@ -238,11 +249,14 @@ namespace XSwiftBus
plane->position.heading = static_cast<float>(heading);
}
void CTraffic::setPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
void CTraffic::setPlaneSurfaces(const std::string &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround)
{
Q_UNUSED(onGround);
Plane *plane = m_planesByCallsign.value(callsign, nullptr);
(void) onGround;
auto planeIt = m_planesByCallsign.find(callsign);
if (planeIt == m_planesByCallsign.end()) { return; }
Plane *plane = planeIt->second;
if (!plane) { return; }
plane->hasSurfaces = true;
@@ -263,9 +277,12 @@ namespace XSwiftBus
plane->surfaces.lights.flashPattern = lightPattern;
}
void CTraffic::setPlaneTransponder(const QString &callsign, int code, bool modeC, bool ident)
void CTraffic::setPlaneTransponder(const std::string &callsign, int code, bool modeC, bool ident)
{
Plane *plane = m_planesByCallsign.value(callsign, nullptr);
auto planeIt = m_planesByCallsign.find(callsign);
if (planeIt == m_planesByCallsign.end()) { return; }
Plane *plane = planeIt->second;
if (!plane) { return; }
plane->hasXpdr = true;
plane->xpdr.code = code;
@@ -277,9 +294,9 @@ namespace XSwiftBus
void CTraffic::requestRemoteAircraftData()
{
if (m_planesByCallsign.empty()) { return; }
const QList<Plane *> planes = m_planesByCallsign.values();
for (const Plane *plane : planes)
for (const auto &kv : m_planesByCallsign)
{
Plane *plane = kv.second;
assert(plane);
double lat = plane->position.lat;
double lon = plane->position.lon;
@@ -287,7 +304,7 @@ namespace XSwiftBus
double groundElevation = plane->terrainProbe.getElevation(lat, lon, elevation);
if (std::isnan(groundElevation)) { groundElevation = 0.0; }
double fudgeFactor = 3.0;
actualVertOffsetInfo(qPrintable(plane->modelName), nullptr, &fudgeFactor);
actualVertOffsetInfo(plane->modelName.c_str(), nullptr, &fudgeFactor);
emitRemoteAircraftData(plane->callsign, lat, lon, groundElevation, fudgeFactor);
}
}
@@ -332,7 +349,7 @@ namespace XSwiftBus
message.getArgument(path);
queueDBusCall([ = ]()
{
sendDBusReply(sender, serial, loadPlanesPackage(QString::fromStdString(path)));
sendDBusReply(sender, serial, loadPlanesPackage(path));
});
}
else if (message.getMethodName() == "setDefaultIcao")
@@ -342,7 +359,7 @@ namespace XSwiftBus
message.getArgument(defaultIcao);
queueDBusCall([ = ]()
{
setDefaultIcao(QString::fromStdString(defaultIcao));
setDefaultIcao(defaultIcao);
});
}
else if (message.getMethodName() == "setDrawingLabels")
@@ -404,7 +421,7 @@ namespace XSwiftBus
queueDBusCall([ = ]()
{
addPlane(QString::fromStdString(callsign), QString::fromStdString(modelName), QString::fromStdString(aircraftIcao), QString::fromStdString(airlineIcao), QString::fromStdString(livery));
addPlane(callsign, modelName, aircraftIcao, airlineIcao, livery);
});
}
else if (message.getMethodName() == "removePlane")
@@ -415,7 +432,7 @@ namespace XSwiftBus
message.getArgument(callsign);
queueDBusCall([ = ]()
{
removePlane(QString::fromStdString(callsign));
removePlane(callsign);
});
}
else if (message.getMethodName() == "removeAllPlanes")
@@ -446,7 +463,7 @@ namespace XSwiftBus
message.getArgument(heading);
queueDBusCall([ = ]()
{
setPlanePosition(QString::fromStdString(callsign), latitude, longitude, altitude, pitch, roll, heading);
setPlanePosition(callsign, latitude, longitude, altitude, pitch, roll, heading);
});
}
else if (message.getMethodName() == "setPlaneSurfaces")
@@ -489,7 +506,7 @@ namespace XSwiftBus
message.getArgument(onGround);
queueDBusCall([ = ]()
{
setPlaneSurfaces(QString::fromStdString(callsign), gear, flap, spoiler, speedBrake, slat, wingSweep, thrust, elevator,
setPlaneSurfaces(callsign, gear, flap, spoiler, speedBrake, slat, wingSweep, thrust, elevator,
rudder, aileron, landLight, beaconLight, strobeLight, navLight, lightPattern,
onGround);
});
@@ -508,7 +525,7 @@ namespace XSwiftBus
message.getArgument(ident);
queueDBusCall([ = ]()
{
setPlaneTransponder(QString::fromStdString(callsign), code, modeC, ident);
setPlaneTransponder(callsign, code, modeC, ident);
});
}
else if (message.getMethodName() == "requestRemoteAircraftData")
@@ -546,8 +563,9 @@ namespace XSwiftBus
int CTraffic::getPlaneData(void *id, int dataType, void *io_data)
{
QHash<void *, Plane *> planesById = m_planesById;
Plane *plane = m_planesById.value(id, nullptr);
auto planeIt = m_planesById.find(id);
assert(planeIt != m_planesById.end());
Plane *plane = planeIt->second;
if (!plane) { return xpmpData_Unavailable; }
switch (dataType)
@@ -568,18 +586,20 @@ namespace XSwiftBus
case xpmpDataType_Surfaces:
if (plane->hasSurfaces)
{
const auto currentTime = QDateTime::currentMSecsSinceEpoch();
const auto now = std::chrono::system_clock::now();
if (plane->surfaces.gearPosition != plane->targetGearPosition)
{
// interpolate gear position
constexpr float gearMoveTimeMs = 5000;
const auto gearPositionDiffRemaining = plane->targetGearPosition - plane->surfaces.gearPosition;
const auto gearPositionDiffThisFrame = (currentTime - plane->prevSurfacesLerpTime) / gearMoveTimeMs;
auto diffMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - plane->prevSurfacesLerpTime);
const auto gearPositionDiffThisFrame = (diffMs.count()) / gearMoveTimeMs;
plane->surfaces.gearPosition += std::copysign(gearPositionDiffThisFrame, gearPositionDiffRemaining);
plane->surfaces.gearPosition = qBound(0.0f, plane->surfaces.gearPosition, 1.0f);
plane->surfaces.gearPosition = std::max(0.0f, std::min(plane->surfaces.gearPosition, 1.0f));
}
plane->prevSurfacesLerpTime = currentTime;
plane->prevSurfacesLerpTime = now;
const auto io_surfaces = static_cast<XPMPPlaneSurfaces_t *>(io_data);
if (memcmpPayload(io_surfaces, &plane->surfaces))

View File

@@ -15,11 +15,6 @@
#include "dbusobject.h"
#include "datarefs.h"
#include "terrainprobe.h"
#include <QDateTime>
#include <QObject>
#include <QHash>
#include <QVector>
#include <QStringList>
#include "XPMPMultiplayer.h"
#include <XPLM/XPLMDisplay.h>
#include <functional>
@@ -42,19 +37,19 @@ namespace XSwiftBus
CTraffic(CDBusConnection *dbusConnection);
//! Destructor
virtual ~CTraffic();
~CTraffic() override;
//! DBus interface name
static const QString &InterfaceName()
static const std::string &InterfaceName()
{
static QString s(XSWIFTBUS_TRAFFIC_INTERFACENAME);
static std::string s(XSWIFTBUS_TRAFFIC_INTERFACENAME);
return s;
}
//! DBus object path
static const QString &ObjectPath()
static const std::string &ObjectPath()
{
static QString s(XSWIFTBUS_TRAFFIC_OBJECTPATH);
static std::string s(XSWIFTBUS_TRAFFIC_OBJECTPATH);
return s;
}
@@ -68,10 +63,10 @@ namespace XSwiftBus
void cleanup();
//! Load a collection of planes from the given directory and return true if successful
bool loadPlanesPackage(const QString &path);
bool loadPlanesPackage(const std::string &path);
//! Set the ICAO code to use for aircraft without a model match
void setDefaultIcao(const QString &defaultIcao);
void setDefaultIcao(const std::string &defaultIcao);
//! Set whether the plugin draws type and callsign labels above aircraft
void setDrawingLabels(bool drawing);
@@ -86,23 +81,23 @@ namespace XSwiftBus
void setMaxDrawDistance(double nauticalMiles);
//! Introduce a new traffic aircraft
void addPlane(const QString &callsign, const QString &modelName, const QString &aircraftIcao, const QString &airlineIcao, const QString &livery);
void addPlane(const std::string &callsign, const std::string &modelName, const std::string &aircraftIcao, const std::string &airlineIcao, const std::string &livery);
//! Remove a traffic aircraft
void removePlane(const QString &callsign);
void removePlane(const std::string &callsign);
//! Remove all traffic aircraft
void removeAllPlanes();
//! Set the position of a traffic aircraft
void setPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading);
void setPlanePosition(const std::string &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading);
//! Set the flight control surfaces and lights of a traffic aircraft
void setPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
void setPlaneSurfaces(const std::string &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround);
//! Set the transponder of a traffic aircraft
void setPlaneTransponder(const QString &callsign, int code, bool modeC, bool ident);
void setPlaneTransponder(const std::string &callsign, int code, bool modeC, bool ident);
//! Request traffic plane data. A signal remoteAircraftData will be emitted for each known plane
void requestRemoteAircraftData();
@@ -117,7 +112,7 @@ namespace XSwiftBus
bool m_enabled = false;
void emitSimFrame();
void emitRemoteAircraftData(const QString &callsign, double latitude, double longitude, double elevation, double modelVerticalOffset);
void emitRemoteAircraftData(const std::string &callsign, double latitude, double longitude, double elevation, double modelVerticalOffset);
static int preferences(const char *section, const char *name, int def);
static float preferences(const char *section, const char *name, float def);
@@ -125,26 +120,27 @@ namespace XSwiftBus
struct Plane
{
void *id = nullptr;
QString callsign;
QString aircraftIcao;
QString airlineIcao;
QString livery;
QString modelName;
std::string callsign;
std::string aircraftIcao;
std::string airlineIcao;
std::string livery;
std::string modelName;
bool hasSurfaces = false;
bool hasXpdr = false;
char label[32] {};
CTerrainProbe terrainProbe;
XPMPPlaneSurfaces_t surfaces;
float targetGearPosition = 0;
qint64 prevSurfacesLerpTime = 0;
std::chrono::system_clock::time_point prevSurfacesLerpTime;
XPMPPlaneRadar_t xpdr;
XPMPPlanePosition_t position;
Plane(void *id_, QString callsign_, QString aircraftIcao_, QString airlineIcao_, QString livery_, QString modelName_);
Plane(void *id_, const std::string &callsign_, const std::string &aircraftIcao_, const std::string &airlineIcao_,
const std::string &livery_, const std::string &modelName_);
};
QHash<QString, Plane *> m_planesByCallsign;
QHash<void *, Plane *> m_planesById;
qint64 m_timestampLastSimFrame = QDateTime::currentMSecsSinceEpoch();
std::unordered_map<std::string, Plane *> m_planesByCallsign;
std::unordered_map<void *, Plane *> m_planesById;
std::chrono::system_clock::time_point m_timestampLastSimFrame = std::chrono::system_clock::now();
int getPlaneData(void *id, int dataType, void *io_data);
static int getPlaneData(void *id, int dataType, void *io_data, void *self)

View File

@@ -15,19 +15,19 @@
#include "utils.h"
#include <XPMPMultiplayerCSL.h>
#include <QString>
#include <QtGlobal>
#include <string>
#include <sstream>
namespace XSwiftBus
{
QString g_xplanePath;
QString g_sep;
std::string g_xplanePath;
std::string g_sep;
//! Init global xplane path
void initXPlanePath()
{
if (!g_xplanePath.isEmpty() && !g_sep.isEmpty()) {}
if (!g_xplanePath.empty() && !g_sep.empty()) {}
char xplanePath[512];
XPLMGetSystemPath(xplanePath);
@@ -43,6 +43,116 @@ namespace XSwiftBus
g_xplanePath = xplanePath;
}
std::string getDirName(const string &filePath)
{
std::string seperator = "/\\";
std::size_t sepPos = filePath.find_last_of(seperator);
if(sepPos != std::string::npos)
{
return filePath.substr(0, sepPos);
}
else
{
return {};
}
}
std::string getFileName(const std::string &filePath)
{
std::string seperator = "/\\";
std::size_t sepPos = filePath.find_last_of(seperator);
if(sepPos != std::string::npos)
{
return filePath.substr(sepPos + 1, filePath.size() - 1);
}
else
{
return filePath;
}
}
std::string getBaseName(const std::string &filePath)
{
std::string seperator = ".";
std::string fileName = getFileName(filePath);
std::size_t sepPos = fileName.find(seperator);
if(sepPos != std::string::npos)
{
return fileName.substr(0, sepPos);
}
else
{
return fileName;
}
}
std::vector<std::string> split(const std::string &str, size_t maxSplitCount)
{
std::string s(str);
std::string delimiter = " ";
size_t pos = 0;
std::vector<std::string> tokens;
while ((pos = s.find(delimiter)) != std::string::npos)
{
tokens.push_back(s.substr(0, pos));
s.erase(0, pos + delimiter.length());
if (tokens.size() == maxSplitCount) { break; }
}
tokens.push_back(s);
return tokens;
}
void Logger::print(const std::string &filePath, int line, MsgType type, const std::string &message)
{
(void) line;
(void) type;
assert(!filePath.empty());
std::ostringstream ss;
ss << "xswiftbus";
ss << ' ';
#if defined(XSWIFTBUS_ENABLE_TRACE_LOG)
switch (type)
{
case DebugMsg:
ss << "Debug";
break;
case InfoMsg:
ss << "Info";
break;
case WarningMsg:
ss << "Warning";
break;
case FatalMsg:
ss << "Fatal";
}
ss << ' ';
std::string seperator = "/\\";
std::size_t sepPos = filePath.find_last_of(seperator);
if(sepPos != std::string::npos)
{
ss << filePath.substr(sepPos + 1, filePath.size() - 1);
}
else
{
ss << filePath;
}
ss << ' ';
ss << line;
ss << " : ";
#endif
ss << message;
ss << "\n";
std::string buffer = ss.str();
XPLMDebugString(buffer.c_str());
}
}
//! \endcond

View File

@@ -14,12 +14,12 @@
#include <XPLM/XPLMPlugin.h>
#include <XPLM/XPLMProcessing.h>
#include <XPLM/XPLMUtilities.h>
#include <QCoreApplication>
#include <QSharedPointer>
#include <vector>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <clocale>
#include <string>
/*!
* \file
@@ -28,58 +28,58 @@
/*!
* Install a Qt message handler which outputs to the X-Plane debug log.
*/
class QXPlaneMessageHandler
{
static void handler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QByteArray localMsg = msg.toLocal8Bit();
QByteArray file(context.file);
if (file.isEmpty()) file = "<unknown>";
//class QXPlaneMessageHandler
//{
// static void handler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
// {
// QByteArray localMsg = msg.toLocal8Bit();
// QByteArray file(context.file);
// if (file.isEmpty()) file = "<unknown>";
int line = context.line;
// int line = context.line;
char *buffer = new char[64 + localMsg.size() + file.size()];
switch (type) {
case QtDebugMsg:
std::sprintf(buffer, "%s:%d: Debug: %s\n", file.constData(), line, localMsg.constData());
XPLMDebugString(buffer);
break;
case QtInfoMsg:
std::sprintf(buffer, "%s:%d: Info: %s\n", file.constData(), line, localMsg.constData());
XPLMDebugString(buffer);
break;
case QtWarningMsg:
std::sprintf(buffer, "%s:%d: Warning: %s\n", file.constData(), line, localMsg.constData());
XPLMDebugString(buffer);
break;
default:
case QtCriticalMsg:
std::sprintf(buffer, "%s:%d: Error: %s\n", file.constData(), line, localMsg.constData());
XPLMDebugString(buffer);
break;
case QtFatalMsg:
std::sprintf(buffer, "%s:%d: Fatal: %s\n", file.constData(), line, localMsg.constData());
XPLMDebugString(buffer);
std::abort();
}
delete[] buffer;
}
// char *buffer = new char[64 + localMsg.size() + file.size()];
// switch (type) {
// case QtDebugMsg:
// std::sprintf(buffer, "%s:%d: Debug: %s\n", file.constData(), line, localMsg.constData());
// XPLMDebugString(buffer);
// break;
// case QtInfoMsg:
// std::sprintf(buffer, "%s:%d: Info: %s\n", file.constData(), line, localMsg.constData());
// XPLMDebugString(buffer);
// break;
// case QtWarningMsg:
// std::sprintf(buffer, "%s:%d: Warning: %s\n", file.constData(), line, localMsg.constData());
// XPLMDebugString(buffer);
// break;
// default:
// case QtCriticalMsg:
// std::sprintf(buffer, "%s:%d: Error: %s\n", file.constData(), line, localMsg.constData());
// XPLMDebugString(buffer);
// break;
// case QtFatalMsg:
// std::sprintf(buffer, "%s:%d: Fatal: %s\n", file.constData(), line, localMsg.constData());
// XPLMDebugString(buffer);
// std::abort();
// }
// delete[] buffer;
// }
public:
/*!
* Install the handler.
*/
static void install()
{
qInstallMessageHandler(handler);
}
//public:
// /*!
// * Install the handler.
// */
// static void install()
// {
// qInstallMessageHandler(handler);
// }
//! Not copyable.
//! @{
QXPlaneMessageHandler(const QXPlaneMessageHandler &) = delete;
QXPlaneMessageHandler &operator =(const QXPlaneMessageHandler &) = delete;
//! @}
};
// //! Not copyable.
// //! @{
// QXPlaneMessageHandler(const QXPlaneMessageHandler &) = delete;
// QXPlaneMessageHandler &operator =(const QXPlaneMessageHandler &) = delete;
// //! @}
//};
/*!
* QApplication subclass used by XSwiftBus.
@@ -89,101 +89,134 @@ public:
* Qt framework, they can simply copy & paste this class into their project
* and both X-Plane plugins will be able to share a single QApplication safely.
*/
class QSharedApplication : public QCoreApplication
{
Q_OBJECT
//class QSharedApplication : public QCoreApplication
//{
// Q_OBJECT
QWeakPointer<QCoreApplication> m_weakptr;
// QWeakPointer<QCoreApplication> m_weakptr;
QSharedApplication(QSharedPointer<QCoreApplication> &ptr, int &argc, char **argv) : QCoreApplication(argc, argv)
{
ptr.reset(this);
m_weakptr = ptr;
}
// QSharedApplication(QSharedPointer<QCoreApplication> &ptr, int &argc, char **argv) : QCoreApplication(argc, argv)
// {
// ptr.reset(this);
// m_weakptr = ptr;
// }
static char *strdup(const char *s) { auto s2 = static_cast<char *>(std::malloc(std::strlen(s) + 1)); return std::strcpy(s2, s); }
// static char *strdup(const char *s) { auto s2 = static_cast<char *>(std::malloc(std::strlen(s) + 1)); return std::strcpy(s2, s); }
public:
/*!
* Returns a shared pointer to the QApplication.
*
* The QApplication will not be destroyed while this shared pointer exists.
*/
static QSharedPointer<QCoreApplication> sharedInstance()
{
QSharedPointer<QCoreApplication> ptr;
if (! instance())
{
static int argc = 1;
static char *argv[] = { strdup("X-Plane") };
//public:
// /*!
// * Returns a shared pointer to the QApplication.
// *
// * The QApplication will not be destroyed while this shared pointer exists.
// */
// static QSharedPointer<QCoreApplication> sharedInstance()
// {
// QSharedPointer<QCoreApplication> ptr;
// if (! instance())
// {
// static int argc = 1;
// static char *argv[] = { strdup("X-Plane") };
#ifdef Q_OS_UNIX
/* Workaround for #362 */
char* xplocale = setlocale(LC_ALL, nullptr);
#endif
//#ifdef Q_OS_UNIX
// /* Workaround for #362 */
// char* xplocale = setlocale(LC_ALL, nullptr);
//#endif
new QSharedApplication(ptr, argc, argv);
// new QSharedApplication(ptr, argc, argv);
#ifdef Q_OS_UNIX
setlocale(LC_ALL, xplocale);
#endif
}
if (! instance()->inherits("QSharedApplication"))
{
qFatal("There is an unshared QCoreApplication in another plugin");
}
return static_cast<QSharedApplication*>(instance())->m_weakptr;
}
};
//#ifdef Q_OS_UNIX
// setlocale(LC_ALL, xplocale);
//#endif
// }
// if (! instance()->inherits("QSharedApplication"))
// {
// qFatal("There is an unshared QCoreApplication in another plugin");
// }
// return static_cast<QSharedApplication*>(instance())->m_weakptr;
// }
//};
/*!
* Runs the Qt event loop inside the X-Plane event loop.
*/
class QXPlaneEventLoop : public QObject
{
Q_OBJECT
///*!
// * Runs the Qt event loop inside the X-Plane event loop.
// */
//class QXPlaneEventLoop : public QObject
//{
// Q_OBJECT
QXPlaneEventLoop(QObject *parent) : QObject(parent)
{
XPLMRegisterFlightLoopCallback(callback, -1, nullptr);
}
// QXPlaneEventLoop(QObject *parent) : QObject(parent)
// {
// XPLMRegisterFlightLoopCallback(callback, -1, nullptr);
// }
~QXPlaneEventLoop()
{
XPLMUnregisterFlightLoopCallback(callback, nullptr);
}
// ~QXPlaneEventLoop()
// {
// XPLMUnregisterFlightLoopCallback(callback, nullptr);
// }
static float callback(float, float, int, void *)
{
QCoreApplication::processEvents();
QCoreApplication::sendPostedEvents();
return -1;
}
// static float callback(float, float, int, void *)
// {
// QCoreApplication::processEvents();
// QCoreApplication::sendPostedEvents();
// return -1;
// }
public:
/*!
* Registers the X-Plane callback which calls into the Qt event loop,
* unless one was already registered.
*/
static void exec()
{
if (! QCoreApplication::instance()->findChild<QXPlaneEventLoop *>())
{
new QXPlaneEventLoop(QCoreApplication::instance());
}
}
};
//public:
// /*!
// * Registers the X-Plane callback which calls into the Qt event loop,
// * unless one was already registered.
// */
// static void exec()
// {
// if (! QCoreApplication::instance()->findChild<QXPlaneEventLoop *>())
// {
// new QXPlaneEventLoop(QCoreApplication::instance());
// }
// }
//};
namespace XSwiftBus
{
//! Absolute xplane path
extern QString g_xplanePath;
extern std::string g_xplanePath;
//! Platform specific dir separator
extern QString g_sep;
extern std::string g_sep;
//! Init global xplane path
void initXPlanePath();
//! Returns the directory name of a given file path
std::string getDirName(const std::string &filePath);
//! Returns the filename (including extension) of a given file path
std::string getFileName(const std::string &filePath);
//! Returns the filename without extension of a given file path
std::string getBaseName(const std::string &filePath);
//! Splits the given string maximal maxSplitCount times and returns the tokens
//! The size of the returned vector is up to maxSplitCount + 1 or less
std::vector<std::string> split(const std::string &str, size_t maxSplitCount = 0);
//! Simple logger class.
//! Don't use it directly, but the _LOG macros instead
class Logger
{
public:
//! Message type
enum MsgType { DebugMsg, WarningMsg, FatalMsg, InfoMsg };
Logger() = delete;
//! Print message to X-Plane log
static void print(const std::string &filePath, int line, MsgType type, const std::string &message);
};
//! Logger convenience macros
//! @{
#define DEBUG_LOG(msg) Logger::print(__FILE__, __LINE__, Logger::DebugMsg, msg)
#define INFO_LOG(msg) Logger::print(__FILE__, __LINE__, Logger::InfoMsg, msg)
//! @}
}
#endif // guard

View File

@@ -10,7 +10,7 @@
//! \cond PRIVATE
#include "weather.h"
#include <QDebug>
#include "utils.h"
namespace XSwiftBus
{
@@ -37,7 +37,7 @@ namespace XSwiftBus
case 0: setCloudLayerImpl(m_cloudLayer0, base, tops, type, coverage); break;
case 1: setCloudLayerImpl(m_cloudLayer1, base, tops, type, coverage); break;
case 2: setCloudLayerImpl(m_cloudLayer2, base, tops, type, coverage); break;
default: qDebug() << "Invalid cloud layer" << layer; break;
default: DEBUG_LOG("Invalid cloud layer"); break;
}
}
@@ -60,7 +60,7 @@ namespace XSwiftBus
case 0: setWindLayerImpl(m_windLayer0, altitude, direction, speed, shearDirection, shearSpeed, turbulence); break;
case 1: setWindLayerImpl(m_windLayer1, altitude, direction, speed, shearDirection, shearSpeed, turbulence); break;
case 2: setWindLayerImpl(m_windLayer2, altitude, direction, speed, shearDirection, shearSpeed, turbulence); break;
default: qDebug() << "Invalid wind layer" << layer; break;
default: DEBUG_LOG("Invalid wind layer"); break;
}
}

View File

@@ -1,10 +1,9 @@
load(common_pre)
QT += core gui widgets dbus network
TEMPLATE = lib
CONFIG += shared plugin
CONFIG -= qt
INCLUDEPATH += $$EXTERNALSROOT/common/include/XPLM
@@ -107,7 +106,6 @@ INSTALLS += target
dep_target.path = $$PREFIX/$$XSWIFTBUS_DIR
win32 {
dep_target.files *= $$DestRoot/lib/blackmisc.dll
dep_target.files *= $$DestRoot/bin/dbus-daemon.exe
win32-g++ {
dep_target.files *= $$DestRoot/bin/libdbus-1-3.dll
@@ -118,12 +116,6 @@ win32 {
dep_target.files *= $$DestRoot/bin/expat.dll
dep_target.files *= $$DestRoot/bin/libevent_core.dll
}
dep_target.files *= $$[QT_INSTALL_BINS]/Qt5Core$${DLL_DEBUG_SUFFIX}.dll
dep_target.files *= $$[QT_INSTALL_BINS]/Qt5Gui$${DLL_DEBUG_SUFFIX}.dll
dep_target.files *= $$[QT_INSTALL_BINS]/Qt5Widgets$${DLL_DEBUG_SUFFIX}.dll
dep_target.files *= $$[QT_INSTALL_BINS]/Qt5DBus$${DLL_DEBUG_SUFFIX}.dll
dep_target.files *= $$[QT_INSTALL_BINS]/Qt5Network$${DLL_DEBUG_SUFFIX}.dll
dep_target.files *= $$[QT_INSTALL_BINS]/Qt5Xml$${DLL_DEBUG_SUFFIX}.dll
dep_target.CONFIG += no_check_exist
dbus_share.path = $$PREFIX/$$XSWIFTBUS_DIR/share/dbus-1
@@ -135,24 +127,8 @@ win32 {
legacy_data_target.files *= LegacyData
} else:macx: {
dep_target.files *= $$DestRoot/lib/libdbus-1.3.dylib
dep_target.files *= $$DestRoot/lib/libevent_core.2.1.8.dylib
dep_target.extra += rsync -avzl --exclude \'Headers*\' --exclude \'*debug*\' $$[QT_INSTALL_LIBS]/QtCore.framework/ $${PREFIX}/$$XSWIFTBUS_DIR/QtCore.framework/ &&
dep_target.extra += rsync -avzl --exclude \'Headers*\' --exclude \'*debug*\' $$[QT_INSTALL_LIBS]/QtGui.framework/ $${PREFIX}/$$XSWIFTBUS_DIR/QtGui.framework/ &&
dep_target.extra += rsync -avzl --exclude \'Headers*\' --exclude \'*debug*\' $$[QT_INSTALL_LIBS]/QtWidgets.framework/ $${PREFIX}/$$XSWIFTBUS_DIR/QtWidgets.framework/ &&
dep_target.extra += rsync -avzl --exclude \'Headers*\' --exclude \'*debug*\' $$[QT_INSTALL_LIBS]/QtDBus.framework/ $${PREFIX}/$$XSWIFTBUS_DIR/QtDBus.framework/ &&
dep_target.extra += rsync -avzl --exclude \'Headers*\' --exclude \'*debug*\' $$[QT_INSTALL_LIBS]/QtNetwork.framework/ $${PREFIX}/$$XSWIFTBUS_DIR/QtNetwork.framework/ &&
dep_target.extra += rsync -avzl --exclude \'Headers*\' --exclude \'*debug*\' $$[QT_INSTALL_LIBS]/QtXml.framework/ $${PREFIX}/$$XSWIFTBUS_DIR/QtXml.framework/
dep_target.CONFIG += no_check_exist
# Manually copy to workaround shortcomings introduced
# when qmake migrated away from GNU install in Qt 5.9
dep_target.depends += copy_blackmisc
copy_blackmisc.target = copy_blackmisc
source_path = $$PREFIX/lib/libblackmisc.0.dylib
dest_path = $$PREFIX/$$XSWIFTBUS_DIR
copy_blackmisc.commands = cp $$shell_path($$source_path) $$shell_path($$dest_path)
QMAKE_EXTRA_TARGETS += copy_blackmisc
legacy_data_target.path = $$PREFIX/xswiftbus
legacy_data_target.files *= LegacyData
@@ -160,48 +136,13 @@ win32 {
# We cannot modify the original library since this is xswiftbus specific.
legacy_data_target.depends += fix_plugin_rpath
fix_plugin_rpath.target = fix_plugin_rpath
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/libblackmisc.0.dylib\" \"@loader_path/libblackmisc.0.dylib\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/mac.xpl) &&
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/QtWidgets.framework/Versions/5/QtWidgets\" \"@loader_path/QtWidgets.framework/Versions/5/QtWidgets\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/mac.xpl) &&
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/QtGui.framework/Versions/5/QtGui\" \"@loader_path/QtGui.framework/Versions/5/QtGui\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/mac.xpl) &&
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/QtDBus.framework/Versions/5/QtDBus\" \"@loader_path/QtDBus.framework/Versions/5/QtDBus\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/mac.xpl) &&
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/QtNetwork.framework/Versions/5/QtNetwork\" \"@loader_path/QtNetwork.framework/Versions/5/QtNetwork\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/mac.xpl) &&
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/QtCore.framework/Versions/5/QtCore\" \"@loader_path/QtCore.framework/Versions/5/QtCore\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/mac.xpl) &&
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/QtXml.framework/Versions/5/QtXml\" \"@loader_path/QtXml.framework/Versions/5/QtXml\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/libblackmisc.0.dylib) &&
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/libevent_core.2.1.8.dylib\" \"@loader_path/libevent_core.2.1.8.dylib\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/mac.xpl) &&
fix_plugin_rpath.commands += install_name_tool -change \"@rpath/libdbus-1.3.dylib\" \"@loader_path/libdbus-1.3.dylib\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/mac.xpl)
QMAKE_EXTRA_TARGETS += fix_plugin_rpath
fix_plugin_rpath.depends += fix_misc_rpath
fix_misc_rpath.target = fix_misc_rpath
fix_misc_rpath.commands += install_name_tool -id \"@loader_path/libblackmisc.0.dylib\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/libblackmisc.0.dylib) &&
fix_misc_rpath.commands += install_name_tool -change \"@rpath/QtGui.framework/Versions/5/QtGui\" \"@loader_path/QtGui.framework/Versions/5/QtGui\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/libblackmisc.0.dylib) &&
fix_misc_rpath.commands += install_name_tool -change \"@rpath/QtDBus.framework/Versions/5/QtDBus\" \"@loader_path/QtDBus.framework/Versions/5/QtDBus\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/libblackmisc.0.dylib) &&
fix_misc_rpath.commands += install_name_tool -change \"@rpath/QtNetwork.framework/Versions/5/QtNetwork\" \"@loader_path/QtNetwork.framework/Versions/5/QtNetwork\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/libblackmisc.0.dylib) &&
fix_misc_rpath.commands += install_name_tool -change \"@rpath/QtCore.framework/Versions/5/QtCore\" \"@loader_path/QtCore.framework/Versions/5/QtCore\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/libblackmisc.0.dylib) &&
fix_misc_rpath.commands += install_name_tool -change \"@rpath/QtXml.framework/Versions/5/QtXml\" \"@loader_path/QtXml.framework/Versions/5/QtXml\" $$shell_path($$PREFIX/$$XSWIFTBUS_DIR/libblackmisc.0.dylib)
QMAKE_EXTRA_TARGETS += fix_misc_rpath
} else:unix: {
dep_target.files *= $$[QT_INSTALL_LIBS]/libQt5Core.so.5
dep_target.files *= $$[QT_INSTALL_LIBS]/libQt5Gui.so.5
dep_target.files *= $$[QT_INSTALL_LIBS]/libQt5Widgets.so.5
dep_target.files *= $$[QT_INSTALL_LIBS]/libQt5DBus.so.5
dep_target.files *= $$[QT_INSTALL_LIBS]/libQt5Network.so.5
dep_target.files *= $$[QT_INSTALL_LIBS]/libQt5Xml.so.5
dep_target.files *= $$[QT_INSTALL_LIBS]/libicui18n.so.56
dep_target.files *= $$[QT_INSTALL_LIBS]/libicuuc.so.56
dep_target.files *= $$[QT_INSTALL_LIBS]/libicudata.so.56
dep_target.CONFIG += no_check_exist
# Manually copy to workaround shortcomings introduced
# when qmake migrated away from GNU install in Qt 5.9
dep_target.depends += copy_blackmisc
copy_blackmisc.target = copy_blackmisc
source_path = $$PREFIX/lib/libblackmisc.so.0
dest_path = $$PREFIX/$$XSWIFTBUS_DIR
copy_blackmisc.commands = cp $$shell_path($$source_path) $$shell_path($$dest_path)
QMAKE_EXTRA_TARGETS += copy_blackmisc
legacy_data_target.path = $$PREFIX/xswiftbus
legacy_data_target.files *= LegacyData
}