diff --git a/src/AndroidManifest.xml.in b/src/AndroidManifest.xml.in index 0da0b3d7f..74dc46a19 100644 --- a/src/AndroidManifest.xml.in +++ b/src/AndroidManifest.xml.in @@ -156,7 +156,7 @@ - + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d7cd24063..eee8b9fd6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -544,6 +544,8 @@ qt_add_qml_module(${PROJECT_NAME} URI akaflieg_freiburg.enroute VERSION 1.0 NO_RESOURCE_TARGET_PATH + DEPENDENCIES + QtQuick QML_FILES qml/main.qml qml/dialogs/AddBTDeviceDialog.qml @@ -624,7 +626,6 @@ qt_add_qml_module(${PROJECT_NAME} traffic/TrafficDataProvider_BluetoothLowEnergy.cpp ) - # # Translations # diff --git a/src/GlobalSettings.cpp b/src/GlobalSettings.cpp index 7a7361183..b90ace337 100644 --- a/src/GlobalSettings.cpp +++ b/src/GlobalSettings.cpp @@ -35,17 +35,20 @@ GlobalSettings::GlobalSettings(QObject *parent) QCoreApplication::processEvents(); // Save some values - settings.setValue(QStringLiteral("lastVersion"), ENROUTE_VERSION_STRING); + m_settings.setValue(QStringLiteral("lastVersion"), ENROUTE_VERSION_STRING); + + // Read values + m_positioningByTrafficDataReceiver = m_settings.value(QStringLiteral("positioningByTrafficDataReceiver"), false).toBool(); // Convert old setting to new system - if (settings.contains(QStringLiteral("Map/hideUpperAirspaces"))) { - auto hide = settings.value(QStringLiteral("Map/hideUpperAirspaces"), false).toBool(); + if (m_settings.contains(QStringLiteral("Map/hideUpperAirspaces"))) { + auto hide = m_settings.value(QStringLiteral("Map/hideUpperAirspaces"), false).toBool(); if (hide) { setAirspaceAltitudeLimit( Units::Distance::fromFT(10000) ); } else { setAirspaceAltitudeLimit( Units::Distance::fromFT(qInf()) ); } - settings.remove(QStringLiteral("Map/hideUpperAirspaces")); + m_settings.remove(QStringLiteral("Map/hideUpperAirspaces")); } } @@ -56,7 +59,7 @@ GlobalSettings::GlobalSettings(QObject *parent) auto GlobalSettings::airspaceAltitudeLimit() const -> Units::Distance { - auto aspAlttLimit = Units::Distance::fromFT( settings.value(QStringLiteral("Map/airspaceAltitudeLimit_ft"), qQNaN()).toDouble() ); + auto aspAlttLimit = Units::Distance::fromFT( m_settings.value(QStringLiteral("Map/airspaceAltitudeLimit_ft"), qQNaN()).toDouble() ); if (aspAlttLimit < airspaceAltitudeLimit_min) { aspAlttLimit = airspaceAltitudeLimit_min; } @@ -69,21 +72,21 @@ auto GlobalSettings::airspaceAltitudeLimit() const -> Units::Distance auto GlobalSettings::fontSize() const -> int { - auto fontSize = settings.value(QStringLiteral("fontSize"), 14).toInt(); + auto fontSize = m_settings.value(QStringLiteral("fontSize"), 14).toInt(); return qBound(14, fontSize, 20); } auto GlobalSettings::lastValidAirspaceAltitudeLimit() const -> Units::Distance { - auto result = Units::Distance::fromFT(settings.value(QStringLiteral("Map/lastValidAirspaceAltitudeLimit_ft"), 99999).toInt() ); + auto result = Units::Distance::fromFT(m_settings.value(QStringLiteral("Map/lastValidAirspaceAltitudeLimit_ft"), 99999).toInt() ); return qBound(airspaceAltitudeLimit_min, result, airspaceAltitudeLimit_max); } auto GlobalSettings::mapBearingPolicy() const -> GlobalSettings::MapBearingPolicy { - auto intVal = settings.value(QStringLiteral("Map/bearingPolicy"), 0).toInt(); + auto intVal = m_settings.value(QStringLiteral("Map/bearingPolicy"), 0).toInt(); if (intVal == 0) { return NUp; } @@ -103,7 +106,7 @@ void GlobalSettings::setAcceptedTerms(int terms) if (terms == acceptedTerms()) { return; } - settings.setValue(QStringLiteral("acceptedTerms"), terms); + m_settings.setValue(QStringLiteral("acceptedTerms"), terms); emit acceptedTermsChanged(); } @@ -113,7 +116,7 @@ void GlobalSettings::setAlwaysOpenExternalWebsites(bool alwaysOpen) if (alwaysOpen == alwaysOpenExternalWebsites()) { return; } - settings.setValue(QStringLiteral("alwaysOpenExternalWebsites"), alwaysOpen); + m_settings.setValue(QStringLiteral("alwaysOpenExternalWebsites"), alwaysOpen); emit alwaysOpenExternalWebsitesChanged(); } @@ -128,13 +131,13 @@ void GlobalSettings::setAirspaceAltitudeLimit(Units::Distance newAirspaceAltitud } if (newAirspaceAltitudeLimit != airspaceAltitudeLimit()) { - settings.setValue(QStringLiteral("Map/airspaceAltitudeLimit_ft"), newAirspaceAltitudeLimit.toFeet()); + m_settings.setValue(QStringLiteral("Map/airspaceAltitudeLimit_ft"), newAirspaceAltitudeLimit.toFeet()); emit airspaceAltitudeLimitChanged(); } if (newAirspaceAltitudeLimit.isFinite() && (newAirspaceAltitudeLimit != lastValidAirspaceAltitudeLimit())) { - settings.setValue(QStringLiteral("Map/lastValidAirspaceAltitudeLimit_ft"), newAirspaceAltitudeLimit.toFeet()); + m_settings.setValue(QStringLiteral("Map/lastValidAirspaceAltitudeLimit_ft"), newAirspaceAltitudeLimit.toFeet()); emit lastValidAirspaceAltitudeLimitChanged(); } } @@ -146,7 +149,7 @@ void GlobalSettings::setExpandNotamAbbreviations(bool newExpandNotamAbbreviation { return; } - settings.setValue(QStringLiteral("expandNotamAbbreviations"), newExpandNotamAbbreviations); + m_settings.setValue(QStringLiteral("expandNotamAbbreviations"), newExpandNotamAbbreviations); emit expandNotamAbbreviationsChanged(); } @@ -160,7 +163,7 @@ void GlobalSettings::setFontSize(int newFontSize) { return; } - settings.setValue(QStringLiteral("fontSize"), newFontSize); + m_settings.setValue(QStringLiteral("fontSize"), newFontSize); emit fontSizeChanged(); } @@ -171,7 +174,7 @@ void GlobalSettings::setHideGlidingSectors(bool hide) { return; } - settings.setValue(QStringLiteral("Map/hideGlidingSectors"), hide); + m_settings.setValue(QStringLiteral("Map/hideGlidingSectors"), hide); emit hideGlidingSectorsChanged(); } @@ -182,7 +185,7 @@ void GlobalSettings::setIgnoreSSLProblems(bool ignore) { return; } - settings.setValue(QStringLiteral("ignoreSSLProblems"), ignore); + m_settings.setValue(QStringLiteral("ignoreSSLProblems"), ignore); emit ignoreSSLProblemsChanged(); } @@ -193,7 +196,7 @@ void GlobalSettings::setLastWhatsNewHash(Units::ByteSize lwnh) { return; } - settings.setValue(QStringLiteral("lastWhatsNewHash"), QVariant::fromValue((size_t)lwnh)); + m_settings.setValue(QStringLiteral("lastWhatsNewHash"), QVariant::fromValue((size_t)lwnh)); emit lastWhatsNewHashChanged(); } @@ -204,7 +207,7 @@ void GlobalSettings::setLastWhatsNewInMapsHash(Units::ByteSize lwnh) { return; } - settings.setValue(QStringLiteral("lastWhatsNewInMapsHash"), QVariant::fromValue((size_t)lwnh)); + m_settings.setValue(QStringLiteral("lastWhatsNewInMapsHash"), QVariant::fromValue((size_t)lwnh)); emit lastWhatsNewInMapsHashChanged(); } @@ -215,7 +218,7 @@ void GlobalSettings::setPrivacyHash(Units::ByteSize newHash) { return; } - settings.setValue(QStringLiteral("privacyHash"), QVariant::fromValue((size_t)newHash)); + m_settings.setValue(QStringLiteral("privacyHash"), QVariant::fromValue((size_t)newHash)); emit privacyHashChanged(); } @@ -229,13 +232,13 @@ void GlobalSettings::setMapBearingPolicy(MapBearingPolicy policy) switch(policy){ case NUp: - settings.setValue(QStringLiteral("Map/bearingPolicy"), 0); + m_settings.setValue(QStringLiteral("Map/bearingPolicy"), 0); break; case TTUp: - settings.setValue(QStringLiteral("Map/bearingPolicy"), 1); + m_settings.setValue(QStringLiteral("Map/bearingPolicy"), 1); break; default: - settings.setValue(QStringLiteral("Map/bearingPolicy"), 2); + m_settings.setValue(QStringLiteral("Map/bearingPolicy"), 2); break; } emit mapBearingPolicyChanged(); @@ -249,20 +252,15 @@ void GlobalSettings::setNightMode(bool newNightMode) return; } - settings.setValue(QStringLiteral("Map/nightMode"), newNightMode); + m_settings.setValue(QStringLiteral("Map/nightMode"), newNightMode); emit nightModeChanged(); } void GlobalSettings::setPositioningByTrafficDataReceiver(bool newPositioningByTrafficDataReceiver) { - if (newPositioningByTrafficDataReceiver == positioningByTrafficDataReceiver()) - { - return; - } - - settings.setValue(QStringLiteral("positioningByTrafficDataReceiver"), newPositioningByTrafficDataReceiver); - emit positioningByTrafficDataReceiverChanged(); + m_settings.setValue(QStringLiteral("positioningByTrafficDataReceiver"), newPositioningByTrafficDataReceiver); + m_positioningByTrafficDataReceiver = newPositioningByTrafficDataReceiver; } @@ -272,7 +270,7 @@ void GlobalSettings::setShowAltitudeAGL(bool newShowAltitudeAGL) { return; } - settings.setValue(QStringLiteral("showAltitudeAGL"), newShowAltitudeAGL); + m_settings.setValue(QStringLiteral("showAltitudeAGL"), newShowAltitudeAGL); emit showAltitudeAGLChanged(); } @@ -283,6 +281,6 @@ void GlobalSettings::setVoiceNotifications(uint newVoiceNotifications) { return; } - settings.setValue(QStringLiteral("voiceNotifications"), newVoiceNotifications); + m_settings.setValue(QStringLiteral("voiceNotifications"), newVoiceNotifications); emit voiceNotificationsChanged(); } diff --git a/src/GlobalSettings.h b/src/GlobalSettings.h index e55264b98..5ce5acc0c 100644 --- a/src/GlobalSettings.h +++ b/src/GlobalSettings.h @@ -20,6 +20,7 @@ #pragma once +#include #include #include @@ -155,6 +156,9 @@ class GlobalSettings : public QObject /*! \brief Night mode */ Q_PROPERTY(bool nightMode READ nightMode WRITE setNightMode NOTIFY nightModeChanged) + /*! \brief Use traffic data receiver for positioning */ + Q_PROPERTY(bool positioningByTrafficDataReceiver READ positioningByTrafficDataReceiver WRITE setPositioningByTrafficDataReceiver BINDABLE bindablePositioningByTrafficDataReceiver) + /*! \brief Hash of the last "privacy" message that was accepted by the user * * This property is used in the app to determine if the message has been @@ -165,9 +169,6 @@ class GlobalSettings : public QObject /*! \brief Show Altitude AGL */ Q_PROPERTY(bool showAltitudeAGL READ showAltitudeAGL WRITE setShowAltitudeAGL NOTIFY showAltitudeAGLChanged) - /*! \brief Use traffic data receiver for positioning */ - Q_PROPERTY(bool positioningByTrafficDataReceiver READ positioningByTrafficDataReceiver WRITE setPositioningByTrafficDataReceiver NOTIFY positioningByTrafficDataReceiverChanged) - /*! \brief Voice notifications that should be played * * This property is an "or" of the entries of Notifications::Notification::Importance. It determines @@ -184,13 +185,13 @@ class GlobalSettings : public QObject * * @returns Property acceptedTerms */ - [[nodiscard]] auto acceptedTerms() const -> int { return settings.value(QStringLiteral("acceptedTerms"), 0).toInt(); } + [[nodiscard]] auto acceptedTerms() const -> int { return m_settings.value(QStringLiteral("acceptedTerms"), 0).toInt(); } /*! \brief Getter function for property of the same name * * @returns Property alwaysOpenExternalWebsites */ - [[nodiscard]] bool alwaysOpenExternalWebsites() const { return settings.value(QStringLiteral("alwaysOpenExternalWebsites"), false).toBool(); } + [[nodiscard]] bool alwaysOpenExternalWebsites() const { return m_settings.value(QStringLiteral("alwaysOpenExternalWebsites"), false).toBool(); } /*! \brief Getter function for property of the same name * @@ -202,7 +203,7 @@ class GlobalSettings : public QObject * * @returns Property expandNotamAbbreviations */ - [[nodiscard]] bool expandNotamAbbreviations() const { return settings.value(QStringLiteral("expandNotamAbbreviations"), false).toBool(); } + [[nodiscard]] bool expandNotamAbbreviations() const { return m_settings.value(QStringLiteral("expandNotamAbbreviations"), false).toBool(); } /*! \brief Getter function for property with the same name * @@ -214,13 +215,13 @@ class GlobalSettings : public QObject * * @returns Property hideGlidingSectors */ - [[nodiscard]] auto hideGlidingSectors() const -> bool { return settings.value(QStringLiteral("Map/hideGlidingSectors"), true).toBool(); } + [[nodiscard]] auto hideGlidingSectors() const -> bool { return m_settings.value(QStringLiteral("Map/hideGlidingSectors"), true).toBool(); } /*! \brief Getter function for property of the same name * * @returns Property ignoreSSLProblems */ - [[nodiscard]] auto ignoreSSLProblems() const -> bool { return settings.value(QStringLiteral("ignoreSSLProblems"), false).toBool(); } + [[nodiscard]] auto ignoreSSLProblems() const -> bool { return m_settings.value(QStringLiteral("ignoreSSLProblems"), false).toBool(); } /*! \brief Getter function for property with the same name * @@ -234,7 +235,7 @@ class GlobalSettings : public QObject */ [[nodiscard]] auto lastWhatsNewHash() const -> Units::ByteSize { - return settings.value(QStringLiteral("lastWhatsNewHash"), 0).value(); + return m_settings.value(QStringLiteral("lastWhatsNewHash"), 0).value(); } /*! \brief Getter function for property of the same name @@ -243,7 +244,7 @@ class GlobalSettings : public QObject */ [[nodiscard]] auto lastWhatsNewInMapsHash() const -> Units::ByteSize { - return settings.value(QStringLiteral("lastWhatsNewInMapsHash"), 0).value(); + return m_settings.value(QStringLiteral("lastWhatsNewInMapsHash"), 0).value(); } /*! \brief Getter function for property of the same name @@ -256,25 +257,31 @@ class GlobalSettings : public QObject * * @returns Property night mode */ - [[nodiscard]] auto nightMode() const -> bool { return settings.value(QStringLiteral("Map/nightMode"), false).toBool(); } + [[nodiscard]] auto nightMode() const -> bool { return m_settings.value(QStringLiteral("Map/nightMode"), false).toBool(); } + + /*! \brief Getter function for property of the same name + * + * @returns Property positioningByTrafficDataReceiver + */ + [[nodiscard]] bool positioningByTrafficDataReceiver() const { return m_positioningByTrafficDataReceiver.value(); } /*! \brief Getter function for property of the same name * * @returns Property positioningByTrafficDataReceiver */ - [[nodiscard]] auto positioningByTrafficDataReceiver() const -> bool { return settings.value(QStringLiteral("positioningByTrafficDataReceiver"), false).toBool(); } + [[nodiscard]] QBindable bindablePositioningByTrafficDataReceiver() const { return &m_positioningByTrafficDataReceiver; } /*! \brief Getter function for property of the same name * * @returns Property privacyHash */ - [[nodiscard]] auto privacyHash() const -> Units::ByteSize { return settings.value(QStringLiteral("privacyHash"), 0).value(); } + [[nodiscard]] auto privacyHash() const -> Units::ByteSize { return m_settings.value(QStringLiteral("privacyHash"), 0).value(); } /*! \brief Getter function for property of the same name * * @returns Property positioningByTrafficDataReceiver */ - [[nodiscard]] auto showAltitudeAGL() const -> bool { return settings.value(QStringLiteral("showAltitudeAGL"), false).toBool(); } + [[nodiscard]] auto showAltitudeAGL() const -> bool { return m_settings.value(QStringLiteral("showAltitudeAGL"), false).toBool(); } /*! \brief Getter function for property of the same name * @@ -282,7 +289,7 @@ class GlobalSettings : public QObject */ [[nodiscard]] auto voiceNotifications() const -> uint { - return settings.value(QStringLiteral("voiceNotifications"), + return m_settings.value(QStringLiteral("voiceNotifications"), Notifications::Notification::Info_Navigation | Notifications::Notification::Warning | Notifications::Notification::Warning_Navigation | @@ -439,9 +446,6 @@ class GlobalSettings : public QObject /*! \brief Notifier signal */ void nightModeChanged(); - /*! \brief Notifier signal */ - void positioningByTrafficDataReceiverChanged(); - /*! \brief Notifier signal */ void privacyHashChanged(); @@ -454,5 +458,7 @@ class GlobalSettings : public QObject private: Q_DISABLE_COPY_MOVE(GlobalSettings) - QSettings settings; + QSettings m_settings; + + QProperty m_positioningByTrafficDataReceiver; }; diff --git a/src/fileFormats/GeoTIFF.cpp b/src/fileFormats/GeoTIFF.cpp index 85053028b..113076f6e 100644 --- a/src/fileFormats/GeoTIFF.cpp +++ b/src/fileFormats/GeoTIFF.cpp @@ -62,7 +62,7 @@ QList FileFormats::GeoTIFF::getTransformation(const QMap int qRegisterMetaType(); qRegisterMetaType(); - qmlRegisterUncreatableType("enroute", 1, 0, "DemoRunner", QStringLiteral("DemoRunner objects cannot be created in QML")); - qmlRegisterUncreatableType("enroute", 1, 0, "SSLErrorHandler", QStringLiteral("SSLErrorHandler objects cannot be created in QML")); - qmlRegisterUncreatableType("enroute", 1, 0, "GeoMapProvider", QStringLiteral("GeoMapProvider objects cannot be created in QML")); - qmlRegisterUncreatableType("enroute", 1, 0, "WaypointLibrary", QStringLiteral("WaypointLibrary objects cannot be created in QML")); - qmlRegisterUncreatableType("enroute", 1, 0, "DataManager", QStringLiteral("DataManager objects cannot be created in QML")); - qmlRegisterUncreatableType("enroute", 1, 0, "TrafficDataProvider", QStringLiteral("TrafficDataProvider objects cannot be created in QML")); - qmlRegisterUncreatableType("enroute", 1, 0, "TrafficFactor_WithPosition", QStringLiteral("TrafficFactor_WithPosition objects cannot be created in QML")); - - // Required by the maplibre plugin to QtLocation QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); diff --git a/src/navigation/Navigator.cpp b/src/navigation/Navigator.cpp index d1eb30fa5..1f249487d 100644 --- a/src/navigation/Navigator.cpp +++ b/src/navigation/Navigator.cpp @@ -43,9 +43,12 @@ Navigation::Navigator::Navigator(QObject *parent) : GlobalObject(parent) // Restore aircraft QFile file(m_aircraftFileName); - if (file.open(QIODevice::ReadOnly)) { + if (file.open(QIODevice::ReadOnly)) + { (void)m_aircraft.loadFromJSON(file.readAll()); - } else { + } + else + { auto cruiseSpeed = Units::Speed::fromKN(settings.value(QStringLiteral("Aircraft/cruiseSpeedInKTS"), 0.0).toDouble()); auto descentSpeed = Units::Speed::fromKN(settings.value(QStringLiteral("Aircraft/descentSpeedInKTS"), 0.0).toDouble()); auto fuelConsumption = Units::VolumeFlow::fromLPH(settings.value(QStringLiteral("Aircraft/fuelConsumptionInLPH"), 0.0).toDouble()); @@ -73,7 +76,8 @@ void Navigation::Navigator::deferredInitialization() auto Navigation::Navigator::flightRoute() -> FlightRoute* { - if (m_flightRoute.isNull()) { + if (m_flightRoute.isNull()) + { m_flightRoute = new FlightRoute(this); m_flightRoute->load(m_flightRouteFileName); connect(m_flightRoute, &Navigation::FlightRoute::waypointsChanged, this, [this]() {if (m_flightRoute != nullptr) {(void)m_flightRoute->save(m_flightRouteFileName);}}); @@ -89,7 +93,8 @@ auto Navigation::Navigator::flightRoute() -> FlightRoute* void Navigation::Navigator::setAircraft(const Navigation::Aircraft& newAircraft) { - if (newAircraft == m_aircraft) { + if (newAircraft == m_aircraft) + { return; } @@ -106,7 +111,8 @@ void Navigation::Navigator::setAircraft(const Navigation::Aircraft& newAircraft) void Navigation::Navigator::setFlightStatus(FlightStatus newFlightStatus) { - if (m_flightStatus == newFlightStatus) { + if (m_flightStatus == newFlightStatus) + { return; } @@ -117,7 +123,8 @@ void Navigation::Navigator::setFlightStatus(FlightStatus newFlightStatus) void Navigation::Navigator::setWind(Weather::Wind newWind) { - if (newWind == m_wind) { + if (newWind == m_wind) + { return; } @@ -139,16 +146,17 @@ void Navigation::Navigator::setWind(Weather::Wind newWind) void Navigation::Navigator::updateAltitudeLimit() { auto info = GlobalObject::positionProvider()->positionInfo(); - if (!info.isValid()) { + if (!info.isValid()) + { return; } auto altLimit = GlobalObject::globalSettings()->airspaceAltitudeLimit(); auto trueAltitude = info.trueAltitudeAMSL(); if (altLimit.isFinite() && - trueAltitude.isFinite() && - (trueAltitude + Units::Distance::fromFT(1000) > altLimit)) { - + trueAltitude.isFinite() && + (trueAltitude + Units::Distance::fromFT(1000) > altLimit)) + { // Round trueAltitude+1000ft up to nearest 500ft and set that as a new limit auto newAltLimit = Units::Distance::fromFT(500.0*qCeil(trueAltitude.toFeet()/500.0+2.0)); GlobalObject::globalSettings()->setAirspaceAltitudeLimit(newAltLimit); @@ -160,7 +168,8 @@ void Navigation::Navigator::updateAltitudeLimit() void Navigation::Navigator::updateFlightStatus() { auto info = GlobalObject::positionProvider()->positionInfo(); - if (!info.isValid()) { + if (!info.isValid()) + { setFlightStatus(Unknown); return; } @@ -168,22 +177,26 @@ void Navigation::Navigator::updateFlightStatus() // Get ground speed and aircraft minimum speed auto GS = info.groundSpeed(); auto aircraftMinSpeed = m_aircraft.minimumSpeed(); - if (!GS.isFinite() || !aircraftMinSpeed.isFinite()) { + if (!GS.isFinite() || !aircraftMinSpeed.isFinite()) + { setFlightStatus(Unknown); return; } // Go to ground mode if ground speed is less then aircraftMinSpeed-flightSpeedHysteresis - if (m_flightStatus == Flight) { + if (m_flightStatus == Flight) + { // If we are in flight at present, go back to ground mode only if the ground speed is less than minFlightSpeedInKT-flightSpeedHysteresis - if ( GS < aircraftMinSpeed-flightSpeedHysteresis) { + if ( GS < aircraftMinSpeed-flightSpeedHysteresis) + { setFlightStatus(Ground); } return; } // Go to flight mode if ground speed is more than aircraftMinSpeed - if ( GS > aircraftMinSpeed ) { + if ( GS > aircraftMinSpeed ) + { setFlightStatus(Flight); } } @@ -223,7 +236,7 @@ void Navigation::Navigator::updateRemainingRouteInfo() } // If we are closer than 3 nm from endpoint, then we do not give a remaining route info - auto finalCoordinate = geoPath[geoPath.size()-1]; + const auto &finalCoordinate = geoPath[geoPath.size() - 1]; if (Units::Distance::fromM(finalCoordinate.distanceTo(info.coordinate())) < Leg::nearThreshold) { RemainingRouteInfo rrInfo; diff --git a/src/positioning/PositionInfo.cpp b/src/positioning/PositionInfo.cpp index 55d8a2829..28c2bd19d 100644 --- a/src/positioning/PositionInfo.cpp +++ b/src/positioning/PositionInfo.cpp @@ -22,8 +22,8 @@ #include "geomaps/GeoMapProvider.h" #include "positioning/PositionInfo.h" -Positioning::PositionInfo::PositionInfo(const QGeoPositionInfo &info) - : m_positionInfo(info) +Positioning::PositionInfo::PositionInfo(const QGeoPositionInfo& info, const QString& source) + : m_positionInfo(info), m_source(source) {} auto Positioning::PositionInfo::groundSpeed() const -> Units::Speed @@ -38,7 +38,6 @@ auto Positioning::PositionInfo::groundSpeed() const -> Units::Speed return Units::Speed::fromMPS(m_positionInfo.attribute(QGeoPositionInfo::GroundSpeed)); } - auto Positioning::PositionInfo::isValid() const -> bool { if (!m_positionInfo.isValid()) { @@ -49,7 +48,6 @@ auto Positioning::PositionInfo::isValid() const -> bool return expiry >= QDateTime::currentDateTime(); } - auto Positioning::PositionInfo::positionErrorEstimate() const -> Units::Distance { if (!m_positionInfo.isValid()) { @@ -62,7 +60,6 @@ auto Positioning::PositionInfo::positionErrorEstimate() const -> Units::Distance return Units::Distance::fromM(m_positionInfo.attribute(QGeoPositionInfo::HorizontalAccuracy)); } - auto Positioning::PositionInfo::terrainElevationAMSL() -> Units::Distance { if (m_terrainAMSL.isFinite()) @@ -74,7 +71,6 @@ auto Positioning::PositionInfo::terrainElevationAMSL() -> Units::Distance return m_terrainAMSL; } - auto Positioning::PositionInfo::trueAltitudeAMSL() const -> Units::Distance { if (!m_positionInfo.isValid()) { @@ -127,7 +123,6 @@ auto Positioning::PositionInfo::trueAltitudeErrorEstimate() const -> Units::Dist return Units::Distance::fromM(m_positionInfo.attribute(QGeoPositionInfo::VerticalAccuracy)); } - auto Positioning::PositionInfo::trueTrack() const -> Units::Angle { if (!m_positionInfo.isValid()) @@ -150,7 +145,6 @@ auto Positioning::PositionInfo::trueTrack() const -> Units::Angle return Units::Angle::fromDEG(m_positionInfo.attribute(QGeoPositionInfo::Direction)); } - auto Positioning::PositionInfo::trueTrackErrorEstimate() const -> Units::Angle { if (!trueTrack().isFinite()) @@ -165,7 +159,6 @@ auto Positioning::PositionInfo::trueTrackErrorEstimate() const -> Units::Angle return Units::Angle::fromDEG(m_positionInfo.attribute(QGeoPositionInfo::DirectionAccuracy)); } - auto Positioning::PositionInfo::variation() const -> Units::Angle { if (!m_positionInfo.isValid()) { @@ -178,7 +171,6 @@ auto Positioning::PositionInfo::variation() const -> Units::Angle return Units::Angle::fromDEG(m_positionInfo.attribute(QGeoPositionInfo::MagneticVariation)); } - auto Positioning::PositionInfo::verticalSpeed() const -> Units::Speed { if (!m_positionInfo.isValid()) { diff --git a/src/positioning/PositionInfo.h b/src/positioning/PositionInfo.h index 2fcf03e90..8bf56817a 100644 --- a/src/positioning/PositionInfo.h +++ b/src/positioning/PositionInfo.h @@ -22,7 +22,7 @@ #include #include -#include +//#include #include "units/Angle.h" #include "units/Distance.h" @@ -53,8 +53,10 @@ class PositionInfo /*! \brief Constructor * * @param info QGeoPositionInfo this is copied into this class + * + * @param source Name of the source that generated with instance */ - explicit PositionInfo(const QGeoPositionInfo &info); + explicit PositionInfo(const QGeoPositionInfo& info, const QString& source); /*! \brief Coordinate * @@ -87,6 +89,12 @@ class PositionInfo */ [[nodiscard]] Q_INVOKABLE Units::Distance positionErrorEstimate() const; + /*! \brief Name of source, as set in the constructor + * + * @returns Name of source + */ + [[nodiscard]] Q_INVOKABLE QString source() const {return m_source;} + /*! \brief Elevation of terrain at a given coordinate, above sea level * * @returns Elevation of the terrain at position, or @@ -187,8 +195,9 @@ class PositionInfo private: QGeoPositionInfo m_positionInfo; - Units::Distance m_terrainAMSL{}; - Units::Distance m_trueAltitudeAGL {}; + QString m_source; + Units::Distance m_terrainAMSL; + Units::Distance m_trueAltitudeAGL; }; } // namespace Positioning diff --git a/src/positioning/PositionInfoSource_Abstract.cpp b/src/positioning/PositionInfoSource_Abstract.cpp index a1085bfd1..e38cfd04f 100644 --- a/src/positioning/PositionInfoSource_Abstract.cpp +++ b/src/positioning/PositionInfoSource_Abstract.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2021-2023 by Stefan Kebekus * + * Copyright (C) 2021-2024 by Stefan Kebekus * * stefan.kebekus@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -21,85 +21,24 @@ #include "positioning/PositionInfoSource_Abstract.h" -Positioning::PositionInfoSource_Abstract::PositionInfoSource_Abstract(QObject *parent) : QObject(parent) +Positioning::PositionInfoSource_Abstract::PositionInfoSource_Abstract(QObject* parent) : QObject(parent) { // Setup timer m_positionInfoTimer.setInterval( PositionInfo::lifetime ); m_positionInfoTimer.setSingleShot(true); - connect(&m_positionInfoTimer, &QTimer::timeout, this, &Positioning::PositionInfoSource_Abstract::resetPositionInfo); - - // Setup timer - m_pressureAltitudeTimer.setInterval( PositionInfo::lifetime ); - m_pressureAltitudeTimer.setSingleShot(true); - connect(&m_pressureAltitudeTimer, &QTimer::timeout, this, &Positioning::PositionInfoSource_Abstract::resetPressureAltitude); + connect(&m_positionInfoTimer, &QTimer::timeout, this, [this]() {setPositionInfo({});}); } -void Positioning::PositionInfoSource_Abstract::setPositionInfo(const Positioning::PositionInfo &info) +void Positioning::PositionInfoSource_Abstract::setPositionInfo(const Positioning::PositionInfo& info) { - if (info.isValid()) { + if (info.isValid()) + { m_positionInfoTimer.start(); } - if (info == m_positionInfo) { - return; - } + Qt::beginPropertyUpdateGroup(); m_positionInfo = info; - emit positionInfoChanged(); - - auto newReceiving = m_positionInfo.isValid(); - if (_receivingPositionInfo == newReceiving) { - return; - } - - _receivingPositionInfo = newReceiving; - emit receivingPositionInfoChanged(); -} - - -void Positioning::PositionInfoSource_Abstract::setSourceName(const QString &name) -{ - if (m_sourceName == name) { - return; - } - - m_sourceName = name; - emit sourceNameChanged(m_sourceName); -} - - -void Positioning::PositionInfoSource_Abstract::setStatusString(const QString &status) -{ - if (m_statusString == status) { - return; - } - - m_statusString = status; - emit statusStringChanged(m_statusString); -} - - -void Positioning::PositionInfoSource_Abstract::setPressureAltitude(Units::Distance newPressureAltitude) -{ - if (newPressureAltitude.isFinite()) { - m_pressureAltitudeTimer.start(); - } - if (newPressureAltitude == m_pressureAltitude) { - return; - } - - m_pressureAltitude = newPressureAltitude; - emit pressureAltitudeChanged(); -} - - -void Positioning::PositionInfoSource_Abstract::resetPressureAltitude() -{ - setPressureAltitude( {} ); -} - - -void Positioning::PositionInfoSource_Abstract::resetPositionInfo() -{ - setPositionInfo( {} ); + m_receivingPositionInfo = info.isValid(); + Qt::endPropertyUpdateGroup(); } diff --git a/src/positioning/PositionInfoSource_Abstract.h b/src/positioning/PositionInfoSource_Abstract.h index 11492092f..8bc442701 100644 --- a/src/positioning/PositionInfoSource_Abstract.h +++ b/src/positioning/PositionInfoSource_Abstract.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2021-2023 by Stefan Kebekus * + * Copyright (C) 2021-2024 by Stefan Kebekus * * stefan.kebekus@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -21,22 +21,19 @@ #pragma once #include +#include #include #include "positioning/PositionInfo.h" -#include "units/Distance.h" namespace Positioning { -/*! \brief Abstract base class for all classes that provide geographic position information +/*! \brief Abstract base class for all classes that provide geographic position + * information * * This is the base class for all classes that provide geographic position - * information. The information is exposed via two properties, positionInfo - * and pressureAltitude. - * - * The property statusString gives more information about the status of the - * source + * information. */ @@ -51,7 +48,6 @@ class PositionInfoSource_Abstract : public QObject { explicit PositionInfoSource_Abstract(QObject *parent = nullptr); - // // Properties // @@ -62,140 +58,122 @@ class PositionInfoSource_Abstract : public QObject { * that the data is up-to-date, the position information will be set to an * invalid positionInfo when no data has arrived for more than the time * specified in PositionInfo::lifetime. + */ + Q_PROPERTY(Positioning::PositionInfo positionInfo READ positionInfo BINDABLE bindablePositionInfo) + + /*! \brief Indicator that position information is being received * - * Consumers of the class can use positionInfo().isValid() property to - * check if position data is continually arriving. + * This is a shortcut for positionInfo().isValid. This property exists + * because it does not change so often, and can thus be more efficient to + * use. */ - Q_PROPERTY(Positioning::PositionInfo positionInfo READ positionInfo NOTIFY positionInfoChanged) + Q_PROPERTY(bool receivingPositionInfo READ receivingPositionInfo BINDABLE bindableReceivingPositionInfo) - /*! \brief Getter method for property with the same name + /*! \brief Source name * - * @returns Property positionInfo + * This property holds a translated, human-readable string that describes + * the source. This could typically be a string of the form "Traffic + * Receiver" or "Built-in satellite receiver". */ - [[nodiscard]] auto positionInfo() const -> Positioning::PositionInfo - { - return m_positionInfo; - } + Q_PROPERTY(QString sourceName READ sourceName BINDABLE bindableSourceName) - /*! \brief Pressure altitude + /*! \brief Source status * - * This property holds information about the pressure altitude, that is, - * the altitude that you would read off your altimeter if the altimeter is - * set to 1013.2 hPa. To ensure that the data is up-to-date, the position - * information will be set to "invalid" when no data has arrived for more - * than the time specified in PositionInfo::lifetime. + * This property holds a translated, human-readable string that describes + * the status of the positionInfo source. This could typically be a string + * of the form "OK" or "Insufficient permission to access position info" */ - Q_PROPERTY(Units::Distance pressureAltitude READ pressureAltitude NOTIFY pressureAltitudeChanged) + Q_PROPERTY(QString statusString READ statusString BINDABLE bindableStatusString) + + + // + // Getter Methods + // /*! \brief Getter method for property with the same name * - * @returns Property pressureAltitude + * @returns Property positionInfo */ - [[nodiscard]] auto pressureAltitude() const -> Units::Distance + [[nodiscard]] Positioning::PositionInfo positionInfo() const { - return m_pressureAltitude; + return m_positionInfo.value(); } - /*! \brief Indicator that position information is being received + /*! \brief Getter method for property with the same name * - * Use this property to tell if position information is being received. + * @returns Property positionInfo */ - Q_PROPERTY(bool receivingPositionInfo READ receivingPositionInfo NOTIFY receivingPositionInfoChanged) + [[nodiscard]] QBindable bindablePositionInfo() const + { + return &m_positionInfo; + } /*! \brief Getter method for property with the same name * * @returns Property receivingPositionInfo */ - [[nodiscard]] auto receivingPositionInfo() const -> bool - { - return _receivingPositionInfo; - } + [[nodiscard]] bool receivingPositionInfo() const {return m_receivingPositionInfo.value();} - /*! \brief Source name + /*! \brief Getter method for property with the same name * - * This property holds a translated, human-readable string that describes - * the source. This could typically be a string of the form "Traffic - * Receiver" or "Built-in satellite receiver". + * @returns Property receivingPositionInfo */ - Q_PROPERTY(QString sourceName READ sourceName NOTIFY sourceNameChanged) + [[nodiscard]] QBindable bindableReceivingPositionInfo() {return &m_receivingPositionInfo;} /*! \brief Getter method for property with the same name * * @returns Property sourceName */ - [[nodiscard]] auto sourceName() const -> QString + [[nodiscard]] QString sourceName() const { - return m_sourceName; + return m_sourceName.value(); } - /*! \brief Source status + /*! \brief Getter method for property with the same name * - * This property holds a translated, human-readable string that describes - * the status of the positionInfo source. This could typically be a string - * of the form "OK" or "Insufficient permission to access position info" + * @returns Property sourceName */ - Q_PROPERTY(QString statusString READ statusString NOTIFY statusStringChanged) + [[nodiscard]] QBindable bindableSourceName() const + { + return &m_sourceName; + } /*! \brief Getter method for property with the same name * * @returns Property statusString */ - [[nodiscard]] auto statusString() const -> QString + [[nodiscard]] QString statusString() const { - return m_statusString; + return m_statusString.value(); } -signals: - /*! \brief Notifier signal */ - void positionInfoChanged(); - - /*! \brief Notifier signal */ - void pressureAltitudeChanged(); - - /*! \brief Notifier signal */ - void receivingPositionInfoChanged(); - - /*! \brief Notifier signal */ - void sourceNameChanged(const QString &name); - - /*! \brief Notifier signal */ - void statusStringChanged(const QString &status); + /*! \brief Getter method for property with the same name + * + * @returns Property statusString + */ + [[nodiscard]] QBindable bindableStatusString() const + { + return &m_statusString; + } protected: // This method must be used by child classes to update the position info. // The class uses a timer internally to reset the position info to "invalid" // after the time specified in PositionInfo::lifetime seconds. It also // updates the property receivingPositionInfo. - void setPositionInfo(const Positioning::PositionInfo &info); - - // This method must be used by child classes to update the pressure altitude - // The class uses a timer internally to reset the position info to "invalid" - // after the time specified in PositionInfo::lifetime seconds. - void setPressureAltitude(Units::Distance newPressureAltitude); + void setPositionInfo(const Positioning::PositionInfo& info); // This method must be used by child classes to update the source name - void setSourceName(const QString &name); + void setSourceName(const QString& name) {m_sourceName = name;} - // This method must be used by child classes to update the status string - void setStatusString(const QString &status); + QProperty m_statusString; private: - // Resets the position info to "invalid" - void resetPositionInfo(); - - // Resets the pressure altitude to "invalid" - void resetPressureAltitude(); - - Units::Distance m_pressureAltitude {}; - QTimer m_pressureAltitudeTimer; - - Positioning::PositionInfo m_positionInfo; + QProperty m_positionInfo; QTimer m_positionInfoTimer; - QString m_sourceName; - QString m_statusString; - - bool _receivingPositionInfo{false}; + QProperty m_receivingPositionInfo {false}; + QProperty m_sourceName; }; } // namespace Positioning diff --git a/src/positioning/PositionInfoSource_Satellite.cpp b/src/positioning/PositionInfoSource_Satellite.cpp index 3a75157f9..21e11ed02 100644 --- a/src/positioning/PositionInfoSource_Satellite.cpp +++ b/src/positioning/PositionInfoSource_Satellite.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2021 by Stefan Kebekus * + * Copyright (C) 2021-2024 by Stefan Kebekus * * stefan.kebekus@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -54,29 +54,33 @@ void Positioning::PositionInfoSource_Satellite::startUpdates() void Positioning::PositionInfoSource_Satellite::updateStatusString() { - if (source == nullptr) { - setStatusString( tr("Not installed or access denied") ); + if (source == nullptr) + { + m_statusString = tr("Not installed or access denied"); return; } auto sourceStatus = source->error(); - if (sourceStatus == QGeoPositionInfoSource::AccessError) { - setStatusString( tr("Access denied") ); + if (sourceStatus == QGeoPositionInfoSource::AccessError) + { + m_statusString = tr("Access denied"); return; } - if (sourceStatus == QGeoPositionInfoSource::ClosedError) { - setStatusString( tr("Connection to satellite system lost") ); + if (sourceStatus == QGeoPositionInfoSource::ClosedError) + { + m_statusString = tr("Connection to satellite system lost"); return; } - if (!receivingPositionInfo()) { - setStatusString( tr("Waiting for signal") ); + if (!receivingPositionInfo()) + { + m_statusString = tr("Waiting for signal"); return; } - setStatusString( tr("Receiving data") ); + m_statusString = tr("Receiving data"); } @@ -99,6 +103,6 @@ void Positioning::PositionInfoSource_Satellite::onPositionUpdated(const QGeoPosi // Therefore, set the current time as a timestamp. correctedInfo.setTimestamp( QDateTime::currentDateTimeUtc() ); - setPositionInfo( Positioning::PositionInfo(correctedInfo) ); + setPositionInfo( Positioning::PositionInfo(correctedInfo, sourceName()) ); updateStatusString(); } diff --git a/src/positioning/PositionProvider.cpp b/src/positioning/PositionProvider.cpp index f438e379b..856d95b12 100644 --- a/src/positioning/PositionProvider.cpp +++ b/src/positioning/PositionProvider.cpp @@ -25,12 +25,15 @@ #include "GlobalSettings.h" #include "positioning/PositionProvider.h" #include "traffic/TrafficDataProvider.h" -#include "units/Units.h" +#include "Units.h" + using namespace Qt::Literals::StringLiterals; -Positioning::PositionProvider::PositionProvider(QObject *parent) : PositionInfoSource_Abstract(parent) +Positioning::PositionProvider::PositionProvider(QObject* parent) + : QObject(parent), + m_receivingPositionInfo(false) { // Restore the last valid coordiante and track QSettings const settings; @@ -42,16 +45,9 @@ Positioning::PositionProvider::PositionProvider(QObject *parent) : PositionInfoS m_lastValidCoordinate = tmp; } m_lastValidTT = Units::Angle::fromDEG( qBound(0, settings.value(QStringLiteral("PositionProvider/lastValidTrack"), 0).toInt(), 359) ); + m_approximateLastValidCoordinate = m_lastValidCoordinate.value(); - // Wire up satellite source - connect(&satelliteSource, &Positioning::PositionInfoSource_Satellite::positionInfoChanged, this, &PositionProvider::onPositionUpdated); - connect(&satelliteSource, &Positioning::PositionInfoSource_Satellite::pressureAltitudeChanged, this, &PositionProvider::onPressureAltitudeUpdated); - - // Binding for updateStatusString - connect(this, &Positioning::PositionProvider::receivingPositionInfoChanged, this, &Positioning::PositionProvider::updateStatusString); - connect(&satelliteSource, &Positioning::PositionInfoSource_Satellite::statusStringChanged, this, &Positioning::PositionProvider::updateStatusString); - - // Wire up traffic data provider source + // Start deferred initialization QTimer::singleShot(0, this, &Positioning::PositionProvider::deferredInitialization); // Save position at regular intervals @@ -61,90 +57,35 @@ Positioning::PositionProvider::PositionProvider(QObject *parent) : PositionInfoS connect(saveTimer, &QTimer::timeout, this, &Positioning::PositionProvider::savePositionAndTrack); connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Positioning::PositionProvider::savePositionAndTrack); saveTimer->start(); - - // Update properties - updateStatusString(); - m_approximateLastValidCoordinate = m_lastValidCoordinate.value(); - connect(this, &Positioning::PositionProvider::lastValidCoordinateChanged, this, [this]() { - if (m_approximateLastValidCoordinate.value().isValid() - && (m_approximateLastValidCoordinate.value().distanceTo(m_lastValidCoordinate) < 10000)) - { - return; - } - m_approximateLastValidCoordinate = m_lastValidCoordinate.value(); - }); } - - -void Positioning::PositionProvider::deferredInitialization() const +void Positioning::PositionProvider::deferredInitialization() { - connect(GlobalObject::trafficDataProvider(), &Traffic::TrafficDataProvider::positionInfoChanged, this, &PositionProvider::onPositionUpdated); - connect(GlobalObject::trafficDataProvider(), &Traffic::TrafficDataProvider::pressureAltitudeChanged, this, &PositionProvider::onPressureAltitudeUpdated); + // Binding for updateStatusString + m_statusString.setBinding([this]() {return computeStatusString();}); + m_incomingPositionInfo.setBinding([this]() {return computeIncomingPositionInfo();}); + m_incomingPositionInfoNotifier = m_incomingPositionInfo.addNotifier([this]() {return onIncomingPositionInfoUpdated();}); + onIncomingPositionInfoUpdated(); } - -void Positioning::PositionProvider::onPositionUpdated() +void Positioning::PositionProvider::onIncomingPositionInfoUpdated() { - // This method is called if one of our providers has a new position info. - // We go through the list of providers in order of preference, to find the first one - // that has a valid position info available for us. - PositionInfo newInfo; - QString source; - - - if (GlobalObject::globalSettings()->positioningByTrafficDataReceiver()) - { - - // Priority #1: Traffic data provider - auto* trafficDataProvider = GlobalObject::trafficDataProvider(); - if (trafficDataProvider != nullptr) - { - newInfo = trafficDataProvider->positionInfo(); - source = trafficDataProvider->sourceName(); - } - - // Priority #2: Built-in sat receiver - if (!newInfo.isValid()) - { - newInfo = satelliteSource.positionInfo(); - source = satelliteSource.sourceName(); - } - - } - else + auto newInfo = m_incomingPositionInfo.value(); + if (!newInfo.isValid()) { - - // Priority #1: Built-in sat receiver - newInfo = satelliteSource.positionInfo(); - source = satelliteSource.sourceName(); - - // Priority #2: Traffic data provider - if (!newInfo.isValid()) - { - auto* trafficDataProvider = GlobalObject::trafficDataProvider(); - if (trafficDataProvider != nullptr) - { - newInfo = trafficDataProvider->positionInfo(); - source = trafficDataProvider->sourceName(); - } - - } - + m_receivingPositionInfo = false; + m_positionInfo = newInfo; + return; } + // If no vertical speed has been provided by the system, we compute our own. auto oldInfo = positionInfo(); auto oldTimeStamp = oldInfo.timestamp(); auto newTimeStamp = newInfo.timestamp(); - if (newTimeStamp == oldTimeStamp) - { - return; - } - - // If no vertical speed has been provided by the system, we compute our own. if (!newInfo.verticalSpeed().isFinite() - && newInfo.trueAltitudeAMSL().isFinite() - && oldInfo.trueAltitudeAMSL().isFinite()) + && newInfo.trueAltitudeAMSL().isFinite() + && oldInfo.trueAltitudeAMSL().isFinite() + && (newTimeStamp != oldTimeStamp)) { auto deltaV = (newInfo.trueAltitudeAMSL() - oldInfo.trueAltitudeAMSL()); auto deltaT = Units::Timespan::fromMS( static_cast(oldTimeStamp.msecsTo(newTimeStamp)) ); @@ -153,47 +94,36 @@ void Positioning::PositionProvider::onPositionUpdated() { if (oldInfo.verticalSpeed().isFinite()) { - vSpeed = 0.8*vSpeed + 0.2*positionInfo().verticalSpeed(); + vSpeed = 0.8*vSpeed + 0.2*oldInfo.verticalSpeed(); } QGeoPositionInfo tmp = newInfo; + QString const src = newInfo.source(); tmp.setAttribute(QGeoPositionInfo::VerticalSpeed, vSpeed.toMPS()); - newInfo = PositionInfo(tmp); + newInfo = PositionInfo(tmp, src); } } // Set new info - setPositionInfo(newInfo); - setLastValidCoordinate(newInfo.coordinate()); - setLastValidTT(newInfo.trueTrack()); - setSourceName(source); - updateStatusString(); -} - - -void Positioning::PositionProvider::onPressureAltitudeUpdated() -{ - // This method is called if one of our providers has a new pressure altitude. - // We go through the list of providers in order of preference, to find the first one - // that has valid data for us. - Units::Distance pAlt; + m_positionInfo = newInfo; + m_receivingPositionInfo = true; - // Priority #1: Traffic data provider - auto* trafficDataProvider = GlobalObject::trafficDataProvider(); - if (trafficDataProvider != nullptr) { - pAlt = trafficDataProvider->pressureAltitude(); + m_lastValidCoordinate = newInfo.coordinate(); + auto TT = newInfo.trueTrack(); + if (TT.isFinite()) + { + m_lastValidTT = TT; } - - // Priority #2: Built-in sat receiver - if (!pAlt.isFinite()) { - pAlt = satelliteSource.pressureAltitude(); + if (!m_approximateLastValidCoordinate.value().isValid()) + { + m_approximateLastValidCoordinate = m_lastValidCoordinate.value(); + } + if (m_approximateLastValidCoordinate.value().isValid() + && (m_approximateLastValidCoordinate.value().distanceTo(m_lastValidCoordinate) > 10000)) + { + m_approximateLastValidCoordinate = m_lastValidCoordinate.value(); } - - // Set new info - setPressureAltitude(pAlt); - } - void Positioning::PositionProvider::savePositionAndTrack() { // Save the last valid coordinate @@ -203,37 +133,10 @@ void Positioning::PositionProvider::savePositionAndTrack() settings.setValue(QStringLiteral("PositionProvider/lastValidAltitude"), m_lastValidCoordinate.value().altitude()); // Save the last valid track - settings.setValue(QStringLiteral("PositionProvider/lastValidTrack"), m_lastValidTT.toDEG()); -} - - -void Positioning::PositionProvider::setLastValidCoordinate(const QGeoCoordinate &newCoordinate) -{ - if (!newCoordinate.isValid()) { - return; - } - if (newCoordinate == m_lastValidCoordinate) { - return; - } - m_lastValidCoordinate = newCoordinate; - emit lastValidCoordinateChanged(m_lastValidCoordinate); -} - - -void Positioning::PositionProvider::setLastValidTT(Units::Angle newTT) -{ - if (!newTT.isFinite()) { - return; - } - if (newTT == m_lastValidTT) { - return; - } - m_lastValidTT = newTT; - emit lastValidTTChanged(m_lastValidTT); + settings.setValue(QStringLiteral("PositionProvider/lastValidTrack"), m_lastValidTT.value().toDEG()); } - -auto Positioning::PositionProvider::lastValidCoordinate() -> QGeoCoordinate +QGeoCoordinate Positioning::PositionProvider::lastValidCoordinate() { auto *positionProvider = GlobalObject::positionProvider(); if (positionProvider == nullptr) { @@ -242,31 +145,74 @@ auto Positioning::PositionProvider::lastValidCoordinate() -> QGeoCoordinate return positionProvider->m_lastValidCoordinate.value(); } - -auto Positioning::PositionProvider::lastValidTT() -> Units::Angle +Units::Angle Positioning::PositionProvider::lastValidTT() { auto *positionProvider = GlobalObject::positionProvider(); if (positionProvider == nullptr) { return {}; } - return positionProvider->m_lastValidTT; + return positionProvider->m_lastValidTT.value(); } -void Positioning::PositionProvider::updateStatusString() +// +// Computing Functions/Bindings +// + +QString Positioning::PositionProvider::computeStatusString() { - if (receivingPositionInfo()) { + if (m_positionInfo.value().isValid()) + { QString result = QStringLiteral("
    "); - result += QStringLiteral("
  • %1: %2
  • ").arg(tr("Source"), sourceName()); + result += QStringLiteral("
  • %1: %2
  • ").arg(tr("Source"), m_positionInfo.value().source()); result += QStringLiteral("
  • %1
  • ").arg(tr("Receiving position information")); result += u"
"_s; - setStatusString(result); - return; + return result; } QString result = QStringLiteral("

%1

    ").arg(tr("Not receiving position information")); result += QStringLiteral("
  • %1: %2
  • ").arg( satelliteSource.sourceName(), satelliteSource.statusString()); result += QStringLiteral("
  • %1: %2
  • ").arg( tr("Traffic receiver"), tr("Not receiving position information")); result += u"
"_s; - setStatusString(result); + return result; +} + +Positioning::PositionInfo Positioning::PositionProvider::computeIncomingPositionInfo() +{ + // This method is called if one of our providers has a new position info. + // We go through the list of providers in order of preference, to find the first one + // that has a valid position info available for us. + PositionInfo newInfo; + + if (GlobalObject::globalSettings()->positioningByTrafficDataReceiver()) + { + // Priority #1: Traffic data provider + auto* trafficDataProvider = GlobalObject::trafficDataProvider(); + if (trafficDataProvider != nullptr) + { + newInfo = trafficDataProvider->positionInfo(); + } + + // Priority #2: Built-in sat receiver + if (!newInfo.isValid()) + { + newInfo = satelliteSource.positionInfo(); + } + } + else + { + // Priority #1: Built-in sat receiver + newInfo = satelliteSource.positionInfo(); + + // Priority #2: Traffic data provider + if (!newInfo.isValid()) + { + auto* trafficDataProvider = GlobalObject::trafficDataProvider(); + if (trafficDataProvider != nullptr) + { + newInfo = trafficDataProvider->positionInfo(); + } + } + } + return newInfo; } diff --git a/src/positioning/PositionProvider.h b/src/positioning/PositionProvider.h index 3cf72d4dc..d38eee409 100644 --- a/src/positioning/PositionProvider.h +++ b/src/positioning/PositionProvider.h @@ -24,7 +24,6 @@ #include #include "GlobalObject.h" -#include "positioning/PositionInfoSource_Abstract.h" #include "positioning/PositionInfoSource_Satellite.h" @@ -46,17 +45,12 @@ namespace Positioning { * The methods in this class are reentrant, but not thread safe. */ -class PositionProvider : public PositionInfoSource_Abstract +class PositionProvider : public QObject { Q_OBJECT QML_ELEMENT QML_SINGLETON - // Repeat properties from PositionInfoSource_Abstract so qmllint knows about them - Q_PROPERTY(Positioning::PositionInfo positionInfo READ positionInfo NOTIFY positionInfoChanged) - Q_PROPERTY(Units::Distance pressureAltitude READ pressureAltitude NOTIFY pressureAltitudeChanged) - Q_PROPERTY(bool receivingPositionInfo READ receivingPositionInfo NOTIFY receivingPositionInfoChanged) - public: /*! \brief Standard constructor @@ -97,7 +91,7 @@ class PositionProvider : public PositionInfoSource_Abstract * value is stored in a QSetting at destruction, and restored in the * construction. */ - Q_PROPERTY(QGeoCoordinate lastValidCoordinate READ lastValidCoordinate NOTIFY lastValidCoordinateChanged) + Q_PROPERTY(QGeoCoordinate lastValidCoordinate READ lastValidCoordinate BINDABLE bindableLastValidCoordinate) /*! \brief Last valid true track * @@ -105,7 +99,32 @@ class PositionProvider : public PositionInfoSource_Abstract * start, this property is set to 0°. The value is stored in a QSetting at * destruction, and restored in the construction. */ - Q_PROPERTY(Units::Angle lastValidTT READ lastValidTT NOTIFY lastValidTTChanged) + Q_PROPERTY(Units::Angle lastValidTT READ lastValidTT BINDABLE bindableLastValidTT) + + /*! \brief Position information + * + * This property holds information about the device position. To ensure + * that the data is up-to-date, the position information will be set to an + * invalid positionInfo when no data has arrived for more than the time + * specified in PositionInfo::lifetime. + */ + Q_PROPERTY(Positioning::PositionInfo positionInfo READ positionInfo BINDABLE bindablePositionInfo NOTIFY positionInfoChanged) + + /*! \brief Indicator that position information is being received + * + * This is a shortcut for positionInfo().isValid. This property exists + * because it does not change so often, and can thus be more efficient to + * use. + */ + Q_PROPERTY(bool receivingPositionInfo READ receivingPositionInfo BINDABLE bindableReceivingPositionInfo) + + /*! \brief Source status + * + * This property holds a translated, human-readable string that describes + * the status of the positionInfo source. This could typically be a string + * of the form "OK" or "Insufficient permission to access position info" + */ + Q_PROPERTY(QString statusString READ statusString BINDABLE bindableStatusString) // @@ -116,20 +135,80 @@ class PositionProvider : public PositionInfoSource_Abstract * * @returns Property approximateLastValidCoordinate */ - Q_REQUIRED_RESULT QGeoCoordinate approximateLastValidCoordinate() const {return {m_approximateLastValidCoordinate};} - Q_REQUIRED_RESULT QBindable bindableApproximateLastValidCoordinate() const {return &m_approximateLastValidCoordinate;} + [[nodiscard]] QGeoCoordinate approximateLastValidCoordinate() const {return m_approximateLastValidCoordinate.value();} + + /*! \brief Getter function for the property with the same name + * + * @returns Property approximateLastValidCoordinate + */ + [[nodiscard]] QBindable bindableApproximateLastValidCoordinate() const {return &m_approximateLastValidCoordinate;} /*! \brief Getter function for the property with the same name * * @returns Property lastValidCoordinate */ - static QGeoCoordinate lastValidCoordinate(); + [[nodiscard]] static QGeoCoordinate lastValidCoordinate(); + + /*! \brief Getter function for the property with the same name + * + * @returns Property lastValidCoordinate + */ + [[nodiscard]] QBindable bindableLastValidCoordinate() {return &m_lastValidCoordinate;} + + /*! \brief Getter function for the property with the same name + * + * @returns Property lastValidTrack + */ + [[nodiscard]] static Units::Angle lastValidTT(); /*! \brief Getter function for the property with the same name * * @returns Property lastValidTrack */ - static Units::Angle lastValidTT(); + [[nodiscard]] QBindable bindableLastValidTT() {return &m_lastValidTT;} + + /*! \brief Getter method for property with the same name + * + * @returns Property positionInfo + */ + [[nodiscard]] Positioning::PositionInfo positionInfo() const {return m_positionInfo.value();} + + /*! \brief Getter method for property with the same name + * + * @returns Property positionInfo + */ + [[nodiscard]] QBindable bindablePositionInfo() const {return &m_positionInfo;} + + /*! \brief Getter method for property with the same name + * + * @returns Property receivingPositionInfo + */ + [[nodiscard]] bool receivingPositionInfo() const {return m_receivingPositionInfo.value();} + + /*! \brief Getter method for property with the same name + * + * @returns Property receivingPositionInfo + */ + [[nodiscard]] QBindable bindableReceivingPositionInfo() {return &m_receivingPositionInfo;} + + /*! \brief Getter method for property with the same name + * + * @returns Property statusString + */ + [[nodiscard]] QString statusString() const + { + return m_statusString.value(); + } + + /*! \brief Getter method for property with the same name + * + * @returns Property statusString + */ + [[nodiscard]] QBindable bindableStatusString() const + { + return &m_statusString; + } + // @@ -145,41 +224,29 @@ class PositionProvider : public PositionInfoSource_Abstract Q_INVOKABLE void startUpdates() { satelliteSource.startUpdates(); } signals: - /*! \brief Notifier signal */ + // Notifier signal void approximateLastValidCoordinateChanged(); - /*! \brief Notifier signal */ - void lastValidTTChanged(Units::Angle); + // Notifier signal + void positionInfoChanged(); - /*! \brief Notifier signal */ - void lastValidCoordinateChanged(QGeoCoordinate); + // Notifier signal + void receivingPositionInfoChanged(); private slots: // Intializations that are moved out of the constructor, in order to avoid // nested uses of constructors in Global. - void deferredInitialization() const; - - // Connected to sources, in order to receive new data - void onPositionUpdated(); - - // Connected to sources, in order to receive new data - void onPressureAltitudeUpdated(); + void deferredInitialization(); // Saves last valid position and track void savePositionAndTrack(); - // Setter method for property with the same name - void setLastValidCoordinate(const QGeoCoordinate &newCoordinate); - - // Setter method for property with the same name - void setLastValidTT(Units::Angle newTT); - - // Setter method for property with the same name - void updateStatusString(); - private: Q_DISABLE_COPY_MOVE(PositionProvider) + // Computation method for property with the same name + QString computeStatusString(); + // Aircraft is considered flying if speed is at least this high static constexpr double minFlightSpeedInKT = 30.0; // Hysteresis for flight speed @@ -192,9 +259,24 @@ private slots: PositionInfoSource_Satellite satelliteSource; - Q_OBJECT_BINDABLE_PROPERTY(PositionProvider, QGeoCoordinate, m_approximateLastValidCoordinate, &Positioning::PositionProvider::approximateLastValidCoordinateChanged) + // The incoming position info is set by a binding that monitors + // the satelliteSource and the TrafficDataSource + QProperty m_incomingPositionInfo; + Positioning::PositionInfo computeIncomingPositionInfo(); + + // This method updates m_approximateLastValidCoordinate, m_lastValidCoordinate and m_lastValidTT + // whenever m_incomingPositionInfo changes. + void onIncomingPositionInfoUpdated(); + QPropertyNotifier m_incomingPositionInfoNotifier; + + Q_OBJECT_BINDABLE_PROPERTY(Positioning::PositionProvider, Positioning::PositionInfo, m_positionInfo, &Positioning::PositionProvider::positionInfoChanged); + Q_OBJECT_BINDABLE_PROPERTY(Positioning::PositionProvider, QGeoCoordinate, m_approximateLastValidCoordinate, &Positioning::PositionProvider::approximateLastValidCoordinateChanged); QProperty m_lastValidCoordinate {QGeoCoordinate(EDTF_lat, EDTF_lon, EDTF_ele)}; - Units::Angle m_lastValidTT {}; + QProperty m_lastValidTT; + + Q_OBJECT_BINDABLE_PROPERTY(Positioning::PositionProvider, bool, m_receivingPositionInfo, &Positioning::PositionProvider::receivingPositionInfoChanged); + QProperty m_statusString; + }; } // namespace Positioning diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 09b742dce..42bd19096 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -27,11 +27,8 @@ import QtQuick.Controls import QtQuick.Layouts import akaflieg_freiburg.enroute -import enroute 1.0 - import "." -import ".." import "../dialogs" Item { diff --git a/src/qml/items/NavBar.qml b/src/qml/items/NavBar.qml index 1620d9d76..a85a14397 100644 --- a/src/qml/items/NavBar.qml +++ b/src/qml/items/NavBar.qml @@ -119,7 +119,7 @@ Rectangle { Layout.alignment: Qt.AlignHCenter - text: PositionProvider.pressureAltitude.isFinite() ? "FL" + ("000" + Math.round(PositionProvider.pressureAltitude.toFeet()/100.0)).slice(-3) : "-" + text: TrafficDataProvider.pressureAltitude.isFinite() ? "FL" + ("000" + Math.round(TrafficDataProvider.pressureAltitude.toFeet()/100.0)).slice(-3) : "-" font.weight: Font.Bold font.pixelSize: dummy.font.pixelSize*1.3 color: "white" diff --git a/src/qml/main.qml b/src/qml/main.qml index 22fd280d2..ebf022e16 100644 --- a/src/qml/main.qml +++ b/src/qml/main.qml @@ -346,7 +346,7 @@ AppWindow { ItemDelegate { // PressureAltitude text: qsTr("Barometric Data") +`
` - + (PositionProvider.pressureAltitude.isFinite() ? qsTr("Receiving pressure altitude.") : qsTr("Not receiving pressure altitude.")) + + (TrafficDataProvider.pressureAltitude.isFinite() ? qsTr("Receiving pressure altitude.") : qsTr("Not receiving pressure altitude.")) + `` icon.source: "/icons/material/ic_speed.svg" Layout.fillWidth: true @@ -359,7 +359,7 @@ AppWindow { } background: Rectangle { anchors.fill: parent - color: PositionProvider.pressureAltitude.isFinite() ? "green" : "red" + color: TrafficDataProvider.pressureAltitude.isFinite() ? "green" : "red" opacity: 0.2 } } diff --git a/src/qml/pages/PressureAltitude.qml b/src/qml/pages/PressureAltitude.qml index 82d875497..123309af3 100644 --- a/src/qml/pages/PressureAltitude.qml +++ b/src/qml/pages/PressureAltitude.qml @@ -68,7 +68,7 @@ Page { Layout.rightMargin: 4 Layout.columnSpan: 3 - text: PositionProvider.pressureAltitude.isFinite() ? qsTr("Receiving static pressure data from traffic receiver") : qsTr("Not connected to a traffic receiver that provides static pressure data") + text: TrafficDataProvider.pressureAltitude.isFinite() ? qsTr("Receiving static pressure data from traffic receiver") : qsTr("Not connected to a traffic receiver that provides static pressure data") wrapMode: Text.WordWrap textFormat: Text.RichText @@ -83,7 +83,7 @@ Page { background: Rectangle { border.color: "black" - color: PositionProvider.pressureAltitude.isFinite() ? "green" : "red" + color: TrafficDataProvider.pressureAltitude.isFinite() ? "green" : "red" opacity: 0.2 radius: 4 } @@ -140,7 +140,7 @@ Page { text: qsTr("Pressure Altitude") } Label { Layout.fillWidth: true - text: PositionProvider.pressureAltitude.isFinite() ? "FL" + ("000" + Math.round(PositionProvider.pressureAltitude.toFeet()/100.0)).slice(-3) : "-" + text: TrafficDataProvider.pressureAltitude.isFinite() ? "FL" + ("000" + Math.round(TrafficDataProvider.pressureAltitude.toFeet()/100.0)).slice(-3) : "-" wrapMode: Text.Wrap } Item { } @@ -149,7 +149,7 @@ Page { Label { Layout.fillWidth: true text: { - var pAlt = PositionProvider.pressureAltitude + var pAlt = TrafficDataProvider.pressureAltitude if (!pAlt.isFinite()) return "-" var qnhpAlt = WeatherDataProvider.QNHPressureAltitude diff --git a/src/traffic/TrafficDataProvider.cpp b/src/traffic/TrafficDataProvider.cpp index 1726e1d5e..e6e7fc52d 100644 --- a/src/traffic/TrafficDataProvider.cpp +++ b/src/traffic/TrafficDataProvider.cpp @@ -33,7 +33,9 @@ using namespace Qt::Literals::StringLiterals; -Traffic::TrafficDataProvider::TrafficDataProvider(QObject *parent) : Positioning::PositionInfoSource_Abstract(parent) +Traffic::TrafficDataProvider::TrafficDataProvider(QObject *parent) + : Positioning::PositionInfoSource_Abstract(parent), + m_receivingHeartbeat(false) { // Create traffic objects const int numTrafficObjects = 20; @@ -68,14 +70,15 @@ Traffic::TrafficDataProvider::TrafficDataProvider(QObject *parent) : Positioning addDataSource( new Traffic::TrafficDataSource_Udp(true, 4000, this) ); addDataSource( new Traffic::TrafficDataSource_Udp(true, 49002, this)); + // Setup Bindings + m_pressureAltitude.setBinding([this]() {return computePressureAltitude();}); + // Bindings for saving loadConnectionInfos(); connect(this, &Traffic::TrafficDataProvider::dataSourcesChanged, this, &Traffic::TrafficDataProvider::saveConnectionInfos); // Bindings for status string - connect(this, &Traffic::TrafficDataProvider::positionInfoChanged, this, &Traffic::TrafficDataProvider::updateStatusString); - connect(this, &Traffic::TrafficDataProvider::pressureAltitudeChanged, this, &Traffic::TrafficDataProvider::updateStatusString); - connect(this, &Traffic::TrafficDataProvider::receivingHeartbeatChanged, this, &Traffic::TrafficDataProvider::updateStatusString); + m_statusString.setBinding([this]() {return computeStatusString();}); // Connect timer. Try to (re)connect after 2s, and then again every five minutes. QTimer::singleShot(2s, this, &Traffic::TrafficDataProvider::connectToTrafficReceiver); @@ -103,18 +106,22 @@ void Traffic::TrafficDataProvider::addDataSource(Traffic::TrafficDataSource_Abst source->setParent(this); QQmlEngine::setObjectOwnership(source, QQmlEngine::CppOwnership); - m_dataSources << source; - connect(source, &Traffic::TrafficDataSource_Abstract::connectivityStatusChanged, this, &Traffic::TrafficDataProvider::updateStatusString); - connect(source, &Traffic::TrafficDataSource_Abstract::errorStringChanged, this, &Traffic::TrafficDataProvider::updateStatusString); connect(source, &Traffic::TrafficDataSource_Abstract::passwordRequest, this, &Traffic::TrafficDataProvider::passwordRequest); connect(source, &Traffic::TrafficDataSource_Abstract::passwordStorageRequest, this, &Traffic::TrafficDataProvider::passwordStorageRequest); - connect(source, &Traffic::TrafficDataSource_Abstract::receivingHeartbeatChanged, this, &Traffic::TrafficDataProvider::updateStatusString); connect(source, &Traffic::TrafficDataSource_Abstract::receivingHeartbeatChanged, this, &Traffic::TrafficDataProvider::onSourceHeartbeatChanged); connect(source, &Traffic::TrafficDataSource_Abstract::trafficReceiverRuntimeErrorChanged, this, &Traffic::TrafficDataProvider::onTrafficReceiverRuntimeError); connect(source, &Traffic::TrafficDataSource_Abstract::trafficReceiverSelfTestErrorChanged, this, &Traffic::TrafficDataProvider::onTrafficReceiverSelfTestError); + auto tmp = m_dataSources.value(); + tmp.append(source); + tmp.removeAll(nullptr); + std::sort(tmp.begin(), + tmp.end(), + [](const Traffic::TrafficDataSource_Abstract* first, const Traffic::TrafficDataSource_Abstract* second) + { return first->sourceName() < second->sourceName(); }); + m_dataSources = tmp; + emit dataSourcesChanged(); - updateStatusString(); } QString Traffic::TrafficDataProvider::addDataSource(const Traffic::ConnectionInfo &connectionInfo) @@ -140,7 +147,7 @@ QString Traffic::TrafficDataProvider::addDataSource(const Traffic::ConnectionInf QString Traffic::TrafficDataProvider::addDataSource_UDP(quint16 port) { // Ignore new device if data source already exists. - foreach(auto _dataSource, m_dataSources) + foreach(auto _dataSource, m_dataSources.value()) { auto* dataSourceUDP = qobject_cast(_dataSource); if (dataSourceUDP != nullptr) @@ -162,7 +169,7 @@ QString Traffic::TrafficDataProvider::addDataSource_SerialPort(const QString& po { #if __has_include() // Ignore new device if data source already exists. - foreach(auto _dataSource, m_dataSources) + foreach(auto _dataSource, m_dataSources.value()) { auto* dataSourceSerialPort = qobject_cast(_dataSource); if (dataSourceSerialPort != nullptr) @@ -186,7 +193,7 @@ QString Traffic::TrafficDataProvider::addDataSource_SerialPort(const QString& po QString Traffic::TrafficDataProvider::addDataSource_TCP(const QString& host, quint16 port) { // Ignore new device if data source already exists. - foreach(auto _dataSource, m_dataSources) + foreach(auto _dataSource, m_dataSources.value()) { auto* dataSourceTCP = qobject_cast(_dataSource); if (dataSourceTCP != nullptr) @@ -206,11 +213,11 @@ QString Traffic::TrafficDataProvider::addDataSource_TCP(const QString& host, qui void Traffic::TrafficDataProvider::clearDataSources() { - if (m_dataSources.isEmpty()) + if (m_dataSources.value().isEmpty()) { return; } - foreach(auto dataSource, m_dataSources) + foreach(auto dataSource, m_dataSources.value()) { if (dataSource.isNull()) { @@ -219,12 +226,15 @@ void Traffic::TrafficDataProvider::clearDataSources() dataSource->disconnect(); delete dataSource; } - m_dataSources.clear(); + + auto tmp = m_dataSources.value(); + tmp.clear(); + m_dataSources = tmp; } void Traffic::TrafficDataProvider::connectToTrafficReceiver() { - foreach(auto dataSource, m_dataSources) + foreach(auto dataSource, m_dataSources.value()) { if (dataSource.isNull()) { @@ -232,14 +242,12 @@ void Traffic::TrafficDataProvider::connectToTrafficReceiver() } dataSource->connectToTrafficReceiver(); } - - updateStatusString(); } QList Traffic::TrafficDataProvider::dataSources() const { QList result; - foreach(auto dataSource, m_dataSources) + foreach(auto dataSource, m_dataSources.value()) { if (dataSource == nullptr) { @@ -264,7 +272,7 @@ void Traffic::TrafficDataProvider::deferredInitialization() const void Traffic::TrafficDataProvider::disconnectFromTrafficReceiver() { - foreach(auto dataSource, m_dataSources) + foreach(auto dataSource, m_dataSources.value()) { if (dataSource.isNull()) { @@ -298,16 +306,16 @@ void Traffic::TrafficDataProvider::loadConnectionInfos() void Traffic::TrafficDataProvider::onSourceHeartbeatChanged() { // If we have a current source, if the current source has a heartbeat and if the current source is a TCP source, then we simply stick with it. - if ((qobject_cast(m_currentSource) != nullptr) + if ((qobject_cast(m_currentSource.value()) != nullptr) && m_currentSource->receivingHeartbeat() ) { - setReceivingHeartbeat(true); + m_receivingHeartbeat = true; return; } // Among the m_dataSources, find the first (=most preferred) source that is receiving heartbeat messages. Traffic::TrafficDataSource_Abstract *heartbeatDataSource = nullptr; - foreach(auto source, m_dataSources) + foreach(auto source, m_dataSources.value()) { if (source.isNull()) { @@ -326,31 +334,29 @@ void Traffic::TrafficDataProvider::onSourceHeartbeatChanged() // Disconnect old m_currentSource - if (!m_currentSource.isNull()) + if (!m_currentSource.value().isNull()) { - disconnect(m_currentSource, &Traffic::TrafficDataSource_Abstract::pressureAltitudeUpdated, this, &Traffic::TrafficDataProvider::setPressureAltitude); - disconnect(m_currentSource, &Traffic::TrafficDataSource_Abstract::factorWithoutPosition, this, &Traffic::TrafficDataProvider::onTrafficFactorWithoutPosition); - disconnect(m_currentSource, &Traffic::TrafficDataSource_Abstract::factorWithPosition, this, &Traffic::TrafficDataProvider::onTrafficFactorWithPosition); - disconnect(m_currentSource, &Traffic::TrafficDataSource_Abstract::positionUpdated, this, &Traffic::TrafficDataProvider::setPositionInfo); - disconnect(m_currentSource, &Traffic::TrafficDataSource_Abstract::warning, this, &Traffic::TrafficDataProvider::setWarning); + disconnect(m_currentSource.value(), &Traffic::TrafficDataSource_Abstract::factorWithoutPosition, this, &Traffic::TrafficDataProvider::onTrafficFactorWithoutPosition); + disconnect(m_currentSource.value(), &Traffic::TrafficDataSource_Abstract::factorWithPosition, this, &Traffic::TrafficDataProvider::onTrafficFactorWithPosition); + disconnect(m_currentSource.value(), &Traffic::TrafficDataSource_Abstract::positionUpdated, this, &Traffic::TrafficDataProvider::setPositionInfo); + disconnect(m_currentSource.value(), &Traffic::TrafficDataSource_Abstract::warning, this, &Traffic::TrafficDataProvider::setWarning); } // Update m_currentsource m_currentSource = heartbeatDataSource; - if (!m_currentSource.isNull()) + if (!m_currentSource.value().isNull()) { // If there is a new m_currentSource, then setup Qt connections and // disconnect all sources of lower priority from the traffic receivers. - connect(m_currentSource, &Traffic::TrafficDataSource_Abstract::pressureAltitudeUpdated, this, &Traffic::TrafficDataProvider::setPressureAltitude); - connect(m_currentSource, &Traffic::TrafficDataSource_Abstract::factorWithoutPosition, this, &Traffic::TrafficDataProvider::onTrafficFactorWithoutPosition); - connect(m_currentSource, &Traffic::TrafficDataSource_Abstract::factorWithPosition, this, &Traffic::TrafficDataProvider::onTrafficFactorWithPosition); - connect(m_currentSource, &Traffic::TrafficDataSource_Abstract::positionUpdated, this, &Traffic::TrafficDataProvider::setPositionInfo); - connect(m_currentSource, &Traffic::TrafficDataSource_Abstract::warning, this, &Traffic::TrafficDataProvider::setWarning); + connect(m_currentSource.value(), &Traffic::TrafficDataSource_Abstract::factorWithoutPosition, this, &Traffic::TrafficDataProvider::onTrafficFactorWithoutPosition); + connect(m_currentSource.value(), &Traffic::TrafficDataSource_Abstract::factorWithPosition, this, &Traffic::TrafficDataProvider::onTrafficFactorWithPosition); + connect(m_currentSource.value(), &Traffic::TrafficDataSource_Abstract::positionUpdated, this, &Traffic::TrafficDataProvider::setPositionInfo); + connect(m_currentSource.value(), &Traffic::TrafficDataSource_Abstract::warning, this, &Traffic::TrafficDataProvider::setWarning); // Disconnect from traffic receiver bool doDisconnect = false; - foreach(auto source, m_dataSources) + foreach(auto source, m_dataSources.value()) { if ( source.isNull() ) { @@ -376,13 +382,13 @@ void Traffic::TrafficDataProvider::onSourceHeartbeatChanged() } // Update heartbeat status - if (m_currentSource.isNull()) + if (m_currentSource.value().isNull()) { - setReceivingHeartbeat(false); + m_receivingHeartbeat = false; } else { - setReceivingHeartbeat(m_currentSource->receivingHeartbeat()); + m_receivingHeartbeat = m_currentSource->receivingHeartbeat(); } } @@ -466,7 +472,7 @@ void Traffic::TrafficDataProvider::onTrafficFactorWithPosition(const Traffic::Tr void Traffic::TrafficDataProvider::onTrafficReceiverRuntimeError() { QString result; - foreach(auto dataSource, m_dataSources) + foreach(auto dataSource, m_dataSources.value()) { if (dataSource.isNull()) { @@ -490,7 +496,7 @@ void Traffic::TrafficDataProvider::onTrafficReceiverRuntimeError() void Traffic::TrafficDataProvider::onTrafficReceiverSelfTestError() { QString result; - foreach(auto dataSource, m_dataSources) + foreach(auto dataSource, m_dataSources.value()) { if (dataSource.isNull()) { @@ -521,7 +527,10 @@ void Traffic::TrafficDataProvider::removeDataSource(Traffic::TrafficDataSource_A return; } - m_dataSources.removeAll(source); + auto tmp = m_dataSources.value(); + tmp.removeAll(source); + m_dataSources = tmp; + emit dataSourcesChanged(); source->deleteLater(); } @@ -534,7 +543,7 @@ void Traffic::TrafficDataProvider::resetWarning() void Traffic::TrafficDataProvider::saveConnectionInfos() { QList connectionInfos; - foreach (auto dataSource, m_dataSources) + foreach (auto dataSource, m_dataSources.value()) { if (dataSource == nullptr) { @@ -564,7 +573,7 @@ void Traffic::TrafficDataProvider::saveConnectionInfos() void Traffic::TrafficDataProvider::setPassword(const QString& SSID, const QString &password) { - foreach(auto dataSource, m_dataSources) + foreach(auto dataSource, m_dataSources.value()) { if (dataSource.isNull()) { @@ -574,16 +583,6 @@ void Traffic::TrafficDataProvider::setPassword(const QString& SSID, const QStrin } } -void Traffic::TrafficDataProvider::setReceivingHeartbeat(bool newReceivingHeartbeat) -{ - if (m_receivingHeartbeat == newReceivingHeartbeat) - { - return; - } - m_receivingHeartbeat = newReceivingHeartbeat; - emit receivingHeartbeatChanged(m_receivingHeartbeat); -} - void Traffic::TrafficDataProvider::setWarning(const Traffic::Warning& warning) { if (warning.alarmLevel() > -1) @@ -600,12 +599,33 @@ void Traffic::TrafficDataProvider::setWarning(const Traffic::Warning& warning) emit warningChanged(m_Warning); } -void Traffic::TrafficDataProvider::updateStatusString() + +// +// Private Methods +// + +Units::Distance Traffic::TrafficDataProvider::computePressureAltitude() +{ + for (const auto &dataSource : m_dataSources.value()) { + if (dataSource.isNull()) + { + continue; + } + auto pAlt = dataSource->pressureAltitude(); + if (pAlt.isFinite()) + { + return pAlt; + } + } + return {}; +} + +QString Traffic::TrafficDataProvider::computeStatusString() { if (receivingHeartbeat()) { QString result; - if (!m_currentSource.isNull()) + if (!m_currentSource.value().isNull()) { result += QStringLiteral("

%1

    ").arg(m_currentSource->sourceName()); } @@ -619,10 +639,8 @@ void Traffic::TrafficDataProvider::updateStatusString() result += QStringLiteral("
  • %1
  • ").arg(tr("Receiving barometric altitude info.")); } result += u"
"_s; - setStatusString(result); - return; + return result; } - const QString result = tr("Not receiving traffic receiver heartbeat through any of the configured data connections."); - setStatusString(result); + return tr("Not receiving traffic receiver heartbeat through any of the configured data connections."); } diff --git a/src/traffic/TrafficDataProvider.h b/src/traffic/TrafficDataProvider.h index 0adc3b3ef..ed322addd 100644 --- a/src/traffic/TrafficDataProvider.h +++ b/src/traffic/TrafficDataProvider.h @@ -84,6 +84,16 @@ class TrafficDataProvider : public Positioning::PositionInfoSource_Abstract { */ Q_PROPERTY(QList dataSources READ dataSources NOTIFY dataSourcesChanged) + /*! \brief Pressure altitude + * + * This property holds information about the pressure altitude, that is, + * the altitude that you would read off your altimeter if the altimeter is + * set to 1013.2 hPa. To ensure that the data is up-to-date, the position + * information will be set to "invalid" when no data has arrived for more + * than the time specified in PositionInfo::lifetime. + */ + Q_PROPERTY(Units::Distance pressureAltitude READ pressureAltitude BINDABLE bindablePressureAltitude) + /*! \brief Heartbeat indicator * * When active, traffic receivers send regular heartbeat messages. These @@ -91,7 +101,7 @@ class TrafficDataProvider : public Positioning::PositionInfoSource_Abstract { * times when no traffic is reported. This property indicates if the class * receives heartbeat messages from at least one of the known receivers. */ - Q_PROPERTY(bool receivingHeartbeat READ receivingHeartbeat WRITE setReceivingHeartbeat NOTIFY receivingHeartbeatChanged) + Q_PROPERTY(bool receivingHeartbeat READ receivingHeartbeat BINDABLE bindableReceivingHeartbeat NOTIFY receivingHeartbeatChanged) /*! \brief Traffic objects whose position is known * @@ -149,13 +159,34 @@ class TrafficDataProvider : public Positioning::PositionInfoSource_Abstract { */ [[nodiscard]] QList dataSources() const; + /*! \brief Getter method for property with the same name + * + * @returns Property pressureAltitude + */ + [[nodiscard]] Units::Distance pressureAltitude() const {return m_pressureAltitude.value();} + + /*! \brief Getter method for property with the same name + * + * @returns Property pressureAltitude + */ + [[nodiscard]] QBindable bindablePressureAltitude() const {return &m_pressureAltitude;} + /*! \brief Getter method for property with the same name * * @returns Property receiving */ [[nodiscard]] bool receivingHeartbeat() const { - return m_receivingHeartbeat; + return m_receivingHeartbeat.value(); + } + + /*! \brief Getter method for property with the same name + * + * @returns Property receiving + */ + [[nodiscard]] QBindable bindableReceivingHeartbeat() const + { + return &m_receivingHeartbeat; } /*! \brief Getter method for property with the same name @@ -292,6 +323,7 @@ class TrafficDataProvider : public Positioning::PositionInfoSource_Abstract { */ static constexpr Units::Distance maxHorizontalDistance = Units::Distance::fromNM(20.0); + signals: /*! \brief Notifier signal */ void dataSourcesChanged(); @@ -314,7 +346,7 @@ class TrafficDataProvider : public Positioning::PositionInfoSource_Abstract { void passwordStorageRequest(const QString& SSID, const QString& password); /*! \brief Notifier signal */ - void receivingHeartbeatChanged(bool); + void receivingHeartbeatChanged(); /*! \brief Notifier signal */ void trafficReceiverRuntimeErrorChanged(); @@ -395,17 +427,16 @@ private slots: // Save connection infos to file void saveConnectionInfos(); - // Setter method - void setReceivingHeartbeat(bool newReceivingHeartbeat); - // Setter method void setWarning(const Traffic::Warning& warning); - // Updates the property statusString that is inherited from - // Positioning::PositionInfoSource_Abstract - void updateStatusString(); - private: + // + // Compute Methods + // + + QString computeStatusString(); + // UDP Socket for ForeFlight Broadcast messages. // See https://www.foreflight.com/connect/spec/ QNetworkDatagram foreFlightBroadcastDatagram {R"({"App":"Enroute Flight Navigation","GDL90":{"port":4000}})", QHostAddress::Broadcast, 63093}; @@ -417,8 +448,8 @@ private slots: QPointer m_trafficObjectWithoutPosition; // TrafficData Sources - QList> m_dataSources; - QPointer m_currentSource; + QProperty>> m_dataSources; + QProperty> m_currentSource; // Property cache Traffic::Warning m_Warning; @@ -426,11 +457,13 @@ private slots: QString m_trafficReceiverRuntimeError; QString m_trafficReceiverSelfTestError; + QProperty m_pressureAltitude; + Units::Distance computePressureAltitude(); + // Reconnect QTimer reconnectionTimer; - // Property Cache - bool m_receivingHeartbeat {false}; + Q_OBJECT_BINDABLE_PROPERTY(Traffic::TrafficDataProvider, bool, m_receivingHeartbeat, &Traffic::TrafficDataProvider::receivingHeartbeatChanged); // Standard file name for saveConnectionInfos() QString stdFileName{QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/connectionInfos.data"}; diff --git a/src/traffic/TrafficDataProvider_BluetoothClassic.cpp b/src/traffic/TrafficDataProvider_BluetoothClassic.cpp index ea9183e21..397ff2b65 100644 --- a/src/traffic/TrafficDataProvider_BluetoothClassic.cpp +++ b/src/traffic/TrafficDataProvider_BluetoothClassic.cpp @@ -36,7 +36,7 @@ QString Traffic::TrafficDataProvider::addDataSource_BluetoothClassic(const Traff } // Ignore new device if data source already exists. - foreach(auto _dataSource, m_dataSources) + foreach(auto _dataSource, m_dataSources.value()) { auto* dataSourceBTClassic = qobject_cast(_dataSource); if (dataSourceBTClassic != nullptr) diff --git a/src/traffic/TrafficDataSource_Abstract.cpp b/src/traffic/TrafficDataSource_Abstract.cpp index 5bd14c14e..ec857890c 100644 --- a/src/traffic/TrafficDataSource_Abstract.cpp +++ b/src/traffic/TrafficDataSource_Abstract.cpp @@ -20,6 +20,7 @@ #include +#include "positioning/PositionInfo.h" #include "traffic/TrafficDataSource_Abstract.h" @@ -35,8 +36,12 @@ Traffic::TrafficDataSource_Abstract::TrafficDataSource_Abstract(bool isCanonical m_heartbeatTimer.setInterval(5s); connect(&m_heartbeatTimer, &QTimer::timeout, this, &Traffic::TrafficDataSource_Abstract::resetReceivingHeartbeat); + // Setup timer for pressure altitude + m_pressureAltitudeTimer.setInterval(Positioning::PositionInfo::lifetime); + m_pressureAltitudeTimer.setSingleShot(true); + connect(&m_pressureAltitudeTimer, &QTimer::timeout, this, [this]() {m_pressureAltitude = Units::Distance();}); + // Setup other times - m_pressureAltitudeTimer.setInterval(5s); m_pressureAltitudeTimer.setSingleShot(true); m_trueAltitudeTimer.setInterval(5s); m_trueAltitudeTimer.setSingleShot(true); @@ -64,6 +69,11 @@ void Traffic::TrafficDataSource_Abstract::setErrorString(const QString& newError emit errorStringChanged(m_errorString); } +void Traffic::TrafficDataSource_Abstract::setPressureAltitude(Units::Distance newPressureAltitude) +{ + m_pressureAltitudeTimer.start(); + m_pressureAltitude = newPressureAltitude; +} void Traffic::TrafficDataSource_Abstract::setReceivingHeartbeat(bool newReceivingHeartbeat) { diff --git a/src/traffic/TrafficDataSource_Abstract.h b/src/traffic/TrafficDataSource_Abstract.h index f165b485e..4ef4d0589 100644 --- a/src/traffic/TrafficDataSource_Abstract.h +++ b/src/traffic/TrafficDataSource_Abstract.h @@ -20,6 +20,8 @@ #pragma once +#include + #include "positioning/PositionInfo.h" #include "traffic/ConnectionInfo.h" #include "traffic/TrafficFactor_DistanceOnly.h" @@ -102,6 +104,16 @@ class TrafficDataSource_Abstract : public QObject { /*! \brief Icon that can be used to represent the connection in a GUI */ Q_PROPERTY(QString icon READ icon CONSTANT) + /*! \brief Pressure altitude + * + * This property holds information about the pressure altitude, that is, + * the altitude that you would read off your altimeter if the altimeter is + * set to 1013.2 hPa. To ensure that the data is up-to-date, the position + * information will be set to "invalid" when no data has arrived for more + * than the time specified in PositionInfo::lifetime. + */ + Q_PROPERTY(Units::Distance pressureAltitude READ pressureAltitude BINDABLE bindablePressureAltitude) + /*! \brief Heartbeat indicator * * When active, traffic receivers send regular heartbeat messages. These @@ -191,6 +203,18 @@ class TrafficDataSource_Abstract : public QObject { */ [[nodiscard]] virtual QString icon() const = 0; + /*! \brief Getter method for property with the same name + * + * @returns Property pressureAltitude + */ + [[nodiscard]] Units::Distance pressureAltitude() const {return m_pressureAltitude.value();} + + /*! \brief Getter method for property with the same name + * + * @returns Property pressureAltitude + */ + [[nodiscard]] QBindable bindablePressureAltitude() const {return &m_pressureAltitude;} + /*! \brief Getter function for the property with the same name * * @returns Property receivingHeartbeat @@ -224,6 +248,7 @@ class TrafficDataSource_Abstract : public QObject { return m_trafficReceiverSelfTestError; } + signals: /*! \brief Notifier signal */ void connectivityStatusChanged(QString newStatus); @@ -267,15 +292,6 @@ class TrafficDataSource_Abstract : public QObject { */ void passwordStorageRequest(const QString& SSID, const QString& password); - /*! \brief Pressure altitude - * - * If this class received pressure altitude information from a connected - * traffic receiver, this information is emitted here. Pressure altitude is - * the altitude shown by your altimeter if the altimeter is set to 1013.2 - * hPa. - */ - void pressureAltitudeUpdated(Units::Distance); - /*! \brief Position info * * If this class received position information from a connected traffic @@ -414,6 +430,16 @@ public slots: */ void setErrorString(const QString& newErrorString = QString()); + /*! \brief Setter function for the property with the same name + * + * This method must be used by child classes to update the pressure altitude + * The class uses a timer internally to reset the position info to "invalid" + * after the time specified in PositionInfo::lifetime seconds. + * + * @param newPressureAltitude Pressure Altitude + */ + void setPressureAltitude(Units::Distance newPressureAltitude); + /*! \brief Setter method for the property with the same name * * When set to 'true' a timer is stated that will automatically reset the @@ -473,9 +499,9 @@ public slots: Units::Distance m_trueAltitudeFOM; // Fig. of Merit QTimer m_trueAltitudeTimer; - // Pressure altitude of own aircraft. See the member m_trueAltitude for a - // description how the timer should be used. - Units::Distance m_pressureAltitude; + // Pressure altitude of own aircraft. The timer will reset the pressureAltitude + // to an invalid value if no data is received for a while. + QProperty m_pressureAltitude; QTimer m_pressureAltitudeTimer; // Heartbeat timer diff --git a/src/traffic/TrafficDataSource_Abstract_FLARM.cpp b/src/traffic/TrafficDataSource_Abstract_FLARM.cpp index fdad07666..99073cc6a 100644 --- a/src/traffic/TrafficDataSource_Abstract_FLARM.cpp +++ b/src/traffic/TrafficDataSource_Abstract_FLARM.cpp @@ -328,7 +328,7 @@ void Traffic::TrafficDataSource_Abstract::processFLARMMessageGPRMC(const QString pInfo.setAttribute(QGeoPositionInfo::Direction, TT ); } - emit positionUpdated( Positioning::PositionInfo(pInfo)); + emit positionUpdated( Positioning::PositionInfo(pInfo, sourceName()) ); } @@ -523,7 +523,7 @@ void Traffic::TrafficDataSource_Abstract::processFLARMMessagePFLAA(const QString m_factor.setCallSign( GlobalObject::flarmnetDB()->getRegistration(targetID) ); m_factor.setHDist(hDist); m_factor.setID(targetID); - m_factor.setPositionInfo( Positioning::PositionInfo(pInfo) ); + m_factor.setPositionInfo( Positioning::PositionInfo(pInfo, sourceName()) ); m_factor.setType(type); m_factor.setVDist(vDist); m_factor.startLiveTime(); @@ -818,5 +818,5 @@ void Traffic::TrafficDataSource_Abstract::processFLARMMessagePGRMZ(const QString { return; } - emit pressureAltitudeUpdated(barometricAlt); + setPressureAltitude(barometricAlt); } diff --git a/src/traffic/TrafficDataSource_Abstract_GDL90.cpp b/src/traffic/TrafficDataSource_Abstract_GDL90.cpp index 58b8288e0..dacfecf74 100644 --- a/src/traffic/TrafficDataSource_Abstract_GDL90.cpp +++ b/src/traffic/TrafficDataSource_Abstract_GDL90.cpp @@ -289,10 +289,10 @@ void Traffic::TrafficDataSource_Abstract::processGDLMessage(const QByteArray& ra m_pressureAltitude = Units::Distance::fromM( qQNaN() ); m_pressureAltitudeTimer.stop(); } - emit pressureAltitudeUpdated(m_pressureAltitude); + setPressureAltitude(m_pressureAltitude); // Update position information and continue - emit positionUpdated( Positioning::PositionInfo(pInfo) ); + emit positionUpdated( Positioning::PositionInfo(pInfo, sourceName()) ); return; } @@ -427,7 +427,7 @@ void Traffic::TrafficDataSource_Abstract::processGDLMessage(const QByteArray& ra m_factor.setCallSign(callSign); m_factor.setHDist(hDist); m_factor.setID(id); - m_factor.setPositionInfo( Positioning::PositionInfo(pInfo) ); + m_factor.setPositionInfo( Positioning::PositionInfo(pInfo, sourceName()) ); m_factor.setType(type); m_factor.setVDist(vDist); m_factor.startLiveTime(); diff --git a/src/traffic/TrafficDataSource_Abstract_XGPS.cpp b/src/traffic/TrafficDataSource_Abstract_XGPS.cpp index 007d6dc03..5aa3c3610 100644 --- a/src/traffic/TrafficDataSource_Abstract_XGPS.cpp +++ b/src/traffic/TrafficDataSource_Abstract_XGPS.cpp @@ -68,7 +68,7 @@ void Traffic::TrafficDataSource_Abstract::processXGPSString(const QByteArray& da // Update position information and continue if (_geoPos.isValid()) { - emit positionUpdated( Positioning::PositionInfo(_geoPos) ); + emit positionUpdated( Positioning::PositionInfo(_geoPos, sourceName()) ); setReceivingHeartbeat(true); } @@ -85,7 +85,7 @@ void Traffic::TrafficDataSource_Abstract::processXGPSString(const QByteArray& da } bool ok = false; - QString const targetID = list[1]; + QString const &targetID = list[1]; double const lat = list[2].toDouble(&ok); if (!ok) { return; @@ -141,7 +141,7 @@ void Traffic::TrafficDataSource_Abstract::processXGPSString(const QByteArray& da m_factor.setCallSign(callsign); m_factor.setHDist(hDist); m_factor.setID(targetID); - m_factor.setPositionInfo( Positioning::PositionInfo(geoPositionInfo) ); + m_factor.setPositionInfo( Positioning::PositionInfo(geoPositionInfo, sourceName()) ); m_factor.setType(Traffic::TrafficFactor_Abstract::unknown); m_factor.setVDist(vDist); m_factor.startLiveTime(); diff --git a/src/traffic/TrafficDataSource_Simulate.cpp b/src/traffic/TrafficDataSource_Simulate.cpp index 738411e0e..ba860cb7d 100644 --- a/src/traffic/TrafficDataSource_Simulate.cpp +++ b/src/traffic/TrafficDataSource_Simulate.cpp @@ -61,7 +61,7 @@ void Traffic::TrafficDataSource_Simulate::sendSimulatorData() geoInfo.setTimestamp( QDateTime::currentDateTimeUtc() ); if (geoInfo.isValid()) { - emit positionUpdated( Positioning::PositionInfo(geoInfo) ); + emit positionUpdated( Positioning::PositionInfo(geoInfo, sourceName()) ); setReceivingHeartbeat(true); } else { setReceivingHeartbeat(false); @@ -82,5 +82,5 @@ void Traffic::TrafficDataSource_Simulate::sendSimulatorData() emit factorWithoutPosition(*trafficFactor_DistanceOnly); } - emit pressureAltitudeUpdated(barometricHeight); + setPressureAltitude(barometricHeight); } diff --git a/src/traffic/TrafficFactor_DistanceOnly.h b/src/traffic/TrafficFactor_DistanceOnly.h index 99dc68b90..a88c478b8 100644 --- a/src/traffic/TrafficFactor_DistanceOnly.h +++ b/src/traffic/TrafficFactor_DistanceOnly.h @@ -38,6 +38,7 @@ namespace Traffic { class TrafficFactor_DistanceOnly : public Traffic::TrafficFactor_Abstract { Q_OBJECT + QML_ELEMENT public: /*! \brief Default constructor diff --git a/src/traffic/TrafficFactor_WithPosition.cpp b/src/traffic/TrafficFactor_WithPosition.cpp index 4431e6c0f..03a94198d 100644 --- a/src/traffic/TrafficFactor_WithPosition.cpp +++ b/src/traffic/TrafficFactor_WithPosition.cpp @@ -19,10 +19,8 @@ ***************************************************************************/ #include "GlobalObject.h" -#include "GlobalSettings.h" #include "navigation/Aircraft.h" #include "navigation/Navigator.h" -#include "positioning/PositionProvider.h" #include "traffic/TrafficFactor_WithPosition.h" @@ -110,7 +108,7 @@ void Traffic::TrafficFactor_WithPosition::updateDescription() if (vDist().isFinite()) { QString result = GlobalObject::navigator()->aircraft().verticalDistanceToString(vDist(), true); - auto climbRateMPS = m_positionInfo.attribute(QGeoPositionInfo::VerticalSpeed); + auto climbRateMPS = m_positionInfo.verticalSpeed().toMPS(); if ( qIsFinite(climbRateMPS) ) { if (climbRateMPS < -1.0) { result += QStringLiteral(" ↘"); @@ -132,7 +130,6 @@ void Traffic::TrafficFactor_WithPosition::updateDescription() } m_description = newDescription; emit descriptionChanged(); - } @@ -140,9 +137,11 @@ void Traffic::TrafficFactor_WithPosition::updateIcon() { // BaseType QString baseType = QStringLiteral("noDirection"); - if (m_positionInfo.hasAttribute(QGeoPositionInfo::GroundSpeed) && m_positionInfo.hasAttribute(QGeoPositionInfo::Direction)) { - auto GS = Units::Speed::fromMPS( m_positionInfo.attribute(QGeoPositionInfo::GroundSpeed) ); - if (GS.isFinite() && (GS.toKN() > 4)) { + if (m_positionInfo.groundSpeed().isFinite() && m_positionInfo.trueTrack().isFinite()) + { + auto GS = m_positionInfo.groundSpeed(); + if (GS.isFinite() && (GS.toKN() > 4)) + { baseType = QStringLiteral("withDirection"); } } @@ -168,5 +167,4 @@ void Traffic::TrafficFactor_WithPosition::updateValid() } TrafficFactor_Abstract::updateValid(); - } diff --git a/src/traffic/TrafficFactor_WithPosition.h b/src/traffic/TrafficFactor_WithPosition.h index 67b0224a8..d05ef59f0 100644 --- a/src/traffic/TrafficFactor_WithPosition.h +++ b/src/traffic/TrafficFactor_WithPosition.h @@ -98,7 +98,7 @@ class TrafficFactor_WithPosition : public TrafficFactor_Abstract { */ [[nodiscard]] auto positionInfo() const -> Positioning::PositionInfo { - return Positioning::PositionInfo(m_positionInfo); + return m_positionInfo; } /*! \brief Setter function for property with the same name @@ -136,7 +136,7 @@ class TrafficFactor_WithPosition : public TrafficFactor_Abstract { // Property values // QString m_icon; - QGeoPositionInfo m_positionInfo; + Positioning::PositionInfo m_positionInfo; Units::Distance m_vDist; Units::Distance m_hDist; diff --git a/src/units/Speed.cpp b/src/units/Speed.cpp index a396f9eae..309052a76 100644 --- a/src/units/Speed.cpp +++ b/src/units/Speed.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2019-2021 by Stefan Kebekus * + * Copyright (C) 2019-2024 by Stefan Kebekus * * stefan.kebekus@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -18,7 +18,6 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "GlobalSettings.h" #include "units/Speed.h" diff --git a/src/units/Timespan.h b/src/units/Timespan.h index 52f32f914..f469ba883 100644 --- a/src/units/Timespan.h +++ b/src/units/Timespan.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2019-2023 by Stefan Kebekus * + * Copyright (C) 2019-2024 by Stefan Kebekus * * stefan.kebekus@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -55,9 +55,10 @@ class Timespan { * * @returns time */ - static auto fromMS(double timeInMS) -> Timespan { + static Timespan fromMS(double timeInMS) + { Timespan result; - result.m_timeInS = qRound(timeInMS/1000.0); + result.m_timeInS = timeInMS/1000.0; return result; }