summaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/geoservices/esri/esri.pro10
-rw-r--r--src/plugins/geoservices/esri/esri_plugin.json3
-rw-r--r--src/plugins/geoservices/esri/geocodereply_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/geocodereply_esri.h2
-rw-r--r--src/plugins/geoservices/esri/geocodingmanagerengine_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/geocodingmanagerengine_esri.h2
-rw-r--r--src/plugins/geoservices/esri/geomapsource.cpp2
-rw-r--r--src/plugins/geoservices/esri/geomapsource.h2
-rw-r--r--src/plugins/geoservices/esri/georoutejsonparser_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/georoutejsonparser_esri.h2
-rw-r--r--src/plugins/geoservices/esri/georoutereply_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/georoutereply_esri.h2
-rw-r--r--src/plugins/geoservices/esri/georoutingmanagerengine_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/georoutingmanagerengine_esri.h2
-rw-r--r--src/plugins/geoservices/esri/geoserviceproviderfactory_esri.cpp9
-rw-r--r--src/plugins/geoservices/esri/geoserviceproviderfactory_esri.h2
-rw-r--r--src/plugins/geoservices/esri/geotiledmap_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/geotiledmap_esri.h2
-rw-r--r--src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp8
-rw-r--r--src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.h2
-rw-r--r--src/plugins/geoservices/esri/geotiledmapreply_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/geotiledmapreply_esri.h2
-rw-r--r--src/plugins/geoservices/esri/geotilefetcher_esri.cpp2
-rw-r--r--src/plugins/geoservices/esri/geotilefetcher_esri.h2
-rw-r--r--src/plugins/geoservices/esri/placecategoriesreply_esri.cpp65
-rw-r--r--src/plugins/geoservices/esri/placecategoriesreply_esri.h61
-rw-r--r--src/plugins/geoservices/esri/placemanagerengine_esri.cpp369
-rw-r--r--src/plugins/geoservices/esri/placemanagerengine_esri.h109
-rw-r--r--src/plugins/geoservices/esri/placesearchreply_esri.cpp223
-rw-r--r--src/plugins/geoservices/esri/placesearchreply_esri.h78
-rw-r--r--src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp24
-rw-r--r--src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp7
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp49
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h2
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h13
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp65
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h1
-rw-r--r--src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp6
-rw-r--r--src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp71
-rw-r--r--src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h13
-rw-r--r--src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp10
-rw-r--r--src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp198
-rw-r--r--src/plugins/geoservices/nokia/qgeoroutexmlparser.h24
-rw-r--r--src/plugins/geoservices/nokia/qgeoroutingmanagerengine_nokia.cpp29
-rw-r--r--src/plugins/geoservices/nokia/qgeoserviceproviderplugin_nokia.cpp6
-rw-r--r--src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp10
-rw-r--r--src/plugins/geoservices/osm/qgeoroutereplyosm.cpp7
-rw-r--r--src/plugins/geoservices/osm/qplacemanagerengineosm.cpp2
-rw-r--r--src/plugins/geoservices/osm/qplacesearchreplyosm.cpp7
-rw-r--r--src/plugins/position/android/src/qgeopositioninfosource_android.cpp4
-rw-r--r--src/plugins/position/corelocation/qgeopositioninfosource_cl.mm71
-rw-r--r--src/plugins/position/geoclue2/geoclue2.pro30
-rw-r--r--src/plugins/position/geoclue2/geocluetypes.cpp62
-rw-r--r--src/plugins/position/geoclue2/geocluetypes.h63
-rw-r--r--src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Client.xml122
-rw-r--r--src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Location.xml96
-rw-r--r--src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Manager.xml60
-rw-r--r--src/plugins/position/geoclue2/plugin.json9
-rw-r--r--src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp443
-rw-r--r--src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2_p.h97
-rw-r--r--src/plugins/position/geoclue2/qgeopositioninfosourcefactory_geoclue2.cpp66
-rw-r--r--src/plugins/position/geoclue2/qgeopositioninfosourcefactory_geoclue2.h68
-rw-r--r--src/plugins/position/position.pro3
-rw-r--r--src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp211
-rw-r--r--src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h8
-rw-r--r--src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp19
-rw-r--r--src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h4
67 files changed, 2601 insertions, 354 deletions
diff --git a/src/plugins/geoservices/esri/esri.pro b/src/plugins/geoservices/esri/esri.pro
index 3a4da208..fce3947f 100644
--- a/src/plugins/geoservices/esri/esri.pro
+++ b/src/plugins/geoservices/esri/esri.pro
@@ -16,7 +16,10 @@ HEADERS += \
geotiledmap_esri.h \
geotiledmappingmanagerengine_esri.h \
geotiledmapreply_esri.h \
- geotilefetcher_esri.h
+ geotilefetcher_esri.h \
+ placemanagerengine_esri.h \
+ placesearchreply_esri.h \
+ placecategoriesreply_esri.h
SOURCES += \
geocodereply_esri.cpp \
@@ -29,7 +32,10 @@ SOURCES += \
geotiledmap_esri.cpp \
geotiledmappingmanagerengine_esri.cpp \
geotiledmapreply_esri.cpp \
- geotilefetcher_esri.cpp
+ geotilefetcher_esri.cpp \
+ placemanagerengine_esri.cpp \
+ placesearchreply_esri.cpp \
+ placecategoriesreply_esri.cpp
RESOURCES += \
esri.qrc
diff --git a/src/plugins/geoservices/esri/esri_plugin.json b/src/plugins/geoservices/esri/esri_plugin.json
index 3398648e..c1e37614 100644
--- a/src/plugins/geoservices/esri/esri_plugin.json
+++ b/src/plugins/geoservices/esri/esri_plugin.json
@@ -7,7 +7,8 @@
"OnlineMappingFeature",
"OnlineGeocodingFeature",
"ReverseGeocodingFeature",
- "OnlineRoutingFeature"
+ "OnlineRoutingFeature",
+ "OnlinePlacesFeature"
],
"Priority": 1000
}
diff --git a/src/plugins/geoservices/esri/geocodereply_esri.cpp b/src/plugins/geoservices/esri/geocodereply_esri.cpp
index f1dac184..fd1071c9 100644
--- a/src/plugins/geoservices/esri/geocodereply_esri.cpp
+++ b/src/plugins/geoservices/esri/geocodereply_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geocodereply_esri.h b/src/plugins/geoservices/esri/geocodereply_esri.h
index 76b416ce..4f216193 100644
--- a/src/plugins/geoservices/esri/geocodereply_esri.h
+++ b/src/plugins/geoservices/esri/geocodereply_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geocodingmanagerengine_esri.cpp b/src/plugins/geoservices/esri/geocodingmanagerengine_esri.cpp
index 976c51cf..17ed3cd2 100644
--- a/src/plugins/geoservices/esri/geocodingmanagerengine_esri.cpp
+++ b/src/plugins/geoservices/esri/geocodingmanagerengine_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geocodingmanagerengine_esri.h b/src/plugins/geoservices/esri/geocodingmanagerengine_esri.h
index ff7bf882..a18f6bdd 100644
--- a/src/plugins/geoservices/esri/geocodingmanagerengine_esri.h
+++ b/src/plugins/geoservices/esri/geocodingmanagerengine_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geomapsource.cpp b/src/plugins/geoservices/esri/geomapsource.cpp
index 7ec63e2f..7a7d264f 100644
--- a/src/plugins/geoservices/esri/geomapsource.cpp
+++ b/src/plugins/geoservices/esri/geomapsource.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geomapsource.h b/src/plugins/geoservices/esri/geomapsource.h
index 86258d2e..24bef6f7 100644
--- a/src/plugins/geoservices/esri/geomapsource.h
+++ b/src/plugins/geoservices/esri/geomapsource.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/georoutejsonparser_esri.cpp b/src/plugins/geoservices/esri/georoutejsonparser_esri.cpp
index 30db48f0..17492d94 100644
--- a/src/plugins/geoservices/esri/georoutejsonparser_esri.cpp
+++ b/src/plugins/geoservices/esri/georoutejsonparser_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/georoutejsonparser_esri.h b/src/plugins/geoservices/esri/georoutejsonparser_esri.h
index 0511cf4d..d6451d70 100644
--- a/src/plugins/geoservices/esri/georoutejsonparser_esri.h
+++ b/src/plugins/geoservices/esri/georoutejsonparser_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/georoutereply_esri.cpp b/src/plugins/geoservices/esri/georoutereply_esri.cpp
index 811ffd0d..95de6b55 100644
--- a/src/plugins/geoservices/esri/georoutereply_esri.cpp
+++ b/src/plugins/geoservices/esri/georoutereply_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/georoutereply_esri.h b/src/plugins/geoservices/esri/georoutereply_esri.h
index 960c90de..19cb85bd 100644
--- a/src/plugins/geoservices/esri/georoutereply_esri.h
+++ b/src/plugins/geoservices/esri/georoutereply_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/georoutingmanagerengine_esri.cpp b/src/plugins/geoservices/esri/georoutingmanagerengine_esri.cpp
index ae722e59..0e6bc2c7 100644
--- a/src/plugins/geoservices/esri/georoutingmanagerengine_esri.cpp
+++ b/src/plugins/geoservices/esri/georoutingmanagerengine_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/georoutingmanagerengine_esri.h b/src/plugins/geoservices/esri/georoutingmanagerengine_esri.h
index 17aaa3ab..eac32222 100644
--- a/src/plugins/geoservices/esri/georoutingmanagerengine_esri.h
+++ b/src/plugins/geoservices/esri/georoutingmanagerengine_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geoserviceproviderfactory_esri.cpp b/src/plugins/geoservices/esri/geoserviceproviderfactory_esri.cpp
index 0a54e008..197b16cd 100644
--- a/src/plugins/geoservices/esri/geoserviceproviderfactory_esri.cpp
+++ b/src/plugins/geoservices/esri/geoserviceproviderfactory_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
@@ -41,6 +41,7 @@
#include "geotiledmappingmanagerengine_esri.h"
#include "geocodingmanagerengine_esri.h"
#include "georoutingmanagerengine_esri.h"
+#include "placemanagerengine_esri.h"
#include <QtLocation/private/qgeotiledmappingmanagerengine_p.h>
@@ -76,11 +77,7 @@ QGeoRoutingManagerEngine *GeoServiceProviderFactoryEsri::createRoutingManagerEng
QPlaceManagerEngine *GeoServiceProviderFactoryEsri::createPlaceManagerEngine(
const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const
{
- Q_UNUSED(parameters)
- Q_UNUSED(error)
- Q_UNUSED(errorString)
-
- return nullptr;
+ return new PlaceManagerEngineEsri(parameters, error, errorString);
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/esri/geoserviceproviderfactory_esri.h b/src/plugins/geoservices/esri/geoserviceproviderfactory_esri.h
index abd0d59b..6208348a 100644
--- a/src/plugins/geoservices/esri/geoserviceproviderfactory_esri.h
+++ b/src/plugins/geoservices/esri/geoserviceproviderfactory_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geotiledmap_esri.cpp b/src/plugins/geoservices/esri/geotiledmap_esri.cpp
index 8feb9615..020001c4 100644
--- a/src/plugins/geoservices/esri/geotiledmap_esri.cpp
+++ b/src/plugins/geoservices/esri/geotiledmap_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geotiledmap_esri.h b/src/plugins/geoservices/esri/geotiledmap_esri.h
index 7a21af9a..0f62d961 100644
--- a/src/plugins/geoservices/esri/geotiledmap_esri.h
+++ b/src/plugins/geoservices/esri/geotiledmap_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp b/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp
index 3fa9a177..5d15835d 100644
--- a/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp
+++ b/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
@@ -53,11 +53,6 @@
#include <QJsonDocument>
#include <QJsonObject>
-static void initResources()
-{
- Q_INIT_RESOURCE(esri);
-}
-
QT_BEGIN_NAMESPACE
static const QString kPrefixEsri(QStringLiteral("esri."));
@@ -241,7 +236,6 @@ bool GeoTiledMappingManagerEngineEsri::initializeMapSources(QGeoServiceProvider:
QString *errorString,
const QGeoCameraCapabilities &cameraCaps)
{
- initResources();
QFile mapsFile(":/esri/maps.json");
if (!mapsFile.open(QIODevice::ReadOnly)) {
diff --git a/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.h b/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.h
index 63172389..222b1779 100644
--- a/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.h
+++ b/src/plugins/geoservices/esri/geotiledmappingmanagerengine_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp b/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
index f4431bf0..78f6c69a 100644
--- a/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
+++ b/src/plugins/geoservices/esri/geotiledmapreply_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geotiledmapreply_esri.h b/src/plugins/geoservices/esri/geotiledmapreply_esri.h
index 572431dd..9e649d4f 100644
--- a/src/plugins/geoservices/esri/geotiledmapreply_esri.h
+++ b/src/plugins/geoservices/esri/geotiledmapreply_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geotilefetcher_esri.cpp b/src/plugins/geoservices/esri/geotilefetcher_esri.cpp
index 8ceba374..00344cf7 100644
--- a/src/plugins/geoservices/esri/geotilefetcher_esri.cpp
+++ b/src/plugins/geoservices/esri/geotilefetcher_esri.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/geotilefetcher_esri.h b/src/plugins/geoservices/esri/geotilefetcher_esri.h
index 5702d1c4..8c109f73 100644
--- a/src/plugins/geoservices/esri/geotilefetcher_esri.h
+++ b/src/plugins/geoservices/esri/geotilefetcher_esri.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013-2016 Esri <contracts@esri.com>
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
diff --git a/src/plugins/geoservices/esri/placecategoriesreply_esri.cpp b/src/plugins/geoservices/esri/placecategoriesreply_esri.cpp
new file mode 100644
index 00000000..44c27b19
--- /dev/null
+++ b/src/plugins/geoservices/esri/placecategoriesreply_esri.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "placecategoriesreply_esri.h"
+
+QT_BEGIN_NAMESPACE
+
+PlaceCategoriesReplyEsri::PlaceCategoriesReplyEsri(QObject *parent) :
+ QPlaceReply(parent)
+{
+}
+
+PlaceCategoriesReplyEsri::~PlaceCategoriesReplyEsri()
+{
+}
+
+void PlaceCategoriesReplyEsri::emitFinished()
+{
+ setFinished(true);
+ emit finished();
+}
+
+void PlaceCategoriesReplyEsri::setError(QPlaceReply::Error errorCode, const QString &errorString)
+{
+ QPlaceReply::setError(errorCode, errorString);
+ emit error(errorCode, errorString);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/esri/placecategoriesreply_esri.h b/src/plugins/geoservices/esri/placecategoriesreply_esri.h
new file mode 100644
index 00000000..14efcfea
--- /dev/null
+++ b/src/plugins/geoservices/esri/placecategoriesreply_esri.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLACECATEGORIESREPLYESRI_H
+#define PLACECATEGORIESREPLYESRI_H
+
+#include <QtLocation/QPlaceReply>
+
+QT_BEGIN_NAMESPACE
+
+class PlaceCategoriesReplyEsri : public QPlaceReply
+{
+ Q_OBJECT
+
+public:
+ explicit PlaceCategoriesReplyEsri(QObject *parent = 0);
+ ~PlaceCategoriesReplyEsri();
+
+ void emitFinished();
+ void setError(QPlaceReply::Error errorCode, const QString &errorString);
+};
+
+QT_END_NAMESPACE
+
+#endif // PLACECATEGORIESREPLYESRI_H
diff --git a/src/plugins/geoservices/esri/placemanagerengine_esri.cpp b/src/plugins/geoservices/esri/placemanagerengine_esri.cpp
new file mode 100644
index 00000000..8f973ff3
--- /dev/null
+++ b/src/plugins/geoservices/esri/placemanagerengine_esri.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "placemanagerengine_esri.h"
+#include "placesearchreply_esri.h"
+#include "placecategoriesreply_esri.h"
+
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+
+#include <QtCore/QUrlQuery>
+
+QT_BEGIN_NAMESPACE
+
+// https://developers.arcgis.com/rest/geocode/api-reference/geocoding-find-address-candidates.htm
+// https://developers.arcgis.com/rest/geocode/api-reference/geocoding-category-filtering.htm
+// https://developers.arcgis.com/rest/geocode/api-reference/geocoding-service-output.htm
+
+static const QString kCategoriesKey(QStringLiteral("categories"));
+static const QString kSingleLineKey(QStringLiteral("singleLine"));
+static const QString kLocationKey(QStringLiteral("location"));
+static const QString kNameKey(QStringLiteral("name"));
+static const QString kOutFieldsKey(QStringLiteral("outFields"));
+static const QString kCandidateFieldsKey(QStringLiteral("candidateFields"));
+static const QString kCountriesKey(QStringLiteral("detailedCountries"));
+static const QString kLocalizedNamesKey(QStringLiteral("localizedNames"));
+static const QString kMaxLocationsKey(QStringLiteral("maxLocations"));
+
+static const QUrl kUrlGeocodeServer("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer?f=pjson");
+static const QUrl kUrlFindAddressCandidates("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates");
+
+PlaceManagerEngineEsri::PlaceManagerEngineEsri(const QVariantMap &parameters, QGeoServiceProvider::Error *error,
+ QString *errorString) :
+ QPlaceManagerEngine(parameters),
+ m_networkManager(new QNetworkAccessManager(this))
+{
+ *error = QGeoServiceProvider::NoError;
+ errorString->clear();
+}
+
+PlaceManagerEngineEsri::~PlaceManagerEngineEsri()
+{
+}
+
+QList<QLocale> PlaceManagerEngineEsri::locales() const
+{
+ return m_locales;
+}
+
+void PlaceManagerEngineEsri::setLocales(const QList<QLocale> &locales)
+{
+ m_locales = locales;
+}
+
+/***** Search *****/
+
+QPlaceSearchReply *PlaceManagerEngineEsri::search(const QPlaceSearchRequest &request)
+{
+ bool unsupported = false;
+
+ // Only public visibility supported
+ unsupported |= request.visibilityScope() != QLocation::UnspecifiedVisibility &&
+ request.visibilityScope() != QLocation::PublicVisibility;
+ unsupported |= request.searchTerm().isEmpty() && request.categories().isEmpty();
+
+ if (unsupported)
+ return QPlaceManagerEngine::search(request);
+
+ QUrlQuery queryItems;
+ queryItems.addQueryItem(QStringLiteral("f"), QStringLiteral("json"));
+
+ const QGeoCoordinate center = request.searchArea().center();
+ if (center.isValid())
+ {
+ const QString location = QString("%1,%2").arg(center.longitude()).arg(center.latitude());
+ queryItems.addQueryItem(kLocationKey, location);
+ }
+
+ const QGeoRectangle boundingBox = request.searchArea().boundingGeoRectangle();
+ if (!boundingBox.isEmpty())
+ {
+ const QString searchExtent = QString("%1,%2,%3,%4")
+ .arg(boundingBox.topLeft().longitude())
+ .arg(boundingBox.topLeft().latitude())
+ .arg(boundingBox.bottomRight().longitude())
+ .arg(boundingBox.bottomRight().latitude());
+ queryItems.addQueryItem(QStringLiteral("searchExtent"), searchExtent);
+ }
+
+ if (!request.searchTerm().isEmpty())
+ queryItems.addQueryItem(kSingleLineKey, request.searchTerm());
+
+ QStringList categories;
+ if (!request.categories().isEmpty())
+ {
+ foreach (const QPlaceCategory &placeCategory, request.categories())
+ categories.append(placeCategory.categoryId());
+ queryItems.addQueryItem("category", categories.join(","));
+ }
+
+ if (request.limit() > 0)
+ queryItems.addQueryItem(kMaxLocationsKey, QString::number(request.limit()));
+
+ queryItems.addQueryItem(kOutFieldsKey, QStringLiteral("*"));
+
+ QUrl requestUrl(kUrlFindAddressCandidates);
+ requestUrl.setQuery(queryItems);
+
+ QNetworkRequest networkRequest(requestUrl);
+ networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+ QNetworkReply *networkReply = m_networkManager->get(networkRequest);
+
+ PlaceSearchReplyEsri *reply = new PlaceSearchReplyEsri(request, networkReply, m_candidateFieldsLocale, m_countriesLocale, this);
+ connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(error(QPlaceReply::Error,QString)), this, SLOT(replyError(QPlaceReply::Error,QString)));
+
+ return reply;
+}
+
+void PlaceManagerEngineEsri::replyFinished()
+{
+ QPlaceReply *reply = qobject_cast<QPlaceReply *>(sender());
+ if (reply)
+ emit finished(reply);
+}
+
+void PlaceManagerEngineEsri::replyError(QPlaceReply::Error errorCode, const QString &errorString)
+{
+ QPlaceReply *reply = qobject_cast<QPlaceReply *>(sender());
+ if (reply)
+ emit error(reply, errorCode, errorString);
+}
+
+/***** Categories *****/
+
+QPlaceReply *PlaceManagerEngineEsri::initializeCategories()
+{
+ initializeGeocodeServer();
+
+ PlaceCategoriesReplyEsri *reply = new PlaceCategoriesReplyEsri(this);
+ connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(error(QPlaceReply::Error,QString)), this, SLOT(replyError(QPlaceReply::Error,QString)));
+
+ // TODO delayed finished() emission
+ if (!m_categories.isEmpty())
+ reply->emitFinished();
+
+ m_pendingCategoriesReply.append(reply);
+ return reply;
+}
+
+void PlaceManagerEngineEsri::parseCategories(const QJsonArray &jsonArray, const QString &parentCategoryId)
+{
+ foreach (const QJsonValue &jsonValue, jsonArray)
+ {
+ if (!jsonValue.isObject())
+ continue;
+
+ const QJsonObject jsonCategory = jsonValue.toObject();
+ const QString key = jsonCategory.value(kNameKey).toString();
+ const QString localeName = localizedName(jsonCategory);
+
+ if (key.isEmpty())
+ continue;
+
+ QPlaceCategory category;
+ category.setCategoryId(key);
+ category.setName(localeName.isEmpty() ? key : localeName); // localizedNames
+ m_categories.insert(key, category);
+ m_subcategories[parentCategoryId].append(key);
+ m_parentCategory.insert(key, parentCategoryId);
+ emit categoryAdded(category, parentCategoryId);
+
+ if (jsonCategory.contains(kCategoriesKey))
+ {
+ const QJsonArray jsonArray = jsonCategory.value(kCategoriesKey).toArray();
+ parseCategories(jsonArray, key);
+ }
+ }
+}
+
+QString PlaceManagerEngineEsri::parentCategoryId(const QString &categoryId) const
+{
+ return m_parentCategory.value(categoryId);
+}
+
+QStringList PlaceManagerEngineEsri::childCategoryIds(const QString &categoryId) const
+{
+ return m_subcategories.value(categoryId);
+}
+
+QPlaceCategory PlaceManagerEngineEsri::category(const QString &categoryId) const
+{
+ return m_categories.value(categoryId);
+}
+
+QList<QPlaceCategory> PlaceManagerEngineEsri::childCategories(const QString &parentId) const
+{
+ QList<QPlaceCategory> categories;
+ foreach (const QString &id, m_subcategories.value(parentId))
+ categories.append(m_categories.value(id));
+ return categories;
+}
+
+void PlaceManagerEngineEsri::finishCategories()
+{
+ foreach (PlaceCategoriesReplyEsri *reply, m_pendingCategoriesReply)
+ reply->emitFinished();
+ m_pendingCategoriesReply.clear();
+}
+
+void PlaceManagerEngineEsri::errorCaterogies(const QString &error)
+{
+ foreach (PlaceCategoriesReplyEsri *reply, m_pendingCategoriesReply)
+ reply->setError(QPlaceReply::CommunicationError, error);
+}
+
+/***** GeocodeServer *****/
+
+void PlaceManagerEngineEsri::initializeGeocodeServer()
+{
+ // Only fetch categories once
+ if (m_categories.isEmpty() && !m_geocodeServerReply)
+ {
+ m_geocodeServerReply = m_networkManager->get(QNetworkRequest(kUrlGeocodeServer));
+ connect(m_geocodeServerReply, SIGNAL(finished()), this, SLOT(geocodeServerReplyFinished()));
+ connect(m_geocodeServerReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(geocodeServerReplyError()));
+ }
+}
+
+QString PlaceManagerEngineEsri::localizedName(const QJsonObject &jsonObject)
+{
+ const QJsonObject localizedNames = jsonObject.value(kLocalizedNamesKey).toObject();
+
+ foreach (const QLocale &locale, m_locales)
+ {
+ const QString localeStr = locale.name();
+ if (localizedNames.contains(localeStr))
+ {
+ return localizedNames.value(localeStr).toString();
+ }
+
+ const QString shortLocale = localeStr.left(2);
+ if (localizedNames.contains(shortLocale))
+ {
+ return localizedNames.value(shortLocale).toString();
+ }
+ }
+ return QString();
+}
+
+void PlaceManagerEngineEsri::parseCandidateFields(const QJsonArray &jsonArray)
+{
+ foreach (const QJsonValue &jsonValue, jsonArray)
+ {
+ if (!jsonValue.isObject())
+ continue;
+
+ const QJsonObject jsonCandidateField = jsonValue.toObject();
+ if (!jsonCandidateField.contains(kLocalizedNamesKey))
+ continue;
+
+ const QString key = jsonCandidateField.value(kNameKey).toString();
+ m_candidateFieldsLocale.insert(key, localizedName(jsonCandidateField));
+ }
+}
+
+void PlaceManagerEngineEsri::parseCountries(const QJsonArray &jsonArray)
+{
+ foreach (const QJsonValue &jsonValue, jsonArray)
+ {
+ if (!jsonValue.isObject())
+ continue;
+
+ const QJsonObject jsonCountry = jsonValue.toObject();
+ if (!jsonCountry.contains(kLocalizedNamesKey))
+ continue;
+
+ const QString key = jsonCountry.value(kNameKey).toString();
+ m_countriesLocale.insert(key, localizedName(jsonCountry));
+ }
+}
+
+void PlaceManagerEngineEsri::geocodeServerReplyFinished()
+{
+ if (!m_geocodeServerReply)
+ return;
+
+ QJsonDocument document = QJsonDocument::fromJson(m_geocodeServerReply->readAll());
+ if (!document.isObject())
+ {
+ errorCaterogies(m_geocodeServerReply->errorString());
+ return;
+ }
+
+ QJsonObject jsonObject = document.object();
+
+ // parse categories
+ if (jsonObject.contains(kCategoriesKey))
+ {
+ const QJsonArray jsonArray = jsonObject.value(kCategoriesKey).toArray();
+ parseCategories(jsonArray, QString());
+ }
+
+ // parse candidateFields
+ if (jsonObject.contains(kCandidateFieldsKey))
+ {
+ const QJsonArray jsonArray = jsonObject.value(kCandidateFieldsKey).toArray();
+ parseCandidateFields(jsonArray);
+ }
+
+ // parse countries
+ if (jsonObject.contains(kCountriesKey))
+ {
+ const QJsonArray jsonArray = jsonObject.value(kCountriesKey).toArray();
+ parseCountries(jsonArray);
+ }
+
+ finishCategories();
+
+ m_geocodeServerReply->deleteLater();
+}
+
+void PlaceManagerEngineEsri::geocodeServerReplyError()
+{
+ if (m_categories.isEmpty() && !m_geocodeServerReply)
+ return;
+
+ errorCaterogies(m_geocodeServerReply->errorString());
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/esri/placemanagerengine_esri.h b/src/plugins/geoservices/esri/placemanagerengine_esri.h
new file mode 100644
index 00000000..2edb2d1a
--- /dev/null
+++ b/src/plugins/geoservices/esri/placemanagerengine_esri.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLACEMANAGERENGINEESRI_H
+#define PLACEMANAGERENGINEESRI_H
+
+#include <QtLocation/QPlaceManagerEngine>
+#include <QtLocation/QGeoServiceProvider>
+
+QT_BEGIN_NAMESPACE
+
+class PlaceCategoriesReplyEsri;
+class QNetworkAccessManager;
+class QNetworkReply;
+
+class PlaceManagerEngineEsri : public QPlaceManagerEngine
+{
+ Q_OBJECT
+
+public:
+ PlaceManagerEngineEsri(const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString);
+ ~PlaceManagerEngineEsri();
+
+ QPlaceSearchReply *search(const QPlaceSearchRequest &request) override;
+
+ QPlaceReply *initializeCategories() override;
+ QString parentCategoryId(const QString &categoryId) const override;
+ QStringList childCategoryIds(const QString &categoryId) const override;
+ QPlaceCategory category(const QString &categoryId) const override;
+
+ QList<QPlaceCategory> childCategories(const QString &parentId) const override;
+
+ QList<QLocale> locales() const override;
+ void setLocales(const QList<QLocale> &locales) override;
+
+private slots:
+ void geocodeServerReplyFinished();
+ void geocodeServerReplyError();
+ void replyFinished();
+ void replyError(QPlaceReply::Error errorCode, const QString &errorString);
+
+private:
+ QNetworkAccessManager *m_networkManager = Q_NULLPTR;
+
+ // geocode serveur
+ void initializeGeocodeServer();
+
+ QNetworkReply *m_geocodeServerReply = Q_NULLPTR;
+
+ // categories
+ void finishCategories();
+ void errorCaterogies(const QString &error);
+ void parseCategories(const QJsonArray &jsonArray, const QString &parentCategoryId);
+
+ QList<PlaceCategoriesReplyEsri *> m_pendingCategoriesReply;
+ QHash<QString, QPlaceCategory> m_categories;
+ QHash<QString, QStringList> m_subcategories;
+ QHash<QString, QString> m_parentCategory;
+
+ // localized names
+ QString localizedName(const QJsonObject &jsonObject);
+ void parseCandidateFields(const QJsonArray &jsonArray);
+ void parseCountries(const QJsonArray &jsonArray);
+
+ QList<QLocale> m_locales;
+ QHash<QString, QString> m_candidateFieldsLocale;
+ QHash<QString, QString> m_countriesLocale;
+ void localizedName();
+};
+
+QT_END_NAMESPACE
+
+#endif // PLACEMANAGERENGINEESRI_H
diff --git a/src/plugins/geoservices/esri/placesearchreply_esri.cpp b/src/plugins/geoservices/esri/placesearchreply_esri.cpp
new file mode 100644
index 00000000..a5a3585a
--- /dev/null
+++ b/src/plugins/geoservices/esri/placesearchreply_esri.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "placesearchreply_esri.h"
+#include "placemanagerengine_esri.h"
+
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonObject>
+#include <QtNetwork/QNetworkReply>
+#include <QtPositioning/QGeoCircle>
+#include <QtPositioning/QGeoRectangle>
+#include <QtLocation/QPlaceResult>
+#include <QtLocation/QPlaceSearchRequest>
+#include <QtLocation/private/qplacesearchrequest_p.h>
+
+static const QString kCandidatesKey(QStringLiteral("candidates"));
+static const QString kAttributesKey(QStringLiteral("attributes"));
+static const QString kAddressKey(QStringLiteral("address"));
+static const QString kLongLabelKey(QStringLiteral("LongLabel"));
+static const QString kCityKey(QStringLiteral("City"));
+static const QString kCountryKey(QStringLiteral("Country"));
+static const QString kRegionKey(QStringLiteral("Region"));
+static const QString kPostalKey(QStringLiteral("Postal"));
+static const QString kStAddrKey(QStringLiteral("StAddr"));
+static const QString kStateKey(QStringLiteral("State"));
+static const QString kDistrictKey(QStringLiteral("District"));
+static const QString kLocationKey(QStringLiteral("location"));
+static const QString kXKey(QStringLiteral("x"));
+static const QString kYKey(QStringLiteral("y"));
+static const QString kDistanceKey(QStringLiteral("Distance"));
+static const QString kPhoneKey(QStringLiteral("Phone"));
+static const QString kExtentKey(QStringLiteral("extent"));
+static const QString kXminKey(QStringLiteral("xmin"));
+static const QString kYminKey(QStringLiteral("ymin"));
+static const QString kXmaxKey(QStringLiteral("xmax"));
+static const QString kYmaxKey(QStringLiteral("ymax"));
+
+QT_BEGIN_NAMESPACE
+
+PlaceSearchReplyEsri::PlaceSearchReplyEsri(const QPlaceSearchRequest &request, QNetworkReply *reply,
+ const QHash<QString, QString> &candidateFields,
+ const QHash<QString, QString> &countries, PlaceManagerEngineEsri *parent) :
+ QPlaceSearchReply(parent), m_candidateFields(candidateFields), m_countries(countries)
+{
+ Q_ASSERT(parent);
+ if (!reply) {
+ setError(UnknownError, QStringLiteral("Null reply"));
+ return;
+ }
+ setRequest(request);
+
+ connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
+ connect(this, &QPlaceReply::aborted, reply, &QNetworkReply::abort);
+ connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
+}
+
+PlaceSearchReplyEsri::~PlaceSearchReplyEsri()
+{
+}
+
+void PlaceSearchReplyEsri::setError(QPlaceReply::Error errorCode, const QString &errorString)
+{
+ QPlaceReply::setError(errorCode, errorString);
+ emit error(errorCode, errorString);
+ setFinished(true);
+ emit finished();
+}
+
+void PlaceSearchReplyEsri::replyFinished()
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+
+ if (reply->error() != QNetworkReply::NoError)
+ return;
+
+ QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
+ if (!document.isObject())
+ {
+ setError(ParseError, tr("Response parse error"));
+ return;
+ }
+
+ QJsonValue suggestions = document.object().value(kCandidatesKey);
+ if (!suggestions.isArray())
+ {
+ setError(ParseError, tr("Response parse error"));
+ return;
+ }
+
+ QJsonArray resultsArray = suggestions.toArray();
+
+ QList<QPlaceSearchResult> results;
+ for (int i = 0; i < resultsArray.count(); ++i)
+ {
+ QJsonObject item = resultsArray.at(i).toObject();
+ QPlaceResult placeResult = parsePlaceResult(item);
+ results.append(placeResult);
+ }
+
+ setResults(results);
+ setFinished(true);
+ emit finished();
+}
+
+void PlaceSearchReplyEsri::networkError(QNetworkReply::NetworkError error)
+{
+ Q_UNUSED(error)
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+ setError(QPlaceReply::CommunicationError, reply->errorString());
+}
+
+QPlaceResult PlaceSearchReplyEsri::parsePlaceResult(const QJsonObject &item) const
+{
+ QPlace place;
+ QHash<QString, QString> keys;
+
+ // set attributes
+ const QJsonObject attributes = item.value(kAttributesKey).toObject();
+ for (const QString &key: attributes.keys())
+ {
+ const QString value = attributes.value(key).toVariant().toString();
+ if (!value.isEmpty())
+ {
+ QPlaceAttribute attribute;
+ attribute.setLabel(m_candidateFields.value(key, key)); // local name or key
+ attribute.setText(value);
+ place.setExtendedAttribute(key, attribute);
+ keys.insert(key, value);
+ }
+ }
+
+ if (keys.contains(kPhoneKey))
+ {
+ QPlaceContactDetail contactDetail;
+ contactDetail.setLabel(m_candidateFields.value(kPhoneKey, kPhoneKey)); // local name or key
+ contactDetail.setValue(keys.value(kPhoneKey));
+ place.appendContactDetail(QPlaceContactDetail::Phone, contactDetail);
+ }
+
+ // set address
+ QGeoAddress geoAddress;
+ geoAddress.setCity(keys.value(kCityKey));
+ geoAddress.setCountry(m_countries.value(keys.value(kCountryKey))); // mismatch code ISO2 vs ISO3
+ geoAddress.setCounty(keys.value(kRegionKey));
+ geoAddress.setPostalCode(keys.value(kPostalKey));
+ geoAddress.setStreet(keys.value(kStAddrKey));
+ geoAddress.setState(keys.value(kStateKey));
+ geoAddress.setDistrict(keys.value(kDistrictKey));
+
+ // set location
+ const QJsonObject location = item.value(kLocationKey).toObject();
+ const QGeoCoordinate coordinate = QGeoCoordinate(location.value(kYKey).toDouble(),
+ location.value(kXKey).toDouble());
+
+ // set boundingBox
+ const QJsonObject extent = item.value(kExtentKey).toObject();
+ const QGeoCoordinate topLeft(extent.value(kYminKey).toDouble(),
+ extent.value(kXminKey).toDouble());
+ const QGeoCoordinate bottomRight(extent.value(kYmaxKey).toDouble(),
+ extent.value(kXmaxKey).toDouble());
+ const QGeoRectangle boundingBox(topLeft, bottomRight);
+
+ // set geolocation
+ QGeoLocation geoLocation;
+ geoLocation.setCoordinate(coordinate);
+ geoLocation.setAddress(geoAddress);
+ geoLocation.setBoundingBox(boundingBox);
+
+ // set place
+ place.setName(keys.value(kLongLabelKey));
+ place.setLocation(geoLocation);
+ place.setPlaceId(attributes.value(kLongLabelKey).toString());
+
+ // set place result
+ QPlaceResult result;
+ result.setPlace(place);
+ result.setTitle(keys.value(kAddressKey));
+ result.setDistance(keys.value(kDistanceKey).toDouble());
+
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/esri/placesearchreply_esri.h b/src/plugins/geoservices/esri/placesearchreply_esri.h
new file mode 100644
index 00000000..195d650d
--- /dev/null
+++ b/src/plugins/geoservices/esri/placesearchreply_esri.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013-2018 Esri <contracts@esri.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLACESEARCHREPLYESRI_H
+#define PLACESEARCHREPLYESRI_H
+
+#include <QtLocation/QPlaceSearchReply>
+#include <QNetworkReply>
+
+QT_BEGIN_NAMESPACE
+
+class PlaceManagerEngineEsri;
+class QNetworkReply;
+class QPlaceResult;
+
+class PlaceSearchReplyEsri : public QPlaceSearchReply
+{
+ Q_OBJECT
+
+public:
+ PlaceSearchReplyEsri(const QPlaceSearchRequest &request, QNetworkReply *reply,
+ const QHash<QString, QString> &candidateFields,
+ const QHash<QString, QString> &countries, PlaceManagerEngineEsri *parent);
+ ~PlaceSearchReplyEsri();
+
+ QString requestUrl;
+
+private slots:
+ void setError(QPlaceReply::Error errorCode, const QString &errorString);
+ void replyFinished();
+ void networkError(QNetworkReply::NetworkError error);
+
+private:
+ QPlaceResult parsePlaceResult(const QJsonObject &item) const;
+
+ const QHash<QString, QString> &m_candidateFields;
+ const QHash<QString, QString> &m_countries;
+};
+
+QT_END_NAMESPACE
+
+#endif // PLACESEARCHREPLYESRI_H
diff --git a/src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp b/src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp
index af0e263b..dede9dbc 100644
--- a/src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp
+++ b/src/plugins/geoservices/itemsoverlay/qgeomapitemsoverlay.cpp
@@ -70,10 +70,16 @@ public:
#endif
void updateObjectsGeometry();
+
+ void setVisibleArea(const QRectF &visibleArea) override;
+ QRectF visibleArea() const override;
+
protected:
void changeViewportSize(const QSize &size) override;
void changeCameraData(const QGeoCameraData &oldCameraData) override;
void changeActiveMapType(const QGeoMapType mapType) override;
+
+ QRectF m_visibleArea;
};
QGeoMapItemsOverlay::QGeoMapItemsOverlay(QGeoMappingManagerEngineItemsOverlay *engine, QObject *parent)
@@ -131,6 +137,24 @@ void QGeoMapItemsOverlay::removeMapObject(QGeoMapObject *obj)
#endif
}
+void QGeoMapItemsOverlayPrivate::setVisibleArea(const QRectF &visibleArea)
+{
+ Q_Q(QGeoMapItemsOverlay);
+ const QRectF va = clampVisibleArea(visibleArea);
+ if (va == m_visibleArea)
+ return;
+
+ m_visibleArea = va;
+ m_geoProjection->setVisibleArea(va);
+
+ q->sgNodeChanged();
+}
+
+QRectF QGeoMapItemsOverlayPrivate::visibleArea() const
+{
+ return m_visibleArea;
+}
+
QGeoMapItemsOverlayPrivate::QGeoMapItemsOverlayPrivate(QGeoMappingManagerEngineItemsOverlay *engine, QGeoMapItemsOverlay *map)
: QGeoMapPrivate(engine, new QGeoProjectionWebMercator)
{
diff --git a/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp b/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
index c5f9d38c..8b0772ad 100644
--- a/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
+++ b/src/plugins/geoservices/mapbox/qgeoroutereplymapbox.cpp
@@ -127,6 +127,13 @@ void QGeoRouteReplyMapbox::networkReplyFinished()
QByteArray routeReply = reply->readAll();
QGeoRouteReply::Error error = parser->parseReply(routes, errorString, routeReply);
+ // Setting the request into the result
+ for (QGeoRoute &route : routes) {
+ route.setRequest(request());
+ for (QGeoRoute &leg: route.routeLegs()) {
+ leg.setRequest(request());
+ }
+ }
QVariantMap metadata;
metadata["osrm.reply-json"] = routeReply;
diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp
index dfebc20d..ed36cd5f 100644
--- a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp
+++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.cpp
@@ -106,12 +106,12 @@ QSGNode *QGeoMapMapboxGLPrivate::updateSceneGraph(QSGNode *node, QQuickWindow *w
if (m_useFBO) {
QSGMapboxGLTextureNode *mbglNode = new QSGMapboxGLTextureNode(m_settings, m_viewportSize, window->devicePixelRatio(), q);
QObject::connect(mbglNode->map(), &QMapboxGL::mapChanged, q, &QGeoMapMapboxGL::onMapChanged);
- m_syncState = MapTypeSync | CameraDataSync | ViewportSync;
+ m_syncState = MapTypeSync | CameraDataSync | ViewportSync | VisibleAreaSync;
node = mbglNode;
} else {
QSGMapboxGLRenderNode *mbglNode = new QSGMapboxGLRenderNode(m_settings, m_viewportSize, window->devicePixelRatio(), q);
QObject::connect(mbglNode->map(), &QMapboxGL::mapChanged, q, &QGeoMapMapboxGL::onMapChanged);
- m_syncState = MapTypeSync | CameraDataSync | ViewportSync;
+ m_syncState = MapTypeSync | CameraDataSync | ViewportSync | VisibleAreaSync;
node = mbglNode;
}
}
@@ -125,7 +125,19 @@ QSGNode *QGeoMapMapboxGLPrivate::updateSceneGraph(QSGNode *node, QQuickWindow *w
map->setStyleUrl(m_activeMapType.name());
}
- if (m_syncState & CameraDataSync) {
+ if (m_syncState & VisibleAreaSync) {
+ if (m_visibleArea.isEmpty()) {
+ map->setMargins(QMargins());
+ } else {
+ QMargins margins(m_visibleArea.x(), // left
+ m_visibleArea.y(), // top
+ m_viewportSize.width() - m_visibleArea.width() - m_visibleArea.x(), // right
+ m_viewportSize.height() - m_visibleArea.height() - m_visibleArea.y()); // bottom
+ map->setMargins(margins);
+ }
+ }
+
+ if (m_syncState & CameraDataSync || m_syncState & VisibleAreaSync) {
map->setZoom(zoomLevelFrom256(m_cameraData.zoomLevel() , MBGL_TILE_SIZE));
map->setBearing(m_cameraData.bearing());
map->setPitch(m_cameraData.tilt());
@@ -291,6 +303,25 @@ void QGeoMapMapboxGLPrivate::changeActiveMapType(const QGeoMapType)
emit q->sgNodeChanged();
}
+void QGeoMapMapboxGLPrivate::setVisibleArea(const QRectF &visibleArea)
+{
+ Q_Q(QGeoMapMapboxGL);
+ const QRectF va = clampVisibleArea(visibleArea);
+ if (va == m_visibleArea)
+ return;
+
+ m_visibleArea = va;
+ m_geoProjection->setVisibleArea(va);
+
+ m_syncState = m_syncState | VisibleAreaSync;
+ emit q->sgNodeChanged();
+}
+
+QRectF QGeoMapMapboxGLPrivate::visibleArea() const
+{
+ return m_visibleArea;
+}
+
void QGeoMapMapboxGLPrivate::syncStyleChanges(QMapboxGL *map)
{
for (const auto& change : m_styleChanges) {
@@ -347,7 +378,7 @@ QString QGeoMapMapboxGL::copyrightsStyleSheet() const
return QStringLiteral("* { vertical-align: middle; font-weight: normal }");
}
-void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings)
+void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings, bool useChinaEndpoint)
{
Q_D(QGeoMapMapboxGL);
@@ -355,8 +386,13 @@ void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings)
// If the access token is not set, use the development access token.
// This will only affect mapbox:// styles.
+ // Mapbox China requires a China-specific access token.
if (d->m_settings.accessToken().isEmpty()) {
- d->m_settings.setAccessToken(developmentToken);
+ if (useChinaEndpoint) {
+ qWarning("Mapbox China requires an access token: https://www.mapbox.com/contact/sales");
+ } else {
+ d->m_settings.setAccessToken(developmentToken);
+ }
}
}
@@ -376,7 +412,8 @@ QGeoMap::Capabilities QGeoMapMapboxGL::capabilities() const
{
return Capabilities(SupportsVisibleRegion
| SupportsSetBearing
- | SupportsAnchoringCoordinate);
+ | SupportsAnchoringCoordinate
+ | SupportsVisibleArea );
}
QSGNode *QGeoMapMapboxGL::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window)
diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h
index 0ffaf4ea..5fc2260e 100644
--- a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h
+++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl.h
@@ -54,7 +54,7 @@ public:
virtual ~QGeoMapMapboxGL();
QString copyrightsStyleSheet() const override;
- void setMapboxGLSettings(const QMapboxGLSettings &);
+ void setMapboxGLSettings(const QMapboxGLSettings &, bool useChinaEndpoint);
void setUseFBO(bool);
void setMapItemsBefore(const QString &);
Capabilities capabilities() const override;
diff --git a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h
index ffb06208..f07b4c98 100644
--- a/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h
+++ b/src/plugins/geoservices/mapboxgl/qgeomapmapboxgl_p.h
@@ -43,6 +43,7 @@
#include <QtCore/QSharedPointer>
#include <QtCore/QTimer>
#include <QtCore/QVariant>
+#include <QtCore/QRectF>
#include <QtLocation/private/qgeomap_p_p.h>
#include <QtLocation/private/qgeomapparameter_p.h>
@@ -70,9 +71,10 @@ public:
/* Data members */
enum SyncState : int {
NoSync = 0,
- ViewportSync = 1 << 0,
- CameraDataSync = 1 << 1,
- MapTypeSync = 1 << 2
+ ViewportSync = 1 << 0,
+ CameraDataSync = 1 << 1,
+ MapTypeSync = 1 << 2,
+ VisibleAreaSync = 1 << 3
};
Q_DECLARE_FLAGS(SyncStates, SyncState);
@@ -96,11 +98,16 @@ protected:
void changeCameraData(const QGeoCameraData &oldCameraData) override;
void changeActiveMapType(const QGeoMapType mapType) override;
+ void setVisibleArea(const QRectF &visibleArea) override;
+ QRectF visibleArea() const override;
+
private:
Q_DISABLE_COPY(QGeoMapMapboxGLPrivate);
void syncStyleChanges(QMapboxGL *map);
void threadedRenderingHack(QQuickWindow *window, QMapboxGL *map);
+
+ QRectF m_visibleArea;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoMapMapboxGLPrivate::SyncStates)
diff --git a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp
index cc48afb2..d2463106 100644
--- a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp
+++ b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.cpp
@@ -69,30 +69,45 @@ QGeoMappingManagerEngineMapboxGL::QGeoMappingManagerEngineMapboxGL(const QVarian
int mapId = 0;
const QByteArray pluginName = "mapboxgl";
- mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/streets-v10"),
- tr("Streets"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/basic-v9"),
- tr("Basic"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/bright-v9"),
- tr("Bright"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::TerrainMap, QStringLiteral("mapbox://styles/mapbox/outdoors-v10"),
- tr("Outdoors"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, QStringLiteral("mapbox://styles/mapbox/satellite-v9"),
- tr("Satellite"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::HybridMap, QStringLiteral("mapbox://styles/mapbox/satellite-streets-v10"),
- tr("Satellite Streets"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/light-v9"),
- tr("Light"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/dark-v9"),
- tr("Dark"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/navigation-preview-day-v2"),
- tr("Navigation Preview Day"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/navigation-preview-night-v2"),
- tr("Navigation Preview Night"), false, true, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::CarNavigationMap, QStringLiteral("mapbox://styles/mapbox/navigation-guidance-day-v2"),
- tr("Navigation Guidance Day"), false, false, ++mapId, pluginName, cameraCaps);
- mapTypes << QGeoMapType(QGeoMapType::CarNavigationMap, QStringLiteral("mapbox://styles/mapbox/navigation-guidance-night-v2"),
- tr("Navigation Guidance Night"), false, true, ++mapId, pluginName, cameraCaps);
+ if (parameters.contains(QStringLiteral("mapboxgl.china"))) {
+ m_useChinaEndpoint = parameters.value(QStringLiteral("mapboxgl.china")).toBool();
+ }
+
+ if (m_useChinaEndpoint) {
+ m_settings.setApiBaseUrl(QStringLiteral("https://api.mapbox.cn"));
+
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/streets-zh-v1"),
+ tr("China Streets"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/light-zh-v1"),
+ tr("China Light"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/dark-zh-v1"),
+ tr("China Dark"), false, false, ++mapId, pluginName, cameraCaps);
+ } else {
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/streets-v10"),
+ tr("Streets"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/basic-v9"),
+ tr("Basic"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, QStringLiteral("mapbox://styles/mapbox/bright-v9"),
+ tr("Bright"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::TerrainMap, QStringLiteral("mapbox://styles/mapbox/outdoors-v10"),
+ tr("Outdoors"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, QStringLiteral("mapbox://styles/mapbox/satellite-v9"),
+ tr("Satellite"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::HybridMap, QStringLiteral("mapbox://styles/mapbox/satellite-streets-v10"),
+ tr("Satellite Streets"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/light-v9"),
+ tr("Light"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::GrayStreetMap, QStringLiteral("mapbox://styles/mapbox/dark-v9"),
+ tr("Dark"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/navigation-preview-day-v2"),
+ tr("Navigation Preview Day"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::TransitMap, QStringLiteral("mapbox://styles/mapbox/navigation-preview-night-v2"),
+ tr("Navigation Preview Night"), false, true, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::CarNavigationMap, QStringLiteral("mapbox://styles/mapbox/navigation-guidance-day-v2"),
+ tr("Navigation Guidance Day"), false, false, ++mapId, pluginName, cameraCaps);
+ mapTypes << QGeoMapType(QGeoMapType::CarNavigationMap, QStringLiteral("mapbox://styles/mapbox/navigation-guidance-night-v2"),
+ tr("Navigation Guidance Night"), false, true, ++mapId, pluginName, cameraCaps);
+ }
if (parameters.contains(QStringLiteral("mapboxgl.mapping.additional_style_urls"))) {
const QString ids = parameters.value(QStringLiteral("mapboxgl.mapping.additional_style_urls")).toString();
@@ -156,7 +171,7 @@ QGeoMappingManagerEngineMapboxGL::~QGeoMappingManagerEngineMapboxGL()
QGeoMap *QGeoMappingManagerEngineMapboxGL::createMap()
{
QGeoMapMapboxGL* map = new QGeoMapMapboxGL(this, 0);
- map->setMapboxGLSettings(m_settings);
+ map->setMapboxGLSettings(m_settings, m_useChinaEndpoint);
map->setUseFBO(m_useFBO);
map->setMapItemsBefore(m_mapItemsBefore);
diff --git a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h
index b3afe77b..9ceb8ccc 100644
--- a/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h
+++ b/src/plugins/geoservices/mapboxgl/qgeomappingmanagerenginemapboxgl.h
@@ -59,6 +59,7 @@ public:
private:
QMapboxGLSettings m_settings;
bool m_useFBO = true;
+ bool m_useChinaEndpoint = false;
QString m_mapItemsBefore;
};
diff --git a/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp b/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp
index dd25c99e..afa723a5 100644
--- a/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp
+++ b/src/plugins/geoservices/mapboxgl/qgeoserviceproviderpluginmapboxgl.cpp
@@ -40,16 +40,10 @@
#include <QtGui/QOpenGLContext>
-static void initResources()
-{
- Q_INIT_RESOURCE(mapboxgl);
-}
-
QT_BEGIN_NAMESPACE
QGeoServiceProviderFactoryMapboxGL::QGeoServiceProviderFactoryMapboxGL()
{
- initResources();
}
QGeoCodingManagerEngine *QGeoServiceProviderFactoryMapboxGL::createGeocodingManagerEngine(
diff --git a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
index 6c47d3ee..b45fdef1 100644
--- a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
+++ b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange.cpp
@@ -41,6 +41,7 @@
#include <QtCore/QRegularExpression>
#include <QtCore/QStringList>
#include <QtPositioning/QGeoPath>
+#include <QtPositioning/QGeoPolygon>
#include <QtQml/QJSValue>
namespace {
@@ -66,7 +67,7 @@ QString getId(QDeclarativeGeoMapItemBase *mapItem)
// Mapbox GL supports geometry segments that spans above 180 degrees in
// longitude. To keep visual expectations in parity with Qt, we need to adapt
// the coordinates to always use the shortest path when in ambiguity.
-bool geoRectangleCrossesDateLine(const QGeoRectangle &rect) {
+static bool geoRectangleCrossesDateLine(const QGeoRectangle &rect) {
return rect.topLeft().longitude() > rect.bottomRight().longitude();
}
@@ -112,24 +113,35 @@ QMapbox::Feature featureFromMapCircle(QDeclarativeCircleMapItem *mapItem)
return QMapbox::Feature(QMapbox::Feature::PolygonType, geometry, {}, getId(mapItem));
}
-QMapbox::Feature featureFromMapPolygon(QDeclarativePolygonMapItem *mapItem)
+static QMapbox::Coordinates qgeocoordinate2mapboxcoordinate(const QList<QGeoCoordinate> &crds, const bool crossesDateline, bool closed = false)
{
- const QGeoPath *path = static_cast<const QGeoPath *>(&mapItem->geoShape());
QMapbox::Coordinates coordinates;
- const bool crossesDateline = geoRectangleCrossesDateLine(path->boundingGeoRectangle());
- for (const QGeoCoordinate &coordinate : path->path()) {
+ for (const QGeoCoordinate &coordinate : crds) {
if (!coordinates.empty() && crossesDateline && qAbs(coordinate.longitude() - coordinates.last().second) > 180.0) {
coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() + (coordinate.longitude() >= 0 ? -360.0 : 360.0) };
} else {
coordinates << QMapbox::Coordinate { coordinate.latitude(), coordinate.longitude() };
}
}
+ if (closed && !coordinates.empty() && coordinates.last() != coordinates.first())
+ coordinates.append(coordinates.first()); // closing the path
+ return coordinates;
+}
- if (!coordinates.empty())
- coordinates.append(coordinates.first()); // closing the path
-
- QMapbox::CoordinatesCollections geometry { { coordinates } };
+QMapbox::Feature featureFromMapPolygon(QDeclarativePolygonMapItem *mapItem)
+{
+ const QGeoPolygon *polygon = static_cast<const QGeoPolygon *>(&mapItem->geoShape());
+ const bool crossesDateline = geoRectangleCrossesDateLine(polygon->boundingGeoRectangle());
+ QMapbox::CoordinatesCollections geometry;
+ QMapbox::CoordinatesCollection poly;
+ QMapbox::Coordinates coordinates = qgeocoordinate2mapboxcoordinate(polygon->path(), crossesDateline, true);
+ poly.push_back(coordinates);
+ for (int i = 0; i < polygon->holesCount(); ++i) {
+ coordinates = qgeocoordinate2mapboxcoordinate(polygon->holePath(i), crossesDateline, true);
+ poly.push_back(coordinates);
+ }
+ geometry.push_back(poly);
return QMapbox::Feature(QMapbox::Feature::PolygonType, geometry, {}, getId(mapItem));
}
@@ -186,8 +198,7 @@ QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::addMapParamete
{
static const QStringList acceptedParameterTypes = QStringList()
<< QStringLiteral("paint") << QStringLiteral("layout") << QStringLiteral("filter")
- << QStringLiteral("layer") << QStringLiteral("source") << QStringLiteral("image")
- << QStringLiteral("margins");
+ << QStringLiteral("layer") << QStringLiteral("source") << QStringLiteral("image");
QList<QSharedPointer<QMapboxGLStyleChange>> changes;
@@ -213,9 +224,6 @@ QList<QSharedPointer<QMapboxGLStyleChange>> QMapboxGLStyleChange::addMapParamete
case 5: // image
changes << QMapboxGLStyleAddImage::fromMapParameter(param);
break;
- case 6: // margins
- changes << QMapboxGLMapMargins::fromMapParameter(param);
- break;
}
return changes;
@@ -641,38 +649,3 @@ QSharedPointer<QMapboxGLStyleChange> QMapboxGLStyleAddImage::fromMapParameter(QG
return QSharedPointer<QMapboxGLStyleChange>(image);
}
-
-// QMapboxGLMapMargins
-
-void QMapboxGLMapMargins::apply(QMapboxGL *map)
-{
- // FIXME: Qt projection handlers are not yet aware of these margins,
- // thus map items placement, {to,from}Coordinate, mouse area, etc.
- // will require manual fixups.
- map->setMargins(m_margins);
-}
-
-QSharedPointer<QMapboxGLStyleChange> QMapboxGLMapMargins::fromMapParameter(QGeoMapParameter *param)
-{
- Q_ASSERT(param->type() == "margins");
-
- auto mapMargins = new QMapboxGLMapMargins();
-
- QVariant leftMargin = param->property("left");
- if (leftMargin.isValid())
- mapMargins->m_margins.setLeft(leftMargin.toInt());
-
- QVariant topMargin = param->property("top");
- if (topMargin.isValid())
- mapMargins->m_margins.setTop(topMargin.toInt());
-
- QVariant rightMargin = param->property("right");
- if (rightMargin.isValid())
- mapMargins->m_margins.setRight(rightMargin.toInt());
-
- QVariant bottomMargin = param->property("bottom");
- if (bottomMargin.isValid())
- mapMargins->m_margins.setBottom(bottomMargin.toInt());
-
- return QSharedPointer<QMapboxGLStyleChange>(mapMargins);
-}
diff --git a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h
index 38aa87f8..fd5b9af4 100644
--- a/src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h
+++ b/src/plugins/geoservices/mapboxgl/qmapboxglstylechange_p.h
@@ -190,17 +190,4 @@ private:
QImage m_sprite;
};
-class QMapboxGLMapMargins : public QMapboxGLStyleChange
-{
-public:
- static QSharedPointer<QMapboxGLStyleChange> fromMapParameter(QGeoMapParameter *);
-
- void apply(QMapboxGL *map) override;
-
-private:
- QMapboxGLMapMargins() = default;
-
- QMargins m_margins;
-};
-
#endif // QQMAPBOXGLSTYLECHANGE_P_H
diff --git a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
index 9808b539..28aa930f 100644
--- a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
+++ b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp
@@ -46,6 +46,7 @@
#include <QtLocation/QPlaceIcon>
#include <QtLocation/QPlaceResult>
#include <QtLocation/QPlaceProposedSearchResult>
+#include <QtLocation/private/qplacesearchrequest_p.h>
#include <QtCore/QDebug>
@@ -113,15 +114,24 @@ void QPlaceSearchReplyHere::replyFinished()
results.append(parseSearchResult(item));
}
+ QPlaceSearchRequest r_orig = request();
+ QPlaceSearchRequestPrivate *rpimpl_orig = QPlaceSearchRequestPrivate::get(r_orig);
+
if (resultsObject.contains(QStringLiteral("next"))) {
QPlaceSearchRequest request;
request.setSearchContext(QUrl(resultsObject.value(QStringLiteral("next")).toString()));
+ QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(request);
+ rpimpl->related = true;
+ rpimpl->page = rpimpl_orig->page + 1;
setNextPageRequest(request);
}
if (resultsObject.contains(QStringLiteral("previous"))) {
QPlaceSearchRequest request;
request.setSearchContext(QUrl(resultsObject.value(QStringLiteral("previous")).toString()));
+ QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(request);
+ rpimpl->related = true;
+ rpimpl->page = rpimpl_orig->page - 1;
setPreviousPageRequest(request);
}
diff --git a/src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp b/src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp
index 8e436a97..65e39dee 100644
--- a/src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp
+++ b/src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp
@@ -40,9 +40,12 @@
#include <QStringList>
#include <QString>
#include <QtCore/QThreadPool>
+#include <QDebug>
#include <QtPositioning/QGeoRectangle>
+#include <QtPositioning/QGeoPath>
#include <QtLocation/QGeoRoute>
+#include <QtLocation/private/qgeoroutesegment_p.h>
QT_BEGIN_NAMESPACE
@@ -65,6 +68,10 @@ QGeoRouteXmlParser::~QGeoRouteXmlParser()
void QGeoRouteXmlParser::parse(const QByteArray &data)
{
m_data = data;
+// QFile file("/tmp/here.xml");
+// file.open(QIODevice::WriteOnly);
+// file.write(data);
+// file.close();
QThreadPool::globalInstance()->start(this);
}
@@ -134,8 +141,9 @@ bool QGeoRouteXmlParser::parseRoute(QGeoRoute *route)
{
Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "Route");
m_maneuvers.clear();
- m_segments.clear();
-
+// m_segments.clear();
+ m_legs.clear();
+ int legIndex = 0;
m_reader->readNext();
while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == "Route") &&
!m_reader->hasError()) {
@@ -161,7 +169,7 @@ bool QGeoRouteXmlParser::parseRoute(QGeoRoute *route)
return false;
route->setBounds(bounds);
} else if (m_reader->name() == "Leg") {
- if (!parseLeg())
+ if (!parseLeg(legIndex++))
return false;
} else if (m_reader->name() == "Summary") {
if (!parseSummary(route))
@@ -179,20 +187,32 @@ bool QGeoRouteXmlParser::parseRoute(QGeoRoute *route)
return postProcessRoute(route);
}
-bool QGeoRouteXmlParser::parseLeg()
+bool QGeoRouteXmlParser::parseLeg(int legIndex)
{
- Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "Leg");
-
+ Q_ASSERT(m_reader->isStartElement() && m_reader->name() == QStringLiteral("Leg"));
+ QGeoRouteLeg leg;
+ leg.setLegIndex(legIndex);
m_reader->readNext();
- while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == "Leg") &&
+ QList<QGeoManeuverContainer> maneuvers;
+ QList<QGeoRouteSegmentContainer> links;
+ while (!(m_reader->tokenType() == QXmlStreamReader::EndElement
+ && m_reader->name() == QStringLiteral("Leg")) &&
!m_reader->hasError()) {
if (m_reader->tokenType() == QXmlStreamReader::StartElement) {
- if (m_reader->name() == "Maneuver") {
- if (!parseManeuver())
- return false;
- } else if (m_reader->name() == "Link") {
- if (!parseLink())
+ if (m_reader->name() == QStringLiteral("Maneuver")) {
+ if (!parseManeuver(maneuvers))
return false;
+ }
+// Currently unused, after requesting shape attribute in maneuvers.
+// Links, however, contain additional info, such as speed limits, and might become needed in the future.
+// else if (m_reader->name() == QStringLiteral("Link")) {
+// if (!parseLink(links))
+// return false;
+// }
+ else if (m_reader->name() == "TravelTime") {
+ leg.setTravelTime(qRound(m_reader->readElementText().toDouble()));
+ } else if (m_reader->name() == "Length") {
+ leg.setDistance(m_reader->readElementText().toDouble());
} else {
m_reader->skipCurrentElement();
}
@@ -200,81 +220,98 @@ bool QGeoRouteXmlParser::parseLeg()
m_reader->readNext();
}
- return !m_reader->hasError();
+ if (m_reader->hasError())
+ return false;
+
+ m_legs << leg;
+// m_segments << links;
+ m_maneuvers << maneuvers;
+ return true;
}
+//static bool fuzzyCompare(const QGeoCoordinate &a, const QGeoCoordinate& b)
+//{
+// return qFuzzyCompare(a.latitude(), b.latitude()) && qFuzzyCompare(a.longitude(), b.longitude());
+//}
+
bool QGeoRouteXmlParser::postProcessRoute(QGeoRoute *route)
{
- QList<QGeoRouteSegment> routeSegments;
+ QList<QList<QGeoRouteSegment>> legSegments;
+ Q_ASSERT(m_maneuvers.size());
+
- int maneuverIndex = 0;
- for (int i = 0; i < m_segments.count(); ++i) {
- // In case there is a maneuver in the middle of the list with no
- // link ID attached, attach it to the next available segment
- while ((maneuverIndex < m_maneuvers.size() - 1) && m_maneuvers.at(maneuverIndex).toId.isEmpty()) {
+ // Step 3: populate the linkMap, linkId -> linkContainer
+ for (int i = 0; i < m_maneuvers.size(); i++) {
+ legSegments << QList<QGeoRouteSegment>();
+ QList<QGeoRouteSegment> &segments = legSegments[i];
+ QList<QGeoManeuverContainer> &maneuvers = m_maneuvers[i];
+ for (int j = 0; j < m_maneuvers.at(i).size(); j++) {
+ QGeoManeuverContainer &maneuver = maneuvers[j];
QGeoRouteSegment segment;
- segment.setManeuver(m_maneuvers.at(maneuverIndex).maneuver);
- QList<QGeoCoordinate> path; // use instruction position as one point segment path
- path.append(m_maneuvers.at(maneuverIndex).maneuver.position());
- segment.setPath(path);
- routeSegments.append(segment);
- ++maneuverIndex;
- }
- QGeoRouteSegment segment = m_segments.at(i).segment;
- if ((maneuverIndex < m_maneuvers.size()) && m_segments.at(i).id == m_maneuvers.at(maneuverIndex).toId) {
- segment.setManeuver(m_maneuvers.at(maneuverIndex).maneuver);
- ++maneuverIndex;
+ QVariantMap extendedAttributes;
+ extendedAttributes["first"] = maneuver.first;
+ extendedAttributes["last"] = maneuver.last;
+ extendedAttributes["legIndex"] = i;
+ extendedAttributes["id"] = maneuver.id;
+ extendedAttributes["toLink"] = maneuver.toLink;
+ extendedAttributes["index"] = j;
+ maneuver.maneuver.setExtendedAttributes(extendedAttributes);
+
+ segment.setDistance(maneuver.maneuver.distanceToNextInstruction());
+ segment.setTravelTime(maneuver.maneuver.timeToNextInstruction());
+ segment.setPath(maneuver.path);
+ segment.setManeuver(maneuver.maneuver);
+ segments << segment;
}
- routeSegments.append(segment);
- }
-
- // For the final maneuver in the list, make sure to attach it to the very
- // last segment on the path, this is why we don't process the last
- // maneuver in the loop above
- while (maneuverIndex < m_maneuvers.size()) {
- QGeoRouteSegment segment;
- segment.setManeuver(m_maneuvers.at(maneuverIndex).maneuver);
- QList<QGeoCoordinate> path; // use instruction position as one point segment path
- path.append(m_maneuvers.at(maneuverIndex).maneuver.position());
- segment.setPath(path);
-
- routeSegments.append(segment);
- ++maneuverIndex;
}
- QList<QGeoRouteSegment> compactedRouteSegments;
- compactedRouteSegments.append(routeSegments.first());
- routeSegments.removeFirst();
-
- while (routeSegments.size() > 0) {
- QGeoRouteSegment segment = routeSegments.first();
- routeSegments.removeFirst();
-
- QGeoRouteSegment lastSegment = compactedRouteSegments.last();
-
- if (lastSegment.maneuver().isValid()) {
- compactedRouteSegments.append(segment);
- } else {
- compactedRouteSegments.removeLast();
- lastSegment.setDistance(lastSegment.distance() + segment.distance());
- lastSegment.setTravelTime(lastSegment.travelTime() + segment.travelTime());
- QList<QGeoCoordinate> path = lastSegment.path();
- path.append(segment.path());
- lastSegment.setPath(path);
- lastSegment.setManeuver(segment.maneuver());
- compactedRouteSegments.append(lastSegment);
+ // Step 7: connect all segments.
+ QGeoRouteSegment segment;
+ QGeoRouteSegment firstSegment;
+ for (auto &segments: legSegments) {
+ for (int j = 0; j < segments.size(); j++) {
+ if (segment.isValid()) {
+ segment.setNextRouteSegment(segments[j]);
+ } else {
+ firstSegment = segments[j];
+ }
+ segment = segments[j];
+ if (j == segments.size() - 1) {
+ QGeoRouteSegmentPrivate *sp = QGeoRouteSegmentPrivate::get(segment);
+ sp->setLegLastSegment(true);
+ }
}
}
- if (compactedRouteSegments.size() > 0) {
- route->setFirstRouteSegment(compactedRouteSegments.at(0));
- for (int i = 0; i < compactedRouteSegments.size() - 1; ++i)
- compactedRouteSegments[i].setNextRouteSegment(compactedRouteSegments.at(i + 1));
+ if (firstSegment.isValid())
+ route->setFirstRouteSegment(firstSegment);
+
+ // Step 8: fill route legs.
+ for (int i = 0; i < m_legs.size(); i++) {
+ m_legs[i].setTravelMode(route->travelMode());
+ m_legs[i].setRequest(route->request());
+ m_legs[i].setOverallRoute(*route);
+ m_legs[i].setLegIndex(i);
+
+ m_legs[i].setFirstRouteSegment(legSegments[i].first());
+
+ // handle path
+ QList<QGeoCoordinate> path;
+ QGeoRouteSegment s = m_legs[i].firstRouteSegment();
+ while (s.isValid()) {
+ path.append(s.path());
+ if (s.isLegLastSegment())
+ break;
+ s = s.nextRouteSegment();
+ }
+ m_legs[i].setPath(path);
+ m_legs[i].setBounds(QGeoPath(path).boundingGeoRectangle());
}
-
+ route->setRouteLegs(m_legs);
+ m_legs.clear();
+// m_segments.clear();
m_maneuvers.clear();
- m_segments.clear();
return true;
}
@@ -394,7 +431,7 @@ bool QGeoRouteXmlParser::parseCoordinates(QGeoCoordinate &coord)
return !m_reader->hasError();
}
-bool QGeoRouteXmlParser::parseManeuver()
+bool QGeoRouteXmlParser::parseManeuver(QList<QGeoManeuverContainer> &maneuvers)
{
Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "Maneuver");
@@ -415,8 +452,14 @@ bool QGeoRouteXmlParser::parseManeuver()
maneuverContainter.maneuver.setPosition(coordinates);
} else if (m_reader->name() == "Instruction") {
maneuverContainter.maneuver.setInstructionText(m_reader->readElementText());
+ } else if (m_reader->name() == "Shape") {
+ QString elementName = m_reader->name().toString();
+ QList<QGeoCoordinate> path;
+ if (!parseGeoPoints(m_reader->readElementText(), &path, elementName))
+ return false;
+ maneuverContainter.path = path;
} else if (m_reader->name() == "ToLink") {
- maneuverContainter.toId = m_reader->readElementText();
+ maneuverContainter.toLink = m_reader->readElementText();
} else if (m_reader->name() == "TravelTime") {
maneuverContainter.maneuver.setTimeToNextInstruction(qRound(m_reader->readElementText().toDouble()));
} else if (m_reader->name() == "Length") {
@@ -457,11 +500,11 @@ bool QGeoRouteXmlParser::parseManeuver()
if (m_reader->hasError())
return false;
- m_maneuvers.append(maneuverContainter);
+ maneuvers.append(maneuverContainter);
return true;
}
-bool QGeoRouteXmlParser::parseLink()
+bool QGeoRouteXmlParser::parseLink(QList<QGeoRouteSegmentContainer> &links)
{
Q_ASSERT(m_reader->isStartElement() && m_reader->name() == QStringLiteral("Link"));
m_reader->readNext();
@@ -498,8 +541,7 @@ bool QGeoRouteXmlParser::parseLink()
if (m_reader->hasError())
return false;
-
- m_segments.append(segmentContainer);
+ links.append(segmentContainer);
return true;
}
diff --git a/src/plugins/geoservices/nokia/qgeoroutexmlparser.h b/src/plugins/geoservices/nokia/qgeoroutexmlparser.h
index e2feb728..7f2cc149 100644
--- a/src/plugins/geoservices/nokia/qgeoroutexmlparser.h
+++ b/src/plugins/geoservices/nokia/qgeoroutexmlparser.h
@@ -45,6 +45,7 @@
#include <QtLocation/QGeoRouteRequest>
#include <QtLocation/QGeoRouteSegment>
#include <QtLocation/QGeoManeuver>
+#include <QtLocation/qgeoroute.h>
QT_BEGIN_NAMESPACE
@@ -58,7 +59,12 @@ class QGeoManeuverContainer
public:
QGeoManeuver maneuver;
QString id;
- QString toId;
+ QString toLink; // Id of the link this maneuver brings into
+ int legIndex = 0;
+ int index = 0;
+ QList<QGeoCoordinate> path;
+ bool first = false;
+ bool last = false;
};
class QGeoRouteSegmentContainer
@@ -67,6 +73,11 @@ public:
QGeoRouteSegment segment;
QString id;
QString maneuverId;
+
+ bool operator ==(const QGeoRouteSegmentContainer &other) const
+ {
+ return ( segment == other.segment && id == other.id && maneuverId == other.maneuverId );
+ }
};
class QGeoDynamicSpeedInfoContainer
@@ -104,9 +115,9 @@ private:
bool parseMode(QGeoRoute *route);
bool parseSummary(QGeoRoute *route);
bool parseGeoPoints(const QString &strPoints, QList<QGeoCoordinate> *geoPoints, const QString &elementName);
- bool parseLeg();
- bool parseManeuver();
- bool parseLink();
+ bool parseLeg(int legIndex);
+ bool parseManeuver(QList<QGeoManeuverContainer> &maneuvers);
+ bool parseLink(QList<QGeoRouteSegmentContainer> &links);
bool postProcessRoute(QGeoRoute *route);
bool parseBoundingBox(QGeoRectangle &bounds);
@@ -117,8 +128,9 @@ private:
QXmlStreamReader *m_reader;
QList<QGeoRoute> m_results;
- QList<QGeoManeuverContainer> m_maneuvers;
- QList<QGeoRouteSegmentContainer> m_segments;
+ QList<QGeoRouteLeg> m_legs;
+ QList<QList<QGeoManeuverContainer>> m_maneuvers;
+ //QList<QList<QGeoRouteSegmentContainer>> m_segments;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/nokia/qgeoroutingmanagerengine_nokia.cpp b/src/plugins/geoservices/nokia/qgeoroutingmanagerengine_nokia.cpp
index 1ae01636..73b998b1 100644
--- a/src/plugins/geoservices/nokia/qgeoroutingmanagerengine_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeoroutingmanagerengine_nokia.cpp
@@ -399,46 +399,36 @@ QString QGeoRoutingManagerEngineNokia::routeRequestString(const QGeoRouteRequest
requestString += trimDouble(area.bottomRight().longitude());
}
-// TODO: work out what was going on here
-// - segment and instruction/maneuever functions are mixed and matched
-// - tried to implement sensible equivalents below
-// QStringList legAttributes;
-// if (request.instructionDetail() & QGeoRouteRequest::BasicSegmentData) {
-// requestString += "&linkattributes=sh,le"; //shape,length
-// legAttributes.append("links");
-// }
-//
-// if (request.instructionDetail() & QGeoRouteRequest::BasicInstructions) {
-// legAttributes.append("maneuvers");
-// requestString += "&maneuverattributes=po,tt,le,di"; //position,traveltime,length,direction
-// if (!(request.instructionDetail() & QGeoRouteRequest::NoSegmentData))
-// requestString += ",li"; //link
-// }
-
QStringList legAttributes;
- if (request.segmentDetail() & QGeoRouteRequest::BasicSegmentData) {
+// if (request.segmentDetail() & QGeoRouteRequest::BasicSegmentData) // QTBUG-70501, this code expects to find links
+ {
requestString += "&linkattributes=sh,le"; //shape,length
legAttributes.append("links");
}
- if (request.maneuverDetail() & QGeoRouteRequest::BasicManeuvers) {
+// if (request.maneuverDetail() & QGeoRouteRequest::BasicManeuvers) // QTBUG-70501, this code expects to find maneuvers
+ {
legAttributes.append("maneuvers");
- requestString += "&maneuverattributes=po,tt,le,di"; //position,traveltime,length,direction
+ //requestString += "&maneuverattributes=po,tt,le,di"; //position,traveltime,length,direction
+ requestString += "&maneuverattributes=all";
if (!(request.segmentDetail() & QGeoRouteRequest::NoSegmentData))
requestString += ",li"; //link
}
+ // Handle QTBUG-70502, when API fixes it
requestString += "&routeattributes=sm,sh,bb,lg"; //summary,shape,boundingBox,legs
if (legAttributes.count() > 0) {
requestString += "&legattributes=";
requestString += legAttributes.join(",");
}
+ // Handle QTBUG-70503, when API fixes it
requestString += "&departure=";
requestString += QDateTime::currentDateTime().toUTC().toString("yyyy-MM-ddThh:mm:ssZ");
requestString += "&instructionformat=text";
+ // ToDo: make this request-able
requestString += "&metricSystem=";
if (QLocale::MetricSystem == measurementSystem())
requestString += "metric";
@@ -447,6 +437,7 @@ QString QGeoRoutingManagerEngineNokia::routeRequestString(const QGeoRouteRequest
const QLocale loc(locale());
+ // ToDo: make this request-able
if (QLocale::C != loc.language() && QLocale::AnyLanguage != loc.language()) {
requestString += "&language=";
requestString += loc.name();
diff --git a/src/plugins/geoservices/nokia/qgeoserviceproviderplugin_nokia.cpp b/src/plugins/geoservices/nokia/qgeoserviceproviderplugin_nokia.cpp
index f68a0d99..e4ef86d6 100644
--- a/src/plugins/geoservices/nokia/qgeoserviceproviderplugin_nokia.cpp
+++ b/src/plugins/geoservices/nokia/qgeoserviceproviderplugin_nokia.cpp
@@ -47,11 +47,6 @@
#include <QNetworkProxy>
#include <QCoreApplication>
-static void initResources()
-{
- Q_INIT_RESOURCE(nokia);
-}
-
QT_BEGIN_NAMESPACE
namespace
@@ -117,7 +112,6 @@ namespace
QGeoServiceProviderFactoryNokia::QGeoServiceProviderFactoryNokia()
{
- initResources();
}
QGeoCodingManagerEngine *QGeoServiceProviderFactoryNokia::createGeocodingManagerEngine(
diff --git a/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp b/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
index ab575463..5094b72e 100644
--- a/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
+++ b/src/plugins/geoservices/nokia/qplacemanagerengine_nokiav2.cpp
@@ -52,6 +52,7 @@
#include <QtCore/QJsonArray>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
+#include <QtCore/QRegularExpression>
#include <QtCore/QStandardPaths>
#include <QtCore/QUrlQuery>
#include <QtNetwork/QNetworkProxy>
@@ -690,13 +691,14 @@ QPlaceIcon QPlaceManagerEngineNokiaV2::icon(const QString &remotePath,
QPlaceIcon icon;
QVariantMap params;
- QRegExp rx("(.*)(/icons/categories/.*)");
+ QRegularExpression rx("(.*)(/icons/categories/.*)");
+ QRegularExpressionMatch match = rx.match(remotePath);
QString iconPrefix;
QString nokiaIcon;
- if (rx.indexIn(remotePath) != -1 && !rx.cap(1).isEmpty() && !rx.cap(2).isEmpty()) {
- iconPrefix = rx.cap(1);
- nokiaIcon = rx.cap(2);
+ if (match.hasMatch() && !match.capturedRef(1).isEmpty() && !match.capturedRef(2).isEmpty()) {
+ iconPrefix = match.captured(1);
+ nokiaIcon = match.captured(2);
if (QFile::exists(m_localDataPath + nokiaIcon))
iconPrefix = QString::fromLatin1("file://") + m_localDataPath;
diff --git a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
index 732e8d72..af2a03b1 100644
--- a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
@@ -75,6 +75,13 @@ void QGeoRouteReplyOsm::networkReplyFinished()
QList<QGeoRoute> routes;
QString errorString;
QGeoRouteReply::Error error = parser->parseReply(routes, errorString, reply->readAll());
+ // Setting the request into the result
+ for (QGeoRoute &route : routes) {
+ route.setRequest(request());
+ for (QGeoRoute &leg: route.routeLegs()) {
+ leg.setRequest(request());
+ }
+ }
if (error == QGeoRouteReply::NoError) {
setRoutes(routes.mid(0, request().numberAlternativeRoutes() + 1));
diff --git a/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp b/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
index 3c201e41..be66414f 100644
--- a/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
+++ b/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp
@@ -191,7 +191,7 @@ QPlaceSearchReply *QPlaceManagerEngineOsm::search(const QPlaceSearchRequest &req
this, SLOT(replyError(QPlaceReply::Error,QString)));
if (m_debugQuery)
- reply->requestUrl = requestUrl.toString();
+ reply->requestUrl = requestUrl.url(QUrl::None);
return reply;
}
diff --git a/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp b/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
index 0228a975..80c50d1b 100644
--- a/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
+++ b/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp
@@ -48,6 +48,7 @@
#include <QtPositioning/QGeoRectangle>
#include <QtLocation/QPlaceResult>
#include <QtLocation/QPlaceSearchRequest>
+#include <QtLocation/private/qplacesearchrequest_p.h>
QT_BEGIN_NAMESPACE
@@ -135,6 +136,9 @@ void QPlaceSearchReplyOsm::replyFinished()
parameters.insert(QStringLiteral("ExcludePlaceIds"), epi);
r.setSearchContext(parameters);
+ QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(r);
+ rpimpl->related = true;
+ rpimpl->page--;
setPreviousPageRequest(r);
}
@@ -147,6 +151,9 @@ void QPlaceSearchReplyOsm::replyFinished()
parameters.insert(QStringLiteral("ExcludePlaceIds"), epi);
r.setSearchContext(parameters);
+ QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(r);
+ rpimpl->related = true;
+ rpimpl->page++;
setNextPageRequest(r);
}
diff --git a/src/plugins/position/android/src/qgeopositioninfosource_android.cpp b/src/plugins/position/android/src/qgeopositioninfosource_android.cpp
index 7b4706d8..59b8beab 100644
--- a/src/plugins/position/android/src/qgeopositioninfosource_android.cpp
+++ b/src/plugins/position/android/src/qgeopositioninfosource_android.cpp
@@ -223,7 +223,7 @@ void QGeoPositionInfoSourceAndroid::requestTimeout()
const QGeoPositionInfo info = queuedSingleUpdates[i];
//anything newer by 20s is always better
- const int timeDelta = best.timestamp().secsTo(info.timestamp());
+ const qint64 timeDelta = best.timestamp().secsTo(info.timestamp());
if (abs(timeDelta) > 20) {
if (timeDelta > 0)
best = info;
@@ -232,7 +232,7 @@ void QGeoPositionInfoSourceAndroid::requestTimeout()
//compare accuracy
if (info.hasAttribute(QGeoPositionInfo::HorizontalAccuracy) &&
- info.hasAttribute(QGeoPositionInfo::HorizontalAccuracy))
+ best.hasAttribute(QGeoPositionInfo::HorizontalAccuracy))
{
best = info.attribute(QGeoPositionInfo::HorizontalAccuracy) <
best.attribute(QGeoPositionInfo::HorizontalAccuracy) ? info : best;
diff --git a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm
index 94c5b807..6435963b 100644
--- a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm
+++ b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm
@@ -47,16 +47,16 @@
#define MINIMUM_UPDATE_INTERVAL 1000
@interface PositionLocationDelegate : NSObject <CLLocationManagerDelegate>
+@end
+
+@implementation PositionLocationDelegate
{
QGeoPositionInfoSourceCL *m_positionInfoSource;
}
-@end
-@implementation PositionLocationDelegate
-- (id)initWithInfoSource:(QGeoPositionInfoSourceCL*) positionInfoSource
+- (instancetype)initWithInfoSource:(QGeoPositionInfoSourceCL*) positionInfoSource
{
- self = [super init];
- if (self) {
+ if ((self = [self init])) {
m_positionInfoSource = positionInfoSource;
}
return self;
@@ -140,7 +140,39 @@ void QGeoPositionInfoSourceCL::setUpdateInterval(int msec)
bool QGeoPositionInfoSourceCL::enableLocationManager()
{
if (!m_locationManager) {
- m_locationManager = [[CLLocationManager alloc] init];
+ if ([CLLocationManager locationServicesEnabled]) {
+ // Location Services Are Enabled
+ switch ([CLLocationManager authorizationStatus]) {
+ case kCLAuthorizationStatusNotDetermined:
+ // User has not yet made a choice with regards to this application
+ break;
+ case kCLAuthorizationStatusRestricted:
+ // This application is not authorized to use location services. Due
+ // to active restrictions on location services, the user cannot change
+ // this status, and may not have personally denied authorization
+ return false;
+ case kCLAuthorizationStatusDenied:
+ // User has explicitly denied authorization for this application, or
+ // location services are disabled in Settings
+ return false;
+ case kCLAuthorizationStatusAuthorizedAlways:
+ // This app is authorized to start location services at any time.
+ break;
+#ifndef Q_OS_MACOS
+ case kCLAuthorizationStatusAuthorizedWhenInUse:
+ // This app is authorized to start most location services while running in the foreground.
+ break;
+#endif
+ default:
+ // By default, try to enable it
+ break;
+ }
+ } else {
+ // Location Services Disabled
+ return false;
+ }
+
+ m_locationManager = [[CLLocationManager alloc] init];
#if defined(Q_OS_IOS) || defined(Q_OS_WATCHOS)
if (__builtin_available(watchOS 4.0, *)) {
@@ -162,18 +194,29 @@ bool QGeoPositionInfoSourceCL::enableLocationManager()
m_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
m_locationManager.delegate = [[PositionLocationDelegate alloc] initWithInfoSource:this];
- // These two methods are new in iOS 8. They require NSLocationAlwaysUsageDescription
- // and NSLocationWhenInUseUsageDescription to be set in Info.plist to work (methods are
- // noop if there are no such entries in plist).
+ // -requestAlwaysAuthorization is available on iOS (>= 8.0) and watchOS (>= 2.0).
+ // This method requires both NSLocationAlwaysAndWhenInUseUsageDescription and
+ // NSLocationWhenInUseUsageDescription entries present in Info.plist (otherwise,
+ // while probably a noop, the call generates a warning).
+ // -requestWhenInUseAuthorization only requires NSLocationWhenInUseUsageDescription
+ // entry in Info.plist (available on iOS (>= 8.0), tvOS (>= 9.0) and watchOS (>= 2.0).
+
#ifndef Q_OS_MACOS
+ NSDictionary<NSString *, id> *infoDict = NSBundle.mainBundle.infoDictionary;
+ const bool hasAlwaysUseUsage = !![infoDict objectForKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"];
+ const bool hasWhenInUseUsage = !![infoDict objectForKey:@"NSLocationWhenInUseUsageDescription"];
#ifndef Q_OS_TVOS
- [m_locationManager requestAlwaysAuthorization];
-#endif
- [m_locationManager requestWhenInUseAuthorization];
-#endif
+ if (hasAlwaysUseUsage && hasWhenInUseUsage)
+ [m_locationManager requestAlwaysAuthorization];
+ else
+#endif // !Q_OS_TVOS
+ if (hasWhenInUseUsage)
+ [m_locationManager requestWhenInUseAuthorization];
+#endif // !Q_OS_MACOS
+
}
- return (m_locationManager != 0);
+ return (m_locationManager != nullptr);
}
void QGeoPositionInfoSourceCL::setTimeoutInterval(int msec)
diff --git a/src/plugins/position/geoclue2/geoclue2.pro b/src/plugins/position/geoclue2/geoclue2.pro
new file mode 100644
index 00000000..1bd129d5
--- /dev/null
+++ b/src/plugins/position/geoclue2/geoclue2.pro
@@ -0,0 +1,30 @@
+TARGET = qtposition_geoclue2
+
+QT = core positioning dbus
+
+HEADERS += \
+ qgeopositioninfosource_geoclue2_p.h \
+ qgeopositioninfosourcefactory_geoclue2.h \
+ geocluetypes.h
+
+SOURCES += \
+ qgeopositioninfosource_geoclue2.cpp \
+ qgeopositioninfosourcefactory_geoclue2.cpp \
+ geocluetypes.cpp
+
+QDBUSXML2CPP_INTERFACE_HEADER_FLAGS += \
+ "-N -i geocluetypes.h"
+
+DBUS_INTERFACES += \
+ org.freedesktop.GeoClue2.Manager.xml \
+ org.freedesktop.GeoClue2.Client.xml \
+ org.freedesktop.GeoClue2.Location.xml
+
+INCLUDEPATH += $$QT.location.includes $$OUT_PWD
+
+OTHER_FILES += \
+ plugin.json
+
+PLUGIN_TYPE = position
+PLUGIN_CLASS_NAME = QGeoPositionInfoSourceFactoryGeoclue2
+load(qt_plugin)
diff --git a/src/plugins/position/geoclue2/geocluetypes.cpp b/src/plugins/position/geoclue2/geocluetypes.cpp
new file mode 100644
index 00000000..dec55d3c
--- /dev/null
+++ b/src/plugins/position/geoclue2/geocluetypes.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "geocluetypes.h"
+
+QT_BEGIN_NAMESPACE
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Timestamp &ts)
+{
+ arg.beginStructure();
+ arg << ts.m_seconds;
+ arg << ts.m_microseconds;
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &arg, Timestamp &ts)
+{
+ arg.beginStructure();
+ arg >> ts.m_seconds;
+ arg >> ts.m_microseconds;
+ arg.endStructure();
+ return arg;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/position/geoclue2/geocluetypes.h b/src/plugins/position/geoclue2/geocluetypes.h
new file mode 100644
index 00000000..0f3eb522
--- /dev/null
+++ b/src/plugins/position/geoclue2/geocluetypes.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GEOCLUETYPES_H
+#define GEOCLUETYPES_H
+
+#include <QtDBus/QDBusArgument>
+
+class Timestamp
+{
+public:
+ quint64 m_seconds = 0;
+ quint64 m_microseconds = 0;
+};
+
+Q_DECLARE_METATYPE(Timestamp)
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_TYPEINFO(Timestamp, Q_MOVABLE_TYPE);
+
+QDBusArgument &operator<<(QDBusArgument &arg, const Timestamp &ts);
+const QDBusArgument &operator>>(const QDBusArgument &arg, Timestamp &ts);
+
+QT_END_NAMESPACE
+
+#endif // GEOCLUETYPES_H
diff --git a/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Client.xml b/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Client.xml
new file mode 100644
index 00000000..4a9399b7
--- /dev/null
+++ b/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Client.xml
@@ -0,0 +1,122 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<!--
+ GeoClue 2.0 Interface Specification
+
+ Copyright 2013 Red Hat, Inc.
+-->
+
+<node>
+
+ <!--
+ org.freedesktop.GeoClue2.Client:
+ @short_description: The Application-specific client API
+
+ This is the interface you use to retrieve location information and receive
+ location update signals from GeoClue service. You get the client object to
+ use this interface on from org.freedesktop.GeoClue2.Manager.GetClient()
+ method.
+ -->
+ <interface name="org.freedesktop.GeoClue2.Client">
+ <!--
+ Location:
+
+ Current location as path to a #org.freedesktop.GeoClue2.Location object.
+ Please note that this property will be set to "/" (D-Bus equivalent of
+ null) initially, until Geoclue finds user's location. You want to delay
+ reading this property until your callback to
+ #org.freedesktop.GeoClue2.Client::LocationUpdated signal is called for
+ the first time after starting the client.
+ -->
+ <property name="Location" type="o" access="read"/>
+
+ <!--
+ DistanceThreshold:
+
+ Contains the current distance threshold in meters. This value is used
+ by the service when it gets new location info. If the distance moved is
+ below the threshold, it won't emit the LocationUpdated signal.
+ The default value is 0. When TimeThreshold is zero, it always emits
+ the signal.
+ -->
+ <property name="DistanceThreshold" type="u" access="readwrite">
+ <annotation name="org.freedesktop.Accounts.DefaultValue" value="0"/>
+ </property>
+
+ <!--
+ TimeThreshold:
+
+ Contains the current time threshold in seconds. This value is used
+ by the service when it gets new location info. If the time since the
+ last update is below the threshold, it won't emit the LocationUpdated
+ signal. The default value is 0. When TimeThreshold is zero, it always
+ emits the signal.
+ -->
+ <property name="TimeThreshold" type="u" access="readwrite">
+ <annotation name="org.freedesktop.Accounts.DefaultValue" value="0"/>
+ </property>
+
+ <!--
+ DesktopId:
+
+ The desktop file id (the basename of the desktop file). This property
+ must be set by applications for authorization to work.
+ -->
+ <property name="DesktopId" type="s" access="readwrite"/>
+
+ <!--
+ RequestedAccuracyLevel:
+
+ The level of accuracy requested by client, as
+ <link linkend="GClueAccuracyLevel">GClueAccuracyLevel</link>.
+
+ Please keep in mind that the actual accuracy of location information is
+ dependent on available hardware on your machine, external resources
+ and/or how much accuracy user agrees to be confortable with.
+ -->
+ <property name="RequestedAccuracyLevel" type="u" access="readwrite"/>
+
+ <!--
+ Active:
+
+ If client is active, i-e started successfully using
+ org.freedesktop.GeoClue2.Client.Start() and receiving location updates.
+
+ Please keep in mind that geoclue can at any time stop and start the
+ client on user (agent) request. Applications that are interested in
+ in these changes, should watch for changes in this property.
+ -->
+ <property name="Active" type="b" access="read"/>
+
+ <!--
+ Start:
+
+ Start receiving events about the current location. Applications should
+ hook-up to #org.freedesktop.GeoClue2.Client::LocationUpdated signal
+ before calling this method.
+ -->
+ <method name="Start"/>
+
+ <!--
+ Stop:
+
+ Stop receiving events about the current location.
+ -->
+ <method name="Stop"/>
+
+ <!--
+ LocationUpdated:
+ @old: old location as path to a #org.freedesktop.GeoClue2.Location object
+ @new: new location as path to a #org.freedesktop.GeoClue2.Location object
+
+ The signal is emitted every time the location changes.
+ The client should set the DistanceThreshold property to control how
+ often this signal is emitted.
+ -->
+ <signal name="LocationUpdated">
+ <arg name="oldLocation" type="o"/>
+ <arg name="newLocation" type="o"/>
+ </signal>
+ </interface>
+</node>
diff --git a/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Location.xml b/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Location.xml
new file mode 100644
index 00000000..ebf2ea6b
--- /dev/null
+++ b/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Location.xml
@@ -0,0 +1,96 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<!--
+ GeoClue 2.0 Interface Specification
+
+ Copyright 2013 Red Hat, Inc.
+-->
+
+<node>
+
+ <!--
+ org.freedesktop.GeoClue2.Location:
+ @short_description: The Location interface
+
+ This is the interface you use on location objects.
+ -->
+ <interface name="org.freedesktop.GeoClue2.Location">
+
+ <!--
+ Latitude:
+
+ The latitude of the location, in degrees.
+ -->
+ <property name="Latitude" type="d" access="read"/>
+
+ <!--
+ Longitude:
+
+ The longitude of the location, in degrees.
+ -->
+ <property name="Longitude" type="d" access="read"/>
+
+ <!--
+ Accuracy:
+
+ The accuracy of the location fix, in meters.
+ -->
+ <property name="Accuracy" type="d" access="read"/>
+
+ <!--
+ Altitude:
+
+ The altitude of the location fix, in meters. When unknown, its set to
+ minimum double value, -1.7976931348623157e+308.
+ -->
+ <property name="Altitude" type="d" access="read"/>
+
+ <!--
+ Speed:
+
+ The speed in meters per second. When unknown, it's set to -1.0.
+ -->
+ <property name="Speed" type="d" access="read"/>
+
+ <!--
+ Heading:
+
+ The heading direction in degrees with respect to North direction, in
+ clockwise order. That means North becomes 0 degree, East: 90 degrees,
+ South: 180 degrees, West: 270 degrees and so on. When unknown,
+ it's set to -1.0.
+ -->
+ <property name="Heading" type="d" access="read"/>
+
+ <!--
+ Description:
+
+ A human-readable description of the location, if available.
+
+ WARNING: Applications should not rely on this property since not all
+ sources provide a description. If you really need a description (or
+ more details) about current location, use a reverse-geocoding API, e.g
+ geocode-glib.
+ -->
+ <property name="Description" type="s" access="read"/>
+
+
+ <!--
+ Timestamp:
+
+ The timestamp when the location was determined, in seconds and
+ microseconds since the Epoch. This is the time of measurement if the
+ backend provided that information, otherwise the time when GeoClue
+ received the new location.
+
+ Note that GeoClue can't guarantee that the timestamp will always
+ monotonically increase, as a backend may not respect that.
+ Also note that a timestamp can be very old, e.g. because of a cached
+ location.
+ -->
+ <property name="Timestamp" type="(tt)" access="read">
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="Timestamp"/>
+ </property>
+ </interface>
+</node>
diff --git a/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Manager.xml b/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Manager.xml
new file mode 100644
index 00000000..cf9590f6
--- /dev/null
+++ b/src/plugins/position/geoclue2/org.freedesktop.GeoClue2.Manager.xml
@@ -0,0 +1,60 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<!--
+ GeoClue 2.0 Interface Specification
+
+ Copyright 2013 Red Hat, Inc.
+-->
+
+<node>
+
+ <!--
+ org.freedesktop.GeoClue2.Manager:
+ @short_description: The GeoClue service manager
+
+ This is the interface you use to talk to main GeoClue2 manager object at
+ path "/org/freedesktop/GeoClue2/Manager". The only thing you do with this
+ interface is to call org.freedesktop.GeoClue2.Manager.GetClient() on it
+ to get your application specific client object.
+ -->
+ <interface name="org.freedesktop.GeoClue2.Manager">
+ <!--
+ InUse:
+
+ Whether service is currently is use by any application.
+ -->
+ <property name="InUse" type="b" access="read"/>
+
+ <!--
+ AvailableAccuracyLevel:
+
+ The level of available accuracy, as
+ <link linkend="GClueAccuracyLevel">GClueAccuracyLevel</link>.
+ -->
+ <property name="AvailableAccuracyLevel" type="u" access="read"/>
+
+ <!--
+ GetClient:
+ @client: The path for newly created client object
+
+ Retrieves a client object which can only be used by the calling
+ application only.
+ -->
+ <method name="GetClient">
+ <arg name="client" type="o" direction="out"/>
+ </method>
+
+ <!--
+ AddAgent:
+ @id: The Desktop ID (excluding .desktop) of the agent
+
+ An API for user authorization agents to register themselves. Each agent
+ is responsible for the user it is running as. Application developers
+ can and should simply ignore this API.
+ -->
+ <method name="AddAgent">
+ <arg name="id" type="s" direction="in"/>
+ </method>
+ </interface>
+</node>
diff --git a/src/plugins/position/geoclue2/plugin.json b/src/plugins/position/geoclue2/plugin.json
new file mode 100644
index 00000000..c23d40e0
--- /dev/null
+++ b/src/plugins/position/geoclue2/plugin.json
@@ -0,0 +1,9 @@
+{
+ "Keys": ["geoclue2"],
+ "Provider": "geoclue2",
+ "Position": true,
+ "Satellite": false,
+ "Monitor": false,
+ "Priority": 1000,
+ "Testable": false
+}
diff --git a/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp b/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp
new file mode 100644
index 00000000..10484e3b
--- /dev/null
+++ b/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp
@@ -0,0 +1,443 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeopositioninfosource_geoclue2_p.h"
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QSaveFile>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QTimer>
+#include <QtDBus/QDBusPendingCallWatcher>
+
+// Auto-generated D-Bus files.
+#include <client_interface.h>
+#include <location_interface.h>
+
+Q_DECLARE_LOGGING_CATEGORY(lcPositioningGeoclue2)
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+// NOTE: Copied from the /usr/include/libgeoclue-2.0/gclue-client.h
+enum GClueAccuracyLevel {
+ GCLUE_ACCURACY_LEVEL_NONE = 0,
+ GCLUE_ACCURACY_LEVEL_COUNTRY = 1,
+ GCLUE_ACCURACY_LEVEL_CITY = 4,
+ GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD = 5,
+ GCLUE_ACCURACY_LEVEL_STREET = 6,
+ GCLUE_ACCURACY_LEVEL_EXACT = 8
+};
+
+const char GEOCLUE2_SERVICE_NAME[] = "org.freedesktop.GeoClue2";
+const int MINIMUM_UPDATE_INTERVAL = 1000;
+const int UPDATE_TIMEOUT_COLD_START = 120000;
+
+static QString lastPositionFilePath()
+{
+ return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
+ + QStringLiteral("/qtposition-geoclue2");
+}
+
+} // namespace
+
+QGeoPositionInfoSourceGeoclue2::QGeoPositionInfoSourceGeoclue2(QObject *parent)
+ : QGeoPositionInfoSource(parent)
+ , m_requestTimer(new QTimer(this))
+ , m_manager(QLatin1String(GEOCLUE2_SERVICE_NAME),
+ QStringLiteral("/org/freedesktop/GeoClue2/Manager"),
+ QDBusConnection::systemBus(),
+ this)
+{
+ qDBusRegisterMetaType<Timestamp>();
+
+ restoreLastPosition();
+
+ m_requestTimer->setSingleShot(true);
+ connect(m_requestTimer, &QTimer::timeout,
+ this, &QGeoPositionInfoSourceGeoclue2::requestUpdateTimeout);
+}
+
+QGeoPositionInfoSourceGeoclue2::~QGeoPositionInfoSourceGeoclue2()
+{
+ saveLastPosition();
+}
+
+void QGeoPositionInfoSourceGeoclue2::setUpdateInterval(int msec)
+{
+ QGeoPositionInfoSource::setUpdateInterval(msec);
+ configureClient();
+}
+
+QGeoPositionInfo QGeoPositionInfoSourceGeoclue2::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
+{
+ if (fromSatellitePositioningMethodsOnly && !m_lastPositionFromSatellite)
+ return QGeoPositionInfo();
+ return m_lastPosition;
+}
+
+QGeoPositionInfoSourceGeoclue2::PositioningMethods QGeoPositionInfoSourceGeoclue2::supportedPositioningMethods() const
+{
+ bool ok;
+ const auto accuracy = m_manager.property("AvailableAccuracyLevel").toUInt(&ok);
+ if (!ok) {
+ const_cast<QGeoPositionInfoSourceGeoclue2 *>(this)->setError(AccessError);
+ return NoPositioningMethods;
+ }
+
+ switch (accuracy) {
+ case GCLUE_ACCURACY_LEVEL_COUNTRY:
+ case GCLUE_ACCURACY_LEVEL_CITY:
+ case GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD:
+ case GCLUE_ACCURACY_LEVEL_STREET:
+ return NonSatellitePositioningMethods;
+ case GCLUE_ACCURACY_LEVEL_EXACT:
+ return AllPositioningMethods;
+ case GCLUE_ACCURACY_LEVEL_NONE:
+ default:
+ return NoPositioningMethods;
+ }
+}
+
+void QGeoPositionInfoSourceGeoclue2::setPreferredPositioningMethods(PositioningMethods methods)
+{
+ QGeoPositionInfoSource::setPreferredPositioningMethods(methods);
+ configureClient();
+}
+
+int QGeoPositionInfoSourceGeoclue2::minimumUpdateInterval() const
+{
+ return MINIMUM_UPDATE_INTERVAL;
+}
+
+QGeoPositionInfoSource::Error QGeoPositionInfoSourceGeoclue2::error() const
+{
+ return m_error;
+}
+
+void QGeoPositionInfoSourceGeoclue2::startUpdates()
+{
+ if (m_running) {
+ qCWarning(lcPositioningGeoclue2) << "Already running";
+ return;
+ }
+
+ qCDebug(lcPositioningGeoclue2) << "Starting updates";
+ m_running = true;
+
+ startClient();
+
+ if (m_lastPosition.isValid()) {
+ QMetaObject::invokeMethod(this, "positionUpdated", Qt::QueuedConnection,
+ Q_ARG(QGeoPositionInfo, m_lastPosition));
+ }
+}
+
+void QGeoPositionInfoSourceGeoclue2::stopUpdates()
+{
+ if (!m_running) {
+ qCWarning(lcPositioningGeoclue2) << "Already stopped";
+ return;
+ }
+
+ qCDebug(lcPositioningGeoclue2) << "Stopping updates";
+ m_running = false;
+
+ stopClient();
+}
+
+void QGeoPositionInfoSourceGeoclue2::requestUpdate(int timeout)
+{
+ if (timeout < minimumUpdateInterval() && timeout != 0) {
+ emit updateTimeout();
+ return;
+ }
+
+ if (m_requestTimer->isActive()) {
+ qCDebug(lcPositioningGeoclue2) << "Request timer was active, ignoring startUpdates";
+ return;
+ }
+
+ m_requestTimer->start(timeout ? timeout : UPDATE_TIMEOUT_COLD_START);
+ startClient();
+}
+
+void QGeoPositionInfoSourceGeoclue2::setError(QGeoPositionInfoSource::Error error)
+{
+ m_error = error;
+ emit QGeoPositionInfoSource::error(m_error);
+}
+
+void QGeoPositionInfoSourceGeoclue2::restoreLastPosition()
+{
+#if !defined(QT_NO_DATASTREAM)
+ const auto filePath = lastPositionFilePath();
+ QFile file(filePath);
+ if (file.open(QIODevice::ReadOnly)) {
+ QDataStream out(&file);
+ out >> m_lastPosition;
+ }
+#endif
+}
+
+void QGeoPositionInfoSourceGeoclue2::saveLastPosition()
+{
+#if !defined(QT_NO_DATASTREAM) && QT_CONFIG(temporaryfile)
+ if (!m_lastPosition.isValid())
+ return;
+
+ const auto filePath = lastPositionFilePath();
+ QSaveFile file(filePath);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ QDataStream out(&file);
+ // Only save position and timestamp.
+ out << QGeoPositionInfo(m_lastPosition.coordinate(), m_lastPosition.timestamp());
+ file.commit();
+ }
+#endif
+}
+
+void QGeoPositionInfoSourceGeoclue2::createClient()
+{
+ const QDBusPendingReply<QDBusObjectPath> reply = m_manager.GetClient();
+ const auto watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished,
+ [this](QDBusPendingCallWatcher *watcher) {
+ const QScopedPointer<QDBusPendingCallWatcher, QScopedPointerDeleteLater>
+ scopedWatcher(watcher);
+ const QDBusPendingReply<QDBusObjectPath> reply = *scopedWatcher;
+ if (reply.isError()) {
+ const auto error = reply.error();
+ qCWarning(lcPositioningGeoclue2) << "Unable to obtain the client patch:"
+ << error.name() + error.message();
+ setError(AccessError);
+ } else {
+ const QString clientPath = reply.value().path();
+ qCDebug(lcPositioningGeoclue2) << "Client path is:"
+ << clientPath;
+ delete m_client;
+ m_client = new OrgFreedesktopGeoClue2ClientInterface(
+ QLatin1String(GEOCLUE2_SERVICE_NAME),
+ clientPath,
+ QDBusConnection::systemBus(),
+ this);
+ if (!m_client->isValid()) {
+ const auto error = m_client->lastError();
+ qCCritical(lcPositioningGeoclue2) << "Unable to create the client object:"
+ << error.name() << error.message();
+ setError(AccessError);
+ delete m_client;
+ } else {
+ connect(m_client.data(), &OrgFreedesktopGeoClue2ClientInterface::LocationUpdated,
+ this, &QGeoPositionInfoSourceGeoclue2::handleNewLocation);
+
+ if (configureClient())
+ startClient();
+ }
+ }
+ });
+}
+
+void QGeoPositionInfoSourceGeoclue2::startClient()
+{
+ // only start the client if someone asked for it already
+ if (!m_running && !m_requestTimer->isActive())
+ return;
+
+ if (!m_client) {
+ createClient();
+ return;
+ }
+
+ const QDBusPendingReply<> reply = m_client->Start();
+ const auto watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished,
+ [this](QDBusPendingCallWatcher *watcher) {
+ const QScopedPointer<QDBusPendingCallWatcher, QScopedPointerDeleteLater>
+ scopedWatcher(watcher);
+ const QDBusPendingReply<> reply = *scopedWatcher;
+ if (reply.isError()) {
+ const auto error = reply.error();
+ qCCritical(lcPositioningGeoclue2) << "Unable to start the client:"
+ << error.name() << error.message();
+ setError(AccessError);
+ delete m_client;
+ } else {
+ qCDebug(lcPositioningGeoclue2) << "Client successfully started";
+
+ const QDBusObjectPath location = m_client->location();
+ const QString path = location.path();
+ if (path.isEmpty() || path == QLatin1String("/"))
+ return;
+
+ handleNewLocation({}, location);
+ }
+ });
+}
+
+void QGeoPositionInfoSourceGeoclue2::stopClient()
+{
+ // Only stop client if updates are no longer wanted.
+ if (m_requestTimer->isActive() || m_running || !m_client)
+ return;
+
+ const QDBusPendingReply<> reply = m_client->Stop();
+ const auto watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished,
+ [this](QDBusPendingCallWatcher *watcher) {
+ const QScopedPointer<QDBusPendingCallWatcher, QScopedPointerDeleteLater>
+ scopedWatcher(watcher);
+ const QDBusPendingReply<> reply = *scopedWatcher;
+ if (reply.isError()) {
+ const auto error = reply.error();
+ qCCritical(lcPositioningGeoclue2) << "Unable to stop the client:"
+ << error.name() << error.message();
+ setError(AccessError);
+ } else {
+ qCDebug(lcPositioningGeoclue2) << "Client successfully stopped";
+ }
+ delete m_client;
+ });
+}
+
+bool QGeoPositionInfoSourceGeoclue2::configureClient()
+{
+ if (!m_client)
+ return false;
+
+ auto desktopId = QString::fromUtf8(qgetenv("QT_GEOCLUE_APP_DESKTOP_ID"));
+ if (desktopId.isEmpty())
+ desktopId = QCoreApplication::applicationName();
+ if (desktopId.isEmpty()) {
+ qCCritical(lcPositioningGeoclue2) << "Unable to configure the client "
+ "due to the application desktop id "
+ "is not set via QT_GEOCLUE_APP_DESKTOP_ID "
+ "envirorment variable or QCoreApplication::applicationName";
+ setError(AccessError);
+ return false;
+ }
+
+ m_client->setDesktopId(desktopId);
+
+ const auto msecs = updateInterval();
+ const uint secs = qMax(uint(msecs), 0u) / 1000u;
+ m_client->setTimeThreshold(secs);
+
+ const auto methods = preferredPositioningMethods();
+ switch (methods) {
+ case SatellitePositioningMethods:
+ m_client->setRequestedAccuracyLevel(GCLUE_ACCURACY_LEVEL_EXACT);
+ break;
+ case NonSatellitePositioningMethods:
+ m_client->setRequestedAccuracyLevel(GCLUE_ACCURACY_LEVEL_STREET);
+ break;
+ case AllPositioningMethods:
+ m_client->setRequestedAccuracyLevel(GCLUE_ACCURACY_LEVEL_EXACT);
+ break;
+ default:
+ m_client->setRequestedAccuracyLevel(GCLUE_ACCURACY_LEVEL_NONE);
+ break;
+ }
+
+ return true;
+}
+
+void QGeoPositionInfoSourceGeoclue2::requestUpdateTimeout()
+{
+ qCDebug(lcPositioningGeoclue2) << "Request update timeout occurred";
+
+ emit updateTimeout();
+
+ stopClient();
+}
+
+void QGeoPositionInfoSourceGeoclue2::handleNewLocation(const QDBusObjectPath &oldLocation,
+ const QDBusObjectPath &newLocation)
+{
+ if (m_requestTimer->isActive())
+ m_requestTimer->stop();
+
+ const auto oldPath = oldLocation.path();
+ const auto newPath = newLocation.path();
+ qCDebug(lcPositioningGeoclue2) << "Old location object path:" << oldPath;
+ qCDebug(lcPositioningGeoclue2) << "New location object path:" << newPath;
+
+ OrgFreedesktopGeoClue2LocationInterface location(
+ QLatin1String(GEOCLUE2_SERVICE_NAME),
+ newPath,
+ QDBusConnection::systemBus(),
+ this);
+ if (!location.isValid()) {
+ const auto error = location.lastError();
+ qCCritical(lcPositioningGeoclue2) << "Unable to create the location object:"
+ << error.name() << error.message();
+ } else {
+ QGeoCoordinate coordinate(location.latitude(),
+ location.longitude());
+ if (const auto altitude = location.altitude() > std::numeric_limits<double>::min())
+ coordinate.setAltitude(altitude);
+
+ const Timestamp ts = location.timestamp();
+ if (ts.m_seconds == 0 && ts.m_microseconds == 0) {
+ const auto dt = QDateTime::currentDateTime();
+ m_lastPosition = QGeoPositionInfo(coordinate, dt);
+ } else {
+ auto dt = QDateTime::fromSecsSinceEpoch(qint64(ts.m_seconds));
+ dt = dt.addMSecs(ts.m_microseconds / 1000);
+ m_lastPosition = QGeoPositionInfo(coordinate, dt);
+ }
+
+ const auto accuracy = location.accuracy();
+ // We assume that an accuracy as 0.0 means that it comes from a sattelite.
+ m_lastPositionFromSatellite = qFuzzyCompare(accuracy, 0.0);
+
+ m_lastPosition.setAttribute(QGeoPositionInfo::HorizontalAccuracy, accuracy);
+ if (const auto speed = location.speed() >= 0.0)
+ m_lastPosition.setAttribute(QGeoPositionInfo::GroundSpeed, speed);
+ if (const auto heading = location.heading() >= 0.0)
+ m_lastPosition.setAttribute(QGeoPositionInfo::Direction, heading);
+
+ emit positionUpdated(m_lastPosition);
+ qCDebug(lcPositioningGeoclue2) << "New position:" << m_lastPosition;
+ }
+
+ stopClient();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2_p.h b/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2_p.h
new file mode 100644
index 00000000..16f5b9a1
--- /dev/null
+++ b/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGEOPOSITIONINFOSOURCE_GEOCLUE2_P_H
+#define QGEOPOSITIONINFOSOURCE_GEOCLUE2_P_H
+
+#include <QtPositioning/QGeoPositionInfoSource>
+#include <QtCore/QPointer>
+#include <manager_interface.h>
+
+class OrgFreedesktopGeoClue2ClientInterface;
+
+QT_BEGIN_NAMESPACE
+class QDBusObjectPath;
+class QTimer;
+
+class QGeoPositionInfoSourceGeoclue2 : public QGeoPositionInfoSource
+{
+ Q_OBJECT
+
+public:
+ explicit QGeoPositionInfoSourceGeoclue2(QObject *parent = nullptr);
+ ~QGeoPositionInfoSourceGeoclue2();
+
+ // From QGeoPositionInfoSource
+ void setUpdateInterval(int msec) override;
+ QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const override;
+ PositioningMethods supportedPositioningMethods() const override;
+ void setPreferredPositioningMethods(PositioningMethods methods) override;
+ int minimumUpdateInterval() const override;
+
+ Error error() const override;
+
+ void startUpdates() override;
+ void stopUpdates() override;
+ void requestUpdate(int timeout = 5000) override;
+
+private:
+ void setError(QGeoPositionInfoSource::Error error);
+ void restoreLastPosition();
+ void saveLastPosition();
+ void createClient();
+ bool configureClient();
+ void startClient();
+ void stopClient();
+ void requestUpdateTimeout();
+ void handleNewLocation(const QDBusObjectPath &oldLocation,
+ const QDBusObjectPath &newLocation);
+
+ QTimer *m_requestTimer = nullptr;
+ OrgFreedesktopGeoClue2ManagerInterface m_manager;
+ QPointer<OrgFreedesktopGeoClue2ClientInterface> m_client;
+ bool m_running = false;
+ bool m_lastPositionFromSatellite = false;
+ QGeoPositionInfoSource::Error m_error = NoError;
+ QGeoPositionInfo m_lastPosition;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOPOSITIONINFOSOURCE_GEOCLUE2_P_H
diff --git a/src/plugins/position/geoclue2/qgeopositioninfosourcefactory_geoclue2.cpp b/src/plugins/position/geoclue2/qgeopositioninfosourcefactory_geoclue2.cpp
new file mode 100644
index 00000000..a713c31f
--- /dev/null
+++ b/src/plugins/position/geoclue2/qgeopositioninfosourcefactory_geoclue2.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeopositioninfosource_geoclue2_p.h"
+#include "qgeopositioninfosourcefactory_geoclue2.h"
+
+#include <QtCore/QLoggingCategory>
+
+Q_LOGGING_CATEGORY(lcPositioningGeoclue2, "qt.positioning.geoclue2")
+
+QT_BEGIN_NAMESPACE
+
+QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryGeoclue2::positionInfoSource(QObject *parent)
+{
+ return new QGeoPositionInfoSourceGeoclue2(parent);
+}
+
+QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryGeoclue2::satelliteInfoSource(QObject *parent)
+{
+ Q_UNUSED(parent)
+ return nullptr;
+}
+
+QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryGeoclue2::areaMonitor(QObject *parent)
+{
+ Q_UNUSED(parent)
+ return nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/position/geoclue2/qgeopositioninfosourcefactory_geoclue2.h b/src/plugins/position/geoclue2/qgeopositioninfosourcefactory_geoclue2.h
new file mode 100644
index 00000000..bfacd848
--- /dev/null
+++ b/src/plugins/position/geoclue2/qgeopositioninfosourcefactory_geoclue2.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtPositioning module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGEOPOSITIONINFOSOURCEFACTORY_GEOCLUE2_H
+#define QGEOPOSITIONINFOSOURCEFACTORY_GEOCLUE2_H
+
+#include <QtCore/QObject>
+#include <QtPositioning/QGeoPositionInfoSourceFactory>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Qt Positioning plugin for Geoclue. This plugin supports Geoclue version 2.x.
+*/
+class QGeoPositionInfoSourceFactoryGeoclue2 : public QObject, public QGeoPositionInfoSourceFactory
+{
+ Q_OBJECT
+
+ Q_PLUGIN_METADATA(IID "org.qt-project.qt.position.sourcefactory/5.0"
+ FILE "plugin.json")
+
+ Q_INTERFACES(QGeoPositionInfoSourceFactory)
+
+public:
+ QGeoPositionInfoSource *positionInfoSource(QObject *parent) override;
+ QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent) override;
+ QGeoAreaMonitorSource *areaMonitor(QObject *parent) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOPOSITIONINFOSOURCEFACTORY_GEOCLUE2_H
diff --git a/src/plugins/position/position.pro b/src/plugins/position/position.pro
index b9832ff4..6800d5a3 100644
--- a/src/plugins/position/position.pro
+++ b/src/plugins/position/position.pro
@@ -2,7 +2,8 @@ TEMPLATE = subdirs
QT_FOR_CONFIG += positioning-private
-qtHaveModule(dbus):SUBDIRS += geoclue
+linux:qtHaveModule(dbus):SUBDIRS += geoclue
+linux:qtHaveModule(dbus):SUBDIRS += geoclue2
qtConfig(gypsy):SUBDIRS += gypsy
qtConfig(winrt_geolocation):SUBDIRS += winrt
qtHaveModule(simulator):SUBDIRS += simulator
diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp
index 046d862e..139a6b3d 100644
--- a/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp
+++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt.cpp
@@ -36,11 +36,12 @@
#include "qgeopositioninfosource_winrt_p.h"
-#include <QCoreApplication>
-#include <QMutex>
-#include <qfunctions_winrt.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qfunctions_winrt.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmutex.h>
#ifdef Q_OS_WINRT
-#include <private/qeventdispatcher_winrt_p.h>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
#endif
#include <functional>
@@ -56,10 +57,11 @@ using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
typedef ITypedEventHandler<Geolocator *, PositionChangedEventArgs *> GeoLocatorPositionHandler;
-typedef ITypedEventHandler<Geolocator *, StatusChangedEventArgs *> GeoLocatorStatusHandler;
typedef IAsyncOperationCompletedHandler<Geoposition*> PositionHandler;
typedef IAsyncOperationCompletedHandler<GeolocationAccessStatus> AccessHandler;
+Q_DECLARE_LOGGING_CATEGORY(lcPositioningWinRT)
+
QT_BEGIN_NAMESPACE
#ifndef Q_OS_WINRT
@@ -70,7 +72,36 @@ HRESULT runOnXamlThread(const std::function<HRESULT ()> &delegate, bool waitForR
return delegate();
}
}
-#endif
+
+static inline HRESULT await(const ComPtr<IAsyncOperation<GeolocationAccessStatus>> &asyncOp,
+ GeolocationAccessStatus *result)
+{
+ ComPtr<IAsyncInfo> asyncInfo;
+ HRESULT hr = asyncOp.As(&asyncInfo);
+ if (FAILED(hr))
+ return hr;
+
+ AsyncStatus status;
+ while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == AsyncStatus::Started)
+ QThread::yieldCurrentThread();
+
+ if (FAILED(hr) || status != AsyncStatus::Completed) {
+ HRESULT ec;
+ hr = asyncInfo->get_ErrorCode(&ec);
+ if (FAILED(hr))
+ return hr;
+ hr = asyncInfo->Close();
+ if (FAILED(hr))
+ return hr;
+ return ec;
+ }
+
+ if (FAILED(hr))
+ return hr;
+
+ return asyncOp->GetResults(result);
+}
+#endif // !Q_OS_WINRT
class QGeoPositionInfoSourceWinRTPrivate {
public:
@@ -83,13 +114,37 @@ public:
EventRegistrationToken positionToken;
QMutex mutex;
bool updatesOngoing;
+ int minimumUpdateInterval;
+
+ PositionStatus nativeStatus() const;
};
+PositionStatus QGeoPositionInfoSourceWinRTPrivate::nativeStatus() const
+{
+#ifdef Q_OS_WINRT
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
+
+ PositionStatus status;
+ HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, &status]() {
+ return locator->get_LocationStatus(&status);
+ });
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Could not query status");
+ return PositionStatus_NotAvailable;
+ }
+ return status;
+#else
+ return PositionStatus_Ready;
+#endif
+}
+
QGeoPositionInfoSourceWinRT::QGeoPositionInfoSourceWinRT(QObject *parent)
: QGeoPositionInfoSource(parent)
, d_ptr(new QGeoPositionInfoSourceWinRTPrivate)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
+ CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
Q_D(QGeoPositionInfoSourceWinRT);
d->positionError = QGeoPositionInfoSource::NoError;
d->updatesOngoing = false;
@@ -97,10 +152,13 @@ QGeoPositionInfoSourceWinRT::QGeoPositionInfoSourceWinRT(QObject *parent)
QGeoPositionInfoSourceWinRT::~QGeoPositionInfoSourceWinRT()
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
+ CoUninitialize();
}
int QGeoPositionInfoSourceWinRT::init()
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_D(QGeoPositionInfoSourceWinRT);
if (!requestAccess()) {
qWarning ("Location access failed.");
@@ -111,13 +169,11 @@ int QGeoPositionInfoSourceWinRT::init()
&d->locator);
RETURN_HR_IF_FAILED("Could not initialize native location services.");
- hr = d->locator->add_StatusChanged(Callback<GeoLocatorStatusHandler>(this,
- &QGeoPositionInfoSourceWinRT::onStatusChanged).Get(),
- &d->statusToken);
- RETURN_HR_IF_FAILED("Could not add status callback.");
-
- hr = d->locator->put_ReportInterval(1000);
- RETURN_HR_IF_FAILED("Could not initialize report interval.");
+ UINT32 interval;
+ hr = d->locator->get_ReportInterval(&interval);
+ RETURN_HR_IF_FAILED("Could not retrieve report interval.");
+ d->minimumUpdateInterval = static_cast<int>(interval);
+ setUpdateInterval(d->minimumUpdateInterval);
return hr;
});
@@ -137,7 +193,6 @@ int QGeoPositionInfoSourceWinRT::init()
d->positionToken.value = 0;
d->periodicTimer.setSingleShot(true);
- d->periodicTimer.setInterval(minimumUpdateInterval());
connect(&d->periodicTimer, &QTimer::timeout, this, &QGeoPositionInfoSourceWinRT::virtualPositionUpdate);
d->singleUpdateTimer.setSingleShot(true);
@@ -151,6 +206,7 @@ int QGeoPositionInfoSourceWinRT::init()
QGeoPositionInfo QGeoPositionInfoSourceWinRT::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_D(const QGeoPositionInfoSourceWinRT);
Q_UNUSED(fromSatellitePositioningMethodsOnly)
return d->lastPosition;
@@ -160,13 +216,8 @@ QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceWinRT::supporte
{
Q_D(const QGeoPositionInfoSourceWinRT);
- PositionStatus status;
- HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([d, &status]() {
- HRESULT hr = d->locator->get_LocationStatus(&status);
- return hr;
- });
- if (FAILED(hr))
- return QGeoPositionInfoSource::NoPositioningMethods;
+ PositionStatus status = d->nativeStatus();
+ qCDebug(lcPositioningWinRT) << __FUNCTION__ << status;
switch (status) {
case PositionStatus::PositionStatus_NoData:
@@ -180,6 +231,7 @@ QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSourceWinRT::supporte
void QGeoPositionInfoSourceWinRT::setPreferredPositioningMethods(QGeoPositionInfoSource::PositioningMethods methods)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__ << methods;
Q_D(QGeoPositionInfoSourceWinRT);
PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods();
@@ -187,7 +239,7 @@ void QGeoPositionInfoSourceWinRT::setPreferredPositioningMethods(QGeoPositionInf
if (previousPreferredPositioningMethods == preferredPositioningMethods())
return;
- bool needsRestart = d->positionToken.value != 0;
+ const bool needsRestart = d->positionToken.value != 0;
if (needsRestart)
stopHandler();
@@ -207,19 +259,20 @@ void QGeoPositionInfoSourceWinRT::setPreferredPositioningMethods(QGeoPositionInf
void QGeoPositionInfoSourceWinRT::setUpdateInterval(int msec)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__ << msec;
Q_D(QGeoPositionInfoSourceWinRT);
- // Windows Phone 8.1 and Windows 10 do not support 0 interval
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
- if (msec == 0)
- msec = minimumUpdateInterval();
-#endif
-
- // If msec is 0 we send updates as data becomes available, otherwise we force msec to be equal
- // to or larger than the minimum update interval.
+ // minimumUpdateInterval is initialized to the lowest possible update interval in init().
+ // Passing 0 will cause an error on Windows 10.
+ // See https://docs.microsoft.com/en-us/uwp/api/windows.devices.geolocation.geolocator.reportinterval
if (msec != 0 && msec < minimumUpdateInterval())
msec = minimumUpdateInterval();
- HRESULT hr = d->locator->put_ReportInterval(msec);
+ const bool needsRestart = d->positionToken.value != 0;
+
+ if (needsRestart)
+ stopHandler();
+
+ HRESULT hr = d->locator->put_ReportInterval(static_cast<UINT32>(msec));
if (FAILED(hr)) {
setError(QGeoPositionInfoSource::UnknownSourceError);
qErrnoWarning(hr, "Failed to set update interval");
@@ -229,17 +282,20 @@ void QGeoPositionInfoSourceWinRT::setUpdateInterval(int msec)
d->periodicTimer.setInterval(qMax(msec, minimumUpdateInterval()));
QGeoPositionInfoSource::setUpdateInterval(msec);
+
+ if (needsRestart)
+ startHandler();
}
int QGeoPositionInfoSourceWinRT::minimumUpdateInterval() const
{
- // We use one second to reduce potential timer events
- // in case the platform itself stops reporting
- return 1000;
+ Q_D(const QGeoPositionInfoSourceWinRT);
+ return d->minimumUpdateInterval;
}
void QGeoPositionInfoSourceWinRT::startUpdates()
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_D(QGeoPositionInfoSourceWinRT);
if (d->updatesOngoing)
@@ -253,6 +309,7 @@ void QGeoPositionInfoSourceWinRT::startUpdates()
void QGeoPositionInfoSourceWinRT::stopUpdates()
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_D(QGeoPositionInfoSourceWinRT);
stopHandler();
@@ -262,6 +319,7 @@ void QGeoPositionInfoSourceWinRT::stopUpdates()
bool QGeoPositionInfoSourceWinRT::startHandler()
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_D(QGeoPositionInfoSourceWinRT);
// Check if already attached
@@ -301,6 +359,7 @@ bool QGeoPositionInfoSourceWinRT::startHandler()
void QGeoPositionInfoSourceWinRT::stopHandler()
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_D(QGeoPositionInfoSourceWinRT);
if (!d->positionToken.value)
@@ -314,6 +373,7 @@ void QGeoPositionInfoSourceWinRT::stopHandler()
void QGeoPositionInfoSourceWinRT::requestUpdate(int timeout)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_D(QGeoPositionInfoSourceWinRT);
if (timeout != 0 && timeout < minimumUpdateInterval()) {
@@ -330,6 +390,7 @@ void QGeoPositionInfoSourceWinRT::requestUpdate(int timeout)
void QGeoPositionInfoSourceWinRT::virtualPositionUpdate()
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_D(QGeoPositionInfoSourceWinRT);
QMutexLocker locker(&d->mutex);
@@ -367,6 +428,7 @@ void QGeoPositionInfoSourceWinRT::singleUpdateTimeOut()
void QGeoPositionInfoSourceWinRT::updateSynchronized(QGeoPositionInfo currentInfo)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__ << currentInfo;
Q_D(QGeoPositionInfoSourceWinRT);
QMutexLocker locker(&d->mutex);
@@ -388,11 +450,13 @@ void QGeoPositionInfoSourceWinRT::updateSynchronized(QGeoPositionInfo currentInf
QGeoPositionInfoSource::Error QGeoPositionInfoSourceWinRT::error() const
{
Q_D(const QGeoPositionInfoSourceWinRT);
+ qCDebug(lcPositioningWinRT) << __FUNCTION__ << d->positionError;
return d->positionError;
}
void QGeoPositionInfoSourceWinRT::setError(QGeoPositionInfoSource::Error positionError)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__ << positionError;
Q_D(QGeoPositionInfoSourceWinRT);
if (positionError == d->positionError)
@@ -404,14 +468,9 @@ void QGeoPositionInfoSourceWinRT::setError(QGeoPositionInfoSource::Error positio
bool QGeoPositionInfoSourceWinRT::checkNativeState()
{
Q_D(QGeoPositionInfoSourceWinRT);
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
- PositionStatus status;
- HRESULT hr = d->locator->get_LocationStatus(&status);
- if (FAILED(hr)) {
- setError(QGeoPositionInfoSource::UnknownSourceError);
- qErrnoWarning(hr, "Could not query status");
- return false;
- }
+ PositionStatus status = d->nativeStatus();
bool result = false;
switch (status) {
@@ -432,41 +491,53 @@ bool QGeoPositionInfoSourceWinRT::checkNativeState()
HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPositionChangedEventArgs *args)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_UNUSED(locator);
HRESULT hr;
- ComPtr<IGeoposition> pos;
- hr = args->get_Position(&pos);
+ ComPtr<IGeoposition> position;
+ hr = args->get_Position(&position);
RETURN_HR_IF_FAILED("Could not access position object.");
QGeoPositionInfo currentInfo;
ComPtr<IGeocoordinate> coord;
- hr = pos->get_Coordinate(&coord);
+ hr = position->get_Coordinate(&coord);
if (FAILED(hr))
qErrnoWarning(hr, "Could not access coordinate");
- DOUBLE lat;
- hr = coord->get_Latitude(&lat);
+ ComPtr<IGeocoordinateWithPoint> pointCoordinate;
+ hr = coord.As(&pointCoordinate);
if (FAILED(hr))
- qErrnoWarning(hr, "Could not access latitude");
+ qErrnoWarning(hr, "Could not cast coordinate.");
- DOUBLE lon;
- hr = coord->get_Longitude(&lon);
+ ComPtr<IGeopoint> point;
+ hr = pointCoordinate->get_Point(&point);
if (FAILED(hr))
- qErrnoWarning(hr, "Could not access longitude");
-
- // Depending on data source altitude can
- // be identified or not
- IReference<double> *alt;
- hr = coord->get_Altitude(&alt);
- if (SUCCEEDED(hr) && alt) {
- double altd;
- hr = alt->get_Value(&altd);
- currentInfo.setCoordinate(QGeoCoordinate(lat, lon, altd));
- } else {
- currentInfo.setCoordinate(QGeoCoordinate(lat, lon));
+ qErrnoWarning(hr, "Could not obtain coordinate's point.");
+
+ BasicGeoposition pos;
+ hr = point->get_Position(&pos);
+ if (FAILED(hr))
+ qErrnoWarning(hr, "Could not obtain point's position.");
+
+ DOUBLE lat = pos.Latitude;
+ DOUBLE lon = pos.Longitude;
+ DOUBLE alt = pos.Altitude;
+
+ bool altitudeAvailable = false;
+ ComPtr<IGeoshape> shape;
+ hr = point.As(&shape);
+ if (SUCCEEDED(hr) && shape) {
+ AltitudeReferenceSystem altitudeSystem;
+ hr = shape->get_AltitudeReferenceSystem(&altitudeSystem);
+ if (SUCCEEDED(hr) && altitudeSystem == AltitudeReferenceSystem_Geoid)
+ altitudeAvailable = true;
}
+ if (altitudeAvailable)
+ currentInfo.setCoordinate(QGeoCoordinate(lat, lon, alt));
+ else
+ currentInfo.setCoordinate(QGeoCoordinate(lat, lon));
DOUBLE accuracy;
hr = coord->get_Accuracy(&accuracy);
@@ -477,7 +548,7 @@ HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPo
hr = coord->get_AltitudeAccuracy(&altAccuracy);
if (SUCCEEDED(hr) && altAccuracy) {
double value;
- hr = alt->get_Value(&value);
+ hr = altAccuracy->get_Value(&value);
currentInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy, value);
}
@@ -525,16 +596,9 @@ HRESULT QGeoPositionInfoSourceWinRT::onPositionChanged(IGeolocator *locator, IPo
return S_OK;
}
-HRESULT QGeoPositionInfoSourceWinRT::onStatusChanged(IGeolocator*, IStatusChangedEventArgs *args)
-{
- PositionStatus st;
- args->get_Status(&st);
- return S_OK;
-}
-
bool QGeoPositionInfoSourceWinRT::requestAccess() const
{
-#ifdef Q_OS_WINRT
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
static GeolocationAccessStatus accessStatus = GeolocationAccessStatus_Unspecified;
static ComPtr<IGeolocatorStatics> statics;
@@ -557,11 +621,12 @@ bool QGeoPositionInfoSourceWinRT::requestAccess() const
Q_ASSERT_SUCCEEDED(hr);
// We cannot wait inside the XamlThread as that would deadlock
+#ifdef Q_OS_WINRT
QWinRTFunctions::await(op, &accessStatus);
+#else
+ await(op, &accessStatus);
+#endif
return accessStatus == GeolocationAccessStatus_Allowed;
-#else // Q_OS_WINRT
- return true;
-#endif // Q_OS_WINRT
}
QT_END_NAMESPACE
diff --git a/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h b/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h
index 9f3a1c7f..4319ccae 100644
--- a/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h
+++ b/src/plugins/position/winrt/qgeopositioninfosource_winrt_p.h
@@ -51,7 +51,7 @@
#include "qgeopositioninfosource.h"
#include "qgeopositioninfo.h"
-#include <QTimer>
+#include <QtCore/qtimer.h>
#include <EventToken.h>
#include <wrl.h>
@@ -62,7 +62,6 @@ namespace ABI {
namespace Geolocation{
struct IGeolocator;
struct IPositionChangedEventArgs;
- struct IStatusChangedEventArgs;
}
}
}
@@ -76,7 +75,7 @@ class QGeoPositionInfoSourceWinRT : public QGeoPositionInfoSource
{
Q_OBJECT
public:
- QGeoPositionInfoSourceWinRT(QObject *parent = 0);
+ QGeoPositionInfoSourceWinRT(QObject *parent = nullptr);
~QGeoPositionInfoSourceWinRT();
int init();
@@ -92,9 +91,6 @@ public:
HRESULT onPositionChanged(ABI::Windows::Devices::Geolocation::IGeolocator *locator,
ABI::Windows::Devices::Geolocation::IPositionChangedEventArgs *args);
- HRESULT onStatusChanged(ABI::Windows::Devices::Geolocation::IGeolocator*,
- ABI::Windows::Devices::Geolocation::IStatusChangedEventArgs *args);
-
bool requestAccess() const;
Q_SIGNALS:
void nativePositionUpdate(const QGeoPositionInfo);
diff --git a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp
index e58744a0..b1ec6fb3 100644
--- a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp
+++ b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.cpp
@@ -37,24 +37,37 @@
#include "qgeopositioninfosourcefactory_winrt.h"
#include "qgeopositioninfosource_winrt_p.h"
+#include <QtCore/qloggingcategory.h>
+
+Q_LOGGING_CATEGORY(lcPositioningWinRT, "qt.positioning.winrt")
+
+QT_BEGIN_NAMESPACE
+
QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryWinRT::positionInfoSource(QObject *parent)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
QGeoPositionInfoSourceWinRT *src = new QGeoPositionInfoSourceWinRT(parent);
if (src->init() < 0) {
+ qCDebug(lcPositioningWinRT) << __FUNCTION__ << "Source initialization failed.";
delete src;
- src = 0;
+ return nullptr;
}
+ qCDebug(lcPositioningWinRT) << __FUNCTION__ << "Created position info source.";
return src;
}
QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryWinRT::satelliteInfoSource(QObject *parent)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_UNUSED(parent);
- return 0;
+ return nullptr;
}
QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryWinRT::areaMonitor(QObject *parent)
{
+ qCDebug(lcPositioningWinRT) << __FUNCTION__;
Q_UNUSED(parent);
- return 0;
+ return nullptr;
}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h
index 46cd3853..d09ddb64 100644
--- a/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h
+++ b/src/plugins/position/winrt/qgeopositioninfosourcefactory_winrt.h
@@ -37,8 +37,8 @@
#ifndef QGEOPOSITIONINFOSOURCEFACTORY_WINRT_H
#define QGEOPOSITIONINFOSOURCEFACTORY_WINRT_H
-#include <QObject>
-#include <QGeoPositionInfoSourceFactory>
+#include <QtCore/qobject.h>
+#include <QtPositioning/qgeopositioninfosourcefactory.h>
QT_BEGIN_NAMESPACE