From 85cf7346df97b51347e8cbd3577fa241b315f45e Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 31 Aug 2024 08:35:50 +0200 Subject: [PATCH 01/64] Cleanup code, improve GUI experience in weather report dialog --- src/notam/Notam.cpp | 25 ++++++++++++++++--------- src/notam/Notam.h | 19 ++++++++++++++----- src/notam/NotamList.cpp | 1 + src/notam/NotamList.h | 1 + src/qml/dialogs/WeatherReport.qml | 2 +- src/weather/METAR.cpp | 2 +- 6 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/notam/Notam.cpp b/src/notam/Notam.cpp index df3df92e0..39deaa30b 100644 --- a/src/notam/Notam.cpp +++ b/src/notam/Notam.cpp @@ -250,9 +250,9 @@ QString NOTAM::Notam::richText() const result += u"%1 until %2"_qs.arg(effectiveStartString, effectiveEndString); } - if ((m_minimumFL.size() == 3) && (m_maximumFL.size() == 3) && !(m_minimumFL == "000" && m_maximumFL == "999")) + if ((m_minimumFL.size() == 3) && (m_maximumFL.size() == 3) && !(m_minimumFL == u"000"_qs && m_maximumFL == u"999"_qs)) { - result += u"FL%1-FL%2"_qs.arg(m_minimumFL, m_maximumFL).replace("FL000", "GND"); + result += u"FL%1-FL%2"_qs.arg(m_minimumFL, m_maximumFL).replace(u"FL000"_qs, u"GND"_qs); } if (!m_schedule.isEmpty()) @@ -278,33 +278,38 @@ QString NOTAM::Notam::richText() const } -QString NOTAM::Notam::sectionTitle() const +void NOTAM::Notam::updateSectionTitle() { if (GlobalObject::notamProvider()->isRead(m_number)) { - return "Marked as read"; + m_sectionTitle = u"Marked as read"_qs; + return; } if (m_effectiveStart.isValid()) { if (m_effectiveStart < QDateTime::currentDateTimeUtc()) { - return "Current"; + m_sectionTitle = u"Current"_qs; + return; } if (m_effectiveStart < QDateTime::currentDateTimeUtc().addDays(1)) { - return "Next 24h"; + m_sectionTitle = u"Next 24h"_qs; + return; } if (m_effectiveStart < QDateTime::currentDateTimeUtc().addDays(90)) { - return "Next 90 days"; + m_sectionTitle = u"Next 90 days"_qs; + return; } if (m_effectiveStart < QDateTime::currentDateTimeUtc().addDays(90)) { - return "> 90 days"; + m_sectionTitle = u"> 90 days"_qs; + return; } } - return "NOTAM"; + m_sectionTitle = u"NOTAM"_qs; } @@ -372,6 +377,7 @@ QDataStream& NOTAM::operator<<(QDataStream& stream, const NOTAM::Notam& notam) stream << notam.m_radius; stream << notam.m_region; stream << notam.m_schedule; + stream << notam.m_sectionTitle; stream << notam.m_text; stream << notam.m_traffic; @@ -394,6 +400,7 @@ QDataStream& NOTAM::operator>>(QDataStream& stream, NOTAM::Notam& notam) stream >> notam.m_radius; stream >> notam.m_region; stream >> notam.m_schedule; + stream >> notam.m_sectionTitle; stream >> notam.m_text; stream >> notam.m_traffic; diff --git a/src/notam/Notam.h b/src/notam/Notam.h index 65be2d45e..1d32f2398 100644 --- a/src/notam/Notam.h +++ b/src/notam/Notam.h @@ -98,8 +98,12 @@ class Notam { /*! \brief Region where this NOTAM is valid */ Q_PROPERTY(QGeoCircle region READ region CONSTANT) -#warning - Q_PROPERTY(QString sectionTitle READ sectionTitle CONSTANT) + /*! \brief Section title + * + * This member can be set as desired, to allow for section titles + * when displaying NOTAMs in a QML ListView. + */ + Q_PROPERTY(QString sectionTitle MEMBER m_sectionTitle) /*! \brief Traffic entry of the NOTAM */ Q_PROPERTY(QString traffic READ traffic CONSTANT) @@ -169,9 +173,6 @@ class Notam { */ Q_REQUIRED_RESULT QGeoCircle region() const { return m_region; } -#warning - Q_REQUIRED_RESULT QString sectionTitle() const; - /*! \brief Getter function for the property with the same name * * @returns Property traffic @@ -210,6 +211,13 @@ class Notam { */ Q_REQUIRED_RESULT Q_INVOKABLE QString richText() const; + /*! \brief Update section title according to the current time + * + * This method uses the current time to set the NOTAM's section title to one of + * "Marked as read", "Current", "Next 24h", "Next 90 days", "> 90 days" or + * "NOTAM". + */ + void updateSectionTitle(); private: /* Notam members, as described by the FAA */ @@ -222,6 +230,7 @@ class Notam { QString m_minimumFL; QString m_number; Units::Distance m_radius; + QString m_sectionTitle; QString m_schedule; QString m_text; QString m_traffic; diff --git a/src/notam/NotamList.cpp b/src/notam/NotamList.cpp index 9cd4a4c5e..c4b83ab5d 100644 --- a/src/notam/NotamList.cpp +++ b/src/notam/NotamList.cpp @@ -182,6 +182,7 @@ NOTAM::NotamList NOTAM::NotamList::restricted(const GeoMaps::Waypoint& waypoint) { continue; } + notam.updateSectionTitle(); result.m_notams.append(notam); } diff --git a/src/notam/NotamList.h b/src/notam/NotamList.h index c4bdf86ec..975666479 100644 --- a/src/notam/NotamList.h +++ b/src/notam/NotamList.h @@ -174,6 +174,7 @@ class NotamList { * @param waypoint Waypoint * * @returns NotamList with all notams centered within restrictionRadius of the given waypoint, without expired and duplicated NOTAMs. + * Section titles are set depending on the current time, using NOTAM::updateSectionTitle(). */ Q_REQUIRED_RESULT NOTAM::NotamList restricted(const GeoMaps::Waypoint& waypoint) const; diff --git a/src/qml/dialogs/WeatherReport.qml b/src/qml/dialogs/WeatherReport.qml index 2b0f152fa..f131762d1 100644 --- a/src/qml/dialogs/WeatherReport.qml +++ b/src/qml/dialogs/WeatherReport.qml @@ -37,7 +37,7 @@ CenteringDialog { modal: true standardButtons: Dialog.Close - title: weatherStation ? weatherStation.extendedName : "" + title: weatherStation ? weatherStation.ICAOCode + " • " + weatherStation.extendedName : "" ColumnLayout { anchors.fill: parent diff --git a/src/weather/METAR.cpp b/src/weather/METAR.cpp index 07982bdd2..f30e2adc8 100644 --- a/src/weather/METAR.cpp +++ b/src/weather/METAR.cpp @@ -279,7 +279,7 @@ auto Weather::METAR::summary() const -> QString { } if (resultList.isEmpty()) { - return {}; + return tr("%1 %2").arg(messageType(), Navigation::Clock::describeTimeDifference(_observationTime)); } return tr("%1 %2: %3").arg(messageType(), Navigation::Clock::describeTimeDifference(_observationTime), resultList.join(QStringLiteral(" • "))); From c5520db988ef0506fd389a9b801ab8d9d117e1fa Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 31 Aug 2024 17:50:38 +0200 Subject: [PATCH 02/64] Clean up and update --- src/notam/Notam.h | 22 +++++++++++----------- src/notam/NotamList.h | 19 +++++++++++-------- src/notam/NotamProvider.h | 9 ++++++++- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/notam/Notam.h b/src/notam/Notam.h index 1d32f2398..492602c9f 100644 --- a/src/notam/Notam.h +++ b/src/notam/Notam.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2023 by Stefan Kebekus * + * Copyright (C) 2023-2024 by Stefan Kebekus * * stefan.kebekus@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -55,18 +55,18 @@ class Notam { /*! \brief Flight Information Region of this NOTAM */ Q_PROPERTY(QString affectedFIR READ affectedFIR CONSTANT) - /*! \brief Cancels other Notam + /*! \brief Cancels other NOTAM * - * If this is a cancel notam, then this property holds the number - * of the notam that is to be cancelled. Otherwise, this property - * holds an empty string. + * If this is a cancel notam, then this property holds the number of the + * notam that is to be cancelled. Otherwise, this property holds an empty + * string. */ Q_PROPERTY(QString cancels READ cancels CONSTANT) - /*! \brief Coordinates of the Notam */ + /*! \brief Coordinates of the NOTAM */ Q_PROPERTY(QGeoCoordinate coordinate READ coordinate CONSTANT) - /*! \brief Effective end of the Notam, if date is given + /*! \brief Effective end of the NOTAM, if date is given * * If the effectiveEnd field of the Notam specified a precise date/time, * then this time is found here. If not, the property contains an invalid @@ -74,7 +74,7 @@ class Notam { */ Q_PROPERTY(QDateTime effectiveEnd READ effectiveEnd CONSTANT) - /*! \brief Effective start of the Notam, if date is given + /*! \brief Effective start of the NOTAM, if date is given * * If the effectiveStart field of the Notam specified a precise date/time, * then this time is found here. If not, the property contains an invalid @@ -213,9 +213,9 @@ class Notam { /*! \brief Update section title according to the current time * - * This method uses the current time to set the NOTAM's section title to one of - * "Marked as read", "Current", "Next 24h", "Next 90 days", "> 90 days" or - * "NOTAM". + * This method uses the current time to set the NOTAM's section title to + * one of "Marked as read", "Current", "Next 24h", "Next 90 days", "> 90 + * days" or "NOTAM". */ void updateSectionTitle(); diff --git a/src/notam/NotamList.h b/src/notam/NotamList.h index 975666479..ed5fe1fa6 100644 --- a/src/notam/NotamList.h +++ b/src/notam/NotamList.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2023 by Stefan Kebekus * + * Copyright (C) 2023-2024 by Stefan Kebekus * * stefan.kebekus@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -54,8 +54,8 @@ class NotamList { /*! \brief Constructs a NotamList from FAA GeoJSON data * * This constructor sets the member m_retrieved to - * QDateTime::currentDateTimeUtc(). Invalid Notams and Cancel Notams - * will not be added to the list. + * QDateTime::currentDateTimeUtc(). Invalid Notams and Cancel Notams will + * not be added to the list. * * @param jsonDoc JSON dociment, as provided by the FAA * @@ -140,14 +140,15 @@ class NotamList { /*! \brief Time span between retrieved and now * - * @returns Time span between retrieved and now. If retrieved() is invalid, and invalid time is returned. + * @returns Time span between retrieved and now. If retrieved() is invalid, + * and invalid time is returned. */ Q_REQUIRED_RESULT Units::Timespan age() const; /*! \brief Sublist with expired and duplicated entries removed * - * @param cancelledNotamNumbers Set with numbers of notams that are - * known as cancelled + * @param cancelledNotamNumbers Set with numbers of notams that are known + * as cancelled * * @returns Sublist with expired and duplicated entries removed. */ @@ -173,8 +174,10 @@ class NotamList { * * @param waypoint Waypoint * - * @returns NotamList with all notams centered within restrictionRadius of the given waypoint, without expired and duplicated NOTAMs. - * Section titles are set depending on the current time, using NOTAM::updateSectionTitle(). + * @returns NotamList with all notams centered within restrictionRadius of + * the given waypoint, without expired and duplicated NOTAMs. Section + * titles are set depending on the current time, using + * NOTAM::updateSectionTitle(). */ Q_REQUIRED_RESULT NOTAM::NotamList restricted(const GeoMaps::Waypoint& waypoint) const; diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index c2d5e7208..44ac402f8 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2023 by Stefan Kebekus * + * Copyright (C) 2023-2024 by Stefan Kebekus * * stefan.kebekus@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -72,6 +72,8 @@ class NotamProvider : public GlobalObject { /*! \brief Waypoints with Notam items, for presentation in a map */ Q_PROPERTY(QList waypoints READ waypoints NOTIFY dataChanged) +#warning + Q_PROPERTY(QString status READ status NOTIFY statusChanged) // @@ -97,6 +99,8 @@ class NotamProvider : public GlobalObject { */ Q_REQUIRED_RESULT QList waypoints() const; +#warning + Q_REQUIRED_RESULT QString status() const; // @@ -142,6 +146,9 @@ class NotamProvider : public GlobalObject { /*! \brief Notifier signal */ void dataChanged(); + /*! \brief Notifier signal */ + void statusChanged(); + private slots: // Removes outdated and irrelevant data from the database. This slot is called // once per hour. From 9ac00be5ad03369b3a5b0118d1095051ad73e2a9 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Tue, 3 Sep 2024 14:31:03 +0200 Subject: [PATCH 03/64] Saving intermediate work --- src/notam/NotamProvider.h | 9 - src/qml/items/MFM.qml | 349 +++++++++++++++------------- src/qml/items/NavBar.qml | 2 +- src/qml/items/RemainingRouteBar.qml | 4 +- 4 files changed, 192 insertions(+), 172 deletions(-) diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index 44ac402f8..40cc557b7 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -72,9 +72,6 @@ class NotamProvider : public GlobalObject { /*! \brief Waypoints with Notam items, for presentation in a map */ Q_PROPERTY(QList waypoints READ waypoints NOTIFY dataChanged) -#warning - Q_PROPERTY(QString status READ status NOTIFY statusChanged) - // // Getter Methods @@ -99,9 +96,6 @@ class NotamProvider : public GlobalObject { */ Q_REQUIRED_RESULT QList waypoints() const; -#warning - Q_REQUIRED_RESULT QString status() const; - // // Methods @@ -146,9 +140,6 @@ class NotamProvider : public GlobalObject { /*! \brief Notifier signal */ void dataChanged(); - /*! \brief Notifier signal */ - void statusChanged(); - private slots: // Removes outdated and irrelevant data from the database. This slot is called // once per hour. diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 5d79f63d5..0e2b75afd 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -218,6 +218,10 @@ Item { Binding on center { id: centerBinding + // #warning + // Error here: this section should compute the coordinate for the center of the display + // It does compute the coordiname for the center of centerItem, which is not the same. + restoreMode: Binding.RestoreNone when: flightMap.followGPS === true value: { @@ -232,13 +236,11 @@ Item { // of the aircraft. The following lines find a good radius for that // circle, which ensures that the circle does not collide with any of the // GUI elements. - const xCenter = flightMap.width/2.0 - const yCenter = flightMap.height/2.0 + const xCenter = centerItem.x + centerItem.width/2.0 + const yCenter = centerItem.y + centerItem.height/2.0 const radiusInPixel = Math.min( - Math.abs(xCenter-zoomIn.x), - Math.abs(xCenter-followGPSButton.x-followGPSButton.width), - Math.abs(yCenter-northButton.y-northButton.height), - Math.abs(yCenter-zoomIn.y) + centerItem.width/2.0, + centerItem.height/2.0 ) const radiusInM = 10000.0*radiusInPixel/flightMap.pixelPer10km @@ -590,219 +592,246 @@ Item { } } - RemainingRouteBar { - id: remainingRoute + GridLayout { + anchors.fill: parent + columns: 3 - visible: !Global.currentVAC.isValid + RemainingRouteBar { + id: remainingRoute - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - } + Layout.columnSpan: 3 + Layout.fillWidth: true - Pane { - id: airspaceAltLabel + visible: !Global.currentVAC.isValid + } - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: menuButton.verticalCenter - topPadding: 0 - bottomPadding: 0 - visible: (!Global.currentVAC.isValid) && GlobalSettings.airspaceAltitudeLimit.isFinite() && !DataManager.baseMapsRaster.hasFile + Item { + implicitHeight: menuButton.implicitHeight + implicitWidth: menuButton.implicitBackgroundWidth - Label { + MapButton { + id: menuButton - text: { - // Mention - Navigator.aircraft.verticalDistanceUnit + icon.source: "/icons/material/ic_menu.svg" + visible: !Global.currentVAC.isValid - var airspaceAltitudeLimit = GlobalSettings.airspaceAltitudeLimit - var airspaceAltitudeLimitString = Navigator.aircraft.verticalDistanceToString(airspaceAltitudeLimit) - return " "+qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString)+" " + onClicked: { + PlatformAdaptor.vibrateBrief() + drawer.open() + } } } - } - MapButton { - id: menuButton - icon.source: "/icons/material/ic_menu.svg" + Item { + Layout.alignment: Qt.AlignHCenter - anchors.left: parent.left - anchors.leftMargin: 0.5*font.pixelSize + SafeInsets.left - anchors.top: remainingRoute.visible ? remainingRoute.bottom : parent.top - anchors.topMargin: 0.5*font.pixelSize + implicitHeight: airspaceAltLabel.implicitHeight + implicitWidth: airspaceAltLabel.implicitWidth - visible: !Global.currentVAC.isValid + Label { + id: airspaceAltLabel + visible: (!Global.currentVAC.isValid) && GlobalSettings.airspaceAltitudeLimit.isFinite() && !DataManager.baseMapsRaster.hasFile - onClicked: { - PlatformAdaptor.vibrateBrief() - drawer.open() - } - } + text: { + // Mention + Navigator.aircraft.verticalDistanceUnit - MapButton { - id: northButton + var airspaceAltitudeLimit = GlobalSettings.airspaceAltitudeLimit + var airspaceAltitudeLimitString = Navigator.aircraft.verticalDistanceToString(airspaceAltitudeLimit) + return " "+qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString)+" " + } + background: Rectangle { + color: "white" + opacity: 0.8 + } - anchors.horizontalCenter: zoomIn.horizontalCenter - anchors.verticalCenter: menuButton.verticalCenter + } + } + + MapButton { + id: northButton - rotation: -flightMap.bearing + rotation: -flightMap.bearing - icon.source: "/icons/NorthArrow.svg" + icon.source: "/icons/NorthArrow.svg" - onClicked: { - if (GlobalSettings.mapBearingPolicy === GlobalSettings.NUp) { - GlobalSettings.mapBearingPolicy = GlobalSettings.TTUp - toast.doToast(qsTr("Map Mode: Track Up")) - } else { - GlobalSettings.mapBearingPolicy = GlobalSettings.NUp - toast.doToast(qsTr("Map Mode: North Up")) + onClicked: { + if (GlobalSettings.mapBearingPolicy === GlobalSettings.NUp) { + GlobalSettings.mapBearingPolicy = GlobalSettings.TTUp + toast.doToast(qsTr("Map Mode: Track Up")) + } else { + GlobalSettings.mapBearingPolicy = GlobalSettings.NUp + toast.doToast(qsTr("Map Mode: North Up")) + } } } - } - MapButton { - id: followGPSButton - icon.source: "/icons/material/ic_my_location.svg" + Item { + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: 24 - enabled: !flightMap.followGPS + Scale { + id: leftScale - anchors.left: parent.left - anchors.leftMargin: 0.5*font.pixelSize + SafeInsets.left - anchors.bottom: trafficDataReceiverButton.top - anchors.bottomMargin: trafficDataReceiverButton.visible ? 0.5*font.pixelSize : 1.5*font.pixelSize + anchors.fill: parent + opacity: GlobalSettings.nightMode ? 0.3 : 1.0 + visible: (!Global.currentVAC.isValid) && !scale.visible - onClicked: { - PlatformAdaptor.vibrateBrief() - flightMap.followGPS = true - toast.doToast(qsTr("Map Mode: Autopan")) + pixelPer10km: flightMap.pixelPer10km + vertical: true + } } - } - MapButton { - id: trafficDataReceiverButton + Rectangle { + id: centerItem + + color: "white" + opacity: 0.3 + Layout.fillHeight: true + Layout.fillWidth: true + } + + Item { + Layout.fillHeight: true + } - icon.source: "/icons/material/ic_airplanemode_active.svg" - icon.color: "red" - enabled: !TrafficDataProvider.receivingHeartbeat - anchors.left: parent.left - anchors.leftMargin: 0.5*font.pixelSize + SafeInsets.left - anchors.bottom: navBar.top - anchors.bottomMargin: visible ? 1.5*font.pixelSize : 0 + Item { + implicitHeight: followGPSButton.implicitHeight + implicitWidth: followGPSButton.implicitBackgroundWidth + MapButton { + id: followGPSButton - onClicked: { - PlatformAdaptor.vibrateBrief() - PlatformAdaptor.vibrateBrief() - stackView.pop() - stackView.push("../pages/TrafficReceiver.qml", {"appWindow": view}) + icon.source: "/icons/material/ic_my_location.svg" + + enabled: !flightMap.followGPS + + onClicked: { + PlatformAdaptor.vibrateBrief() + flightMap.followGPS = true + toast.doToast(qsTr("Map Mode: Autopan")) + } + } } - } - MapButton { - id: zoomIn + Item { + Layout.fillWidth: true + } - icon.source: "/icons/material/ic_add.svg" - enabled: flightMap.zoomLevel < flightMap.maximumZoomLevel - autoRepeat: true + Item { + implicitHeight: zoomIn.implicitHeight + implicitWidth: zoomIn.implicitBackgroundWidth + MapButton { + id: zoomIn - anchors.right: parent.right - anchors.rightMargin: 0.5*font.pixelSize + SafeInsets.right - anchors.bottom: zoomOut.top - anchors.bottomMargin: 0.5*font.pixelSize + icon.source: "/icons/material/ic_add.svg" + enabled: flightMap.zoomLevel < flightMap.maximumZoomLevel + autoRepeat: true - onClicked: { - centerBindingAnimation.omitAnimationforZoom() - PlatformAdaptor.vibrateBrief() - flightMap.zoomLevel += 1 + onClicked: { + centerBindingAnimation.omitAnimationforZoom() + PlatformAdaptor.vibrateBrief() + flightMap.zoomLevel += 1 + } + } } - } - MapButton { - id: zoomOut - icon.source: "/icons/material/ic_remove.svg" - enabled: flightMap.zoomLevel > flightMap.minimumZoomLevel - autoRepeat: true + Item { + implicitHeight: trafficDataReceiverButton.implicitHeight + implicitWidth: trafficDataReceiverButton.implicitWidth + MapButton { + id: trafficDataReceiverButton - anchors.right: parent.right - anchors.rightMargin: 0.5*font.pixelSize + SafeInsets.right - anchors.bottom: navBar.top - anchors.bottomMargin: 1.5*font.pixelSize + icon.source: "/icons/material/ic_airplanemode_active.svg" + icon.color: "red" + enabled: !TrafficDataProvider.receivingHeartbeat - onClicked: { - centerBindingAnimation.omitAnimationforZoom() - PlatformAdaptor.vibrateBrief() - var newZoomLevel = Math.max(flightMap.zoomLevel - 1, flightMap.minimumZoomLevel) - flightMap.zoomLevel = newZoomLevel + onClicked: { + PlatformAdaptor.vibrateBrief() + PlatformAdaptor.vibrateBrief() + stackView.pop() + stackView.push("../pages/TrafficReceiver.qml", {"appWindow": view}) + } + } } - } - Scale { - id: leftScale + Item { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: 24 - anchors.top: northButton.bottom - anchors.topMargin: 0.5*font.pixelSize - anchors.bottom: followGPSButton.top - anchors.bottomMargin: 0.5*font.pixelSize - anchors.horizontalCenter: followGPSButton.horizontalCenter + Scale { + id: scale - opacity: GlobalSettings.nightMode ? 0.3 : 1.0 - visible: (!Global.currentVAC.isValid) && !scale.visible + anchors.fill: parent - pixelPer10km: flightMap.pixelPer10km - vertical: true - width: 30 - } + opacity: GlobalSettings.nightMode ? 0.3 : 1.0 + visible: (!Global.currentVAC.isValid) && (page.height > page.width) + + pixelPer10km: flightMap.pixelPer10km + vertical: false + } + } - Scale { - id: scale + Item { + implicitHeight: zoomOut.implicitHeight + implicitWidth: zoomOut.implicitBackgroundWidth + MapButton { + id: zoomOut - anchors.left: followGPSButton.right - anchors.leftMargin: 0.5*font.pixelSize - anchors.right: zoomIn.left - anchors.rightMargin: 0.5*font.pixelSize - anchors.verticalCenter: zoomOut.verticalCenter + icon.source: "/icons/material/ic_remove.svg" + enabled: flightMap.zoomLevel > flightMap.minimumZoomLevel + autoRepeat: true - opacity: GlobalSettings.nightMode ? 0.3 : 1.0 - visible: (!Global.currentVAC.isValid) && (parent.height > parent.width) + onClicked: { + centerBindingAnimation.omitAnimationforZoom() + PlatformAdaptor.vibrateBrief() + var newZoomLevel = Math.max(flightMap.zoomLevel - 1, flightMap.minimumZoomLevel) + flightMap.zoomLevel = newZoomLevel + } + } + } - pixelPer10km: flightMap.pixelPer10km - vertical: false - height: 30 - } - Pane { - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: navBar.top - anchors.bottomMargin: 0.4*font.pixelSize - topPadding: 0 - bottomPadding: 0 + Item { + Layout.columnSpan: 3 + Layout.alignment: Qt.AlignHCenter - visible: (!Global.currentVAC.isValid) - Label { - id: noCopyrightInfo - text: ""+qsTr("Map Data Copyright Info")+"" - onLinkActivated: { - Global.dialogLoader.active = false - Global.dialogLoader.setSource("../dialogs/LongTextDialog.qml", {title: qsTr("Map Data Copyright Information"), - text: GeoMapProvider.copyrightNotice, - standardButtons: Dialog.Ok}) - Global.dialogLoader.active = true + implicitHeight: noCopyrightInfo.implicitHeight + implicitWidth: noCopyrightInfo.implicitWidth + + Label { + id: noCopyrightInfo + visible: (!Global.currentVAC.isValid) + text: ""+qsTr("Map Data Copyright Info")+"" + onLinkActivated: { + Global.dialogLoader.active = false + Global.dialogLoader.setSource("../dialogs/LongTextDialog.qml", {title: qsTr("Map Data Copyright Information"), + text: GeoMapProvider.copyrightNotice, + standardButtons: Dialog.Ok}) + Global.dialogLoader.active = true + } + background: Rectangle { + color: "white" + opacity: 0.8 + } } } - } - NavBar { - id: navBar + NavBar { + id: navBar - anchors.right: parent.right - anchors.left: parent.left + Layout.fillWidth: true + Layout.columnSpan: 3 + } - y: parent.height - height } + WaypointDescription { id: waypointDescription objectName: "waypointDescription" diff --git a/src/qml/items/NavBar.qml b/src/qml/items/NavBar.qml index 4def1bb0c..1620d9d76 100644 --- a/src/qml/items/NavBar.qml +++ b/src/qml/items/NavBar.qml @@ -29,7 +29,7 @@ Rectangle { color: "#AA000000" - height: trueAltitude.implicitHeight + SafeInsets.bottom + implicitHeight: trueAltitude.implicitHeight + SafeInsets.bottom // Dummy control. Used to glean the font size. Control { diff --git a/src/qml/items/RemainingRouteBar.qml b/src/qml/items/RemainingRouteBar.qml index c61952ac3..b1b4ec2ed 100644 --- a/src/qml/items/RemainingRouteBar.qml +++ b/src/qml/items/RemainingRouteBar.qml @@ -30,8 +30,8 @@ Rectangle { // Remaining route info shown in this item property var rri: Navigator.remainingRouteInfo - height: grid.implicitHeight + SafeInsets.top - Behavior on height { NumberAnimation { duration: 100 } } + implicitHeight: grid.implicitHeight + SafeInsets.top + Behavior on implicitHeight { NumberAnimation { duration: 100 } } clip: true From 74f7e0d82427f6c1c1cc84442522d04be44a1416 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Wed, 4 Sep 2024 08:30:24 +0200 Subject: [PATCH 04/64] Update MFM.qml --- src/qml/items/MFM.qml | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 0e2b75afd..07fba2204 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -58,7 +58,7 @@ Item { property bool followGPS: true property real animatedTrack: PositionProvider.lastValidTT.isFinite() ? PositionProvider.lastValidTT.toDEG() : 0 - Behavior on animatedTrack { RotationAnimation {duration: 400; direction: RotationAnimation.Shortest } } + Behavior on animatedTrack { RotationAnimation {duration: 1000; direction: RotationAnimation.Shortest } } // GESTURES @@ -210,9 +210,22 @@ Item { // PROPERTY "center" // + // Initially, set the center to the last saved value - center: PositionProvider.lastValidCoordinate + //center: PositionProvider.lastValidCoordinate + + property real xx: { + var xCenter = centerItem.x + centerItem.width/2.0 + var yCenter = centerItem.y + centerItem.height/2.0 + const radiusInPixel = Math.min(centerItem.width/2.0, centerItem.height/2.0) + xCenter -= (radiusInPixel*Math.sin((animatedTrack - flightMap.bearing) * Math.PI / 180.0)) + yCenter += (radiusInPixel*Math.cos((animatedTrack - flightMap.bearing) * Math.PI / 180.0)) + flightMap.alignCoordinateToPoint(ownPosition.coordinate, Qt.point(xCenter, yCenter)) + return 0 + } + +/* // If "followGPS" is true, then update the map center whenever a new GPS position comes in // or the zoom level changes Binding on center { @@ -266,7 +279,7 @@ Item { interval: 410 // little more than time for animation onTriggered: centerBindingAnimation.enabled = true } - +*/ // // PROPERTY "zoomLevel" @@ -788,11 +801,11 @@ Item { autoRepeat: true onClicked: { - centerBindingAnimation.omitAnimationforZoom() - PlatformAdaptor.vibrateBrief() - var newZoomLevel = Math.max(flightMap.zoomLevel - 1, flightMap.minimumZoomLevel) - flightMap.zoomLevel = newZoomLevel - } + centerBindingAnimation.omitAnimationforZoom() + PlatformAdaptor.vibrateBrief() + var newZoomLevel = Math.max(flightMap.zoomLevel - 1, flightMap.minimumZoomLevel) + flightMap.zoomLevel = newZoomLevel + } } } From 50fdbff511229e841b1b95bb94bb7361f8164390 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Thu, 5 Sep 2024 20:10:28 +0200 Subject: [PATCH 05/64] Update MFM.qml --- src/qml/items/MFM.qml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 07fba2204..79b828a4e 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -215,12 +215,18 @@ Item { //center: PositionProvider.lastValidCoordinate property real xx: { + if (!flightMap.followGPS) + return 0 + var xCenter = centerItem.x + centerItem.width/2.0 var yCenter = centerItem.y + centerItem.height/2.0 - const radiusInPixel = Math.min(centerItem.width/2.0, centerItem.height/2.0) - xCenter -= (radiusInPixel*Math.sin((animatedTrack - flightMap.bearing) * Math.PI / 180.0)) - yCenter += (radiusInPixel*Math.cos((animatedTrack - flightMap.bearing) * Math.PI / 180.0)) + if ((Navigator.flightStatus === Navigator.Flight) && PositionProvider.lastValidTT.isFinite()) + { + const radiusInPixel = Math.min(centerItem.width/2.0, centerItem.height/2.0) + xCenter -= (radiusInPixel*Math.sin((animatedTrack - flightMap.bearing) * Math.PI / 180.0)) + yCenter += (radiusInPixel*Math.cos((animatedTrack - flightMap.bearing) * Math.PI / 180.0)) + } flightMap.alignCoordinateToPoint(ownPosition.coordinate, Qt.point(xCenter, yCenter)) return 0 } From 3e8bcd9490c1b0c95ee523f0e5f895e8f15194b0 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Fri, 6 Sep 2024 10:44:03 +0200 Subject: [PATCH 06/64] Update MFM.qml --- src/qml/items/MFM.qml | 105 ++++++++++++------------------------------ 1 file changed, 29 insertions(+), 76 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 79b828a4e..d9f3c5bff 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -134,18 +134,19 @@ Item { : PointerDevice.Mouse onWheel: (event) => { const loc = flightMap.toCoordinate(wheel.point.position) - switch (event.modifiers) { - case Qt.NoModifier: + if (event.modifiers === Qt.NoModifier) + { zoomLevelBehavior.enabled = false flightMap.zoomLevel += event.angleDelta.y / 240 zoomLevelBehavior.enabled = true - break - case Qt.ShiftModifier: + } + else + { bearingBehavior.enabled = false flightMap.bearing += event.angleDelta.y / 5 bearingBehavior.enabled = true - break } + flightMap.followGPS = false; flightMap.alignCoordinateToPoint(loc, wheel.point.position) } } @@ -214,78 +215,35 @@ Item { // Initially, set the center to the last saved value //center: PositionProvider.lastValidCoordinate - property real xx: { - if (!flightMap.followGPS) - return 0 - - var xCenter = centerItem.x + centerItem.width/2.0 - var yCenter = centerItem.y + centerItem.height/2.0 - if ((Navigator.flightStatus === Navigator.Flight) && PositionProvider.lastValidTT.isFinite()) - { - const radiusInPixel = Math.min(centerItem.width/2.0, centerItem.height/2.0) - xCenter -= (radiusInPixel*Math.sin((animatedTrack - flightMap.bearing) * Math.PI / 180.0)) - yCenter += (radiusInPixel*Math.cos((animatedTrack - flightMap.bearing) * Math.PI / 180.0)) - } - flightMap.alignCoordinateToPoint(ownPosition.coordinate, Qt.point(xCenter, yCenter)) - return 0 - } - -/* // If "followGPS" is true, then update the map center whenever a new GPS position comes in // or the zoom level changes - Binding on center { - id: centerBinding - - // #warning - // Error here: this section should compute the coordinate for the center of the display - // It does compute the coordiname for the center of centerItem, which is not the same. - - restoreMode: Binding.RestoreNone - when: flightMap.followGPS === true - value: { - // If not in flight, then aircraft stays in center of display - if (Navigator.flightStatus !== Navigator.Flight) - return PositionProvider.lastValidCoordinate - if (!PositionProvider.lastValidTT.isFinite()) - return PositionProvider.lastValidCoordinate - - // Otherwise, we position the aircraft someplace on a circle around the - // center, so that the map shows a larger portion of the airspace ahead - // of the aircraft. The following lines find a good radius for that - // circle, which ensures that the circle does not collide with any of the - // GUI elements. - const xCenter = centerItem.x + centerItem.width/2.0 - const yCenter = centerItem.y + centerItem.height/2.0 - const radiusInPixel = Math.min( - centerItem.width/2.0, - centerItem.height/2.0 - ) - const radiusInM = 10000.0*radiusInPixel/flightMap.pixelPer10km - - return PositionProvider.lastValidCoordinate.atDistanceAndAzimuth(radiusInM, PositionProvider.lastValidTT.toDEG()) - } - } + property var centerCoordinate: { + // If not in flight, then aircraft stays in center of display + if (Navigator.flightStatus !== Navigator.Flight) + return ownPosition.coordinate + if (!PositionProvider.lastValidTT.isFinite()) + return ownPosition.coordinate - // We expect GPS updates every second. So, we choose an animation of duration 1000ms here, to obtain a flowing movement - Behavior on center { - id: centerBindingAnimation - CoordinateAnimation { duration: 1000 } - enabled: true - - function omitAnimationforZoom() { - centerBindingAnimation.enabled = false - omitAnimationForZoomTimer.stop() // stop in case it was already runnnig - omitAnimationForZoomTimer.start() - } + // Otherwise, we position the aircraft someplace on a circle around the + // center, so that the map shows a larger portion of the airspace ahead + // of the aircraft. The following lines find a good radius for that + // circle, which ensures that the circle does not collide with any of the + // GUI elements. + const radiusInPixel = Math.min(centerItem.width/2.0, centerItem.height/2.0) + const radiusInM = 10000.0*radiusInPixel/flightMap.pixelPer10km + + return ownPosition.coordinate.atDistanceAndAzimuth(radiusInM, animatedTrack) } - Timer { - id: omitAnimationForZoomTimer - interval: 410 // little more than time for animation - onTriggered: centerBindingAnimation.enabled = true + onCenterCoordinateChanged: { + if (!flightMap.followGPS) + return + var xCenter = centerItem.x + centerItem.width/2.0 + var yCenter = centerItem.y + centerItem.height/2.0 + flightMap.alignCoordinateToPoint(centerCoordinate, Qt.point(xCenter, yCenter)) } -*/ + // // PROPERTY "zoomLevel" @@ -407,10 +365,7 @@ Item { id: ownPosition coordinate: PositionProvider.lastValidCoordinate - - Behavior on coordinate { - CoordinateAnimation { duration: 1000 } - } + Behavior on coordinate { CoordinateAnimation { duration: 1000 } } Connections { // This is a workaround against a bug in Qt 5.15.2. The position of the MapQuickItem @@ -751,7 +706,6 @@ Item { autoRepeat: true onClicked: { - centerBindingAnimation.omitAnimationforZoom() PlatformAdaptor.vibrateBrief() flightMap.zoomLevel += 1 } @@ -807,7 +761,6 @@ Item { autoRepeat: true onClicked: { - centerBindingAnimation.omitAnimationforZoom() PlatformAdaptor.vibrateBrief() var newZoomLevel = Math.max(flightMap.zoomLevel - 1, flightMap.minimumZoomLevel) flightMap.zoomLevel = newZoomLevel From 91ff930ab871803c5804bdbf8bea1f99e65fd5db Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 7 Sep 2024 09:39:39 +0200 Subject: [PATCH 07/64] Update MFM.qml --- src/qml/items/MFM.qml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index d9f3c5bff..d81f7d099 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -170,6 +170,10 @@ Item { if (active) { flightMap.followGPS = false + if (GlobalSettings.mapBearingPolicy === GlobalSettings.TTUp) + { + GlobalSettings.mapBearingPolicy = GlobalSettings.UserDefinedBearingUp + } } } } @@ -196,6 +200,7 @@ Item { // If "followGPS" is true, then update the map bearing whenever a new GPS position comes in Binding on bearing { + restoreMode: Binding.RestoreNone when: GlobalSettings.mapBearingPolicy !== GlobalSettings.UserDefinedBearingUp value: GlobalSettings.mapBearingPolicy === GlobalSettings.TTUp ? PositionProvider.lastValidTT.toDEG() : 0 } @@ -244,6 +249,12 @@ Item { flightMap.alignCoordinateToPoint(centerCoordinate, Qt.point(xCenter, yCenter)) } + onMapReadyChanged: { + var xCenter = centerItem.x + centerItem.width/2.0 + var yCenter = centerItem.y + centerItem.height/2.0 + flightMap.alignCoordinateToPoint(centerCoordinate, Qt.point(xCenter, yCenter)) + } + // // PROPERTY "zoomLevel" From 4090ef77453e6c0cddeaa3725791c9a9fc652b41 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 8 Sep 2024 09:56:29 +0200 Subject: [PATCH 08/64] Update NotamProvider.h --- src/notam/NotamProvider.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index 44ac402f8..cc9edc7e4 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -73,7 +73,7 @@ class NotamProvider : public GlobalObject { Q_PROPERTY(QList waypoints READ waypoints NOTIFY dataChanged) #warning - Q_PROPERTY(QString status READ status NOTIFY statusChanged) +// Q_PROPERTY(QString status READ status NOTIFY statusChanged) // From eda61ef7c70e796c9e0653401313cffdc2c17a68 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 8 Sep 2024 09:58:37 +0200 Subject: [PATCH 09/64] Update enrouteText --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 60dbc81a7..3a5c25158 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 60dbc81a7115485c09f885312e6456dffb213ccd +Subproject commit 3a5c25158bde2b2170c43bb450961a1b6bdf1960 From 2843eff9eecd4e719f92d54b407fd6d25da1cc92 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 8 Sep 2024 12:57:26 +0200 Subject: [PATCH 10/64] Update MFM.qml --- src/qml/items/MFM.qml | 242 +++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 132 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index d81f7d099..9ee68daf1 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -590,10 +590,10 @@ Item { visible: !Global.currentVAC.isValid } + // Column 1: Main Menu / Vertical Scale / ... - Item { - implicitHeight: menuButton.implicitHeight - implicitWidth: menuButton.implicitBackgroundWidth + ColumnLayout { + Layout.fillHeight: true MapButton { id: menuButton @@ -602,20 +602,69 @@ Item { visible: !Global.currentVAC.isValid onClicked: { - PlatformAdaptor.vibrateBrief() - drawer.open() + PlatformAdaptor.vibrateBrief() + drawer.open() + } } + + Item { + Layout.alignment: Qt.AlignHCenter + Layout.fillHeight: true + Layout.preferredWidth: 24 + + Scale { + id: leftScale + + anchors.fill: parent + opacity: GlobalSettings.nightMode ? 0.3 : 1.0 + visible: (!Global.currentVAC.isValid) && !scale.visible + + pixelPer10km: flightMap.pixelPer10km + vertical: true + } + } + + MapButton { + id: followGPSButton + + icon.source: "/icons/material/ic_my_location.svg" + + enabled: !flightMap.followGPS + + onClicked: { + PlatformAdaptor.vibrateBrief() + flightMap.followGPS = true + toast.doToast(qsTr("Map Mode: Autopan")) + } + } + + MapButton { + id: trafficDataReceiverButton + + icon.source: "/icons/material/ic_airplanemode_active.svg" + icon.color: "red" + enabled: !TrafficDataProvider.receivingHeartbeat + + onClicked: { + PlatformAdaptor.vibrateBrief() + PlatformAdaptor.vibrateBrief() + stackView.pop() + stackView.push("../pages/TrafficReceiver.qml", {"appWindow": view}) + } } } - Item { - Layout.alignment: Qt.AlignHCenter + // Colmnn 2: Info Label / Center Item / Copyright / Horizontal Scale - implicitHeight: airspaceAltLabel.implicitHeight - implicitWidth: airspaceAltLabel.implicitWidth + ColumnLayout { + Layout.fillHeight: true + Layout.fillWidth: true Label { id: airspaceAltLabel + + Layout.alignment: Qt.AlignHCenter + visible: (!Global.currentVAC.isValid) && GlobalSettings.airspaceAltitudeLimit.isFinite() && !DataManager.baseMapsRaster.hasFile text: { @@ -626,89 +675,86 @@ Item { var airspaceAltitudeLimitString = Navigator.aircraft.verticalDistanceToString(airspaceAltitudeLimit) return " "+qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString)+" " } - background: Rectangle { - color: "white" - opacity: 0.8 - } + background: Rectangle { color: "white" } + } + Rectangle { + id: centerItem + + color: "white" + opacity: 0.3 + Layout.fillHeight: true + Layout.fillWidth: true } - } - MapButton { - id: northButton + Label { + id: noCopyrightInfo - rotation: -flightMap.bearing + Layout.alignment: Qt.AlignRight - icon.source: "/icons/NorthArrow.svg" + visible: (!Global.currentVAC.isValid) + text: " "+qsTr("Map Data ⓒ Info")+" " + opacity: 0.8 - onClicked: { - if (GlobalSettings.mapBearingPolicy === GlobalSettings.NUp) { - GlobalSettings.mapBearingPolicy = GlobalSettings.TTUp - toast.doToast(qsTr("Map Mode: Track Up")) - } else { - GlobalSettings.mapBearingPolicy = GlobalSettings.NUp - toast.doToast(qsTr("Map Mode: North Up")) + //style: Text.Outline + //styleColor: "white" + onLinkActivated: { + Global.dialogLoader.active = false + Global.dialogLoader.setSource("../dialogs/LongTextDialog.qml", {title: qsTr("Map Data Copyright Information"), + text: GeoMapProvider.copyrightNotice, + standardButtons: Dialog.Ok}) + Global.dialogLoader.active = true + } + background: Rectangle { + opacity: 0.8 + color: "lightgray" } } - } - - - Item { - Layout.fillHeight: true - Layout.alignment: Qt.AlignHCenter - Layout.preferredWidth: 24 Scale { - id: leftScale + id: scale + + Layout.bottomMargin: 14 + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: 24 - anchors.fill: parent opacity: GlobalSettings.nightMode ? 0.3 : 1.0 - visible: (!Global.currentVAC.isValid) && !scale.visible + visible: (!Global.currentVAC.isValid) && (page.height > page.width) pixelPer10km: flightMap.pixelPer10km - vertical: true + vertical: false } - } - - Rectangle { - id: centerItem - color: "white" - opacity: 0.3 - Layout.fillHeight: true - Layout.fillWidth: true } - Item { - Layout.fillHeight: true - } + // Column 3: North Button / Spacer / Zoom In / Zoom Out + ColumnLayout { + Layout.fillHeight: true - Item { - implicitHeight: followGPSButton.implicitHeight - implicitWidth: followGPSButton.implicitBackgroundWidth MapButton { - id: followGPSButton + id: northButton - icon.source: "/icons/material/ic_my_location.svg" + rotation: -flightMap.bearing - enabled: !flightMap.followGPS + icon.source: "/icons/NorthArrow.svg" onClicked: { - PlatformAdaptor.vibrateBrief() - flightMap.followGPS = true - toast.doToast(qsTr("Map Mode: Autopan")) - } + if (GlobalSettings.mapBearingPolicy === GlobalSettings.NUp) { + GlobalSettings.mapBearingPolicy = GlobalSettings.TTUp + toast.doToast(qsTr("Map Mode: Track Up")) + } else { + GlobalSettings.mapBearingPolicy = GlobalSettings.NUp + toast.doToast(qsTr("Map Mode: North Up")) + } + } } - } - Item { - Layout.fillWidth: true - } + Item { + Layout.fillHeight: true + } - Item { - implicitHeight: zoomIn.implicitHeight - implicitWidth: zoomIn.implicitBackgroundWidth MapButton { id: zoomIn @@ -721,49 +767,7 @@ Item { flightMap.zoomLevel += 1 } } - } - - - Item { - implicitHeight: trafficDataReceiverButton.implicitHeight - implicitWidth: trafficDataReceiverButton.implicitWidth - MapButton { - id: trafficDataReceiverButton - - icon.source: "/icons/material/ic_airplanemode_active.svg" - icon.color: "red" - enabled: !TrafficDataProvider.receivingHeartbeat - - onClicked: { - PlatformAdaptor.vibrateBrief() - PlatformAdaptor.vibrateBrief() - stackView.pop() - stackView.push("../pages/TrafficReceiver.qml", {"appWindow": view}) - } - } - } - - Item { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - Layout.preferredHeight: 24 - - Scale { - id: scale - - anchors.fill: parent - - opacity: GlobalSettings.nightMode ? 0.3 : 1.0 - visible: (!Global.currentVAC.isValid) && (page.height > page.width) - - pixelPer10km: flightMap.pixelPer10km - vertical: false - } - } - Item { - implicitHeight: zoomOut.implicitHeight - implicitWidth: zoomOut.implicitBackgroundWidth MapButton { id: zoomOut @@ -779,32 +783,6 @@ Item { } } - - Item { - Layout.columnSpan: 3 - Layout.alignment: Qt.AlignHCenter - - implicitHeight: noCopyrightInfo.implicitHeight - implicitWidth: noCopyrightInfo.implicitWidth - - Label { - id: noCopyrightInfo - visible: (!Global.currentVAC.isValid) - text: ""+qsTr("Map Data Copyright Info")+"" - onLinkActivated: { - Global.dialogLoader.active = false - Global.dialogLoader.setSource("../dialogs/LongTextDialog.qml", {title: qsTr("Map Data Copyright Information"), - text: GeoMapProvider.copyrightNotice, - standardButtons: Dialog.Ok}) - Global.dialogLoader.active = true - } - background: Rectangle { - color: "white" - opacity: 0.8 - } - } - } - NavBar { id: navBar From 2fb6ac5692d1937b9275223c7922e08f0d8fa7ea Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 8 Sep 2024 17:57:32 +0200 Subject: [PATCH 11/64] Update MFM.qml --- src/qml/items/MFM.qml | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 9ee68daf1..de873da57 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -539,7 +539,6 @@ Item { flightMap.center = waypoint.coordinate } } - } BrightnessContrast { // Graphical effects: increase contrast, reduce brightness in dark mode @@ -591,7 +590,6 @@ Item { } // Column 1: Main Menu / Vertical Scale / ... - ColumnLayout { Layout.fillHeight: true @@ -655,7 +653,6 @@ Item { } // Colmnn 2: Info Label / Center Item / Copyright / Horizontal Scale - ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true @@ -675,7 +672,7 @@ Item { var airspaceAltitudeLimitString = Navigator.aircraft.verticalDistanceToString(airspaceAltitudeLimit) return " "+qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString)+" " } - background: Rectangle { color: "white" } + background: Pane {} // Rectangle { color: "white" } } Rectangle { @@ -693,11 +690,12 @@ Item { Layout.alignment: Qt.AlignRight visible: (!Global.currentVAC.isValid) - text: " "+qsTr("Map Data ⓒ Info")+" " + text: " "+qsTr("ⓒ Map Data")+" " opacity: 0.8 //style: Text.Outline - //styleColor: "white" + //styleColor: GlobalSettings.nightMode ? "black" : "white" + background: Pane { opacity: GlobalSettings.nightMode ? 0.3 : 0.8 } onLinkActivated: { Global.dialogLoader.active = false Global.dialogLoader.setSource("../dialogs/LongTextDialog.qml", {title: qsTr("Map Data Copyright Information"), @@ -705,10 +703,6 @@ Item { standardButtons: Dialog.Ok}) Global.dialogLoader.active = true } - background: Rectangle { - opacity: 0.8 - color: "lightgray" - } } Scale { @@ -725,11 +719,9 @@ Item { pixelPer10km: flightMap.pixelPer10km vertical: false } - } // Column 3: North Button / Spacer / Zoom In / Zoom Out - ColumnLayout { Layout.fillHeight: true @@ -789,7 +781,6 @@ Item { Layout.fillWidth: true Layout.columnSpan: 3 } - } From 4bbaf9635bafa94dc7e21b12f966f2d5983fed7d Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 8 Sep 2024 17:58:44 +0200 Subject: [PATCH 12/64] Fix debug warning --- src/dataManagement/DataManager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dataManagement/DataManager.cpp b/src/dataManagement/DataManager.cpp index a60a5d403..6bdb8a291 100644 --- a/src/dataManagement/DataManager.cpp +++ b/src/dataManagement/DataManager.cpp @@ -401,8 +401,6 @@ void DataManagement::DataManager::updateDataItemListAndWhatsNew() } } - qWarning() << minVersionString << currentVersionString; - if (minVersionString > currentVersionString) { if (!m_appUpdateRequired) From d679033b230c07976c573eb58844b326c7f20154 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 9 Sep 2024 06:36:57 +0200 Subject: [PATCH 13/64] Update MFM.qml --- src/qml/items/MFM.qml | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index de873da57..5af2c2f74 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -216,11 +216,6 @@ Item { // PROPERTY "center" // - - // Initially, set the center to the last saved value - //center: PositionProvider.lastValidCoordinate - - // If "followGPS" is true, then update the map center whenever a new GPS position comes in // or the zoom level changes property var centerCoordinate: { @@ -244,17 +239,28 @@ Item { onCenterCoordinateChanged: { if (!flightMap.followGPS) return - var xCenter = centerItem.x + centerItem.width/2.0 - var yCenter = centerItem.y + centerItem.height/2.0 - flightMap.alignCoordinateToPoint(centerCoordinate, Qt.point(xCenter, yCenter)) + alignMapToCenter() } - onMapReadyChanged: { - var xCenter = centerItem.x + centerItem.width/2.0 - var yCenter = centerItem.y + centerItem.height/2.0 - flightMap.alignCoordinateToPoint(centerCoordinate, Qt.point(xCenter, yCenter)) + property var centerPoint: { + const xCenter = centerItem.x + centerItem.width/2.0 + const yCenter = centerItem.y + centerItem.height/2.0 + return Qt.point(xCenter, yCenter) + } + + onCenterPointChanged: { + if (!flightMap.followGPS) + return + alignMapToCenter() } + onMapReadyChanged: alignMapToCenter() + + function alignMapToCenter() { + const xCenter = centerItem.x + centerItem.width/2.0 + const yCenter = centerItem.y + centerItem.height/2.0 + flightMap.alignCoordinateToPoint(centerCoordinate, Qt.point(xCenter, yCenter)) + } // // PROPERTY "zoomLevel" From a0c7768840f35829b82864ae50e5603fd6fb9cf4 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 9 Sep 2024 18:30:30 +0200 Subject: [PATCH 14/64] Update MFM.qml --- src/qml/items/MFM.qml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 5af2c2f74..fcb01f5d0 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -57,6 +57,11 @@ Item { copyrightsVisible: false // We have our own copyrights notice property bool followGPS: true + onFollowGPSChanged: { + if (followGPS) + alignMapToCenter() + } + property real animatedTrack: PositionProvider.lastValidTT.isFinite() ? PositionProvider.lastValidTT.toDEG() : 0 Behavior on animatedTrack { RotationAnimation {duration: 1000; direction: RotationAnimation.Shortest } } @@ -257,11 +262,12 @@ Item { onMapReadyChanged: alignMapToCenter() function alignMapToCenter() { - const xCenter = centerItem.x + centerItem.width/2.0 - const yCenter = centerItem.y + centerItem.height/2.0 + const xCenter = col2.x + centerItem.x + centerItem.width/2.0 + const yCenter = col2.y + centerItem.y + centerItem.height/2.0 flightMap.alignCoordinateToPoint(centerCoordinate, Qt.point(xCenter, yCenter)) } + // // PROPERTY "zoomLevel" // @@ -660,6 +666,8 @@ Item { // Colmnn 2: Info Label / Center Item / Copyright / Horizontal Scale ColumnLayout { + id: col2 + Layout.fillHeight: true Layout.fillWidth: true @@ -681,11 +689,9 @@ Item { background: Pane {} // Rectangle { color: "white" } } - Rectangle { + Item { id: centerItem - color: "white" - opacity: 0.3 Layout.fillHeight: true Layout.fillWidth: true } From b0d9f267611cec138500daa7f79365d823a52815 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 9 Sep 2024 18:41:45 +0200 Subject: [PATCH 15/64] Update MFM.qml --- src/qml/items/MFM.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index fcb01f5d0..9b7031db2 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -248,8 +248,8 @@ Item { } property var centerPoint: { - const xCenter = centerItem.x + centerItem.width/2.0 - const yCenter = centerItem.y + centerItem.height/2.0 + const xCenter = col2.x + centerItem.x + centerItem.width/2.0 + const yCenter = col2.y + centerItem.y + centerItem.height/2.0 return Qt.point(xCenter, yCenter) } @@ -262,9 +262,7 @@ Item { onMapReadyChanged: alignMapToCenter() function alignMapToCenter() { - const xCenter = col2.x + centerItem.x + centerItem.width/2.0 - const yCenter = col2.y + centerItem.y + centerItem.height/2.0 - flightMap.alignCoordinateToPoint(centerCoordinate, Qt.point(xCenter, yCenter)) + flightMap.alignCoordinateToPoint(centerCoordinate, centerPoint) } @@ -604,6 +602,7 @@ Item { // Column 1: Main Menu / Vertical Scale / ... ColumnLayout { Layout.fillHeight: true + Layout.leftMargin: SafeInsets.left MapButton { id: menuButton @@ -736,6 +735,7 @@ Item { // Column 3: North Button / Spacer / Zoom In / Zoom Out ColumnLayout { Layout.fillHeight: true + Layout.rightMargin: SafeInsets.right MapButton { id: northButton From b41cf55daa3515dae46d089805dec0b88bbb6d9c Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Tue, 10 Sep 2024 06:42:13 +0200 Subject: [PATCH 16/64] Update MFM.qml --- src/qml/items/MFM.qml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 9b7031db2..f4ebb5942 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -674,8 +674,10 @@ Item { id: airspaceAltLabel Layout.alignment: Qt.AlignHCenter + Layout.minimumWidth: 10 visible: (!Global.currentVAC.isValid) && GlobalSettings.airspaceAltitudeLimit.isFinite() && !DataManager.baseMapsRaster.hasFile + wrapMode: Text.WordWrap text: { // Mention @@ -683,9 +685,11 @@ Item { var airspaceAltitudeLimit = GlobalSettings.airspaceAltitudeLimit var airspaceAltitudeLimitString = Navigator.aircraft.verticalDistanceToString(airspaceAltitudeLimit) - return " "+qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString)+" " + return " fdjk fg skgl dfjghdjfghlshjdf fj "+qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString)+" " } - background: Pane {} // Rectangle { color: "white" } + background: Pane { + Material.elevation: 3 + } // Rectangle { color: "white" } } Item { From ffe71af6cdf8bbf4068fef22a4ca7dfc4bfa669d Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Tue, 10 Sep 2024 07:54:04 +0200 Subject: [PATCH 17/64] Update MFM.qml --- src/qml/items/MFM.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index f4ebb5942..aef017ff4 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -669,12 +669,14 @@ Item { Layout.fillHeight: true Layout.fillWidth: true + Layout.minimumWidth: 0 Label { id: airspaceAltLabel Layout.alignment: Qt.AlignHCenter - Layout.minimumWidth: 10 + //Layout.preferredWidth: Math.min(col2.width, implicitWidth) + Layout.maximumWidth: col2.width visible: (!Global.currentVAC.isValid) && GlobalSettings.airspaceAltitudeLimit.isFinite() && !DataManager.baseMapsRaster.hasFile wrapMode: Text.WordWrap From 553f246cae1210bbc5794ad93d7c54b481d21f29 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Tue, 10 Sep 2024 19:28:32 +0200 Subject: [PATCH 18/64] Update MFM.qml --- src/qml/items/MFM.qml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index aef017ff4..4269f94d2 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -675,7 +675,6 @@ Item { id: airspaceAltLabel Layout.alignment: Qt.AlignHCenter - //Layout.preferredWidth: Math.min(col2.width, implicitWidth) Layout.maximumWidth: col2.width visible: (!Global.currentVAC.isValid) && GlobalSettings.airspaceAltitudeLimit.isFinite() && !DataManager.baseMapsRaster.hasFile @@ -687,11 +686,14 @@ Item { var airspaceAltitudeLimit = GlobalSettings.airspaceAltitudeLimit var airspaceAltitudeLimitString = Navigator.aircraft.verticalDistanceToString(airspaceAltitudeLimit) - return " fdjk fg skgl dfjghdjfghlshjdf fj "+qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString)+" " + return qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString) } - background: Pane { - Material.elevation: 3 - } // Rectangle { color: "white" } + + leftPadding: font.pixelSize/2.0 + rightPadding: font.pixelSize/2.0 + bottomPadding: font.pixelSize/4.0 + topPadding: font.pixelSize/4.0 + background: Pane { Material.elevation: 1 } } Item { From f62fa62c3a78ddc394842eb138df645323e8752a Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Tue, 10 Sep 2024 19:43:01 +0200 Subject: [PATCH 19/64] Update MFM.qml --- src/qml/items/MFM.qml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 4269f94d2..6c1c087ad 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -677,16 +677,22 @@ Item { Layout.alignment: Qt.AlignHCenter Layout.maximumWidth: col2.width - visible: (!Global.currentVAC.isValid) && GlobalSettings.airspaceAltitudeLimit.isFinite() && !DataManager.baseMapsRaster.hasFile + visible: (!Global.currentVAC.isValid) && !DataManager.baseMapsRaster.hasFile && (text !== "") wrapMode: Text.WordWrap text: { - // Mention - Navigator.aircraft.verticalDistanceUnit + var resultList = [] + + if (GlobalSettings.airspaceAltitudeLimit.isFinite()) + { + var airspaceAltitudeLimit = GlobalSettings.airspaceAltitudeLimit + var airspaceAltitudeLimitString = Navigator.aircraft.verticalDistanceToString(airspaceAltitudeLimit) + resultList.push(qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString)) + } + if (DataManager.items.downloading) + resultList.push(qsTr("Downloading Maps and Data")) + return resultList.join(" • ") - var airspaceAltitudeLimit = GlobalSettings.airspaceAltitudeLimit - var airspaceAltitudeLimitString = Navigator.aircraft.verticalDistanceToString(airspaceAltitudeLimit) - return qsTr("Airspaces up to %1").arg(airspaceAltitudeLimitString) } leftPadding: font.pixelSize/2.0 From 69ba68bbcb6d0e547673a33d86ecf838102a1129 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Wed, 11 Sep 2024 06:52:00 +0200 Subject: [PATCH 20/64] Merge features --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 3a5c25158..60dbc81a7 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 3a5c25158bde2b2170c43bb450961a1b6bdf1960 +Subproject commit 60dbc81a7115485c09f885312e6456dffb213ccd From e2c56166ac7aceeaa61b5d5dbe1c8fb96a49c631 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Wed, 11 Sep 2024 07:04:55 +0200 Subject: [PATCH 21/64] Translations --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 60dbc81a7..88caad998 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 60dbc81a7115485c09f885312e6456dffb213ccd +Subproject commit 88caad99844e3de411c51cbca06f4fdf272b234c From ab24cfefc4236034568342cbbca081ce4b00b4be Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Wed, 11 Sep 2024 07:41:35 +0200 Subject: [PATCH 22/64] Starting to implement NOTAMProvider.status --- src/notam/NotamProvider.cpp | 7 +++++++ src/notam/NotamProvider.h | 17 +++++++++++++++-- src/qml/items/MFM.qml | 4 +++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 338a4a413..f1660c92c 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -170,6 +170,13 @@ QByteArray NOTAM::NotamProvider::GeoJSON() const } +QString NOTAM::NotamProvider::status() const +{ +#warning + return u"NOTAM status template"_qs; +} + + QList NOTAM::NotamProvider::waypoints() const { QList result; diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index 94527c132..b46a6f585 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -72,8 +72,12 @@ class NotamProvider : public GlobalObject { /*! \brief Waypoints with Notam items, for presentation in a map */ Q_PROPERTY(QList waypoints READ waypoints NOTIFY dataChanged) -#warning -// Q_PROPERTY(QString status READ status NOTIFY statusChanged) + /*! \brief Status + * + * This is a translated, human-readable text with warnings about incomplete NOTAM data, + * or an empty string in case of no warning. + */ + Q_PROPERTY(QString status READ status NOTIFY statusChanged) // @@ -93,6 +97,12 @@ class NotamProvider : public GlobalObject { */ Q_REQUIRED_RESULT QDateTime lastUpdate() const { return m_lastUpdate; } + /*! \brief Getter function for the property with the same name + * + * @returns Property status + */ + Q_REQUIRED_RESULT QString status() const; + /*! \brief Getter function for the property with the same name * * @returns Property waypoints @@ -143,6 +153,9 @@ class NotamProvider : public GlobalObject { /*! \brief Notifier signal */ void dataChanged(); + /*! \brief Notifier signal */ + void statusChanged(); + private slots: // Removes outdated and irrelevant data from the database. This slot is called // once per hour. diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 6c1c087ad..3d274eb31 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -676,6 +676,7 @@ Item { Layout.alignment: Qt.AlignHCenter Layout.maximumWidth: col2.width + Layout.topMargin: 14 visible: (!Global.currentVAC.isValid) && !DataManager.baseMapsRaster.hasFile && (text !== "") wrapMode: Text.WordWrap @@ -691,8 +692,9 @@ Item { } if (DataManager.items.downloading) resultList.push(qsTr("Downloading Maps and Data")) + if (NotamProvider.status !== "") + resultList.push(NotamProvider.status) return resultList.join(" • ") - } leftPadding: font.pixelSize/2.0 From a38b34555cd022f27cfdda694241409a2bd7bb3d Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 14 Sep 2024 12:00:30 +0200 Subject: [PATCH 23/64] Update NotamProvider.cpp --- src/notam/NotamProvider.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index f1660c92c..8cb96f277 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -172,8 +172,26 @@ QByteArray NOTAM::NotamProvider::GeoJSON() const QString NOTAM::NotamProvider::status() const { -#warning - return u"NOTAM status template"_qs; + auto position = Positioning::PositionProvider::lastValidCoordinate(); + foreach (auto notamList, m_notamLists) + { + if (notamList.isOutdated()) + { + continue; + } + + auto region = notamList.region(); + if (!region.isValid()) + { + continue; + } + auto rangeInM = region.radius() - region.center().distanceTo(position); + if (rangeInM >= marginRadius.toM()) + { + return {}; + } + } + return tr("NOTAMs not current, requesting update"); } From 122913d62946d5938da02f8cd357586098f7ba15 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 16 Sep 2024 07:37:26 +0200 Subject: [PATCH 24/64] Finish NOTAM status --- src/notam/NotamProvider.cpp | 62 +++++++++++++++++++++---------------- src/notam/NotamProvider.h | 16 +++++++--- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 8cb96f277..2445e5b1e 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -51,7 +51,7 @@ void NOTAM::NotamProvider::deferredInitialization() timer->start(11min); connect(timer, &QTimer::timeout, this, &NOTAM::NotamProvider::updateData); connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateData); - QTimer::singleShot(10s, this, &NOTAM::NotamProvider::updateData); + QTimer::singleShot(2s, this, &NOTAM::NotamProvider::updateData); // Wire up clean(). Clean the data every 61 minutes. timer = new QTimer(this); @@ -75,6 +75,14 @@ void NOTAM::NotamProvider::deferredInitialization() } } clean(); + + // Setup Status + auto* statusTimer = new QTimer(this); + connect(statusTimer, &QTimer::timeout, this, &NOTAM::NotamProvider::updateStatus); + statusTimer->setInterval(5min+1s); + statusTimer->start(); + connect(this, &NOTAM::NotamProvider::dataChanged, this, &NOTAM::NotamProvider::updateStatus); + updateStatus(); } @@ -170,31 +178,6 @@ QByteArray NOTAM::NotamProvider::GeoJSON() const } -QString NOTAM::NotamProvider::status() const -{ - auto position = Positioning::PositionProvider::lastValidCoordinate(); - foreach (auto notamList, m_notamLists) - { - if (notamList.isOutdated()) - { - continue; - } - - auto region = notamList.region(); - if (!region.isValid()) - { - continue; - } - auto rangeInM = region.radius() - region.center().distanceTo(position); - if (rangeInM >= marginRadius.toM()) - { - return {}; - } - } - return tr("NOTAMs not current, requesting update"); -} - - QList NOTAM::NotamProvider::waypoints() const { QList result; @@ -340,7 +323,6 @@ void NOTAM::NotamProvider::setRead(const QString& number, bool read) void NOTAM::NotamProvider::clean() { - QList newNotamLists; QSet regionsSeen; bool haveChange = false; @@ -605,3 +587,29 @@ void NOTAM::NotamProvider::startRequest(const QGeoCoordinate& coordinate) connect(reply, &QNetworkReply::finished, this, &NOTAM::NotamProvider::downloadFinished); connect(reply, &QNetworkReply::errorOccurred, this, &NOTAM::NotamProvider::downloadFinished); } + + +void NOTAM::NotamProvider::updateStatus() +{ + auto position = Positioning::PositionProvider::lastValidCoordinate(); + foreach (auto notamList, m_notamLists) + { + if (notamList.isOutdated()) + { + continue; + } + + auto region = notamList.region(); + if (!region.isValid()) + { + continue; + } + auto rangeInM = region.radius() - region.center().distanceTo(position); + if (rangeInM >= marginRadius.toM()) + { + m_status = QString(); + return; + } + } + m_status = tr("NOTAMs not current around own position, requesting update"); +} diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index b46a6f585..d11cff93b 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -20,6 +20,7 @@ #pragma once +#include #include #include @@ -77,7 +78,7 @@ class NotamProvider : public GlobalObject { * This is a translated, human-readable text with warnings about incomplete NOTAM data, * or an empty string in case of no warning. */ - Q_PROPERTY(QString status READ status NOTIFY statusChanged) + Q_PROPERTY(QString status READ status BINDABLE bindableStatus) // @@ -101,7 +102,8 @@ class NotamProvider : public GlobalObject { * * @returns Property status */ - Q_REQUIRED_RESULT QString status() const; + Q_REQUIRED_RESULT QString status() const {return m_status;} + Q_REQUIRED_RESULT QBindable bindableStatus() {return &m_status;} /*! \brief Getter function for the property with the same name * @@ -153,9 +155,6 @@ class NotamProvider : public GlobalObject { /*! \brief Notifier signal */ void dataChanged(); - /*! \brief Notifier signal */ - void statusChanged(); - private slots: // Removes outdated and irrelevant data from the database. This slot is called // once per hour. @@ -176,6 +175,10 @@ private slots: // the data. void updateData(); + // Checks if NOTAM data is available for an area of marginRadius around the + // current position and around the current flight route. Update status accordingly. + void updateStatus(); + private: Q_DISABLE_COPY_MOVE(NotamProvider) @@ -203,6 +206,9 @@ private slots: // Time of last update to data QDateTime m_lastUpdate; + // Filename for loading/saving NOTAM data + QProperty m_status; + // Filename for loading/saving NOTAM data QString m_stdFileName; From 304bdbce1c1143bc863b595debeec8ac54a9c551 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 16 Sep 2024 08:19:49 +0200 Subject: [PATCH 25/64] Update NotamProvider.cpp --- src/notam/NotamProvider.cpp | 55 +++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 2445e5b1e..6544cd0fd 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -82,6 +82,7 @@ void NOTAM::NotamProvider::deferredInitialization() statusTimer->setInterval(5min+1s); statusTimer->start(); connect(this, &NOTAM::NotamProvider::dataChanged, this, &NOTAM::NotamProvider::updateStatus); + connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateStatus); updateStatus(); } @@ -386,7 +387,6 @@ void NOTAM::NotamProvider::downloadFinished() } if (networkReply->error() != QNetworkReply::NoError) { - qWarning() << "FAA NOTAM Server returned with an error." << networkReply->error(); networkReply->deleteLater(); continue; } @@ -398,11 +398,9 @@ void NOTAM::NotamProvider::downloadFinished() auto jsonDoc = QJsonDocument::fromJson(data); if (jsonDoc.isNull()) { - qWarning() << u"FAA NOTAM Server returned with invalid or empty JSON data."_qs; continue; } NotamList const notamList(jsonDoc, region, &m_cancelledNotamNumbers); - qWarning() << u"FAA NOTAM Server returned with %1 NOTAMs."_qs.arg(notamList.notams().size()); m_notamLists.prepend(notamList); newDataAdded = true; } @@ -468,7 +466,7 @@ void NOTAM::NotamProvider::updateData() } } -/* + /* QGeoCoordinate startPoint = leg.startPoint().coordinate(); QGeoCoordinate const endPoint = leg.endPoint().coordinate(); if (!startPoint.isValid() || !endPoint.isValid()) @@ -577,7 +575,6 @@ void NOTAM::NotamProvider::startRequest(const QGeoCoordinate& coordinate) .arg(coordinateRounded.longitude()) .arg(coordinateRounded.latitude()) .arg( qRound(1.2*requestRadius.toNM()) ); - qWarning() << "NOTAM::NotamProvider::startRequest" << urlString; QNetworkRequest const request(urlString); auto* reply = GlobalObject::networkAccessManager()->get(request); @@ -592,24 +589,54 @@ void NOTAM::NotamProvider::startRequest(const QGeoCoordinate& coordinate) void NOTAM::NotamProvider::updateStatus() { auto position = Positioning::PositionProvider::lastValidCoordinate(); - foreach (auto notamList, m_notamLists) + + QList positionList; + positionList.append(position); + auto* route = navigator()->flightRoute(); + if (route != nullptr) { - if (notamList.isOutdated()) + positionList += route->geoPath(); + } + + foreach (auto pos, positionList) + { + if (!pos.isValid()) { continue; } - auto region = notamList.region(); - if (!region.isValid()) + bool hasNOTAM = false; + foreach (auto notamList, m_notamLists) { - continue; + if (notamList.isOutdated()) + { + continue; + } + + auto region = notamList.region(); + if (!region.isValid()) + { + continue; + } + auto rangeInM = region.radius() - region.center().distanceTo(pos); + if (rangeInM >= marginRadius.toM()) + { + hasNOTAM = true; + break; + } } - auto rangeInM = region.radius() - region.center().distanceTo(position); - if (rangeInM >= marginRadius.toM()) + if (!hasNOTAM) { - m_status = QString(); + if (position == pos) + { + m_status = tr("NOTAMs not current around own position, requesting update"); + } + else + { + m_status = tr("NOTAMs not current around route, requesting update"); + } return; } } - m_status = tr("NOTAMs not current around own position, requesting update"); + m_status = QString(); } From 151a787e571e9c7a26744bf1f238f774ca6cb82e Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 16 Sep 2024 08:23:11 +0200 Subject: [PATCH 26/64] Translations --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 88caad998..128cd0c60 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 88caad99844e3de411c51cbca06f4fdf272b234c +Subproject commit 128cd0c60bc810003ea6a7d7be299cfe9f560e95 From 14c2678c8115b3d3aaa7de26d22a10af5a67907a Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 16 Sep 2024 15:14:59 +0200 Subject: [PATCH 27/64] Cleanup, minor fixes --- src/notam/NotamProvider.cpp | 7 ++++--- src/notam/NotamProvider.h | 12 +++++++----- src/platform/FileExchange_Linux.cpp | 2 +- src/platform/FileExchange_MacOS.cpp | 2 +- src/platform/PlatformAdaptor_Abstract.cpp | 11 ++++++++++- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 6544cd0fd..31d5ca9aa 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -39,8 +38,6 @@ using namespace std::chrono_literals; NOTAM::NotamProvider::NotamProvider(QObject* parent) : GlobalObject(parent) { - // Set stdFileName for saving and loading NOTAM data - m_stdFileName = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+u"/notam.dat"_qs; } @@ -73,6 +70,10 @@ void NOTAM::NotamProvider::deferredInitialization() inputStream >> m_readNotamNumbers; inputStream >> m_notamLists; } + if (!m_notamLists.isEmpty()) + { + m_lastUpdate = m_notamLists[0].retrieved(); + } } clean(); diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index d11cff93b..72f0b5263 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "GlobalObject.h" #include "notam/NotamList.h" @@ -68,7 +69,7 @@ class NotamProvider : public GlobalObject { Q_PROPERTY(QByteArray GeoJSON READ GeoJSON NOTIFY dataChanged) /*! \brief Time of last database update */ - Q_PROPERTY(QDateTime lastUpdate READ lastUpdate NOTIFY dataChanged) + Q_PROPERTY(QDateTime lastUpdate READ lastUpdate BINDABLE bindableLastUpdate) /*! \brief Waypoints with Notam items, for presentation in a map */ Q_PROPERTY(QList waypoints READ waypoints NOTIFY dataChanged) @@ -96,13 +97,14 @@ class NotamProvider : public GlobalObject { * * @returns Property lastUpdate */ - Q_REQUIRED_RESULT QDateTime lastUpdate() const { return m_lastUpdate; } + Q_REQUIRED_RESULT QDateTime lastUpdate() const {return {m_lastUpdate};} + Q_REQUIRED_RESULT QBindable bindableLastUpdate() { return &m_lastUpdate; } /*! \brief Getter function for the property with the same name * * @returns Property status */ - Q_REQUIRED_RESULT QString status() const {return m_status;} + Q_REQUIRED_RESULT QString status() const {return {m_status};} Q_REQUIRED_RESULT QBindable bindableStatus() {return &m_status;} /*! \brief Getter function for the property with the same name @@ -204,13 +206,13 @@ private slots: QList m_notamLists; // Time of last update to data - QDateTime m_lastUpdate; + QProperty m_lastUpdate; // Filename for loading/saving NOTAM data QProperty m_status; // Filename for loading/saving NOTAM data - QString m_stdFileName; + QString m_stdFileName { QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+u"/notam.dat"_qs }; // The method updateDate() ensures that data is requested for marginRadius around // own position and current flight route. diff --git a/src/platform/FileExchange_Linux.cpp b/src/platform/FileExchange_Linux.cpp index 5de40178e..36e9d33f8 100644 --- a/src/platform/FileExchange_Linux.cpp +++ b/src/platform/FileExchange_Linux.cpp @@ -54,7 +54,7 @@ auto Platform::FileExchange::shareContent(const QByteArray& content, const QStri QMimeDatabase const mimeDataBase; QMimeType const mime = mimeDataBase.mimeTypeForName(mimeType); - auto fileNameX = QFileDialog::getSaveFileName(nullptr, tr("Export flight route"), QDir::homePath()+"/"+fileNameTemplate+"."+mime.preferredSuffix(), tr("%1 (*.%2);;All files (*)").arg(mime.comment(), mime.preferredSuffix())); + auto fileNameX = QFileDialog::getSaveFileName(nullptr, tr("Export Data"), QDir::homePath()+"/"+fileNameTemplate+"."+mime.preferredSuffix(), tr("%1 (*.%2);;All files (*)").arg(mime.comment(), mime.preferredSuffix())); if (fileNameX.isEmpty()) { return QStringLiteral("abort"); diff --git a/src/platform/FileExchange_MacOS.cpp b/src/platform/FileExchange_MacOS.cpp index 54aa69324..f2e89e428 100644 --- a/src/platform/FileExchange_MacOS.cpp +++ b/src/platform/FileExchange_MacOS.cpp @@ -54,7 +54,7 @@ auto Platform::FileExchange::shareContent(const QByteArray& content, const QStri QMimeDatabase const mimeDataBase; QMimeType const mime = mimeDataBase.mimeTypeForName(mimeType); - auto fileNameX = QFileDialog::getSaveFileName(nullptr, tr("Export flight route"), QDir::homePath()+"/"+fileNameTemplate+"."+mime.preferredSuffix(), tr("%1 (*.%2);;All files (*)").arg(mime.comment(), mime.preferredSuffix())); + auto fileNameX = QFileDialog::getSaveFileName(nullptr, tr("Export Data"), QDir::homePath()+"/"+fileNameTemplate+"."+mime.preferredSuffix(), tr("%1 (*.%2);;All files (*)").arg(mime.comment(), mime.preferredSuffix())); if (fileNameX.isEmpty()) { return QStringLiteral("abort"); diff --git a/src/platform/PlatformAdaptor_Abstract.cpp b/src/platform/PlatformAdaptor_Abstract.cpp index c484a2f0c..d48b66801 100644 --- a/src/platform/PlatformAdaptor_Abstract.cpp +++ b/src/platform/PlatformAdaptor_Abstract.cpp @@ -24,7 +24,7 @@ #include #include - +#include "notam/NotamProvider.h" #include "platform/PlatformAdaptor_Abstract.h" #include "qimage.h" @@ -76,6 +76,15 @@ QString Platform::PlatformAdaptor_Abstract::systemInfo() result += u"\n"_qs; result += u"\n"_qs; result += u"\n"_qs.arg("Last Map Update Check", updateCheckTimeStamp); + auto lastNOTAMUpdate = notamProvider()->lastUpdate(); + if (lastNOTAMUpdate.isValid()) + { + result += u"\n"_qs.arg("Last NOTAM download", notamProvider()->lastUpdate().toString()); + } + else + { + result += u"\n"_qs.arg("Last NOTAM download", "NONE"); + } result += u"
%1%2
%1%2
%1%2

\n"_qs; return result; From b9ac14f35df0f7b35a4e5abe1e24e321f8bfc524 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 16 Sep 2024 15:23:39 +0200 Subject: [PATCH 28/64] Fix issue #405 --- src/qml/items/MFM.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 3d274eb31..fba90ded2 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -122,7 +122,7 @@ Item { return } - if (Math.abs(pinch.rawBearing-pinch.startBearing) > 5) + if (Math.abs(pinch.rawBearing-pinch.startBearing) > 20) { GlobalSettings.mapBearingPolicy = GlobalSettings.UserDefinedBearingUp } From fbd2ecaea99997130d55525605f85dde93e76455 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 16 Sep 2024 20:51:25 +0200 Subject: [PATCH 29/64] Update NotamProvider.cpp --- src/notam/NotamProvider.cpp | 57 ++++--------------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 6544cd0fd..2519211bf 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -51,7 +51,6 @@ void NOTAM::NotamProvider::deferredInitialization() timer->start(11min); connect(timer, &QTimer::timeout, this, &NOTAM::NotamProvider::updateData); connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateData); - QTimer::singleShot(2s, this, &NOTAM::NotamProvider::updateData); // Wire up clean(). Clean the data every 61 minutes. timer = new QTimer(this); @@ -83,6 +82,8 @@ void NOTAM::NotamProvider::deferredInitialization() statusTimer->start(); connect(this, &NOTAM::NotamProvider::dataChanged, this, &NOTAM::NotamProvider::updateStatus); connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateStatus); + + updateData(); updateStatus(); } @@ -444,63 +445,17 @@ void NOTAM::NotamProvider::updateData() auto* route = navigator()->flightRoute(); if (route != nullptr) { - foreach(auto leg, route->legs()) + foreach(auto pos, route->geoPath()) { - QGeoCoordinate const startPoint = leg.startPoint().coordinate(); - if (startPoint.isValid()) - { - auto _range = range(startPoint); - if (_range < marginRadius) - { - startRequest(startPoint); - } - } - - QGeoCoordinate const endPoint = leg.endPoint().coordinate(); - if (endPoint.isValid()) + if (pos.isValid()) { - auto _range = range(endPoint); + auto _range = range(pos); if (_range < marginRadius) { - startRequest(endPoint); + startRequest(pos); } } - /* - QGeoCoordinate startPoint = leg.startPoint().coordinate(); - QGeoCoordinate const endPoint = leg.endPoint().coordinate(); - if (!startPoint.isValid() || !endPoint.isValid()) - { - continue; - } - - while(true) - { - // Check if the range at the startPoint at least marginRadius+1NM - // If not, request data for startPoint and start over - auto rangeAtStartPoint = range(startPoint); - if (rangeAtStartPoint < marginRadius+Units::Distance::fromNM(1)) - { - startRequest(startPoint); - continue; - } - - // Check if every point between startPoint and endPoint has a range - // of at least marginRadius. If so, there is nothing to do for this - // and we continue with the next leg. - auto distanceToEndPoint = Units::Distance::fromM(startPoint.distanceTo(endPoint)); - if (rangeAtStartPoint > distanceToEndPoint+marginRadius) - { - break; - } - - // Move the startPoint closer to the endPoint, so all points between - // the new and the old startPoint have a range of at least - // marginRadius. Then start over. - auto azimuth = startPoint.azimuthTo(endPoint); - startPoint = startPoint.atDistanceAndAzimuth((rangeAtStartPoint-marginRadius).toM(), azimuth); - } -*/ } } From a6e2faff17686a44631f30228ab0a3372f23f4a6 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 16 Sep 2024 20:59:01 +0200 Subject: [PATCH 30/64] Fixing issue #426 --- src/dataManagement/DataManager.cpp | 30 +++++++++++++++++++++++------- src/dataManagement/DataManager.h | 10 ++++------ src/notam/NotamProvider.cpp | 3 +-- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/dataManagement/DataManager.cpp b/src/dataManagement/DataManager.cpp index 6bdb8a291..31a637631 100644 --- a/src/dataManagement/DataManager.cpp +++ b/src/dataManagement/DataManager.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -61,13 +62,16 @@ void DataManagement::DataManager::deferredInitialization() // If there is a downloaded maps.json file, we read it. updateDataItemListAndWhatsNew(); - // If the last update is more than one day ago, automatically initiate an - // update, so that maps stay at least roughly current. - auto lastUpdate = QSettings().value(QStringLiteral("DataManager/MapListTimeStamp"), QDateTime()).toDateTime(); - if (!lastUpdate.isValid() || (qAbs(lastUpdate.daysTo(QDateTime::currentDateTime()) > 0))) - { - updateRemoteDataItemList(); - } + // Update maps.json file if that is too old. Check that whenever the app comes forward. + updateRemoteDataItemListIfOutdated(); + connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, + [this](Qt::ApplicationState state) + { + if (state == Qt::ApplicationActive) + { + updateRemoteDataItemListIfOutdated(); + } + }); } @@ -487,3 +491,15 @@ void DataManagement::DataManager::updateDataItemListAndWhatsNew() emit whatsNewChanged(); } } + + +void DataManagement::DataManager::updateRemoteDataItemListIfOutdated() +{ + // If the last update is more than one day ago, automatically initiate an + // update, so that maps stay at least roughly current. + auto lastUpdate = QSettings().value(QStringLiteral("DataManager/MapListTimeStamp"), QDateTime()).toDateTime(); + if (!lastUpdate.isValid() || (qAbs(lastUpdate.daysTo(QDateTime::currentDateTime()) > 0))) + { + m_mapList.startDownload(); + } +} diff --git a/src/dataManagement/DataManager.h b/src/dataManagement/DataManager.h index f8d79dfa7..1bc368e39 100644 --- a/src/dataManagement/DataManager.h +++ b/src/dataManagement/DataManager.h @@ -301,12 +301,10 @@ class DataManager : public GlobalObject public slots: /*! \brief Triggers an update of the list of remotely available data items * - * This will trigger a download the file maps.json from the remote server. + * This will trigger a download the file maps.json from the remote server if the last update + * is more than one day ago. */ - void updateRemoteDataItemList() - { - m_mapList.startDownload(); - } + void updateRemoteDataItemListIfOutdated(); signals: /*! Notifier signal */ @@ -360,7 +358,7 @@ public slots: QString m_dataDirectory {QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/aviation_maps"}; // The current whats new string from _aviationMaps. - QString m_whatsNew {}; + QString m_whatsNew; // This Downloadable object manages the central text file that describes the // remotely available aviation maps. diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 31d5ca9aa..8bda8af9b 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -80,8 +80,7 @@ void NOTAM::NotamProvider::deferredInitialization() // Setup Status auto* statusTimer = new QTimer(this); connect(statusTimer, &QTimer::timeout, this, &NOTAM::NotamProvider::updateStatus); - statusTimer->setInterval(5min+1s); - statusTimer->start(); + statusTimer->start(5min+1s); connect(this, &NOTAM::NotamProvider::dataChanged, this, &NOTAM::NotamProvider::updateStatus); connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateStatus); updateStatus(); From 093a3a19639bf8f4c4f7abebaa7a72ea82b0ce15 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Thu, 19 Sep 2024 20:38:12 +0200 Subject: [PATCH 31/64] Robustify code --- src/notam/NotamProvider.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 4d45b3442..61ac166cb 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -83,8 +83,9 @@ void NOTAM::NotamProvider::deferredInitialization() connect(this, &NOTAM::NotamProvider::dataChanged, this, &NOTAM::NotamProvider::updateStatus); connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateStatus); - updateData(); - updateStatus(); + // Set variables initially + QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateData); + QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateStatus); } From 0c38ddc82b9b2c8f0aff693538523ff498449dfe Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Fri, 20 Sep 2024 08:48:19 +0200 Subject: [PATCH 32/64] Translations --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 128cd0c60..95b4c0678 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 128cd0c60bc810003ea6a7d7be299cfe9f560e95 +Subproject commit 95b4c0678e76bd4aaa5807273028c67a01bfa088 From 55fe25c8ae1ba3b227f46d8e86d0112bda4fdb76 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Fri, 20 Sep 2024 20:39:37 +0200 Subject: [PATCH 33/64] Implemented issue/suggestion #356 --- src/icons.qrc.in | 3 +- src/qml/dialogs/FlightRouteAddWPDialog.qml | 2 +- src/qml/pages/Nearby.qml | 48 ++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/icons.qrc.in b/src/icons.qrc.in index 75f08b4b9..d645352be 100644 --- a/src/icons.qrc.in +++ b/src/icons.qrc.in @@ -55,7 +55,8 @@ ${material-design-icons_SOURCE_DIR}/content/svg/production/ic_remove_24px.svg ${material-design-icons_SOURCE_DIR}/content/svg/production/ic_remove_circle_24px.svg ${material-design-icons_SOURCE_DIR}/maps/svg/production/ic_satellite_24px.svg - ${material-design-icons_SOURCE_DIR}/content/svg/design/ic_send_24px.svg + ${material-design-icons_SOURCE_DIR}/action/svg/production/ic_search_24px.svg + ${material-design-icons_SOURCE_DIR}/content/svg/production/ic_send_24px.svg ${material-design-icons_SOURCE_DIR}/action/svg/production/ic_settings_24px.svg ${material-design-icons_SOURCE_DIR}/action/svg/production/ic_settings_ethernet_24px.svg ${material-design-icons_SOURCE_DIR}/communication/svg/production/ic_speaker_phone_24px.svg diff --git a/src/qml/dialogs/FlightRouteAddWPDialog.qml b/src/qml/dialogs/FlightRouteAddWPDialog.qml index 5fe0ad985..d11960803 100644 --- a/src/qml/dialogs/FlightRouteAddWPDialog.qml +++ b/src/qml/dialogs/FlightRouteAddWPDialog.qml @@ -77,7 +77,7 @@ CenteringDialog { } } - // On iOS17, the property displayText sees many bounced. + // On iOS17, the property displayText sees many bounces. onDisplayTextChanged: debounceTimer.restart() } diff --git a/src/qml/pages/Nearby.qml b/src/qml/pages/Nearby.qml index 4087894c9..2582cad4f 100644 --- a/src/qml/pages/Nearby.qml +++ b/src/qml/pages/Nearby.qml @@ -48,6 +48,7 @@ Page { TabButton { text: "AD" } TabButton { text: "WP" } TabButton { text: "NAV" } + TabButton { icon.source: "/icons/material/ic_search.svg" } } SwipeView { @@ -137,6 +138,53 @@ Page { text: qsTr("

Sorry!

No navaid data available.

") } } + + ColumnLayout { + + Item { + Layout.preferredHeight: textInput.font.pixelSize/4.0 + } + + MyTextField { + id: textInput + + Layout.fillWidth: true + Layout.leftMargin: font.pixelSize/2.0 + Layout.rightMargin: font.pixelSize/2.0 + + focus: true + + placeholderText: qsTr("Filter by Name") + } + + DecoratedListView { + id: naList2 + + Layout.fillHeight: true + Layout.fillWidth: true + + clip: true + + delegate: waypointDelegate + + Binding { + naList2.model: GeoMapProvider.filteredWaypoints(textInput.displayText) + delayed: true + } + + Label { + anchors.fill: parent + anchors.topMargin: font.pixelSize*2 + visible: parent.count === 0 + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + textFormat: Text.StyledText + wrapMode: Text.Wrap + text: qsTr("

Sorry!

No waypoints match your filter.

") + } + } + } } footer: Footer { From 488e0a39d8f66348fc2aa5e98d9e077e88694ce5 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Fri, 20 Sep 2024 21:08:20 +0200 Subject: [PATCH 34/64] Translations --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 95b4c0678..46c066b67 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 95b4c0678e76bd4aaa5807273028c67a01bfa088 +Subproject commit 46c066b674cd8edb331c0bc8c811dab55e3877f2 From a62f0371217ff5d346943238b6addee206d22a32 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 21 Sep 2024 10:38:09 +0200 Subject: [PATCH 35/64] Starting to implement "adding waypoint by coordinates" --- src/qml/dialogs/FlightRouteAddWPDialog.qml | 9 ++++++++- src/qml/items/WaypointDelegate.qml | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/qml/dialogs/FlightRouteAddWPDialog.qml b/src/qml/dialogs/FlightRouteAddWPDialog.qml index d11960803..248b70e40 100644 --- a/src/qml/dialogs/FlightRouteAddWPDialog.qml +++ b/src/qml/dialogs/FlightRouteAddWPDialog.qml @@ -57,16 +57,22 @@ CenteringDialog { Label { Layout.fillWidth: true - text: qsTr("Choose a waypoint from the list below.") + text: qsTr("Choose a waypoint from the list below or enter coordinates manually.") wrapMode: Text.Wrap textFormat: Text.StyledText } + Item { + Layout.preferredHeight: textInput.font.pixelSize/2.0 + } + MyTextField { id: textInput Layout.fillWidth: true + placeholderText: qsTr("Filter by Name") + focus: true onAccepted: { @@ -97,6 +103,7 @@ CenteringDialog { onTriggered: wpList.model = GeoMapProvider.filteredWaypoints(textInput.displayText) } + model: GeoMapProvider.filteredWaypoints(textInput.displayText) delegate: waypointDelegate ScrollIndicator.vertical: ScrollIndicator {} diff --git a/src/qml/items/WaypointDelegate.qml b/src/qml/items/WaypointDelegate.qml index ace661c0b..db602b10b 100644 --- a/src/qml/items/WaypointDelegate.qml +++ b/src/qml/items/WaypointDelegate.qml @@ -38,8 +38,8 @@ Item { } } - width: parent ? parent.width : 0 - height: idel.implicitHeight + implicitWidth: parent ? parent.width : 0 + implicitHeight: idel.implicitHeight // Background color according to METAR/FAA flight category Rectangle { From c3fef3f2b2a4bf127471e91bba20dfe088f5449c Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 21 Sep 2024 11:56:02 +0200 Subject: [PATCH 36/64] Fix binding loops --- src/qml/items/MyTextField.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qml/items/MyTextField.qml b/src/qml/items/MyTextField.qml index cc8253f0d..c6b3437d3 100644 --- a/src/qml/items/MyTextField.qml +++ b/src/qml/items/MyTextField.qml @@ -46,6 +46,8 @@ TextField { return width > 5*font.pixelSize } rightPadding: hasClearButton ? toolButton.width : undefined + implicitWidth: 100 // set arbitrary value to avoid binding loop + // Fix problem on iOS Component.onCompleted: PlatformAdaptor.setupInputMethodEventFilter(textField) From 5296db3d300ce5b70efb870e1d14bdb7f196abfe Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 21 Sep 2024 12:40:37 +0200 Subject: [PATCH 37/64] Remove unused properties --- src/qml/dialogs/FlightRouteAddWPDialog.qml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/qml/dialogs/FlightRouteAddWPDialog.qml b/src/qml/dialogs/FlightRouteAddWPDialog.qml index 248b70e40..c7540e300 100644 --- a/src/qml/dialogs/FlightRouteAddWPDialog.qml +++ b/src/qml/dialogs/FlightRouteAddWPDialog.qml @@ -60,10 +60,12 @@ CenteringDialog { text: qsTr("Choose a waypoint from the list below or enter coordinates manually.") wrapMode: Text.Wrap textFormat: Text.StyledText + visible: textInput.text === "" } Item { - Layout.preferredHeight: textInput.font.pixelSize/2.0 + Layout.preferredHeight: textInput.font.pixelSize + visible: textInput.text === "" } MyTextField { @@ -87,6 +89,18 @@ CenteringDialog { onDisplayTextChanged: debounceTimer.restart() } + Label { + Layout.fillWidth: true + Layout.topMargin: font.pixelSize + + text: qsTr("

Sorry!

No waypoints match your filter.

") + wrapMode: Text.Wrap + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + + visible: wpList.model.length === 0 + } + DecoratedListView { id: wpList From f2adb991c8175f78107f9c4db5e39e1cc56e1d2c Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 21 Sep 2024 12:41:02 +0200 Subject: [PATCH 38/64] Remove unused properties --- src/qml/pages/WaypointLibraryPage.qml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/qml/pages/WaypointLibraryPage.qml b/src/qml/pages/WaypointLibraryPage.qml index 8bf2c5ebc..c63015f79 100644 --- a/src/qml/pages/WaypointLibraryPage.qml +++ b/src/qml/pages/WaypointLibraryPage.qml @@ -356,10 +356,6 @@ Page { anchors.fill: parent - leftMargin: SafeInsets.left - rightMargin: SafeInsets.right - bottomMargin: SafeInsets.bottom - clip: true model: { From b55c3f508c6a1f5bfdf14c467e6642db6819a54a Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 21 Sep 2024 14:23:27 +0200 Subject: [PATCH 39/64] Allow adding waypoints by coordinate --- src/qml/dialogs/WaypointEditor.qml | 27 ++++++++++++------ src/qml/items/DegreeInput.qml | 13 +++++++++ src/qml/pages/WaypointLibraryPage.qml | 40 +++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/qml/dialogs/WaypointEditor.qml b/src/qml/dialogs/WaypointEditor.qml index 6801851fd..7d14d3a68 100644 --- a/src/qml/dialogs/WaypointEditor.qml +++ b/src/qml/dialogs/WaypointEditor.qml @@ -47,15 +47,15 @@ CenteringDialog { modal: true title: qsTr("Edit Waypoint") - standardButtons: Dialog.Cancel|Dialog.Ok - onAboutToShow: { // This is necessary, because the initial binding "latInput.value: waypoint.coordinate.latitude" // breaks as soon as the user edits the coordinates manually. latInput.value = waypoint.coordinate.latitude longInput.value = waypoint.coordinate.longitude + eleField.valueMeter = waypoint.coordinate.altitude wpNameField.text = waypoint.extendedName wpNotesField.text = waypoint.notes + wpNameField.focus = true } DecoratedScrollView { @@ -89,6 +89,7 @@ CenteringDialog { Layout.minimumWidth: font.pixelSize*5 text: waypoint.extendedName + focus: true } @@ -212,8 +213,6 @@ CenteringDialog { value: waypoint.coordinate.latitude minValue: -90.0 maxValue: 90.0 - - onAcceptableInputChanged: enableOk() } Label { @@ -230,8 +229,6 @@ CenteringDialog { value: waypoint.coordinate.longitude minValue: -180.0 maxValue: 180.0 - - onAcceptableInputChanged: enableOk() } @@ -361,12 +358,24 @@ CenteringDialog { model: [ qsTr("Feet"), qsTr("Meter") ] } - } } - function enableOk() { - waypointEditorDialog.standardButton(DialogButtonBox.Ok).enabled = latInput.acceptableInput && longInput.acceptableInput + + footer: DialogButtonBox { + + Button { + text: qsTr("Cancel") + flat: true + DialogButtonBox.buttonRole: DialogButtonBox.RejectRole + } + + Button { + text: qsTr("OK") + flat: true + DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole + enabled: (wpNameField.displayText !== "") && latInput.acceptableInput && longInput.acceptableInput + } } } // Dialog diff --git a/src/qml/items/DegreeInput.qml b/src/qml/items/DegreeInput.qml index a7814b51c..c9fdf12f3 100644 --- a/src/qml/items/DegreeInput.qml +++ b/src/qml/items/DegreeInput.qml @@ -36,10 +36,23 @@ StackLayout { dms_d.acceptableInput && dms_m.acceptableInput && dms_s.acceptableInput && + !isNaN(value) && (value >= minValue) && (value <= maxValue) function setTexts() { + if (isNaN(value)) { + d_d.text = "" + + dm_d.text = "" + dm_m.text = "" + + dms_d.text = "" + dms_m.text = "" + dms_s.text = "" + return + } + var minutes = 60.0*(Math.abs(value) - Math.floor(Math.abs(value))) var seconds = 60.0*(minutes - Math.floor(minutes)) diff --git a/src/qml/pages/WaypointLibraryPage.qml b/src/qml/pages/WaypointLibraryPage.qml index c63015f79..68c26af47 100644 --- a/src/qml/pages/WaypointLibraryPage.qml +++ b/src/qml/pages/WaypointLibraryPage.qml @@ -278,7 +278,6 @@ Page { anchors.left: parent.left anchors.right: parent.right - bottomPadding: SafeInsets.bottom leftPadding: SafeInsets.left rightPadding: SafeInsets.right topPadding: font.pixelSize @@ -386,6 +385,27 @@ Page { } + footer: Footer { + ColumnLayout { + width: parent.width + + Button { + id: addWPButton + + flat: true + + Layout.alignment: Qt.AlignHCenter + text: qsTr("Add Waypoint") + icon.source: "/icons/material/ic_add_circle.svg" + + onClicked: { + PlatformAdaptor.vibrateBrief() + addWP.open() + } + } + } + } + // This is the name of the file that openFromLibrary will open property string finalFileName; @@ -423,7 +443,6 @@ Page { page.reloadWaypointList() // Re-display aircraft that have been swiped out close() } - } LongTextDialog { @@ -457,6 +476,23 @@ Page { } + WaypointEditor { + id: addWP + + title: qsTr("Add Waypoint") + + onAccepted: { + let newWP = waypoint.copy() + newWP.name = newName + newWP.notes = newNotes + newWP.coordinate = QtPositioning.coordinate(newLatitude, newLongitude, newAltitudeMeter) + WaypointLibrary.add(newWP) + page.reloadWaypointList() + toast.doToast(qsTr("Waypoint added")) + } + + } + WaypointDescription { id: waypointDescription } From 988e31e8b93a7eac68bc3090adb5e6cd4b6567d7 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 21 Sep 2024 14:50:22 +0200 Subject: [PATCH 40/64] Uniformize GUI --- src/qml/items/MyTextField.qml | 5 +---- src/qml/pages/WaypointLibraryPage.qml | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/qml/items/MyTextField.qml b/src/qml/items/MyTextField.qml index c6b3437d3..fdf956e1a 100644 --- a/src/qml/items/MyTextField.qml +++ b/src/qml/items/MyTextField.qml @@ -67,9 +67,6 @@ TextField { icon.width: font.pixelSize icon.height: font.pixelSize - onClicked: { - textField.clear() - textField.onEditingFinished() - } + onClicked: textField.clear() } } diff --git a/src/qml/pages/WaypointLibraryPage.qml b/src/qml/pages/WaypointLibraryPage.qml index 68c26af47..9a120416e 100644 --- a/src/qml/pages/WaypointLibraryPage.qml +++ b/src/qml/pages/WaypointLibraryPage.qml @@ -257,17 +257,13 @@ Page { anchors.top: parent.top anchors.topMargin: page.font.pixelSize - Label { - Layout.alignment: Qt.AlignBaseline - - text: qsTr("Filter") - } - MyTextField { id: textInput Layout.alignment: Qt.AlignBaseline Layout.fillWidth: true + + placeholderText: qsTr("Filter by Name") } } @@ -357,12 +353,18 @@ Page { clip: true - model: { - // Mention waypoints to ensure that the list gets updated - WaypointLibrary.waypoints + model: + Binding { + wpList.model: { + // Mention waypoints to ensure that the list gets updated + WaypointLibrary.waypoints - return WaypointLibrary.filteredWaypoints(textInput.text) + return WaypointLibrary.filteredWaypoints(textInput.displayText) + } + delayed: true } + + delegate: waypointDelegate ScrollIndicator.vertical: ScrollIndicator {} } From ebe3f66682691b496cc43fb5533b36082f6a2c23 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 21 Sep 2024 15:04:59 +0200 Subject: [PATCH 41/64] Update WaypointLibraryPage.qml --- src/qml/pages/WaypointLibraryPage.qml | 175 +++++++++++++------------- 1 file changed, 84 insertions(+), 91 deletions(-) diff --git a/src/qml/pages/WaypointLibraryPage.qml b/src/qml/pages/WaypointLibraryPage.qml index 9a120416e..e8feaab55 100644 --- a/src/qml/pages/WaypointLibraryPage.qml +++ b/src/qml/pages/WaypointLibraryPage.qml @@ -247,109 +247,100 @@ Page { } } - RowLayout { - id: filterRow + Component { + id: waypointDelegate - anchors.left: parent.left - anchors.leftMargin: SafeInsets.left+font.pixelSize - anchors.right: parent.right - anchors.rightMargin: SafeInsets.right+font.pixelSize - anchors.top: parent.top - anchors.topMargin: page.font.pixelSize + RowLayout { + width: wpList.width + height: iDel.height - MyTextField { - id: textInput - - Layout.alignment: Qt.AlignBaseline - Layout.fillWidth: true + SwipeToDeleteDelegate { + id: iDel + Layout.fillWidth: true - placeholderText: qsTr("Filter by Name") - } - } + text: modelData.name + icon.source: modelData.icon - Pane { + onClicked: { + PlatformAdaptor.vibrateBrief() + waypointDescription.waypoint = modelData + waypointDescription.open() + } - anchors.top: filterRow.bottom - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right + swipe.onCompleted: { + PlatformAdaptor.vibrateBrief() + removeDialog.waypoint = modelData + removeDialog.open() + } + } - leftPadding: SafeInsets.left - rightPadding: SafeInsets.right - topPadding: font.pixelSize + ToolButton { + id: editButton - Component { - id: waypointDelegate + icon.source: "/icons/material/ic_mode_edit.svg" + onClicked: { + PlatformAdaptor.vibrateBrief() + wpEditor.waypoint = modelData + wpEditor.open() + } + } - RowLayout { - width: wpList.width - height: iDel.height + ToolButton { + id: cptMenuButton - SwipeToDeleteDelegate { - id: iDel - Layout.fillWidth: true + icon.source: "/icons/material/ic_more_horiz.svg" - text: modelData.name - icon.source: modelData.icon + onClicked: { + PlatformAdaptor.vibrateBrief() + cptMenu.open() + } - onClicked: { - PlatformAdaptor.vibrateBrief() - waypointDescription.waypoint = modelData - waypointDescription.open() - } + AutoSizingMenu { + id: cptMenu - swipe.onCompleted: { - PlatformAdaptor.vibrateBrief() - removeDialog.waypoint = modelData - removeDialog.open() - } - } + Action { + id: removeAction + text: qsTr("Remove…") + onTriggered: { + PlatformAdaptor.vibrateBrief() + removeDialog.waypoint = modelData + removeDialog.open() + } + } // removeAction + } // AutoSizingMenu - ToolButton { - id: editButton + } - icon.source: "/icons/material/ic_mode_edit.svg" - onClicked: { - PlatformAdaptor.vibrateBrief() - wpEditor.waypoint = modelData - wpEditor.open() - } - } + } - ToolButton { - id: cptMenuButton + } - icon.source: "/icons/material/ic_more_horiz.svg" - onClicked: { - PlatformAdaptor.vibrateBrief() - cptMenu.open() - } + ColumnLayout { + anchors.fill: parent + anchors.leftMargin: SafeInsets.left + anchors.rightMargin: SafeInsets.right - AutoSizingMenu { - id: cptMenu + Item { + Layout.preferredHeight: textInput.font.pixelSize/4.0 + } - Action { - id: removeAction - text: qsTr("Remove…") - onTriggered: { - PlatformAdaptor.vibrateBrief() - removeDialog.waypoint = modelData - removeDialog.open() - } - } // removeAction - } // AutoSizingMenu - } + MyTextField { + id: textInput - } + Layout.fillWidth: true + Layout.leftMargin: font.pixelSize/2.0 + Layout.rightMargin: font.pixelSize/2.0 + placeholderText: qsTr("Filter by Name") } DecoratedListView { id: wpList - anchors.fill: parent + Layout.fillWidth: true + Layout.fillHeight: true clip: true @@ -364,29 +355,31 @@ Page { delayed: true } - delegate: waypointDelegate ScrollIndicator.vertical: ScrollIndicator {} } - } - Label { - anchors.fill: parent + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + visible: (wpList.count === 0) + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + leftPadding: font.pixelSize*2 + rightPadding: font.pixelSize*2 + + textFormat: Text.RichText + wrapMode: Text.Wrap + text: (textInput.text === "") + ? qsTr("

Sorry!

No waypoint available. To add a waypoint here, choose 'Add Waypoint' below or double-tap on a point in the moving map.

") + : qsTr("

Sorry!

No waypoints match your filter.

") + } - visible: (wpList.count === 0) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - leftPadding: font.pixelSize*2 - rightPadding: font.pixelSize*2 - - textFormat: Text.RichText - wrapMode: Text.Wrap - text: (textInput.text === "") - ? qsTr("

Sorry!

No waypoint available. To add a waypoint here, double-tap on a point in the moving map.

") - : qsTr("

Sorry!

No waypoints match your filter criteria.

") } + footer: Footer { ColumnLayout { width: parent.width From c3c20141996dac8499814163896bc4261ac7ca3a Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 21 Sep 2024 20:42:50 +0200 Subject: [PATCH 42/64] Add possibility to enter waypoint by coordinates --- src/CMakeLists.txt | 1 - src/qml/dialogs/FlightRouteAddWPDialog.qml | 143 --------------------- src/qml/dialogs/WaypointEditor.qml | 2 +- src/qml/items/DegreeInput.qml | 2 +- src/qml/pages/FlightRouteEditor.qml | 140 +++++++++++++++++++- src/qml/pages/Nearby.qml | 2 +- 6 files changed, 141 insertions(+), 149 deletions(-) delete mode 100644 src/qml/dialogs/FlightRouteAddWPDialog.qml diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c96dc10cd..aa8f6f9e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -538,7 +538,6 @@ qt_add_qml_module(${PROJECT_NAME} qml/dialogs/AircraftSaveDialog.qml qml/dialogs/ErrorDialog.qml qml/dialogs/FirstRunDialog.qml - qml/dialogs/FlightRouteAddWPDialog.qml qml/dialogs/FlightRouteSaveDialog.qml qml/dialogs/LongTextDialogMD.qml qml/dialogs/NotamListDialog.qml diff --git a/src/qml/dialogs/FlightRouteAddWPDialog.qml b/src/qml/dialogs/FlightRouteAddWPDialog.qml deleted file mode 100644 index c7540e300..000000000 --- a/src/qml/dialogs/FlightRouteAddWPDialog.qml +++ /dev/null @@ -1,143 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2019-2023 by Stefan Kebekus * - * stefan.kebekus@gmail.com * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import akaflieg_freiburg.enroute - -import "../items" - -CenteringDialog { - id: dlg - title: qsTr("Add Waypoint to Route") - modal: true - - standardButtons: DialogButtonBox.Cancel - - Component { - id: waypointDelegate - - WordWrappingItemDelegate { - text: model.modelData.twoLineTitle - icon.source: model.modelData.icon - - width: wpList.width - - onClicked: { - PlatformAdaptor.vibrateBrief() - Navigator.flightRoute.append(model.modelData) - close() - } - } - - } - - ColumnLayout { - anchors.fill: parent - - Label { - Layout.fillWidth: true - - text: qsTr("Choose a waypoint from the list below or enter coordinates manually.") - wrapMode: Text.Wrap - textFormat: Text.StyledText - visible: textInput.text === "" - } - - Item { - Layout.preferredHeight: textInput.font.pixelSize - visible: textInput.text === "" - } - - MyTextField { - id: textInput - - Layout.fillWidth: true - - placeholderText: qsTr("Filter by Name") - - focus: true - - onAccepted: { - if (wpList.model.length > 0) { - PlatformAdaptor.vibrateBrief() - Navigator.flightRoute.append(wpList.model[0]) - close() - } - } - - // On iOS17, the property displayText sees many bounces. - onDisplayTextChanged: debounceTimer.restart() - } - - Label { - Layout.fillWidth: true - Layout.topMargin: font.pixelSize - - text: qsTr("

Sorry!

No waypoints match your filter.

") - wrapMode: Text.Wrap - textFormat: Text.StyledText - horizontalAlignment: Text.AlignHCenter - - visible: wpList.model.length === 0 - } - - DecoratedListView { - id: wpList - - Layout.fillHeight: true - Layout.fillWidth: true - Layout.preferredHeight: contentHeight - - clip: true - - // Debounce timer to update the property model only 200ms after the last change of textInput.displayText - Timer { - id: debounceTimer - interval: 200 // 200ms - onTriggered: wpList.model = GeoMapProvider.filteredWaypoints(textInput.displayText) - } - - model: GeoMapProvider.filteredWaypoints(textInput.displayText) - delegate: waypointDelegate - ScrollIndicator.vertical: ScrollIndicator {} - - Label { - anchors.fill: wpList - anchors.topMargin: font.pixelSize*2 - - visible: (wpList.count === 0) - horizontalAlignment: Text.AlignHCenter - textFormat: Text.StyledText - wrapMode: Text.Wrap - text: (textInput.text === "") - ? qsTr("

Sorry!

No waypoints available. Please make sure that an aviation map is installed.

") - : qsTr("

Sorry!

No waypoints match your filter criteria.

") - onLinkActivated: Qt.openUrlExternally(link) - } - - } - - } - - onOpened: textInput.clear() -} // Page diff --git a/src/qml/dialogs/WaypointEditor.qml b/src/qml/dialogs/WaypointEditor.qml index 7d14d3a68..9588b3106 100644 --- a/src/qml/dialogs/WaypointEditor.qml +++ b/src/qml/dialogs/WaypointEditor.qml @@ -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 * diff --git a/src/qml/items/DegreeInput.qml b/src/qml/items/DegreeInput.qml index c9fdf12f3..2eb880755 100644 --- a/src/qml/items/DegreeInput.qml +++ b/src/qml/items/DegreeInput.qml @@ -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 * diff --git a/src/qml/pages/FlightRouteEditor.qml b/src/qml/pages/FlightRouteEditor.qml index 66c0a0853..5a352b5f5 100644 --- a/src/qml/pages/FlightRouteEditor.qml +++ b/src/qml/pages/FlightRouteEditor.qml @@ -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 * @@ -699,9 +699,127 @@ Page { } } - FlightRouteAddWPDialog { + CenteringDialog { id: flightRouteAddWPDialog + title: qsTr("Add Waypoint to Route") + modal: true + + standardButtons: DialogButtonBox.Cancel + + Component { + id: waypointDelegate + + WordWrappingItemDelegate { + text: model.modelData.twoLineTitle + icon.source: model.modelData.icon + + width: wpList.width + + onClicked: { + PlatformAdaptor.vibrateBrief() + Navigator.flightRoute.append(model.modelData) + close() + } + } + + } + + ColumnLayout { + anchors.fill: parent + + Label { + Layout.fillWidth: true + + text: qsTr("Choose a waypoint from the list below or enter coordinates manually.") + wrapMode: Text.Wrap + textFormat: Text.StyledText + visible: textInput.displayText === "" + onLinkActivated: { + PlatformAdaptor.vibrateBrief() + flightRouteAddWPDialog.close() + addbyCoordinates.open() + } + } + + Item { + Layout.preferredHeight: textInput.font.pixelSize + visible: textInput.displayText === "" + } + + MyTextField { + id: textInput + + Layout.fillWidth: true + + placeholderText: qsTr("Filter by Name") + + focus: true + + onAccepted: { + if (wpList.model.length > 0) { + PlatformAdaptor.vibrateBrief() + Navigator.flightRoute.append(wpList.model[0]) + close() + } + } + + // On iOS17, the property displayText sees many bounces. + onDisplayTextChanged: debounceTimer.restart() + } + + Label { + Layout.fillWidth: true + Layout.topMargin: font.pixelSize + + text: qsTr("

Sorry!

No waypoints match your filter.

") + wrapMode: Text.Wrap + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + + visible: wpList.model.length === 0 + } + + DecoratedListView { + id: wpList + + Layout.fillHeight: true + Layout.fillWidth: true + Layout.preferredHeight: contentHeight + + clip: true + + // Debounce timer to update the property model only 200ms after the last change of textInput.displayText + Timer { + id: debounceTimer + interval: 200 // 200ms + onTriggered: wpList.model = GeoMapProvider.filteredWaypoints(textInput.displayText) + } + + model: GeoMapProvider.filteredWaypoints(textInput.displayText) + delegate: waypointDelegate + ScrollIndicator.vertical: ScrollIndicator {} + + Label { + anchors.fill: wpList + anchors.topMargin: font.pixelSize*2 + + visible: (wpList.count === 0) + horizontalAlignment: Text.AlignHCenter + textFormat: Text.StyledText + wrapMode: Text.Wrap + text: (textInput.text === "") + ? qsTr("

Sorry!

No waypoints available. Please make sure that an aviation map is installed.

") + : qsTr("

Sorry!

No waypoints match your filter criteria.

") + onLinkActivated: Qt.openUrlExternally(link) + } + + } + + } + + onOpened: textInput.clear() + Connections { target: DemoRunner @@ -712,6 +830,24 @@ Page { } + WaypointEditor { + id: addbyCoordinates + + title: qsTr("Add Waypoint to Route") + modal: true + + onAccepted: { + PlatformAdaptor.vibrateBrief() + let newWP = waypoint.copy() + newWP.name = newName + newWP.notes = newNotes + newWP.coordinate = QtPositioning.coordinate(newLatitude, newLongitude, newAltitudeMeter) + Navigator.flightRoute.append(newWP) + addbyCoordinates.close() + } + + } + LongTextDialog { id: clearDialog diff --git a/src/qml/pages/Nearby.qml b/src/qml/pages/Nearby.qml index 2582cad4f..6458bf148 100644 --- a/src/qml/pages/Nearby.qml +++ b/src/qml/pages/Nearby.qml @@ -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 * From d6c545c43551b64bfedad19549d1ea68bc833e0b Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 22 Sep 2024 18:13:39 +0200 Subject: [PATCH 43/64] Cleanup --- src/notam/NotamProvider.cpp | 41 ++++++++++++++++++++++--------------- src/notam/NotamProvider.h | 15 +++++++------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 61ac166cb..24086020e 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -58,6 +58,7 @@ void NOTAM::NotamProvider::deferredInitialization() connect(this, &NOTAM::NotamProvider::dataChanged, this, &NOTAM::NotamProvider::save, Qt::QueuedConnection); // Load NOTAM data from file in stdFileName, then clean the data (which potentially triggers save()). + QList newNotamLists; auto inputFile = QFile(m_stdFileName); if (inputFile.open(QIODevice::ReadOnly)) { @@ -67,13 +68,10 @@ void NOTAM::NotamProvider::deferredInitialization() if (magicString == QStringLiteral(GIT_COMMIT)) { inputStream >> m_readNotamNumbers; - inputStream >> m_notamLists; - } - if (!m_notamLists.isEmpty()) - { - m_lastUpdate = m_notamLists[0].retrieved(); + inputStream >> newNotamLists; } } + m_notamLists = newNotamLists; clean(); // Setup Status @@ -100,7 +98,6 @@ NOTAM::NotamProvider::~NotamProvider() networkReply->abort(); } - m_notamLists.clear(); m_networkReplies.clear(); } @@ -116,7 +113,7 @@ QByteArray NOTAM::NotamProvider::GeoJSON() const QSet coordinatesSeen; QSet regionsCovered; - foreach(auto notamList, m_notamLists) + foreach(auto notamList, m_notamLists.value()) { foreach(auto notam, notamList.notams()) { @@ -187,7 +184,7 @@ QList NOTAM::NotamProvider::waypoints() const QSet coordinatesSeen; QSet regionsCovered; - foreach(auto notamList, m_notamLists) + foreach(auto notamList, m_notamLists.value()) { foreach(auto notam, notamList.notams()) { @@ -254,7 +251,7 @@ NOTAM::NotamList NOTAM::NotamProvider::notams(const GeoMaps::Waypoint& waypoint) // Check if notams for the location are present in our database. // Go through the database, oldest to newest. - foreach (auto notamList, m_notamLists) + foreach (auto notamList, m_notamLists.value()) { // Disregard outdated notamLists if (notamList.isOutdated()) @@ -324,6 +321,17 @@ void NOTAM::NotamProvider::setRead(const QString& number, bool read) // Private Slots // +QDateTime NOTAM::NotamProvider::lastUpdateBinding() +{ + auto notamLists = m_notamLists.value(); + if (notamLists.isEmpty()) + { + return {}; + } + return notamLists[0].retrieved(); +} + + void NOTAM::NotamProvider::clean() { QList newNotamLists; @@ -331,7 +339,7 @@ void NOTAM::NotamProvider::clean() bool haveChange = false; // Iterate over notamLists, newest lists first - foreach(auto notamList, m_notamLists) + foreach(auto notamList, m_notamLists.value()) { // If this notamList is outdated, then so all all further ones. We can thus end here. if (notamList.isOutdated()) @@ -369,7 +377,6 @@ void NOTAM::NotamProvider::clean() void NOTAM::NotamProvider::downloadFinished() { - bool newDataAdded = false; m_networkReplies.removeAll(nullptr); foreach(auto networkReply, m_networkReplies) @@ -402,15 +409,17 @@ void NOTAM::NotamProvider::downloadFinished() { continue; } +#warning not optimal, causes too many changes NotamList const notamList(jsonDoc, region, &m_cancelledNotamNumbers); - m_notamLists.prepend(notamList); + auto newNotamList = m_notamLists.value(); + newNotamList.prepend(notamList); + m_notamLists = newNotamList; newDataAdded = true; } if (newDataAdded) { clean(); - m_lastUpdate = QDateTime::currentDateTimeUtc(); emit dataChanged(); } } @@ -424,7 +433,7 @@ void NOTAM::NotamProvider::save() const QDataStream outputStream(&outputFile); outputStream << QStringLiteral(GIT_COMMIT); outputStream << m_readNotamNumbers; - outputStream << m_notamLists; + outputStream << m_notamLists.value(); } } @@ -479,7 +488,7 @@ Units::Distance NOTAM::NotamProvider::range(const QGeoCoordinate& position) // If we have a NOTAM list that contains the position // within half its radius, then stop. - foreach (auto notamList, m_notamLists) + foreach (auto notamList, m_notamLists.value()) { if (notamList.isOutdated()) { @@ -562,7 +571,7 @@ void NOTAM::NotamProvider::updateStatus() } bool hasNOTAM = false; - foreach (auto notamList, m_notamLists) + foreach (auto notamList, m_notamLists.value()) { if (notamList.isOutdated()) { diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index 72f0b5263..f40587ef4 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -61,7 +61,6 @@ class NotamProvider : public GlobalObject { // Properties // - /*! \brief List of NOTAM points * * This property holds GeoJSON, to describe points where NOTAMs are active. @@ -86,7 +85,6 @@ class NotamProvider : public GlobalObject { // Getter Methods // - /*! \brief Getter function for property with the same name * * @returns Property GeoJSON @@ -118,7 +116,7 @@ class NotamProvider : public GlobalObject { // Methods // - /*! \brief Notams for a given waypoint + /*! \brief NOTAMs for a given waypoint * * The returned list is empty and has a valid property "retrieved" if the * NotamProvider is sure that there are no relevant notams for the given @@ -137,7 +135,7 @@ class NotamProvider : public GlobalObject { */ [[nodiscard]] Q_INVOKABLE NOTAM::NotamList notams(const GeoMaps::Waypoint& waypoint); - /*! \brief Check is a notam number is registred as read + /*! \brief Check if a NOTAM number is registred as read * * @param number Notam number * @@ -145,7 +143,7 @@ class NotamProvider : public GlobalObject { */ [[nodiscard]] Q_INVOKABLE bool isRead(const QString& number) { return m_readNotamNumbers.contains(number); } - /*! \brief Register notam number as read or unread + /*! \brief Register NOTAM number as read or unread * * @param number Notam number * @@ -157,6 +155,9 @@ class NotamProvider : public GlobalObject { /*! \brief Notifier signal */ void dataChanged(); +private: + QDateTime lastUpdateBinding(); + private slots: // Removes outdated and irrelevant data from the database. This slot is called // once per hour. @@ -203,10 +204,10 @@ private slots: QList> m_networkReplies; // List of NotamLists, sorted so that newest lists come first - QList m_notamLists; + QProperty> m_notamLists; // Time of last update to data - QProperty m_lastUpdate; + QProperty m_lastUpdate {[this]() {return this->lastUpdateBinding();}}; // Filename for loading/saving NOTAM data QProperty m_status; From fe1746f5825122ccd85855efb663b23ec01a2431 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 22 Sep 2024 19:52:14 +0200 Subject: [PATCH 44/64] Working... --- src/notam/NotamProvider.cpp | 144 ++++++++++++++++++------------------ src/notam/NotamProvider.h | 16 ++-- src/qml/items/FlightMap.qml | 2 +- 3 files changed, 83 insertions(+), 79 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 24086020e..9fe35df8e 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -71,7 +71,7 @@ void NOTAM::NotamProvider::deferredInitialization() inputStream >> newNotamLists; } } - m_notamLists = newNotamLists; + m_notamLists.setValue(newNotamLists); clean(); // Setup Status @@ -107,77 +107,6 @@ NOTAM::NotamProvider::~NotamProvider() // Getter Methods // -QByteArray NOTAM::NotamProvider::GeoJSON() const -{ - QList result; - QSet coordinatesSeen; - QSet regionsCovered; - - foreach(auto notamList, m_notamLists.value()) - { - foreach(auto notam, notamList.notams()) - { - if (!notam.isValid() || notam.isOutdated()) - { - continue; - } - auto coordinate = notam.coordinate(); - if (!coordinate.isValid()) - { - continue; - } - if (!notamList.region().contains(coordinate)) - { - continue; - } - - - // If we already have a waypoint for that coordinate, then don't add another one. - if (coordinatesSeen.contains(coordinate)) - { - continue; - } - - // If the coordinate has already been handled by an earlier (=newer) notamList, - // then don't add it here. - bool hasBeenCovered = false; - foreach(auto region, regionsCovered) - { - if (region.contains(coordinate)) - { - hasBeenCovered = true; - break; - } - } - if (hasBeenCovered) - { - continue; - } - - coordinatesSeen += coordinate; - result.append(notam.GeoJSON()); - } - - regionsCovered += notamList.region(); - } - - - QJsonArray waypointArray; - foreach (const auto& jsonObject, result) - { - waypointArray.append(jsonObject); - } - - QJsonObject jsonObj; - jsonObj.insert(QStringLiteral("type"), "FeatureCollection"); - jsonObj.insert(QStringLiteral("features"), waypointArray); - - QJsonDocument doc; - doc.setObject(jsonObj); - return doc.toJson(); -} - - QList NOTAM::NotamProvider::waypoints() const { QList result; @@ -321,7 +250,76 @@ void NOTAM::NotamProvider::setRead(const QString& number, bool read) // Private Slots // -QDateTime NOTAM::NotamProvider::lastUpdateBinding() +QByteArray NOTAM::NotamProvider::computeGeoJSON() +{ + QList result; + QSet coordinatesSeen; + QSet regionsCovered; + +#warning can simplify! + foreach(auto notamList, m_notamLists.value()) + { + foreach(auto notam, notamList.notams()) + { + if (!notam.isValid() || notam.isOutdated()) + { + continue; + } + auto coordinate = notam.coordinate(); + if (!coordinate.isValid()) + { + continue; + } + if (!notamList.region().contains(coordinate)) + { + continue; + } + + // If we already have a waypoint for that coordinate, then don't add another one. + if (coordinatesSeen.contains(coordinate)) + { + continue; + } + + // If the coordinate has already been handled by an earlier (=newer) notamList, + // then don't add it here. + bool hasBeenCovered = false; + foreach(auto region, regionsCovered) + { + if (region.contains(coordinate)) + { + hasBeenCovered = true; + break; + } + } + if (hasBeenCovered) + { + continue; + } + + coordinatesSeen += coordinate; + result.append(notam.GeoJSON()); + } + + regionsCovered += notamList.region(); + } + + QJsonArray waypointArray; + foreach (const auto& jsonObject, result) + { + waypointArray.append(jsonObject); + } + QJsonObject jsonObj; + jsonObj.insert(QStringLiteral("type"), "FeatureCollection"); + jsonObj.insert(QStringLiteral("features"), waypointArray); + + QJsonDocument doc; + doc.setObject(jsonObj); + return doc.toJson(); +} + + +QDateTime NOTAM::NotamProvider::computeLastUpdate() { auto notamLists = m_notamLists.value(); if (notamLists.isEmpty()) diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index f40587ef4..b6a863a99 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -65,7 +65,7 @@ class NotamProvider : public GlobalObject { * * This property holds GeoJSON, to describe points where NOTAMs are active. */ - Q_PROPERTY(QByteArray GeoJSON READ GeoJSON NOTIFY dataChanged) + Q_PROPERTY(QByteArray geoJSON READ geoJSON BINDABLE bindableGeoJSON) /*! \brief Time of last database update */ Q_PROPERTY(QDateTime lastUpdate READ lastUpdate BINDABLE bindableLastUpdate) @@ -89,14 +89,15 @@ class NotamProvider : public GlobalObject { * * @returns Property GeoJSON */ - [[nodiscard]] QByteArray GeoJSON() const; + Q_REQUIRED_RESULT QByteArray geoJSON() const {return {m_geoJSON};} + Q_REQUIRED_RESULT QBindable bindableGeoJSON() {return &m_geoJSON;} /*! \brief Getter function for the property with the same name * * @returns Property lastUpdate */ Q_REQUIRED_RESULT QDateTime lastUpdate() const {return {m_lastUpdate};} - Q_REQUIRED_RESULT QBindable bindableLastUpdate() { return &m_lastUpdate; } + Q_REQUIRED_RESULT QBindable bindableLastUpdate() {return &m_lastUpdate;} /*! \brief Getter function for the property with the same name * @@ -156,7 +157,9 @@ class NotamProvider : public GlobalObject { void dataChanged(); private: - QDateTime lastUpdateBinding(); + // Property bindings + QByteArray computeGeoJSON(); + QDateTime computeLastUpdate(); private slots: // Removes outdated and irrelevant data from the database. This slot is called @@ -206,8 +209,11 @@ private slots: // List of NotamLists, sorted so that newest lists come first QProperty> m_notamLists; + // GeoJSON, for use in map + QProperty m_geoJSON {[this]() {return this->computeGeoJSON();}}; + // Time of last update to data - QProperty m_lastUpdate {[this]() {return this->lastUpdateBinding();}}; + QProperty m_lastUpdate {[this]() {return this->computeLastUpdate();}}; // Filename for loading/saving NOTAM data QProperty m_status; diff --git a/src/qml/items/FlightMap.qml b/src/qml/items/FlightMap.qml index a6c6ce88b..232cb3399 100644 --- a/src/qml/items/FlightMap.qml +++ b/src/qml/items/FlightMap.qml @@ -173,7 +173,7 @@ Map { styleId: "notams" type: "geojson" - property string data: NotamProvider.GeoJSON + property string data: NotamProvider.geoJSON } LayerParameter { From 8f1872e3e2c2f68b7a5290b8e67da0d4174dde8f Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 22 Sep 2024 20:00:34 +0200 Subject: [PATCH 45/64] Translations --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 46c066b67..62c164e28 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 46c066b674cd8edb331c0bc8c811dab55e3877f2 +Subproject commit 62c164e28c663811063cf48ffd6a5041e1e65e0d From a27decb3bea147f2d79c258bd8db9862024be620 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 23 Sep 2024 20:27:08 +0200 Subject: [PATCH 46/64] Cleanup --- src/notam/NotamProvider.cpp | 77 +++++-------------------------------- src/notam/NotamProvider.h | 16 ++------ 2 files changed, 14 insertions(+), 79 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 9fe35df8e..f7262c8ec 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -54,9 +54,6 @@ void NOTAM::NotamProvider::deferredInitialization() timer->start(61min); connect(timer, &QTimer::timeout, this, &NOTAM::NotamProvider::clean); - // Save the NOTAM data every time that the database changes - connect(this, &NOTAM::NotamProvider::dataChanged, this, &NOTAM::NotamProvider::save, Qt::QueuedConnection); - // Load NOTAM data from file in stdFileName, then clean the data (which potentially triggers save()). QList newNotamLists; auto inputFile = QFile(m_stdFileName); @@ -84,6 +81,15 @@ void NOTAM::NotamProvider::deferredInitialization() // Set variables initially QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateData); QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateStatus); + + // Setup Bindings + m_geoJSON.setBinding([this]() {return this->computeGeoJSON();}); + m_lastUpdate.setBinding([this]() {return this->computeLastUpdate();}); + + // Setup Notifiers + // + // Save the NOTAM data every time that the database changes + m_saveNotifier = m_notamLists.addNotifier([this]() {this->save();}); } @@ -102,70 +108,6 @@ NOTAM::NotamProvider::~NotamProvider() } - -// -// Getter Methods -// - -QList NOTAM::NotamProvider::waypoints() const -{ - QList result; - QSet coordinatesSeen; - QSet regionsCovered; - - foreach(auto notamList, m_notamLists.value()) - { - foreach(auto notam, notamList.notams()) - { - if (!notam.isValid() || notam.isOutdated()) - { - continue; - } - auto coordinate = notam.coordinate(); - if (!coordinate.isValid()) - { - continue; - } - if (!notamList.region().contains(coordinate)) - { - continue; - } - - - // If we already have a waypoint for that coordinate, then don't add another one. - if (coordinatesSeen.contains(coordinate)) - { - continue; - } - - // If the coordinate has already been handled by an earlier (=newer) notamList, - // then don't add it here. - bool hasBeenCovered = false; - foreach(auto region, regionsCovered) - { - if (region.contains(coordinate)) - { - hasBeenCovered = true; - break; - } - } - if (hasBeenCovered) - { - continue; - } - - coordinatesSeen += coordinate; - result.append(coordinate); - } - - regionsCovered += notamList.region(); - } - - return result; -} - - - // // Methods // @@ -425,6 +367,7 @@ void NOTAM::NotamProvider::downloadFinished() void NOTAM::NotamProvider::save() const { + qWarning() << "NOTAM::NotamProvider::save()"; auto outputFile = QFile(m_stdFileName); if (outputFile.open(QIODevice::WriteOnly)) { diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index b6a863a99..e13332b47 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -56,7 +56,6 @@ class NotamProvider : public GlobalObject { } - // // Properties // @@ -70,9 +69,6 @@ class NotamProvider : public GlobalObject { /*! \brief Time of last database update */ Q_PROPERTY(QDateTime lastUpdate READ lastUpdate BINDABLE bindableLastUpdate) - /*! \brief Waypoints with Notam items, for presentation in a map */ - Q_PROPERTY(QList waypoints READ waypoints NOTIFY dataChanged) - /*! \brief Status * * This is a translated, human-readable text with warnings about incomplete NOTAM data, @@ -106,12 +102,6 @@ class NotamProvider : public GlobalObject { Q_REQUIRED_RESULT QString status() const {return {m_status};} Q_REQUIRED_RESULT QBindable bindableStatus() {return &m_status;} - /*! \brief Getter function for the property with the same name - * - * @returns Property waypoints - */ - Q_REQUIRED_RESULT QList waypoints() const; - // // Methods @@ -188,6 +178,8 @@ private slots: private: Q_DISABLE_COPY_MOVE(NotamProvider) + QPropertyNotifier m_saveNotifier; + // Compute the radius of the circle around the waypoint that is covered by // existing or requested notam data. Returns Units::Distance::fromM(-1) if // the waypoint is not covered by data. @@ -210,10 +202,10 @@ private slots: QProperty> m_notamLists; // GeoJSON, for use in map - QProperty m_geoJSON {[this]() {return this->computeGeoJSON();}}; + QProperty m_geoJSON; // Time of last update to data - QProperty m_lastUpdate {[this]() {return this->computeLastUpdate();}}; + QProperty m_lastUpdate; // Filename for loading/saving NOTAM data QProperty m_status; From 00aeb36d2947461f6ccb61d1a4d7a91b4d594901 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Tue, 24 Sep 2024 07:37:13 +0200 Subject: [PATCH 47/64] Move to C++ bindings for simplicity and robustness --- src/navigation/Clock.cpp | 3 +- src/navigation/FlightRoute.cpp | 113 ++++++++++++++----------- src/navigation/FlightRoute.h | 16 ++-- src/navigation/FlightRoute_GPX.cpp | 2 +- src/notam/NotamProvider.cpp | 122 +++++++++++++-------------- src/notam/NotamProvider.h | 5 +- src/positioning/PositionProvider.cpp | 23 +++-- src/positioning/PositionProvider.h | 51 +++++++++-- 8 files changed, 196 insertions(+), 139 deletions(-) diff --git a/src/navigation/Clock.cpp b/src/navigation/Clock.cpp index 86cdb3392..c7019c7ed 100644 --- a/src/navigation/Clock.cpp +++ b/src/navigation/Clock.cpp @@ -19,7 +19,6 @@ ***************************************************************************/ #include "Clock.h" -#include "positioning/PositionProvider.h" #include #include @@ -32,7 +31,7 @@ using namespace std::chrono_literals; Navigation::Clock::Clock(QObject *parent) : GlobalObject(parent) { // We need to update the time regularly. I do not use a simple timer here that emits "timeChanged" once per minute, because I - // want the signal to be emitted right after the full minute. So, I use a timer that once a minute set a single-shot time + // want the signal to be emitted right after the full minute. So, I use a timer that once a minute sets a single-shot timer // that is set to fire up 500ms after the full minute. This design will also work reliably if "timer" get out of sync, // for instance because the app was sleeping for a while. auto *timer = new QTimer(this); diff --git a/src/navigation/FlightRoute.cpp b/src/navigation/FlightRoute.cpp index eb8659e0a..e0f89adcf 100644 --- a/src/navigation/FlightRoute.cpp +++ b/src/navigation/FlightRoute.cpp @@ -39,6 +39,10 @@ Navigation::FlightRoute::FlightRoute(QObject *parent) connect(this, &FlightRoute::waypointsChanged, this, &Navigation::FlightRoute::summaryChanged); connect(GlobalObject::navigator(), &Navigation::Navigator::aircraftChanged, this, &Navigation::FlightRoute::summaryChanged); connect(GlobalObject::navigator(), &Navigation::Navigator::windChanged, this, &Navigation::FlightRoute::summaryChanged); + + // Setup Bindings + m_geoPath.setBinding([this]() {return this->computeGeoPath();}); + } @@ -50,7 +54,7 @@ auto Navigation::FlightRoute::boundingRectangle() const -> QGeoRectangle { QGeoRectangle bbox; - for(const auto &_waypoint : m_waypoints) + for(const auto &_waypoint : m_waypoints.value()) { if (!_waypoint.isValid()) { @@ -72,10 +76,10 @@ auto Navigation::FlightRoute::boundingRectangle() const -> QGeoRectangle return bbox; } -auto Navigation::FlightRoute::geoPath() const -> QList +QList Navigation::FlightRoute::computeGeoPath() { QList result; - for(const auto& _waypoint : m_waypoints) + for(const auto& _waypoint : m_waypoints.value()) { if (!_waypoint.isValid()) { @@ -91,12 +95,7 @@ auto Navigation::FlightRoute::midFieldWaypoints() const -> QList result; - if (m_waypoints.isEmpty()) - { - return result; - } - - foreach(auto wpt, m_waypoints) + foreach(auto wpt, m_waypoints.value()) { if (wpt.category() == u"WP") { @@ -183,7 +182,9 @@ auto Navigation::FlightRoute::summary() const -> QString void Navigation::FlightRoute::append(const GeoMaps::Waypoint& waypoint) { - m_waypoints.append(waypoint); + auto newWaypoints = m_waypoints.value(); + newWaypoints.append(waypoint); + m_waypoints = newWaypoints; updateLegs(); emit waypointsChanged(); @@ -196,21 +197,21 @@ void Navigation::FlightRoute::append(const QGeoCoordinate& position) auto Navigation::FlightRoute::canAppend(const GeoMaps::Waypoint &other) const -> bool { - if (m_waypoints.isEmpty()) + if (m_waypoints.value().isEmpty()) { return true; } - return !m_waypoints.last().isNear(other); + return !m_waypoints.value().last().isNear(other); } auto Navigation::FlightRoute::canInsert(const GeoMaps::Waypoint &other) const -> bool { - if (m_waypoints.size() < 2) + if (m_waypoints.value().size() < 2) { return false; } - foreach(const auto& waypoint, m_waypoints) + foreach(const auto& waypoint, m_waypoints.value()) { if (waypoint.isNear(other)) { @@ -222,7 +223,7 @@ auto Navigation::FlightRoute::canInsert(const GeoMaps::Waypoint &other) const -> void Navigation::FlightRoute::clear() { - m_waypoints.clear(); + m_waypoints = QVector(); updateLegs(); emit waypointsChanged(); @@ -230,7 +231,7 @@ void Navigation::FlightRoute::clear() auto Navigation::FlightRoute::contains(const GeoMaps::Waypoint& waypoint) const -> bool { - foreach(auto _waypoint, m_waypoints) + foreach(auto _waypoint, m_waypoints.value()) { if (!_waypoint.isValid()) { @@ -254,19 +255,20 @@ void Navigation::FlightRoute::insert(const GeoMaps::Waypoint& waypoint) int shortestIndex = 0; double shortestRoute = 10e9; - for(int idx=0; idx qsizetype { - for(auto i=m_waypoints.size()-1; i>=0; i--) + for(auto i=m_waypoints.value().size()-1; i>=0; i--) { - auto _waypoint = m_waypoints.at(i); + auto _waypoint = m_waypoints.value().at(i); if (!_waypoint.isValid()) { continue; @@ -324,7 +327,7 @@ auto Navigation::FlightRoute::load(const QString& fileName) -> QString return tr("The file '%1' contains too many waypoints. Flight routes with more than 100 waypoints are not supported.").arg(myFileName); } - m_waypoints.clear(); + QVector newWaypoints; foreach(auto waypoint, result) { if (!waypoint.isValid()) @@ -337,14 +340,14 @@ auto Navigation::FlightRoute::load(const QString& fileName) -> QString auto nearest = GlobalObject::geoMapProvider()->closestWaypoint(pos, distPos); if (nearest.type() == u"WP") { - m_waypoints << waypoint; + newWaypoints << waypoint; } else { - m_waypoints << nearest; + newWaypoints << nearest; } - } + m_waypoints = newWaypoints; updateLegs(); emit waypointsChanged(); @@ -353,13 +356,16 @@ auto Navigation::FlightRoute::load(const QString& fileName) -> QString void Navigation::FlightRoute::moveDown(int idx) { + QVector newWaypoints = m_waypoints.value(); + // Paranoid safety checks - if ((idx < 0) || (idx > m_waypoints.size()-2)) + if ((idx < 0) || (idx > newWaypoints.size()-2)) { return; } - m_waypoints.move(idx, idx+1); + newWaypoints.move(idx, idx+1); + m_waypoints = newWaypoints; updateLegs(); emit waypointsChanged(); @@ -367,13 +373,16 @@ void Navigation::FlightRoute::moveDown(int idx) void Navigation::FlightRoute::moveUp(int idx) { + QVector newWaypoints = m_waypoints.value(); + // Paranoid safety checks - if ((idx < 1) || (idx >= m_waypoints.size())) + if ((idx < 1) || (idx >= newWaypoints.size())) { return; } - m_waypoints.move(idx, idx-1); + newWaypoints.move(idx, idx-1); + m_waypoints = newWaypoints; updateLegs(); emit waypointsChanged(); @@ -381,39 +390,47 @@ void Navigation::FlightRoute::moveUp(int idx) void Navigation::FlightRoute::removeWaypoint(int idx) { + QVector newWaypoints = m_waypoints.value(); + // Paranoid safety checks - if ((idx < 0) || (idx >= m_waypoints.size())) + if ((idx < 0) || (idx >= newWaypoints.size())) { return; } - m_waypoints.removeAt(idx); + newWaypoints.removeAt(idx); + m_waypoints = newWaypoints; updateLegs(); emit waypointsChanged(); } void Navigation::FlightRoute::replaceWaypoint(int idx, const GeoMaps::Waypoint& newWaypoint) { + QVector newWaypoints = m_waypoints.value(); + // Paranoid safety checks - if ((idx < 0) || (idx >= m_waypoints.size())) + if ((idx < 0) || (idx >= newWaypoints.size())) { return; } - // If name did not - if (m_waypoints[idx] == newWaypoint) + + // If no change is necessary, then return + if (newWaypoints[idx] == newWaypoint) { return; } - - m_waypoints[idx] = newWaypoint; + newWaypoints[idx] = newWaypoint; + m_waypoints = newWaypoints; updateLegs(); emit waypointsChanged(); } void Navigation::FlightRoute::reverse() { - std::reverse(m_waypoints.begin(), m_waypoints.end()); + QVector newWaypoints = m_waypoints.value(); + std::reverse(newWaypoints.begin(), newWaypoints.end()); + m_waypoints = newWaypoints; updateLegs(); emit waypointsChanged(); } @@ -439,7 +456,7 @@ auto Navigation::FlightRoute::save(const QString& fileName) const -> QString auto Navigation::FlightRoute::suggestedFilename() const -> QString { - if (m_waypoints.size() < 2) + if (m_waypoints.value().size() < 2) { return tr("Flight Route"); } @@ -447,8 +464,8 @@ auto Navigation::FlightRoute::suggestedFilename() const -> QString // // Get name for start point (e.g. "EDTL (LAHR)") // - QString start = m_waypoints.constFirst().ICAOCode(); // ICAO code of start point - QString name = m_waypoints.constFirst().name(); // Name of start point + auto start = m_waypoints.value().constFirst().ICAOCode(); // ICAO code of start point + auto name = m_waypoints.value().constFirst().name(); // Name of start point name.replace(u'(', u""_qs); name.replace(u')', u""_qs); if (name.length() > 11) @@ -470,8 +487,8 @@ auto Navigation::FlightRoute::suggestedFilename() const -> QString // // Get name for end point (e.g. "EDTG (BREMGARTEN)") // - QString end = m_waypoints.constLast().ICAOCode(); // ICAO code of end point - name = m_waypoints.constLast().name(); // Name of end point + QString end = m_waypoints.value().constLast().ICAOCode(); // ICAO code of end point + name = m_waypoints.value().constLast().name(); // Name of end point name.replace(u"("_qs, u""_qs); name.replace(u")"_qs, u""_qs); if (name.length() > 11) @@ -518,7 +535,7 @@ auto Navigation::FlightRoute::suggestedFilename() const -> QString auto Navigation::FlightRoute::toGeoJSON() const -> QByteArray { QJsonArray waypointArray; - foreach(const auto& waypoint, m_waypoints) + foreach(const auto& waypoint, m_waypoints.value()) { if (waypoint.isValid()) { @@ -540,9 +557,9 @@ void Navigation::FlightRoute::updateLegs() { m_legs.clear(); - for(int i=0; i #include #include #include @@ -94,7 +95,7 @@ namespace Navigation * This property holds a list of coordinates of the waypoints, suitable * for drawing the flight path on a QML map. */ - Q_PROPERTY(QList geoPath READ geoPath NOTIFY waypointsChanged) + Q_PROPERTY(QList geoPath READ geoPath BINDABLE bindableGeoPath) /*! \brief List of waypoints in the flight route that are not airfields * @@ -144,7 +145,8 @@ namespace Navigation * * @returns Property geoPath */ - [[nodiscard]] auto geoPath() const -> QList; + [[nodiscard]] QList geoPath() const {return {m_geoPath};} + [[nodiscard]] QBindable> bindableGeoPath() const {return &m_geoPath;} /*! \brief Getter function for the property with the same name * @@ -162,7 +164,7 @@ namespace Navigation * * @returns Property size */ - [[nodiscard]] auto size() const -> qsizetype { return m_waypoints.size(); } + [[nodiscard]] auto size() const -> qsizetype { return m_waypoints.value().size(); } /*! \brief Getter function for the property with the same name * @@ -174,7 +176,7 @@ namespace Navigation * * @returns Property waypoints */ - [[nodiscard]] auto waypoints() const -> QList {return m_waypoints;} + [[nodiscard]] auto waypoints() const -> QList {return {m_waypoints};} // @@ -353,10 +355,14 @@ namespace Navigation private: Q_DISABLE_COPY_MOVE(FlightRoute) + // Computer functions for bindings + QList computeGeoPath(); + // Helper function for method toGPX [[nodiscard]] auto gpxElements(const QString& indent, const QString& tag) const -> QString; - QVector m_waypoints; + QProperty> m_geoPath; + QProperty> m_waypoints; QVector m_legs; diff --git a/src/navigation/FlightRoute_GPX.cpp b/src/navigation/FlightRoute_GPX.cpp index 925cd0c42..53ec286b5 100644 --- a/src/navigation/FlightRoute_GPX.cpp +++ b/src/navigation/FlightRoute_GPX.cpp @@ -106,7 +106,7 @@ auto Navigation::FlightRoute::gpxElements(const QString& indent, const QString& // waypoints // - for(const auto& _waypoint : m_waypoints) { + for(const auto& _waypoint : m_waypoints.value()) { if (!_waypoint.isValid()) { continue; // skip silently diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index f7262c8ec..e6619f306 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -71,24 +71,16 @@ void NOTAM::NotamProvider::deferredInitialization() m_notamLists.setValue(newNotamLists); clean(); - // Setup Status - auto* statusTimer = new QTimer(this); - connect(statusTimer, &QTimer::timeout, this, &NOTAM::NotamProvider::updateStatus); - statusTimer->start(5min+1s); - connect(this, &NOTAM::NotamProvider::dataChanged, this, &NOTAM::NotamProvider::updateStatus); - connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateStatus); - // Set variables initially QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateData); - QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateStatus); // Setup Bindings m_geoJSON.setBinding([this]() {return this->computeGeoJSON();}); m_lastUpdate.setBinding([this]() {return this->computeLastUpdate();}); + m_status.setBinding([this]() {return this->computeStatus();}); // Setup Notifiers - // - // Save the NOTAM data every time that the database changes + // -- Save the NOTAM data every time that the database changes m_saveNotifier = m_notamLists.addNotifier([this]() {this->save();}); } @@ -272,6 +264,61 @@ QDateTime NOTAM::NotamProvider::computeLastUpdate() } +QString NOTAM::NotamProvider::computeStatus() +{ + qWarning() << "NOTAM::NotamProvider::computeStatus()"; + + auto position = GlobalObject::positionProvider()->approximateLastValidCoordinate(); + + QList positionList; + positionList.append(position); + auto* route = navigator()->flightRoute(); + if (route != nullptr) + { +#warning Not bindable yet + positionList += route->geoPath(); + } + + foreach (auto pos, positionList) + { + if (!pos.isValid()) + { + continue; + } + + bool hasNOTAM = false; + foreach (auto notamList, m_notamLists.value()) + { + if (notamList.isOutdated()) + { + continue; + } + + auto region = notamList.region(); + if (!region.isValid()) + { + continue; + } + auto rangeInM = region.radius() - region.center().distanceTo(pos); + if (rangeInM >= marginRadius.toM()) + { + hasNOTAM = true; + break; + } + } + if (!hasNOTAM) + { + if (position == pos) + { + return tr("NOTAMs not current around own position, requesting update"); + } + return tr("NOTAMs not current around route, requesting update"); + } + } + return {}; +} + + void NOTAM::NotamProvider::clean() { QList newNotamLists; @@ -491,58 +538,3 @@ void NOTAM::NotamProvider::startRequest(const QGeoCoordinate& coordinate) connect(reply, &QNetworkReply::errorOccurred, this, &NOTAM::NotamProvider::downloadFinished); } - -void NOTAM::NotamProvider::updateStatus() -{ - auto position = Positioning::PositionProvider::lastValidCoordinate(); - - QList positionList; - positionList.append(position); - auto* route = navigator()->flightRoute(); - if (route != nullptr) - { - positionList += route->geoPath(); - } - - foreach (auto pos, positionList) - { - if (!pos.isValid()) - { - continue; - } - - bool hasNOTAM = false; - foreach (auto notamList, m_notamLists.value()) - { - if (notamList.isOutdated()) - { - continue; - } - - auto region = notamList.region(); - if (!region.isValid()) - { - continue; - } - auto rangeInM = region.radius() - region.center().distanceTo(pos); - if (rangeInM >= marginRadius.toM()) - { - hasNOTAM = true; - break; - } - } - if (!hasNOTAM) - { - if (position == pos) - { - m_status = tr("NOTAMs not current around own position, requesting update"); - } - else - { - m_status = tr("NOTAMs not current around route, requesting update"); - } - return; - } - } - m_status = QString(); -} diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index e13332b47..d11bfe7ed 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -150,6 +150,7 @@ class NotamProvider : public GlobalObject { // Property bindings QByteArray computeGeoJSON(); QDateTime computeLastUpdate(); + QString computeStatus(); private slots: // Removes outdated and irrelevant data from the database. This slot is called @@ -171,10 +172,6 @@ private slots: // the data. void updateData(); - // Checks if NOTAM data is available for an area of marginRadius around the - // current position and around the current flight route. Update status accordingly. - void updateStatus(); - private: Q_DISABLE_COPY_MOVE(NotamProvider) diff --git a/src/positioning/PositionProvider.cpp b/src/positioning/PositionProvider.cpp index 82a60700c..a130dfd27 100644 --- a/src/positioning/PositionProvider.cpp +++ b/src/positioning/PositionProvider.cpp @@ -33,9 +33,9 @@ Positioning::PositionProvider::PositionProvider(QObject *parent) : PositionInfoS // Restore the last valid coordiante and track QSettings settings; QGeoCoordinate tmp; - tmp.setLatitude(settings.value(QStringLiteral("PositionProvider/lastValidLatitude"), m_lastValidCoordinate.latitude()).toDouble()); - tmp.setLongitude(settings.value(QStringLiteral("PositionProvider/lastValidLongitude"), m_lastValidCoordinate.longitude()).toDouble()); - tmp.setAltitude(settings.value(QStringLiteral("PositionProvider/lastValidAltitude"), m_lastValidCoordinate.altitude()).toDouble()); + tmp.setLatitude(settings.value(QStringLiteral("PositionProvider/lastValidLatitude"), m_lastValidCoordinate.value().latitude()).toDouble()); + tmp.setLongitude(settings.value(QStringLiteral("PositionProvider/lastValidLongitude"), m_lastValidCoordinate.value().longitude()).toDouble()); + tmp.setAltitude(settings.value(QStringLiteral("PositionProvider/lastValidAltitude"), m_lastValidCoordinate.value().altitude()).toDouble()); if ((tmp.type() == QGeoCoordinate::Coordinate2D) || (tmp.type() == QGeoCoordinate::Coordinate3D)) { m_lastValidCoordinate = tmp; } @@ -62,6 +62,17 @@ Positioning::PositionProvider::PositionProvider(QObject *parent) : PositionInfoS // Update properties updateStatusString(); + m_approximateLastValidCoordinate.setBinding([this]() { + if (!m_approximateLastValidCoordinate.value().isValid()) + { + return m_lastValidCoordinate.value(); + } + if (m_approximateLastValidCoordinate.value().distanceTo(m_lastValidCoordinate) > 10000) + { + return m_lastValidCoordinate.value(); + } + return m_approximateLastValidCoordinate.value(); + }); } @@ -189,9 +200,9 @@ void Positioning::PositionProvider::savePositionAndTrack() { // Save the last valid coordinate QSettings settings; - settings.setValue(QStringLiteral("PositionProvider/lastValidLatitude"), m_lastValidCoordinate.latitude()); - settings.setValue(QStringLiteral("PositionProvider/lastValidLongitude"), m_lastValidCoordinate.longitude()); - settings.setValue(QStringLiteral("PositionProvider/lastValidAltitude"), m_lastValidCoordinate.altitude()); + settings.setValue(QStringLiteral("PositionProvider/lastValidLatitude"), m_lastValidCoordinate.value().latitude()); + settings.setValue(QStringLiteral("PositionProvider/lastValidLongitude"), m_lastValidCoordinate.value().longitude()); + settings.setValue(QStringLiteral("PositionProvider/lastValidAltitude"), m_lastValidCoordinate.value().altitude()); // Save the last valid track settings.setValue(QStringLiteral("PositionProvider/lastValidTrack"), m_lastValidTT.toDEG()); diff --git a/src/positioning/PositionProvider.h b/src/positioning/PositionProvider.h index 3ffed1416..087cd7e8b 100644 --- a/src/positioning/PositionProvider.h +++ b/src/positioning/PositionProvider.h @@ -20,6 +20,7 @@ #pragma once +#include #include #include "GlobalObject.h" @@ -67,12 +68,28 @@ class PositionProvider : public PositionInfoSource_Abstract // No default constructor, important for QML singleton explicit PositionProvider() = delete; + /*! \brief Standard destructor */ + ~PositionProvider() override = default; + + // factory function for QML singleton static Positioning::PositionProvider* create(QQmlEngine* /*unused*/, QJSEngine* /*unused*/) { return GlobalObject::positionProvider(); } + + // + // PROPERTIES + // + + /*! \brief Approximate last valid coordinate + * + * This property equals lastValidCoordinate, except that it is updated only every ten + * minutes. + */ + Q_PROPERTY(QGeoCoordinate approximateLastValidCoordinate READ approximateLastValidCoordinate BINDABLE bindableApproximateLastValidCoordinate) + /*! \brief Last valid coordinate reading * * This property holds the last valid coordinate known. At the first @@ -82,12 +99,6 @@ class PositionProvider : public PositionInfoSource_Abstract */ Q_PROPERTY(QGeoCoordinate lastValidCoordinate READ lastValidCoordinate NOTIFY lastValidCoordinateChanged) - /*! \brief Getter function for the property with the same name - * - * @returns Property lastValidCoordinate - */ - static auto lastValidCoordinate() -> QGeoCoordinate; - /*! \brief Last valid true track * * This property holds the last valid true track known. At the first @@ -96,11 +107,34 @@ class PositionProvider : public PositionInfoSource_Abstract */ Q_PROPERTY(Units::Angle lastValidTT READ lastValidTT NOTIFY lastValidTTChanged) + + // + // Getter Methods + // + + /*! \brief Getter function for the property with the same name + * + * @returns Property approximateLastValidCoordinate + */ + Q_REQUIRED_RESULT QGeoCoordinate approximateLastValidCoordinate() const {return {m_approximateLastValidCoordinate};} + Q_REQUIRED_RESULT QBindable bindableApproximateLastValidCoordinate() const {return &m_approximateLastValidCoordinate;} + + /*! \brief Getter function for the property with the same name + * + * @returns Property lastValidCoordinate + */ + static QGeoCoordinate lastValidCoordinate(); + /*! \brief Getter function for the property with the same name * * @returns Property lastValidTrack */ - static auto lastValidTT() -> Units::Angle; + static Units::Angle lastValidTT(); + + + // + // Methods + // /*! \brief startUpdates * @@ -155,7 +189,8 @@ private slots: PositionInfoSource_Satellite satelliteSource; - QGeoCoordinate m_lastValidCoordinate {EDTF_lat, EDTF_lon, EDTF_ele}; + QProperty m_approximateLastValidCoordinate; + QProperty m_lastValidCoordinate {QGeoCoordinate(EDTF_lat, EDTF_lon, EDTF_ele)}; Units::Angle m_lastValidTT {}; }; From d52d834caa0e6de5e93db9cb726ae4fde07f22e8 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Thu, 26 Sep 2024 07:42:33 +0200 Subject: [PATCH 48/64] Uncluttering code --- src/navigation/FlightRoute.cpp | 2 - src/notam/NotamProvider.cpp | 61 ++++++++++------------------ src/notam/NotamProvider.h | 22 +++++----- src/positioning/PositionProvider.cpp | 18 ++++---- src/qml/pages/FlightRouteEditor.qml | 2 +- 5 files changed, 39 insertions(+), 66 deletions(-) diff --git a/src/navigation/FlightRoute.cpp b/src/navigation/FlightRoute.cpp index e0f89adcf..2272fbba6 100644 --- a/src/navigation/FlightRoute.cpp +++ b/src/navigation/FlightRoute.cpp @@ -287,7 +287,6 @@ void Navigation::FlightRoute::insert(const GeoMaps::Waypoint& waypoint) auto Navigation::FlightRoute::lastIndexOf(const GeoMaps::Waypoint& waypoint) const -> qsizetype { - for(auto i=m_waypoints.value().size()-1; i>=0; i--) { auto _waypoint = m_waypoints.value().at(i); @@ -301,7 +300,6 @@ auto Navigation::FlightRoute::lastIndexOf(const GeoMaps::Waypoint& waypoint) con } } return -1; - } auto Navigation::FlightRoute::load(const QString& fileName) -> QString diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index e6619f306..f272deb4e 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -43,17 +43,6 @@ NOTAM::NotamProvider::NotamProvider(QObject* parent) : void NOTAM::NotamProvider::deferredInitialization() { - // Wire up updateData. Check NOTAM database every 10 seconds after start, every 11 minutes, and whenever the flight route changes. - auto* timer = new QTimer(this); - timer->start(11min); - connect(timer, &QTimer::timeout, this, &NOTAM::NotamProvider::updateData); - connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateData); - - // Wire up clean(). Clean the data every 61 minutes. - timer = new QTimer(this); - timer->start(61min); - connect(timer, &QTimer::timeout, this, &NOTAM::NotamProvider::clean); - // Load NOTAM data from file in stdFileName, then clean the data (which potentially triggers save()). QList newNotamLists; auto inputFile = QFile(m_stdFileName); @@ -68,11 +57,20 @@ void NOTAM::NotamProvider::deferredInitialization() inputStream >> newNotamLists; } } - m_notamLists.setValue(newNotamLists); - clean(); + m_notamLists = clean(newNotamLists); - // Set variables initially + // Wire up updateData. Check NOTAM database after start, every 11 minutes, and whenever the flight route changes. QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateData); + auto* timer = new QTimer(this); + timer->start(11min); + connect(timer, &QTimer::timeout, this, &NOTAM::NotamProvider::updateData); + connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateData); + + // Clean the data every hour. + timer = new QTimer(this); + timer->start(59min); + connect(timer, &QTimer::timeout, this, [this]() {m_notamLists = clean(m_notamLists);}); + // Setup Bindings m_geoJSON.setBinding([this]() {return this->computeGeoJSON();}); @@ -267,6 +265,7 @@ QDateTime NOTAM::NotamProvider::computeLastUpdate() QString NOTAM::NotamProvider::computeStatus() { qWarning() << "NOTAM::NotamProvider::computeStatus()"; + return {}; auto position = GlobalObject::positionProvider()->approximateLastValidCoordinate(); @@ -275,7 +274,6 @@ QString NOTAM::NotamProvider::computeStatus() auto* route = navigator()->flightRoute(); if (route != nullptr) { -#warning Not bindable yet positionList += route->geoPath(); } @@ -287,7 +285,7 @@ QString NOTAM::NotamProvider::computeStatus() } bool hasNOTAM = false; - foreach (auto notamList, m_notamLists.value()) + for (const auto& notamList : m_notamLists.value()) { if (notamList.isOutdated()) { @@ -319,19 +317,17 @@ QString NOTAM::NotamProvider::computeStatus() } -void NOTAM::NotamProvider::clean() +QList NOTAM::NotamProvider::clean(const QList& notamLists) { QList newNotamLists; QSet regionsSeen; - bool haveChange = false; // Iterate over notamLists, newest lists first - foreach(auto notamList, m_notamLists.value()) + foreach(auto notamList, notamLists) { // If this notamList is outdated, then so all all further ones. We can thus end here. if (notamList.isOutdated()) { - haveChange = true; break; } @@ -339,32 +335,23 @@ void NOTAM::NotamProvider::clean() // is irrelevant. Skip over this list. if (regionsSeen.contains(notamList.region())) { - haveChange = true; continue; } regionsSeen += notamList.region(); auto cleanedList = notamList.cleaned(m_cancelledNotamNumbers); - if (cleanedList.notams().size() != notamList.notams().size()) - { - haveChange = true; - } newNotamLists.append(cleanedList); } +#warning No good m_cancelledNotamNumbers.clear(); - if (haveChange) - { - m_notamLists = newNotamLists; - emit dataChanged(); - } + return newNotamLists; } void NOTAM::NotamProvider::downloadFinished() { - bool newDataAdded = false; m_networkReplies.removeAll(nullptr); foreach(auto networkReply, m_networkReplies) { @@ -400,14 +387,7 @@ void NOTAM::NotamProvider::downloadFinished() NotamList const notamList(jsonDoc, region, &m_cancelledNotamNumbers); auto newNotamList = m_notamLists.value(); newNotamList.prepend(notamList); - m_notamLists = newNotamList; - newDataAdded = true; - } - - if (newDataAdded) - { - clean(); - emit dataChanged(); + m_notamLists = clean(newNotamList); } } @@ -428,6 +408,7 @@ void NOTAM::NotamProvider::save() const void NOTAM::NotamProvider::updateData() { + qWarning() << "NOTAM::NotamProvider::updateData()"; // Check if Notam data is available for a circle of marginRadius around // the current position. auto position = Positioning::PositionProvider::lastValidCoordinate(); @@ -456,7 +437,6 @@ void NOTAM::NotamProvider::updateData() } } - } @@ -514,6 +494,7 @@ Units::Distance NOTAM::NotamProvider::range(const QGeoCoordinate& position) void NOTAM::NotamProvider::startRequest(const QGeoCoordinate& coordinate) { + qWarning() << "NOTAM::NotamProvider::startRequest" << coordinate; if (!coordinate.isValid()) { return; diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index d11bfe7ed..aa0248283 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -142,10 +142,6 @@ class NotamProvider : public GlobalObject { */ Q_INVOKABLE void setRead(const QString& number, bool read); -signals: - /*! \brief Notifier signal */ - void dataChanged(); - private: // Property bindings QByteArray computeGeoJSON(); @@ -153,19 +149,12 @@ class NotamProvider : public GlobalObject { QString computeStatus(); private slots: - // Removes outdated and irrelevant data from the database. This slot is called - // once per hour. - void clean(); - // This slot is connected to signals QNetworkReply::finished and // QNetworkReply::errorOccurred of the QNetworkReply contained in the list // in m_networkReply. This method reads the incoming data and adds it to the // database void downloadFinished(); - // Save NOTAM data to file whose name is found in m_stdFileName. There are - // no error checks of any kind. - void save() const; // Checks if NOTAM data is available for an area of marginRadius around the // current position and around the current flight route. If not, requests @@ -175,10 +164,19 @@ private slots: private: Q_DISABLE_COPY_MOVE(NotamProvider) + // Removes outdated NOTAMs and outdated NOTAMLists. + QList clean(const QList& notamLists); + + // Save NOTAM data to a file, using the filename found in m_stdFileName. There are + // no error checks of any kind. + void save() const; + + // This propertyNotifier ensures that the method save() is called whenever + // m_notamLists changes. QPropertyNotifier m_saveNotifier; // Compute the radius of the circle around the waypoint that is covered by - // existing or requested notam data. Returns Units::Distance::fromM(-1) if + // existing or requested NOTAM data. Returns Units::Distance::fromM(-1) if // the waypoint is not covered by data. Units::Distance range(const QGeoCoordinate& position); diff --git a/src/positioning/PositionProvider.cpp b/src/positioning/PositionProvider.cpp index a130dfd27..f0fa76f30 100644 --- a/src/positioning/PositionProvider.cpp +++ b/src/positioning/PositionProvider.cpp @@ -31,7 +31,7 @@ Positioning::PositionProvider::PositionProvider(QObject *parent) : PositionInfoSource_Abstract(parent) { // Restore the last valid coordiante and track - QSettings settings; + QSettings const settings; QGeoCoordinate tmp; tmp.setLatitude(settings.value(QStringLiteral("PositionProvider/lastValidLatitude"), m_lastValidCoordinate.value().latitude()).toDouble()); tmp.setLongitude(settings.value(QStringLiteral("PositionProvider/lastValidLongitude"), m_lastValidCoordinate.value().longitude()).toDouble()); @@ -62,16 +62,14 @@ Positioning::PositionProvider::PositionProvider(QObject *parent) : PositionInfoS // Update properties updateStatusString(); - m_approximateLastValidCoordinate.setBinding([this]() { - if (!m_approximateLastValidCoordinate.value().isValid()) - { - return m_lastValidCoordinate.value(); - } - if (m_approximateLastValidCoordinate.value().distanceTo(m_lastValidCoordinate) > 10000) + 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_lastValidCoordinate.value(); + return; } - return m_approximateLastValidCoordinate.value(); + m_approximateLastValidCoordinate = m_lastValidCoordinate.value(); }); } @@ -79,10 +77,8 @@ Positioning::PositionProvider::PositionProvider(QObject *parent) : PositionInfoS void Positioning::PositionProvider::deferredInitialization() const { - connect(GlobalObject::trafficDataProvider(), &Traffic::TrafficDataProvider::positionInfoChanged, this, &PositionProvider::onPositionUpdated); connect(GlobalObject::trafficDataProvider(), &Traffic::TrafficDataProvider::pressureAltitudeChanged, this, &PositionProvider::onPressureAltitudeUpdated); - } diff --git a/src/qml/pages/FlightRouteEditor.qml b/src/qml/pages/FlightRouteEditor.qml index 5a352b5f5..936d93669 100644 --- a/src/qml/pages/FlightRouteEditor.qml +++ b/src/qml/pages/FlightRouteEditor.qml @@ -719,7 +719,7 @@ Page { onClicked: { PlatformAdaptor.vibrateBrief() Navigator.flightRoute.append(model.modelData) - close() + flightRouteAddWPDialog.close() } } From 47fe9661828b93071173943b236e94c1d1bf3e9d Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Fri, 27 Sep 2024 08:49:13 +0200 Subject: [PATCH 49/64] Update translations --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 62c164e28..b6a976bfe 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 62c164e28c663811063cf48ffd6a5041e1e65e0d +Subproject commit b6a976bfea8370c038dadbba9f0a61b204df345d From 99234bcb4280333286dcb2480c90a6edab1b07de Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Fri, 27 Sep 2024 16:57:59 +0200 Subject: [PATCH 50/64] Working on cleanup --- src/notam/NotamProvider.cpp | 51 ++++++++----------------------------- src/notam/NotamProvider.h | 5 +--- 2 files changed, 12 insertions(+), 44 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index f272deb4e..c8ec877a0 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -57,7 +57,7 @@ void NOTAM::NotamProvider::deferredInitialization() inputStream >> newNotamLists; } } - m_notamLists = clean(newNotamLists); + m_notamLists = cleaned(newNotamLists); // Wire up updateData. Check NOTAM database after start, every 11 minutes, and whenever the flight route changes. QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateData); @@ -69,7 +69,7 @@ void NOTAM::NotamProvider::deferredInitialization() // Clean the data every hour. timer = new QTimer(this); timer->start(59min); - connect(timer, &QTimer::timeout, this, [this]() {m_notamLists = clean(m_notamLists);}); + connect(timer, &QTimer::timeout, this, [this]() {m_notamLists = cleaned(m_notamLists);}); // Setup Bindings @@ -186,54 +186,25 @@ QByteArray NOTAM::NotamProvider::computeGeoJSON() { QList result; QSet coordinatesSeen; - QSet regionsCovered; -#warning can simplify! foreach(auto notamList, m_notamLists.value()) { - foreach(auto notam, notamList.notams()) + for(const auto& notam : notamList.notams()) { - if (!notam.isValid() || notam.isOutdated()) - { - continue; - } auto coordinate = notam.coordinate(); if (!coordinate.isValid()) { continue; } - if (!notamList.region().contains(coordinate)) - { - continue; - } // If we already have a waypoint for that coordinate, then don't add another one. if (coordinatesSeen.contains(coordinate)) { continue; } - - // If the coordinate has already been handled by an earlier (=newer) notamList, - // then don't add it here. - bool hasBeenCovered = false; - foreach(auto region, regionsCovered) - { - if (region.contains(coordinate)) - { - hasBeenCovered = true; - break; - } - } - if (hasBeenCovered) - { - continue; - } - coordinatesSeen += coordinate; result.append(notam.GeoJSON()); } - - regionsCovered += notamList.region(); } QJsonArray waypointArray; @@ -317,7 +288,7 @@ QString NOTAM::NotamProvider::computeStatus() } -QList NOTAM::NotamProvider::clean(const QList& notamLists) +QList NOTAM::NotamProvider::cleaned(const QList& notamLists, const QSet& cancelledNotams) { QList newNotamLists; QSet regionsSeen; @@ -340,11 +311,9 @@ QList NOTAM::NotamProvider::clean(const QList NOTAM::NotamProvider::clean(const QList cancelledNotams; + m_networkReplies.removeAll(nullptr); foreach(auto networkReply, m_networkReplies) { @@ -370,6 +342,7 @@ void NOTAM::NotamProvider::downloadFinished() } if (networkReply->error() != QNetworkReply::NoError) { +#warning Error! Try again in 5 minutes! networkReply->deleteLater(); continue; } @@ -383,12 +356,10 @@ void NOTAM::NotamProvider::downloadFinished() { continue; } -#warning not optimal, causes too many changes - NotamList const notamList(jsonDoc, region, &m_cancelledNotamNumbers); - auto newNotamList = m_notamLists.value(); + NotamList const notamList(jsonDoc, region, &cancelledNotams); newNotamList.prepend(notamList); - m_notamLists = clean(newNotamList); } + m_notamLists = cleaned(newNotamList, cancelledNotams); } diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index aa0248283..8baf50f7f 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -165,7 +165,7 @@ private slots: Q_DISABLE_COPY_MOVE(NotamProvider) // Removes outdated NOTAMs and outdated NOTAMLists. - QList clean(const QList& notamLists); + static QList cleaned(const QList& notamLists, const QSet& cancelledNotams = {}); // Save NOTAM data to a file, using the filename found in m_stdFileName. There are // no error checks of any kind. @@ -187,9 +187,6 @@ private slots: // List with numbers of notams that have been marked as read QList m_readNotamNumbers; - // Set with numbers of notams that have been cancelled - QSet m_cancelledNotamNumbers; - // List of pending network requests QList> m_networkReplies; From 31e244d0bf9c18fffe2feb43f53e7214984f1dab Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Fri, 27 Sep 2024 21:40:27 +0200 Subject: [PATCH 51/64] Cleanup --- src/notam/NotamProvider.cpp | 15 ++++++++------- src/notam/NotamProvider.h | 1 + src/positioning/PositionProvider.h | 5 ++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index c8ec877a0..6dcde1703 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -59,17 +59,18 @@ void NOTAM::NotamProvider::deferredInitialization() } m_notamLists = cleaned(newNotamLists); - // Wire up updateData. Check NOTAM database after start, every 11 minutes, and whenever the flight route changes. + // Wire up updateData. Check NOTAM database after start, and whenever the flight route changes. QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateData); - auto* timer = new QTimer(this); - timer->start(11min); - connect(timer, &QTimer::timeout, this, &NOTAM::NotamProvider::updateData); connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateData); + connect(GlobalObject::positionProvider(), &Positioning::PositionProvider::approximateLastValidCoordinateChanged, this, &NOTAM::NotamProvider::updateData); - // Clean the data every hour. - timer = new QTimer(this); + // Clean and check the NOTAM database the data every hour. + auto* timer = new QTimer(this); timer->start(59min); - connect(timer, &QTimer::timeout, this, [this]() {m_notamLists = cleaned(m_notamLists);}); + connect(timer, &QTimer::timeout, this, [this]() { + updateData(); + m_notamLists = cleaned(m_notamLists); + }); // Setup Bindings diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index 8baf50f7f..ca6968e2e 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -160,6 +160,7 @@ private slots: // current position and around the current flight route. If not, requests // the data. void updateData(); + //QPropertyNotifier m_updateDataNotifier; private: Q_DISABLE_COPY_MOVE(NotamProvider) diff --git a/src/positioning/PositionProvider.h b/src/positioning/PositionProvider.h index 087cd7e8b..3cf72d4dc 100644 --- a/src/positioning/PositionProvider.h +++ b/src/positioning/PositionProvider.h @@ -145,6 +145,9 @@ class PositionProvider : public PositionInfoSource_Abstract Q_INVOKABLE void startUpdates() { satelliteSource.startUpdates(); } signals: + /*! \brief Notifier signal */ + void approximateLastValidCoordinateChanged(); + /*! \brief Notifier signal */ void lastValidTTChanged(Units::Angle); @@ -189,7 +192,7 @@ private slots: PositionInfoSource_Satellite satelliteSource; - QProperty m_approximateLastValidCoordinate; + Q_OBJECT_BINDABLE_PROPERTY(PositionProvider, QGeoCoordinate, m_approximateLastValidCoordinate, &Positioning::PositionProvider::approximateLastValidCoordinateChanged) QProperty m_lastValidCoordinate {QGeoCoordinate(EDTF_lat, EDTF_lon, EDTF_ele)}; Units::Angle m_lastValidTT {}; }; From f65c0e5808a560b3da332ca61ffc014e908c5355 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 07:45:55 +0200 Subject: [PATCH 52/64] Cleanup --- src/notam/NotamProvider.cpp | 40 ++++++++++++++++++------------------- src/notam/NotamProvider.h | 22 ++++++++++---------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NotamProvider.cpp index 6dcde1703..df957c17d 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NotamProvider.cpp @@ -80,13 +80,13 @@ void NOTAM::NotamProvider::deferredInitialization() // Setup Notifiers // -- Save the NOTAM data every time that the database changes - m_saveNotifier = m_notamLists.addNotifier([this]() {this->save();}); + m_saveNotifier = m_notamLists.addNotifier([this]() {save();}); } NOTAM::NotamProvider::~NotamProvider() { - foreach(auto networkReply, m_networkReplies) + for(const auto& networkReply : m_networkReplies) { if (networkReply.isNull()) { @@ -113,7 +113,7 @@ NOTAM::NotamList NOTAM::NotamProvider::notams(const GeoMaps::Waypoint& waypoint) // Check if notams for the location are present in our database. // Go through the database, oldest to newest. - foreach (auto notamList, m_notamLists.value()) + for(const auto& notamList : m_notamLists.value()) { // Disregard outdated notamLists if (notamList.isOutdated()) @@ -128,20 +128,20 @@ NOTAM::NotamList NOTAM::NotamProvider::notams(const GeoMaps::Waypoint& waypoint) { startRequest(waypoint.coordinate()); } - return notamList.restricted(waypoint); } } // Check if internet requests notams for the location are pending. // In that case, return an empty list. - foreach(auto networkReply, m_networkReplies) + for(const auto& networkReply : m_networkReplies) { // Paranoid safety checks if (networkReply.isNull()) { continue; } +#warning What about failed replies? auto area = networkReply->property("area").value(); if (!area.isValid()) { @@ -183,12 +183,12 @@ void NOTAM::NotamProvider::setRead(const QString& number, bool read) // Private Slots // -QByteArray NOTAM::NotamProvider::computeGeoJSON() +QByteArray NOTAM::NotamProvider::computeGeoJSON() const { QList result; QSet coordinatesSeen; - foreach(auto notamList, m_notamLists.value()) + for(const auto& notamList : m_notamLists.value()) { for(const auto& notam : notamList.notams()) { @@ -209,7 +209,7 @@ QByteArray NOTAM::NotamProvider::computeGeoJSON() } QJsonArray waypointArray; - foreach (const auto& jsonObject, result) + for(const auto& jsonObject : result) { waypointArray.append(jsonObject); } @@ -223,7 +223,7 @@ QByteArray NOTAM::NotamProvider::computeGeoJSON() } -QDateTime NOTAM::NotamProvider::computeLastUpdate() +QDateTime NOTAM::NotamProvider::computeLastUpdate() const { auto notamLists = m_notamLists.value(); if (notamLists.isEmpty()) @@ -234,11 +234,8 @@ QDateTime NOTAM::NotamProvider::computeLastUpdate() } -QString NOTAM::NotamProvider::computeStatus() +QString NOTAM::NotamProvider::computeStatus() const { - qWarning() << "NOTAM::NotamProvider::computeStatus()"; - return {}; - auto position = GlobalObject::positionProvider()->approximateLastValidCoordinate(); QList positionList; @@ -249,7 +246,7 @@ QString NOTAM::NotamProvider::computeStatus() positionList += route->geoPath(); } - foreach (auto pos, positionList) + for(const auto& pos : positionList) { if (!pos.isValid()) { @@ -295,7 +292,7 @@ QList NOTAM::NotamProvider::cleaned(const QList regionsSeen; // Iterate over notamLists, newest lists first - foreach(auto notamList, notamLists) + for(const auto& notamList : notamLists) { // If this notamList is outdated, then so all all further ones. We can thus end here. if (notamList.isOutdated()) @@ -326,7 +323,7 @@ void NOTAM::NotamProvider::downloadFinished() QSet cancelledNotams; m_networkReplies.removeAll(nullptr); - foreach(auto networkReply, m_networkReplies) + for(const auto& networkReply : m_networkReplies) { // Paranoid safety checks if (networkReply.isNull()) @@ -343,7 +340,8 @@ void NOTAM::NotamProvider::downloadFinished() } if (networkReply->error() != QNetworkReply::NoError) { -#warning Error! Try again in 5 minutes! + // Network error? Then try again in 5 minutes. + QTimer::singleShot(5min, this, &NOTAM::NotamProvider::updateData); networkReply->deleteLater(); continue; } @@ -366,7 +364,6 @@ void NOTAM::NotamProvider::downloadFinished() void NOTAM::NotamProvider::save() const { - qWarning() << "NOTAM::NotamProvider::save()"; auto outputFile = QFile(m_stdFileName); if (outputFile.open(QIODevice::WriteOnly)) { @@ -396,7 +393,7 @@ void NOTAM::NotamProvider::updateData() auto* route = navigator()->flightRoute(); if (route != nullptr) { - foreach(auto pos, route->geoPath()) + for(const auto& pos : route->geoPath()) { if (pos.isValid()) { @@ -428,7 +425,7 @@ Units::Distance NOTAM::NotamProvider::range(const QGeoCoordinate& position) // If we have a NOTAM list that contains the position // within half its radius, then stop. - foreach (auto notamList, m_notamLists.value()) + for(const auto& notamList : m_notamLists.value()) { if (notamList.isOutdated()) { @@ -444,13 +441,14 @@ Units::Distance NOTAM::NotamProvider::range(const QGeoCoordinate& position) result = qMax(result, Units::Distance::fromM(rangeInM)); } - foreach(auto networkReply, m_networkReplies) + for(auto& networkReply : m_networkReplies) { // Paranoid safety checks if (networkReply.isNull()) { continue; } +#warning what about failed replies?! auto region = networkReply->property("area").value(); if (!region.isValid()) { diff --git a/src/notam/NotamProvider.h b/src/notam/NotamProvider.h index ca6968e2e..0216ff601 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NotamProvider.h @@ -85,22 +85,22 @@ class NotamProvider : public GlobalObject { * * @returns Property GeoJSON */ - Q_REQUIRED_RESULT QByteArray geoJSON() const {return {m_geoJSON};} - Q_REQUIRED_RESULT QBindable bindableGeoJSON() {return &m_geoJSON;} + Q_REQUIRED_RESULT QByteArray geoJSON() const {return m_geoJSON.value();} + Q_REQUIRED_RESULT QBindable bindableGeoJSON() const {return &m_geoJSON;} /*! \brief Getter function for the property with the same name * * @returns Property lastUpdate */ Q_REQUIRED_RESULT QDateTime lastUpdate() const {return {m_lastUpdate};} - Q_REQUIRED_RESULT QBindable bindableLastUpdate() {return &m_lastUpdate;} + Q_REQUIRED_RESULT QBindable bindableLastUpdate() const {return &m_lastUpdate;} /*! \brief Getter function for the property with the same name * * @returns Property status */ Q_REQUIRED_RESULT QString status() const {return {m_status};} - Q_REQUIRED_RESULT QBindable bindableStatus() {return &m_status;} + Q_REQUIRED_RESULT QBindable bindableStatus() const {return &m_status;} // @@ -116,7 +116,7 @@ class NotamProvider : public GlobalObject { * The returned list is empty and has an invalid property "retrieved" if * the NotamProvider has no data. * - * Calling this method might trigger an update of the Notam database. + * Calling this method might trigger an update of the NOTAM database. * Consumers can watch the property lastUpdate to learn about database * updates. * @@ -132,7 +132,7 @@ class NotamProvider : public GlobalObject { * * @returns True is notam is known as read */ - [[nodiscard]] Q_INVOKABLE bool isRead(const QString& number) { return m_readNotamNumbers.contains(number); } + [[nodiscard]] Q_INVOKABLE bool isRead(const QString& number) const { return m_readNotamNumbers.contains(number); } /*! \brief Register NOTAM number as read or unread * @@ -144,9 +144,9 @@ class NotamProvider : public GlobalObject { private: // Property bindings - QByteArray computeGeoJSON(); - QDateTime computeLastUpdate(); - QString computeStatus(); + QByteArray computeGeoJSON() const; + QDateTime computeLastUpdate() const; + QString computeStatus() const; private slots: // This slot is connected to signals QNetworkReply::finished and @@ -155,12 +155,10 @@ private slots: // database void downloadFinished(); - // Checks if NOTAM data is available for an area of marginRadius around the // current position and around the current flight route. If not, requests // the data. void updateData(); - //QPropertyNotifier m_updateDataNotifier; private: Q_DISABLE_COPY_MOVE(NotamProvider) @@ -191,7 +189,7 @@ private slots: // List of pending network requests QList> m_networkReplies; - // List of NotamLists, sorted so that newest lists come first + // List of NOTAMLists, sorted so that newest lists come first QProperty> m_notamLists; // GeoJSON, for use in map From 29d5c535ad8869ed6fac8a3d7f4fb3655f4b9020 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 12:32:24 +0200 Subject: [PATCH 53/64] Rename files --- src/CMakeLists.txt | 12 +- src/GlobalObject.cpp | 8 +- src/GlobalObject.h | 4 +- src/notam/{Notam.cpp => NOTAM.cpp} | 20 +-- src/notam/{Notam.h => NOTAM.h} | 32 ++-- src/notam/{NotamList.cpp => NOTAMList.cpp} | 26 +-- src/notam/{NotamList.h => NOTAMList.h} | 40 ++--- .../{NotamProvider.cpp => NOTAMProvider.cpp} | 169 ++++++++---------- .../{NotamProvider.h => NOTAMProvider.h} | 95 ++++++---- src/platform/PlatformAdaptor_Abstract.cpp | 2 +- 10 files changed, 207 insertions(+), 201 deletions(-) rename src/notam/{Notam.cpp => NOTAM.cpp} (96%) rename src/notam/{Notam.h => NOTAM.h} (91%) rename src/notam/{NotamList.cpp => NOTAMList.cpp} (89%) rename src/notam/{NotamList.h => NOTAMList.h} (83%) rename src/notam/{NotamProvider.cpp => NOTAMProvider.cpp} (74%) rename src/notam/{NotamProvider.h => NOTAMProvider.h} (65%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aa8f6f9e9..e531d7dae 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,9 +69,9 @@ set(SOURCES navigation/Leg.h navigation/Navigator.h navigation/RemainingRouteInfo.h - notam/Notam.h - notam/NotamList.h - notam/NotamProvider.h + notam/NOTAM.h + notam/NOTAMList.h + notam/NOTAMProvider.h notification/Notification.h notification/Notification_DataUpdateAvailable.h notification/NotificationManager.h @@ -163,9 +163,9 @@ set(SOURCES navigation/Leg.cpp navigation/Navigator.cpp navigation/RemainingRouteInfo.cpp - notam/Notam.cpp - notam/NotamList.cpp - notam/NotamProvider.cpp + notam/NOTAM.cpp + notam/NOTAMList.cpp + notam/NOTAMProvider.cpp notification/Notification.cpp notification/Notification_DataUpdateAvailable.cpp notification/NotificationManager.cpp diff --git a/src/GlobalObject.cpp b/src/GlobalObject.cpp index b918950fa..29211d41b 100644 --- a/src/GlobalObject.cpp +++ b/src/GlobalObject.cpp @@ -33,7 +33,7 @@ #include "geomaps/WaypointLibrary.h" #include "navigation/Clock.h" #include "navigation/Navigator.h" -#include "notam/NotamProvider.h" +#include "notam/NOTAMProvider.h" #include "notification/NotificationManager.h" #include "platform/FileExchange.h" #include "platform/PlatformAdaptor.h" @@ -56,7 +56,7 @@ QPointer g_geoMapProvider {}; QPointer g_librarian {}; QPointer g_platformAdaptor {}; QPointer g_navigator {}; -QPointer g_notamProvider {}; +QPointer g_notamProvider {}; QPointer g_networkAccessManager {}; QPointer g_notificationManager {}; QPointer g_passwordDB {}; @@ -203,9 +203,9 @@ auto GlobalObject::networkAccessManager() -> QNetworkAccessManager* } -auto GlobalObject::notamProvider() -> NOTAM::NotamProvider* +auto GlobalObject::notamProvider() -> NOTAM::NOTAMProvider* { - return allocateInternal(g_notamProvider); + return allocateInternal(g_notamProvider); } diff --git a/src/GlobalObject.h b/src/GlobalObject.h index eb5e24932..5407f4a4b 100644 --- a/src/GlobalObject.h +++ b/src/GlobalObject.h @@ -48,7 +48,7 @@ class Navigator; namespace NOTAM { -class NotamProvider; +class NOTAMProvider; } // namespace NOTAM namespace Notifications @@ -221,7 +221,7 @@ class GlobalObject : public QObject * * @returns Pointer to appplication-wide static instance. */ - Q_INVOKABLE static NOTAM::NotamProvider* notamProvider(); + Q_INVOKABLE static NOTAM::NOTAMProvider* notamProvider(); /*! \brief Pointer to appplication-wide static notification manager instance * diff --git a/src/notam/Notam.cpp b/src/notam/NOTAM.cpp similarity index 96% rename from src/notam/Notam.cpp rename to src/notam/NOTAM.cpp index 39deaa30b..e9ec800d1 100644 --- a/src/notam/Notam.cpp +++ b/src/notam/NOTAM.cpp @@ -23,8 +23,8 @@ #include "GlobalObject.h" #include "GlobalSettings.h" -#include "notam/Notam.h" -#include "notam/NotamProvider.h" +#include "notam/NOTAM.h" +#include "notam/NOTAMProvider.h" // Static objects @@ -110,7 +110,7 @@ Q_GLOBAL_STATIC(ContractionList, // Constructor/Destructor // -NOTAM::Notam::Notam(const QJsonObject& jsonObject) +NOTAM::NOTAM::NOTAM(const QJsonObject& jsonObject) { auto notamObject = jsonObject[u"properties"_qs][u"coreNOTAMData"_qs][u"notam"_qs].toObject(); @@ -142,7 +142,7 @@ NOTAM::Notam::Notam(const QJsonObject& jsonObject) // Getter Methods // -QString NOTAM::Notam::cancels() const +QString NOTAM::NOTAM::cancels() const { if (!m_text.contains(*cancelNotamStart)) { @@ -152,7 +152,7 @@ QString NOTAM::Notam::cancels() const } -QJsonObject NOTAM::Notam::GeoJSON() const +QJsonObject NOTAM::NOTAM::GeoJSON() const { QMap m_properties; m_properties[u"CAT"_qs] = u"NOTAM"_qs; @@ -173,7 +173,7 @@ QJsonObject NOTAM::Notam::GeoJSON() const } -bool NOTAM::Notam::isValid() const +bool NOTAM::NOTAM::isValid() const { if (!m_coordinate.isValid()) { @@ -196,7 +196,7 @@ bool NOTAM::Notam::isValid() const // Methods // -QString NOTAM::Notam::richText() const +QString NOTAM::NOTAM::richText() const { QStringList result; @@ -278,7 +278,7 @@ QString NOTAM::Notam::richText() const } -void NOTAM::Notam::updateSectionTitle() +void NOTAM::NOTAM::updateSectionTitle() { if (GlobalObject::notamProvider()->isRead(m_number)) { @@ -362,7 +362,7 @@ QGeoCoordinate NOTAM::interpretNOTAMCoordinates(const QString& string) } -QDataStream& NOTAM::operator<<(QDataStream& stream, const NOTAM::Notam& notam) +QDataStream& NOTAM::operator<<(QDataStream& stream, const NOTAM& notam) { stream << notam.m_affectedFIR; stream << notam.m_coordinate; @@ -385,7 +385,7 @@ QDataStream& NOTAM::operator<<(QDataStream& stream, const NOTAM::Notam& notam) } -QDataStream& NOTAM::operator>>(QDataStream& stream, NOTAM::Notam& notam) +QDataStream& NOTAM::operator>>(QDataStream& stream, NOTAM& notam) { stream >> notam.m_affectedFIR; stream >> notam.m_coordinate; diff --git a/src/notam/Notam.h b/src/notam/NOTAM.h similarity index 91% rename from src/notam/Notam.h rename to src/notam/NOTAM.h index 492602c9f..653a12a2e 100644 --- a/src/notam/Notam.h +++ b/src/notam/NOTAM.h @@ -30,22 +30,22 @@ namespace NOTAM { /*! \brief This extremely simple class holds a the data item of a NOTAM */ -class Notam { +class NOTAM { Q_GADGET QML_VALUE_TYPE(notam) - friend QDataStream& operator<<(QDataStream& stream, const NOTAM::Notam ¬am); - friend QDataStream& operator>>(QDataStream& stream, NOTAM::Notam& notam); + friend QDataStream& operator<<(QDataStream& stream, const NOTAM& notam); + friend QDataStream& operator>>(QDataStream& stream, NOTAM& notam); public: - /*! \brief Constructs an invalid Notam */ - Notam() = default; + /*! \brief Constructs an invalid NOTAM */ + NOTAM() = default; - /*! \brief Constructs a Notam from GeoJSON data, as provided by the FAA + /*! \brief Constructs a NOTAM from GeoJSON data, as provided by the FAA * * @param jsonObject JSON object, as provided by the FAA */ - explicit Notam(const QJsonObject& jsonObject); + explicit NOTAM(const QJsonObject& jsonObject); // @@ -68,7 +68,7 @@ class Notam { /*! \brief Effective end of the NOTAM, if date is given * - * If the effectiveEnd field of the Notam specified a precise date/time, + * If the effectiveEnd field of the NOTAM specified a precise date/time, * then this time is found here. If not, the property contains an invalid * QDateTime. */ @@ -76,7 +76,7 @@ class Notam { /*! \brief Effective start of the NOTAM, if date is given * - * If the effectiveStart field of the Notam specified a precise date/time, + * If the effectiveStart field of the NOTAM specified a precise date/time, * then this time is found here. If not, the property contains an invalid * QDateTime. */ @@ -191,7 +191,7 @@ class Notam { * * @returns True on equality. */ - Q_REQUIRED_RESULT [[nodiscard]] Q_INVOKABLE bool operator==(const NOTAM::Notam& rhs) const = default; + Q_REQUIRED_RESULT [[nodiscard]] Q_INVOKABLE bool operator==(const NOTAM& rhs) const = default; /*! \brief Check if effectiveEnd is valid and earlier than currentTime * @@ -202,10 +202,10 @@ class Notam { return m_effectiveEnd.isValid() && (m_effectiveEnd < QDateTime::currentDateTimeUtc()); } - /*! \brief Rich text description of the Notam + /*! \brief Rich text description of the NOTAM * * The description and changes with time (e.g. when passing the effective start - * date of the Notam. + * date of the NOTAM. * * @return HTML string */ @@ -220,7 +220,7 @@ class Notam { void updateSectionTitle(); private: - /* Notam members, as described by the FAA */ + /* NOTAM members, as described by the FAA */ QString m_affectedFIR; QGeoCoordinate m_coordinate; QString m_effectiveEndString; @@ -268,15 +268,15 @@ QGeoCoordinate interpretNOTAMCoordinates(const QString& string); * * There is no checks for errors of any kind. */ -QDataStream& operator<<(QDataStream& stream, const NOTAM::Notam ¬am); +QDataStream& operator<<(QDataStream& stream, const NOTAM& notam); /*! \brief Deserialization * * There is no checks for errors of any kind. */ -QDataStream& operator>>(QDataStream& stream, NOTAM::Notam& notam); +QDataStream& operator>>(QDataStream& stream, NOTAM& notam); } // namespace NOTAM // Declare meta types -Q_DECLARE_METATYPE(NOTAM::Notam) +Q_DECLARE_METATYPE(NOTAM::NOTAM) diff --git a/src/notam/NotamList.cpp b/src/notam/NOTAMList.cpp similarity index 89% rename from src/notam/NotamList.cpp rename to src/notam/NOTAMList.cpp index c4b83ab5d..230a228e7 100644 --- a/src/notam/NotamList.cpp +++ b/src/notam/NOTAMList.cpp @@ -22,11 +22,11 @@ #include #include -#include "notam/NotamList.h" -#include "notam/NotamProvider.h" +#include "notam/NOTAMList.h" +#include "notam/NOTAMProvider.h" -NOTAM::NotamList::NotamList(const QJsonDocument& jsonDoc, const QGeoCircle& region, QSet* cancelledNotamNumbers) +NOTAM::NOTAMList::NOTAMList(const QJsonDocument& jsonDoc, const QGeoCircle& region, QSet* cancelledNotamNumbers) { QSet numbersSeen; @@ -34,7 +34,7 @@ NOTAM::NotamList::NotamList(const QJsonDocument& jsonDoc, const QGeoCircle& regi foreach(auto item, items) { - Notam const notam(item.toObject()); + NOTAM const notam(item.toObject()); // Ignore invalid notams if (!notam.isValid()) @@ -83,7 +83,7 @@ NOTAM::NotamList::NotamList(const QJsonDocument& jsonDoc, const QGeoCircle& regi // Getter Methods // -QString NOTAM::NotamList::summary() const +QString NOTAM::NOTAMList::summary() const { QStringList results; @@ -110,7 +110,7 @@ QString NOTAM::NotamList::summary() const // Methods // -Units::Timespan NOTAM::NotamList::age() const +Units::Timespan NOTAM::NOTAMList::age() const { if (!m_retrieved.isValid()) { @@ -121,9 +121,9 @@ Units::Timespan NOTAM::NotamList::age() const } -NOTAM::NotamList NOTAM::NotamList::cleaned(const QSet& cancelledNotamNumbers) const +NOTAM::NOTAMList NOTAM::NOTAMList::cleaned(const QSet& cancelledNotamNumbers) const { - NotamList result; + NOTAMList result; result.m_region = m_region; result.m_retrieved = m_retrieved; @@ -152,9 +152,9 @@ NOTAM::NotamList NOTAM::NotamList::cleaned(const QSet& cancelledNotamNu } -NOTAM::NotamList NOTAM::NotamList::restricted(const GeoMaps::Waypoint& waypoint) const +NOTAM::NOTAMList NOTAM::NOTAMList::restricted(const GeoMaps::Waypoint& waypoint) const { - NotamList result; + NOTAMList result; result.m_retrieved = m_retrieved; auto radius = qMin(restrictionRadius.toM(), qMax(0.0, m_region.radius() - m_region.center().distanceTo(waypoint.coordinate()))); @@ -187,7 +187,7 @@ NOTAM::NotamList NOTAM::NotamList::restricted(const GeoMaps::Waypoint& waypoint) } std::sort(result.m_notams.begin(), result.m_notams.end(), - [](const Notam& first, const Notam& second) + [](const NOTAM& first, const NOTAM& second) { auto aRead = GlobalObject::notamProvider()->isRead(first.number()); auto bRead = GlobalObject::notamProvider()->isRead(second.number()); @@ -216,7 +216,7 @@ NOTAM::NotamList NOTAM::NotamList::restricted(const GeoMaps::Waypoint& waypoint) // Non-Member Methods // -QDataStream& NOTAM::operator<<(QDataStream& stream, const NOTAM::NotamList& notamList) +QDataStream& NOTAM::operator<<(QDataStream& stream, const NOTAMList& notamList) { stream << notamList.m_notams; stream << notamList.m_region; @@ -226,7 +226,7 @@ QDataStream& NOTAM::operator<<(QDataStream& stream, const NOTAM::NotamList& nota } -QDataStream& NOTAM::operator>>(QDataStream& stream, NOTAM::NotamList& notamList) +QDataStream& NOTAM::operator>>(QDataStream& stream, NOTAMList& notamList) { stream >> notamList.m_notams; stream >> notamList.m_region; diff --git a/src/notam/NotamList.h b/src/notam/NOTAMList.h similarity index 83% rename from src/notam/NotamList.h rename to src/notam/NOTAMList.h index ed5fe1fa6..4314b414c 100644 --- a/src/notam/NotamList.h +++ b/src/notam/NOTAMList.h @@ -23,7 +23,7 @@ #include #include "geomaps/Waypoint.h" -#include "notam/Notam.h" +#include "notam/NOTAM.h" #include "units/Timespan.h" namespace NOTAM { @@ -36,22 +36,22 @@ namespace NOTAM { * and the region in the member m_region. */ -class NotamList { +class NOTAMList { Q_GADGET QML_VALUE_TYPE(notamList) - friend QDataStream& operator<<(QDataStream& stream, const NOTAM::NotamList& notamList); - friend QDataStream& operator>>(QDataStream& stream, NOTAM::NotamList& notamList); + friend QDataStream& operator<<(QDataStream& stream, const NOTAMList& notamList); + friend QDataStream& operator>>(QDataStream& stream, NOTAMList& notamList); public: - /*! \brief Constructs an empty NotamList + /*! \brief Constructs an empty NOTAMList * - * Constructs an empty NotamList with an invalid region and an invalid + * Constructs an empty NOTAMList with an invalid region and an invalid * QDateTime for the property retrieved. */ - NotamList() = default; + NOTAMList() = default; - /*! \brief Constructs a NotamList from FAA GeoJSON data + /*! \brief Constructs a NOTAMList from FAA GeoJSON data * * This constructor sets the member m_retrieved to * QDateTime::currentDateTimeUtc(). Invalid Notams and Cancel Notams will @@ -64,7 +64,7 @@ class NotamList { * @param cancelledNotamNumbers Pointer to a set where numbers of cancelled * Notams are added. The nullptr is allowed. */ - NotamList(const QJsonDocument& jsonDoc, const QGeoCircle& region, QSet* cancelledNotamNumbers=nullptr); + NOTAMList(const QJsonDocument& jsonDoc, const QGeoCircle& region, QSet* cancelledNotamNumbers=nullptr); @@ -79,7 +79,7 @@ class NotamList { Q_PROPERTY(bool isValid READ isValid) /*! \brief List of Notams */ - Q_PROPERTY(QList notams READ notams) + Q_PROPERTY(QList notams READ notams) /*! \brief Region covered by this list */ Q_PROPERTY(QGeoCircle region READ region) @@ -112,7 +112,7 @@ class NotamList { * * @returns Property notams */ - Q_REQUIRED_RESULT QList notams() const { return m_notams; } + Q_REQUIRED_RESULT QList notams() const { return m_notams; } /*! \brief Getter function for the property with the same name * @@ -152,11 +152,11 @@ class NotamList { * * @returns Sublist with expired and duplicated entries removed. */ - Q_REQUIRED_RESULT NOTAM::NotamList cleaned(const QSet& cancelledNotamNumbers) const; + Q_REQUIRED_RESULT NOTAMList cleaned(const QSet& cancelledNotamNumbers) const; /*! \brief Check if outdated * - * A NotamList is outdated if its age is invalid or greater than 24h + * A NOTAMList is outdated if its age is invalid or greater than 24h * * @returns True if outdated */ @@ -164,7 +164,7 @@ class NotamList { /*! \brief Check if list needs update * - * A NotamList needs an update if its age is invalid or greater than 12h + * A NOTAMList needs an update if its age is invalid or greater than 12h * * @returns True if outdated */ @@ -174,19 +174,19 @@ class NotamList { * * @param waypoint Waypoint * - * @returns NotamList with all notams centered within restrictionRadius of + * @returns NOTAMList with all notams centered within restrictionRadius of * the given waypoint, without expired and duplicated NOTAMs. Section * titles are set depending on the current time, using * NOTAM::updateSectionTitle(). */ - Q_REQUIRED_RESULT NOTAM::NotamList restricted(const GeoMaps::Waypoint& waypoint) const; + Q_REQUIRED_RESULT NOTAMList restricted(const GeoMaps::Waypoint& waypoint) const; /*! \brief Radius used in the method restricted() */ static constexpr Units::Distance restrictionRadius = Units::Distance::fromNM(20.0); private: /* List of Notams */ - QList m_notams; + QList m_notams; /* Region */ QGeoCircle m_region; @@ -199,16 +199,16 @@ class NotamList { * * There is no checks for errors of any kind. */ -QDataStream& operator<<(QDataStream& stream, const NOTAM::NotamList& notamList); +QDataStream& operator<<(QDataStream& stream, const NOTAMList& notamList); /*! \brief Deserialization * * There is no checks for errors of any kind. */ -QDataStream& operator>>(QDataStream& stream, NOTAM::NotamList& notamList); +QDataStream& operator>>(QDataStream& stream, NOTAMList& notamList); } // namespace NOTAM // Declare meta types -Q_DECLARE_METATYPE(NOTAM::NotamList) +Q_DECLARE_METATYPE(NOTAM::NOTAMList) diff --git a/src/notam/NotamProvider.cpp b/src/notam/NOTAMProvider.cpp similarity index 74% rename from src/notam/NotamProvider.cpp rename to src/notam/NOTAMProvider.cpp index df957c17d..521933c4b 100644 --- a/src/notam/NotamProvider.cpp +++ b/src/notam/NOTAMProvider.cpp @@ -24,7 +24,7 @@ #include #include "navigation/Navigator.h" -#include "notam/NotamProvider.h" +#include "notam/NOTAMProvider.h" #include "positioning/PositionProvider.h" using namespace std::chrono_literals; @@ -35,16 +35,16 @@ using namespace std::chrono_literals; // Constructor/Destructor // -NOTAM::NotamProvider::NotamProvider(QObject* parent) : +NOTAM::NOTAMProvider::NOTAMProvider(QObject* parent) : GlobalObject(parent) { } -void NOTAM::NotamProvider::deferredInitialization() +void NOTAM::NOTAMProvider::deferredInitialization() { // Load NOTAM data from file in stdFileName, then clean the data (which potentially triggers save()). - QList newNotamLists; + QList newNotamLists; auto inputFile = QFile(m_stdFileName); if (inputFile.open(QIODevice::ReadOnly)) { @@ -60,9 +60,9 @@ void NOTAM::NotamProvider::deferredInitialization() m_notamLists = cleaned(newNotamLists); // Wire up updateData. Check NOTAM database after start, and whenever the flight route changes. - QTimer::singleShot(0, this, &NOTAM::NotamProvider::updateData); - connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAM::NotamProvider::updateData); - connect(GlobalObject::positionProvider(), &Positioning::PositionProvider::approximateLastValidCoordinateChanged, this, &NOTAM::NotamProvider::updateData); + QTimer::singleShot(0, this, &NOTAMProvider::updateData); + connect(navigator()->flightRoute(), &Navigation::FlightRoute::waypointsChanged, this, &NOTAMProvider::updateData); + connect(GlobalObject::positionProvider(), &Positioning::PositionProvider::approximateLastValidCoordinateChanged, this, &NOTAMProvider::updateData); // Clean and check the NOTAM database the data every hour. auto* timer = new QTimer(this); @@ -84,7 +84,7 @@ void NOTAM::NotamProvider::deferredInitialization() } -NOTAM::NotamProvider::~NotamProvider() +NOTAM::NOTAMProvider::~NOTAMProvider() { for(const auto& networkReply : m_networkReplies) { @@ -103,8 +103,9 @@ NOTAM::NotamProvider::~NotamProvider() // Methods // -NOTAM::NotamList NOTAM::NotamProvider::notams(const GeoMaps::Waypoint& waypoint) +NOTAM::NOTAMList NOTAM::NOTAMProvider::notams(const GeoMaps::Waypoint& waypoint) { +#warning Simplify! // Paranoid safety checks if (!waypoint.coordinate().isValid()) { @@ -132,7 +133,7 @@ NOTAM::NotamList NOTAM::NotamProvider::notams(const GeoMaps::Waypoint& waypoint) } } - // Check if internet requests notams for the location are pending. + // Check if internet requests NOTAMs for the location are pending. // In that case, return an empty list. for(const auto& networkReply : m_networkReplies) { @@ -141,7 +142,10 @@ NOTAM::NotamList NOTAM::NotamProvider::notams(const GeoMaps::Waypoint& waypoint) { continue; } -#warning What about failed replies? + if (!networkReply->isRunning()) + { + continue; + } auto area = networkReply->property("area").value(); if (!area.isValid()) { @@ -160,7 +164,7 @@ NOTAM::NotamList NOTAM::NotamProvider::notams(const GeoMaps::Waypoint& waypoint) } -void NOTAM::NotamProvider::setRead(const QString& number, bool read) +void NOTAM::NOTAMProvider::setRead(const QString& number, bool read) { if (read) { @@ -183,7 +187,7 @@ void NOTAM::NotamProvider::setRead(const QString& number, bool read) // Private Slots // -QByteArray NOTAM::NotamProvider::computeGeoJSON() const +QByteArray NOTAM::NOTAMProvider::computeGeoJSON() const { QList result; QSet coordinatesSeen; @@ -223,7 +227,7 @@ QByteArray NOTAM::NotamProvider::computeGeoJSON() const } -QDateTime NOTAM::NotamProvider::computeLastUpdate() const +QDateTime NOTAM::NOTAMProvider::computeLastUpdate() const { auto notamLists = m_notamLists.value(); if (notamLists.isEmpty()) @@ -234,7 +238,7 @@ QDateTime NOTAM::NotamProvider::computeLastUpdate() const } -QString NOTAM::NotamProvider::computeStatus() const +QString NOTAM::NOTAMProvider::computeStatus() const { auto position = GlobalObject::positionProvider()->approximateLastValidCoordinate(); @@ -252,43 +256,23 @@ QString NOTAM::NotamProvider::computeStatus() const { continue; } - - bool hasNOTAM = false; - for (const auto& notamList : m_notamLists.value()) + if (covers(pos, true, false)) { - if (notamList.isOutdated()) - { - continue; - } - - auto region = notamList.region(); - if (!region.isValid()) - { - continue; - } - auto rangeInM = region.radius() - region.center().distanceTo(pos); - if (rangeInM >= marginRadius.toM()) - { - hasNOTAM = true; - break; - } + continue; } - if (!hasNOTAM) + if (position == pos) { - if (position == pos) - { - return tr("NOTAMs not current around own position, requesting update"); - } - return tr("NOTAMs not current around route, requesting update"); + return tr("NOTAMs not current around own position, requesting update"); } + return tr("NOTAMs not current around waypoint, requesting update"); } return {}; } -QList NOTAM::NotamProvider::cleaned(const QList& notamLists, const QSet& cancelledNotams) +QList NOTAM::NOTAMProvider::cleaned(const QList& notamLists, const QSet& cancelledNotams) { - QList newNotamLists; + QList newNotamLists; QSet regionsSeen; // Iterate over notamLists, newest lists first @@ -317,7 +301,7 @@ QList NOTAM::NotamProvider::cleaned(const QList cancelledNotams; @@ -341,7 +325,7 @@ void NOTAM::NotamProvider::downloadFinished() if (networkReply->error() != QNetworkReply::NoError) { // Network error? Then try again in 5 minutes. - QTimer::singleShot(5min, this, &NOTAM::NotamProvider::updateData); + QTimer::singleShot(5min, this, &NOTAMProvider::updateData); networkReply->deleteLater(); continue; } @@ -355,14 +339,14 @@ void NOTAM::NotamProvider::downloadFinished() { continue; } - NotamList const notamList(jsonDoc, region, &cancelledNotams); + NOTAMList const notamList(jsonDoc, region, &cancelledNotams); newNotamList.prepend(notamList); } m_notamLists = cleaned(newNotamList, cancelledNotams); } -void NOTAM::NotamProvider::save() const +void NOTAM::NOTAMProvider::save() const { auto outputFile = QFile(m_stdFileName); if (outputFile.open(QIODevice::WriteOnly)) @@ -375,35 +359,17 @@ void NOTAM::NotamProvider::save() const } -void NOTAM::NotamProvider::updateData() +void NOTAM::NOTAMProvider::updateData() { - qWarning() << "NOTAM::NotamProvider::updateData()"; - // Check if Notam data is available for a circle of marginRadius around - // the current position. auto position = Positioning::PositionProvider::lastValidCoordinate(); - if (position.isValid()) - { - auto _range = range(position); - if (_range < marginRadius) - { - startRequest(position); - } - } + startRequest(position); auto* route = navigator()->flightRoute(); if (route != nullptr) { for(const auto& pos : route->geoPath()) { - if (pos.isValid()) - { - auto _range = range(pos); - if (_range < marginRadius) - { - startRequest(pos); - } - } - + startRequest(pos); } } } @@ -414,63 +380,75 @@ void NOTAM::NotamProvider::updateData() // Private Methods // -Units::Distance NOTAM::NotamProvider::range(const QGeoCoordinate& position) +bool NOTAM::NOTAMProvider::covers(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const { - auto result = Units::Distance::fromM(-1.0); - if (!position.isValid()) { - return result; + return true; } - // If we have a NOTAM list that contains the position - // within half its radius, then stop. for(const auto& notamList : m_notamLists.value()) { if (notamList.isOutdated()) { continue; } + if (notamList.needsUpdate() && !includeDataThatNeedsUpdate) + { + continue; + } - auto region = notamList.region(); + const auto region = notamList.region(); if (!region.isValid()) { continue; } - auto rangeInM = region.radius() - region.center().distanceTo(position); - result = qMax(result, Units::Distance::fromM(rangeInM)); + if (region.radius() - region.center().distanceTo(position) >= minimumRadiusPoint.toM()) + { + return true; + } } - for(auto& networkReply : m_networkReplies) + if (includeRunningDownloads) { - // Paranoid safety checks - if (networkReply.isNull()) + for(const auto& networkReply : m_networkReplies) { - continue; - } -#warning what about failed replies?! - auto region = networkReply->property("area").value(); - if (!region.isValid()) - { - continue; + // Paranoid safety checks + if (networkReply.isNull()) + { + continue; + } + if (!networkReply->isRunning()) + { + continue; + } + auto region = networkReply->property("area").value(); + if (region.radius() - region.center().distanceTo(position) >= minimumRadiusPoint.toM()) + { + return true; + } } - auto rangeInM = region.radius() - region.center().distanceTo(position); - result = qMax(result, Units::Distance::fromM(rangeInM)); } - return result; + return false; } -void NOTAM::NotamProvider::startRequest(const QGeoCoordinate& coordinate) +void NOTAM::NOTAMProvider::startRequest(const QGeoCoordinate& coordinate) { - qWarning() << "NOTAM::NotamProvider::startRequest" << coordinate; if (!coordinate.isValid()) { return; } - const QGeoCoordinate coordinateRounded( qRound(coordinate.latitude()), qRound(coordinate.longitude()) ); + // If data exists for marginRadius around that coordinate or if that data is already + // requested for download, then return immediately. + if (covers(coordinate, false, true)) + { + return; + } + + const QGeoCoordinate coordinateRounded( qRound(coordinate.latitude()), qRound(coordinate.longitude()) ); auto urlString = u"https://enroute-data.akaflieg-freiburg.de/enrouteProxy/notam.php?" "locationLongitude=%1&" "locationLatitude=%2&" @@ -478,14 +456,15 @@ void NOTAM::NotamProvider::startRequest(const QGeoCoordinate& coordinate) "pageSize=1000"_qs .arg(coordinateRounded.longitude()) .arg(coordinateRounded.latitude()) - .arg( qRound(1.2*requestRadius.toNM()) ); + .arg( qRound(requestRadius.toNM()) ); QNetworkRequest const request(urlString); auto* reply = GlobalObject::networkAccessManager()->get(request); reply->setProperty("area", QVariant::fromValue(QGeoCircle(coordinateRounded, requestRadius.toM())) ); + connect(reply, &QNetworkReply::finished, this, &NOTAMProvider::downloadFinished); + connect(reply, &QNetworkReply::errorOccurred, this, &NOTAMProvider::downloadFinished); + m_networkReplies.append(reply); - connect(reply, &QNetworkReply::finished, this, &NOTAM::NotamProvider::downloadFinished); - connect(reply, &QNetworkReply::errorOccurred, this, &NOTAM::NotamProvider::downloadFinished); } diff --git a/src/notam/NotamProvider.h b/src/notam/NOTAMProvider.h similarity index 65% rename from src/notam/NotamProvider.h rename to src/notam/NOTAMProvider.h index 0216ff601..184b512d1 100644 --- a/src/notam/NotamProvider.h +++ b/src/notam/NOTAMProvider.h @@ -26,35 +26,51 @@ #include #include "GlobalObject.h" -#include "notam/NotamList.h" +#include "notam/NOTAMList.h" namespace NOTAM { -/*! \brief This extremely simple class holds a the data item of a NOTAM */ - -class NotamProvider : public GlobalObject { +/*! \brief Manage NOTAM data and download NOTAM data from the FAA if required. + * + * This class attempts to ensure that for any given point in time, current NOTAM data + * is provided for circles of radius minimumRadiusPoint around the current position + * and every waypoint in the flightRoute, as well as a region of at least + * minimumRadiusFlightRoute around the flight route. + * + * There is API to access the data, and to request NOTAM data for arbitrary coordinates. + */ + +class NOTAMProvider : public GlobalObject { Q_OBJECT QML_ELEMENT QML_SINGLETON public: - explicit NotamProvider(QObject* parent = nullptr); + explicit NOTAMProvider(QObject* parent = nullptr); // deferred initialization void deferredInitialization() override; // No default constructor, important for QML singleton - explicit NotamProvider() = delete; + explicit NOTAMProvider() = delete; /*! \brief Standard destructor */ - ~NotamProvider() override; + ~NOTAMProvider() override; // factory function for QML singleton - static NOTAM::NotamProvider* create(QQmlEngine* /*unused*/, QJSEngine* /*unused*/) + static NOTAMProvider* create(QQmlEngine* /*unused*/, QJSEngine* /*unused*/) { return GlobalObject::notamProvider(); } + // NOTAM data is considered to cover a given point if the data covers a circle of radius + // minimumRadiusPoint around that point. + static constexpr Units::Distance minimumRadiusPoint = Units::Distance::fromNM(20.0); + + // NOTAM data is considered to cover the flight route if it covers a region of at least + // minimumRadiusFlightRoute around the route + static constexpr Units::Distance minimumRadiusFlightRoute = Units::Distance::fromNM(3.0); + // // Properties @@ -107,6 +123,7 @@ class NotamProvider : public GlobalObject { // Methods // + /*! \brief NOTAMs for a given waypoint * * The returned list is empty and has a valid property "retrieved" if the @@ -124,7 +141,7 @@ class NotamProvider : public GlobalObject { * * @returns List of Notams relevant for the waypoint */ - [[nodiscard]] Q_INVOKABLE NOTAM::NotamList notams(const GeoMaps::Waypoint& waypoint); + [[nodiscard]] Q_INVOKABLE NOTAMList notams(const GeoMaps::Waypoint& waypoint); /*! \brief Check if a NOTAM number is registred as read * @@ -142,12 +159,6 @@ class NotamProvider : public GlobalObject { */ Q_INVOKABLE void setRead(const QString& number, bool read); -private: - // Property bindings - QByteArray computeGeoJSON() const; - QDateTime computeLastUpdate() const; - QString computeStatus() const; - private slots: // This slot is connected to signals QNetworkReply::finished and // QNetworkReply::errorOccurred of the QNetworkReply contained in the list @@ -161,26 +172,35 @@ private slots: void updateData(); private: - Q_DISABLE_COPY_MOVE(NotamProvider) + Q_DISABLE_COPY_MOVE(NOTAMProvider) + + // Property computing functions + [[nodiscard]] QByteArray computeGeoJSON() const; + [[nodiscard]] QDateTime computeLastUpdate() const; + [[nodiscard]] QString computeStatus() const; // Removes outdated NOTAMs and outdated NOTAMLists. - static QList cleaned(const QList& notamLists, const QSet& cancelledNotams = {}); + [[nodiscard]] static QList cleaned(const QList& notamLists, const QSet& cancelledNotams = {}); + + // Check if current NOTAM data exists for a circle of radius minimalRadius around + // position. This method ignores outdated NOTAM data. An invalid position is always + // considered to be covered. + // + // includeDataThatNeedsUpdate: If true, then also count NOTAM lists that need an update as NOTAM data + // + // includeRunningDownloads: If true, then also count running downloads as NOTAM data + [[nodiscard]] bool covers(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const; // Save NOTAM data to a file, using the filename found in m_stdFileName. There are // no error checks of any kind. - void save() const; - - // This propertyNotifier ensures that the method save() is called whenever + // The propertyNotifier ensures that the method save() is called whenever // m_notamLists changes. + void save() const; QPropertyNotifier m_saveNotifier; - // Compute the radius of the circle around the waypoint that is covered by - // existing or requested NOTAM data. Returns Units::Distance::fromM(-1) if - // the waypoint is not covered by data. - Units::Distance range(const QGeoCoordinate& position); - - // Request Notam data from the FAA, for a circle of radius requestRadius - // around the coordinate. + // Request NOTAM data from the FAA, for a circle of radius requestRadius + // around the coordinate. For performance reasons, the request will be ignored + // if existing NOTAM data or ongoing download requests cover the position alreads. void startRequest(const QGeoCoordinate& coordinate); // List with numbers of notams that have been marked as read @@ -190,7 +210,15 @@ private slots: QList> m_networkReplies; // List of NOTAMLists, sorted so that newest lists come first - QProperty> m_notamLists; + QProperty> m_notamLists; + + // This is a list of control points. The computing function guarantees that +// the NOTAM data covers a region of at least marginRadiusFlightRoute around the route if +// the data covers a circle of radius + // marginRadius around every control point point. Exeption: For performance reasons, this guarantee +// is lifted if the flight route contains a leg +// of size > maximumFlightRouteLegLength. + QProperty> m_controlPoints4FlightRoute; // GeoJSON, for use in map QProperty m_geoJSON; @@ -204,14 +232,13 @@ private slots: // Filename for loading/saving NOTAM data QString m_stdFileName { QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+u"/notam.dat"_qs }; - // The method updateDate() ensures that data is requested for marginRadius around - // own position and current flight route. - static constexpr Units::Distance marginRadius = Units::Distance::fromNM(5.0); + // NOTAM data is considered to cover the flight route if it covers a region of at least + // marginRadiusFlightRoute around the route + static constexpr Units::Distance maximumFlightRouteLegLength = Units::Distance::fromNM(200.0); // Requests for Notam data are requestRadius around given position. - // This is the maximum that FAA API currently allows (FAA max is 100NM, but - // the number here is multiplied internally with a factor of 1.2) - static constexpr Units::Distance requestRadius = Units::Distance::fromNM(83.0); + // This is the maximum that FAA API currently allows (FAA max is 100NM) + static constexpr Units::Distance requestRadius = Units::Distance::fromNM(99.0); }; } // namespace NOTAM diff --git a/src/platform/PlatformAdaptor_Abstract.cpp b/src/platform/PlatformAdaptor_Abstract.cpp index d48b66801..8fdfd9676 100644 --- a/src/platform/PlatformAdaptor_Abstract.cpp +++ b/src/platform/PlatformAdaptor_Abstract.cpp @@ -24,7 +24,7 @@ #include #include -#include "notam/NotamProvider.h" +#include "notam/NOTAMProvider.h" #include "platform/PlatformAdaptor_Abstract.h" #include "qimage.h" From b3c4003a93e57a9339b41f6832159b677a7bdbfb Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 13:09:42 +0200 Subject: [PATCH 54/64] Working... --- src/notam/NOTAMProvider.cpp | 65 ++++++++++++++++++------------------- src/notam/NOTAMProvider.h | 48 +++++++++++++++++++-------- 2 files changed, 65 insertions(+), 48 deletions(-) diff --git a/src/notam/NOTAMProvider.cpp b/src/notam/NOTAMProvider.cpp index 521933c4b..2edf20267 100644 --- a/src/notam/NOTAMProvider.cpp +++ b/src/notam/NOTAMProvider.cpp @@ -74,9 +74,10 @@ void NOTAM::NOTAMProvider::deferredInitialization() // Setup Bindings - m_geoJSON.setBinding([this]() {return this->computeGeoJSON();}); - m_lastUpdate.setBinding([this]() {return this->computeLastUpdate();}); - m_status.setBinding([this]() {return this->computeStatus();}); + m_controlPoints4FlightRoute.setBinding([this]() {return computeControlPoints4FlightRoute();}); + m_geoJSON.setBinding([this]() {return computeGeoJSON();}); + m_lastUpdate.setBinding([this]() {return computeLastUpdate();}); + m_status.setBinding([this]() {return computeStatus();}); // Setup Notifiers // -- Save the NOTAM data every time that the database changes @@ -94,7 +95,7 @@ NOTAM::NOTAMProvider::~NOTAMProvider() } networkReply->abort(); } - +#warning Need to delete! m_networkReplies.clear(); } @@ -187,6 +188,22 @@ void NOTAM::NOTAMProvider::setRead(const QString& number, bool read) // Private Slots // +QList NOTAM::NOTAMProvider::computeControlPoints4FlightRoute() const +{ + auto* route = navigator()->flightRoute(); + if (route != nullptr) + { + return {}; + } + + QList result; + result += route->geoPath(); + +#warning need to implement + return result; +} + + QByteArray NOTAM::NOTAMProvider::computeGeoJSON() const { QList result; @@ -240,31 +257,17 @@ QDateTime NOTAM::NOTAMProvider::computeLastUpdate() const QString NOTAM::NOTAMProvider::computeStatus() const { - auto position = GlobalObject::positionProvider()->approximateLastValidCoordinate(); - - QList positionList; - positionList.append(position); - auto* route = navigator()->flightRoute(); - if (route != nullptr) + if (!hasDataForPosition(GlobalObject::positionProvider()->approximateLastValidCoordinate(), true, false)) { - positionList += route->geoPath(); + return tr("NOTAMs not current around own position, requesting update"); } - for(const auto& pos : positionList) + for(const auto& pos : m_controlPoints4FlightRoute.value()) { - if (!pos.isValid()) + if (!hasDataForPosition(pos, true, false)) { - continue; + return tr("NOTAMs not current around waypoint, requesting update"); } - if (covers(pos, true, false)) - { - continue; - } - if (position == pos) - { - return tr("NOTAMs not current around own position, requesting update"); - } - return tr("NOTAMs not current around waypoint, requesting update"); } return {}; } @@ -361,16 +364,10 @@ void NOTAM::NOTAMProvider::save() const void NOTAM::NOTAMProvider::updateData() { - auto position = Positioning::PositionProvider::lastValidCoordinate(); - startRequest(position); - - auto* route = navigator()->flightRoute(); - if (route != nullptr) + startRequest(GlobalObject::positionProvider()->approximateLastValidCoordinate()); + for(const auto& pos : m_controlPoints4FlightRoute.value()) { - for(const auto& pos : route->geoPath()) - { - startRequest(pos); - } + startRequest(pos); } } @@ -380,7 +377,7 @@ void NOTAM::NOTAMProvider::updateData() // Private Methods // -bool NOTAM::NOTAMProvider::covers(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const +bool NOTAM::NOTAMProvider::hasDataForPosition(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const { if (!position.isValid()) { @@ -443,7 +440,7 @@ void NOTAM::NOTAMProvider::startRequest(const QGeoCoordinate& coordinate) // If data exists for marginRadius around that coordinate or if that data is already // requested for download, then return immediately. - if (covers(coordinate, false, true)) + if (hasDataForPosition(coordinate, false, true)) { return; } diff --git a/src/notam/NOTAMProvider.h b/src/notam/NOTAMProvider.h index 184b512d1..997492cd1 100644 --- a/src/notam/NOTAMProvider.h +++ b/src/notam/NOTAMProvider.h @@ -82,7 +82,11 @@ class NOTAMProvider : public GlobalObject { */ Q_PROPERTY(QByteArray geoJSON READ geoJSON BINDABLE bindableGeoJSON) - /*! \brief Time of last database update */ + /*! \brief Time of last database update + * + * This is the time of the last successful data download from the FAA server. + * The property holds an invalid QDateTime if no data is available. + */ Q_PROPERTY(QDateTime lastUpdate READ lastUpdate BINDABLE bindableLastUpdate) /*! \brief Status @@ -99,9 +103,14 @@ class NOTAMProvider : public GlobalObject { /*! \brief Getter function for property with the same name * - * @returns Property GeoJSON + * @returns Property geoJSON */ Q_REQUIRED_RESULT QByteArray geoJSON() const {return m_geoJSON.value();} + + /*! \brief Getter function for property with the same name + * + * @returns Property geoJSON + */ Q_REQUIRED_RESULT QBindable bindableGeoJSON() const {return &m_geoJSON;} /*! \brief Getter function for the property with the same name @@ -109,6 +118,11 @@ class NOTAMProvider : public GlobalObject { * @returns Property lastUpdate */ Q_REQUIRED_RESULT QDateTime lastUpdate() const {return {m_lastUpdate};} + + /*! \brief Getter function for the property with the same name + * + * @returns Property lastUpdate + */ Q_REQUIRED_RESULT QBindable bindableLastUpdate() const {return &m_lastUpdate;} /*! \brief Getter function for the property with the same name @@ -116,6 +130,11 @@ class NOTAMProvider : public GlobalObject { * @returns Property status */ Q_REQUIRED_RESULT QString status() const {return {m_status};} + + /*! \brief Getter function for the property with the same name + * + * @returns Property status + */ Q_REQUIRED_RESULT QBindable bindableStatus() const {return &m_status;} @@ -127,11 +146,11 @@ class NOTAMProvider : public GlobalObject { /*! \brief NOTAMs for a given waypoint * * The returned list is empty and has a valid property "retrieved" if the - * NotamProvider is sure that there are no relevant notams for the given + * NOTAMProvider is sure that there are no relevant NOTAMs for the given * waypoint. * * The returned list is empty and has an invalid property "retrieved" if - * the NotamProvider has no data. + * the NOTAMProvider has no data. * * Calling this method might trigger an update of the NOTAM database. * Consumers can watch the property lastUpdate to learn about database @@ -139,9 +158,9 @@ class NOTAMProvider : public GlobalObject { * * @param waypoint Waypoint for which the notam list is compiled * - * @returns List of Notams relevant for the waypoint + * @returns List of NOTAMS relevant for the waypoint */ - [[nodiscard]] Q_INVOKABLE NOTAMList notams(const GeoMaps::Waypoint& waypoint); + Q_REQUIRED_RESULT Q_INVOKABLE NOTAMList notams(const GeoMaps::Waypoint& waypoint); /*! \brief Check if a NOTAM number is registred as read * @@ -149,7 +168,7 @@ class NOTAMProvider : public GlobalObject { * * @returns True is notam is known as read */ - [[nodiscard]] Q_INVOKABLE bool isRead(const QString& number) const { return m_readNotamNumbers.contains(number); } + Q_REQUIRED_RESULT Q_INVOKABLE bool isRead(const QString& number) const { return m_readNotamNumbers.contains(number); } /*! \brief Register NOTAM number as read or unread * @@ -159,11 +178,11 @@ class NOTAMProvider : public GlobalObject { */ Q_INVOKABLE void setRead(const QString& number, bool read); -private slots: +private slots: // This slot is connected to signals QNetworkReply::finished and // QNetworkReply::errorOccurred of the QNetworkReply contained in the list // in m_networkReply. This method reads the incoming data and adds it to the - // database + // database. On error, it requests a call to updateData in five minutes. void downloadFinished(); // Checks if NOTAM data is available for an area of marginRadius around the @@ -175,12 +194,13 @@ private slots: Q_DISABLE_COPY_MOVE(NOTAMProvider) // Property computing functions - [[nodiscard]] QByteArray computeGeoJSON() const; - [[nodiscard]] QDateTime computeLastUpdate() const; - [[nodiscard]] QString computeStatus() const; + Q_REQUIRED_RESULT QList computeControlPoints4FlightRoute() const; + Q_REQUIRED_RESULT QByteArray computeGeoJSON() const; + Q_REQUIRED_RESULT QDateTime computeLastUpdate() const; + Q_REQUIRED_RESULT QString computeStatus() const; // Removes outdated NOTAMs and outdated NOTAMLists. - [[nodiscard]] static QList cleaned(const QList& notamLists, const QSet& cancelledNotams = {}); + Q_REQUIRED_RESULT static QList cleaned(const QList& notamLists, const QSet& cancelledNotams = {}); // Check if current NOTAM data exists for a circle of radius minimalRadius around // position. This method ignores outdated NOTAM data. An invalid position is always @@ -189,7 +209,7 @@ private slots: // includeDataThatNeedsUpdate: If true, then also count NOTAM lists that need an update as NOTAM data // // includeRunningDownloads: If true, then also count running downloads as NOTAM data - [[nodiscard]] bool covers(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const; + Q_REQUIRED_RESULT bool hasDataForPosition(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const; // Save NOTAM data to a file, using the filename found in m_stdFileName. There are // no error checks of any kind. From 5ac1c975557e879257ee8cf0ae2c665439c5d779 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 14:42:15 +0200 Subject: [PATCH 55/64] Done. --- src/notam/NOTAMProvider.cpp | 257 +++++++++++++++++++----------------- src/notam/NOTAMProvider.h | 48 ++++--- src/qml/items/FlightMap.qml | 2 +- src/qml/items/MFM.qml | 4 +- 4 files changed, 167 insertions(+), 144 deletions(-) diff --git a/src/notam/NOTAMProvider.cpp b/src/notam/NOTAMProvider.cpp index 2edf20267..36ec5d1c6 100644 --- a/src/notam/NOTAMProvider.cpp +++ b/src/notam/NOTAMProvider.cpp @@ -40,7 +40,6 @@ NOTAM::NOTAMProvider::NOTAMProvider(QObject* parent) : { } - void NOTAM::NOTAMProvider::deferredInitialization() { // Load NOTAM data from file in stdFileName, then clean the data (which potentially triggers save()). @@ -84,7 +83,6 @@ void NOTAM::NOTAMProvider::deferredInitialization() m_saveNotifier = m_notamLists.addNotifier([this]() {save();}); } - NOTAM::NOTAMProvider::~NOTAMProvider() { for(const auto& networkReply : m_networkReplies) @@ -93,9 +91,10 @@ NOTAM::NOTAMProvider::~NOTAMProvider() { continue; } + disconnect(networkReply, nullptr, this, nullptr); networkReply->abort(); + delete networkReply; } -#warning Need to delete! m_networkReplies.clear(); } @@ -106,7 +105,6 @@ NOTAM::NOTAMProvider::~NOTAMProvider() NOTAM::NOTAMList NOTAM::NOTAMProvider::notams(const GeoMaps::Waypoint& waypoint) { -#warning Simplify! // Paranoid safety checks if (!waypoint.coordinate().isValid()) { @@ -164,7 +162,6 @@ NOTAM::NOTAMList NOTAM::NOTAMProvider::notams(const GeoMaps::Waypoint& waypoint) return {}; } - void NOTAM::NOTAMProvider::setRead(const QString& number, bool read) { if (read) @@ -183,96 +180,10 @@ void NOTAM::NOTAMProvider::setRead(const QString& number, bool read) } - // -// Private Slots +// Private Methods // -QList NOTAM::NOTAMProvider::computeControlPoints4FlightRoute() const -{ - auto* route = navigator()->flightRoute(); - if (route != nullptr) - { - return {}; - } - - QList result; - result += route->geoPath(); - -#warning need to implement - return result; -} - - -QByteArray NOTAM::NOTAMProvider::computeGeoJSON() const -{ - QList result; - QSet coordinatesSeen; - - for(const auto& notamList : m_notamLists.value()) - { - for(const auto& notam : notamList.notams()) - { - auto coordinate = notam.coordinate(); - if (!coordinate.isValid()) - { - continue; - } - - // If we already have a waypoint for that coordinate, then don't add another one. - if (coordinatesSeen.contains(coordinate)) - { - continue; - } - coordinatesSeen += coordinate; - result.append(notam.GeoJSON()); - } - } - - QJsonArray waypointArray; - for(const auto& jsonObject : result) - { - waypointArray.append(jsonObject); - } - QJsonObject jsonObj; - jsonObj.insert(QStringLiteral("type"), "FeatureCollection"); - jsonObj.insert(QStringLiteral("features"), waypointArray); - - QJsonDocument doc; - doc.setObject(jsonObj); - return doc.toJson(); -} - - -QDateTime NOTAM::NOTAMProvider::computeLastUpdate() const -{ - auto notamLists = m_notamLists.value(); - if (notamLists.isEmpty()) - { - return {}; - } - return notamLists[0].retrieved(); -} - - -QString NOTAM::NOTAMProvider::computeStatus() const -{ - if (!hasDataForPosition(GlobalObject::positionProvider()->approximateLastValidCoordinate(), true, false)) - { - return tr("NOTAMs not current around own position, requesting update"); - } - - for(const auto& pos : m_controlPoints4FlightRoute.value()) - { - if (!hasDataForPosition(pos, true, false)) - { - return tr("NOTAMs not current around waypoint, requesting update"); - } - } - return {}; -} - - QList NOTAM::NOTAMProvider::cleaned(const QList& notamLists, const QSet& cancelledNotams) { QList newNotamLists; @@ -303,7 +214,6 @@ QList NOTAM::NOTAMProvider::cleaned(const QList& no return newNotamLists; } - void NOTAM::NOTAMProvider::downloadFinished() { auto newNotamList = m_notamLists.value(); @@ -348,35 +258,6 @@ void NOTAM::NOTAMProvider::downloadFinished() m_notamLists = cleaned(newNotamList, cancelledNotams); } - -void NOTAM::NOTAMProvider::save() const -{ - auto outputFile = QFile(m_stdFileName); - if (outputFile.open(QIODevice::WriteOnly)) - { - QDataStream outputStream(&outputFile); - outputStream << QStringLiteral(GIT_COMMIT); - outputStream << m_readNotamNumbers; - outputStream << m_notamLists.value(); - } -} - - -void NOTAM::NOTAMProvider::updateData() -{ - startRequest(GlobalObject::positionProvider()->approximateLastValidCoordinate()); - for(const auto& pos : m_controlPoints4FlightRoute.value()) - { - startRequest(pos); - } -} - - - -// -// Private Methods -// - bool NOTAM::NOTAMProvider::hasDataForPosition(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const { if (!position.isValid()) @@ -430,6 +311,17 @@ bool NOTAM::NOTAMProvider::hasDataForPosition(const QGeoCoordinate& position, bo return false; } +void NOTAM::NOTAMProvider::save() const +{ + auto outputFile = QFile(m_stdFileName); + if (outputFile.open(QIODevice::WriteOnly)) + { + QDataStream outputStream(&outputFile); + outputStream << QStringLiteral(GIT_COMMIT); + outputStream << m_readNotamNumbers; + outputStream << m_notamLists.value(); + } +} void NOTAM::NOTAMProvider::startRequest(const QGeoCoordinate& coordinate) { @@ -465,3 +357,124 @@ void NOTAM::NOTAMProvider::startRequest(const QGeoCoordinate& coordinate) m_networkReplies.append(reply); } +void NOTAM::NOTAMProvider::updateData() +{ + startRequest(GlobalObject::positionProvider()->approximateLastValidCoordinate()); + for(const auto& pos : m_controlPoints4FlightRoute.value()) + { + startRequest(pos); + } +} + + +// +// Private Members and Member Computing Methods +// + +QList NOTAM::NOTAMProvider::computeControlPoints4FlightRoute() +{ + auto* route = navigator()->flightRoute(); + if (route == nullptr) + { + return {}; + } + + auto minDistControlPoints = (minimumRadiusPoint-minimumRadiusFlightRoute)*2.0; + + QList result; + result += route->geoPath(); + for (const auto& leg : route->legs()) + { + if (leg.distance() > maximumFlightRouteLegLength) + { + continue; + } + + auto startCoordinate = leg.startPoint().coordinate(); + auto endCoordinate = leg.endPoint().coordinate(); + while (startCoordinate.distanceTo(endCoordinate) > minDistControlPoints.toM()) + { + auto azimuth = startCoordinate.azimuthTo(endCoordinate); + startCoordinate = startCoordinate.atDistanceAndAzimuth(minDistControlPoints.toM(), azimuth); + result += startCoordinate; + } + } + + return result; +} + +QByteArray NOTAM::NOTAMProvider::computeGeoJSON() const +{ + QList result; + QSet coordinatesSeen; + + for(const auto& notamList : m_notamLists.value()) + { + for(const auto& notam : notamList.notams()) + { + auto coordinate = notam.coordinate(); + if (!coordinate.isValid()) + { + continue; + } + + // If we already have a waypoint for that coordinate, then don't add another one. + if (coordinatesSeen.contains(coordinate)) + { + continue; + } + coordinatesSeen += coordinate; + result.append(notam.GeoJSON()); + } + } + + QJsonArray waypointArray; + for(const auto& jsonObject : result) + { + waypointArray.append(jsonObject); + } + QJsonObject jsonObj; + jsonObj.insert(QStringLiteral("type"), "FeatureCollection"); + jsonObj.insert(QStringLiteral("features"), waypointArray); + + QJsonDocument doc; + doc.setObject(jsonObj); + return doc.toJson(); +} + +QDateTime NOTAM::NOTAMProvider::computeLastUpdate() const +{ + auto notamLists = m_notamLists.value(); + if (notamLists.isEmpty()) + { + return {}; + } + return notamLists[0].retrieved(); +} + +QString NOTAM::NOTAMProvider::computeStatus() const +{ + if (!hasDataForPosition(GlobalObject::positionProvider()->approximateLastValidCoordinate(), true, false)) + { + return tr("NOTAMs not current around own position, requesting update"); + } + + for(const auto& pos : m_controlPoints4FlightRoute.value()) + { + if (!hasDataForPosition(pos, true, false)) + { + return tr("NOTAMs not current around waypoint, requesting update"); + } + } + return {}; +} + + + + + + +// +// Private Methods +// + diff --git a/src/notam/NOTAMProvider.h b/src/notam/NOTAMProvider.h index 997492cd1..01076ccfa 100644 --- a/src/notam/NOTAMProvider.h +++ b/src/notam/NOTAMProvider.h @@ -178,30 +178,26 @@ class NOTAMProvider : public GlobalObject { */ Q_INVOKABLE void setRead(const QString& number, bool read); -private slots: - // This slot is connected to signals QNetworkReply::finished and - // QNetworkReply::errorOccurred of the QNetworkReply contained in the list - // in m_networkReply. This method reads the incoming data and adds it to the - // database. On error, it requests a call to updateData in five minutes. - void downloadFinished(); +private: - // Checks if NOTAM data is available for an area of marginRadius around the - // current position and around the current flight route. If not, requests - // the data. - void updateData(); private: Q_DISABLE_COPY_MOVE(NOTAMProvider) - // Property computing functions - Q_REQUIRED_RESULT QList computeControlPoints4FlightRoute() const; - Q_REQUIRED_RESULT QByteArray computeGeoJSON() const; - Q_REQUIRED_RESULT QDateTime computeLastUpdate() const; - Q_REQUIRED_RESULT QString computeStatus() const; + + // + // Private Methods + // // Removes outdated NOTAMs and outdated NOTAMLists. Q_REQUIRED_RESULT static QList cleaned(const QList& notamLists, const QSet& cancelledNotams = {}); + // This method reads the incoming data from network replies and adds it to the + // database. It cleans up the list of network replies in m_networkReplies. On error, it requests a call to updateData in five minutes. This method is connected to signals QNetworkReply::finished and + // QNetworkReply::errorOccurred of the QNetworkReply contained in the list + // in m_networkReply. + void downloadFinished(); + // Check if current NOTAM data exists for a circle of radius minimalRadius around // position. This method ignores outdated NOTAM data. An invalid position is always // considered to be covered. @@ -223,6 +219,16 @@ private slots: // if existing NOTAM data or ongoing download requests cover the position alreads. void startRequest(const QGeoCoordinate& coordinate); + // Checks if NOTAM data is available for an area of marginRadius around the + // current position and around the current flight route. If not, requests + // the data. + void updateData(); + + + // + // Private Members and Member Computing Methods + // + // List with numbers of notams that have been marked as read QList m_readNotamNumbers; @@ -233,21 +239,25 @@ private slots: QProperty> m_notamLists; // This is a list of control points. The computing function guarantees that -// the NOTAM data covers a region of at least marginRadiusFlightRoute around the route if -// the data covers a circle of radius + // the NOTAM data covers a region of at least marginRadiusFlightRoute around the route if + // the data covers a circle of radius // marginRadius around every control point point. Exeption: For performance reasons, this guarantee -// is lifted if the flight route contains a leg -// of size > maximumFlightRouteLegLength. + // is lifted if the flight route contains a leg + // of size > maximumFlightRouteLegLength. QProperty> m_controlPoints4FlightRoute; + Q_REQUIRED_RESULT static QList computeControlPoints4FlightRoute(); // GeoJSON, for use in map QProperty m_geoJSON; + Q_REQUIRED_RESULT QByteArray computeGeoJSON() const; // Time of last update to data QProperty m_lastUpdate; + Q_REQUIRED_RESULT QDateTime computeLastUpdate() const; // Filename for loading/saving NOTAM data QProperty m_status; + Q_REQUIRED_RESULT QString computeStatus() const; // Filename for loading/saving NOTAM data QString m_stdFileName { QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+u"/notam.dat"_qs }; diff --git a/src/qml/items/FlightMap.qml b/src/qml/items/FlightMap.qml index 232cb3399..083b414d5 100644 --- a/src/qml/items/FlightMap.qml +++ b/src/qml/items/FlightMap.qml @@ -173,7 +173,7 @@ Map { styleId: "notams" type: "geojson" - property string data: NotamProvider.geoJSON + property string data: NOTAMProvider.geoJSON } LayerParameter { diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index fba90ded2..7a4b56e4a 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -692,8 +692,8 @@ Item { } if (DataManager.items.downloading) resultList.push(qsTr("Downloading Maps and Data")) - if (NotamProvider.status !== "") - resultList.push(NotamProvider.status) + if (NOTAMProvider.status !== "") + resultList.push(NOTAMProvider.status) return resultList.join(" • ") } From 5a132cdf390a7d41376e5e805371a5b538742bd5 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 17:17:32 +0200 Subject: [PATCH 56/64] Cleanup --- .gitignore | 1 + src/notam/NOTAMProvider.h | 71 +++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 99ce770b8..1392cb6bd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ build-android-release/ build-android-debug/ build-linux/ build-macos/ +.project # Doxygen generated documentation doc/APIdoc diff --git a/src/notam/NOTAMProvider.h b/src/notam/NOTAMProvider.h index 01076ccfa..ea43632c3 100644 --- a/src/notam/NOTAMProvider.h +++ b/src/notam/NOTAMProvider.h @@ -32,12 +32,13 @@ namespace NOTAM { /*! \brief Manage NOTAM data and download NOTAM data from the FAA if required. * - * This class attempts to ensure that for any given point in time, current NOTAM data - * is provided for circles of radius minimumRadiusPoint around the current position - * and every waypoint in the flightRoute, as well as a region of at least - * minimumRadiusFlightRoute around the flight route. + * This class attempts to ensure that for any given point in time, current + * NOTAM data is provided for circles of radius minimumRadiusPoint around the + * current position and every waypoint in the flightRoute, as well as a region + * of at least minimumRadiusFlightRoute around the flight route. * - * There is API to access the data, and to request NOTAM data for arbitrary coordinates. + * There is API to access the data, and to request NOTAM data for arbitrary + * coordinates. */ class NOTAMProvider : public GlobalObject { @@ -63,8 +64,8 @@ class NOTAMProvider : public GlobalObject { return GlobalObject::notamProvider(); } - // NOTAM data is considered to cover a given point if the data covers a circle of radius - // minimumRadiusPoint around that point. + // NOTAM data is considered to cover a given point if the data covers a + // circle of radius minimumRadiusPoint around that point. static constexpr Units::Distance minimumRadiusPoint = Units::Distance::fromNM(20.0); // NOTAM data is considered to cover the flight route if it covers a region of at least @@ -84,15 +85,15 @@ class NOTAMProvider : public GlobalObject { /*! \brief Time of last database update * - * This is the time of the last successful data download from the FAA server. - * The property holds an invalid QDateTime if no data is available. + * This is the time of the last successful data download from the FAA + * server. The property holds an invalid QDateTime if no data is available. */ Q_PROPERTY(QDateTime lastUpdate READ lastUpdate BINDABLE bindableLastUpdate) /*! \brief Status * - * This is a translated, human-readable text with warnings about incomplete NOTAM data, - * or an empty string in case of no warning. + * This is a translated, human-readable text with warnings about incomplete + * NOTAM data, or an empty string in case of no warning. */ Q_PROPERTY(QString status READ status BINDABLE bindableStatus) @@ -192,31 +193,35 @@ class NOTAMProvider : public GlobalObject { // Removes outdated NOTAMs and outdated NOTAMLists. Q_REQUIRED_RESULT static QList cleaned(const QList& notamLists, const QSet& cancelledNotams = {}); - // This method reads the incoming data from network replies and adds it to the - // database. It cleans up the list of network replies in m_networkReplies. On error, it requests a call to updateData in five minutes. This method is connected to signals QNetworkReply::finished and + // This method reads the incoming data from network replies and adds it to + // the database. It cleans up the list of network replies in + // m_networkReplies. On error, it requests a call to updateData in five + // minutes. This method is connected to signals QNetworkReply::finished and // QNetworkReply::errorOccurred of the QNetworkReply contained in the list // in m_networkReply. void downloadFinished(); - // Check if current NOTAM data exists for a circle of radius minimalRadius around - // position. This method ignores outdated NOTAM data. An invalid position is always - // considered to be covered. + // Check if current NOTAM data exists for a circle of radius minimalRadius + // around position. This method ignores outdated NOTAM data. An invalid + // position is always considered to be covered. // - // includeDataThatNeedsUpdate: If true, then also count NOTAM lists that need an update as NOTAM data + // includeDataThatNeedsUpdate: If true, then also count NOTAM lists that + // need an update as NOTAM data // - // includeRunningDownloads: If true, then also count running downloads as NOTAM data + // includeRunningDownloads: If true, then also count running downloads as + // NOTAM data Q_REQUIRED_RESULT bool hasDataForPosition(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const; - // Save NOTAM data to a file, using the filename found in m_stdFileName. There are - // no error checks of any kind. - // The propertyNotifier ensures that the method save() is called whenever - // m_notamLists changes. + // Save NOTAM data to a file, using the filename found in m_stdFileName. + // There are no error checks of any kind. The propertyNotifier ensures that + // the method save() is called whenever m_notamLists changes. void save() const; QPropertyNotifier m_saveNotifier; // Request NOTAM data from the FAA, for a circle of radius requestRadius - // around the coordinate. For performance reasons, the request will be ignored - // if existing NOTAM data or ongoing download requests cover the position alreads. + // around the coordinate. For performance reasons, the request will be + // ignored if existing NOTAM data or ongoing download requests cover the + // position alreads. void startRequest(const QGeoCoordinate& coordinate); // Checks if NOTAM data is available for an area of marginRadius around the @@ -239,11 +244,11 @@ class NOTAMProvider : public GlobalObject { QProperty> m_notamLists; // This is a list of control points. The computing function guarantees that - // the NOTAM data covers a region of at least marginRadiusFlightRoute around the route if - // the data covers a circle of radius - // marginRadius around every control point point. Exeption: For performance reasons, this guarantee - // is lifted if the flight route contains a leg - // of size > maximumFlightRouteLegLength. + // the NOTAM data covers a region of at least marginRadiusFlightRoute around + // the route if the data covers a circle of radius marginRadius around every + // control point point. Exeption: For performance reasons, this guarantee is + // lifted if the flight route contains a leg of size > + // maximumFlightRouteLegLength. QProperty> m_controlPoints4FlightRoute; Q_REQUIRED_RESULT static QList computeControlPoints4FlightRoute(); @@ -262,12 +267,12 @@ class NOTAMProvider : public GlobalObject { // Filename for loading/saving NOTAM data QString m_stdFileName { QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+u"/notam.dat"_qs }; - // NOTAM data is considered to cover the flight route if it covers a region of at least - // marginRadiusFlightRoute around the route + // NOTAM data is considered to cover the flight route if it covers a region + // of at least marginRadiusFlightRoute around the route static constexpr Units::Distance maximumFlightRouteLegLength = Units::Distance::fromNM(200.0); - // Requests for Notam data are requestRadius around given position. - // This is the maximum that FAA API currently allows (FAA max is 100NM) + // Requests for Notam data are requestRadius around given position. This is + // the maximum that FAA API currently allows (FAA max is 100NM) static constexpr Units::Distance requestRadius = Units::Distance::fromNM(99.0); }; From cc2e7d6d26f91556b6672d1d39b00516c47d2c55 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 17:27:12 +0200 Subject: [PATCH 57/64] cleanup --- src/positioning/Geoid.cpp | 24 +++++++++---------- src/positioning/PositionInfo.cpp | 7 ++---- src/positioning/PositionInfo.h | 4 ++-- src/positioning/PositionInfoSource_Abstract.h | 6 ++--- .../PositionInfoSource_Satellite.cpp | 8 +++---- .../PositionInfoSource_Satellite.h | 3 +++ src/positioning/PositionProvider.cpp | 2 +- 7 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/positioning/Geoid.cpp b/src/positioning/Geoid.cpp index e83f165f4..21b6a25fb 100644 --- a/src/positioning/Geoid.cpp +++ b/src/positioning/Geoid.cpp @@ -39,7 +39,7 @@ void Positioning::Geoid::readEGM() { QFile file(QStringLiteral(":/WW15MGH.DAC")); - qint64 egm96_size_2 = (qint64)egm96_size * (qint64)2; + qint64 const egm96_size_2 = (qint64) egm96_size * (qint64) 2; if (!file.open(QIODevice::ReadOnly) || file.size() != (egm96_size_2)) { @@ -49,7 +49,8 @@ void Positioning::Geoid::readEGM() egm.resize(egm96_size); - qint64 nread = file.read(static_cast(static_cast(egm.data())), egm96_size_2); + qint64 const nread = file.read(static_cast(static_cast(egm.data())), + egm96_size_2); file.close(); @@ -104,17 +105,16 @@ auto Positioning::Geoid::separation(const QGeoCoordinate& coord) -> Units::Dista // integer row north and south of latitude // - int north = qFloor(row(latitude)); - int south = (north + 1) < egm96_rows? (north + 1) : north; + int const north = qFloor(row(latitude)); + int const south = (north + 1) < egm96_rows ? (north + 1) : north; // integer column west and east of latitude // - int west = qFloor(col(longitude)) % egm96_cols; - int east = (west + 1) % egm96_cols; + int const west = qFloor(col(longitude)) % egm96_cols; + int const east = (west + 1) % egm96_cols; - auto geoid = [&] (int row, int col) -> qreal - { - int idx = row * egm96_cols + col; + auto geoid = [&](int row, int col) -> qreal { + int const idx = row * egm96_cols + col; return idx >=0 && idx < egm96_size ? egm.at(idx) * 0.01 : 0.0; }; @@ -124,10 +124,8 @@ auto Positioning::Geoid::separation(const QGeoCoordinate& coord) -> Units::Dista double interpolated = 0; double row_dist = row(latitude) - north; double col_dist = col(longitude) - qFloor(col(longitude)); - for (int irow : {north, south}) - { - for (int icol : {west, east}) - { + for (int const irow : {north, south}) { + for (int const icol : {west, east}) { interpolated += geoid(irow, icol) * (1 - row_dist) * (1 - col_dist); col_dist = 1 - col_dist; } diff --git a/src/positioning/PositionInfo.cpp b/src/positioning/PositionInfo.cpp index e03c7ffcb..55d8a2829 100644 --- a/src/positioning/PositionInfo.cpp +++ b/src/positioning/PositionInfo.cpp @@ -22,12 +22,9 @@ #include "geomaps/GeoMapProvider.h" #include "positioning/PositionInfo.h" - Positioning::PositionInfo::PositionInfo(const QGeoPositionInfo &info) -{ - m_positionInfo = info; -} - + : m_positionInfo(info) +{} auto Positioning::PositionInfo::groundSpeed() const -> Units::Speed { diff --git a/src/positioning/PositionInfo.h b/src/positioning/PositionInfo.h index 2f251c4f0..2fcf03e90 100644 --- a/src/positioning/PositionInfo.h +++ b/src/positioning/PositionInfo.h @@ -186,8 +186,8 @@ class PositionInfo private: - QGeoPositionInfo m_positionInfo {}; - Units::Distance m_terrainAMSL {}; + QGeoPositionInfo m_positionInfo; + Units::Distance m_terrainAMSL{}; Units::Distance m_trueAltitudeAGL {}; }; diff --git a/src/positioning/PositionInfoSource_Abstract.h b/src/positioning/PositionInfoSource_Abstract.h index c57428aa5..11492092f 100644 --- a/src/positioning/PositionInfoSource_Abstract.h +++ b/src/positioning/PositionInfoSource_Abstract.h @@ -192,10 +192,10 @@ class PositionInfoSource_Abstract : public QObject { Positioning::PositionInfo m_positionInfo; QTimer m_positionInfoTimer; - QString m_sourceName {}; - QString m_statusString {}; + QString m_sourceName; + QString m_statusString; - bool _receivingPositionInfo {false}; + bool _receivingPositionInfo{false}; }; } // namespace Positioning diff --git a/src/positioning/PositionInfoSource_Satellite.cpp b/src/positioning/PositionInfoSource_Satellite.cpp index 297684c2d..3a75157f9 100644 --- a/src/positioning/PositionInfoSource_Satellite.cpp +++ b/src/positioning/PositionInfoSource_Satellite.cpp @@ -21,15 +21,15 @@ #include "positioning/Geoid.h" #include "positioning/PositionInfoSource_Satellite.h" - -Positioning::PositionInfoSource_Satellite::PositionInfoSource_Satellite(QObject *parent) : PositionInfoSource_Abstract(parent) +Positioning::PositionInfoSource_Satellite::PositionInfoSource_Satellite(QObject *parent) + : PositionInfoSource_Abstract(parent) + , source(QGeoPositionInfoSource::createDefaultSource(this)) { - source = QGeoPositionInfoSource::createDefaultSource(this); if (source != nullptr) { source->setPreferredPositioningMethods(QGeoPositionInfoSource::AllPositioningMethods); source->setUpdateInterval(1000); - QString sName = source->sourceName(); + QString const sName = source->sourceName(); if (sName.isEmpty()) { setSourceName( tr("Built-in receiver") ); } else { diff --git a/src/positioning/PositionInfoSource_Satellite.h b/src/positioning/PositionInfoSource_Satellite.h index bc0931a0e..1524b39c2 100644 --- a/src/positioning/PositionInfoSource_Satellite.h +++ b/src/positioning/PositionInfoSource_Satellite.h @@ -48,6 +48,9 @@ class PositionInfoSource_Satellite : public PositionInfoSource_Abstract */ explicit PositionInfoSource_Satellite(QObject *parent = nullptr); + // Default desctructor + ~PositionInfoSource_Satellite() override = default; + /*! \brief startUpdates * * Requests permissions if necessary and starts to provide data diff --git a/src/positioning/PositionProvider.cpp b/src/positioning/PositionProvider.cpp index f0fa76f30..b81690d58 100644 --- a/src/positioning/PositionProvider.cpp +++ b/src/positioning/PositionProvider.cpp @@ -237,7 +237,7 @@ auto Positioning::PositionProvider::lastValidCoordinate() -> QGeoCoordinate if (positionProvider == nullptr) { return {}; } - return positionProvider->m_lastValidCoordinate; + return positionProvider->m_lastValidCoordinate.value(); } From f82faccfd882fb4865d577dd2e5ed543fe13ec54 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 17:47:10 +0200 Subject: [PATCH 58/64] Cleanup --- src/DemoRunner.cpp | 2 +- src/DemoRunner.h | 2 +- src/Sensors.cpp | 2 +- src/dataManagement/Downloadable_SingleFile.h | 4 +-- src/fileFormats/GeoTIFF.h | 8 +++--- src/fileFormats/TIFF.h | 2 +- src/fileFormats/TripKit.h | 2 +- src/geomaps/Airspace.h | 10 +++---- src/geomaps/VAC.h | 12 ++++----- src/main.cpp | 7 ++--- src/navigation/Aircraft.h | 4 +-- src/navigation/RemainingRouteInfo.h | 15 +++++------ src/notification/Notification.h | 2 -- src/platform/PlatformAdaptor_Abstract.cpp | 3 ++- src/traffic/ConnectionInfo.h | 8 +++--- src/traffic/ConnectionScanner_Abstract.h | 2 +- src/traffic/FlarmnetDB.h | 2 +- src/traffic/PasswordDB.h | 4 +-- src/traffic/TrafficDataProvider.cpp | 2 +- src/traffic/TrafficDataProvider.h | 6 ++--- src/traffic/TrafficDataSource_Abstract.h | 8 +++--- src/traffic/TrafficFactor_Abstract.h | 6 ++--- src/traffic/TrafficFactor_DistanceOnly.h | 2 +- src/ui/ScaleQuickItem.cpp | 20 +++++++------- src/units/ByteSize.h | 2 +- src/units/Distance.cpp | 3 ++- src/weather/WeatherDataProvider.cpp | 28 +++++++++++--------- 27 files changed, 84 insertions(+), 84 deletions(-) diff --git a/src/DemoRunner.cpp b/src/DemoRunner.cpp index bbac4823d..30cc286f9 100644 --- a/src/DemoRunner.cpp +++ b/src/DemoRunner.cpp @@ -89,7 +89,7 @@ void DemoRunner::generateGooglePlayScreenshots() generateScreenshotsForDevices({"phone", "sevenInch", "tenInch"}, false); } -void DemoRunner::generateScreenshotsForDevices(QStringList devices, bool manual) +void DemoRunner::generateScreenshotsForDevices(const QStringList &devices, bool manual) { #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) || defined(Q_OS_IOS) Q_ASSERT(m_engine != nullptr); diff --git a/src/DemoRunner.h b/src/DemoRunner.h index 4148b0a4d..d61723cb5 100644 --- a/src/DemoRunner.h +++ b/src/DemoRunner.h @@ -111,7 +111,7 @@ public slots: QPointer m_engine; - void generateScreenshotsForDevices(QStringList, bool); + void generateScreenshotsForDevices(const QStringList &, bool); static void saveScreenshot(bool, QQuickWindow *, const QString&); }; diff --git a/src/Sensors.cpp b/src/Sensors.cpp index 8f54e9c85..f7b4360af 100644 --- a/src/Sensors.cpp +++ b/src/Sensors.cpp @@ -101,7 +101,7 @@ void Sensors::updateStatusString() { QString newStatus; - QStringList sensorNames; + QStringList const sensorNames; #if defined(Q_OS_ANDROID) or defined(Q_OS_IOS) auto types = QPressureSensor::sensorTypes(); if (types.contains("QPressureSensor")) diff --git a/src/dataManagement/Downloadable_SingleFile.h b/src/dataManagement/Downloadable_SingleFile.h index b65463ed0..5fd6ad8dd 100644 --- a/src/dataManagement/Downloadable_SingleFile.h +++ b/src/dataManagement/Downloadable_SingleFile.h @@ -382,13 +382,13 @@ class Downloadable_SingleFile : public Downloadable_Abstract // Temporary file for storing partiall data when downloading the remote // file. Set to nullptr when no download is in progress. - QPointer m_saveFile{}; + QPointer m_saveFile; // URL of the remote file, as set in the constructor QUrl m_url; // Name of the local file, as set in the constructor - QString m_fileName{}; + QString m_fileName; // Modification date of the remote file, set directly via a setter method or // by calling downloadRemoteFileInfo(). diff --git a/src/fileFormats/GeoTIFF.h b/src/fileFormats/GeoTIFF.h index 7fc9259a6..016cb5e98 100644 --- a/src/fileFormats/GeoTIFF.h +++ b/src/fileFormats/GeoTIFF.h @@ -170,10 +170,10 @@ class GeoTIFF : public TIFF void interpretGeoData(); // Geographic coordinates for corner of raster image - QGeoCoordinate m_topLeft {}; - QGeoCoordinate m_topRight {}; - QGeoCoordinate m_bottomLeft {}; - QGeoCoordinate m_bottomRight {}; + QGeoCoordinate m_topLeft; + QGeoCoordinate m_topRight; + QGeoCoordinate m_bottomLeft; + QGeoCoordinate m_bottomRight; // Name QString m_name; diff --git a/src/fileFormats/TIFF.h b/src/fileFormats/TIFF.h index ae61fb0d1..c4f10e14a 100644 --- a/src/fileFormats/TIFF.h +++ b/src/fileFormats/TIFF.h @@ -119,7 +119,7 @@ class TIFF : public DataFileAbstract void readRasterSize(); // Size of the raster imags - QSize m_rasterSize {}; + QSize m_rasterSize; // TIFF tags and associated data QMap m_TIFFFields; diff --git a/src/fileFormats/TripKit.h b/src/fileFormats/TripKit.h index 070467087..6388bd945 100644 --- a/src/fileFormats/TripKit.h +++ b/src/fileFormats/TripKit.h @@ -136,7 +136,7 @@ class TripKit : public DataFileAbstract // Some trip kits contain the content top-level, other trip kits hide the content ina top-level // directory. This string is either empty or of the form "topLevelDirName/". - QString m_prefix {}; + QString m_prefix; }; } // namespace FileFormats diff --git a/src/geomaps/Airspace.h b/src/geomaps/Airspace.h index 33665ad65..fe8691f88 100644 --- a/src/geomaps/Airspace.h +++ b/src/geomaps/Airspace.h @@ -156,11 +156,11 @@ class Airspace { // in meters. If the height string cannot be parsed, returns the original string [[nodiscard]] static auto makeMetric(const QString& standard) -> QString; - QString m_name{}; - QString m_CAT{}; - QString m_upperBound{}; - QString m_lowerBound{}; - QGeoPolygon m_polygon{}; + QString m_name; + QString m_CAT; + QString m_upperBound; + QString m_lowerBound; + QGeoPolygon m_polygon; }; /*! \brief Comparison */ diff --git a/src/geomaps/VAC.h b/src/geomaps/VAC.h index 2d7bfa859..f65f4d43e 100644 --- a/src/geomaps/VAC.h +++ b/src/geomaps/VAC.h @@ -197,22 +197,22 @@ class VAC // /*! \brief Member variable for property of the same name */ - QGeoCoordinate bottomLeft {}; + QGeoCoordinate bottomLeft; /*! \brief Member variable for property of the same name */ - QGeoCoordinate bottomRight {}; + QGeoCoordinate bottomRight; /*! \brief Member variable for property of the same name */ - QString fileName {}; + QString fileName; /*! \brief Member variable for property of the same name */ - QString name {}; + QString name; /*! \brief Member variable for property of the same name */ - QGeoCoordinate topLeft {}; + QGeoCoordinate topLeft; /*! \brief Member variable for property of the same name */ - QGeoCoordinate topRight {}; + QGeoCoordinate topRight; private: // Obtain values for topLeft etc by looking at the file name diff --git a/src/main.cpp b/src/main.cpp index d9a7f5b14..bb58d550c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -186,12 +186,9 @@ auto main(int argc, char *argv[]) -> int KDSingleApplication kdsingleapp; if (!kdsingleapp.isPrimaryInstance()) { - if (positionalArguments.length() > 0) - { + if (!positionalArguments.empty()) { kdsingleapp.sendMessage(positionalArguments[0].toUtf8()); - } - else - { + } else { kdsingleapp.sendMessage(QByteArray()); } return 0; diff --git a/src/navigation/Aircraft.h b/src/navigation/Aircraft.h index 86101810f..abf9cbd0e 100644 --- a/src/navigation/Aircraft.h +++ b/src/navigation/Aircraft.h @@ -386,8 +386,8 @@ class Aircraft { FuelConsumptionUnit m_fuelConsumptionUnit {LiterPerHour}; HorizontalDistanceUnit m_horizontalDistanceUnit {NauticalMile}; Units::Speed m_minimumSpeed {}; - QString m_name {}; - VerticalDistanceUnit m_verticalDistanceUnit {Feet}; + QString m_name; + VerticalDistanceUnit m_verticalDistanceUnit{Feet}; }; } // namespace Navigation diff --git a/src/navigation/RemainingRouteInfo.h b/src/navigation/RemainingRouteInfo.h index a2b3e96f5..1fd6a984f 100644 --- a/src/navigation/RemainingRouteInfo.h +++ b/src/navigation/RemainingRouteInfo.h @@ -148,19 +148,18 @@ class RemainingRouteInfo { Status status {NoRoute}; QString note; - GeoMaps::Waypoint nextWP {}; - Units::Distance nextWP_DIST {}; + GeoMaps::Waypoint nextWP; + Units::Distance nextWP_DIST{}; Units::Timespan nextWP_ETE {}; - QDateTime nextWP_ETA {}; - Units::Angle nextWP_TC {}; + QDateTime nextWP_ETA; + Units::Angle nextWP_TC{}; - GeoMaps::Waypoint finalWP {}; - Units::Distance finalWP_DIST {}; + GeoMaps::Waypoint finalWP; + Units::Distance finalWP_DIST{}; Units::Timespan finalWP_ETE {}; - QDateTime finalWP_ETA {}; + QDateTime finalWP_ETA; }; - /*! \brief Comparison */ auto operator==(const Navigation::RemainingRouteInfo&, const Navigation::RemainingRouteInfo&) -> bool; diff --git a/src/notification/Notification.h b/src/notification/Notification.h index b59a0e92c..e97e437de 100644 --- a/src/notification/Notification.h +++ b/src/notification/Notification.h @@ -22,11 +22,9 @@ #include #include -#include #include "units/Timespan.h" - namespace Notifications { /*! \brief Base class for all notifications diff --git a/src/platform/PlatformAdaptor_Abstract.cpp b/src/platform/PlatformAdaptor_Abstract.cpp index 8fdfd9676..df3e349d0 100644 --- a/src/platform/PlatformAdaptor_Abstract.cpp +++ b/src/platform/PlatformAdaptor_Abstract.cpp @@ -71,7 +71,8 @@ QString Platform::PlatformAdaptor_Abstract::systemInfo() result += u"%1%2\n"_qs.arg("Locale", language()); result += u"
\n"_qs; - QString updateCheckTimeStamp = QSettings().value(QStringLiteral("DataManager/MapListTimeStamp")).toString(); + QString const updateCheckTimeStamp + = QSettings().value(QStringLiteral("DataManager/MapListTimeStamp")).toString(); result += u"

Data

\n"_qs; result += u"\n"_qs; result += u"\n"_qs; diff --git a/src/traffic/ConnectionInfo.h b/src/traffic/ConnectionInfo.h index 09fd117f1..bc060d7a6 100644 --- a/src/traffic/ConnectionInfo.h +++ b/src/traffic/ConnectionInfo.h @@ -281,16 +281,16 @@ class ConnectionInfo { // bool m_canConnect { false }; bool m_canonical { false }; - QString m_description {}; - QString m_icon { u"/icons/material/ic_delete.svg"_qs }; + QString m_description; + QString m_icon{u"/icons/material/ic_delete.svg"_qs}; QString m_name { QObject::tr("Invalid Device", "Traffic::ConnectionInfo") }; Traffic::ConnectionInfo::Type m_type { Traffic::ConnectionInfo::Invalid }; // // Private members, depending on m_type // - QBluetoothDeviceInfo m_bluetoothDeviceInfo {}; - quint16 m_port {0}; + QBluetoothDeviceInfo m_bluetoothDeviceInfo; + quint16 m_port{0}; QString m_host; }; diff --git a/src/traffic/ConnectionScanner_Abstract.h b/src/traffic/ConnectionScanner_Abstract.h index 312432221..935662ffc 100644 --- a/src/traffic/ConnectionScanner_Abstract.h +++ b/src/traffic/ConnectionScanner_Abstract.h @@ -147,7 +147,7 @@ public slots: QList m_connectionInfos; // Property error - QString m_error {}; + QString m_error; // Property isScanning bool m_isScanning {false}; diff --git a/src/traffic/FlarmnetDB.h b/src/traffic/FlarmnetDB.h index c58cc5f96..d2fbc9d63 100644 --- a/src/traffic/FlarmnetDB.h +++ b/src/traffic/FlarmnetDB.h @@ -78,7 +78,7 @@ private slots: QPointer flarmnetDBDownloadable; - QCache m_cache {}; + QCache m_cache; }; } // namespace Traffic diff --git a/src/traffic/PasswordDB.h b/src/traffic/PasswordDB.h index eac8e55cf..75cd04d5c 100644 --- a/src/traffic/PasswordDB.h +++ b/src/traffic/PasswordDB.h @@ -151,9 +151,9 @@ class PasswordDB : public QObject { bool m_empty {true}; // Password database - QString passwordDBFileName {}; + QString passwordDBFileName; - QHash m_passwordDB {}; + QHash m_passwordDB; }; } // namespace Traffic diff --git a/src/traffic/TrafficDataProvider.cpp b/src/traffic/TrafficDataProvider.cpp index e597ad7cb..0aeed326d 100644 --- a/src/traffic/TrafficDataProvider.cpp +++ b/src/traffic/TrafficDataProvider.cpp @@ -254,7 +254,7 @@ QList Traffic::TrafficDataProvider::dataSo return result; } -void Traffic::TrafficDataProvider::deferredInitialization() +void Traffic::TrafficDataProvider::deferredInitialization() const { // Try to (re)connect whenever the network situation changes connect(GlobalObject::platformAdaptor(), &Platform::PlatformAdaptor_Abstract::wifiConnected, this, &Traffic::TrafficDataProvider::connectToTrafficReceiver); diff --git a/src/traffic/TrafficDataProvider.h b/src/traffic/TrafficDataProvider.h index 2c4b2bb73..0adc3b3ef 100644 --- a/src/traffic/TrafficDataProvider.h +++ b/src/traffic/TrafficDataProvider.h @@ -365,7 +365,7 @@ private slots: // Intializations that are moved out of the constructor, in order to avoid // nested uses of constructors in Global. - void deferredInitialization(); + void deferredInitialization() const; // Sends out foreflight broadcast message See // https://www.foreflight.com/connect/spec/ @@ -423,8 +423,8 @@ private slots: // Property cache Traffic::Warning m_Warning; QTimer m_WarningTimer; - QString m_trafficReceiverRuntimeError {}; - QString m_trafficReceiverSelfTestError {}; + QString m_trafficReceiverRuntimeError; + QString m_trafficReceiverSelfTestError; // Reconnect QTimer reconnectionTimer; diff --git a/src/traffic/TrafficDataSource_Abstract.h b/src/traffic/TrafficDataSource_Abstract.h index c5f29f077..f165b485e 100644 --- a/src/traffic/TrafficDataSource_Abstract.h +++ b/src/traffic/TrafficDataSource_Abstract.h @@ -458,10 +458,10 @@ public slots: // Property caches bool m_canonical {false}; - QString m_connectivityStatus {}; - QString m_errorString {}; - QString m_trafficReceiverRuntimeError {}; - QString m_trafficReceiverSelfTestError {}; + QString m_connectivityStatus; + QString m_errorString; + QString m_trafficReceiverRuntimeError; + QString m_trafficReceiverSelfTestError; // True altitude of own aircraft. We store these values because the // necessary information to compile a PositionInfo class does not always diff --git a/src/traffic/TrafficFactor_Abstract.h b/src/traffic/TrafficFactor_Abstract.h index 92c164e8c..0b7785f65 100644 --- a/src/traffic/TrafficFactor_Abstract.h +++ b/src/traffic/TrafficFactor_Abstract.h @@ -459,7 +459,7 @@ class TrafficFactor_Abstract : public QObject { // "dispatchUpdateDescription", which whose address is already known to the constructor. virtual void updateDescription(); void dispatchUpdateDescription(); - QString m_description {}; + QString m_description; private: Q_DISABLE_COPY_MOVE(TrafficFactor_Abstract) @@ -469,8 +469,8 @@ class TrafficFactor_Abstract : public QObject { // int m_alarmLevel {0}; bool m_animate {false}; - QString m_callSign {}; - QString m_color {QStringLiteral("red")}; + QString m_callSign; + QString m_color{QStringLiteral("red")}; Units::Distance m_hDist; QString m_ID; AircraftType m_type {AircraftType::unknown}; diff --git a/src/traffic/TrafficFactor_DistanceOnly.h b/src/traffic/TrafficFactor_DistanceOnly.h index 748eee9a3..99dc68b90 100644 --- a/src/traffic/TrafficFactor_DistanceOnly.h +++ b/src/traffic/TrafficFactor_DistanceOnly.h @@ -122,7 +122,7 @@ class TrafficFactor_DistanceOnly : public Traffic::TrafficFactor_Abstract { // // Property values // - QGeoCoordinate m_coordinate {}; + QGeoCoordinate m_coordinate; }; } // namespace Traffic diff --git a/src/ui/ScaleQuickItem.cpp b/src/ui/ScaleQuickItem.cpp index c8a3057ff..ea2d5a25f 100644 --- a/src/ui/ScaleQuickItem.cpp +++ b/src/ui/ScaleQuickItem.cpp @@ -58,11 +58,12 @@ void Ui::ScaleQuickItem::paint(QPainter *painter) pixelPerUnit = _pixelPer10km * 0.1852; break; } - qreal scaleSizeInUnit = _vertical ? (height()-10.0)/pixelPerUnit : (width()-10.0)/pixelPerUnit; - qreal ScaleUnitInUnit = pow(10.0, floor(log10(scaleSizeInUnit))); - int sizeOfUnitInPix = qRound(ScaleUnitInUnit*pixelPerUnit); - qreal sizeOfScaleInUnit = floor(scaleSizeInUnit/ScaleUnitInUnit)*ScaleUnitInUnit; - int sizeOfScaleInPix = qRound(sizeOfScaleInUnit*pixelPerUnit); + qreal const scaleSizeInUnit = _vertical ? (height() - 10.0) / pixelPerUnit + : (width() - 10.0) / pixelPerUnit; + qreal const ScaleUnitInUnit = pow(10.0, floor(log10(scaleSizeInUnit))); + int const sizeOfUnitInPix = qRound(ScaleUnitInUnit * pixelPerUnit); + qreal const sizeOfScaleInUnit = floor(scaleSizeInUnit / ScaleUnitInUnit) * ScaleUnitInUnit; + int const sizeOfScaleInPix = qRound(sizeOfScaleInUnit * pixelPerUnit); // Compute size of text. Set font to somewhat smaller than standard size. QFont font = painter->font(); @@ -84,8 +85,8 @@ void Ui::ScaleQuickItem::paint(QPainter *painter) text = QStringLiteral("%1 nm").arg(sizeOfScaleInUnit); break; } - int textWidth = painter->fontMetrics().horizontalAdvance(text); - int textHeight = painter->fontMetrics().height(); + int const textWidth = painter->fontMetrics().horizontalAdvance(text); + int const textHeight = painter->fontMetrics().height(); // Draw only if width() or height() is large enough if (_vertical) { @@ -99,8 +100,9 @@ void Ui::ScaleQuickItem::paint(QPainter *painter) } // Coordinates for the left/top point of the scale - int baseX = _vertical ? 8 : qRound((width()-sizeOfScaleInPix)/2.0); - int baseY = _vertical ? qRound((height()-sizeOfScaleInPix)/2.0) : qRound(height()) - 8 ; + int const baseX = _vertical ? 8 : qRound((width() - sizeOfScaleInPix) / 2.0); + int const baseY = _vertical ? qRound((height() - sizeOfScaleInPix) / 2.0) + : qRound(height()) - 8; // Draw underlying white, slightly tranparent rectangle painter->fillRect(0, 0, static_cast(width()), static_cast(height()), QColor(0xff, 0xff, 0xff, 0xe0)); diff --git a/src/units/ByteSize.h b/src/units/ByteSize.h index eddfd1ef7..a7c9ef80d 100644 --- a/src/units/ByteSize.h +++ b/src/units/ByteSize.h @@ -55,7 +55,7 @@ namespace Units { * * @returns True is size is zero */ - Q_INVOKABLE bool isNull() const { return value==0; } + [[nodiscard]] Q_INVOKABLE bool isNull() const { return value == 0; } /*! \brief Conversion from Units::ByteSize to size_t * diff --git a/src/units/Distance.cpp b/src/units/Distance.cpp index 98f089e9d..d3d1e3414 100644 --- a/src/units/Distance.cpp +++ b/src/units/Distance.cpp @@ -20,6 +20,7 @@ #include "units/Distance.h" +#include auto Units::Distance::toString(Units::Distance::DistanceUnit units, bool roundBigNumbers, bool forceSign) const -> QString { @@ -79,7 +80,7 @@ QDataStream& operator<<(QDataStream& stream, const Units::Distance& distance) QDataStream& operator>>(QDataStream& stream, Units::Distance& distance) { - double tmp; + double tmp = NAN; stream >> tmp; distance = Units::Distance::fromM(tmp); return stream; diff --git a/src/weather/WeatherDataProvider.cpp b/src/weather/WeatherDataProvider.cpp index 52a84f513..86af0e5dc 100644 --- a/src/weather/WeatherDataProvider.cpp +++ b/src/weather/WeatherDataProvider.cpp @@ -50,7 +50,7 @@ Weather::WeatherDataProvider::WeatherDataProvider(QObject *parent) : QObject(par // Connect the timer to the update method. This will set backgroundUpdate to the default value, // which is true. So these updates happen in the background. // Schedule the first update in 1 seconds from now - connect(&_updateTimer, &QTimer::timeout, this, [=, this](){ this->update(); }); + connect(&_updateTimer, &QTimer::timeout, this, [this]() { this->update(); }); _updateTimer.setInterval(updateIntervalNormal_ms); _updateTimer.start(); @@ -631,12 +631,13 @@ void Weather::WeatherDataProvider::update(bool isBackgroundUpdate) bBox.setWidth( bBox.width() + 2.0/factor ); { - QString urlString = u"https://enroute-data.akaflieg-freiburg.de/enrouteProxy/metar.php?format=xml&bbox=%1,%2,%3,%4"_qs - .arg(bBox.bottomLeft().latitude()) - .arg(bBox.bottomLeft().longitude()) - .arg(bBox.topRight().latitude()) - .arg(bBox.topRight().longitude()); - QUrl url = QUrl(urlString); + QString const urlString + = u"https://enroute-data.akaflieg-freiburg.de/enrouteProxy/metar.php?format=xml&bbox=%1,%2,%3,%4"_qs + .arg(bBox.bottomLeft().latitude()) + .arg(bBox.bottomLeft().longitude()) + .arg(bBox.topRight().latitude()) + .arg(bBox.topRight().longitude()); + QUrl const url = QUrl(urlString); QNetworkRequest request(url); request.setRawHeader("accept", "application/xml"); QPointer const reply = GlobalObject::networkAccessManager()->get(request); @@ -646,12 +647,13 @@ void Weather::WeatherDataProvider::update(bool isBackgroundUpdate) } { - QString urlString = u"https://enroute-data.akaflieg-freiburg.de/enrouteProxy/taf.php?format=xml&bbox=%1,%2,%3,%4"_qs - .arg(bBox.bottomLeft().latitude()) - .arg(bBox.bottomLeft().longitude()) - .arg(bBox.topRight().latitude()) - .arg(bBox.topRight().longitude()); - QUrl url = QUrl(urlString); + QString const urlString + = u"https://enroute-data.akaflieg-freiburg.de/enrouteProxy/taf.php?format=xml&bbox=%1,%2,%3,%4"_qs + .arg(bBox.bottomLeft().latitude()) + .arg(bBox.bottomLeft().longitude()) + .arg(bBox.topRight().latitude()) + .arg(bBox.topRight().longitude()); + QUrl const url = QUrl(urlString); QNetworkRequest request(url); request.setRawHeader("accept", "application/xml"); QPointer const reply = GlobalObject::networkAccessManager()->get(request); From b2eb3ece447db3b7b18eaf2bc63a105158d75b49 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 19:17:18 +0200 Subject: [PATCH 59/64] GFX tuning --- src/Sensors.cpp | 2 +- src/qml/items/MFM.qml | 30 ++++++--- src/ui/ScaleQuickItem.cpp | 101 ++++++++++++++++------------- src/ui/ScaleQuickItem.h | 131 +++++++++++++++++++++----------------- 4 files changed, 152 insertions(+), 112 deletions(-) diff --git a/src/Sensors.cpp b/src/Sensors.cpp index f7b4360af..8f54e9c85 100644 --- a/src/Sensors.cpp +++ b/src/Sensors.cpp @@ -101,7 +101,7 @@ void Sensors::updateStatusString() { QString newStatus; - QStringList const sensorNames; + QStringList sensorNames; #if defined(Q_OS_ANDROID) or defined(Q_OS_IOS) auto types = QPressureSensor::sensorTypes(); if (types.contains("QPressureSensor")) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index 7a4b56e4a..c29a08113 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -621,15 +621,20 @@ Item { Layout.fillHeight: true Layout.preferredWidth: 24 - Scale { - id: leftScale - - anchors.fill: parent + Pane { opacity: GlobalSettings.nightMode ? 0.3 : 1.0 visible: (!Global.currentVAC.isValid) && !scale.visible + anchors.fill: parent - pixelPer10km: flightMap.pixelPer10km - vertical: true + contentItem: Scale { + id: leftScale + + anchors.fill: parent + color: Material.foreground + + pixelPer10km: flightMap.pixelPer10km + vertical: true + } } } @@ -732,9 +737,10 @@ Item { } } - Scale { + Pane { id: scale + Material.elevation: 1 Layout.bottomMargin: 14 Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter @@ -743,8 +749,14 @@ Item { opacity: GlobalSettings.nightMode ? 0.3 : 1.0 visible: (!Global.currentVAC.isValid) && (page.height > page.width) - pixelPer10km: flightMap.pixelPer10km - vertical: false + contentItem: Scale + { + anchors.fill: parent + + color: Material.foreground + pixelPer10km: flightMap.pixelPer10km + vertical: false + } } } diff --git a/src/ui/ScaleQuickItem.cpp b/src/ui/ScaleQuickItem.cpp index ea2d5a25f..923d8911b 100644 --- a/src/ui/ScaleQuickItem.cpp +++ b/src/ui/ScaleQuickItem.cpp @@ -22,7 +22,7 @@ #include #include "GlobalObject.h" -#include "GlobalSettings.h" +//#include "GlobalSettings.h" #include "ScaleQuickItem.h" #include "navigation/Aircraft.h" #include "navigation/Navigator.h" @@ -31,34 +31,34 @@ Ui::ScaleQuickItem::ScaleQuickItem(QQuickItem *parent) : QQuickPaintedItem(parent) { - connect(GlobalObject::navigator(), &Navigation::Navigator::aircraftChanged, this, &QQuickItem::update); setRenderTarget(QQuickPaintedItem::FramebufferObject); } -void Ui::ScaleQuickItem::paint(QPainter *painter) +void Ui::ScaleQuickItem::paint(QPainter* painter) { // Safety check. Continue only if data provided is sane - if (_pixelPer10km < 20) { + if (m_pixelPer10km < 20) { return; } // Pre-compute a few numbers that will be used when drawing qreal pixelPerUnit = NAN; - switch (GlobalObject::navigator()->aircraft().horizontalDistanceUnit()) { + switch (GlobalObject::navigator()->aircraft().horizontalDistanceUnit()) + { case Navigation::Aircraft::Kilometer: - pixelPerUnit = _pixelPer10km * 0.1; + pixelPerUnit = m_pixelPer10km * 0.1; break; case Navigation::Aircraft::StatuteMile: - pixelPerUnit = _pixelPer10km * 0.1609344; + pixelPerUnit = m_pixelPer10km * 0.1609344; break; case Navigation::Aircraft::NauticalMile: - pixelPerUnit = _pixelPer10km * 0.1852; + pixelPerUnit = m_pixelPer10km * 0.1852; break; } - qreal const scaleSizeInUnit = _vertical ? (height() - 10.0) / pixelPerUnit + qreal const scaleSizeInUnit = m_vertical ? (height() - 10.0) / pixelPerUnit : (width() - 10.0) / pixelPerUnit; qreal const ScaleUnitInUnit = pow(10.0, floor(log10(scaleSizeInUnit))); int const sizeOfUnitInPix = qRound(ScaleUnitInUnit * pixelPerUnit); @@ -67,14 +67,18 @@ void Ui::ScaleQuickItem::paint(QPainter *painter) // Compute size of text. Set font to somewhat smaller than standard size. QFont font = painter->font(); - if (font.pointSizeF() > 0.0) { + if (font.pointSizeF() > 0.0) + { font.setPointSizeF(font.pointSizeF()*0.8); - } else { + } + else + { font.setPixelSize(qRound(font.pixelSize()*0.8)); } painter->setFont(font); QString text; - switch (GlobalObject::navigator()->aircraft().horizontalDistanceUnit()) { + switch (GlobalObject::navigator()->aircraft().horizontalDistanceUnit()) + { case Navigation::Aircraft::Kilometer: text = QStringLiteral("%1 km").arg(sizeOfScaleInUnit); break; @@ -89,77 +93,83 @@ void Ui::ScaleQuickItem::paint(QPainter *painter) int const textHeight = painter->fontMetrics().height(); // Draw only if width() or height() is large enough - if (_vertical) { - if (height() < textWidth*1.5) { + if (m_vertical) + { + if (height() < textWidth*1.5) + { return; } - } else { - if (width() < textWidth*1.5) { + } + else + { + if (width() < textWidth*1.5) + { return; } } // Coordinates for the left/top point of the scale - int const baseX = _vertical ? 8 : qRound((width() - sizeOfScaleInPix) / 2.0); - int const baseY = _vertical ? qRound((height() - sizeOfScaleInPix) / 2.0) + int const baseX = m_vertical ? 8 : qRound((width() - sizeOfScaleInPix) / 2.0); + int const baseY = m_vertical ? qRound((height() - sizeOfScaleInPix) / 2.0) : qRound(height()) - 8; // Draw underlying white, slightly tranparent rectangle - painter->fillRect(0, 0, static_cast(width()), static_cast(height()), QColor(0xff, 0xff, 0xff, 0xe0)); + // painter->fillRect(0, 0, static_cast(width()), static_cast(height()), QColor(0xff, 0xff, 0xff, 0xe0)); // Draw scale - if (_vertical) { - painter->setPen(QPen(Qt::white, 2)); + if (m_vertical) + { + painter->setPen(QPen(m_color, 1)); painter->drawLine(baseX, baseY, baseX, baseY+sizeOfScaleInPix); painter->drawLine(baseX+3, baseY, baseX-3, baseY); painter->drawLine(baseX+3, baseY+sizeOfScaleInPix, baseX-3, baseY+sizeOfScaleInPix); - for(int i=1; i*ScaleUnitInUnitdrawLine(baseX, baseY + i*sizeOfUnitInPix, baseX-3, baseY + i*sizeOfUnitInPix); - } - - painter->setPen(QPen(Qt::black, 1)); - painter->drawLine(baseX, baseY, baseX, baseY+sizeOfScaleInPix); - painter->drawLine(baseX+3, baseY, baseX-3, baseY); - painter->drawLine(baseX+3, baseY+sizeOfScaleInPix, baseX-3, baseY+sizeOfScaleInPix); - for(int i=1; i*ScaleUnitInUnitdrawLine(baseX, baseY + i*sizeOfUnitInPix, baseX-3, baseY + i*sizeOfUnitInPix); } // Draw text painter->rotate(-90.0); painter->drawText(-qRound(height()/2.0)-textWidth/2, baseX+textHeight, text); - } else { - painter->setPen(QPen(Qt::white, 2)); - painter->drawLine(baseX, baseY, baseX+sizeOfScaleInPix, baseY); - painter->drawLine(baseX, baseY+3, baseX, baseY-3); - painter->drawLine(baseX+sizeOfScaleInPix, baseY+3, baseX+sizeOfScaleInPix, baseY-3); - for(int i=1; i*ScaleUnitInUnitdrawLine(baseX + i*sizeOfUnitInPix, baseY, baseX + i*sizeOfUnitInPix, baseY+3); - } - - painter->setPen(QPen(Qt::black, 1)); + } + else + { + painter->setPen(QPen(m_color, 1)); painter->drawLine(baseX, baseY, baseX+sizeOfScaleInPix, baseY); painter->drawLine(baseX, baseY+3, baseX, baseY-3); painter->drawLine(baseX+sizeOfScaleInPix, baseY+3, baseX+sizeOfScaleInPix, baseY-3); - for(int i=1; i*ScaleUnitInUnitdrawLine(baseX + i*sizeOfUnitInPix, baseY, baseX + i*sizeOfUnitInPix, baseY+3); } // Draw text painter->drawText(baseX+sizeOfScaleInPix/2-textWidth/2, baseY-5, text); } +} +void Ui::ScaleQuickItem::setColor(QColor _color) +{ + if (m_color == _color) + { + return; + } + + m_color = _color; + update(); + emit colorChanged(); } void Ui::ScaleQuickItem::setPixelPer10km(qreal _pxp10k) { - if (qFuzzyCompare(_pixelPer10km, _pxp10k)) { + if (qFuzzyCompare(m_pixelPer10km, _pxp10k)) + { return; } - _pixelPer10km = _pxp10k; + m_pixelPer10km = _pxp10k; update(); emit pixelPer10kmChanged(); } @@ -167,11 +177,12 @@ void Ui::ScaleQuickItem::setPixelPer10km(qreal _pxp10k) void Ui::ScaleQuickItem::setVertical(bool newVertical) { - if (_vertical == newVertical) { + if (m_vertical == newVertical) + { return; } - _vertical = newVertical; + m_vertical = newVertical; update(); emit verticalChanged(); } diff --git a/src/ui/ScaleQuickItem.h b/src/ui/ScaleQuickItem.h index fa295fca2..b93e8b414 100644 --- a/src/ui/ScaleQuickItem.h +++ b/src/ui/ScaleQuickItem.h @@ -37,72 +37,89 @@ namespace Ui { class ScaleQuickItem : public QQuickPaintedItem { - Q_OBJECT - QML_NAMED_ELEMENT(Scale) + Q_OBJECT + QML_NAMED_ELEMENT(Scale) public: - /*! \brief Standard constructor - * - * @param parent The standard QObject parent pointer - */ - explicit ScaleQuickItem(QQuickItem *parent = nullptr); - - /*! \brief Number of pixel that represent a distance of 10km on the map */ - Q_PROPERTY(qreal pixelPer10km READ pixelPer10km WRITE setPixelPer10km NOTIFY pixelPer10kmChanged) - - /*! \brief Getter function for the property with the same name - - @returns Property pixelPer10km - */ - [[nodiscard]] auto pixelPer10km() const -> qreal {return _pixelPer10km;} - - /*! \brief Setter function for the property with the same name - - @param _pxp10k Property pixelPer10km - */ - void setPixelPer10km(qreal _pxp10k); - - /*! \brief Determines whether the scale should use km or nm */ - - /*! \brief Re-implemented from QQuickPaintedItem to implement painting - * - * @param painter Pointer to the QPainter used for painting - */ - void paint(QPainter *painter) override; - - /*! \brief Determines whether the scale should be drawn vertically or horizontally - * - * This property defaults to 'false'. - */ - Q_PROPERTY(bool vertical READ vertical WRITE setVertical NOTIFY verticalChanged) - - /*! \brief Getter function for the property with the same name - * - * @returns Property vertical - */ - [[nodiscard]] auto vertical() const -> bool {return _vertical;} - - /*! \brief Setter function for the property with the same name - * - * @param newVertical Property vertical - */ - void setVertical(bool newVertical); + /*! \brief Standard constructor + * + * @param parent The standard QObject parent pointer + */ + explicit ScaleQuickItem(QQuickItem *parent = nullptr); + + // Default destructor + ~ScaleQuickItem() override = default; + + /*! \brief Foreground color */ + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged REQUIRED) + + /*! \brief Getter function for the property with the same name + * + * @returns Property pixelPer10km + */ + [[nodiscard]] QColor color() const {return m_color;} + + /*! \brief Setter function for the property with the same name + * + * @param _color Property color + */ + void setColor(QColor _color); + + /*! \brief Number of pixel that represent a distance of 10km on the map */ + Q_PROPERTY(qreal pixelPer10km READ pixelPer10km WRITE setPixelPer10km NOTIFY pixelPer10kmChanged) + + /*! \brief Getter function for the property with the same name + * + * @returns Property pixelPer10km + */ + [[nodiscard]] auto pixelPer10km() const -> qreal {return m_pixelPer10km;} + + /*! \brief Setter function for the property with the same name + * + * @param _pxp10k Property pixelPer10km + */ + void setPixelPer10km(qreal _pxp10k); + + /*! \brief Re-implemented from QQuickPaintedItem to implement painting + * + * @param painter Pointer to the QPainter used for painting + */ + void paint(QPainter* painter) override; + + /*! \brief Determines whether the scale should be drawn vertically or horizontally + * + * This property defaults to 'false'. + */ + Q_PROPERTY(bool vertical READ vertical WRITE setVertical NOTIFY verticalChanged) + + /*! \brief Getter function for the property with the same name + * + * @returns Property vertical + */ + [[nodiscard]] auto vertical() const -> bool {return m_vertical;} + + /*! \brief Setter function for the property with the same name + * + * @param newVertical Property vertical + */ + void setVertical(bool newVertical); signals: - /*! \brief Notification signal for property with the same name */ - void pixelPer10kmChanged(); + /*! \brief Notification signal for property with the same name */ + void colorChanged(); - /*! \brief Notification signal for property with the same name */ - void useMetricUnitsChanged(); + /*! \brief Notification signal for property with the same name */ + void pixelPer10kmChanged(); - /*! \brief Notification signal for property with the same name */ - void verticalChanged(); + /*! \brief Notification signal for property with the same name */ + void verticalChanged(); private: - Q_DISABLE_COPY_MOVE(ScaleQuickItem) + Q_DISABLE_COPY_MOVE(ScaleQuickItem) - qreal _pixelPer10km {0.0}; - bool _vertical {false}; + qreal m_pixelPer10km {0.0}; + bool m_vertical {false}; + QColor m_color {Qt::black}; }; } // namespace Ui From ebdd1446a62b46bdb64dd1622f1a7a3e23b6e68d Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sat, 28 Sep 2024 21:21:36 +0200 Subject: [PATCH 60/64] Update ScaleQuickItem.cpp --- src/ui/ScaleQuickItem.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ui/ScaleQuickItem.cpp b/src/ui/ScaleQuickItem.cpp index 923d8911b..963ec796c 100644 --- a/src/ui/ScaleQuickItem.cpp +++ b/src/ui/ScaleQuickItem.cpp @@ -40,7 +40,7 @@ Ui::ScaleQuickItem::ScaleQuickItem(QQuickItem *parent) void Ui::ScaleQuickItem::paint(QPainter* painter) { // Safety check. Continue only if data provided is sane - if (m_pixelPer10km < 20) { + if (m_pixelPer10km < 2) { return; } @@ -113,9 +113,6 @@ void Ui::ScaleQuickItem::paint(QPainter* painter) int const baseY = m_vertical ? qRound((height() - sizeOfScaleInPix) / 2.0) : qRound(height()) - 8; - // Draw underlying white, slightly tranparent rectangle - // painter->fillRect(0, 0, static_cast(width()), static_cast(height()), QColor(0xff, 0xff, 0xff, 0xe0)); - // Draw scale if (m_vertical) { From 1912cb19bedcae2e0842f44d99416a1c7944ca31 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 29 Sep 2024 18:06:57 +0200 Subject: [PATCH 61/64] Fix NOTAM spelling --- src/qml/dialogs/NotamListDialog.qml | 4 ++-- src/qml/dialogs/WaypointDescription.qml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qml/dialogs/NotamListDialog.qml b/src/qml/dialogs/NotamListDialog.qml index 220fb9ded..62af12fd1 100644 --- a/src/qml/dialogs/NotamListDialog.qml +++ b/src/qml/dialogs/NotamListDialog.qml @@ -47,7 +47,7 @@ CenteringDialog { width: parent ? parent.width : undefined required property var model - property bool read: NotamProvider.isRead(delItem.model.modelData.number) + property bool read: NOTAMProvider.isRead(delItem.model.modelData.number) contentItem: Label { id: lbl @@ -96,7 +96,7 @@ CenteringDialog { onClicked: { read = !read - NotamProvider.setRead(delItem.model.modelData.number, read) + NOTAMProvider.setRead(delItem.model.modelData.number, read) if (read) seqA.start() } diff --git a/src/qml/dialogs/WaypointDescription.qml b/src/qml/dialogs/WaypointDescription.qml index db7cc1bad..14d315230 100644 --- a/src/qml/dialogs/WaypointDescription.qml +++ b/src/qml/dialogs/WaypointDescription.qml @@ -120,8 +120,8 @@ CenteringDialog { property notamList notamList: { // Mention lastUpdate, so we update whenever there is new data - NotamProvider.lastUpdate - return NotamProvider.notams(waypoint) + NOTAMProvider.lastUpdate + return NOTAMProvider.notams(waypoint) } visible: text !== "" From 02cb6029742affeba59a31b55b27bd61a9032e52 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Sun, 29 Sep 2024 18:12:55 +0200 Subject: [PATCH 62/64] Update MFM.qml --- src/qml/items/MFM.qml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/qml/items/MFM.qml b/src/qml/items/MFM.qml index c29a08113..356d830ef 100644 --- a/src/qml/items/MFM.qml +++ b/src/qml/items/MFM.qml @@ -142,7 +142,15 @@ Item { if (event.modifiers === Qt.NoModifier) { zoomLevelBehavior.enabled = false - flightMap.zoomLevel += event.angleDelta.y / 240 + var newZoom = flightMap.zoomLevel + event.angleDelta.y / 240 + if (newZoom < flightMap.minimumZoomLevel) { + newZoom = flightMap.minimumZoomLevel + } + if (newZoom > flightMap.maximumZoomLevel) { + newZoom = flightMap.maximumZoomLevel + } + flightMap.zoomLevel = newZoom + //flightMap.zoomLevel += event.angleDelta.y / 240 zoomLevelBehavior.enabled = true } else From a22c4f2812ef286d75181d97c724feefd0f35df1 Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Mon, 30 Sep 2024 08:05:43 +0200 Subject: [PATCH 63/64] Translations --- 3rdParty/enrouteText | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index b6a976bfe..3998002b6 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit b6a976bfea8370c038dadbba9f0a61b204df345d +Subproject commit 3998002b68c328af10945cc8aab05d3b902ca817 From 678271bdc148fb632e3b26e26b7db328b1cd7cea Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Tue, 1 Oct 2024 08:14:18 +0200 Subject: [PATCH 64/64] Bump version number, update translations --- 3rdParty/enrouteText | 2 +- CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/3rdParty/enrouteText b/3rdParty/enrouteText index 3998002b6..36f84448d 160000 --- a/3rdParty/enrouteText +++ b/3rdParty/enrouteText @@ -1 +1 @@ -Subproject commit 3998002b68c328af10945cc8aab05d3b902ca817 +Subproject commit 36f84448d9737f67333a94d6e67abb7e41cb4070 diff --git a/CMakeLists.txt b/CMakeLists.txt index 08baf7945..a18eac47d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ option(QTDEPLOY "Generate and run Qt deployment scripts" OFF) # Project data # -project(enroute VERSION 2.31.10) +project(enroute VERSION 2.31.11) set(APP_ID de.akaflieg_freiburg.enroute) set(DISPLAY_NAME "Enroute") math(EXPR PROJECT_VERSION_CODE 10000*${PROJECT_VERSION_MAJOR}+100*${PROJECT_VERSION_MINOR}+${PROJECT_VERSION_PATCH})