2017-04-27 18:24:53 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "core/gpslocation.h"
|
|
|
|
#include "qt-models/gpslistmodel.h"
|
|
|
|
#include "core/pref.h"
|
2018-06-03 20:15:19 +00:00
|
|
|
#include "core/qthelper.h"
|
2018-09-12 10:45:19 +00:00
|
|
|
#include "core/settings/qPrefLocationService.h"
|
2015-11-11 23:19:09 +00:00
|
|
|
#include <time.h>
|
2015-11-14 01:21:43 +00:00
|
|
|
#include <unistd.h>
|
2015-11-11 18:52:52 +00:00
|
|
|
#include <QDebug>
|
2015-11-11 23:19:09 +00:00
|
|
|
#include <QVariant>
|
2015-11-14 01:21:43 +00:00
|
|
|
#include <QUrlQuery>
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QTimer>
|
2015-11-18 21:14:19 +00:00
|
|
|
|
2015-12-02 22:30:47 +00:00
|
|
|
GpsLocation *GpsLocation::m_Instance = NULL;
|
|
|
|
|
2016-04-18 05:41:30 +00:00
|
|
|
GpsLocation::GpsLocation(void (*showMsgCB)(const char *), QObject *parent) :
|
|
|
|
QObject(parent),
|
|
|
|
m_GpsSource(0),
|
|
|
|
waitingForPosition(false),
|
|
|
|
haveSource(UNKNOWN)
|
2015-11-11 18:52:52 +00:00
|
|
|
{
|
2015-12-02 22:30:47 +00:00
|
|
|
Q_ASSERT_X(m_Instance == NULL, "GpsLocation", "GpsLocation recreated");
|
|
|
|
m_Instance = this;
|
2015-11-19 02:10:58 +00:00
|
|
|
showMessageCB = showMsgCB;
|
2015-11-12 21:04:23 +00:00
|
|
|
// create a QSettings object that's separate from the main application settings
|
2015-11-13 19:55:39 +00:00
|
|
|
geoSettings = new QSettings(QSettings::NativeFormat, QSettings::UserScope,
|
|
|
|
QString("org.subsurfacedivelog"), QString("subsurfacelocation"), this);
|
2015-11-18 22:44:07 +00:00
|
|
|
userAgent = getUserAgent();
|
2016-04-18 05:41:30 +00:00
|
|
|
(void)getGpsSource();
|
2016-01-11 01:22:20 +00:00
|
|
|
loadFromStorage();
|
2018-09-12 10:45:19 +00:00
|
|
|
|
|
|
|
// register changes in time threshold
|
2018-09-24 08:00:55 +00:00
|
|
|
connect(qPrefLocationService::instance(), SIGNAL(time_thresholdChanged(int)), this, SLOT(setGpsTimeThreshold(int)));
|
2015-11-11 18:52:52 +00:00
|
|
|
}
|
2015-11-11 20:34:56 +00:00
|
|
|
|
2015-12-02 22:30:47 +00:00
|
|
|
GpsLocation *GpsLocation::instance()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_Instance != NULL);
|
|
|
|
|
|
|
|
return m_Instance;
|
|
|
|
}
|
|
|
|
|
2017-05-06 18:06:18 +00:00
|
|
|
bool GpsLocation::hasInstance()
|
|
|
|
{
|
|
|
|
return m_Instance != NULL;
|
|
|
|
}
|
|
|
|
|
2015-12-02 22:30:47 +00:00
|
|
|
GpsLocation::~GpsLocation()
|
|
|
|
{
|
|
|
|
m_Instance = NULL;
|
|
|
|
}
|
|
|
|
|
2017-07-25 09:44:30 +00:00
|
|
|
void GpsLocation::setGpsTimeThreshold(int seconds)
|
|
|
|
{
|
|
|
|
if (m_GpsSource) {
|
|
|
|
m_GpsSource->setUpdateInterval(seconds * 1000);
|
2018-04-14 18:06:18 +00:00
|
|
|
status(QString("Set GPS service update interval to %1 s").arg(m_GpsSource->updateInterval() / 1000));
|
2017-07-25 09:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-30 18:58:18 +00:00
|
|
|
QGeoPositionInfoSource *GpsLocation::getGpsSource()
|
|
|
|
{
|
2016-04-18 05:41:30 +00:00
|
|
|
if (haveSource == NOGPS)
|
|
|
|
return 0;
|
|
|
|
|
2016-01-02 01:19:28 +00:00
|
|
|
if (!m_GpsSource) {
|
|
|
|
m_GpsSource = QGeoPositionInfoSource::createDefaultSource(this);
|
|
|
|
if (m_GpsSource != 0) {
|
2016-04-18 05:50:33 +00:00
|
|
|
#if defined(Q_OS_IOS)
|
|
|
|
// at least Qt 5.6.0 isn't doing things right on iOS - it MUST check for permission before
|
|
|
|
// accessing the position source
|
|
|
|
// I have a hacked version of Qt 5.6.0 that I will build the iOS binaries with for now;
|
|
|
|
// this test below righ after creating the source checks if the location service is disabled
|
|
|
|
// and set's an error right when the position source is created to indicate this
|
|
|
|
if (m_GpsSource->error() == QGeoPositionInfoSource::AccessError) {
|
|
|
|
haveSource = NOGPS;
|
|
|
|
emit haveSourceChanged();
|
|
|
|
m_GpsSource = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2016-04-18 05:41:30 +00:00
|
|
|
haveSource = (m_GpsSource->supportedPositioningMethods() & QGeoPositionInfoSource::SatellitePositioningMethods) ? HAVEGPS : NOGPS;
|
|
|
|
emit haveSourceChanged();
|
2015-12-02 22:30:47 +00:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
|
|
|
if (verbose)
|
|
|
|
#endif
|
2016-03-24 15:49:45 +00:00
|
|
|
status(QString("Created position source %1").arg(m_GpsSource->sourceName()));
|
2016-01-02 01:19:28 +00:00
|
|
|
connect(m_GpsSource, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(newPosition(QGeoPositionInfo)));
|
|
|
|
connect(m_GpsSource, SIGNAL(updateTimeout()), this, SLOT(updateTimeout()));
|
2016-04-18 05:47:53 +00:00
|
|
|
connect(m_GpsSource, SIGNAL(error(QGeoPositionInfoSource::Error)), this, SLOT(positionSourceError(QGeoPositionInfoSource::Error)));
|
2017-07-25 09:44:30 +00:00
|
|
|
setGpsTimeThreshold(prefs.time_threshold);
|
2015-11-30 18:58:18 +00:00
|
|
|
} else {
|
2015-12-18 22:37:01 +00:00
|
|
|
#ifdef SUBSURFACE_MOBILE
|
2015-11-30 18:58:18 +00:00
|
|
|
status("don't have GPS source");
|
2015-12-18 22:37:01 +00:00
|
|
|
#endif
|
2016-04-18 05:41:30 +00:00
|
|
|
haveSource = NOGPS;
|
|
|
|
emit haveSourceChanged();
|
2015-11-30 18:58:18 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-02 01:19:28 +00:00
|
|
|
return m_GpsSource;
|
2015-11-30 18:58:18 +00:00
|
|
|
}
|
|
|
|
|
2015-11-19 02:56:50 +00:00
|
|
|
bool GpsLocation::hasLocationsSource()
|
|
|
|
{
|
2016-04-18 05:41:30 +00:00
|
|
|
(void)getGpsSource();
|
|
|
|
return haveSource == HAVEGPS;
|
2015-11-19 02:56:50 +00:00
|
|
|
}
|
|
|
|
|
2015-11-11 20:34:56 +00:00
|
|
|
void GpsLocation::serviceEnable(bool toggle)
|
|
|
|
{
|
2015-11-30 18:58:18 +00:00
|
|
|
QGeoPositionInfoSource *gpsSource = getGpsSource();
|
2016-04-18 05:41:30 +00:00
|
|
|
if (haveSource != HAVEGPS) {
|
2015-11-11 23:19:09 +00:00
|
|
|
if (toggle)
|
|
|
|
status("Can't start location service, no location source available");
|
2015-11-11 20:34:56 +00:00
|
|
|
return;
|
2015-11-11 23:19:09 +00:00
|
|
|
}
|
2015-11-11 20:34:56 +00:00
|
|
|
if (toggle) {
|
|
|
|
gpsSource->startUpdates();
|
2016-03-24 15:49:45 +00:00
|
|
|
status(QString("Starting Subsurface GPS service with update interval %1").arg(gpsSource->updateInterval()));
|
2015-11-11 20:34:56 +00:00
|
|
|
} else {
|
|
|
|
gpsSource->stopUpdates();
|
|
|
|
status("Stopping Subsurface GPS service");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-02 01:21:30 +00:00
|
|
|
QString GpsLocation::currentPosition()
|
|
|
|
{
|
2018-04-14 18:06:18 +00:00
|
|
|
qDebug() << "current position requested";
|
2016-01-02 01:21:30 +00:00
|
|
|
if (!hasLocationsSource())
|
2018-04-14 18:06:18 +00:00
|
|
|
return tr("Unknown GPS location (no GPS source)");
|
2018-04-14 19:00:57 +00:00
|
|
|
if (m_trackers.count()) {
|
|
|
|
QDateTime lastFixTime = QDateTime().fromMSecsSinceEpoch((m_trackers.lastKey() - gettimezoneoffset(m_trackers.lastKey())) * 1000);
|
|
|
|
QDateTime now = QDateTime::currentDateTime();
|
|
|
|
int delta = lastFixTime.secsTo(now);
|
|
|
|
qDebug() << "lastFixTime" << lastFixTime.toString() << "now" << now.toString() << "delta" << delta;
|
|
|
|
if (delta < 300) {
|
|
|
|
// we can simply use the last position that we tracked
|
|
|
|
gpsTracker gt = m_trackers.last();
|
2018-10-20 18:12:15 +00:00
|
|
|
QString gpsString = printGPSCoords(>.location);
|
2018-04-14 19:00:57 +00:00
|
|
|
qDebug() << "returning last position" << gpsString;
|
|
|
|
return gpsString;
|
|
|
|
} else {
|
|
|
|
qDebug() << "last position saved was too old" << lastFixTime.toString();
|
|
|
|
}
|
2016-01-02 01:21:30 +00:00
|
|
|
}
|
|
|
|
qDebug() << "requesting new GPS position";
|
|
|
|
m_GpsSource->requestUpdate();
|
|
|
|
// ok, we need to get the current position and somehow in the callback update the location in the QML UI
|
|
|
|
// punting right now
|
|
|
|
waitingForPosition = true;
|
QML UI: rewrite the commitChanges function
I couldn't figure out how to break this down into small, useful commits.
Part of the problem is that I kept going while working on this and as you
can see from looking at the commit, diff tries so hard to find small code
fragments that moved around, that the diff overall becomes quite
unreadable and it seemed impossible to recreate the sequence of steps
after the fact.
It all started with adding the parsing for the GPS coordinates. But while
testing that code I found several issues with the rest of the function.
Most importantly it seemed ridiculous that we carefully tried to match the
texts that the DiveObjectHelper would create for the various fields,
instead of just using the DiveObjectHelper to do just that. And once I had
converted that I once again realized just how long and hard to understand
that function was getting and decided to break out some of the more
complex parts into their own helper functions.
But of course all this didn't happen in this logical, structured, ordered
way. Instead I did all of these things at the same time, testing,
rearranging, etc.
So in the end I went with one BIG commit that does all of this in one fell
swoop.
This adds four helper functions to deal with start time/date, duration,
location and gps coordinates, and depth of the dive.
To avoid mistakes when dealing with the GPS coordinates, there's another
helper to encapsulate the creation of the dive site and we switched to a
current GPS location.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-15 13:01:14 +00:00
|
|
|
return GPS_CURRENT_POS;
|
2016-01-02 01:21:30 +00:00
|
|
|
}
|
|
|
|
|
2015-11-11 18:52:52 +00:00
|
|
|
void GpsLocation::newPosition(QGeoPositionInfo pos)
|
|
|
|
{
|
2016-03-24 18:50:32 +00:00
|
|
|
int64_t lastTime = 0;
|
2015-11-11 23:44:58 +00:00
|
|
|
QGeoCoordinate lastCoord;
|
2016-01-09 22:07:58 +00:00
|
|
|
int nr = m_trackers.count();
|
2015-11-11 23:44:58 +00:00
|
|
|
if (nr) {
|
2016-01-09 22:07:58 +00:00
|
|
|
gpsTracker gt = m_trackers.last();
|
2018-10-20 18:12:15 +00:00
|
|
|
lastCoord.setLatitude(gt.location.lat.udeg / 1000000.0);
|
|
|
|
lastCoord.setLongitude(gt.location.lon.udeg / 1000000.0);
|
2016-01-09 22:07:58 +00:00
|
|
|
lastTime = gt.when;
|
2015-11-11 23:44:58 +00:00
|
|
|
}
|
2016-01-02 01:20:30 +00:00
|
|
|
// if we are waiting for a position update or
|
2015-11-13 20:01:01 +00:00
|
|
|
// if we have no record stored or if at least the configured minimum
|
|
|
|
// time has passed or we moved at least the configured minimum distance
|
2016-03-24 18:50:32 +00:00
|
|
|
int64_t delta = (int64_t)pos.timestamp().toTime_t() + gettimezoneoffset() - lastTime;
|
|
|
|
if (!nr || waitingForPosition || delta > prefs.time_threshold ||
|
2015-11-14 17:10:06 +00:00
|
|
|
lastCoord.distanceTo(pos.coordinate()) > prefs.distance_threshold) {
|
2018-04-14 18:06:18 +00:00
|
|
|
QString msg("received new position %1 after delta %2 threshold %3 (now %4 last %5)");
|
2018-04-15 21:43:26 +00:00
|
|
|
status(qPrintable(msg.arg(pos.coordinate().toString()).arg(delta).arg(prefs.time_threshold).arg(pos.timestamp().toString()).arg(QDateTime().fromMSecsSinceEpoch(lastTime * 1000).toString())));
|
2016-01-02 01:20:30 +00:00
|
|
|
waitingForPosition = false;
|
2018-04-14 18:07:41 +00:00
|
|
|
acquiredPosition();
|
2016-01-09 22:07:58 +00:00
|
|
|
gpsTracker gt;
|
|
|
|
gt.when = pos.timestamp().toTime_t();
|
|
|
|
gt.when += gettimezoneoffset(gt.when);
|
2018-10-20 18:12:15 +00:00
|
|
|
gt.location = create_location(pos.coordinate().latitude(), pos.coordinate().longitude());
|
2016-01-09 22:07:58 +00:00
|
|
|
addFixToStorage(gt);
|
2018-04-14 18:06:18 +00:00
|
|
|
gpsTracker gtNew = m_trackers.last();
|
2018-04-15 21:43:26 +00:00
|
|
|
qDebug() << "newest fix is now at" << QDateTime().fromMSecsSinceEpoch(gtNew.when - gettimezoneoffset(gtNew.when) * 1000).toString();
|
2015-11-11 23:44:58 +00:00
|
|
|
}
|
2015-11-11 18:50:55 +00:00
|
|
|
}
|
|
|
|
|
2015-11-11 18:52:52 +00:00
|
|
|
void GpsLocation::updateTimeout()
|
|
|
|
{
|
2015-11-11 19:16:59 +00:00
|
|
|
status("request to get new position timed out");
|
|
|
|
}
|
|
|
|
|
2016-04-18 05:47:53 +00:00
|
|
|
void GpsLocation::positionSourceError(QGeoPositionInfoSource::Error)
|
|
|
|
{
|
|
|
|
status("error receiving a GPS location");
|
|
|
|
haveSource = NOGPS;
|
|
|
|
emit haveSourceChanged();
|
|
|
|
}
|
|
|
|
|
2015-11-11 19:16:59 +00:00
|
|
|
void GpsLocation::status(QString msg)
|
|
|
|
{
|
|
|
|
qDebug() << msg;
|
2015-11-19 02:10:58 +00:00
|
|
|
if (showMessageCB)
|
|
|
|
(*showMessageCB)(qPrintable(msg));
|
2015-11-11 18:52:52 +00:00
|
|
|
}
|
2015-11-12 22:57:27 +00:00
|
|
|
|
2015-11-13 17:17:13 +00:00
|
|
|
int GpsLocation::getGpsNum() const
|
|
|
|
{
|
2016-01-09 22:07:58 +00:00
|
|
|
return m_trackers.count();
|
2015-11-13 17:17:13 +00:00
|
|
|
}
|
|
|
|
|
2016-01-09 22:07:58 +00:00
|
|
|
static void copy_gps_location(struct gpsTracker &gps, struct dive *d)
|
2015-11-12 22:57:27 +00:00
|
|
|
{
|
|
|
|
struct dive_site *ds = get_dive_site_by_uuid(d->dive_site_uuid);
|
2016-01-11 18:02:58 +00:00
|
|
|
if (!ds) {
|
|
|
|
d->dive_site_uuid = create_dive_site(qPrintable(gps.name), gps.when);
|
|
|
|
ds = get_dive_site_by_uuid(d->dive_site_uuid);
|
|
|
|
}
|
2018-10-20 18:12:15 +00:00
|
|
|
ds->location = gps.location;
|
2015-11-12 22:57:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define SAME_GROUP 6 * 3600 /* six hours */
|
2017-12-12 08:29:03 +00:00
|
|
|
#define SET_LOCATION(_dive, _gpsfix, _mark) \
|
|
|
|
{ \
|
|
|
|
copy_gps_location(_gpsfix, _dive); \
|
|
|
|
changed = true; \
|
|
|
|
last = _mark; \
|
|
|
|
}
|
|
|
|
|
2016-01-11 03:34:21 +00:00
|
|
|
bool GpsLocation::applyLocations()
|
2015-11-12 22:57:27 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
bool changed = false;
|
|
|
|
int last = 0;
|
2016-01-09 22:07:58 +00:00
|
|
|
int cnt = m_trackers.count();
|
2015-11-12 22:57:27 +00:00
|
|
|
if (cnt == 0)
|
2016-01-11 03:34:21 +00:00
|
|
|
return false;
|
2015-11-12 22:57:27 +00:00
|
|
|
|
|
|
|
// create a table with the GPS information
|
2016-01-09 22:07:58 +00:00
|
|
|
QList<struct gpsTracker> gpsTable = m_trackers.values();
|
2015-11-12 22:57:27 +00:00
|
|
|
|
|
|
|
// now walk the dive table and see if we can fill in missing gps data
|
|
|
|
struct dive *d;
|
|
|
|
for_each_dive(i, d) {
|
|
|
|
if (dive_has_gps_location(d))
|
|
|
|
continue;
|
|
|
|
for (int j = last; j < cnt; j++) {
|
|
|
|
if (time_during_dive_with_offset(d, gpsTable[j].when, SAME_GROUP)) {
|
|
|
|
if (verbose)
|
2015-11-14 01:21:43 +00:00
|
|
|
qDebug() << "processing gpsFix @" << get_dive_date_string(gpsTable[j].when) <<
|
2015-11-12 22:57:27 +00:00
|
|
|
"which is withing six hours of dive from" <<
|
|
|
|
get_dive_date_string(d->when) << "until" <<
|
2017-09-30 16:00:34 +00:00
|
|
|
get_dive_date_string(dive_endtime(d));
|
2015-11-12 22:57:27 +00:00
|
|
|
/*
|
|
|
|
* If position is fixed during dive. This is the good one.
|
|
|
|
* Asign and mark position, and end gps_location loop
|
|
|
|
*/
|
|
|
|
if (time_during_dive_with_offset(d, gpsTable[j].when, 0)) {
|
|
|
|
if (verbose)
|
2015-11-14 01:21:43 +00:00
|
|
|
qDebug() << "gpsFix is during the dive, pick that one";
|
2017-12-12 08:29:03 +00:00
|
|
|
SET_LOCATION(d, gpsTable[j], j);
|
2015-11-12 22:57:27 +00:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If it is not, check if there are more position fixes in SAME_GROUP range
|
|
|
|
*/
|
|
|
|
if (j + 1 < cnt && time_during_dive_with_offset(d, gpsTable[j+1].when, SAME_GROUP)) {
|
|
|
|
if (verbose)
|
|
|
|
qDebug() << "look at the next gps fix @" << get_dive_date_string(gpsTable[j+1].when);
|
|
|
|
/* we know the gps fixes are sorted; if they are both before the dive, ignore the first,
|
|
|
|
* if theay are both after the dive, take the first,
|
|
|
|
* if the first is before and the second is after, take the closer one */
|
|
|
|
if (gpsTable[j+1].when < d->when) {
|
|
|
|
if (verbose)
|
|
|
|
qDebug() << "which is closer to the start of the dive, do continue with that";
|
|
|
|
continue;
|
2017-09-30 16:00:34 +00:00
|
|
|
} else if (gpsTable[j].when > dive_endtime(d)) {
|
2015-11-12 22:57:27 +00:00
|
|
|
if (verbose)
|
|
|
|
qDebug() << "which is even later after the end of the dive, so pick the previous one";
|
2017-12-12 08:29:03 +00:00
|
|
|
SET_LOCATION(d, gpsTable[j], j);
|
2015-11-12 22:57:27 +00:00
|
|
|
break;
|
|
|
|
} else {
|
2015-11-14 01:21:43 +00:00
|
|
|
/* ok, gpsFix is before, nextgpsFix is after */
|
2017-09-30 16:00:34 +00:00
|
|
|
if (d->when - gpsTable[j].when <= gpsTable[j+1].when - dive_endtime(d)) {
|
2015-11-12 22:57:27 +00:00
|
|
|
if (verbose)
|
|
|
|
qDebug() << "pick the one before as it's closer to the start";
|
2017-12-12 08:29:03 +00:00
|
|
|
SET_LOCATION(d, gpsTable[j], j);
|
2015-11-12 22:57:27 +00:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (verbose)
|
|
|
|
qDebug() << "pick the one after as it's closer to the start";
|
2017-12-12 08:29:03 +00:00
|
|
|
SET_LOCATION(d, gpsTable[j + 1], j + 1);
|
2015-11-12 22:57:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If no more positions in range, the actual is the one. Asign, mark and end loop.
|
|
|
|
*/
|
|
|
|
} else {
|
|
|
|
if (verbose)
|
|
|
|
qDebug() << "which seems to be the best one for this dive, so pick it";
|
2017-12-12 08:29:03 +00:00
|
|
|
SET_LOCATION(d, gpsTable[j], j);
|
2015-11-12 22:57:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* If position is out of SAME_GROUP range and in the future, mark position for
|
|
|
|
* next dive iteration and end the gps_location loop
|
|
|
|
*/
|
2017-09-30 16:00:34 +00:00
|
|
|
if (gpsTable[j].when >= dive_endtime(d) + SAME_GROUP) {
|
2015-11-12 22:57:27 +00:00
|
|
|
last = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2015-11-19 03:19:56 +00:00
|
|
|
if (changed)
|
|
|
|
mark_divelist_changed(true);
|
2016-01-11 03:34:21 +00:00
|
|
|
return changed;
|
2015-11-12 22:57:27 +00:00
|
|
|
}
|
2015-11-14 01:20:45 +00:00
|
|
|
|
2016-01-09 22:07:58 +00:00
|
|
|
QMap<qint64, gpsTracker> GpsLocation::currentGPSInfo() const
|
2016-01-09 07:18:41 +00:00
|
|
|
{
|
2016-01-09 22:07:58 +00:00
|
|
|
return m_trackers;
|
2016-01-09 07:18:41 +00:00
|
|
|
}
|
|
|
|
|
2016-01-11 01:22:20 +00:00
|
|
|
void GpsLocation::loadFromStorage()
|
|
|
|
{
|
|
|
|
int nr = geoSettings->value(QString("count")).toInt();
|
|
|
|
for (int i = 0; i < nr; i++) {
|
|
|
|
struct gpsTracker gt;
|
|
|
|
gt.when = geoSettings->value(QString("gpsFix%1_time").arg(i)).toLongLong();
|
2018-10-20 18:12:15 +00:00
|
|
|
gt.location.lat.udeg = geoSettings->value(QString("gpsFix%1_lat").arg(i)).toInt();
|
|
|
|
gt.location.lon.udeg = geoSettings->value(QString("gpsFix%1_lon").arg(i)).toInt();
|
2016-01-11 01:22:20 +00:00
|
|
|
gt.name = geoSettings->value(QString("gpsFix%1_name").arg(i)).toString();
|
|
|
|
gt.idx = i;
|
|
|
|
m_trackers.insert(gt.when, gt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GpsLocation::replaceFixToStorage(gpsTracker >)
|
|
|
|
{
|
|
|
|
if (!m_trackers.keys().contains(gt.when)) {
|
|
|
|
addFixToStorage(gt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gpsTracker replacedTracker = m_trackers.value(gt.when);
|
|
|
|
geoSettings->setValue(QString("gpsFix%1_time").arg(replacedTracker.idx), gt.when);
|
2018-10-20 18:12:15 +00:00
|
|
|
geoSettings->setValue(QString("gpsFix%1_lat").arg(replacedTracker.idx), gt.location.lat.udeg);
|
|
|
|
geoSettings->setValue(QString("gpsFix%1_lon").arg(replacedTracker.idx), gt.location.lon.udeg);
|
2016-01-11 01:22:20 +00:00
|
|
|
geoSettings->setValue(QString("gpsFix%1_name").arg(replacedTracker.idx), gt.name);
|
2018-10-20 18:12:15 +00:00
|
|
|
replacedTracker.location = gt.location;
|
2016-01-11 01:22:20 +00:00
|
|
|
replacedTracker.name = gt.name;
|
|
|
|
}
|
|
|
|
|
2016-01-09 22:07:58 +00:00
|
|
|
void GpsLocation::addFixToStorage(gpsTracker >)
|
2016-01-08 05:34:21 +00:00
|
|
|
{
|
2016-01-09 22:07:58 +00:00
|
|
|
int nr = m_trackers.count();
|
|
|
|
geoSettings->setValue("count", nr + 1);
|
|
|
|
geoSettings->setValue(QString("gpsFix%1_time").arg(nr), gt.when);
|
2018-10-20 18:12:15 +00:00
|
|
|
geoSettings->setValue(QString("gpsFix%1_lat").arg(nr), gt.location.lat.udeg);
|
|
|
|
geoSettings->setValue(QString("gpsFix%1_lon").arg(nr), gt.location.lon.udeg);
|
2016-01-09 22:07:58 +00:00
|
|
|
geoSettings->setValue(QString("gpsFix%1_name").arg(nr), gt.name);
|
|
|
|
gt.idx = nr;
|
|
|
|
geoSettings->sync();
|
|
|
|
m_trackers.insert(gt.when, gt);
|
2016-01-08 05:34:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-09 22:07:58 +00:00
|
|
|
void GpsLocation::deleteFixFromStorage(gpsTracker >)
|
2016-01-09 07:18:41 +00:00
|
|
|
{
|
2016-01-09 22:07:58 +00:00
|
|
|
qint64 when = gt.when;
|
|
|
|
int cnt = m_trackers.count();
|
|
|
|
if (cnt == 0 || !m_trackers.keys().contains(when)) {
|
|
|
|
qDebug() << "no gps fix with timestamp" << when;
|
|
|
|
return;
|
|
|
|
}
|
2016-03-07 00:11:06 +00:00
|
|
|
if (geoSettings->value(QString("gpsFix%1_time").arg(gt.idx)).toLongLong() != when) {
|
2016-01-09 22:07:58 +00:00
|
|
|
qDebug() << "uh oh - index for tracker has gotten out of sync...";
|
|
|
|
return;
|
2016-01-09 07:18:41 +00:00
|
|
|
}
|
2016-01-09 22:07:58 +00:00
|
|
|
if (cnt > 1) {
|
|
|
|
// now we move the last tracker into that spot (so our settings stay consecutive)
|
|
|
|
// and delete the last settings entry
|
|
|
|
when = geoSettings->value(QString("gpsFix%1_time").arg(cnt - 1)).toLongLong();
|
|
|
|
struct gpsTracker movedTracker = m_trackers.value(when);
|
|
|
|
movedTracker.idx = gt.idx;
|
2016-01-11 01:39:13 +00:00
|
|
|
m_trackers.remove(movedTracker.when);
|
|
|
|
m_trackers.insert(movedTracker.when, movedTracker);
|
2016-01-09 22:07:58 +00:00
|
|
|
geoSettings->setValue(QString("gpsFix%1_time").arg(movedTracker.idx), when);
|
2018-10-20 18:12:15 +00:00
|
|
|
geoSettings->setValue(QString("gpsFix%1_lat").arg(movedTracker.idx), movedTracker.location.lat.udeg);
|
|
|
|
geoSettings->setValue(QString("gpsFix%1_lon").arg(movedTracker.idx), movedTracker.location.lon.udeg);
|
2016-01-09 22:07:58 +00:00
|
|
|
geoSettings->setValue(QString("gpsFix%1_name").arg(movedTracker.idx), movedTracker.name);
|
2016-01-09 07:18:41 +00:00
|
|
|
geoSettings->remove(QString("gpsFix%1_lat").arg(cnt - 1));
|
|
|
|
geoSettings->remove(QString("gpsFix%1_lon").arg(cnt - 1));
|
|
|
|
geoSettings->remove(QString("gpsFix%1_time").arg(cnt - 1));
|
|
|
|
geoSettings->remove(QString("gpsFix%1_name").arg(cnt - 1));
|
|
|
|
}
|
2016-01-09 22:07:58 +00:00
|
|
|
geoSettings->setValue("count", cnt - 1);
|
|
|
|
geoSettings->sync();
|
2016-01-11 01:39:13 +00:00
|
|
|
m_trackers.remove(gt.when);
|
2016-01-09 22:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GpsLocation::deleteGpsFix(qint64 when)
|
|
|
|
{
|
2017-12-19 23:01:42 +00:00
|
|
|
auto it = m_trackers.find(when);
|
|
|
|
if (it == m_trackers.end()) {
|
|
|
|
qWarning() << "GpsLocation::deleteGpsFix(): can't find tracker for timestamp " << when;
|
2016-01-09 22:07:58 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-12-19 23:01:42 +00:00
|
|
|
struct gpsTracker deletedTracker = *it;
|
2016-01-09 22:07:58 +00:00
|
|
|
deleteFixFromStorage(deletedTracker);
|
2016-01-11 01:39:13 +00:00
|
|
|
m_deletedTrackers.append(deletedTracker);
|
2016-01-09 07:18:41 +00:00
|
|
|
}
|
|
|
|
|
2017-05-20 20:03:09 +00:00
|
|
|
#ifdef SUBSURFACE_MOBILE
|
2015-11-14 01:20:45 +00:00
|
|
|
void GpsLocation::clearGpsData()
|
|
|
|
{
|
2016-01-09 22:07:58 +00:00
|
|
|
m_trackers.clear();
|
2015-11-14 01:20:45 +00:00
|
|
|
geoSettings->clear();
|
|
|
|
geoSettings->sync();
|
|
|
|
}
|
2017-05-20 20:03:09 +00:00
|
|
|
#endif
|
2015-11-14 01:21:43 +00:00
|
|
|
|
2018-05-21 15:36:04 +00:00
|
|
|
void GpsLocation::postError(QNetworkReply::NetworkError)
|
2015-11-14 01:21:43 +00:00
|
|
|
{
|
|
|
|
status(QString("error when sending a GPS fix: %1").arg(reply->errorString()));
|
|
|
|
}
|