Enroute Flight Navigation
A navigation app for VFR pilots
FlightLog.h
1/***************************************************************************
2 * Copyright (C) 2026 by Stefan Kebekus *
3 * stefan.kebekus@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#pragma once
22
23#include <memory>
24
25#include <QGeoPath>
26#include <QObjectBindableProperty>
27#include <QQmlEngine>
28#include <QTimer>
29#include <QUuid>
30#include <QVariant>
31
32#include "GlobalObject.h"
33#include "flightlog/Flight.h"
34#include "flightlog/FlightDetector.h"
35#include "geomaps/Waypoint.h"
36
37using namespace Qt::Literals::StringLiterals;
38
39namespace Flightlog {
40
42class FlightRecorder;
43
54
55class FlightLog : public GlobalObject
56{
57 Q_OBJECT
58 QML_ELEMENT
59 QML_SINGLETON
60
61public:
62
63 //
64 // Constructors and Destructors
65 //
66
71 explicit FlightLog(QObject* parent = nullptr);
72
73 // deferred initialization
74 void deferredInitialization() override;
75
76 // No default constructor, important for QML singleton
77 explicit FlightLog() = delete;
78
80 ~FlightLog() override;
81
82 // factory function for QML singleton
83 static FlightLog* create(QQmlEngine* /*unused*/, QJSEngine* /*unused*/)
84 {
86 }
87
88
89 //
90 // PROPERTIES
91 //
92
94 Q_PROPERTY(QList<Flightlog::Flight> flights READ flights NOTIFY flightsChanged)
95 [[nodiscard]] auto flights() const -> QList<Flight> { return m_flights; }
96
99 [[nodiscard]] auto detectionState() const -> FlightDetector::DetectionState;
100
102 Q_PROPERTY(int count READ count NOTIFY flightsChanged)
103 [[nodiscard]] auto count() const -> int { return static_cast<int>(m_flights.value().size()); }
104
112 [[nodiscard]] auto displayedTrackPath() const -> QGeoPath;
113
120 [[nodiscard]] auto displayedTrackUuid() const -> QString;
121
127 Q_PROPERTY(bool trackRecording READ trackRecording WRITE setTrackRecording NOTIFY trackRecordingChanged)
128 [[nodiscard]] auto trackRecording() const -> bool;
129 void setTrackRecording(bool enabled);
130
136 Q_PROPERTY(bool showCurrentFlightTrace READ showCurrentFlightTrace WRITE setShowCurrentFlightTrace NOTIFY showCurrentFlightTraceChanged)
137 [[nodiscard]] auto showCurrentFlightTrace() const -> bool;
138 void setShowCurrentFlightTrace(bool enabled);
139
140
141 //
142 // Methods
143 //
144
152 Q_INVOKABLE void addFlight(const Flightlog::Flight& flight);
153
160 Q_INVOKABLE void removeFlight(const QString& uuid);
161
170 Q_INVOKABLE void removeFlights(const QStringList& uuids);
171
177 Q_INVOKABLE void clearFlights();
178
190 Q_INVOKABLE void updateFlight(const QString& uuid, const Flightlog::Flight& flight);
191
209 Q_INVOKABLE static Flightlog::Flight createFlight(
210 const QString& departureICAO,
211 const QString& arrivalICAO,
212 const QString& date,
213 const QString& offBlockTimeStr,
214 const QString& startTimeStr,
215 const QString& landingTimeStr,
216 const QString& onBlockTimeStr,
217 const QString& pilotName,
218 const QString& aircraftCallsign,
219 const QString& comments);
220
227 Q_INVOKABLE void endFlight();
228
238 Q_INVOKABLE QString lastArrivalICAO(const QString& aircraftCallsign) const;
239
251 Q_INVOKABLE static GeoMaps::Waypoint nearestAirfield(const QGeoCoordinate& position = {}, double proximityM = 5000.0);
252
261 [[nodiscard]] Q_INVOKABLE QByteArray exportToIGC(const QString& uuid) const;
262
271 [[nodiscard]] Q_INVOKABLE QByteArray exportToForeFlight(const QStringList& uuids) const;
272
281 [[nodiscard]] Q_INVOKABLE QByteArray exportToJSON(const QStringList& uuids) const;
282
294 [[nodiscard]] Q_INVOKABLE QString importFromJSON(const QString& fileName);
295
303 Q_INVOKABLE void removeTrack(const QString& uuid);
304
312 Q_INVOKABLE void showTrack(const QString& uuid);
313
315 Q_INVOKABLE void hideTrack();
316
317signals:
320
323
326
329
332
337 void takeoffDetected(const QString& time);
338
343 void landingDetected(const QString& time);
344
352 void saveError(const QString& message);
353
354private slots:
355 // Process position updates — delegates to the active FlightDetector
356 void onPositionUpdated();
357
358 // Handle detection state change — forwards signal
359 void onDetectionStateChanged();
360
361 // Handle auto-detection setting change — manages Android foreground service
362 void onAutoFlightDetectionChanged();
363
364#ifdef Q_OS_ANDROID
365 // Posted after a grace period when auto-detection is on but no position
366 // data is arriving. Cancelled when GPS resumes or detection is disabled.
367 void onReceivingPositionInfoChanged(bool receiving);
368#endif
369
370 // Handle takeoff detected by the FlightDetector
371 void onTakeoffDetected(const QString& departureICAO,
372 const QGeoCoordinate& departureCoordinate,
373 const QDateTime& startTime,
374 const QString& aircraftCallsign);
375
376 // Handle landing detected by the FlightDetector
377 void onLandingDetected(const QString& arrivalICAO,
378 const QGeoCoordinate& arrivalCoordinate,
379 const QDateTime& landingTime,
380 int landingCount);
381
382private:
383 Q_DISABLE_COPY_MOVE(FlightLog)
384
385 // Install signal connections for the given detector
386 void connectDetector(FlightDetector* detector);
387
388 // Load flights via m_storage
389 void load();
390
391 // Fill in a coordinate from its ICAO code via the GeoMapProvider, but
392 // only if the coordinate isn't already set (e.g. from a real GPS fix)
393 void resolveCoordinates(Flight& flight);
394
395 // Sort flights by startTime descending
396 void sortFlights(QList<Flight>& flights);
397
398 // Collect the flights matching the given UUID strings; returns all flights if the list is empty
399 [[nodiscard]] auto flightsForUuids(const QStringList& uuids) const -> QList<Flight>;
400
401 // Helper to parse a date+time string to QDateTime
402 static auto parseDateTime(const QString& date, const QString& timeStr) -> QDateTime;
403
404 Q_OBJECT_BINDABLE_PROPERTY(FlightLog, QList<Flightlog::Flight>, m_flights, &FlightLog::flightsChanged)
405
406 // UUID of the flight currently being recorded, or null if none
407 QUuid m_currentFlightUuid;
408
409 // Filename of the flight whose saved track is displayed, or empty
410 QString m_displayedTrackFile;
411
412 // Cached geo path for the displayed saved track
413 QGeoPath m_displayedTrackPath;
414
415 // The active flight detector (owned by this object)
416 FlightDetector* m_detector {nullptr};
417
418 // The flight recorder (owned by this object)
419 std::unique_ptr<FlightRecorder> m_recorder;
420
421 // The persistent storage backend (owned by this object)
422 std::unique_ptr<FlightLogStorage> m_storage;
423
424#ifdef Q_OS_ANDROID
425 // Tracks whether the Android foreground service is running
426 bool m_foregroundServiceRunning {false};
427
428 // Fires after a grace period to post the "no GPS" notification. Started
429 // when auto-detection is enabled with no position data; cancelled when
430 // position arrives or auto-detection is disabled.
431 QTimer m_noGPSTimer;
432#endif
433};
434
435} // namespace Flightlog
Abstract base class for automatic flight detection strategies.
DetectionState
Detection state for automatic takeoff/landing detection.
SQLite-backed storage for the flight log.
Q_INVOKABLE QByteArray exportToForeFlight(const QStringList &uuids) const
Generate ForeFlight CSV content for selected flights.
void flightsChanged()
Notifier signal.
Flightlog::FlightDetector::DetectionState detectionState
Current state of the automatic detection state machine.
Definition FlightLog.h:98
void displayedTrackPathChanged()
Notifier signal for displayedTrackPath and displayedTrackIndex.
void detectionStateChanged()
Notifier signal.
FlightLog(QObject *parent=nullptr)
Standard constructor.
Q_INVOKABLE QString importFromJSON(const QString &fileName)
Import flights from a JSON file.
void saveError(const QString &message)
Emitted when saving the flight log database fails.
Q_INVOKABLE QString lastArrivalICAO(const QString &aircraftCallsign) const
Find the last arrival ICAO for a given aircraft.
void takeoffDetected(const QString &time)
Emitted when a takeoff is detected.
Q_INVOKABLE QByteArray exportToJSON(const QStringList &uuids) const
Generate JSON content for selected flights.
int count
Number of recorded flights.
Definition FlightLog.h:102
Q_INVOKABLE void showTrack(const QString &uuid)
Show a flight's track on the map.
static Q_INVOKABLE GeoMaps::Waypoint nearestAirfield(const QGeoCoordinate &position={}, double proximityM=5000.0)
Find the nearest airfield within 5 km.
Q_INVOKABLE void removeFlights(const QStringList &uuids)
Remove multiple flights from the log by UUID.
Q_INVOKABLE void hideTrack()
Hide the currently displayed track from the map.
bool showCurrentFlightTrace
Whether the live trace of the current flight is shown on map.
Definition FlightLog.h:136
QString displayedTrackUuid
UUID of the flight whose track is displayed, or empty string if none.
Definition FlightLog.h:119
Q_INVOKABLE void endFlight()
Manually end the current in-flight recording.
void trackRecordingChanged()
Notifier signal.
void deferredInitialization() override
Non-constructor initialization.
Q_INVOKABLE void clearFlights()
Remove all flights from the log.
void showCurrentFlightTraceChanged()
Notifier signal.
Q_INVOKABLE void removeTrack(const QString &uuid)
Delete the recorded track for a flight.
~FlightLog() override
Standard destructor.
bool trackRecording
Whether GPS track recording is enabled.
Definition FlightLog.h:127
static Q_INVOKABLE Flightlog::Flight createFlight(const QString &departureICAO, const QString &arrivalICAO, const QString &date, const QString &offBlockTimeStr, const QString &startTimeStr, const QString &landingTimeStr, const QString &onBlockTimeStr, const QString &pilotName, const QString &aircraftCallsign, const QString &comments)
Create a Flight value from individual field strings.
QList< Flightlog::Flight > flights
List of all recorded flights, newest first.
Definition FlightLog.h:94
Q_INVOKABLE void addFlight(const Flightlog::Flight &flight)
Add a new flight to the log.
Q_INVOKABLE void updateFlight(const QString &uuid, const Flightlog::Flight &flight)
Update an existing flight in the log.
void landingDetected(const QString &time)
Emitted when a landing is detected.
Q_INVOKABLE QByteArray exportToIGC(const QString &uuid) const
Get IGC track content for a flight.
Q_INVOKABLE void removeFlight(const QString &uuid)
Remove a flight from the log by UUID.
QGeoPath displayedTrackPath
Coordinates of the track currently displayed on the map.
Definition FlightLog.h:111
GPS track recorder and IGC file manager.
A single flight log entry.
Definition Flight.h:40
GlobalObject(QObject *parent=nullptr)
Standard constructor.
static Q_INVOKABLE Flightlog::FlightLog * flightLog()
Pointer to appplication-wide static FlightLog instance.