diff --git a/src/blackcore/blackcore.contextnetwork.xml b/src/blackcore/blackcore.contextnetwork.xml
new file mode 100644
index 000000000..9da320a3f
--- /dev/null
+++ b/src/blackcore/blackcore.contextnetwork.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/blackcore/blackcore.contextsettings.xml b/src/blackcore/blackcore.contextsettings.xml
new file mode 100644
index 000000000..38717488e
--- /dev/null
+++ b/src/blackcore/blackcore.contextsettings.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/blackcore/blackcore.pro b/src/blackcore/blackcore.pro
index 6839867b6..ed1f9d7ec 100644
--- a/src/blackcore/blackcore.pro
+++ b/src/blackcore/blackcore.pro
@@ -1,7 +1,7 @@
include (../../externals.pri)
# GUI is required for the matrix classes
-QT += network dbus
+QT += network dbus xml
TARGET = blackcore
TEMPLATE = lib
@@ -17,9 +17,24 @@ precompile_header:!isEmpty(PRECOMPILED_HEADER) {
DEFINES += USING_PCH
}
+# Causes nmake to run qdbusxml2cpp to automatically generate the dbus adaptor and interface classes,
+# then automatically adds them to the sources to compile
+# !! Make sure the plugin is available as release build and known QT_PLUGIN_PATH
+# QDBUSXML2CPP_INTERFACE_HEADER_FLAGS = -i blackmisc/blackmiscfreefunctions.h -i blackmisc/blackmiscallvalueclasses.h
+QDBUSXML2CPP_ADAPTOR_HEADER_FLAGS = -i blackmisc/blackmiscfreefunctions.h -i blackmisc/blackmiscallvalueclasses.h
+DBUS_ADAPTORS += blackcore.contextnetwork.xml
+DBUS_ADAPTORS += blackcore.contextsettings.xml
+
+# DBUS_INTERFACES += blackcore.contextnetwork.xml
+
DEFINES += LOG_IN_FILE
HEADERS += *.h
SOURCES += *.cpp
+win32:!win32-g++*: PRE_TARGETDEPS += ../../lib/blackmisc.lib
+else: PRE_TARGETDEPS += ../../lib/libblackmisc.a
+
DESTDIR = ../../lib
+
+OTHER_FILES += readme.txt blackcore.contextnetwork.xml blackcore.contextsettings.xml
diff --git a/src/blackcore/context_network.cpp b/src/blackcore/context_network.cpp
new file mode 100644
index 000000000..e00efd185
--- /dev/null
+++ b/src/blackcore/context_network.cpp
@@ -0,0 +1,398 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "context_network.h"
+#include "coreruntime.h"
+#include "blackmisc/avatcstationlist.h"
+#include
+
+using namespace BlackMisc;
+using namespace BlackMisc::PhysicalQuantities;
+using namespace BlackMisc::Aviation;
+using namespace BlackMisc::Network;
+using namespace BlackMisc::Geo;
+
+namespace BlackCore
+{
+
+ /*
+ * Init this context
+ */
+ CContextNetwork::CContextNetwork(CCoreRuntime *parent) :
+ IContextNetwork(parent),
+ m_atcStationsOnline(), m_atcStationsBooked(), m_aircraftsInRange(),
+ m_network(nullptr), m_ownAircraft(),
+ m_metarCache()
+ {
+
+ // 1. Init by "network driver"
+ this->m_network = new NetworkVatlib(this);
+
+ // 2. Init own aircraft
+ this->initOwnAircraft();
+
+ // 3. Init network access driver for XML data (bookings)
+ this->m_networkManager = new QNetworkAccessManager(this);
+ this->connect(this->m_networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(psAtcBookingsRead(QNetworkReply *)));
+ this->m_atcBookingTimer = new QTimer(this);
+ this->connect(this->m_atcBookingTimer, SIGNAL(timeout()), this, SLOT(readAtcBookingsFromSource()));
+ this->m_atcBookingTimer->start(15 * 1000);
+
+ // 4. connect signals and slots
+ bool connect = this->connect(this->m_network, SIGNAL(connectionStatusChanged(Cvatlib_Network::connStatus, Cvatlib_Network::connStatus)),
+ this, SLOT(psFsdConnectionStatusChanged(Cvatlib_Network::connStatus, Cvatlib_Network::connStatus)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect connectionStatusChanged");
+
+ connect = this->connect(this->m_network, SIGNAL(terminate()),
+ this, SLOT(psFsdConnectionTerminated()));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect terminate");
+
+ connect = this->connect(this->m_network, SIGNAL(atcPositionUpdate(BlackMisc::Aviation::CCallsign, BlackMisc::PhysicalQuantities::CFrequency, BlackMisc::Geo::CCoordinateGeodetic, BlackMisc::PhysicalQuantities::CLength)),
+ this, SLOT(psFsdAtcPositionUpdate(BlackMisc::Aviation::CCallsign, BlackMisc::PhysicalQuantities::CFrequency, BlackMisc::Geo::CCoordinateGeodetic, BlackMisc::PhysicalQuantities::CLength)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect atcPositionUpdate");
+
+ connect = this->connect(this->m_network, SIGNAL(atisQueryReplyReceived(BlackMisc::Aviation::CCallsign, QString)),
+ this, SLOT(psFsdAtisQueryReceived(BlackMisc::Aviation::CCallsign, QString)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect atis");
+
+ connect = this->connect(this->m_network, SIGNAL(metarReceived(QString)),
+ this, SLOT(psFsdMetarReceived(QString)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect metar");
+
+ connect = this->connect(this->m_network, SIGNAL(nameQueryReplyReceived(BlackMisc::Aviation::CCallsign, QString)),
+ this, SLOT(psFsdNameQueryReplyReceived(BlackMisc::Aviation::CCallsign, QString)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect name reply");
+
+ connect = this->connect(this->m_network, SIGNAL(exception(QString, bool)),
+ this, SLOT(psVatlibExceptionMessage(QString, bool)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect exception");
+
+ connect = this->connect(this->m_network, SIGNAL(aircraftInfoReceived(BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftIcao)),
+ this, SLOT(psFsdAircraftInfoReceived(BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftIcao)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect aircraft info");
+
+ connect = this->connect(this->m_network, SIGNAL(pilotDisconnected(BlackMisc::Aviation::CCallsign)),
+ this, SLOT(psFsdPilotDisconnected(BlackMisc::Aviation::CCallsign)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect pilot disconnected");
+
+ connect = this->connect(this->m_network, SIGNAL(aircraftPositionUpdate(BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituation, BlackMisc::Aviation::CTransponder)),
+ this, SLOT(psFsdAircraftPositionUpdate(BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituation, BlackMisc::Aviation::CTransponder)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect aircraft position update");
+
+ connect = this->connect(this->m_network, SIGNAL(frequencyQueryReplyReceived(BlackMisc::Aviation::CCallsign, BlackMisc::PhysicalQuantities::CFrequency)),
+ this, SLOT(psFsdFrequencyReceived(BlackMisc::Aviation::CCallsign, BlackMisc::PhysicalQuantities::CFrequency)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect frequency update");
+
+ connect = this->connect(this->m_network, SIGNAL(textMessagesReceived(BlackMisc::Network::CTextMessageList)),
+ this, SLOT(psFsdTextMessageReceived(BlackMisc::Network::CTextMessageList)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect text message");
+
+
+ // relay status message
+ connect = this->connect(this->m_network, SIGNAL(statusMessage(BlackMisc::CStatusMessage)),
+ this, SIGNAL(statusMessage(BlackMisc::CStatusMessage)));
+ Q_ASSERT_X(connect, "CContextNetwork", "Cannot connect status message");
+ }
+
+ /*
+ * Cleanup
+ */
+ CContextNetwork::~CContextNetwork()
+ {
+ if (this->isConnected()) this->disconnectFromNetwork();
+ this->disconnect(this);
+ this->disconnect(this->m_network);
+ }
+
+ /*
+ * Init own aircraft
+ */
+ void CContextNetwork::initOwnAircraft()
+ {
+ Q_ASSERT(this->getRuntime());
+ Q_ASSERT(this->getRuntime()->getIContextSettings());
+ this->m_ownAircraft.initComSystems();
+ this->m_ownAircraft.initTransponder();
+ CAircraftSituation situation(
+ CCoordinateGeodetic(
+ CLatitude::fromWgs84("N 049° 18' 17"),
+ CLongitude::fromWgs84("E 008° 27' 05"),
+ CLength(0, CLengthUnit::m())),
+ CAltitude(312, CAltitude::MeanSeaLevel, CLengthUnit::ft())
+ );
+ this->m_ownAircraft.setSituation(situation);
+ this->m_ownAircraft.setPilot(this->getRuntime()->getIContextSettings()->getNetworkSettings().getCurrentNetworkServer().getUser());
+
+ // TODO: This would need to come from somewhere (mappings)
+ // Own callsign, plane ICAO status, model used
+ this->m_ownAircraft.setCallsign(CCallsign("BLACK"));
+ this->m_ownAircraft.setIcaoInfo(CAircraftIcao("C172", "L1P", "GA", "GA", "0000ff"));
+ }
+
+ /*
+ * Connect to network
+ */
+ CStatusMessages CContextNetwork::connectToNetwork()
+ {
+ qDebug() << Q_FUNC_INFO;
+
+ CStatusMessages msgs;
+ CServer currentServer = this->getRuntime()->getIContextSettings()->getNetworkSettings().getCurrentNetworkServer();
+
+ if (!currentServer.getUser().isValid())
+ {
+ msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "Invalid user credentials"));
+ }
+ //else if (!this->m_network->isDisconnected())
+ //{
+ // msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "Already connected"));
+ //}
+ else
+ {
+ this->m_ownAircraft.setPilot(currentServer.getUser());
+ this->m_network->setServer(currentServer);
+ //this->m_network->setOwnAircraft(this->m_ownAircraft);
+ this->m_network->initiateConnection();
+ QString msg = "Connection pending ";
+ msg.append(" ").append(currentServer.getAddress()).append(" ").append(QString::number(currentServer.getPort()));
+ msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, msg));
+ }
+ return msgs;
+ }
+
+ /*
+ * Disconnect from network
+ */
+ CStatusMessages CContextNetwork::disconnectFromNetwork()
+ {
+ qDebug() << Q_FUNC_INFO;
+
+ CStatusMessages msgs;
+ //if (this->m_network->isDisconnected())
+ //{
+ // msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityWarning, "Already disconnected"));
+ //}
+ //else
+ {
+ this->m_network->terminateConnection();
+ this->m_aircraftsInRange.clear();
+ this->m_atcStationsBooked.clear();
+ this->m_atcStationsOnline.clear();
+ this->m_metarCache.clear();
+ msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, "Connection terminating"));
+ }
+ return msgs;
+ }
+
+ /*
+ * Connected
+ */
+ bool CContextNetwork::isConnected() const
+ {
+ return false;
+ }
+
+ /*
+ * Own's plane position update
+ */
+ void CContextNetwork::sendOwnAircraftCheckedPositionUpdateToNetwork() const
+ {
+ // TODO: Would this logic go into network_vatlib?
+ // 1. Check not sending to many updates
+ // 2. Send as pull update to intermediate update
+ // 3. Same position, no update?
+ // ...
+
+ // this->log(Q_FUNC_INFO, this->m_ownAircraft.toQString());
+ // this->m_network->sendAircraftUpdate(this->m_ownAircraft);
+ }
+
+ /*
+ * Own Aircraft
+ */
+ CStatusMessages CContextNetwork::setOwnAircraft(const BlackMisc::Aviation::CAircraft &aircraft)
+ {
+ this->log(Q_FUNC_INFO, aircraft.toQString());
+ CStatusMessages msgs;
+ //if (this->m_network->isDisconnected())
+ //{
+ // this->m_ownAircraft = aircraft;
+ //}
+ //else
+ {
+ msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "Cannot set plane info, network already connected"));
+ }
+ return msgs;
+ }
+
+ /*
+ * Own Aircraft details
+ */
+ CStatusMessages CContextNetwork::sendOwnAircraftDetails()
+ {
+#if 0
+ CStatusMessages msgs;
+ if (this->m_network->isDisconnected() && false)
+ {
+ msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "Cannot send plane info, network not connected"));
+
+ }
+ else if (!this->m_ownAircraft.isValidForLogin())
+ {
+ msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "Cannot send plane info, own aircraft is invalid"));
+ }
+ else
+ {
+ // TODO: really sending plane info ??
+ // NOPE: this->m_network->sendAircraftInfo(this->m_ownAircraft);
+ this->sendOwnAircraftCheckedPositionUpdateToNetwork();
+ QString m("Aircraft send ");
+ m.append(this->m_ownAircraft.toQString(true));
+ msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, m));
+ }
+ return msgs;
+#endif // 0
+ return CStatusMessages();
+ }
+
+ /*
+ * Own position
+ */
+ void CContextNetwork::updateOwnPosition(const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::Aviation::CAltitude &altitude)
+ {
+ if (position == this->m_ownAircraft.getPosition() && altitude == this->m_ownAircraft.getAltitude()) return;
+ this->m_ownAircraft.setPosition(position);
+ this->m_ownAircraft.setAltitude(altitude);
+ this->sendOwnAircraftCheckedPositionUpdateToNetwork();
+ }
+
+ /*
+ * Update own situation
+ */
+ void CContextNetwork::updateOwnSituation(const BlackMisc::Aviation::CAircraftSituation &situation)
+ {
+ if (situation == this->m_ownAircraft.getSituation()) return;
+ this->m_ownAircraft.setSituation(situation);
+ this->sendOwnAircraftCheckedPositionUpdateToNetwork();
+ }
+
+ /*
+ * Own cockpit data
+ */
+ void CContextNetwork::updateOwnCockpit(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2, const BlackMisc::Aviation::CTransponder &transponder)
+ {
+ bool changed = false;
+ if (com1 != this->m_ownAircraft.getCom1System())
+ {
+ this->m_ownAircraft.setCom1System(com1);
+ changed = true;
+ }
+ if (com2 != this->m_ownAircraft.getCom2System())
+ {
+ this->m_ownAircraft.setCom2System(com2);
+ changed = true;
+ }
+ if (transponder != this->m_ownAircraft.getTransponder())
+ {
+ this->m_ownAircraft.setTransponder(transponder);
+ changed = true;
+ }
+
+ if (!changed) return;
+ //this->m_network->updateOwnCockpit(com1, com2, transponder);
+ }
+
+ /*
+ * Own aircraft
+ */
+ CAircraft CContextNetwork::getOwnAircraft() const
+ {
+ this->log(Q_FUNC_INFO, this->m_ownAircraft.toQString());
+ return this->m_ownAircraft;
+ }
+
+ /*
+ * Send text messages
+ */
+ void CContextNetwork::sendTextMessages(const CTextMessageList &textMessages)
+ {
+ this->log(Q_FUNC_INFO, textMessages.toQString());
+ this->m_network->sendTextMessages(textMessages);
+ }
+
+ /*
+ * Connection terminated
+ */
+ void CContextNetwork::psFsdConnectionTerminated()
+ {
+ emit this->statusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityInfo, "connection terminated"));
+ emit this->connectionTerminated();
+ }
+
+ /*
+ * Connection status changed
+ */
+ void CContextNetwork::psFsdConnectionStatusChanged(Cvatlib_Network::connStatus from, Cvatlib_Network::connStatus to)
+ {
+ ConnectionStatus fromCs = static_cast(from);
+ ConnectionStatus toCs = static_cast(to);
+ CStatusMessages msgs;
+
+
+ // send 1st position
+ if (toCs == CContextNetwork::ConnectionStatusConnected)
+ {
+ msgs = this->sendOwnAircraftDetails();
+ }
+
+ // send as message
+ QString m("connection status changed ");
+ m.append(this->connectionStatusToString(fromCs)).
+ append(" ").
+ append(this->connectionStatusToString(toCs));
+ qDebug() << m;
+ msgs.append(CStatusMessage(CStatusMessage::TypeTrafficNetwork,
+ toCs == ConnectionStatusError ? CStatusMessage::SeverityError : CStatusMessage::SeverityInfo, m));
+ emit this->statusMessage(msgs.at(0));
+
+ // send as own signal
+ emit this->connectionStatusChanged(fromCs, toCs);
+ }
+
+ /*
+ * Name query
+ */
+ void CContextNetwork::psFsdNameQueryReplyReceived(const CCallsign &callsign, const QString &realname)
+ {
+ this->log(Q_FUNC_INFO, callsign.toQString(), realname);
+ if (realname.isEmpty()) return;
+ CValueMap vm(CAtcStation::IndexControllerRealname, realname);
+ this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsign, vm);
+ this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsign, vm);
+
+ vm = CValueMap(CAircraft::IndexPilotRealname, realname);
+ this->m_aircraftsInRange.applyIf(&CAircraft::getCallsign, callsign, vm);
+ }
+
+
+ /*
+ * Ping, is DBus alive?
+ */
+ qint64 CContextNetwork::ping(qint64 token) const
+ {
+ return token;
+ }
+
+ /*
+ * Exception to status message
+ */
+ void CContextNetwork::psVatlibExceptionMessage(const QString &message, bool fatal)
+ {
+ CStatusMessage msg(CStatusMessage::TypeTrafficNetwork,
+ fatal ? CStatusMessage::SeverityError : CStatusMessage::SeverityWarning, message);
+ emit this->statusMessage(msg);
+ }
+
+} // namespace
diff --git a/src/blackcore/context_network.h b/src/blackcore/context_network.h
new file mode 100644
index 000000000..2c9d3e82e
--- /dev/null
+++ b/src/blackcore/context_network.h
@@ -0,0 +1,354 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BLACKCORE_CONTEXTNETWORK_H
+#define BLACKCORE_CONTEXTNETWORK_H
+
+#include "blackcore/dbus_server.h"
+#include "blackcore/network_vatlib.h"
+#include "blackcore/context_network_interface.h"
+#include "blackmisc/avallclasses.h"
+#include "blackmisc/statusmessage.h"
+#include "blackmisc/statusmessages.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define BLACKCORE_CONTEXTNETWORK_INTERFACENAME "blackcore.contextnetwork"
+
+namespace BlackCore
+{
+
+ class CCoreRuntime;
+
+
+ /*!
+ * \brief Network context
+ */
+ class CContextNetwork : public IContextNetwork
+ {
+ // Register by same name, make signals sender independent
+ // http://dbus.freedesktop.org/doc/dbus-faq.html#idp48032144
+ Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTNETWORK_INTERFACENAME)
+ Q_OBJECT
+
+ public:
+
+ /*!
+ * \brief With link to server
+ * \param server
+ */
+ CContextNetwork(CCoreRuntime *parent);
+
+ /*!
+ * \brief Destructor
+ */
+ virtual ~CContextNetwork();
+
+ /*!
+ * \brief Register myself in DBus
+ * \param server
+ */
+ void registerWithDBus(CDBusServer *server)
+ {
+ server->addObject(IContextNetwork::ServicePath(), this);
+ }
+
+ /*!
+ * \brief Runtime
+ * \return
+ */
+ const CCoreRuntime *getRuntime() const
+ {
+ return reinterpret_cast(this->parent());
+ }
+
+ /*!
+ * \brief Using local objects?
+ * \return
+ */
+ virtual bool usingLocalObjects() const { return true; }
+
+ public slots:
+
+ /*!
+ * \brief Read ATC bookings
+ * \return
+ */
+ virtual void readAtcBookingsFromSource() const;
+
+ /*!
+ * \brief The "central" ATC list with online ATC controllers
+ * \return
+ */
+ // If I make this &getAtcStations XML is not generated correctly
+ // needs to be crosschecked with the latest version of Qt
+ virtual const BlackMisc::Aviation::CAtcStationList getAtcStationsOnline() const
+ {
+ this->log(Q_FUNC_INFO);
+ return m_atcStationsOnline;
+ }
+
+ /*!
+ * \brief ATC list, with booked controllers
+ * \return
+ */
+ // If I make this &getAtcStations XML is not generated correctly
+ virtual const BlackMisc::Aviation::CAtcStationList getAtcStationsBooked() const
+ {
+ this->log(Q_FUNC_INFO);
+ return m_atcStationsBooked;
+ }
+
+ /*!
+ * \brief Aircraft list
+ * \return
+ */
+ // If I make this &getAtcStations XML is not generated correctly
+ virtual const BlackMisc::Aviation::CAircraftList getAircraftsInRange() const
+ {
+ this->log(Q_FUNC_INFO);
+ return m_aircraftsInRange;
+ }
+
+ /*!
+ * \brief Connect to Network
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages connectToNetwork();
+
+ /*!
+ * \brief Disconnect from network
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages disconnectFromNetwork();
+
+ /*!
+ * \brief Network connected?
+ * \return
+ */
+ virtual bool isConnected() const;
+
+ /*!
+ * \brief Set own aircraft
+ * \param aircraft
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages setOwnAircraft(const BlackMisc::Aviation::CAircraft &aircraft);
+
+ /*!
+ * \brief Update own position
+ * \param position
+ * \param altitude
+ */
+ virtual void updateOwnPosition(const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::Aviation::CAltitude &altitude);
+
+ /*!
+ * \brief Update own situation
+ * \param situation
+ */
+ virtual void updateOwnSituation(const BlackMisc::Aviation::CAircraftSituation &situation);
+
+ /*!
+ * \brief Update own cockpit
+ * \param com1
+ * \param com2
+ * \param transponder
+ */
+ virtual void updateOwnCockpit(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2, const BlackMisc::Aviation::CTransponder &transponder);
+
+ /*!
+ * \brief Get own aircraft
+ * \return
+ */
+ virtual BlackMisc::Aviation::CAircraft getOwnAircraft() const;
+
+ /*!
+ * \brief Text messages (also private chat messages)
+ * \param textMessage
+ */
+ virtual void sendTextMessages(const BlackMisc::Network::CTextMessageList &textMessages);
+
+ /*!
+ * \brief Request METAR
+ * \param airportIcaoCode
+ */
+ virtual BlackMisc::Aviation::CInformationMessage getMetar(const QString &airportIcaoCode);
+
+ /*!
+ * \brief Used to check if network is alive
+ * \param token
+ * \return
+ */
+ virtual qint64 ping(qint64 token) const;
+
+ private:
+ BlackMisc::Aviation::CAtcStationList m_atcStationsOnline;
+ BlackMisc::Aviation::CAtcStationList m_atcStationsBooked;
+ BlackMisc::Aviation::CAircraftList m_aircraftsInRange;
+ BlackCore::INetwork *m_network;
+ BlackMisc::Aviation::CAircraft m_ownAircraft;
+ QMap m_metarCache;
+
+ // for reading XML
+ QNetworkAccessManager *m_networkManager;
+ QTimer *m_atcBookingTimer;
+ QDateTime m_atcBookingsUpdateTimestamp;
+
+ /*!
+ * \brief Replace value by new values, but keep object itself intact
+ * \param newStations
+ */
+ void setAtcStationsBooked(const BlackMisc::Aviation::CAtcStationList &newStations);
+
+ /*!
+ * \brief Replace value by new values, but keep object itself intact
+ * \param newStations
+ */
+ void setAtcStationsOnline(const BlackMisc::Aviation::CAtcStationList &newStations);
+
+ /*!
+ * \brief The "central" ATC list with online ATC controllers
+ * \return
+ */
+ BlackMisc::Aviation::CAtcStationList &atcStationsOnline()
+ {
+ return m_atcStationsOnline;
+ }
+
+ /*!
+ * \brief ATC list, with booked controllers
+ * \return
+ */
+ BlackMisc::Aviation::CAtcStationList &atcStationsBooked()
+ {
+ return m_atcStationsBooked;
+ }
+
+ /*!
+ * \brief Check position update before sending to network
+ */
+ void sendOwnAircraftCheckedPositionUpdateToNetwork() const;
+
+ /*!
+ * \brief Own aircraft details
+ * \param aircraft
+ * \return
+ */
+ BlackMisc::CStatusMessages sendOwnAircraftDetails();
+
+ /*!
+ * \brief Init my very onw aircraft
+ */
+ void initOwnAircraft();
+
+ private slots:
+ /*!
+ * \brief Terminated connection
+ */
+ void psFsdConnectionTerminated();
+
+ /*!
+ * \brief Connection status changed
+ * \param from
+ * \param to
+ */
+ void psFsdConnectionStatusChanged(Cvatlib_Network::connStatus from, Cvatlib_Network::connStatus to);
+
+ /*!
+ * \brief ATC position update
+ * \param callsign
+ * \param frequency
+ * \param position
+ * \param range
+ */
+ void psFsdAtcPositionUpdate(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &frequency, const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::PhysicalQuantities::CLength &range);
+
+ /*!
+ * \brief Controller disconnected
+ * \param callsign
+ */
+ void psFsdAtcControllerDisconnected(const BlackMisc::Aviation::CCallsign &callsign);
+
+ /*!
+ * \brief ATIS received
+ * \param callsign
+ * \param atisMessage
+ */
+ void psFsdAtisQueryReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &atisMessage);
+
+ /*!
+ * \brief METAR received
+ * \param metarMessage
+ */
+ void psFsdMetarReceived(const QString &metarMessage);
+
+ /*!
+ * \brief Realnname recevied
+ * \param callsign
+ * \param realname
+ */
+ void psFsdNameQueryReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &realname);
+
+ /*!
+ * \brief Plane info received
+ * \param callsign
+ * \param icaoData
+ */
+ void psFsdAircraftInfoReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftIcao &icaoData);
+
+ /*!
+ * \brief Aircraft position update
+ * \param callsign
+ * \param situation
+ * \param transponder
+ */
+ void psFsdAircraftPositionUpdate(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CTransponder &transponder);
+
+ /*!
+ * \brief Pilot disconnected
+ * \param callsign
+ */
+ void psFsdPilotDisconnected(const BlackMisc::Aviation::CCallsign &callsign);
+
+ /*!
+ * \brief Frequency received
+ * \param callsign
+ * \param frequency
+ */
+ void psFsdFrequencyReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &frequency);
+
+ /*!
+ * \brief Radio text message received
+ * \param callsign
+ * \param message
+ * \param frequencies
+ */
+ void psFsdTextMessageReceived(const BlackMisc::Network::CTextMessageList &messages);
+
+ /*!
+ * \brief Bookings via XML read
+ * \param nwReply
+ * TODO: encapsulate reading from WWW in some class
+ */
+ void psAtcBookingsRead(QNetworkReply *nwReply);
+
+ /*!
+ * \brief Exception message
+ * \param message
+ * \param fatal
+ */
+ void psVatlibExceptionMessage(const QString &message, bool fatal);
+
+ };
+}
+
+// Declaring BlackCore::CContextNetwork * crashed when reading data
+Q_DECLARE_METATYPE(BlackCore::CContextNetwork::ConnectionStatus)
+
+#endif // guard
diff --git a/src/blackcore/context_network_aircraft.cpp b/src/blackcore/context_network_aircraft.cpp
new file mode 100644
index 000000000..02981f3fc
--- /dev/null
+++ b/src/blackcore/context_network_aircraft.cpp
@@ -0,0 +1,101 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "context_network.h"
+#include "coreruntime.h"
+#include "blackmisc/predicates.h"
+
+using namespace BlackMisc;
+using namespace BlackMisc::PhysicalQuantities;
+using namespace BlackMisc::Aviation;
+using namespace BlackMisc::Network;
+using namespace BlackMisc::Geo;
+
+namespace BlackCore
+{
+
+ /*
+ * Aircraft info received
+ */
+ void CContextNetwork::psFsdAircraftInfoReceived(const CCallsign &callsign, const CAircraftIcao &icaoData)
+ {
+ this->log(Q_FUNC_INFO, callsign.toQString(), icaoData.toQString());
+ CAircraftList aircraftsWithCallsign = this->m_aircraftsInRange.findByCallsign(callsign);
+ if (aircraftsWithCallsign.isEmpty())
+ {
+ // new aircraft
+ CAircraft aircraft;
+ aircraft.setCallsign(callsign);
+ aircraft.setIcaoInfo(icaoData);
+ aircraft.calculcateDistanceToPlane(this->m_ownAircraft.getPosition());
+ this->m_aircraftsInRange.insert(aircraft);
+ emit this->m_network->sendFrequencyQuery(callsign);
+ emit this->m_network->sendNameQuery(callsign);
+ emit this->changedAircraftsInRange();
+ }
+ else
+ {
+ // update
+ CValueMap vm(CAircraft::IndexIcao, icaoData.toQVariant());
+ this->m_aircraftsInRange.applyIf(BlackMisc::Predicates::MemberEqual(&CAircraft::getCallsign, callsign), vm);
+ emit this->changedAircraftsInRange();
+ }
+ }
+
+ /*
+ * Aircraft update received
+ */
+ void CContextNetwork::psFsdAircraftPositionUpdate(const CCallsign &callsign, const CAircraftSituation &situation, const CTransponder &transponder)
+ {
+ this->log(Q_FUNC_INFO, callsign.toQString(), situation.toQString(), transponder.toQString());
+ CAircraftList list = this->m_aircraftsInRange.findByCallsign(callsign);
+ if (list.isEmpty())
+ {
+ // new aircraft
+ CAircraft aircraft;
+ aircraft.setCallsign(callsign);
+ aircraft.setSituation(situation);
+ aircraft.setTransponder(transponder);
+ aircraft.calculcateDistanceToPlane(this->m_ownAircraft.getPosition());
+ this->m_aircraftsInRange.insert(aircraft);
+ emit this->m_network->sendFrequencyQuery(callsign);
+ emit this->m_network->sendNameQuery(callsign);
+ emit this->m_network->requestAircraftInfo(callsign);
+ emit this->changedAircraftsInRange();
+ }
+ else
+ {
+ // update
+ CValueMap vm;
+ vm.addValue(CAircraft::IndexTransponder, transponder);
+ vm.addValue(CAircraft::IndexSituation, situation);
+ this->m_aircraftsInRange.applyIf(BlackMisc::Predicates::MemberEqual(&CAircraft::getCallsign, callsign), vm);
+ emit this->changedAircraftsInRange();
+ }
+ }
+
+ /*
+ * Pilot disconnected
+ */
+ void CContextNetwork::psFsdPilotDisconnected(const CCallsign &callsign)
+ {
+ this->log(Q_FUNC_INFO, callsign.toQString());
+ this->m_aircraftsInRange.removeIf(&CAircraft::getCallsign, callsign);
+ }
+
+ /*
+ * Frequency received
+ */
+ void CContextNetwork::psFsdFrequencyReceived(const CCallsign &callsign, const CFrequency &frequency)
+ {
+ this->log(Q_FUNC_INFO, callsign.toQString(), frequency.toQString());
+
+ // update
+ CValueMap vm(CAircraft::IndexFrequencyCom1, frequency.toQVariant());
+ this->m_aircraftsInRange.applyIf(BlackMisc::Predicates::MemberEqual(&CAircraft::getCallsign, callsign), vm);
+ emit this->changedAircraftsInRange();
+ }
+
+} // namespace
diff --git a/src/blackcore/context_network_atc.cpp b/src/blackcore/context_network_atc.cpp
new file mode 100644
index 000000000..2e4b0e210
--- /dev/null
+++ b/src/blackcore/context_network_atc.cpp
@@ -0,0 +1,238 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "context_network.h"
+#include "coreruntime.h"
+#include "blackmisc/avatcstationlist.h"
+#include "blackmisc/predicates.h"
+#include
+#include
+#include
+#include
+#include
+
+using namespace BlackMisc;
+using namespace BlackMisc::PhysicalQuantities;
+using namespace BlackMisc::Aviation;
+using namespace BlackMisc::Network;
+using namespace BlackMisc::Geo;
+
+namespace BlackCore
+{
+
+ /*
+ * Read bookings
+ */
+ void CContextNetwork::readAtcBookingsFromSource() const
+ {
+ QUrl url("http://vatbook.euroutepro.com/xml2.php");
+ QNetworkRequest request(url);
+ this->m_networkManager->get(request);
+ }
+
+ /*
+ * Booked stations
+ */
+ void CContextNetwork::setAtcStationsBooked(const BlackMisc::Aviation::CAtcStationList &newStations)
+ {
+ this->m_atcStationsBooked = newStations;
+ }
+
+ /*
+ * Online stations
+ */
+ void CContextNetwork::setAtcStationsOnline(const BlackMisc::Aviation::CAtcStationList &newStations)
+ {
+ this->m_atcStationsOnline = newStations;
+ }
+
+ /*
+ * Request METAR
+ */
+ BlackMisc::Aviation::CInformationMessage CContextNetwork::getMetar(const QString &airportIcaoCode)
+ {
+ CInformationMessage metar;
+ QString icao = airportIcaoCode.trimmed().toUpper();
+ if (icao.length() != 4) return metar;
+ if (this->m_metarCache.contains(icao)) metar = this->m_metarCache[icao];
+ if (metar.isEmpty() || metar.timeDiffReceivedMs() > 10 * 1000)
+ {
+ // outdated, or not in cache at all
+ this->m_network->requestMetar(airportIcaoCode.trimmed().toUpper());
+
+ // with this little trick we try to make an asynchronous signal / slot
+ // based approach a synchronous return value
+ QTime waitForMetar = QTime::currentTime().addMSecs(1000);
+ while (QTime::currentTime() < waitForMetar)
+ {
+ // process some other events and hope network answer is received already
+ QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
+ if (m_metarCache.contains(icao))
+ {
+ metar = this->m_metarCache[icao];
+ break;
+ }
+ }
+ }
+ return metar;
+ }
+
+ /*
+ * ATC Position update
+ */
+ void CContextNetwork::psFsdAtcPositionUpdate(const CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &frequency, const CCoordinateGeodetic &position, const BlackMisc::PhysicalQuantities::CLength &range)
+ {
+ this->log(Q_FUNC_INFO, callsign.toQString(), frequency.toQString(), position.toQString(), range.toQString());
+ CAtcStationList stationsWithCallsign = this->m_atcStationsOnline.findByCallsign(callsign);
+ if (stationsWithCallsign.isEmpty())
+ {
+ // new station
+ CAtcStation station;
+ station.setCallsign(callsign);
+ station.setRange(range);
+ station.setFrequency(frequency);
+ station.setPosition(position);
+ station.setOnline(true);
+ station.calculcateDistanceToPlane(this->m_ownAircraft.getPosition());
+ this->m_atcStationsOnline.insert(station);
+ emit this->changedAtcStationsOnline();
+ emit this->m_network->sendAtisQuery(callsign); // request ATIS
+ emit this->m_network->sendNameQuery(callsign);
+ }
+ else
+ {
+ // update
+ CValueMap values;
+ values.addValue(CAtcStation::IndexFrequency, frequency);
+ values.addValue(CAtcStation::IndexPosition, position);
+ values.addValue(CAtcStation::IndexRange, range);
+ this->m_atcStationsOnline.applyIf(BlackMisc::Predicates::MemberEqual(&CAtcStation::getCallsign, callsign), values);
+ emit this->changedAtcStationsOnline();
+ }
+ }
+
+ /*
+ * ATC Controller disconnected
+ */
+ void CContextNetwork::psFsdAtcControllerDisconnected(const CCallsign &callsign)
+ {
+ this->log(Q_FUNC_INFO, callsign.toQString());
+ this->m_atcStationsOnline.removeIf(&CAtcStation::getCallsign, callsign);
+ emit this->changedAtcStationsOnline();
+ this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsign, CValueMap(CAtcStation::IndexIsOnline, QVariant(false)));
+ }
+
+ /*
+ * ATIS received
+ */
+ void CContextNetwork::psFsdAtisQueryReceived(const CCallsign &callsign, const QString &atisMessage)
+ {
+ this->log(Q_FUNC_INFO, callsign.toQString(), atisMessage);
+ CValueMap vm(CAtcStation::IndexAtisMessage, atisMessage);
+ this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsign, vm);
+ this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsign, vm);
+ }
+
+ /*
+ * Metar received
+ */
+ void CContextNetwork::psFsdMetarReceived(const QString &metarMessage)
+ {
+ this->log(Q_FUNC_INFO, metarMessage);
+ if (metarMessage.length() < 10) return; // invalid
+ const QString icaoCode = metarMessage.left(4).toUpper();
+ const QString icaoCodeTower = icaoCode + "_TWR";
+ CCallsign callsignTower(icaoCodeTower);
+ CInformationMessage metar(CInformationMessage::METAR, metarMessage);
+
+ // add METAR to existing stations
+ CValueMap vm(CAtcStation::IndexMetar, metar.toQVariant());
+ this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsignTower, vm);
+ this->m_atcStationsBooked.applyIf(&CAtcStation::getCallsign, callsignTower, vm);
+ this->m_metarCache.insert(icaoCode, metar);
+ }
+
+ /*
+ * Bookings read from XML
+ * TODO: encapsulate reading from WWW in some class
+ */
+ void CContextNetwork::psAtcBookingsRead(QNetworkReply *nwReply)
+ {
+ if (nwReply->error() == QNetworkReply::NoError)
+ {
+ QString xmlData = nwReply->readAll();
+ QDomDocument doc;
+
+ if (doc.setContent(xmlData))
+ {
+ QDomNode atc = doc.elementsByTagName("atcs").at(0);
+ QDomNodeList bookingNodes = atc.toElement().elementsByTagName("booking");
+ int size = bookingNodes.size();
+ CSequence stations;
+ for (int i = 0; i < size; i++)
+ {
+ QDomNode bookingNode = bookingNodes.at(i);
+ QDomNodeList bookingNodeValues = bookingNode.childNodes();
+ CAtcStation bookedStation;
+ CUser user;
+ for (int v = 0; v < bookingNodeValues.size(); v++)
+ {
+ QDomNode bookingNodeValue = bookingNodeValues.at(v);
+ QString name = bookingNodeValue.nodeName().toLower();
+ QString value = bookingNodeValue.toElement().text();
+ if (name == "id")
+ {
+ // could be used as unique key
+ }
+ else if (name == "callsign")
+ {
+ bookedStation.setCallsign(CCallsign(value));
+ }
+ else if (name == "name")
+ {
+ user.setRealname(value);
+ }
+ else if (name == "cid")
+ {
+ user.setId(value);
+ }
+ else if (name == "time_end")
+ {
+ QDateTime t = QDateTime::fromString(value, "yyyy-MM-dd HH:mm:ss");
+ bookedStation.setBookedUntilUtc(t);
+ }
+ else if (name == "time_start")
+ {
+ QDateTime t = QDateTime::fromString(value, "yyyy-MM-dd HH:mm:ss");
+ bookedStation.setBookedFromUtc(t);
+ }
+ }
+ // time checks
+ QDateTime now = QDateTime::currentDateTimeUtc();
+ if (now.msecsTo(bookedStation.getBookedUntilUtc()) < (1000 * 60 * 15)) continue; // until n mins in past
+ if (now.msecsTo(bookedStation.getBookedFromUtc()) > (1000 * 60 * 60 * 24)) continue; // to far in the future, n hours
+
+ // booking does not have position, so distance cannot be calculated
+ // bookedStation.calculcateDistanceToPlane(this->m_ownAircraft.getPosition());
+
+ bookedStation.setController(user);
+
+ // consolidate and append
+ this->m_atcStationsOnline.mergeWithBooking(bookedStation);
+ stations.insert(bookedStation);
+ }
+ nwReply->close();
+ nwReply->deleteLater();
+
+ // set the new values
+ if (this->getAtcStationsBooked() != stations)
+ {
+ this->atcStationsBooked() = stations;
+ emit this->changedAtcStationsBooked();
+ }
+ } // node
+ } // content
+ } // method
+} // namespace
diff --git a/src/blackcore/context_network_interface.cpp b/src/blackcore/context_network_interface.cpp
new file mode 100644
index 000000000..511ec222a
--- /dev/null
+++ b/src/blackcore/context_network_interface.cpp
@@ -0,0 +1,194 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "blackcore/context_network_interface.h"
+#include
+#include
+#include
+
+
+namespace BlackCore
+{
+
+ /*
+ * Constructor for DBus
+ */
+ IContextNetwork::IContextNetwork(const QString &serviceName, QDBusConnection &connection, QObject *parent) : QObject(parent), m_dBusInterface(0)
+ {
+ this->m_dBusInterface = new BlackMisc::CGenericDBusInterface(
+ serviceName , IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
+ connection, this);
+ this->relaySignals(serviceName, connection);
+ }
+
+ /*
+ * Workaround for signals, not working without, but why?
+ */
+ void IContextNetwork::relaySignals(const QString &serviceName, QDBusConnection &connection)
+ {
+ connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
+ "connectionStatusChanged", this, SIGNAL(connectionStatusChanged(uint, uint)));
+ connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
+ "changedAtcStationsBooked", this, SIGNAL(changedAtcStationsBooked()));
+ connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
+ "changedAtcStationsOnline", this, SIGNAL(changedAtcStationsOnline()));
+ connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
+ "connectionTerminated", this, SIGNAL(connectionTerminated()));
+ connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
+ "statusMessage", this, SIGNAL(statusMessage(BlackMisc::CStatusMessage)));
+ connection.connect(serviceName, IContextNetwork::ServicePath(), IContextNetwork::InterfaceName(),
+ "textMessagesReceived", this, SIGNAL(textMessagesReceived(BlackMisc::Network::CTextMessageList)));
+ }
+
+ /*
+ * Clear text of status
+ */
+ QString IContextNetwork::connectionStatusToString(ConnectionStatus status) const
+ {
+ int index = metaObject()->indexOfEnumerator("ConnectionStatus");
+ QMetaEnum metaEnum = metaObject()->enumerator(index);
+ return metaEnum.valueToKey(status);
+ }
+
+ /*
+ * Relay to DBus
+ */
+ void IContextNetwork::readAtcBookingsFromSource() const
+ {
+ this->m_dBusInterface->callDBus(QLatin1Literal("readAtcBookingsFromSource"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ const BlackMisc::Aviation::CAtcStationList IContextNetwork::getAtcStationsOnline() const
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("getAtcStationsOnline"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ const BlackMisc::Aviation::CAtcStationList IContextNetwork::getAtcStationsBooked() const
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("getAtcStationsBooked"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ const BlackMisc::Aviation::CAircraftList IContextNetwork::getAircraftsInRange() const
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("getAircraftsInRange"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ BlackMisc::Aviation::CAircraft IContextNetwork::getOwnAircraft() const
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("getOwnAircraft"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ BlackMisc::CStatusMessages IContextNetwork::connectToNetwork()
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("connectToNetwork"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ BlackMisc::CStatusMessages IContextNetwork::disconnectFromNetwork()
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("disconnectFromNetwork"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ bool IContextNetwork::isConnected() const
+ {
+ qint64 token = QDateTime::currentMSecsSinceEpoch();
+ if (this->ping(token) != token) return false; // Core cannot be reached
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("isConnected"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ BlackMisc::CStatusMessages IContextNetwork::setOwnAircraft(const BlackMisc::Aviation::CAircraft &aircraft)
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("setOwnAircraft"), aircraft);
+ }
+
+ /*
+ * Relay to DBus
+ */
+ void IContextNetwork::updateOwnPosition(const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::Aviation::CAltitude &altitude)
+ {
+ this->m_dBusInterface->callDBus(QLatin1Literal("updateOwnPosition"), position, altitude);
+ }
+
+ /*
+ * Relay to DBus
+ */
+ void IContextNetwork::updateOwnSituation(const BlackMisc::Aviation::CAircraftSituation &situation)
+ {
+ this->m_dBusInterface->callDBus(QLatin1Literal("updateOwnSituation"), situation);
+ }
+
+ /*
+ * Relay to DBus
+ */
+ void IContextNetwork::updateOwnCockpit(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2, const BlackMisc::Aviation::CTransponder &transponder)
+ {
+ this->m_dBusInterface->callDBus(QLatin1Literal("updateOwnCockpit"), com1, com2, transponder);
+ }
+
+ /*
+ * Relay to DBus
+ */
+ void IContextNetwork::sendTextMessages(const BlackMisc::Network::CTextMessageList &textMessages)
+ {
+ this->m_dBusInterface->callDBus(QLatin1Literal("sendTextMessages"), textMessages);
+ }
+
+ /*
+ * Relay to DBus
+ */
+ BlackMisc::Aviation::CInformationMessage IContextNetwork::getMetar(const QString &airportIcaoCode)
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("requestMetar"), airportIcaoCode);
+ }
+
+ /*
+ * Ping, is DBus alive?
+ */
+ qint64 IContextNetwork::ping(qint64 token) const
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("ping"), token);
+ }
+
+ /*
+ * Logging
+ */
+ void IContextNetwork::log(const QString &method, const QString &m1, const QString &m2, const QString &m3, const QString &m4) const
+ {
+ if (m1.isEmpty())
+ qDebug() << " LOG: " << method;
+ else if (m2.isEmpty())
+ qDebug() << " LOG: " << method << m1;
+ else if (m3.isEmpty())
+ qDebug() << " LOG: " << method << m1 << m2;
+ else if (m4.isEmpty())
+ qDebug() << " LOG: " << method << m1 << m2 << m3;
+ else
+ qDebug() << " LOG: " << method << m1 << m2 << m3 << m4;
+ }
+
+} // namespace
diff --git a/src/blackcore/context_network_interface.h b/src/blackcore/context_network_interface.h
new file mode 100644
index 000000000..893a3d6d8
--- /dev/null
+++ b/src/blackcore/context_network_interface.h
@@ -0,0 +1,267 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BLACKCORE_CONTEXTNETWORK_INTERFACE_H
+#define BLACKCORE_CONTEXTNETWORK_INTERFACE_H
+
+#include "blackmisc/avallclasses.h"
+#include "blackmisc/statusmessage.h"
+#include "blackmisc/statusmessages.h"
+#include "blackmisc/nwtextmessagelist.h"
+#include "blackmisc/genericdbusinterface.h"
+#include "blackcore/network_vatlib.h"
+#include
+#include
+
+#define BLACKCORE_CONTEXTNETWORK_INTERFACENAME "blackcore.contextnetwork"
+#define BLACKCORE_CONTEXTNETWORK_SERVICEPATH "/network"
+
+// SERVICENAME must contain at least one ".", otherwise generation fails
+// as this is interpreted in the way comain.somename
+
+namespace BlackCore
+{
+
+ /*!
+ * \brief The IContextNetwork class
+ */
+ class IContextNetwork : public QObject
+ {
+ Q_OBJECT
+ Q_ENUMS(ConnectionStatus)
+ Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTNETWORK_INTERFACENAME)
+
+ public:
+ /*!
+ * \brief Service name
+ * \return
+ */
+ static const QString &InterfaceName()
+ {
+ static QString s(BLACKCORE_CONTEXTNETWORK_INTERFACENAME);
+ return s;
+ }
+
+ /*!
+ * \brief Service path
+ * \return
+ */
+ static const QString &ServicePath()
+ {
+ static QString s(BLACKCORE_CONTEXTNETWORK_SERVICEPATH);
+ return s;
+ }
+
+ /*!
+ * \brief Qt compliant status
+ */
+ enum ConnectionStatus
+ {
+ ConnectionStatusIdle = static_cast(Cvatlib_Network::connStatus_Idle),
+ ConnectionStatusConnected = static_cast(Cvatlib_Network::connStatus_Connected),
+ ConnectionStatusConnecting = static_cast(Cvatlib_Network::connStatus_Connecting),
+ ConnectionStatusDisconnected = static_cast(Cvatlib_Network::connStatus_Disconnected),
+ ConnectionStatusError = static_cast(Cvatlib_Network::connStatus_Error)
+ };
+
+ /*!
+ * \brief DBus version constructor
+ * \param serviceName
+ * \param connection
+ * \param parent
+ */
+ IContextNetwork(const QString &serviceName, QDBusConnection &connection, QObject *parent = 0);
+
+ /*!
+ * Destructor
+ */
+ ~IContextNetwork() {}
+
+
+ /*!
+ * \brief Using local objects?
+ * \return
+ */
+ virtual bool usingLocalObjects() const { return false; }
+
+ private:
+ BlackMisc::CGenericDBusInterface *m_dBusInterface;
+
+ /*!
+ * Relay connection signals to local signals
+ * No idea why this has to be wired and is not done automatically
+ * \param connection
+ */
+ void relaySignals(const QString &serviceName, QDBusConnection &connection);
+
+ protected:
+ /*!
+ * \brief IContextNetwork
+ * \param parent
+ */
+ IContextNetwork(QObject *parent = 0) : QObject(parent), m_dBusInterface(0) {}
+
+ /*!
+ * Connection status as cleartext
+ */
+ QString connectionStatusToString(ConnectionStatus status) const;
+
+ /*!
+ * \brief Helper for logging, likely to be removed / changed
+ * \param method
+ * \param m1
+ * \param m2
+ * \param m3
+ * \param m4
+ */
+ void log(const QString &method, const QString &m1 = "", const QString &m2 = "", const QString &m3 = "", const QString &m4 = "") const;
+
+ signals:
+
+ /*!
+ * \brief ATC station list has been changed
+ * \param message
+ */
+ void statusMessage(const BlackMisc::CStatusMessage &message);
+
+ /*!
+ * \brief List has been changed
+ */
+ void changedAtcStationsOnline();
+
+ /*!
+ * \brief ATC station list has been changed
+ */
+ void changedAtcStationsBooked();
+
+ /*!
+ * \brief Aircraft list has been changed
+ */
+ void changedAircraftsInRange();
+
+ /*!
+ * \brief Terminated connection
+ */
+ void connectionTerminated();
+
+ /*!
+ * \brief Connection status changed
+ * \param from
+ * \param to
+ */
+ // If I use the enum, adaptor / interface are not created correctly
+ void connectionStatusChanged(uint from, uint to);
+
+ /*!
+ * \brief Text messages (also private chat messages)
+ * \param textMessage
+ */
+ void textMessagesReceived(const BlackMisc::Network::CTextMessageList &textMessages);
+
+ public slots:
+
+ /*!
+ * \brief Read ATC bookings
+ * \return
+ */
+ virtual void readAtcBookingsFromSource() const;
+
+ /*!
+ * \brief The "central" ATC list with online ATC controllers
+ * \return
+ */
+ // If I make this &getAtcStations XML is not generated correctly
+ virtual const BlackMisc::Aviation::CAtcStationList getAtcStationsOnline() const;
+
+ /*!
+ * \brief ATC list, with booked controllers
+ * \return
+ */
+ virtual const BlackMisc::Aviation::CAtcStationList getAtcStationsBooked() const;
+
+ /*!
+ * \brief Aircraft list
+ * \return
+ */
+ virtual const BlackMisc::Aviation::CAircraftList getAircraftsInRange() const;
+
+ /*!
+ * \brief Get own aircraft
+ * \return
+ */
+ virtual BlackMisc::Aviation::CAircraft getOwnAircraft() const;
+
+ /*!
+ * \brief Connect to Network
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages connectToNetwork();
+
+ /*!
+ * \brief Disconnect from network
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages disconnectFromNetwork();
+
+ /*!
+ * \brief Network connected?
+ * \return
+ */
+ virtual bool isConnected() const;
+
+ /*!
+ * Set own aircraft
+ * \param aircraft
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages setOwnAircraft(const BlackMisc::Aviation::CAircraft &aircraft);
+
+ /*!
+ * \brief Own position, be aware height is terrain height
+ * \param Position
+ * \param altitude
+ * \return
+ */
+ virtual void updateOwnPosition(const BlackMisc::Geo::CCoordinateGeodetic &position, const BlackMisc::Aviation::CAltitude &altitude);
+
+ /*!
+ * \brief Complete situation update
+ * \param Situation
+ * \return
+ */
+ virtual void updateOwnSituation(const BlackMisc::Aviation::CAircraftSituation &situation);
+
+ /*!
+ * \brief Update own cockpit
+ * \param com1
+ * \param com2
+ * \param transponder
+ */
+ virtual void updateOwnCockpit(const BlackMisc::Aviation::CComSystem &com1, const BlackMisc::Aviation::CComSystem &com2, const BlackMisc::Aviation::CTransponder &transponder);
+
+ /*!
+ * \brief Text messages (radio and private chat messages)
+ * \param textMessage
+ */
+ virtual void sendTextMessages(const BlackMisc::Network::CTextMessageList &textMessages);
+
+ /*!
+ * \brief Get METAR, if not available request it
+ * \param airportIcaoCode
+ * \return
+ */
+ virtual BlackMisc::Aviation::CInformationMessage getMetar(const QString &airportIcaoCode);
+
+ /*!
+ * \brief Ping
+ * \param token
+ * \return
+ */
+ virtual qint64 ping(qint64 token) const;
+
+ };
+}
+
+#endif // guard
diff --git a/src/blackcore/context_network_textmessages.cpp b/src/blackcore/context_network_textmessages.cpp
new file mode 100644
index 000000000..7b735565e
--- /dev/null
+++ b/src/blackcore/context_network_textmessages.cpp
@@ -0,0 +1,27 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "context_network.h"
+#include "coreruntime.h"
+
+using namespace BlackMisc;
+using namespace BlackMisc::PhysicalQuantities;
+using namespace BlackMisc::Aviation;
+using namespace BlackMisc::Network;
+using namespace BlackMisc::Geo;
+
+namespace BlackCore
+{
+ /*
+ * Radio text message received
+ */
+ void CContextNetwork::psFsdTextMessageReceived(const CTextMessageList &messages)
+ {
+ if (messages.isEmpty()) return;
+ this->log(Q_FUNC_INFO, messages.toQString());
+ this->textMessagesReceived(messages); // relay
+ }
+
+} // namespace
diff --git a/src/blackcore/context_settings.cpp b/src/blackcore/context_settings.cpp
new file mode 100644
index 000000000..78624390f
--- /dev/null
+++ b/src/blackcore/context_settings.cpp
@@ -0,0 +1,61 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "context_settings.h"
+#include "coreruntime.h"
+#include "blackmisc/settingutilities.h"
+
+using namespace BlackMisc::Settings;
+using namespace BlackMisc::Network;
+using namespace BlackMisc;
+
+namespace BlackCore
+{
+
+ /*
+ * Init this context
+ */
+ CContextSettings::CContextSettings(CCoreRuntime *parent) : IContextSettings(parent), m_settingsNetwork()
+ {
+ // create some dummy settings
+ // this would actually be reading the settings from disk ..
+
+ this->m_settingsNetwork.setCurrentNetworkServer(
+ CServer("Testserver", "Client project testserver", "vatsim-germany.org", 6809,
+ CUser("guest", "Guest Client project", "", "guest")));
+ this->m_settingsNetwork.addTrafficNetworkServer(this->m_settingsNetwork.getCurrentNetworkServer());
+ this->m_settingsNetwork.addTrafficNetworkServer(
+ CServer("Europe C2", "Real VATSIM Server", "88.198.19.202", 6809,
+ CUser("vatsimid", "Black Client", "", "vatsimpw"))
+ );
+ }
+
+ /*
+ * Network settings
+ */
+ BlackMisc::Settings::CSettingsNetwork CContextSettings::getNetworkSettings() const
+ {
+ return this->m_settingsNetwork;
+ }
+
+ /*
+ * Pass value
+ */
+ BlackMisc::CStatusMessages CContextSettings::value(const QString &path, const QString &command, const QVariant &value)
+ {
+ Q_ASSERT(path.length() > 3);
+ Q_ASSERT(path.indexOf('/') >= 0);
+ QString nextLevelPath = CSettingUtilities::removeLeadingPath(path);
+ BlackMisc::CStatusMessages msgs = CSettingUtilities::wrongPathMessages(path);
+ bool changed = false;
+ if (path.startsWith(IContextSettings::PathNetworkSettings()))
+ {
+ msgs = this->m_settingsNetwork.value(nextLevelPath, command, value, changed);
+ if (changed) emit this->changedNetworkSettings();
+ }
+ return msgs;
+ }
+
+} // namespace
diff --git a/src/blackcore/context_settings.h b/src/blackcore/context_settings.h
new file mode 100644
index 000000000..9e74ef933
--- /dev/null
+++ b/src/blackcore/context_settings.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BLACKCORE_CONTEXTSETTINGS_H
+#define BLACKCORE_CONTEXTSETTINGS_H
+
+#include "blackcore/dbus_server.h"
+#include "blackcore/context_settings_interface.h"
+#include "blackmisc/statusmessage.h"
+#include "blackmisc/statusmessages.h"
+#include
+
+#define BLACKCORE_CONTEXTSETTINGS_INTERFACENAME "blackcore.contextsettings"
+
+namespace BlackCore
+{
+ class CCoreRuntime;
+
+ /*!
+ * \brief Network context
+ */
+ class CContextSettings : public IContextSettings
+ {
+ // Register by same name, make signals sender independent
+ // http://dbus.freedesktop.org/doc/dbus-faq.html#idp48032144
+ Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTSETTINGS_INTERFACENAME)
+ Q_OBJECT
+
+ public:
+
+ /*!
+ * Context
+ * \param parent
+ */
+ CContextSettings(CCoreRuntime *parent);
+
+ /*!
+ * Destructor
+ */
+ virtual ~CContextSettings() {}
+
+ /*!
+ * \brief Register myself in DBus
+ * \param server
+ */
+ void registerWithDBus(CDBusServer *server)
+ {
+ server->addObject(IContextSettings::ServicePath(), this);
+ }
+
+ /*!
+ * \brief Runtime
+ * \return
+ */
+ const CCoreRuntime *getRuntime() const
+ {
+ return reinterpret_cast(this->parent());
+ }
+
+ public slots:
+ /*!
+ * \brief Network settings
+ * \return
+ */
+ virtual BlackMisc::Settings::CSettingsNetwork getNetworkSettings() const;
+
+ /*!
+ * \brief Validate
+ * \param path
+ * \param value
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages value(const QString &path, const QString &command, const QVariant &value);
+
+ private:
+ BlackMisc::Settings::CSettingsNetwork m_settingsNetwork;
+
+ };
+}
+
+#endif // guard
diff --git a/src/blackcore/context_settings_interface.cpp b/src/blackcore/context_settings_interface.cpp
new file mode 100644
index 000000000..48f1d148b
--- /dev/null
+++ b/src/blackcore/context_settings_interface.cpp
@@ -0,0 +1,70 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "blackcore/context_settings_interface.h"
+#include "blackmisc/blackmiscfreefunctions.h"
+#include
+#include
+#include
+
+namespace BlackCore
+{
+
+ /*
+ * Constructor for DBus
+ */
+ IContextSettings::IContextSettings(const QString &serviceName, QDBusConnection &connection, QObject *parent) : QObject(parent), m_dBusInterface(0)
+ {
+ this->m_dBusInterface = new BlackMisc::CGenericDBusInterface(
+ serviceName , IContextSettings::ServicePath(), IContextSettings::InterfaceName(),
+ connection, this);
+ this->relaySignals(serviceName, connection);
+ }
+
+ /*
+ * Workaround for unreliable signals
+ */
+ void IContextSettings::relaySignals(const QString &serviceName, QDBusConnection &connection)
+ {
+ connection.connect(serviceName, IContextSettings::ServicePath(), IContextSettings::InterfaceName(),
+ "changedNetworkSettings", this, SIGNAL(changedNetworkSettings()));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ BlackMisc::Settings::CSettingsNetwork IContextSettings::getNetworkSettings() const
+ {
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("getNetworkSettings"));
+ }
+
+ /*
+ * Relay to DBus
+ */
+ BlackMisc::CStatusMessages IContextSettings::value(const QString &path, const QString &command, const QVariant &value)
+ {
+ int type = value.userType() - BlackMisc::firstBlackMetaType();
+ return this->m_dBusInterface->callDBusRet(QLatin1Literal("value"), path, command, QDBusVariant(value), type);
+ }
+
+ /*
+ * DBus version of value
+ */
+ BlackMisc::CStatusMessages IContextSettings::value(const QString &path, const QString &command, QDBusVariant value, int unifiedBlackMetaType)
+ {
+ QVariant qv = value.variant();
+ if (qv.canConvert())
+ {
+ // convert from QDBusArgument
+ int type = BlackMisc::firstBlackMetaType() + unifiedBlackMetaType; // unify
+ qv = BlackMisc::fixQVariantFromDbusArgument(qv, type);
+ }
+ // when called locally, this will call the virtual method
+ // of the concrete implementation in context_settings
+ return this->value(path, command, qv);
+ }
+
+
+} // namespace
diff --git a/src/blackcore/context_settings_interface.h b/src/blackcore/context_settings_interface.h
new file mode 100644
index 000000000..30bab6af9
--- /dev/null
+++ b/src/blackcore/context_settings_interface.h
@@ -0,0 +1,136 @@
+/* Copyright (C) 2013 VATSIM Community / authors
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BLACKCORE_CONTEXTSETTINGS_INTERFACE_H
+#define BLACKCORE_CONTEXTSETTINGS_INTERFACE_H
+
+#include "blackmisc/statusmessages.h"
+#include "blackmisc/genericdbusinterface.h"
+#include "blackmisc/settingutilities.h"
+#include "blackmisc/setnetwork.h"
+#include
+#include
+#include
+
+#define BLACKCORE_CONTEXTSETTINGS_INTERFACENAME "blackcore.contextsettings"
+#define BLACKCORE_CONTEXTSETTINGS_SERVICEPATH "/settings"
+
+// SERVICENAME must contain at least one ".", otherwise generation fails
+// as this is interpreted in the way comain.somename
+
+namespace BlackCore
+{
+
+ /*!
+ * \brief The IContextSettings class
+ */
+ class IContextSettings : public QObject
+ {
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", BLACKCORE_CONTEXTSETTINGS_INTERFACENAME)
+
+ public:
+
+ /*!
+ * \brief Service name
+ * \return
+ */
+ static const QString &InterfaceName()
+ {
+ static QString s(BLACKCORE_CONTEXTSETTINGS_INTERFACENAME);
+ return s;
+ }
+
+ /*!
+ * \brief Service path
+ * \return
+ */
+ static const QString &ServicePath()
+ {
+ static QString s(BLACKCORE_CONTEXTSETTINGS_SERVICEPATH);
+ return s;
+ }
+
+ /*!
+ * \brief Path
+ * \return
+ */
+ static const QString &PathNetworkSettings()
+ {
+ static QString s("network");
+ return s;
+ }
+
+ /*!
+ * \brief DBus version constructor
+ * \param serviceName
+ * \param connection
+ * \param parent
+ */
+ IContextSettings(const QString &serviceName, QDBusConnection &connection, QObject *parent = 0);
+
+ /*!
+ * Destructor
+ */
+ ~IContextSettings() {}
+
+ private:
+ BlackMisc::CGenericDBusInterface *m_dBusInterface;
+
+ /*!
+ * \brief Relay connection signals to local signals
+ * No idea why this has to be wired and is not done automatically
+ * \param connection
+ */
+ void relaySignals(const QString &serviceName, QDBusConnection &connection);
+
+ protected:
+ /*!
+ * \brief IContextSettings
+ * \param parent
+ */
+ IContextSettings(QObject *parent = 0) : QObject(parent), m_dBusInterface(0) {}
+
+ signals:
+
+ /*!
+ * \brief Settings have been changed
+ */
+ void changedNetworkSettings();
+
+ public slots:
+
+ /*!
+ * \brief Network settings
+ * \return
+ */
+ virtual BlackMisc::Settings::CSettingsNetwork getNetworkSettings() const;
+
+ /*!
+ * \brief Handle value
+ * \param path
+ * \param command
+ * \param value
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages value(const QString &path, const QString &command, const QVariant &value);
+
+ /*!
+ * Basically an unwanted signature as this is different from the "local" signature and
+ * contains explicit DBus types (a: QDbusArgument, b: type for conversion).
+ * If this can be removed, fine.
+ *
+ * \brief value
+ * \param path
+ * \param command
+ * \param value
+ * \param unifiedBlackMetaType
+ * \return
+ */
+ virtual BlackMisc::CStatusMessages value(const QString &path, const QString &command, QDBusVariant value, int unifiedBlackMetaType);
+ };
+}
+
+#endif // guard
diff --git a/src/blackcore/coreruntime.cpp b/src/blackcore/coreruntime.cpp
new file mode 100644
index 000000000..fd6c67f74
--- /dev/null
+++ b/src/blackcore/coreruntime.cpp
@@ -0,0 +1,42 @@
+#include "blackcore/coreruntime.h"
+#include "blackmisc/blackmiscfreefunctions.h"
+#include "blackmisc/nwserver.h"
+
+namespace BlackCore
+{
+ /*
+ * Constructor
+ */
+ CCoreRuntime::CCoreRuntime(bool withDbus, QObject *parent) :
+ QObject(parent), m_init(false), m_dbusServer(nullptr), m_contextNetwork(nullptr), m_settings(nullptr)
+ {
+ this->init(withDbus);
+ }
+
+ /*
+ * Init runtime
+ */
+ void CCoreRuntime::init(bool withDbus)
+ {
+ if (m_init) return;
+ BlackMisc::registerMetadata();
+ BlackMisc::initResources();
+
+ // TODO: read settings
+ if (withDbus)
+ {
+ QString dBusAddress = "session";
+ this->m_dbusServer = new CDBusServer(dBusAddress, this);
+ }
+
+ // contexts
+ this->m_settings = new CContextSettings(this);
+ if (withDbus) this->m_settings->registerWithDBus(this->m_dbusServer);
+
+ this->m_contextNetwork = new CContextNetwork(this);
+ if (withDbus) this->m_contextNetwork->registerWithDBus(this->m_dbusServer); // complete object after init
+
+ // flag
+ m_init = true;
+ }
+}
diff --git a/src/blackcore/coreruntime.h b/src/blackcore/coreruntime.h
new file mode 100644
index 000000000..7c5fc48e9
--- /dev/null
+++ b/src/blackcore/coreruntime.h
@@ -0,0 +1,90 @@
+#ifndef BLACKCORE_CORERUNTIME_H
+#define BLACKCORE_CORERUNTIME_H
+
+#include
+#include "dbus_server.h"
+#include "context_network.h"
+#include "context_settings.h"
+
+namespace BlackCore
+{
+ /*!
+ * \brief The CCoreRuntime class
+ */
+ class CCoreRuntime : public QObject
+ {
+ Q_OBJECT
+
+ private:
+ bool m_init; /*!< flag */
+ CDBusServer *m_dbusServer;
+ CContextNetwork *m_contextNetwork;
+ CContextSettings *m_settings;
+
+ /*!
+ * \brief Init
+ * \param withDbus
+ */
+ void init(bool withDbus);
+
+ public:
+ /*!
+ * \brief Constructor
+ * \param withDbus
+ * \param parent
+ */
+ CCoreRuntime(bool withDbus = true, QObject *parent = nullptr);
+
+ /*!
+ * \brief Destructor
+ */
+ virtual ~CCoreRuntime() {}
+
+ /*!
+ * \brief DBus server
+ * \return
+ */
+ const CDBusServer *getDBusServer() const
+ {
+ return this->m_dbusServer;
+ }
+
+ /*!
+ * \brief Context for network
+ * \return
+ */
+ IContextNetwork *getIContextNetwork()
+ {
+ return this->m_contextNetwork;
+ }
+
+ /*!
+ * \brief Context for network
+ * \return
+ */
+ const IContextNetwork *getIContextNetwork() const
+ {
+ return this->m_contextNetwork;
+ }
+
+ /*!
+ * \brief Settings
+ * \return
+ */
+ IContextSettings *getIContextSettings()
+ {
+ return this->m_settings;
+ }
+
+ /*!
+ * \brief Settings
+ * \return
+ */
+ const IContextSettings *getIContextSettings() const
+ {
+ return this->m_settings;
+ }
+
+ };
+}
+#endif // guard
diff --git a/src/blackcore/dbus_server.cpp b/src/blackcore/dbus_server.cpp
index 9af3b339f..5e1071419 100644
--- a/src/blackcore/dbus_server.cpp
+++ b/src/blackcore/dbus_server.cpp
@@ -4,53 +4,155 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include
+#include
#include "dbus_server.h"
namespace BlackCore
{
+ const QString CDBusServer::ServiceName = QString(BLACKCORE_DBUSERVER_SERVICENAME);
+
+ /*
+ * Constructor
+ * Remark, without the default "unix:tmpdir=/tmp" any refereal to address crashes
+ * see http://download.froglogic.com/public/qt5-squishcoco-report/QtBase/source_241_preprocessed.html
+ */
CDBusServer::CDBusServer(const QString &address, QObject *parent) :
- QObject(parent), m_busServer(address, parent)
+ QObject(parent), m_busServer(CDBusServer::isP2P(address) ? address : "unix:tmpdir=/tmp" , parent), m_serverMode(CDBusServer::SERVERMODE_P2P)
{
- if (!m_busServer.isConnected())
+ if (address.isEmpty() || address.toLower() == "session")
{
- qWarning() << m_busServer.lastError().message();
+ // we use a session bus connection instead of a real P2P connection
+ this->m_serverMode = CDBusServer::SERVERMODE_SESSIONBUS;
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ if (!con.registerService(CDBusServer::ServiceName))
+ {
+ qFatal("Cannot register DBus service");
+ }
+ this->newConnection(con);
+ }
+ else if (address.toLower() == "system")
+ {
+ // we use a system bus connection instead of a real P2P connection
+ this->m_serverMode = CDBusServer::SERVERMODE_SYSTEMBUS;
+ QDBusConnection con = QDBusConnection::systemBus();
+ if (!con.registerService(CDBusServer::ServiceName))
+ {
+ qFatal("Cannot register DBus service");
+ }
+ this->newConnection(con);
}
else
{
- qDebug() << "Server listening on address: " << m_busServer.address();
+ this->m_serverMode = CDBusServer::SERVERMODE_P2P;
+ // Note: P2P has no service name
+ if (!m_busServer.isConnected())
+ {
+ qWarning() << m_busServer.lastError().message();
+ }
+ else
+ {
+ qDebug() << "Server listening on address: " << m_busServer.address();
+ }
+ connect(&m_busServer, &QDBusServer::newConnection, this, &CDBusServer::newConnection);
}
-
- connect(&m_busServer, &QDBusServer::newConnection, this, &CDBusServer::newConnection);
}
- void CDBusServer::newConnection(const QDBusConnection & connection)
+ /*
+ * Check for P2P address
+ */
+ bool CDBusServer::isP2P(const QString &address)
{
- QMap::ConstIterator i = m_objects.begin();
+ return !(address.isEmpty() || address.toLower() == "session" || address.toLower() == "system");
+ }
+
+ /*
+ * Class info
+ */
+ const QString CDBusServer::getClassInfo(QObject *object)
+ {
+ if (!object) return "";
+ const QMetaObject *mo = object->metaObject();
+ if (mo->classInfoCount() < 1) return "";
+ for (int i = 0; i < mo->classInfoCount(); i++)
+ {
+ QMetaClassInfo ci = mo->classInfo(i);
+ QString name(ci.name());
+ if (name == "D-Bus Interface") return QString(ci.value());
+ }
+ return "";
+ }
+
+ /*
+ * Connection established
+ */
+ bool CDBusServer::newConnection(const QDBusConnection &connection)
+ {
+ QMap::ConstIterator i = m_objects.begin();
QDBusConnection newConnection(connection);
-
m_DBusConnections.insert(newConnection.name(), newConnection);
-
+ bool success = true;
qDebug() << "New Connection from: " << newConnection.name();
while (i != m_objects.end())
{
- qDebug() << "Adding " << i.key() << "to the new connection.";
- newConnection.registerObject(i.key(), i.value());
+ qDebug() << "Adding " << i.key() << CDBusServer::getClassInfo(i.value()) << "to the new connection.";
+ bool ok = newConnection.registerObject(i.key(), i.value(), CDBusServer::RegisterOptions());
+ Q_ASSERT_X(ok, "CDBusServer::newConnection", "Registration failed");
+ if (!ok) success = false;
++i;
}
+
+ return success;
}
- void CDBusServer::addObject(const QString &name, QObject *object)
+ /*
+ * Add the objects
+ */
+ void CDBusServer::addObject(const QString &path, QObject *object)
{
- m_objects.insert(name, object);
+ if (!object) return;
+ m_objects.insert(path, object); // this will be added when connection is established
+
+ if (this->m_serverMode == CDBusServer::SERVERMODE_P2P) return;
+
+ bool success = false;
+ if (this->m_serverMode == CDBusServer::SERVERMODE_SESSIONBUS)
+ {
+ success = QDBusConnection::sessionBus().registerObject(path, object, CDBusServer::RegisterOptions());
+ qDebug() << "Adding " << path << CDBusServer::getClassInfo(object) << "to the session bus.";
+ if (!success) qDebug() << "Error, no success with registration" << this->lastError().message();
+ }
+ else if (this->m_serverMode == CDBusServer::SERVERMODE_SYSTEMBUS)
+ {
+ success = QDBusConnection::systemBus().registerObject(path, object, CDBusServer::RegisterOptions());
+ qDebug() << "Adding " << path << CDBusServer::getClassInfo(object) << "to the system bus.";
+ if (!success) qDebug() << "Error, no success with registration" << this->lastError().message();
+ }
+ else
+ {
+ Q_ASSERT_X(false, "CDBusServer::addObject", "Wrong server mode");
+ }
+ // Q_ASSERT_X(success, "CDBusServer::addObject", "Registration failed");
}
- void CDBusServer::printError()
+ /*
+ * Print last error message
+ */
+ void CDBusServer::printError() const
{
qWarning() << m_busServer.lastError().name();
}
+ /*
+ * Last error
+ */
+ QDBusError CDBusServer::lastError() const
+ {
+ return this->m_busServer.lastError();
+ }
+
} // namespace BlackCore
diff --git a/src/blackcore/dbus_server.h b/src/blackcore/dbus_server.h
index 3c9068cd8..9bd0c2429 100644
--- a/src/blackcore/dbus_server.h
+++ b/src/blackcore/dbus_server.h
@@ -6,6 +6,7 @@
#ifndef BLACKCORE_DBUSSERVER_H
#define BLACKCORE_DBUSSERVER_H
+#include "blackmisc/valueobject.h" // for qHash overload, include before Qt stuff due GCC issue
#include
#include
#include
@@ -13,52 +14,147 @@
#include
#include
-namespace BlackCore {
+#define BLACKCORE_DBUSERVER_SERVICENAME "org.vatsim.pilotClient"
- /*!
- * \brief Custom DBusServer
- * \details This class implements a custom DBusServer for DBus peer connections
- */
+namespace BlackCore
+{
+
+ /*!
+ * \brief Custom DBusServer
+ * \details This class implements a custom DBusServer for DBus peer connections
+ */
class CDBusServer : public QObject
- {
- Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "org.vatsim.pilotClient")
+ {
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", BLACKCORE_DBUSERVER_SERVICENAME)
- private:
- QDBusServer m_busServer; //!< QDBusServer implementation
+ public:
+ static const QString ServiceName;
- QMap m_objects; //!< Mapping of all exposed objects
+ /*!
+ * \brief Server mode, normally P2P, but can be changed for debugging / testing
+ */
+ enum ServerMode
+ {
+ SERVERMODE_P2P,
+ SERVERMODE_SESSIONBUS,
+ SERVERMODE_SYSTEMBUS
+ };
- QMap m_DBusConnections; //!< Mapping of all DBusConnection objects
+ private:
+ QDBusServer m_busServer; //!< QDBusServer implementation
+ ServerMode m_serverMode;
+ QMap m_objects; //!< Mapping of all exposed objects
+ QMap m_DBusConnections; //!< Mapping of all DBusConnection objects
- public:
+ /*!
+ * \brief Check if address means a real server with P2P connection
+ * \param address
+ * \return
+ */
+ static bool isP2P(const QString &address);
- /*!
- * \brief Constructor
- * \param parent
- */
+ /*!
+ * \brief Get the class info
+ * \param object
+ * \return
+ */
+ static const QString getClassInfo(QObject *object);
+
+ /*!
+ * \brief Register options with connection
+ * \return
+ */
+ static const QDBusConnection::RegisterOptions &RegisterOptions()
+ {
+ static QDBusConnection::RegisterOptions opt = QDBusConnection::ExportAdaptors | QDBusConnection::ExportAllSignals | QDBusConnection::ExportAllSlots;
+ return opt;
+ }
+
+ public:
+ /*!
+ * \brief Constructor
+ * \param parent
+ */
CDBusServer(const QString &address, QObject *parent = 0);
- /*!
- * \brief Adds a QObject to be exposed to DBus
- * \param name
- * \param object
- */
- void addObject(const QString &name, QObject *object);
+ /*!
+ * \brief Adds a QObject to be exposed to DBus
+ * \param name
+ * \param object
+ */
+ void addObject(const QString &name, QObject *object);
- void printError();
+ /*!
+ * \brief printError
+ */
+ void printError() const;
- public slots:
+ /*!
+ * \brief Last error
+ * \return
+ */
+ QDBusError lastError() const;
- /*!
- * \brief Called when a new DBus client has connected
- * \param connection
- */
- void newConnection(const QDBusConnection & connection);
- signals:
- };
+ /*!
+ * \brief Connected?
+ * \return
+ */
+ bool isConnected() const
+ {
+ return this->m_busServer.isConnected();
+ }
+ /*!
+ * \brief address
+ * \return
+ */
+ QString address() const
+ {
+
+ return this->m_busServer.address();
+ }
+
+ /*!
+ * \brief Connection by name
+ * \param connectionName
+ * \return
+ */
+ const QDBusConnection getDbusConnection(const QString &connectionName) const
+ {
+ return this->m_DBusConnections.value(connectionName, CDBusServer::defaultConnection());
+ }
+
+ /*!
+ * \brief Get DBbus connections
+ * \return
+ */
+ const QList getDbusConnections() const
+ {
+ // http://stackoverflow.com/questions/1124340/any-ideas-why-qhash-and-qmap-return-const-t-instead-of-const-t
+ return this->m_DBusConnections.values();
+ }
+
+ /*!
+ * \brief Default connection
+ * \return
+ */
+ static const QDBusConnection &defaultConnection()
+ {
+ static QDBusConnection defaultConnection("default");
+ return defaultConnection;
+ }
+
+ private slots:
+
+ /*!
+ * \brief Called when a new DBus client has connected
+ * \param connection
+ * \return
+ */
+ bool newConnection(const QDBusConnection &connection);
+ };
}
-#endif // DBUSSERVER_H
+#endif // guard
diff --git a/src/blackcore/readme.txt b/src/blackcore/readme.txt
new file mode 100644
index 000000000..5b9adacb9
--- /dev/null
+++ b/src/blackcore/readme.txt
@@ -0,0 +1,27 @@
+Starting: dbus-daemon.exe --session
+- blocks CMD (sometimes daemon continues to run when pressing CTRL/C)
+- does not start without directory session.d, i.e. ..\Qt\Qt5.1.0DBus\qtbase\etc\dbus-1\session.d
+
+!!! The includes are set in the qmake file, there are the header files
+!!! which are used in the interface
+/// qdbuscpp2xml context_network.h -x blackmisc_cpp2xml.dll -o blackcore.contextnetwork.xml
+qdbuscpp2xml context_network_interface.h -x blackmisc_cpp2xml.dll -o blackcore.contextnetwork.xml
+qdbuscpp2xml context_settings_interface.h -x blackmisc_cpp2xml.dll -o blackcore.contextsettings.xml
+
+Set search path for plugins: env.var. QT_PLUGIN_PATH
+
+Done automatically (qmake), but if required manually
+Interface:
+qdbusxml2cpp -i blackmisc/blackmiscfreefunctions.h -i blackmisc/blackmiscallvalueclasses.h -p contextnetwork_interface.h: H:\Projects\Qt\VatsimClient\client\src\blackcore\blackcore.contextnetwork.xml
+qdbusxml2cpp -i contextnetwork_interface.h -p :contextnetwork_interface.cpp H:\Projects\Qt\VatsimClient\client\src\blackcore\blackcore.contextnetwork.xml
+
+The : indicates generation of cpp file
+
+Adaptor:
+qdbusxml2cpp -i blackmisc/blackmiscfreefunctions.h -i blackmisc/blackmiscallvalueclasses.h -a contextnetwork_adaptor.h blackcore.contextnetwork.xml
+qdbusxml2cpp -i context_adaptor.h -a :contextnetwork_adaptor.cpp blackcore.contextnetwork.xml
+
+
+Manually:
+
+
diff --git a/src/blackmisc/genericdbusinterface.h b/src/blackmisc/genericdbusinterface.h
new file mode 100644
index 000000000..5309cef6c
--- /dev/null
+++ b/src/blackmisc/genericdbusinterface.h
@@ -0,0 +1,181 @@
+#ifndef BLACKMISC_GENERICDBUSINTERFACE_H
+#define BLACKMISC_GENERICDBUSINTERFACE_H
+
+#include
+#include
+#include
+
+
+namespace BlackMisc
+{
+
+#include
+
+ /*!
+ * Used for hand written interface based on virtual methods.
+ * Allows to relay a message to DBus in a single code line
+ */
+ class CGenericDBusInterface : public QDBusAbstractInterface
+ {
+
+ public:
+
+ /*!
+ * \brief Generic DBus interface
+ * \param serverName
+ * \param path
+ * \param interfaceName
+ * \param connection
+ * \param parent
+ */
+ CGenericDBusInterface(const QString &serverName, const QString &path, const QString &interfaceName, const QDBusConnection &connection, QObject *parent = 0) :
+ QDBusAbstractInterface(serverName, path, interfaceName.toUtf8().constData(), connection, parent)
+ {
+ // void
+ }
+
+ /*!
+ * \brief Call DBus
+ * \param method
+ */
+ void callDBus(const QLatin1String &method)
+ {
+ QList argumentList;
+ this->asyncCallWithArgumentList(method, argumentList);
+ }
+
+ /*!
+ * \brief Call DBus, no return value
+ * \param method
+ * \param p1
+ * \return
+ */
+ template void callDBus(const QLatin1String &method, P1 p1)
+ {
+ QList argumentList;
+ argumentList << QVariant::fromValue(p1);
+ this->asyncCallWithArgumentList(method, argumentList);
+ }
+
+ /*!
+ * \brief Call DBus, no return value
+ * \param method
+ * \param p1
+ * \param p2
+ * \return
+ */
+ template void callDBus(const QLatin1String &method, P1 p1, P2 p2)
+ {
+ QList argumentList;
+ argumentList << QVariant::fromValue(p1) << QVariant::fromValue(p2);
+ this->asyncCallWithArgumentList(method, argumentList);
+ }
+
+ /*!
+ * \brief Call DBus, no return value
+ * \param method
+ * \param p1
+ * \param p2
+ * \param p3
+ * \return
+ */
+ template void callDBus(const QLatin1String &method, P1 p1, P2 p2, P3 p3)
+ {
+ QList argumentList;
+ argumentList << QVariant::fromValue(p1) << QVariant::fromValue(p2) << QVariant::fromValue(p3);
+ this->asyncCallWithArgumentList(method, argumentList);
+ }
+
+ /*!
+ * \brief Call DBus, no return value
+ * \param method
+ * \param p1
+ * \param p2
+ * \param p3
+ * \param p4
+ * \return
+ */
+ template void callDBus(const QLatin1String &method, P1 p1, P2 p2, P3 p3, P4 p4)
+ {
+ QList argumentList;
+ argumentList << QVariant::fromValue(p1) << QVariant::fromValue(p2) << QVariant::fromValue(p3) << QVariant::fromValue(p4);
+ this->asyncCallWithArgumentList(method, argumentList);
+ }
+
+ /*!
+ * \brief Call DBus with return value
+ * \param method
+ * \return
+ */
+ template Ret callDBusRet(const QLatin1String &method)
+ {
+ QList argumentList;
+ QDBusPendingReply pr = this->asyncCallWithArgumentList(method, argumentList);
+ return pr;
+ }
+
+ /*!
+ * \brief Call DBus with return value
+ * \param method
+ * \param p1
+ * \return
+ */
+ template Ret callDBusRet(const QLatin1String &method, P1 p1)
+ {
+ QList argumentList;
+ argumentList << QVariant::fromValue(p1);
+ QDBusPendingReply pr = this->asyncCallWithArgumentList(method, argumentList);
+ return pr;
+ }
+
+ /*!
+ * \brief Call DBus with return value
+ * \param method
+ * \param p1
+ * \param p2
+ * \return
+ */
+ template Ret callDBusRet(const QLatin1String &method, P1 p1, P2 p2)
+ {
+ QList argumentList;
+ argumentList << QVariant::fromValue(p1) << QVariant::fromValue(p2);
+ QDBusPendingReply pr = this->asyncCallWithArgumentList(method, argumentList);
+ return pr;
+ }
+
+ /*!
+ * \brief Call DBus with return value
+ * \param method
+ * \param p1
+ * \param p2
+ * \param p3
+ * \return
+ */
+ template Ret callDBusRet(const QLatin1String &method, P1 p1, P2 p2, P3 p3)
+ {
+ QList argumentList;
+ argumentList << QVariant::fromValue(p1) << QVariant::fromValue(p2) << QVariant::fromValue(p3);
+ QDBusPendingReply pr = this->asyncCallWithArgumentList(method, argumentList);
+ return pr;
+ }
+
+ /*!
+ * \brief Call DBus with return value
+ * \param method
+ * \param p1
+ * \param p2
+ * \param p3
+ * \param p4
+ * \return
+ */
+ template Ret callDBusRet(const QLatin1String &method, P1 p1, P2 p2, P3 p3, P4 p4)
+ {
+ QList argumentList;
+ argumentList << QVariant::fromValue(p1) << QVariant::fromValue(p2) << QVariant::fromValue(p3) << QVariant::fromValue(p4);
+ QDBusPendingReply pr = this->asyncCallWithArgumentList(method, argumentList);
+ return pr;
+ }
+ };
+}
+
+#endif // guard