diff options
89 files changed, 3096 insertions, 459 deletions
diff --git a/.qmake.conf b/.qmake.conf index 3ca13dd6..f06fddf5 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,7 +1,9 @@ load(qt_build_config) - CONFIG += warning_clean -MODULE_VERSION = 5.13.1 + +DEFINES += QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST + +MODULE_VERSION = 5.14.0 # Adds a way to debug location. The define is needed for multiple subprojects as they # include the essential headers. diff --git a/examples/location/location.pro b/examples/location/location.pro index 6506813f..69fa6516 100644 --- a/examples/location/location.pro +++ b/examples/location/location.pro @@ -7,6 +7,7 @@ qtHaveModule(quick) { mapviewer \ minimal_map \ itemview_transitions \ - planespotter \ - geojson_viewer + planespotter + + qtHaveModule(widgets): SUBDIRS += geojson_viewer } diff --git a/examples/location/mapviewer/mapviewer.pro b/examples/location/mapviewer/mapviewer.pro index 8e3daf81..a5cbbecb 100644 --- a/examples/location/mapviewer/mapviewer.pro +++ b/examples/location/mapviewer/mapviewer.pro @@ -6,7 +6,7 @@ SOURCES += main.cpp # Workaround for QTBUG-38735 QT_FOR_CONFIG += location-private -qtConfig(geoservices_mapboxgl): QT += sql opengl +qtConfig(geoservices_mapboxgl): QT += sql qtConfig(geoservices_osm): QT += concurrent RESOURCES += \ diff --git a/src/3rdparty/mapbox-gl-native b/src/3rdparty/mapbox-gl-native -Subproject 4b85252fbe811a786c6ee9eabedb7639b031dc5 +Subproject 5233c75b3f6c73623c5473b2d6573f31f3ddb4b diff --git a/src/imports/location/location.cpp b/src/imports/location/location.cpp index 45087751..40dffd5d 100644 --- a/src/imports/location/location.cpp +++ b/src/imports/location/location.cpp @@ -35,6 +35,7 @@ ****************************************************************************/ #include <QtLocation/private/qdeclarativegeoserviceprovider_p.h> +#include <QtPositioningQuick/private/qdeclarativepluginparameter_p.h> #include <QtLocation/private/qdeclarativegeomap_p.h> #include <QtLocation/private/qdeclarativegeoroute_p.h> @@ -97,7 +98,7 @@ public: // 5.0 is silent and not advertised qmlRegisterType<QDeclarativeGeoServiceProvider >(uri, major, minor, "Plugin"); - qmlRegisterType<QDeclarativeGeoServiceProviderParameter >(uri, major, minor, "PluginParameter"); + qmlRegisterType<QDeclarativePluginParameter >(uri, major, minor, "PluginParameter"); qmlRegisterUncreatableType<QDeclarativeGeoServiceProviderRequirements>(uri, major, minor, "PluginRequirements", QStringLiteral("PluginRequirements is not intended instantiable by developer.")); qmlRegisterType<QDeclarativeGeoMap >(uri, major, minor, "Map"); @@ -200,6 +201,11 @@ public: qmlRegisterType<QDeclarativeGeoRoute, 13>(uri, major, minor, "Route"); qmlRegisterType<QDeclarativeGeoRouteQuery, 13>(uri, major, minor, "RouteQuery"); + minor = 14; + qmlRegisterType<QDeclarativeGeoMap, 14>(uri, major, minor, "Map"); + qmlRegisterUncreatableType<QDeclarativeGeoMapItemBase, 14>(uri, major, minor, "GeoMapItemBase", + QStringLiteral("GeoMapItemBase is not intended instantiable by developer.")); + // Register the latest Qt version as QML type version qmlRegisterModule(uri, QT_VERSION_MAJOR, QT_VERSION_MINOR); diff --git a/src/imports/location/location.pro b/src/imports/location/location.pro index dec1149b..40605806 100644 --- a/src/imports/location/location.pro +++ b/src/imports/location/location.pro @@ -1,4 +1,4 @@ -QT += quick-private network positioning-private location-private qml-private core-private gui-private +QT += quick-private network positioning-private positioningquick-private location-private qml-private core-private gui-private SOURCES += \ location.cpp diff --git a/src/imports/positioning/positioning.cpp b/src/imports/positioning/positioning.cpp index 4349f63b..38b9378a 100644 --- a/src/imports/positioning/positioning.cpp +++ b/src/imports/positioning/positioning.cpp @@ -41,9 +41,9 @@ #include <QtPositioningQuick/private/qdeclarativegeoaddress_p.h> #include <QtPositioningQuick/private/qdeclarativegeolocation_p.h> #include <QtPositioning/private/qwebmercator_p.h> - -#include <QtPositioningQuick/private/qdeclarativepositionsource_p.h> #include <QtPositioningQuick/private/qdeclarativeposition_p.h> +#include <QtPositioningQuick/private/qdeclarativepositionsource_p.h> +#include <QtPositioningQuick/private/qdeclarativepluginparameter_p.h> #include <QtPositioningQuick/private/qquickgeocoordinateanimation_p.h> #include "locationsingleton.h" @@ -616,6 +616,9 @@ public: minor = 13; qmlRegisterType<QDeclarativeGeoLocation, 13>(uri, major, minor, "Location"); + minor = 14; + qmlRegisterType<QDeclarativePluginParameter >(uri, major, minor, "PluginParameter"); + // Register the latest Qt version as QML type version qmlRegisterModule(uri, QT_VERSION_MAJOR, QT_VERSION_MINOR); } else { diff --git a/src/location/declarativemaps/locationvaluetypehelper.cpp b/src/location/declarativemaps/locationvaluetypehelper.cpp index 8c96c8e7..3e2f3658 100644 --- a/src/location/declarativemaps/locationvaluetypehelper.cpp +++ b/src/location/declarativemaps/locationvaluetypehelper.cpp @@ -38,6 +38,8 @@ #include <QVariantMap> #include <QtQml/QQmlInfo> #include <private/qqmlengine_p.h> +#include <private/qv4scopedvalue_p.h> +#include <private/qv4arrayobject_p.h> QGeoCoordinate parseCoordinate(const QJSValue &value, bool *ok) diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp index b3496816..846fccbf 100644 --- a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp +++ b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp @@ -128,6 +128,17 @@ QT_BEGIN_NAMESPACE \image api-mapcircle.png */ +/*! + \qmlproperty bool QtLocation::MapCircle::autoFadeIn + + This property holds whether the item automatically fades in when zooming into the map + starting from very low zoom levels. By default this is \c true. + Setting this property to \c false causes the map item to always have the opacity specified + with the \l QtQuick::Item::opacity property, which is 1.0 by default. + + \since 5.14 +*/ + static const int CircleSamples = 128; struct Vertex diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp index 5997bd3e..4704dc3e 100644 --- a/src/location/declarativemaps/qdeclarativegeomap.cpp +++ b/src/location/declarativemaps/qdeclarativegeomap.cpp @@ -450,7 +450,7 @@ QQuickGeoMapGestureArea *QDeclarativeGeoMap::gesture() */ void QDeclarativeGeoMap::populateMap() { - QSet<QObject *> kids = children().toSet(); + QSet<QObject *> kids(children().cbegin(), children().cend()); const QList<QQuickItem *> quickKids = childItems(); for (QQuickItem *ite: quickKids) kids.insert(ite); @@ -892,8 +892,10 @@ void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel, bool overzoom) } else { const bool zlHasChanged = zoomLevel != m_cameraData.zoomLevel(); m_cameraData.setZoomLevel(zoomLevel); - if (zlHasChanged) + if (zlHasChanged) { emit zoomLevelChanged(zoomLevel); + emit visibleRegionChanged(); + } } } @@ -976,8 +978,10 @@ void QDeclarativeGeoMap::setBearing(qreal bearing) } else { const bool bearingHasChanged = bearing != m_cameraData.bearing(); m_cameraData.setBearing(bearing); - if (bearingHasChanged) + if (bearingHasChanged) { emit bearingChanged(bearing); + emit visibleRegionChanged(); + } } } @@ -1041,8 +1045,10 @@ void QDeclarativeGeoMap::setTilt(qreal tilt) } else { const bool tiltHasChanged = tilt != m_cameraData.tilt(); m_cameraData.setTilt(tilt); - if (tiltHasChanged) + if (tiltHasChanged) { emit tiltChanged(tilt); + emit visibleRegionChanged(); + } } } @@ -1099,8 +1105,10 @@ void QDeclarativeGeoMap::setFieldOfView(qreal fieldOfView) } else { const bool fovChanged = fieldOfView != m_cameraData.fieldOfView(); m_cameraData.setFieldOfView(fieldOfView); - if (fovChanged) + if (fovChanged) { emit fieldOfViewChanged(fieldOfView); + emit visibleRegionChanged(); + } } } @@ -1266,8 +1274,10 @@ void QDeclarativeGeoMap::setCenter(const QGeoCoordinate ¢er) } else { const bool centerHasChanged = center != m_cameraData.center(); m_cameraData.setCenter(center); - if (centerHasChanged) + if (centerHasChanged) { emit centerChanged(center); + emit visibleRegionChanged(); + } } } @@ -1309,15 +1319,18 @@ void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape) // shape invalidated -> nothing to fit anymore m_visibleRegion = QGeoRectangle(); m_pendingFitViewport = false; + emit visibleRegionChanged(); return; } if (!m_map || !width() || !height()) { m_pendingFitViewport = true; + emit visibleRegionChanged(); return; } fitViewportToGeoShape(m_visibleRegion); + emit visibleRegionChanged(); } QGeoShape QDeclarativeGeoMap::visibleRegion() const @@ -1755,6 +1768,9 @@ void QDeclarativeGeoMap::onCameraDataChanged(const QGeoCameraData &cameraData) emit tiltChanged(m_cameraData.tilt()); if (fovHasChanged) emit fieldOfViewChanged(m_cameraData.fieldOfView()); + if (centerHasChanged || zoomHasChanged || bearingHasChanged + || tiltHasChanged || fovHasChanged) + emit visibleRegionChanged(); } /*! diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h index 55751365..c97c3622 100644 --- a/src/location/declarativemaps/qdeclarativegeomap_p.h +++ b/src/location/declarativemaps/qdeclarativegeomap_p.h @@ -97,7 +97,7 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMap : public QQuickItem Q_PROPERTY(QList<QObject *> mapParameters READ mapParameters) Q_PROPERTY(QGeoServiceProvider::Error error READ error NOTIFY errorChanged) Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) - Q_PROPERTY(QGeoShape visibleRegion READ visibleRegion WRITE setVisibleRegion) + Q_PROPERTY(QGeoShape visibleRegion READ visibleRegion WRITE setVisibleRegion NOTIFY visibleRegionChanged) Q_PROPERTY(bool copyrightsVisible READ copyrightsVisible WRITE setCopyrightsVisible NOTIFY copyrightsVisibleChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(bool mapReady READ mapReady NOTIFY mapReadyChanged) @@ -233,6 +233,7 @@ Q_SIGNALS: void mapReadyChanged(bool ready); Q_REVISION(11) void mapObjectsChanged(); void visibleAreaChanged(); + Q_REVISION(14) void visibleRegionChanged(); protected: void mousePressEvent(QMouseEvent *event) override ; diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp index 162dcac4..9a2ae50b 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp @@ -208,14 +208,31 @@ void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordina setPosition(topLeft); } +bool QDeclarativeGeoMapItemBase::autoFadeIn() const +{ + return m_autoFadeIn; +} + static const double opacityRampMin = 1.5; static const double opacityRampMax = 2.5; + +void QDeclarativeGeoMapItemBase::setAutoFadeIn(bool fadeIn) +{ + if (fadeIn == m_autoFadeIn) + return; + m_autoFadeIn = fadeIn; + if (quickMap_ && quickMap_->zoomLevel() < opacityRampMax) + polishAndUpdate(); +} + /*! \internal */ float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const { - if (quickMap_->zoomLevel() > opacityRampMax) + if (!m_autoFadeIn) // Consider skipping the opacity node instead. + return 1.0; + else if (quickMap_->zoomLevel() > opacityRampMax) return 1.0; else if (quickMap_->zoomLevel() > opacityRampMin) return quickMap_->zoomLevel() - opacityRampMin; diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h index 23fd1da6..38a118e5 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h @@ -84,6 +84,7 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem Q_OBJECT Q_PROPERTY(QGeoShape geoShape READ geoShape WRITE setGeoShape STORED false ) + Q_PROPERTY(bool autoFadeIn READ autoFadeIn WRITE setAutoFadeIn REVISION 14) public: explicit QDeclarativeGeoMapItemBase(QQuickItem *parent = 0); virtual ~QDeclarativeGeoMapItemBase(); @@ -96,6 +97,9 @@ public: virtual const QGeoShape &geoShape() const = 0; virtual void setGeoShape(const QGeoShape &shape) = 0; + bool autoFadeIn() const; + void setAutoFadeIn(bool fadeIn); + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *); @@ -135,6 +139,7 @@ private: QDeclarativeGeoMapItemGroup *parentGroup_; QScopedPointer<QDeclarativeGeoMapItemTransitionManager> m_transitionManager; + bool m_autoFadeIn = true; friend class QDeclarativeGeoMap; friend class QDeclarativeGeoMapItemView; diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp index f7a251a2..43e24620 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp @@ -42,7 +42,6 @@ #include <QtCore/QAbstractItemModel> #include <QtQml/QQmlContext> -#include <QtQml/private/qqmldelegatemodel_p.h> #include <QtQml/private/qqmlopenmetaobject_p.h> #include <QtQuick/private/qquickanimation_p.h> #include <QtQml/QQmlListProperty> diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h index abac5bd5..8b2ab034 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h @@ -56,7 +56,7 @@ #include <QtQml/QQmlParserStatus> #include <QtQml/QQmlIncubator> #include <QtQml/qqml.h> -#include <QtQml/private/qqmldelegatemodel_p.h> +#include <private/qqmldelegatemodel_p.h> #include <QtQuick/private/qquicktransition_p.h> #include <QtLocation/private/qdeclarativegeomapitemgroup_p.h> diff --git a/src/location/declarativemaps/qdeclarativegeomapparameter.cpp b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp index c1361d5d..2408e1c7 100644 --- a/src/location/declarativemaps/qdeclarativegeomapparameter.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp @@ -39,10 +39,28 @@ #include <QByteArray> #include <QMetaObject> #include <QMetaProperty> -#include <QSignalMapper> +#include <QObject> QT_BEGIN_NAMESPACE +namespace { +class SignalMapper : public QObject +{ + Q_OBJECT + + int i; +public: + explicit SignalMapper(int i, QObject *parent = nullptr) + : QObject(parent), i(i) {} + +public Q_SLOTS: + void map() { emit mapped(i); } + +Q_SIGNALS: + void mapped(int); +}; +} // unnamed namespace + /*! \qmltype MapParameter \inqmlmodule QtLocation @@ -114,8 +132,7 @@ void QDeclarativeGeoMapParameter::componentComplete() return; } - QSignalMapper *mapper = new QSignalMapper(this); - mapper->setMapping(this, i); + SignalMapper *mapper = new SignalMapper(i, this); const QByteArray signalName = '2' + property.notifySignal().methodSignature(); // TODO: explain why '2' QObject::connect(this, signalName, mapper, SLOT(map())); @@ -131,3 +148,5 @@ void QDeclarativeGeoMapParameter::onPropertyUpdated(int index) } QT_END_NAMESPACE + +#include "qdeclarativegeomapparameter.moc" diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp index f7409788..ccca309b 100644 --- a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp @@ -115,6 +115,17 @@ QT_BEGIN_NAMESPACE \image api-mapquickitem.png */ +/*! + \qmlproperty bool QtLocation::MapQuickItem::autoFadeIn + + This property holds whether the item automatically fades in when zooming into the map + starting from very low zoom levels. By default this is \c true. + Setting this property to \c false causes the map item to always have the opacity specified + with the \l QtQuick::Item::opacity property, which is 1.0 by default. + + \since 5.14 +*/ + QMapQuickItemMatrix4x4::QMapQuickItemMatrix4x4(QObject *parent) : QQuickTransform(parent) { } void QMapQuickItemMatrix4x4::setMatrix(const QMatrix4x4 &matrix) diff --git a/src/location/declarativemaps/qdeclarativegeoroute.cpp b/src/location/declarativemaps/qdeclarativegeoroute.cpp index 8f5ec5fe..c536b65b 100644 --- a/src/location/declarativemaps/qdeclarativegeoroute.cpp +++ b/src/location/declarativemaps/qdeclarativegeoroute.cpp @@ -43,6 +43,8 @@ #include <QtQml/QQmlEngine> #include <QtQml/qqmlinfo.h> #include <QtQml/private/qqmlengine_p.h> +#include <QtQml/private/qv4scopedvalue_p.h> +#include <QtQml/private/qv4arrayobject_p.h> #include <QtPositioning/QGeoRectangle> QT_BEGIN_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp index 695f6972..f74557c0 100644 --- a/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp +++ b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp @@ -43,6 +43,8 @@ #include <QtQml/QQmlEngine> #include <QtQml/qqmlinfo.h> #include <QtQml/private/qqmlengine_p.h> +#include <QtQml/private/qv4scopedvalue_p.h> +#include <QtQml/private/qv4arrayobject_p.h> #include <QtLocation/QGeoRoutingManager> #include <QtPositioning/QGeoRectangle> #include "qdeclarativegeomapparameter_p.h" diff --git a/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp index b0e05f32..6751a47b 100644 --- a/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp +++ b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp @@ -38,6 +38,8 @@ #include <QtQml/QQmlEngine> #include <QtQml/private/qqmlengine_p.h> +#include <QtQml/private/qv4scopedvalue_p.h> +#include <QtQml/private/qv4arrayobject_p.h> QT_BEGIN_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp index b594d2dc..7810dc74 100644 --- a/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp +++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp @@ -124,7 +124,7 @@ void QDeclarativeGeoServiceProvider::setName(const QString &name) \internal */ bool QDeclarativeGeoServiceProvider::parametersReady() { - for (const QDeclarativeGeoServiceProviderParameter *p: qAsConst(parameters_)) { + for (const QDeclarativePluginParameter *p: qAsConst(parameters_)) { if (!p->isInitialized()) return false; } @@ -179,9 +179,9 @@ void QDeclarativeGeoServiceProvider::componentComplete() { complete_ = true; - for (QDeclarativeGeoServiceProviderParameter *p: qAsConst(parameters_)) { + for (QDeclarativePluginParameter *p: qAsConst(parameters_)) { if (!p->isInitialized()) { - connect(p, &QDeclarativeGeoServiceProviderParameter::initialized, + connect(p, &QDeclarativePluginParameter::initialized, this, &QDeclarativeGeoServiceProvider::tryAttach); } } @@ -192,7 +192,8 @@ void QDeclarativeGeoServiceProvider::componentComplete() || required_->mappingRequirements() != NoMappingFeatures || required_->routingRequirements() != NoRoutingFeatures || required_->geocodingRequirements() != NoGeocodingFeatures - || required_->placesRequirements() != NoPlacesFeatures) { + || required_->placesRequirements() != NoPlacesFeatures + || required_->navigationRequirements() != NoNavigationFeatures) { QStringList providers = QGeoServiceProvider::availableServiceProviders(); @@ -602,9 +603,9 @@ void QDeclarativeGeoServiceProvider::setLocales(const QStringList &locales) This property holds the list of plugin parameters. */ -QQmlListProperty<QDeclarativeGeoServiceProviderParameter> QDeclarativeGeoServiceProvider::parameters() +QQmlListProperty<QDeclarativePluginParameter> QDeclarativeGeoServiceProvider::parameters() { - return QQmlListProperty<QDeclarativeGeoServiceProviderParameter>(this, + return QQmlListProperty<QDeclarativePluginParameter>(this, 0, parameter_append, parameter_count, @@ -615,7 +616,7 @@ QQmlListProperty<QDeclarativeGeoServiceProviderParameter> QDeclarativeGeoService /*! \internal */ -void QDeclarativeGeoServiceProvider::parameter_append(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, QDeclarativeGeoServiceProviderParameter *parameter) +void QDeclarativeGeoServiceProvider::parameter_append(QQmlListProperty<QDeclarativePluginParameter> *prop, QDeclarativePluginParameter *parameter) { QDeclarativeGeoServiceProvider *p = static_cast<QDeclarativeGeoServiceProvider *>(prop->object); p->parameters_.append(parameter); @@ -626,7 +627,7 @@ void QDeclarativeGeoServiceProvider::parameter_append(QQmlListProperty<QDeclarat /*! \internal */ -int QDeclarativeGeoServiceProvider::parameter_count(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop) +int QDeclarativeGeoServiceProvider::parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop) { return static_cast<QDeclarativeGeoServiceProvider *>(prop->object)->parameters_.count(); } @@ -634,7 +635,7 @@ int QDeclarativeGeoServiceProvider::parameter_count(QQmlListProperty<QDeclarativ /*! \internal */ -QDeclarativeGeoServiceProviderParameter *QDeclarativeGeoServiceProvider::parameter_at(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, int index) +QDeclarativePluginParameter *QDeclarativeGeoServiceProvider::parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, int index) { return static_cast<QDeclarativeGeoServiceProvider *>(prop->object)->parameters_[index]; } @@ -642,7 +643,7 @@ QDeclarativeGeoServiceProviderParameter *QDeclarativeGeoServiceProvider::paramet /*! \internal */ -void QDeclarativeGeoServiceProvider::parameter_clear(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop) +void QDeclarativeGeoServiceProvider::parameter_clear(QQmlListProperty<QDeclarativePluginParameter> *prop) { QDeclarativeGeoServiceProvider *p = static_cast<QDeclarativeGeoServiceProvider *>(prop->object); p->parameters_.clear(); @@ -658,7 +659,7 @@ QVariantMap QDeclarativeGeoServiceProvider::parameterMap() const QVariantMap map; for (int i = 0; i < parameters_.size(); ++i) { - QDeclarativeGeoServiceProviderParameter *parameter = parameters_.at(i); + QDeclarativePluginParameter *parameter = parameters_.at(i); map.insert(parameter->name(), parameter->value()); } @@ -673,7 +674,8 @@ QDeclarativeGeoServiceProviderRequirements::QDeclarativeGeoServiceProviderRequir mapping_(QDeclarativeGeoServiceProvider::NoMappingFeatures), routing_(QDeclarativeGeoServiceProvider::NoRoutingFeatures), geocoding_(QDeclarativeGeoServiceProvider::NoGeocodingFeatures), - places_(QDeclarativeGeoServiceProvider::NoPlacesFeatures) + places_(QDeclarativeGeoServiceProvider::NoPlacesFeatures), + navigation_(QDeclarativeGeoServiceProvider::NoNavigationFeatures) { } @@ -769,6 +771,27 @@ void QDeclarativeGeoServiceProviderRequirements::setPlacesRequirements(const QDe /*! \internal */ +QDeclarativeGeoServiceProvider::NavigationFeatures QDeclarativeGeoServiceProviderRequirements::navigationRequirements() const +{ + return navigation_; +} + +/*! + \internal +*/ +void QDeclarativeGeoServiceProviderRequirements::setNavigationRequirements(const QDeclarativeGeoServiceProvider::NavigationFeatures &features) +{ + if (navigation_ == features) + return; + + navigation_ = features; + emit navigationRequirementsChanged(navigation_); + emit requirementsChanged(); +} + +/*! + \internal +*/ bool QDeclarativeGeoServiceProviderRequirements::matches(const QGeoServiceProvider *provider) const { QGeoServiceProvider::MappingFeatures mapping = @@ -817,13 +840,25 @@ bool QDeclarativeGeoServiceProviderRequirements::matches(const QGeoServiceProvid return false; } + QGeoServiceProvider::NavigationFeatures navigation = + static_cast<QGeoServiceProvider::NavigationFeatures>(int(navigation_)); + + if (navigation == QGeoServiceProvider::AnyNavigationFeatures) { + if (provider->navigationFeatures() == QGeoServiceProvider::NoNavigationFeatures) + return false; + } else { + if ((provider->navigationFeatures() & navigation) != navigation) + return false; + } + return true; } bool QDeclarativeGeoServiceProviderRequirements::operator == (const QDeclarativeGeoServiceProviderRequirements &rhs) const { return (mapping_ == rhs.mapping_ && routing_ == rhs.routing_ - && geocoding_ == rhs.geocoding_ && places_ == rhs.places_); + && geocoding_ == rhs.geocoding_ && places_ == rhs.places_ + && navigation_ == rhs.navigation_); } /******************************************************************************* @@ -831,21 +866,25 @@ bool QDeclarativeGeoServiceProviderRequirements::operator == (const QDeclarative /*! \qmltype PluginParameter - \instantiates QDeclarativeGeoServiceProviderParameter + \instantiates QDeclarativePluginParameter \inqmlmodule QtLocation \ingroup qml-QtLocation5-common \since QtLocation 5.5 - \brief The PluginParameter type describes a parameter to a \l Plugin. + \brief The PluginParameter type describes a parameter for a plugin, either + geo service \l Plugin, or \l{Qt Positioning plugins}{position Plugin}. The PluginParameter object is used to provide a parameter of some kind - to a Plugin. Typically these parameters contain details like an application - token for access to a service, or a proxy server to use for network access. + to a plugin. Typically these parameters contain details like an application + token for access to a service, or a proxy server to use for network access, + or the serial port to which a serial GPS receiver is connected. - To set such a parameter, declare a PluginParameter inside a \l Plugin - object, and give it \l{name} and \l{value} properties. A list of valid + To set such a parameter, declare a PluginParameter inside an element that accepts + plugin parameters as configuration objects, such as a \l Plugin object, or a + \l PositionSource object, and give it \l{name} and \l{value} properties. A list of valid parameter names for each plugin is available from the - \l {Qt Location#Plugin References and Parameters}{plugin reference pages}. + \l {Qt Location#Plugin References and Parameters}{plugin reference pages} for geoservice plugins, + and \l {Qt Positioning plugins#Default plugins} for position plugins. \section2 Example Usage @@ -861,33 +900,12 @@ bool QDeclarativeGeoServiceProviderRequirements::operator == (const QDeclarative \endcode */ -QDeclarativeGeoServiceProviderParameter::QDeclarativeGeoServiceProviderParameter(QObject *parent) - : QObject(parent) {} - -QDeclarativeGeoServiceProviderParameter::~QDeclarativeGeoServiceProviderParameter() {} - /*! \qmlproperty string PluginParameter::name This property holds the name of the plugin parameter as a single formatted string. This property is a write-once property. */ -void QDeclarativeGeoServiceProviderParameter::setName(const QString &name) -{ - if (!name_.isEmpty() || name.isEmpty()) - return; - - name_ = name; - - emit nameChanged(name_); - if (value_.isValid()) - emit initialized(); -} - -QString QDeclarativeGeoServiceProviderParameter::name() const -{ - return name_; -} /*! \qmlproperty QVariant PluginParameter::value @@ -895,29 +913,9 @@ QString QDeclarativeGeoServiceProviderParameter::name() const This property holds the value of the plugin parameter which support different types of values (variant). This property is a write-once property. */ -void QDeclarativeGeoServiceProviderParameter::setValue(const QVariant &value) -{ - if (value_.isValid() || !value.isValid() || value.isNull()) - return; - - value_ = value; - - emit valueChanged(value_); - if (!name_.isEmpty()) - emit initialized(); -} - -QVariant QDeclarativeGeoServiceProviderParameter::value() const -{ - return value_; -} - -bool QDeclarativeGeoServiceProviderParameter::isInitialized() const -{ - return !name_.isEmpty() && value_.isValid(); -} /******************************************************************************* + * Implementation now in positioningquick *******************************************************************************/ QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h b/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h index f6a663f3..165f7ba4 100644 --- a/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h +++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h @@ -58,38 +58,10 @@ #include <QtQml/QQmlParserStatus> #include <QtQml/QQmlListProperty> #include <QtLocation/QGeoServiceProvider> +#include <QtPositioningQuick/private/qdeclarativepluginparameter_p.h> QT_BEGIN_NAMESPACE -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProviderParameter : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged) - -public: - explicit QDeclarativeGeoServiceProviderParameter(QObject *parent = 0); - ~QDeclarativeGeoServiceProviderParameter(); - - void setName(const QString &name); - QString name() const; - - void setValue(const QVariant &value); - QVariant value() const; - - bool isInitialized() const; - -Q_SIGNALS: - void nameChanged(const QString &name); - void valueChanged(const QVariant &value); - void initialized(); - -private: - QString name_; - QVariant value_; -}; - class QDeclarativeGeoServiceProviderRequirements; class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProvider : public QObject, public QQmlParserStatus @@ -102,7 +74,7 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProvider : public QObject, Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QStringList availableServiceProviders READ availableServiceProviders CONSTANT) - Q_PROPERTY(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> parameters READ parameters) + Q_PROPERTY(QQmlListProperty<QDeclarativePluginParameter> parameters READ parameters) Q_PROPERTY(QDeclarativeGeoServiceProviderRequirements *required READ requirements WRITE setRequirements) Q_PROPERTY(QStringList locales READ locales WRITE setLocales NOTIFY localesChanged) Q_PROPERTY(QStringList preferred READ preferred WRITE setPreferred NOTIFY preferredChanged) @@ -189,7 +161,7 @@ public: void setName(const QString &name); QString name() const; - QQmlListProperty<QDeclarativeGeoServiceProviderParameter> parameters(); + QQmlListProperty<QDeclarativePluginParameter> parameters(); QVariantMap parameterMap() const; QStringList availableServiceProviders(); @@ -226,14 +198,14 @@ Q_SIGNALS: private: bool parametersReady(); void tryAttach(); - static void parameter_append(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, QDeclarativeGeoServiceProviderParameter *mapObject); - static int parameter_count(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop); - static QDeclarativeGeoServiceProviderParameter *parameter_at(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, int index); - static void parameter_clear(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop); + static void parameter_append(QQmlListProperty<QDeclarativePluginParameter> *prop, QDeclarativePluginParameter *mapObject); + static int parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop); + static QDeclarativePluginParameter *parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, int index); + static void parameter_clear(QQmlListProperty<QDeclarativePluginParameter> *prop); QGeoServiceProvider *sharedProvider_; QString name_; - QList<QDeclarativeGeoServiceProviderParameter *> parameters_; + QList<QDeclarativePluginParameter *> parameters_; QDeclarativeGeoServiceProviderRequirements *required_; bool complete_; bool experimental_; @@ -257,6 +229,9 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProviderRequirements : pub Q_PROPERTY(QDeclarativeGeoServiceProvider::PlacesFeatures places READ placesRequirements WRITE setPlacesRequirements NOTIFY placesRequirementsChanged) + Q_PROPERTY(QDeclarativeGeoServiceProvider::NavigationFeatures navigation + READ navigationRequirements WRITE setNavigationRequirements + NOTIFY navigationRequirementsChanged) public: explicit QDeclarativeGeoServiceProviderRequirements(QObject *parent = 0); @@ -274,6 +249,9 @@ public: QDeclarativeGeoServiceProvider::PlacesFeatures placesRequirements() const; void setPlacesRequirements(const QDeclarativeGeoServiceProvider::PlacesFeatures &features); + QDeclarativeGeoServiceProvider::NavigationFeatures navigationRequirements() const; + void setNavigationRequirements(const QDeclarativeGeoServiceProvider::NavigationFeatures &features); + Q_INVOKABLE bool matches(const QGeoServiceProvider *provider) const; bool operator == (const QDeclarativeGeoServiceProviderRequirements &rhs) const; @@ -283,6 +261,7 @@ Q_SIGNALS: void routingRequirementsChanged(const QDeclarativeGeoServiceProvider::RoutingFeatures &features); void geocodingRequirementsChanged(const QDeclarativeGeoServiceProvider::GeocodingFeatures &features); void placesRequirementsChanged(const QDeclarativeGeoServiceProvider::PlacesFeatures &features); + void navigationRequirementsChanged(const QDeclarativeGeoServiceProvider::NavigationFeatures &features); void requirementsChanged(); @@ -291,12 +270,11 @@ private: QDeclarativeGeoServiceProvider::RoutingFeatures routing_; QDeclarativeGeoServiceProvider::GeocodingFeatures geocoding_; QDeclarativeGeoServiceProvider::PlacesFeatures places_; - + QDeclarativeGeoServiceProvider::NavigationFeatures navigation_; }; QT_END_NAMESPACE -QML_DECLARE_TYPE(QDeclarativeGeoServiceProviderParameter) QML_DECLARE_TYPE(QDeclarativeGeoServiceProviderRequirements) QML_DECLARE_TYPE(QDeclarativeGeoServiceProvider) diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp index fcfa14a5..7a3873a4 100644 --- a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp @@ -135,6 +135,17 @@ QT_BEGIN_NAMESPACE \image api-mappolygon.png */ +/*! + \qmlproperty bool QtLocation::MapPolygon::autoFadeIn + + This property holds whether the item automatically fades in when zooming into the map + starting from very low zoom levels. By default this is \c true. + Setting this property to \c false causes the map item to always have the opacity specified + with the \l QtQuick::Item::opacity property, which is 1.0 by default. + + \since 5.14 +*/ + QGeoMapPolygonGeometry::QGeoMapPolygonGeometry() : assumeSimple_(false) { diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp index 63146fbc..5ca612db 100644 --- a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp +++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp @@ -297,6 +297,17 @@ static QList<QList<QDoubleVector2D> > clipLine( \image api-mappolyline.png */ +/*! + \qmlproperty bool QtLocation::MapPolyline::autoFadeIn + + This property holds whether the item automatically fades in when zooming into the map + starting from very low zoom levels. By default this is \c true. + Setting this property to \c false causes the map item to always have the opacity specified + with the \l QtQuick::Item::opacity property, which is 1.0 by default. + + \since 5.14 +*/ + QDeclarativeMapLineProperties::QDeclarativeMapLineProperties(QObject *parent) : QObject(parent), width_(1.0), diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp index 74f95734..fd4109a7 100644 --- a/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp +++ b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp @@ -114,6 +114,17 @@ QT_BEGIN_NAMESPACE \image api-maprectangle.png */ +/*! + \qmlproperty bool QtLocation::MapRectangle::autoFadeIn + + This property holds whether the item automatically fades in when zooming into the map + starting from very low zoom levels. By default this is \c true. + Setting this property to \c false causes the map item to always have the opacity specified + with the \l QtQuick::Item::opacity property, which is 1.0 by default. + + \since 5.14 +*/ + QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent) : QDeclarativeGeoMapItemBase(parent), border_(this), color_(Qt::transparent), dirtyMaterial_(true), updatingGeometry_(false) diff --git a/src/location/declarativemaps/qquickgeomapgesturearea.cpp b/src/location/declarativemaps/qquickgeomapgesturearea.cpp index 13315917..a33db67a 100644 --- a/src/location/declarativemaps/qquickgeomapgesturearea.cpp +++ b/src/location/declarativemaps/qquickgeomapgesturearea.cpp @@ -999,8 +999,8 @@ void QQuickGeoMapGestureArea::handleWheelEvent(QWheelEvent *event) return; } - const QGeoCoordinate &wheelGeoPos = m_declarativeMap->toCoordinate(event->posF(), false); - const QPointF &preZoomPoint = event->posF(); + const QGeoCoordinate &wheelGeoPos = m_declarativeMap->toCoordinate(event->position(), false); + const QPointF &preZoomPoint = event->position(); // Not using AltModifier as, for some reason, it causes angleDelta to be 0 if (event->modifiers() & Qt::ShiftModifier && rotationEnabled()) { diff --git a/src/location/declarativeplaces/qdeclarativeplace.cpp b/src/location/declarativeplaces/qdeclarativeplace.cpp index 89027d0e..74a8f0c0 100644 --- a/src/location/declarativeplaces/qdeclarativeplace.cpp +++ b/src/location/declarativeplaces/qdeclarativeplace.cpp @@ -1085,7 +1085,7 @@ void QDeclarativePlace::pullExtendedAttributes() QStringList attributeTypes = m_src.extendedAttributeTypes(); foreach (const QString &attributeType, attributeTypes) { m_extendedAttributes->insert(attributeType, - qVariantFromValue(new QDeclarativePlaceAttribute(m_src.extendedAttribute(attributeType)))); + QVariant::fromValue(new QDeclarativePlaceAttribute(m_src.extendedAttribute(attributeType)))); } emit extendedAttributesChanged(); diff --git a/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp b/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp index 1920583b..3d64d299 100644 --- a/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp +++ b/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp @@ -149,10 +149,7 @@ void QDeclarativePlaceContentModel::initializeCollection(int totalCount, const Q int initialCount = m_contentCount; clearData(); - QMapIterator<int, QPlaceContent> i(collection); - while (i.hasNext()) { - i.next(); - + for (auto i = collection.cbegin(), end = collection.cend(); i != end; ++i) { const QPlaceContent &content = i.value(); if (content.type() != m_type) continue; @@ -317,11 +314,9 @@ void QDeclarativePlaceContentModel::fetchFinished() QPlaceContent::Collection contents = reply->content(); //find out which indexes are new and which ones have changed. - QMapIterator<int, QPlaceContent> it(contents); QList<int> changedIndexes; QList<int> newIndexes; - while (it.hasNext()) { - it.next(); + for (auto it = contents.cbegin(), end = contents.cend(); it != end; ++it) { if (!m_content.contains(it.key())) newIndexes.append(it.key()); else if (it.value() != m_content.value(it.key())) @@ -330,14 +325,14 @@ void QDeclarativePlaceContentModel::fetchFinished() //insert new indexes in blocks where within each //block, the indexes are consecutive. - QListIterator<int> newIndexesIter(newIndexes); int startIndex = -1; - while (newIndexesIter.hasNext()) { - int currentIndex = newIndexesIter.next(); + for (auto it = newIndexes.cbegin(), end = newIndexes.cend(); it != end; ++it) { + int currentIndex = *it; if (startIndex == -1) startIndex = currentIndex; - if (!newIndexesIter.hasNext() || (newIndexesIter.hasNext() && (newIndexesIter.peekNext() > (currentIndex + 1)))) { + auto next = std::next(it); + if (next == end || *next > (currentIndex + 1)) { beginInsertRows(QModelIndex(),startIndex,currentIndex); for (int i = startIndex; i <= currentIndex; ++i) { const QPlaceContent &content = contents.value(i); @@ -360,13 +355,13 @@ void QDeclarativePlaceContentModel::fetchFinished() //modify changed indexes in blocks where within each //block, the indexes are consecutive. startIndex = -1; - QListIterator<int> changedIndexesIter(changedIndexes); - while (changedIndexesIter.hasNext()) { - int currentIndex = changedIndexesIter.next(); + for (auto it = changedIndexes.cbegin(), end = changedIndexes.cend(); it != end; ++it) { + int currentIndex = *it; if (startIndex == -1) startIndex = currentIndex; - if (!changedIndexesIter.hasNext() || (changedIndexesIter.hasNext() && changedIndexesIter.peekNext() > (currentIndex + 1))) { + auto next = std::next(it); + if (next == end || *next > (currentIndex + 1)) { for (int i = startIndex; i <= currentIndex; ++i) { const QPlaceContent &content = contents.value(i); m_content.insert(i, content); diff --git a/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp index 4cfd26dd..9129731b 100644 --- a/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp +++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp @@ -963,26 +963,20 @@ void QDeclarativeSearchResultModel::placeRemoved(const QString &placeId) QList<QPlaceSearchResult> QDeclarativeSearchResultModel::resultsFromPages() const { QList<QPlaceSearchResult> res; - QMapIterator<int, QList<QPlaceSearchResult>> i(m_pages); - while (i.hasNext()) { - i.next(); - res.append(i.value()); - } + for (const auto &e : m_pages) + res.append(e); return res; } void QDeclarativeSearchResultModel::removePageRow(int row) { - QMapIterator<int, QList<QPlaceSearchResult>> i(m_pages); int scanned = 0; - while (i.hasNext()) { - i.next(); - QList<QPlaceSearchResult> page = i.value(); + for (auto i = m_pages.begin(), end = m_pages.end(); i != end; ++i) { + QList<QPlaceSearchResult> &page = i.value(); scanned += page.size(); if (row >= scanned) continue; page.removeAt(row - scanned + page.size()); - m_pages.insert(i.key(), page); return; } } diff --git a/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp index 38bfb249..08179c93 100644 --- a/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp +++ b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp @@ -631,24 +631,24 @@ QStringList QDeclarativeSupportedCategoriesModel::populateCategories(QPlaceManag Q_ASSERT(manager); QStringList childIds; - PlaceCategoryNode *node; - QMap<QString, QPlaceCategory> sortedCategories; - foreach ( const QPlaceCategory &category, manager->childCategories(parent.categoryId())) - sortedCategories.insert(category.name(), category); + const auto byName = [](const QPlaceCategory &lhs, const QPlaceCategory &rhs) { + return lhs.name() < rhs.name(); + }; - QMapIterator<QString, QPlaceCategory> iter(sortedCategories); - while (iter.hasNext()) { - iter.next(); - node = new PlaceCategoryNode; + auto categories = manager->childCategories(parent.categoryId()); + std::sort(categories.begin(), categories.end(), byName); + + for (const auto &category : qAsConst(categories)) { + auto node = new PlaceCategoryNode; node->parentId = parent.categoryId(); - node->declCategory = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(iter.value(), m_plugin ,this)); + node->declCategory = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(category, m_plugin ,this)); if (m_hierarchical) - node->childIds = populateCategories(manager, iter.value()); + node->childIds = populateCategories(manager, category); m_categoriesTree.insert(node->declCategory->categoryId(), node); - childIds.append(iter.value().categoryId()); + childIds.append(category.categoryId()); if (!m_hierarchical) { childIds.append(populateCategories(manager,node->declCategory->category())); diff --git a/src/location/doc/snippets/places/requesthandler.h b/src/location/doc/snippets/places/requesthandler.h index e5ee0d00..9aa5fe76 100644 --- a/src/location/doc/snippets/places/requesthandler.h +++ b/src/location/doc/snippets/places/requesthandler.h @@ -358,8 +358,8 @@ public slots: //! [Image handler] void handleImagesReply() { if (contentReply->error() == QPlaceReply::NoError) { - QMapIterator<int, QPlaceContent> iter(contentReply->content()); - while (iter.hasNext()) { + const auto content = contentReply->content(); + for (auto iter = content.cbegin(), end = content.cend(); iter != end; ++iter) { qDebug() << "Index: " << iter.key(); QPlaceImage image = iter.value(); qDebug() << image.url(); diff --git a/src/location/labs/qdeclarativenavigator.cpp b/src/location/labs/qdeclarativenavigator.cpp index 3fc9fb88..ae273774 100644 --- a/src/location/labs/qdeclarativenavigator.cpp +++ b/src/location/labs/qdeclarativenavigator.cpp @@ -284,6 +284,27 @@ QDeclarativePositionSource *QDeclarativeNavigator::positionSource() const return d_ptr->m_params->m_positionSource; } +// navigator automatically adjusts route when user leaves it +bool QDeclarativeNavigator::automaticReroutingEnabled() const +{ + if (d_ptr->m_navigator) + return d_ptr->m_navigator->automaticReroutingEnabled(); + return d_ptr->m_params->m_autoRerouting; +} + +// Whether or not it has an effect while the navigator is active should be plugin-dependent +void QDeclarativeNavigator::setAutomaticReroutingEnabled(bool autoRerouting) +{ + const bool autoReroutingOld = automaticReroutingEnabled(); + d_ptr->m_params->m_autoRerouting = autoRerouting; + // Done this way, and not via signal like setTrackPositionSource because + // plugins might not support automatic rerouting. + if (d_ptr->m_navigator) + d_ptr->m_navigator->setAutomaticReroutingEnabled(autoRerouting); + if (autoRerouting != autoReroutingOld) + emit automaticReroutingEnabledChanged(); +} + bool QDeclarativeNavigator::navigatorReady() const { @@ -297,6 +318,15 @@ bool QDeclarativeNavigator::trackPositionSource() const return d_ptr->m_params->m_trackPositionSource; } +// Navigator is in active tracking mode and the route is being followed. +// This may turn \c false if the user leaves the route. +bool QDeclarativeNavigator::isOnRoute() const +{ + if (d_ptr->m_navigator) + return d_ptr->m_navigator->isOnRoute(); + return false; +} + void QDeclarativeNavigator::setTrackPositionSource(bool trackPositionSource) { if (trackPositionSource == d_ptr->m_params->m_trackPositionSource) @@ -322,6 +352,12 @@ QString QDeclarativeNavigator::errorString() const return d_ptr->m_errorString; } +void QDeclarativeNavigator::recalculateRoutes() +{ + if (d_ptr->m_navigator) + d_ptr->m_navigator->recalculateRoutes(); +} + /* !NOT DOCUMENTED YET! \qmlproperty QAbstractNavigator *Qt.labs.location::Navigator::engineHandle @@ -478,6 +514,10 @@ bool QDeclarativeNavigator::ensureEngine() &d_ptr->m_basicDirections, &QDeclarativeNavigationBasicDirections::nextManeuverIconChanged); connect(d_ptr->m_navigator.get(), &QAbstractNavigator::progressInformationChanged, &d_ptr->m_basicDirections, &QDeclarativeNavigationBasicDirections::progressInformationChanged); + connect(d_ptr->m_navigator.get(), &QAbstractNavigator::isOnRouteChanged, + this, &QDeclarativeNavigator::isOnRouteChanged); + connect(d_ptr->m_navigator.get(), &QAbstractNavigator::alternativeRoutesChanged, + &d_ptr->m_basicDirections, &QDeclarativeNavigationBasicDirections::onAlternativeRoutesChanged); emit navigatorReadyChanged(true); return true; @@ -502,7 +542,7 @@ void QDeclarativeNavigator::setError(QDeclarativeNavigator::NavigationError erro } QDeclarativeNavigationBasicDirections::QDeclarativeNavigationBasicDirections(QDeclarativeNavigator *parent) -: QObject(parent), m_navigator(parent) +: QObject(parent), m_navigator(parent), m_routes(QByteArrayLiteral("routeData"), this) { if (m_navigator) m_navigatorPrivate = m_navigator->d_ptr.data(); @@ -672,6 +712,11 @@ int QDeclarativeNavigationBasicDirections::currentSegment() const return m_navigatorPrivate->m_navigator->currentSegment(); } +QAbstractItemModel *QDeclarativeNavigationBasicDirections::alternativeRoutes() +{ + return &m_routes; +} + void QDeclarativeNavigationBasicDirections::onCurrentRouteChanged() { if (m_currentRoute) @@ -688,5 +733,17 @@ void QDeclarativeNavigationBasicDirections::onCurrentRouteLegChanged() emit currentRouteLegChanged(); } +void QDeclarativeNavigationBasicDirections::onAlternativeRoutesChanged() +{ + const QList<QGeoRoute> &routes = m_navigatorPrivate->m_navigator->alternativeRoutes(); + QList<QDeclarativeGeoRoute *> declarativeRoutes; + for (int i = 0; i < routes.size(); ++i) { + QDeclarativeGeoRoute *route = new QDeclarativeGeoRoute(routes.at(i), &m_routes); + QQmlEngine::setContextForObject(route, QQmlEngine::contextForObject(this)); + declarativeRoutes.append(route); + } + m_routes.updateData(declarativeRoutes); +} + QT_END_NAMESPACE diff --git a/src/location/labs/qdeclarativenavigator_p.h b/src/location/labs/qdeclarativenavigator_p.h index e12d6ba4..24ff798f 100644 --- a/src/location/labs/qdeclarativenavigator_p.h +++ b/src/location/labs/qdeclarativenavigator_p.h @@ -81,6 +81,8 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeNavigator : public QParameterizableO Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) Q_PROPERTY(bool navigatorReady READ navigatorReady NOTIFY navigatorReadyChanged) Q_PROPERTY(bool trackPositionSource READ trackPositionSource WRITE setTrackPositionSource NOTIFY trackPositionSourceChanged) + Q_PROPERTY(bool automaticReroutingEnabled READ automaticReroutingEnabled WRITE setAutomaticReroutingEnabled NOTIFY automaticReroutingEnabledChanged) + Q_PROPERTY(bool isOnRoute READ isOnRoute NOTIFY isOnRouteChanged) Q_PROPERTY(QDeclarativeNavigationBasicDirections *directions READ directions CONSTANT) Q_PROPERTY(NavigationError error READ error NOTIFY errorChanged) Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) @@ -129,17 +131,26 @@ public: void setPositionSource(QDeclarativePositionSource *positionSource); QDeclarativePositionSource *positionSource() const; + // To enable/disable automatic route recalculation in the engines + bool automaticReroutingEnabled() const; + void setAutomaticReroutingEnabled(bool autoRerouting); + bool navigatorReady() const; void setTrackPositionSource(bool trackPositionSource); bool trackPositionSource() const; + // To discover/notify when the tracked position goes off the active navigation route + bool isOnRoute() const; + QDeclarativeNavigationBasicDirections *directions() const; QAbstractNavigator *abstractNavigator() const; NavigationError error() const; QString errorString() const; + Q_INVOKABLE void recalculateRoutes(); + signals: void navigatorReadyChanged(bool ready); void trackPositionSourceChanged(bool trackPositionSource); @@ -150,6 +161,8 @@ signals: void routeChanged(); void positionSourceChanged(); void errorChanged(); + void automaticReroutingEnabledChanged(); + void isOnRouteChanged(); protected: void pluginReady(); diff --git a/src/location/labs/qdeclarativenavigator_p_p.h b/src/location/labs/qdeclarativenavigator_p_p.h index 77fe2ff2..5bf1bd12 100644 --- a/src/location/labs/qdeclarativenavigator_p_p.h +++ b/src/location/labs/qdeclarativenavigator_p_p.h @@ -53,6 +53,9 @@ #include <QtCore/qpointer.h> #include <QtLocation/qgeoroute.h> #include <QtLocation/private/qdeclarativenavigator_p.h> +#include <QAbstractListModel> +#include <QtLocation/private/qdeclarativegeoroute_p.h> +#include <QtLocation/private/qdeclarativegeoroutemodel_p.h> QT_BEGIN_NAMESPACE @@ -67,6 +70,48 @@ class QDeclarativeGeoRouteSegment; class QParameterizableObject; class QAbstractNavigator; +template<typename T, int Role> +class ReadOnlyListModel : public QAbstractListModel +{ +public: + explicit ReadOnlyListModel(const QByteArray &dataRoleName, QObject *parent = nullptr) + : QAbstractListModel(parent) + { + m_roleNames.insert(Role, dataRoleName); + } + + int rowCount(const QModelIndex &) const override + { + return m_data.size(); + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override + { + const int row = index.row(); + if (!index.isValid() || row < 0 || row >= m_data.size() || role != Role) + return QVariant(); + + return QVariant::fromValue(m_data.at(row)); + } + + QHash<int, QByteArray> roleNames() const override + { + return m_roleNames; + } + + void updateData(const QList<T*> &data) + { + beginResetModel(); + qDeleteAll(m_data); + m_data = data; + endResetModel(); + } + +protected: + QHash<int, QByteArray> m_roleNames; + QList<T*> m_data; +}; + class Q_LOCATION_PRIVATE_EXPORT QDeclarativeNavigationBasicDirections : public QObject { Q_OBJECT @@ -83,6 +128,7 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeNavigationBasicDirections : public Q Q_PROPERTY(QDeclarativeGeoRoute *currentRoute READ currentRoute NOTIFY currentRouteChanged) Q_PROPERTY(QDeclarativeGeoRouteLeg *currentRouteLeg READ currentRouteLeg NOTIFY currentRouteChanged) Q_PROPERTY(int currentSegment READ currentSegment NOTIFY currentSegmentChanged) + Q_PROPERTY(QAbstractItemModel *alternativeRoutes READ alternativeRoutes CONSTANT) public: explicit QDeclarativeNavigationBasicDirections(QDeclarativeNavigator *parent); @@ -100,6 +146,7 @@ public: QDeclarativeGeoRoute *currentRoute() const; QDeclarativeGeoRouteLeg *currentRouteLeg() const; int currentSegment() const; + QAbstractItemModel *alternativeRoutes(); Q_SIGNALS: void progressInformationChanged(); @@ -113,12 +160,14 @@ Q_SIGNALS: protected slots: void onCurrentRouteChanged(); void onCurrentRouteLegChanged(); + void onAlternativeRoutesChanged(); protected: QDeclarativeNavigator *m_navigator; QDeclarativeNavigatorPrivate *m_navigatorPrivate; QPointer<QDeclarativeGeoRoute> m_currentRoute; QPointer<QDeclarativeGeoRouteLeg> m_currentRouteLeg; + ReadOnlyListModel<QDeclarativeGeoRoute, QDeclarativeGeoRouteModel::RouteRole> m_routes; friend class QDeclarativeNavigator; }; @@ -132,6 +181,7 @@ public: QPointer<QDeclarativePositionSource> m_positionSource; QList<QPointer<QGeoMapParameter>> m_parameters; bool m_trackPositionSource = true; + bool m_autoRerouting = true; }; class QDeclarativeNavigatorPrivate diff --git a/src/location/labs/qmapobjectview.cpp b/src/location/labs/qmapobjectview.cpp index 90234ea6..8cbf8ded 100644 --- a/src/location/labs/qmapobjectview.cpp +++ b/src/location/labs/qmapobjectview.cpp @@ -36,7 +36,7 @@ #include "qmapobjectview_p.h" #include "qmapobjectview_p_p.h" -#include <QtQml/private/qqmldelegatemodel_p.h> +#include <private/qqmldelegatemodel_p.h> #include <QtLocation/private/qgeomap_p.h> QT_BEGIN_NAMESPACE diff --git a/src/location/maps/qgeotiledmapscene.cpp b/src/location/maps/qgeotiledmapscene.cpp index a5f94c8d..a8bee156 100644 --- a/src/location/maps/qgeotiledmapscene.cpp +++ b/src/location/maps/qgeotiledmapscene.cpp @@ -495,7 +495,9 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, cameraMatrix.lookAt(toVector3D(eye), toVector3D(center), toVector3D(d->m_cameraUp)); root->setMatrix(d->m_projectionMatrix * cameraMatrix); - const QSet<QGeoTileSpec> tilesInSG = QSet<QGeoTileSpec>::fromList(root->tiles.keys()); + QSet<QGeoTileSpec> tilesInSG; + for (auto it = root->tiles.cbegin(), end = root->tiles.cend(); it != end; ++it) + tilesInSG.insert(it.key()); const QSet<QGeoTileSpec> toRemove = tilesInSG - d->m_visibleTiles; const QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - tilesInSG; @@ -640,7 +642,9 @@ QSGNode *QGeoTiledMapScene::updateSceneGraph(QSGNode *oldNode, QQuickWindow *win d->m_updatedTextures.clear(); } - const QSet<QGeoTileSpec> textures = QSet<QGeoTileSpec>::fromList(mapRoot->textures.keys()); + QSet<QGeoTileSpec> textures; + for (auto it = mapRoot->textures.cbegin(), end = mapRoot->textures.cend(); it != end; ++it) + textures.insert(it.key()); const QSet<QGeoTileSpec> toRemove = textures - d->m_visibleTiles; const QSet<QGeoTileSpec> toAdd = d->m_visibleTiles - textures; diff --git a/src/location/maps/qgeotilefetcher.cpp b/src/location/maps/qgeotilefetcher.cpp index b3f7021b..cfca57ac 100644 --- a/src/location/maps/qgeotilefetcher.cpp +++ b/src/location/maps/qgeotilefetcher.cpp @@ -43,6 +43,9 @@ #include "qgeotilespec_p.h" #include "qgeotiledmap_p.h" +#include <algorithm> +#include <iterator> + QT_BEGIN_NAMESPACE QGeoTileFetcher::QGeoTileFetcher(QGeoMappingManagerEngine *parent) @@ -75,7 +78,7 @@ void QGeoTileFetcher::updateTileRequests(const QSet<QGeoTileSpec> &tilesAdded, cancelTileRequests(tilesRemoved); - d->queue_ += tilesAdded.toList(); + std::copy(tilesAdded.cbegin(), tilesAdded.cend(), std::back_inserter(d->queue_)); if (d->enabled_ && initialized() && !d->queue_.isEmpty() && !d->timer_.isActive()) d->timer_.start(0, this); diff --git a/src/location/maps/qnavigationmanagerengine.cpp b/src/location/maps/qnavigationmanagerengine.cpp index 8837e5c6..aa5a980b 100644 --- a/src/location/maps/qnavigationmanagerengine.cpp +++ b/src/location/maps/qnavigationmanagerengine.cpp @@ -141,6 +141,11 @@ QGeoRouteLeg QAbstractNavigator::currentRouteLeg() const return QGeoRouteLeg(); } +QList<QGeoRoute> QAbstractNavigator::alternativeRoutes() const +{ + return QList<QGeoRoute>(); +} + int QAbstractNavigator::currentSegment() const { return 0; diff --git a/src/location/maps/qnavigationmanagerengine_p.h b/src/location/maps/qnavigationmanagerengine_p.h index 331df64f..8d2c9a99 100644 --- a/src/location/maps/qnavigationmanagerengine_p.h +++ b/src/location/maps/qnavigationmanagerengine_p.h @@ -98,7 +98,12 @@ public: virtual int traveledTime() const; virtual QGeoRoute currentRoute() const; virtual QGeoRouteLeg currentRouteLeg() const; + virtual QList<QGeoRoute> alternativeRoutes() const = 0; virtual int currentSegment() const; + virtual void setAutomaticReroutingEnabled(bool autoRerouting) = 0; + virtual bool automaticReroutingEnabled() const = 0; // configured via navigation params at construction time + virtual bool isOnRoute() = 0; + virtual void recalculateRoutes() = 0; public slots: virtual bool start() = 0; @@ -116,6 +121,8 @@ signals: void nextManeuverIconChanged(); void progressInformationChanged(); + void isOnRouteChanged(); + void alternativeRoutesChanged(); private: QScopedPointer<QAbstractNavigatorPrivate> d; diff --git a/src/location/places/qplace.cpp b/src/location/places/qplace.cpp index ab115b5b..4e3e36d3 100644 --- a/src/location/places/qplace.cpp +++ b/src/location/places/qplace.cpp @@ -297,11 +297,8 @@ void QPlace::setContent(QPlaceContent::Type type, const QPlaceContent::Collectio */ void QPlace::insertContent(QPlaceContent::Type type, const QPlaceContent::Collection &content) { - QMapIterator<int, QPlaceContent> iter(content); - while (iter.hasNext()) { - iter.next(); + for (auto iter = content.cbegin(), end = content.cend(); iter != end; ++iter) d_ptr->m_contentCollections[type].insert(iter.key(), iter.value()); - } } /*! diff --git a/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.cpp b/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.cpp index ed594b56..2370e2cc 100644 --- a/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.cpp +++ b/src/plugins/geoservices/mapboxgl/qsgmapboxglnode.cpp @@ -38,6 +38,10 @@ #include "qsgmapboxglnode.h" #include "qgeomapmapboxgl.h" +#if QT_HAS_INCLUDE(<QtQuick/private/qsgplaintexture_p.h>) +#include <QtQuick/private/qsgplaintexture_p.h> +#endif + #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLFunctions> diff --git a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm index dc3903de..fae16715 100644 --- a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm +++ b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm @@ -68,10 +68,8 @@ Q_UNUSED(oldLocation); // Convert location timestamp to QDateTime - QDateTime timeStamp; NSTimeInterval locationTimeStamp = [newLocation.timestamp timeIntervalSince1970]; - timeStamp.setTime_t((uint) locationTimeStamp); - timeStamp.setTime(timeStamp.time().addMSecs((uint)(locationTimeStamp * 1000) % 1000)); + const QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(qRound64(locationTimeStamp * 1000), Qt::UTC); // Construct position info from location data QGeoPositionInfo location(QGeoCoordinate(newLocation.coordinate.latitude, diff --git a/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.cpp b/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.cpp index a82cfb63..95ca42be 100644 --- a/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.cpp +++ b/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.cpp @@ -142,7 +142,7 @@ void QGeoPositionInfoSourceGeoclueMaster::updatePosition(PositionFields fields, if (fields & Altitude) coordinate.setAltitude(altitude); - m_lastPosition = QGeoPositionInfo(coordinate, QDateTime::fromTime_t(timestamp)); + m_lastPosition = QGeoPositionInfo(coordinate, QDateTime::fromSecsSinceEpoch(timestamp)); m_lastPositionFromSatellite = accuracy.level() == Accuracy::Detailed; diff --git a/src/plugins/position/positionpoll/qgeoareamonitor_polling.cpp b/src/plugins/position/positionpoll/qgeoareamonitor_polling.cpp index e39a6212..bbc70f0a 100644 --- a/src/plugins/position/positionpoll/qgeoareamonitor_polling.cpp +++ b/src/plugins/position/positionpoll/qgeoareamonitor_polling.cpp @@ -47,6 +47,8 @@ #include <QtCore/qdebug.h> #include <QtCore/qmutex.h> +#include <mutex> + #define UPDATE_INTERVAL_5S 5000 typedef QHash<QString, QGeoAreaMonitorInfo> MonitorTable; @@ -74,7 +76,7 @@ class QGeoAreaMonitorPollingPrivate : public QObject { Q_OBJECT public: - QGeoAreaMonitorPollingPrivate() : source(0), mutex(QMutex::Recursive) + QGeoAreaMonitorPollingPrivate() { nextExpiryTimer = new QTimer(this); nextExpiryTimer->setSingleShot(true); @@ -84,7 +86,7 @@ public: void startMonitoring(const QGeoAreaMonitorInfo &monitor) { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); activeMonitorAreas.insert(monitor.identifier(), monitor); singleShotTrigger.remove(monitor.identifier()); @@ -95,7 +97,7 @@ public: void requestUpdate(const QGeoAreaMonitorInfo &monitor, int signalId) { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); activeMonitorAreas.insert(monitor.identifier(), monitor); singleShotTrigger.insert(monitor.identifier(), signalId); @@ -106,7 +108,7 @@ public: QGeoAreaMonitorInfo stopMonitoring(const QGeoAreaMonitorInfo &monitor) { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); QGeoAreaMonitorInfo mon = activeMonitorAreas.take(monitor.identifier()); @@ -118,7 +120,7 @@ public: void registerClient(QGeoAreaMonitorPolling *client) { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); connect(this, SIGNAL(timeout(QGeoAreaMonitorInfo)), client, SLOT(timeout(QGeoAreaMonitorInfo))); @@ -134,7 +136,7 @@ public: void deregisterClient(QGeoAreaMonitorPolling *client) { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); registeredClients.removeAll(client); if (registeredClients.isEmpty()) @@ -143,7 +145,7 @@ public: void setPositionSource(QGeoPositionInfoSource *newSource) { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); if (newSource == source) return; @@ -169,20 +171,20 @@ public: QGeoPositionInfoSource* positionSource() const { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); return source; } MonitorTable activeMonitors() const { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); return activeMonitorAreas; } void checkStartStop() { - QMutexLocker locker(&mutex); + const std::lock_guard<QRecursiveMutex> locker(mutex); bool signalsConnected = false; foreach (const QGeoAreaMonitorPolling *client, registeredClients) { @@ -307,9 +309,9 @@ private: MonitorTable activeMonitorAreas; - QGeoPositionInfoSource* source; + QGeoPositionInfoSource* source = nullptr; QList<QGeoAreaMonitorPolling*> registeredClients; - mutable QMutex mutex; + mutable QRecursiveMutex mutex; }; Q_GLOBAL_STATIC(QGeoAreaMonitorPollingPrivate, pollingPrivate) diff --git a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp index 58092ea3..d56f1d46 100644 --- a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp +++ b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp @@ -43,30 +43,101 @@ #include <QtSerialPort/qserialportinfo.h> #include <QtCore/qloggingcategory.h> #include <QSet> +#include "qiopipe_p.h" +#include <QSharedPointer> +#include "qnmeasatelliteinfosource_p.h" Q_LOGGING_CATEGORY(lcSerial, "qt.positioning.serialnmea") +class IODeviceContainer +{ +public: + IODeviceContainer() {} + IODeviceContainer(IODeviceContainer const&) = delete; + void operator=(IODeviceContainer const&) = delete; + + QSharedPointer<QIOPipe> serial(const QString &portName) + { + if (m_serialPorts.contains(portName)) { + m_serialPorts[portName].refs++; + QIOPipe *endPipe = new QIOPipe(m_serialPorts[portName].proxy); + m_serialPorts[portName].proxy->addChildPipe(endPipe); + return QSharedPointer<QIOPipe>(endPipe); + } + IODevice device; + QSerialPort *port = new QSerialPort(portName); + port->setBaudRate(4800); + qCDebug(lcSerial) << "Opening serial port" << portName; + if (!port->open(QIODevice::ReadOnly)) { + qWarning("serialnmea: Failed to open %s", qPrintable(portName)); + delete port; + return {}; + } + qCDebug(lcSerial) << "Opened successfully"; + device.device = port; + device.refs = 1; + device.proxy = new QIOPipe(port, QIOPipe::ProxyPipe); + m_serialPorts[portName] = device; + QIOPipe *endPipe = new QIOPipe(device.proxy); + device.proxy->addChildPipe(endPipe); + return QSharedPointer<QIOPipe>(endPipe); + } + + void releaseSerial(const QString &portName, QSharedPointer<QIOPipe> &pipe) { + if (!m_serialPorts.contains(portName)) + return; + + pipe.clear(); // make sure to release the pipe returned by getSerial, or else, if there are still refs, data will be leaked through it + IODevice &device = m_serialPorts[portName]; + if (device.refs > 1) { + device.refs--; + return; + } + + IODevice taken = m_serialPorts.take(portName); + taken.device->deleteLater(); + } + +private: + + struct IODevice { + QIODevice *device = nullptr; + QIOPipe *proxy = nullptr; // adding client pipes as children of proxy allows to dynamically add clients to one device. + unsigned int refs = 1; + }; + + QMap<QString, IODevice> m_serialPorts; +}; + +Q_GLOBAL_STATIC(IODeviceContainer, deviceContainer) + + class NmeaSource : public QNmeaPositionInfoSource { public: - NmeaSource(QObject *parent); + explicit NmeaSource(QObject *parent, const QVariantMap ¶meters); + ~NmeaSource() override; bool isValid() const { return !m_port.isNull(); } private: - QScopedPointer<QSerialPort> m_port; + QSharedPointer<QIOPipe> m_port; + QString m_portName; }; -NmeaSource::NmeaSource(QObject *parent) - : QNmeaPositionInfoSource(RealTimeMode, parent), - m_port(new QSerialPort) +NmeaSource::NmeaSource(QObject *parent, const QVariantMap ¶meters) + : QNmeaPositionInfoSource(RealTimeMode, parent) { - QByteArray requestedPort = qgetenv("QT_NMEA_SERIAL_PORT"); + QByteArray requestedPort; + if (parameters.contains(QStringLiteral("serialnmea.serial_port"))) + requestedPort = parameters.value(QStringLiteral("serialnmea.serial_port")).toString().toLatin1(); + else + requestedPort = qgetenv("QT_NMEA_SERIAL_PORT"); + QString portName; if (requestedPort.isEmpty()) { const QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts(); qCDebug(lcSerial) << "Found" << ports.count() << "serial ports"; if (ports.isEmpty()) { qWarning("serialnmea: No serial ports found"); - m_port.reset(); return; } @@ -74,8 +145,7 @@ NmeaSource::NmeaSource(QObject *parent) QSet<int> supportedDevices; supportedDevices << 0x67b; // GlobalSat (BU-353S4 and probably others) supportedDevices << 0xe8d; // Qstarz MTK II - QString portName; - foreach (const QSerialPortInfo& port, ports) { + for (const QSerialPortInfo& port : ports) { if (port.hasVendorIdentifier() && supportedDevices.contains(port.vendorIdentifier())) { portName = port.portName(); break; @@ -84,44 +154,116 @@ NmeaSource::NmeaSource(QObject *parent) if (portName.isEmpty()) { qWarning("serialnmea: No known GPS device found. Specify the COM port via QT_NMEA_SERIAL_PORT."); - m_port.reset(); return; } - - m_port->setPortName(portName); + m_portName = portName; } else { - m_port->setPortName(QString::fromUtf8(requestedPort)); + m_portName = QString::fromUtf8(requestedPort); } - m_port->setBaudRate(4800); - - qCDebug(lcSerial) << "Opening serial port" << m_port->portName(); - - if (!m_port->open(QIODevice::ReadOnly)) { - qWarning("serialnmea: Failed to open %s", qPrintable(m_port->portName())); - m_port.reset(); + m_port = deviceContainer->serial(m_portName); + if (!m_port) return; - } setDevice(m_port.data()); +} - qCDebug(lcSerial) << "Opened successfully"; +NmeaSource::~NmeaSource() +{ + deviceContainer->releaseSerial(m_portName, m_port); } + + +class NmeaSatelliteSource : public QNmeaSatelliteInfoSource +{ +public: + NmeaSatelliteSource(QObject *parent, const QVariantMap ¶meters) + : QNmeaSatelliteInfoSource(parent) + { + QByteArray requestedPort; + if (parameters.contains(QStringLiteral("serialnmea.serial_port"))) + requestedPort = parameters.value(QStringLiteral("serialnmea.serial_port")).toString().toLatin1(); + else + requestedPort = qgetenv("QT_NMEA_SERIAL_PORT"); + QString portName; + if (requestedPort.isEmpty()) { + const QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts(); + qCDebug(lcSerial) << "Found" << ports.count() << "serial ports"; + if (ports.isEmpty()) { + qWarning("serialnmea: No serial ports found"); + return; + } + + // Try to find a well-known device. + QSet<int> supportedDevices; + supportedDevices << 0x67b; // GlobalSat (BU-353S4 and probably others) + supportedDevices << 0xe8d; // Qstarz MTK II + foreach (const QSerialPortInfo& port, ports) { + if (port.hasVendorIdentifier() && supportedDevices.contains(port.vendorIdentifier())) { + portName = port.portName(); + break; + } + } + + if (portName.isEmpty()) { + qWarning("serialnmea: No known GPS device found. Specify the COM port via QT_NMEA_SERIAL_PORT."); + return; + } + m_portName = portName; + } else { + m_portName = QString::fromUtf8(requestedPort); + } + + m_port = deviceContainer->serial(m_portName); + if (!m_port) + return; + + setDevice(m_port.data()); + } + + ~NmeaSatelliteSource() + { + deviceContainer->releaseSerial(m_portName, m_port); + } + + bool isValid() const { return !m_port.isNull(); } + +private: + QSharedPointer<QIOPipe> m_port; + QString m_portName; +}; + QGeoPositionInfoSource *QGeoPositionInfoSourceFactorySerialNmea::positionInfoSource(QObject *parent) { - QScopedPointer<NmeaSource> src(new NmeaSource(parent)); - return src->isValid() ? src.take() : nullptr; + return positionInfoSourceWithParameters(parent, QVariantMap()); } QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactorySerialNmea::satelliteInfoSource(QObject *parent) { - Q_UNUSED(parent); - return nullptr; + return satelliteInfoSourceWithParameters(parent, QVariantMap()); } QGeoAreaMonitorSource *QGeoPositionInfoSourceFactorySerialNmea::areaMonitor(QObject *parent) { + return areaMonitorWithParameters(parent, QVariantMap()); +} + +QGeoPositionInfoSource *QGeoPositionInfoSourceFactorySerialNmea::positionInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters) +{ + QScopedPointer<NmeaSource> src(new NmeaSource(parent, parameters)); + return src->isValid() ? src.take() : nullptr; +} + +QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactorySerialNmea::satelliteInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters) +{ + QScopedPointer<NmeaSatelliteSource> src(new NmeaSatelliteSource(parent, parameters)); + return src->isValid() ? src.take() : nullptr; +} + +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactorySerialNmea::areaMonitorWithParameters(QObject *parent, const QVariantMap ¶meters) +{ Q_UNUSED(parent); + Q_UNUSED(parameters) return nullptr; } diff --git a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.h b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.h index e372d56f..c8ca0e7e 100644 --- a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.h +++ b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.h @@ -43,17 +43,21 @@ #include <QObject> #include <qgeopositioninfosourcefactory.h> -class QGeoPositionInfoSourceFactorySerialNmea : public QObject, public QGeoPositionInfoSourceFactory +class QGeoPositionInfoSourceFactorySerialNmea : public QObject, public QGeoPositionInfoSourceFactoryV2 { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.qt.position.sourcefactory/5.0" FILE "plugin.json") - Q_INTERFACES(QGeoPositionInfoSourceFactory) + Q_INTERFACES(QGeoPositionInfoSourceFactoryV2) public: QGeoPositionInfoSource *positionInfoSource(QObject *parent); QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); QGeoAreaMonitorSource *areaMonitor(QObject *parent); + + QGeoPositionInfoSource *positionInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters); + QGeoSatelliteInfoSource *satelliteInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters); + QGeoAreaMonitorSource *areaMonitorWithParameters(QObject *parent, const QVariantMap ¶meters); }; #endif diff --git a/src/plugins/position/serialnmea/qiopipe.cpp b/src/plugins/position/serialnmea/qiopipe.cpp new file mode 100644 index 00000000..ce908d4d --- /dev/null +++ b/src/plugins/position/serialnmea/qiopipe.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** 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 "qiopipe_p.h" +#include <QtCore/qmetaobject.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +/* + proxying means do *not* emit readyRead, and instead pump data + into child pipes directly in a zero-copy fashion. +*/ +QIOPipePrivate::QIOPipePrivate(QIODevice *iodevice, bool proxying) + : m_proxying(proxying), source(iodevice) +{ + const QIOPipe *parentPipe = qobject_cast<QIOPipe *>(iodevice); + if (parentPipe && parentPipe->d_func()->m_proxying) // with proxying parent, + return; // don't do anything + + // read available data, does not emit. + readAvailableData(); + // connect readyRead to onReadyRead + QObjectPrivate::connect(source, &QIODevice::readyRead, this, &QIOPipePrivate::_q_onReadyRead); +} + +QIOPipePrivate::~QIOPipePrivate() +{ +} + +bool QIOPipePrivate::readAvailableData() { + if (!source) + return false; + QByteArray ba = source->readAll(); + if (!ba.size()) + return false; + + pumpData(ba); + return true; +} + +void QIOPipePrivate::pumpData(const QByteArray &ba) +{ + if (m_proxying) { + QVector<int> toRemove; + for (int i = 0; i < childPipes.size(); ++i) { + const QPointer<QIOPipe> &cp = childPipes.at(i); + if (!cp) { + toRemove.append(i); + continue; + } + QIOPipePrivate *cpp = cp->d_func(); + cpp->pushData(ba); + } + for (int i = toRemove.size() - 1; i >= 0; --i) { + childPipes.remove(i); + } + } else { + for (int i = 0; i < readBuffers.size(); i++) + readBuffers[i].append(ba); + } +} + +void QIOPipePrivate::pushData(const QByteArray &ba) +{ + Q_Q(QIOPipe); + if (!ba.size()) + return; + + pumpData(ba); + if (!m_proxying) + emit q->readyRead(); +} + +void QIOPipePrivate::_q_onReadyRead() +{ + Q_Q(QIOPipe); + if (readAvailableData() && !m_proxying) + emit q->readyRead(); +} + +void QIOPipePrivate::addChildPipe(QIOPipe *childPipe) +{ + if (childPipes.contains(childPipe)) + return; + childPipes.append(childPipe); +} + +void QIOPipePrivate::removeChildPipe(QIOPipe *childPipe) +{ + childPipes.removeOne(childPipe); +} + +QIOPipe::QIOPipe(QIODevice *parent, Mode mode) + : QIODevice(*new QIOPipePrivate(parent, mode == ProxyPipe), parent) +{ + if (!parent->isOpen() && !parent->open(QIODevice::ReadOnly)) { + qWarning() << "QIOPipe: Failed to open " << parent; + return; + } + open(ReadOnly); +} + +QIOPipe::~QIOPipe() +{ + +} + +bool QIOPipe::open(QIODevice::OpenMode mode) +{ + if (isOpen()) + return true; + + static const OpenMode supportedOpenMode = ReadOnly; // Currently limit it to read only + if (!(mode & supportedOpenMode)) { + qFatal("Unsupported open mode"); + return false; + } + + return QIODevice::open(mode); +} + +bool QIOPipe::isSequential() const +{ + return true; +} + +void QIOPipe::setReadChannelCount(int count) +{ + Q_D(QIOPipe); + d->setReadChannelCount(qMax(count, 1)); +} + +void QIOPipe::addChildPipe(QIOPipe *childPipe) +{ + Q_D(QIOPipe); + d->addChildPipe(childPipe); +} + +/*! + \reimp + + \omit + This function does not really read anything, as we use QIODevicePrivate's + buffer. The buffer will be read inside of QIODevice before this + method will be called. + See QIODevicePrivate::read, buffer.read(data, maxSize). + \endomit +*/ +qint64 QIOPipe::readData(char *data, qint64 maxlen) +{ + Q_UNUSED(data); + Q_UNUSED(maxlen); + + // return 0 indicating there may be more data in the future + // Returning -1 means no more data in the future (end of stream). + return qint64(0); +} + +qint64 QIOPipe::writeData(const char * /*data*/, qint64 /*len*/) +{ + qFatal("QIOPipe is a read-only device"); + return qint64(0); +} + +QT_END_NAMESPACE diff --git a/src/plugins/position/serialnmea/qiopipe_p.h b/src/plugins/position/serialnmea/qiopipe_p.h new file mode 100644 index 00000000..25758fcb --- /dev/null +++ b/src/plugins/position/serialnmea/qiopipe_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** 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 QIOPIPE_P_H +#define QIOPIPE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qiodevice.h> +#include <QtCore/qbytearray.h> +#include <QtCore/private/qiodevice_p.h> + +QT_BEGIN_NAMESPACE + +class QObject; +class QIOPipePrivate; + +class QIOPipe : public QIODevice +{ + Q_OBJECT + +public: + enum Mode { + EndPipe = 0x0000, + ProxyPipe = 0x0001 + }; + + explicit QIOPipe(QIODevice *parent, Mode mode = EndPipe); + ~QIOPipe() override; + + bool open(OpenMode openMode) override; + bool isSequential() const override; + void setReadChannelCount(int count); + void addChildPipe(QIOPipe *childPipe); + +protected: + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; + +private: + Q_DECLARE_PRIVATE(QIOPipe) + Q_DISABLE_COPY(QIOPipe) +}; + +class QIOPipePrivate : public QIODevicePrivate +{ + Q_DECLARE_PUBLIC(QIOPipe) + +public: + explicit QIOPipePrivate(QIODevice *iodevice, bool proxying); + ~QIOPipePrivate() override; + + bool readAvailableData(); + void pumpData(const QByteArray &ba); + void pushData(const QByteArray &ba); + void _q_onReadyRead(); + void addChildPipe(QIOPipe *childPipe); + void removeChildPipe(QIOPipe *childPipe); + + bool m_proxying = false; + QPointer<QIODevice> source; + QVector<QPointer<QIOPipe>> childPipes; +}; + +#endif // QIOPIPE_P_H + +QT_END_NAMESPACE diff --git a/src/plugins/position/serialnmea/qnmeasatelliteinfosource.cpp b/src/plugins/position/serialnmea/qnmeasatelliteinfosource.cpp new file mode 100644 index 00000000..d31106fc --- /dev/null +++ b/src/plugins/position/serialnmea/qnmeasatelliteinfosource.cpp @@ -0,0 +1,558 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 "qnmeasatelliteinfosource_p.h" +#include <QtPositioning/private/qgeosatelliteinfo_p.h> +#include <QtPositioning/private/qgeosatelliteinfosource_p.h> +#include <QtPositioning/private/qlocationutils_p.h> + +#include <QIODevice> +#include <QBasicTimer> +#include <QTimerEvent> +#include <QTimer> +#include <array> +#include <QDebug> +#include <QtCore/QtNumeric> + + +//QT_BEGIN_NAMESPACE + +#define USE_NMEA_PIMPL 1 + +#if USE_NMEA_PIMPL +class QGeoSatelliteInfoPrivateNmea : public QGeoSatelliteInfoPrivate +{ +public: + QGeoSatelliteInfoPrivateNmea(const QGeoSatelliteInfoPrivate &other); + QGeoSatelliteInfoPrivateNmea(const QGeoSatelliteInfoPrivateNmea &other); + virtual ~QGeoSatelliteInfoPrivateNmea(); + virtual QGeoSatelliteInfoPrivate *clone() const; + + QList<QByteArray> nmeaSentences; +}; + +QGeoSatelliteInfoPrivateNmea::QGeoSatelliteInfoPrivateNmea(const QGeoSatelliteInfoPrivate &other) +: QGeoSatelliteInfoPrivate(other) +{ +} + +QGeoSatelliteInfoPrivateNmea::QGeoSatelliteInfoPrivateNmea(const QGeoSatelliteInfoPrivateNmea &other) +: QGeoSatelliteInfoPrivate(other) +{ + nmeaSentences = other.nmeaSentences; +} + +QGeoSatelliteInfoPrivateNmea::~QGeoSatelliteInfoPrivateNmea() {} + +QGeoSatelliteInfoPrivate *QGeoSatelliteInfoPrivateNmea::clone() const +{ + return new QGeoSatelliteInfoPrivateNmea(*this); +} +#else +typedef QGeoSatelliteInfoPrivate QGeoSatelliteInfoPrivateNmea; +#endif + +class QNmeaSatelliteInfoSourcePrivate : public QObject, public QGeoSatelliteInfoSourcePrivate +{ + Q_OBJECT +public: + QNmeaSatelliteInfoSourcePrivate(QNmeaSatelliteInfoSource *parent); + ~QNmeaSatelliteInfoSourcePrivate(); + + void startUpdates(); + void stopUpdates(); + void requestUpdate(int msec); + void notifyNewUpdate(); + +public slots: + void readyRead(); + void emitPendingUpdate(); + void sourceDataClosed(); + void updateRequestTimeout(); + + +public: + QGeoSatelliteInfoSource *m_source = nullptr; + QGeoSatelliteInfoSource::Error m_satelliteError = QGeoSatelliteInfoSource::NoError; + QPointer<QIODevice> m_device; + struct Update { + QList<QGeoSatelliteInfo> m_satellitesInView; + QList<QGeoSatelliteInfo> m_satellitesInUse; + QList<int> m_inUse; // temp buffer for GSA received before GSV + bool m_validInView = false; + bool m_validInUse = false; + bool m_fresh = false; + bool m_updatingGsv = false; +#if USE_NMEA_PIMPL + QByteArray gsa; + QList<QByteArray> gsv; +#endif + void setSatellitesInView(const QList<QGeoSatelliteInfo> &inView) + { + m_updatingGsv = false; + m_satellitesInView = inView; + m_validInView = m_fresh = true; + if (m_inUse.size()) { + m_satellitesInUse.clear(); + m_validInUse = false; + bool corrupt = false; + for (const auto i: m_inUse) { + bool found = false; + for (const auto &s: m_satellitesInView) { + if (s.satelliteIdentifier() == i) { + m_satellitesInUse.append(s); + found = true; + } + } + if (!found) { // received a GSA before a GSV, but it was incorrect or something. Unrelated to this GSV at least. + m_satellitesInUse.clear(); + corrupt = true; + break; + } + } + m_validInUse = !corrupt; + m_inUse.clear(); + } + } + +// void setSatellitesInUse(const QList<QGeoSatelliteInfo> &inUse) +// { +// m_satellitesInUse = inUse; +// m_validInUse = true; +// m_inUse.clear(); +// } + + bool setSatellitesInUse(const QList<int> &inUse) + { + m_satellitesInUse.clear(); + m_validInUse = false; + m_inUse = inUse; + if (m_updatingGsv) { + m_satellitesInUse.clear(); + m_validInView = false; + return false; + } + for (const auto i: inUse) { + bool found = false; + for (const auto &s: m_satellitesInView) { + if (s.satelliteIdentifier() == i) { + m_satellitesInUse.append(s); + found = true; + } + } + if (!found) { // if satellites in use aren't in view, the related GSV is still to be received. + m_inUse = inUse; // So clear outdated data, buffer the info, and set it later. + m_satellitesInUse.clear(); + m_satellitesInView.clear(); + m_validInView = false; + return false; + } + } + m_validInUse = m_fresh = true; + return true; + } + + void consume() + { + m_fresh = false; + } + + bool isFresh() + { + return m_fresh; + } + + QSet<int> inUse() const + { + QSet<int> res; + for (const auto &s: m_satellitesInUse) + res.insert(s.satelliteIdentifier()); + return res; + } + + void clear() + { + m_satellitesInView.clear(); + m_satellitesInUse.clear(); + m_validInView = m_validInUse = false; + } + + bool isValid() + { + return m_validInView || m_validInUse; // GSV without GSA is valid. GSA with outdated but still matching GSV also valid. + } + } m_pendingUpdate, m_lastUpdate; + bool m_fresh = false; + bool m_invokedStart = false; + bool m_noUpdateLastInterval = false; + bool m_updateTimeoutSent = false; + bool m_connectedReadyRead = false; + int m_pushDelay = 20; + QBasicTimer *m_updateTimer = nullptr; // the timer used in startUpdates() + QTimer *m_requestTimer = nullptr; // the timer used in requestUpdate() + +protected: + void readAvailableData(); + bool openSourceDevice(); + bool initialize(); + void prepareSourceDevice(); + bool emitUpdated(Update &update); + void timerEvent(QTimerEvent *event) override; +}; + +QNmeaSatelliteInfoSourcePrivate::QNmeaSatelliteInfoSourcePrivate(QNmeaSatelliteInfoSource *parent) +: m_source(parent) +{ +} + +void QNmeaSatelliteInfoSourcePrivate::notifyNewUpdate() +{ + if (m_pendingUpdate.isValid() && m_pendingUpdate.isFresh()) { + if (m_requestTimer && m_requestTimer->isActive()) { // User called requestUpdate() + m_requestTimer->stop(); + emitUpdated(m_pendingUpdate); + } else if (m_invokedStart) { // user called startUpdates() + if (m_updateTimer && m_updateTimer->isActive()) { // update interval > 0 + // for periodic updates, only want the most recent update + if (m_noUpdateLastInterval) { + // if the update was invalid when timerEvent was last called, a valid update + // should be sent ASAP + emitPendingUpdate(); // m_noUpdateLastInterval handled in there. + } + } else { // update interval <= 0, send anything new ASAP + m_noUpdateLastInterval = !emitUpdated(m_pendingUpdate); + } + } + } +} + +QNmeaSatelliteInfoSourcePrivate::~QNmeaSatelliteInfoSourcePrivate() +{ + delete m_updateTimer; +} + +void QNmeaSatelliteInfoSourcePrivate::startUpdates() +{ + if (m_invokedStart) + return; + + m_invokedStart = true; + m_pendingUpdate.clear(); + m_noUpdateLastInterval = false; + + bool initialized = initialize(); + if (!initialized) + return; + + // Do not support simulation just yet +// if (m_updateMode == QNmeaPositionInfoSource::RealTimeMode) + { + // skip over any buffered data - we only want the newest data. + // Don't do this in requestUpdate. In that case bufferedData is good to have/use. + if (m_device->bytesAvailable()) { + if (m_device->isSequential()) + m_device->readAll(); + else + m_device->seek(m_device->bytesAvailable()); + } + } + + if (m_updateTimer) + m_updateTimer->stop(); + + if (m_source->updateInterval() > 0) { + if (!m_updateTimer) + m_updateTimer = new QBasicTimer; + m_updateTimer->start(m_source->updateInterval(), this); + } + + if (initialized) + prepareSourceDevice(); +} + +void QNmeaSatelliteInfoSourcePrivate::stopUpdates() +{ + m_invokedStart = false; + if (m_updateTimer) + m_updateTimer->stop(); + m_pendingUpdate.clear(); + m_noUpdateLastInterval = false; +} + +void QNmeaSatelliteInfoSourcePrivate::requestUpdate(int msec) +{ + if (m_requestTimer && m_requestTimer->isActive()) + return; + + if (msec <= 0 || msec < m_source->minimumUpdateInterval()) { + emit m_source->requestTimeout(); + return; + } + + if (!m_requestTimer) { + m_requestTimer = new QTimer(this); + connect(m_requestTimer, SIGNAL(timeout()), SLOT(updateRequestTimeout())); + } + + bool initialized = initialize(); + if (!initialized) { + emit m_source->requestTimeout(); + return; + } + + m_requestTimer->start(msec); + prepareSourceDevice(); +} + +void QNmeaSatelliteInfoSourcePrivate::readyRead() +{ + readAvailableData(); +} + +void QNmeaSatelliteInfoSourcePrivate::emitPendingUpdate() +{ + if (m_pendingUpdate.isValid() && m_pendingUpdate.isFresh()) { + m_updateTimeoutSent = false; + m_noUpdateLastInterval = false; + if (!emitUpdated(m_pendingUpdate)) + m_noUpdateLastInterval = true; +// m_pendingUpdate.clear(); // Do not clear, it will be incrementally updated + } else { // invalid or not fresh update + if (m_noUpdateLastInterval && !m_updateTimeoutSent) { + m_updateTimeoutSent = true; + emit m_source->requestTimeout(); + } + m_noUpdateLastInterval = true; + } +} + +void QNmeaSatelliteInfoSourcePrivate::sourceDataClosed() +{ + if (m_device && m_device->bytesAvailable()) + readAvailableData(); +} + +void QNmeaSatelliteInfoSourcePrivate::updateRequestTimeout() +{ + m_requestTimer->stop(); + emit m_source->requestTimeout(); +} + +void QNmeaSatelliteInfoSourcePrivate::readAvailableData() +{ + while (m_device->canReadLine()) { + char buf[1024]; + qint64 size = m_device->readLine(buf, sizeof(buf)); + QList<int> satInUse; + const bool satInUseParsed = QLocationUtils::getSatInUseFromNmea(buf, size, satInUse); + if (satInUseParsed) { + m_pendingUpdate.setSatellitesInUse(satInUse); +#if USE_NMEA_PIMPL + m_pendingUpdate.gsa = QByteArray(buf, size); + if (m_pendingUpdate.m_satellitesInUse.size()) { + for (auto &s: m_pendingUpdate.m_satellitesInUse) + static_cast<QGeoSatelliteInfoPrivateNmea *>(QGeoSatelliteInfoPrivate::get(s))->nmeaSentences.append(m_pendingUpdate.gsa); + for (auto &s: m_pendingUpdate.m_satellitesInView) + static_cast<QGeoSatelliteInfoPrivateNmea *>(QGeoSatelliteInfoPrivate::get(s))->nmeaSentences.append(m_pendingUpdate.gsa); + } +#endif + } else { + const QLocationUtils::GSVParseStatus parserStatus = QLocationUtils::getSatInfoFromNmea(buf, size, m_pendingUpdate.m_satellitesInView); + if (parserStatus == QLocationUtils::GSVPartiallyParsed) { + m_pendingUpdate.m_updatingGsv = true; +#if USE_NMEA_PIMPL + m_pendingUpdate.gsv.append(QByteArray(buf, size)); +#endif + } else if (parserStatus == QLocationUtils::GSVFullyParsed) { +#if USE_NMEA_PIMPL + m_pendingUpdate.gsv.append(QByteArray(buf, size)); + for (int i = 0; i < m_pendingUpdate.m_satellitesInView.size(); i++) { + const QGeoSatelliteInfo &s = m_pendingUpdate.m_satellitesInView.at(i); + QGeoSatelliteInfoPrivateNmea *pimpl = new QGeoSatelliteInfoPrivateNmea(*QGeoSatelliteInfoPrivate::get(s)); + pimpl->nmeaSentences.append(m_pendingUpdate.gsa); + pimpl->nmeaSentences.append(m_pendingUpdate.gsv); + m_pendingUpdate.m_satellitesInView.replace(i, QGeoSatelliteInfo(*pimpl)); + } + m_pendingUpdate.gsv.clear(); +#endif + m_pendingUpdate.setSatellitesInView(m_pendingUpdate.m_satellitesInView); + } + } + } + notifyNewUpdate(); +} + +bool QNmeaSatelliteInfoSourcePrivate::openSourceDevice() +{ + if (!m_device) { + qWarning("QNmeaSatelliteInfoSource: no QIODevice data source, call setDevice() first"); + return false; + } + + if (!m_device->isOpen() && !m_device->open(QIODevice::ReadOnly)) { + qWarning("QNmeaSatelliteInfoSource: cannot open QIODevice data source"); + return false; + } + + connect(m_device, SIGNAL(aboutToClose()), SLOT(sourceDataClosed())); + connect(m_device, SIGNAL(readChannelFinished()), SLOT(sourceDataClosed())); + connect(m_device, SIGNAL(destroyed()), SLOT(sourceDataClosed())); + + return true; +} + +bool QNmeaSatelliteInfoSourcePrivate::initialize() +{ + if (!openSourceDevice()) + return false; + + return true; +} + +void QNmeaSatelliteInfoSourcePrivate::prepareSourceDevice() +{ + if (!m_connectedReadyRead) { + connect(m_device, SIGNAL(readyRead()), SLOT(readyRead())); + m_connectedReadyRead = true; + } +} + +bool QNmeaSatelliteInfoSourcePrivate::emitUpdated(QNmeaSatelliteInfoSourcePrivate::Update &update) +{ + bool emitted = false; + if (!update.isFresh()) + return emitted; + + update.consume(); + const bool inUseUpdated = update.m_satellitesInUse != m_lastUpdate.m_satellitesInUse; + const bool inViewUpdated = update.m_satellitesInView != m_lastUpdate.m_satellitesInView; + + + m_lastUpdate = update; + if (update.m_validInUse && inUseUpdated) { + emit m_source->satellitesInUseUpdated(update.m_satellitesInUse); + emitted = true; + } + if (update.m_validInView && inViewUpdated) { + emit m_source->satellitesInViewUpdated(update.m_satellitesInView); + emitted = true; + } + return emitted; +} + +void QNmeaSatelliteInfoSourcePrivate::timerEvent(QTimerEvent * /*event*/) +{ + emitPendingUpdate(); +} + + +// currently supports only realtime +QNmeaSatelliteInfoSource::QNmeaSatelliteInfoSource(QObject *parent) +: QGeoSatelliteInfoSource(*new QNmeaSatelliteInfoSourcePrivate(this), parent) +{ + d = static_cast<QNmeaSatelliteInfoSourcePrivate *>(QGeoSatelliteInfoSourcePrivate::get(*this)); +} + +QNmeaSatelliteInfoSource::~QNmeaSatelliteInfoSource() +{ + // d deleted in superclass destructor +} + +void QNmeaSatelliteInfoSource::setDevice(QIODevice *device) +{ + if (device != d->m_device) { + if (!d->m_device) + d->m_device = device; + else + qWarning("QNmeaPositionInfoSource: source device has already been set"); + } +} + +QIODevice *QNmeaSatelliteInfoSource::device() const +{ + return d->m_device; +} + +void QNmeaSatelliteInfoSource::setUpdateInterval(int msec) +{ + int interval = msec; + if (interval != 0) + interval = qMax(msec, minimumUpdateInterval()); + QGeoSatelliteInfoSource::setUpdateInterval(interval); + if (d->m_invokedStart) { + d->stopUpdates(); + d->startUpdates(); + } +} + +int QNmeaSatelliteInfoSource::minimumUpdateInterval() const +{ + return 2; // Some chips are capable of over 100 updates per seconds. +} + +QGeoSatelliteInfoSource::Error QNmeaSatelliteInfoSource::error() const +{ + return d->m_satelliteError; +} + +void QNmeaSatelliteInfoSource::startUpdates() +{ + d->startUpdates(); +} + +void QNmeaSatelliteInfoSource::stopUpdates() +{ + d->stopUpdates(); +} + +void QNmeaSatelliteInfoSource::requestUpdate(int msec) +{ + d->requestUpdate(msec == 0 ? 60000 * 5 : msec); // 5min default timeout +} + +void QNmeaSatelliteInfoSource::setError(QGeoSatelliteInfoSource::Error satelliteError) +{ + d->m_satelliteError = satelliteError; + emit QGeoSatelliteInfoSource::error(satelliteError); +} + + +//QT_END_NAMESPACE + +#include "qnmeasatelliteinfosource.moc" diff --git a/src/plugins/position/serialnmea/qnmeasatelliteinfosource_p.h b/src/plugins/position/serialnmea/qnmeasatelliteinfosource_p.h new file mode 100644 index 00000000..2f7469c6 --- /dev/null +++ b/src/plugins/position/serialnmea/qnmeasatelliteinfosource_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 QNMESATELLITEINFOSOURCE_P_H +#define QNMESATELLITEINFOSOURCE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +//#include <QtPositioning/private/qpositioningglobal_p.h> +#include <QtPositioning/qgeosatelliteinfosource.h> +#include <QtPositioning/qgeosatelliteinfo.h> + +#include <QObject> +#include <QQueue> +#include <QPointer> +#include <QtCore/qiodevice.h> +#include <QtCore/qtimer.h> + +//QT_BEGIN_NAMESPACE + +class QNmeaSatelliteInfoSourcePrivate; +class /*Q_POSITIONING_PRIVATE_EXPORT*/ QNmeaSatelliteInfoSource : public QGeoSatelliteInfoSource +{ + Q_OBJECT +public: + explicit QNmeaSatelliteInfoSource( QObject *parent = nullptr); + ~QNmeaSatelliteInfoSource() override; + + void setDevice(QIODevice *source); + QIODevice *device() const; + + void setUpdateInterval(int msec) override; + int minimumUpdateInterval() const override; + Error error() const override; + +public Q_SLOTS: + void startUpdates() override; + void stopUpdates() override; + void requestUpdate(int timeout = 0) override; + +protected: + QNmeaSatelliteInfoSourcePrivate *d; + void setError(QGeoSatelliteInfoSource::Error satelliteError); + + friend class QNmeaSatelliteInfoSourcePrivate; + Q_DISABLE_COPY(QNmeaSatelliteInfoSource) +}; + +//QT_END_NAMESPACE + +#endif diff --git a/src/plugins/position/serialnmea/serialnmea.pro b/src/plugins/position/serialnmea/serialnmea.pro index bdeb3f13..4e0088bb 100644 --- a/src/plugins/position/serialnmea/serialnmea.pro +++ b/src/plugins/position/serialnmea/serialnmea.pro @@ -1,12 +1,12 @@ TARGET = qtposition_serialnmea -QT = core positioning serialport +QT = core-private positioning-private serialport HEADERS += \ - qgeopositioninfosourcefactory_serialnmea.h + qgeopositioninfosourcefactory_serialnmea.h qnmeasatelliteinfosource_p.h qiopipe_p.h SOURCES += \ - qgeopositioninfosourcefactory_serialnmea.cpp + qgeopositioninfosourcefactory_serialnmea.cpp qnmeasatelliteinfosource.cpp qiopipe.cpp OTHER_FILES += \ plugin.json diff --git a/src/positioning/doc/src/plugins/serialnmea.qdoc b/src/positioning/doc/src/plugins/serialnmea.qdoc new file mode 100644 index 00000000..3e9861b5 --- /dev/null +++ b/src/positioning/doc/src/plugins/serialnmea.qdoc @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page position-plugin-serialnmea.html +\title Qt Positioning Serial NMEA plugin +\ingroup QtPositioning-plugins + +\brief Reads the NMEA stream from a serial connection to provide position updates. + +\section1 Overview + +Included with Qt Location is a position plugin which parses NMEA sentences streamed +over a serial port into position updates. + +This plugin can be loaded by using the provider name \b serialnmea. + + +\section1 Parameters + +The following table lists parameters that \e can be passed to the serialnmea plugin. + +\table +\header + \li Parameter + \li Description +\row + \li serialnmea.serial_port + \li The serial port where the NMEA stream is coming. +\endtable + +\section1 Parameter Usage Example + +The following examples show how to create a \b serialnmea PositionSource +listening on a specific serial port + +\section2 QML + +\code +PositionSource { + name: "serialnmea" + PluginParameter { name: "serialnmea.serial_port"; value: "tnt1" } +} +\endcode + +\section2 C++ + +\code +QVariantMap params; +params["serialnmea.serial_port"] = "tnt1"; +QGeoPositionInfoSource *positionSource = QGeoPositionInfoSource::createSource("serialnmea", params, this); +\endcode + +*/ diff --git a/src/positioning/doc/src/qtpositioning-plugins.qdoc b/src/positioning/doc/src/qtpositioning-plugins.qdoc index 37d25fc5..77fdf3aa 100644 --- a/src/positioning/doc/src/qtpositioning-plugins.qdoc +++ b/src/positioning/doc/src/qtpositioning-plugins.qdoc @@ -27,11 +27,43 @@ /*! \page qtpositioning-plugins.html -\title Qt Positioning service plugins -\brief Implementing Qt Positioning plugins +\title Qt Positioning plugins +\brief Default Plugins and Implementing Qt Positioning plugins + +Qt Positioning provides the majority of its functionality through plugins. +This document outlines how to develop a new position plugin. + +\section1 Default plugins +Some plugins already ship with Qt. These are: + +\table + \row + \li \b android + \li Wraps Android positioning subsystem. Available only on Android. + \row + \li \b corelocation + \li Wraps iOS and macOS positioning subsystems. Available only on Apple platforms supporting corelocation. + \row + \li \b geoclue + \li Interfaces with \l{https://www.freedesktop.org/wiki/Software/GeoClue/}{GeoClue} v0.12. Requires GeoClue 0.12 to be present to function. + \row + \li \b geoclue2 + \li Interfaces with \l{https://www.freedesktop.org/wiki/Software/GeoClue/}{GeoClue} v2. Requires GeoClue v2 to be present to function. + \row + \li \b gypsy + \li Interfaces with \l{https://gypsy.freedesktop.org/wiki/}{Gypsy} daemon. Requires Gypsy to be present to function. + \row + \li \b winrt + \li Wraps WinRT positioning subsystem. Available only on WinRT and Windows10. + \row + \li \b serialnmea + \li A \l {Qt Positioning Serial NMEA plugin}{Serial NMEA} backend that parses NMEA streams from a GPS receiver over a + serial link to provide position updates. + \row + \li \b positionpoll + \li A backend providing only area monitoring functionalities via polling on position updates. +\endtable -Qt Positioning provides the majority of its functionality through plugins. This -document outlines how to develop a new position plugin. \section1 Plugin Description diff --git a/src/positioning/positioning.pro b/src/positioning/positioning.pro index 35e8e9e1..1eff0ab2 100644 --- a/src/positioning/positioning.pro +++ b/src/positioning/positioning.pro @@ -7,7 +7,7 @@ INCLUDEPATH += ../3rdparty/clipper INCLUDEPATH += ../3rdparty/clip2tri QMAKE_DOCS = $$PWD/doc/qtpositioning.qdocconf -OTHER_FILES += configure.json doc/src/*.qdoc # show .qdoc files in Qt Creator +OTHER_FILES += configure.json doc/src/*.qdoc doc/src/plugins/*.qdoc # show .qdoc files in Qt Creator ANDROID_BUNDLED_JAR_DEPENDENCIES = \ jar/QtPositioning.jar:org.qtproject.qt5.android.positioning.QtPositioning @@ -59,6 +59,8 @@ PRIVATE_HEADERS += \ qgeopolygon_p.h \ qgeocoordinateobject_p.h \ qgeopositioninfo_p.h \ + qgeosatelliteinfo_p.h \ + qgeosatelliteinfosource_p.h \ qclipperutils_p.h SOURCES += \ @@ -89,7 +91,6 @@ SOURCES += \ HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS - load(qt_module) LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lclip2tri$$qtPlatformTargetSuffix() diff --git a/src/positioning/qgeopositioninfosource.cpp b/src/positioning/qgeopositioninfosource.cpp index 2e126175..69fcdef0 100644 --- a/src/positioning/qgeopositioninfosource.cpp +++ b/src/positioning/qgeopositioninfosource.cpp @@ -103,6 +103,16 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, \value AllPositioningMethods Satellite-based positioning methods as soon as available. Otherwise non-satellite based methods. */ +QGeoPositionInfoSourcePrivate *QGeoPositionInfoSourcePrivate::get(const QGeoPositionInfoSource &source) +{ + return source.d; +} + +QGeoPositionInfoSourcePrivate::~QGeoPositionInfoSourcePrivate() +{ + +} + void QGeoPositionInfoSourcePrivate::loadMeta() { metaData = plugins().value(providerName); @@ -113,7 +123,24 @@ void QGeoPositionInfoSourcePrivate::loadPlugin() int idx = int(metaData.value(QStringLiteral("index")).toDouble()); if (idx < 0) return; - factory = qobject_cast<QGeoPositionInfoSourceFactory *>(loader()->instance(idx)); + QObject *instance = loader()->instance(idx); + if (!instance) + return; + factoryV2 = qobject_cast<QGeoPositionInfoSourceFactoryV2 *>(instance); + if (!factoryV2) + factory = qobject_cast<QGeoPositionInfoSourceFactory *>(instance); + else + factory = factoryV2; +} + +bool QGeoPositionInfoSourcePrivate::setBackendProperty(const QString &/*name*/, QVariant /*value*/) +{ + return false; +} + +QVariant QGeoPositionInfoSourcePrivate::backendProperty(const QString &/*name*/) const +{ + return QVariant(); } QHash<QString, QJsonObject> QGeoPositionInfoSourcePrivate::plugins(bool reload) @@ -204,6 +231,36 @@ QString QGeoPositionInfoSource::sourceName() const } /*! + Sets the backend-specific property named \a name to \a value. + Returns \c true on success, \c false otherwise. + Backend-specific properties can be used to configure the positioning subsystem behavior + at runtime. + Supported backend-specific properties are listed and described in + \l {Qt Positioning plugins#Default plugins}. + + \sa backendProperty + \since Qt 5.14 +*/ +bool QGeoPositionInfoSource::setBackendProperty(const QString &name, QVariant value) +{ + return d->setBackendProperty(name, value); +} + +/*! + Returns the value of the backend-specific property named \a name, if present. + Otherwise, the returned value will be invalid. + Supported backend-specific properties are listed and described in + \l {Qt Positioning plugins#Default plugins}. + + \sa setBackendProperty + \since Qt 5.14 +*/ +QVariant QGeoPositionInfoSource::backendProperty(const QString &name) const +{ + return d->backendProperty(name); +} + +/*! \property QGeoPositionInfoSource::updateInterval \brief This property holds the requested interval in milliseconds between each update. @@ -271,6 +328,22 @@ QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSource::preferredPosi return d->methods; } +static QGeoPositionInfoSource* createSource_real(const QJsonObject &meta, const QVariantMap ¶meters, QObject *parent) +{ + QGeoPositionInfoSourcePrivate d; + d.metaData = meta; + d.loadPlugin(); + QGeoPositionInfoSource *s = nullptr; + if (!parameters.isEmpty() && d.factoryV2) + s = d.factoryV2->positionInfoSourceWithParameters(parent, parameters); + else if (d.factory) + s = d.factory->positionInfoSource(parent); + if (s) + QGeoPositionInfoSourcePrivate::get(*s)->metaData = d.metaData; + + return s; +} + /*! Creates and returns a position source with the given \a parent that reads from the system's default sources of location data, or the plugin @@ -281,27 +354,32 @@ QGeoPositionInfoSource::PositioningMethods QGeoPositionInfoSource::preferredPosi */ QGeoPositionInfoSource *QGeoPositionInfoSource::createDefaultSource(QObject *parent) { + return createDefaultSource(QVariantMap(), parent); +} + +/*! + Creates and returns a position source with the given \a parent that + reads from the system's default sources of location data, or the plugin + with the highest available priority. + + Returns nullptr if the system has no default position source, no valid plugins + could be found or the user does not have the permission to access the current position. + + This method passes \a parameters to the factory to configure the source. + + \since Qt 5.14 +*/ +QGeoPositionInfoSource *QGeoPositionInfoSource::createDefaultSource(const QVariantMap ¶meters, QObject *parent) +{ QList<QJsonObject> plugins = QGeoPositionInfoSourcePrivate::pluginsSorted(); foreach (const QJsonObject &obj, plugins) { if (obj.value(QStringLiteral("Position")).isBool() && obj.value(QStringLiteral("Position")).toBool()) - { - QGeoPositionInfoSourcePrivate d; - d.metaData = obj; - d.loadPlugin(); - QGeoPositionInfoSource *s = 0; - if (d.factory) - s = d.factory->positionInfoSource(parent); - if (s) { - s->d->metaData = d.metaData; - return s; - } - } + return createSource_real(obj, parameters, parent); } - return 0; + return nullptr; } - /*! Creates and returns a position source with the given \a parent, by loading the plugin named \a sourceName. @@ -310,25 +388,27 @@ QGeoPositionInfoSource *QGeoPositionInfoSource::createDefaultSource(QObject *par */ QGeoPositionInfoSource *QGeoPositionInfoSource::createSource(const QString &sourceName, QObject *parent) { + return createSource(sourceName, QVariantMap(), parent); +} + +/*! + Creates and returns a position source with the given \a parent, + by loading the plugin named \a sourceName. + + Returns nullptr if the plugin cannot be found. + + This method passes \a parameters to the factory to configure the source. + + \since Qt 5.14 +*/ +QGeoPositionInfoSource *QGeoPositionInfoSource::createSource(const QString &sourceName, const QVariantMap ¶meters, QObject *parent) +{ QHash<QString, QJsonObject> plugins = QGeoPositionInfoSourcePrivate::plugins(); if (plugins.contains(sourceName)) - { - QGeoPositionInfoSourcePrivate d; - d.metaData = plugins.value(sourceName); - d.loadPlugin(); - QGeoPositionInfoSource *src = 0; - if (d.factory) - src = d.factory->positionInfoSource(parent); - if (src) - { - src->d->metaData = d.metaData; - return src; - } - } - return 0; + return createSource_real(plugins.value(sourceName), parameters, parent); + return nullptr; } - /*! Returns a list of available source plugins. This includes any default backend plugin for the current platform. @@ -347,6 +427,15 @@ QStringList QGeoPositionInfoSource::availableSources() return plugins; } +QGeoPositionInfoSource::QGeoPositionInfoSource(QGeoPositionInfoSourcePrivate &dd, QObject *parent) +: QObject(parent), + d(&dd) +{ + qRegisterMetaType<QGeoPositionInfo>(); + d->interval = 0; + d->methods = NoPositioningMethods; +} + /*! \fn QGeoPositionInfo QGeoPositionInfoSource::lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const = 0; diff --git a/src/positioning/qgeopositioninfosource.h b/src/positioning/qgeopositioninfosource.h index 7fe02270..eaf5e106 100644 --- a/src/positioning/qgeopositioninfosource.h +++ b/src/positioning/qgeopositioninfosource.h @@ -36,6 +36,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + #ifndef QGEOPOSITIONINFOSOURCE_H #define QGEOPOSITIONINFOSOURCE_H @@ -86,8 +87,13 @@ public: QString sourceName() const; + bool setBackendProperty(const QString &name, QVariant value); + QVariant backendProperty(const QString &name) const; + static QGeoPositionInfoSource *createDefaultSource(QObject *parent); + static QGeoPositionInfoSource *createDefaultSource(const QVariantMap ¶meters, QObject *parent); static QGeoPositionInfoSource *createSource(const QString &sourceName, QObject *parent); + static QGeoPositionInfoSource *createSource(const QString &sourceName, const QVariantMap ¶meters, QObject *parent); static QStringList availableSources(); virtual Error error() const = 0; @@ -103,9 +109,14 @@ Q_SIGNALS: void error(QGeoPositionInfoSource::Error); void supportedPositioningMethodsChanged(); +protected: + QGeoPositionInfoSource(QGeoPositionInfoSourcePrivate &dd, QObject *parent); + private: Q_DISABLE_COPY(QGeoPositionInfoSource) QGeoPositionInfoSourcePrivate *d; + + friend class QGeoPositionInfoSourcePrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoPositionInfoSource::PositioningMethods) diff --git a/src/positioning/qgeopositioninfosource_p.h b/src/positioning/qgeopositioninfosource_p.h index 32fd23e6..ccd92a4e 100644 --- a/src/positioning/qgeopositioninfosource_p.h +++ b/src/positioning/qgeopositioninfosource_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <QtPositioning/private/qpositioningglobal_p.h> #include "qgeopositioninfosource.h" #include "qgeopositioninfosourcefactory.h" #include <QJsonObject> @@ -60,17 +61,23 @@ QT_BEGIN_NAMESPACE -class QGeoPositionInfoSourcePrivate +class Q_POSITIONING_PRIVATE_EXPORT QGeoPositionInfoSourcePrivate { public: + static QGeoPositionInfoSourcePrivate *get(const QGeoPositionInfoSource &source); + virtual ~QGeoPositionInfoSourcePrivate(); + int interval; QGeoPositionInfoSource::PositioningMethods methods; QJsonObject metaData; - QGeoPositionInfoSourceFactory *factory; + QGeoPositionInfoSourceFactory *factory = nullptr; + QGeoPositionInfoSourceFactoryV2 *factoryV2 = nullptr; QString providerName; void loadMeta(); void loadPlugin(); + virtual bool setBackendProperty(const QString &name, QVariant value); + virtual QVariant backendProperty(const QString &name) const; static QHash<QString, QJsonObject> plugins(bool reload = false); static void loadPluginMetadata(QHash<QString, QJsonObject> &list); diff --git a/src/positioning/qgeopositioninfosourcefactory.cpp b/src/positioning/qgeopositioninfosourcefactory.cpp index 6c6e9c73..76803566 100644 --- a/src/positioning/qgeopositioninfosourcefactory.cpp +++ b/src/positioning/qgeopositioninfosourcefactory.cpp @@ -84,4 +84,8 @@ QT_BEGIN_NAMESPACE QGeoPositionInfoSourceFactory::~QGeoPositionInfoSourceFactory() {} +QGeoPositionInfoSourceFactoryV2::~QGeoPositionInfoSourceFactoryV2() +{} + QT_END_NAMESPACE + diff --git a/src/positioning/qgeopositioninfosourcefactory.h b/src/positioning/qgeopositioninfosourcefactory.h index b30aaf7e..e55a1eb3 100644 --- a/src/positioning/qgeopositioninfosourcefactory.h +++ b/src/positioning/qgeopositioninfosourcefactory.h @@ -61,6 +61,21 @@ public: Q_DECLARE_INTERFACE(QGeoPositionInfoSourceFactory, "org.qt-project.qt.position.sourcefactory/5.0") +class Q_POSITIONING_EXPORT QGeoPositionInfoSourceFactoryV2 : public QGeoPositionInfoSourceFactory +{ +public: + virtual ~QGeoPositionInfoSourceFactoryV2(); + + virtual QGeoPositionInfoSource *positionInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters) = 0; + virtual QGeoSatelliteInfoSource *satelliteInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters) = 0; + virtual QGeoAreaMonitorSource *areaMonitorWithParameters(QObject *parent, const QVariantMap ¶meters) = 0; +}; + +// Although not actually used for constructing a specialized loader, this is required for +// casting a QObject * into QGeoPositionInfoSourceFactoryV2 * +Q_DECLARE_INTERFACE(QGeoPositionInfoSourceFactoryV2, + "org.qt-project.qt.position.sourcefactoryV2/5.0") + QT_END_NAMESPACE #endif // QGEOPOSITIONINFOSOURCEFACTORY_H diff --git a/src/positioning/qgeosatelliteinfo.cpp b/src/positioning/qgeosatelliteinfo.cpp index e62bd164..91ebfa85 100644 --- a/src/positioning/qgeosatelliteinfo.cpp +++ b/src/positioning/qgeosatelliteinfo.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ #include "qgeosatelliteinfo.h" +#include "qgeosatelliteinfo_p.h" #include <QHash> #include <QDebug> @@ -44,16 +45,6 @@ QT_BEGIN_NAMESPACE -class QGeoSatelliteInfoPrivate -{ -public: - int signal; - int satId; - QGeoSatelliteInfo::SatelliteSystem system; - QHash<int, qreal> doubleAttribs; -}; - - /*! \class QGeoSatelliteInfo \inmodule QtPositioning @@ -103,6 +94,10 @@ QGeoSatelliteInfo::QGeoSatelliteInfo(const QGeoSatelliteInfo &other) operator=(other); } +QGeoSatelliteInfo::QGeoSatelliteInfo(QGeoSatelliteInfoPrivate &dd) : d(&dd) +{ +} + /*! Destroys a satellite information object. */ @@ -119,10 +114,9 @@ QGeoSatelliteInfo &QGeoSatelliteInfo::operator=(const QGeoSatelliteInfo & other) if (this == &other) return *this; - d->signal = other.d->signal; - d->satId = other.d->satId; - d->system = other.d->system; - d->doubleAttribs = other.d->doubleAttribs; + delete d; + d = other.d->clone(); + return *this; } @@ -132,10 +126,7 @@ QGeoSatelliteInfo &QGeoSatelliteInfo::operator=(const QGeoSatelliteInfo & other) */ bool QGeoSatelliteInfo::operator==(const QGeoSatelliteInfo &other) const { - return d->signal == other.d->signal - && d->satId == other.d->satId - && d->system == other.d->system - && d->doubleAttribs == other.d->doubleAttribs; + return *d == *other.d; } /*! @@ -309,6 +300,40 @@ QDataStream &operator>>(QDataStream &stream, QGeoSatelliteInfo &info) info.d->system = (QGeoSatelliteInfo::SatelliteSystem)system; return stream; } + +QGeoSatelliteInfoPrivate::QGeoSatelliteInfoPrivate() +{ + +} + +QGeoSatelliteInfoPrivate::QGeoSatelliteInfoPrivate(const QGeoSatelliteInfoPrivate &other) +{ + signal = other.signal; + satId = other.satId; + system = other.system; + doubleAttribs = other.doubleAttribs; +} + +QGeoSatelliteInfoPrivate::~QGeoSatelliteInfoPrivate() {} + +QGeoSatelliteInfoPrivate *QGeoSatelliteInfoPrivate::clone() const +{ + return new QGeoSatelliteInfoPrivate(*this); +} + +bool QGeoSatelliteInfoPrivate::operator==(const QGeoSatelliteInfoPrivate &other) const +{ + return signal == other.signal + && satId == other.satId + && system == other.system + && doubleAttribs == other.doubleAttribs; +} + +QGeoSatelliteInfoPrivate *QGeoSatelliteInfoPrivate::get(const QGeoSatelliteInfo &info) +{ + return info.d; +} + #endif QT_END_NAMESPACE diff --git a/src/positioning/qgeosatelliteinfo.h b/src/positioning/qgeosatelliteinfo.h index e68d8d9f..28766257 100644 --- a/src/positioning/qgeosatelliteinfo.h +++ b/src/positioning/qgeosatelliteinfo.h @@ -63,6 +63,7 @@ public: QGeoSatelliteInfo(); QGeoSatelliteInfo(const QGeoSatelliteInfo &other); + QGeoSatelliteInfo(QGeoSatelliteInfoPrivate &dd); ~QGeoSatelliteInfo(); QGeoSatelliteInfo &operator=(const QGeoSatelliteInfo &other); @@ -96,6 +97,7 @@ private: friend Q_POSITIONING_EXPORT QDataStream &operator>>(QDataStream &stream, QGeoSatelliteInfo &info); #endif QGeoSatelliteInfoPrivate *d; + friend class QGeoSatelliteInfoPrivate; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/positioning/qgeosatelliteinfo_p.h b/src/positioning/qgeosatelliteinfo_p.h new file mode 100644 index 00000000..6320bf2e --- /dev/null +++ b/src/positioning/qgeosatelliteinfo_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 QGEOSATELLITEINFO_P_H +#define QGEOSATELLITEINFO_P_H + +#include <QtPositioning/private/qpositioningglobal_p.h> +#include <QtPositioning/qgeosatelliteinfo.h> +#include <QHash> + +QT_BEGIN_NAMESPACE + +class Q_POSITIONING_PRIVATE_EXPORT QGeoSatelliteInfoPrivate +{ +public: + QGeoSatelliteInfoPrivate(); + QGeoSatelliteInfoPrivate(const QGeoSatelliteInfoPrivate &other); + virtual ~QGeoSatelliteInfoPrivate(); + virtual QGeoSatelliteInfoPrivate *clone() const; + virtual bool operator==(const QGeoSatelliteInfoPrivate &other) const; + static QGeoSatelliteInfoPrivate *get(const QGeoSatelliteInfo &info); + + int signal; + int satId; + QGeoSatelliteInfo::SatelliteSystem system; + QHash<int, qreal> doubleAttribs; +}; + +QT_END_NAMESPACE + +#endif // QGEOSATELLITEINFO_P_H diff --git a/src/positioning/qgeosatelliteinfosource.cpp b/src/positioning/qgeosatelliteinfosource.cpp index c55c36d3..6796b921 100644 --- a/src/positioning/qgeosatelliteinfosource.cpp +++ b/src/positioning/qgeosatelliteinfosource.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ #include <qgeosatelliteinfosource.h> +#include <qgeosatelliteinfosource_p.h> #include "qgeopositioninfosourcefactory.h" #include "qgeopositioninfosource_p.h" #include <QPluginLoader> @@ -84,16 +85,20 @@ QT_BEGIN_NAMESPACE update intervals, as returned by minimumUpdateInterval(). */ -class QGeoSatelliteInfoSourcePrivate -{ -public: - int interval; - QString providerName; -}; - /*! Creates a satellite source with the specified \a parent. */ + +QGeoSatelliteInfoSourcePrivate::~QGeoSatelliteInfoSourcePrivate() +{ + +} + +QGeoSatelliteInfoSourcePrivate *QGeoSatelliteInfoSourcePrivate::get(QGeoSatelliteInfoSource &source) +{ + return source.d; +} + QGeoSatelliteInfoSource::QGeoSatelliteInfoSource(QObject *parent) : QObject(parent), d(new QGeoSatelliteInfoSourcePrivate) @@ -101,6 +106,13 @@ QGeoSatelliteInfoSource::QGeoSatelliteInfoSource(QObject *parent) d->interval = 0; } +QGeoSatelliteInfoSource::QGeoSatelliteInfoSource(QGeoSatelliteInfoSourcePrivate &dd, QObject *parent) +: QObject(parent), + d(&dd) +{ + +} + /*! Destroys the satellite source. */ @@ -153,7 +165,21 @@ int QGeoSatelliteInfoSource::updateInterval() const return d->interval; } - +static QGeoSatelliteInfoSource* createSource_real(const QJsonObject &meta, const QVariantMap ¶meters, QObject *parent) +{ + QGeoPositionInfoSourcePrivate d; + d.metaData = meta; + d.loadPlugin(); + QGeoSatelliteInfoSource *s = nullptr; + if (!parameters.isEmpty() && d.factoryV2) + s = d.factoryV2->satelliteInfoSourceWithParameters(parent, parameters); + else if (d.factory) + s = d.factory->satelliteInfoSource(parent); + if (s) + QGeoSatelliteInfoSourcePrivate::get(*s)->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); + + return s; +} /*! Creates and returns a source with the specified \a parent that reads @@ -165,6 +191,34 @@ int QGeoSatelliteInfoSource::updateInterval() const */ QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createDefaultSource(QObject *parent) { + return createDefaultSource(QVariantMap(), parent); +} + +/*! + Creates and returns a source with the given \a parent, + by loading the plugin named \a sourceName. + + Returns 0 if the plugin cannot be found. +*/ +QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createSource(const QString &sourceName, QObject *parent) +{ + return createSource(sourceName, QVariantMap(), parent); +} + +/*! + Creates and returns a satellite source with the given \a parent that + reads from the system's default sources of satellite data, or the plugin + with the highest available priority. + + Returns nullptr if the system has no default satellite source, no valid plugins + could be found or the user does not have the permission to access the satellite information. + + This method passes \a parameters to the factory to configure the source. + + \since Qt 5.14 +*/ +QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createDefaultSource(const QVariantMap ¶meters, QObject *parent) +{ QList<QJsonObject> plugins = QGeoPositionInfoSourcePrivate::pluginsSorted(); foreach (const QJsonObject &obj, plugins) { if (obj.value(QStringLiteral("Satellite")).isBool() @@ -176,43 +230,29 @@ QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createDefaultSource(QObject *p if (inTest) continue; } - QGeoPositionInfoSourcePrivate d; - d.metaData = obj; - d.loadPlugin(); - QGeoSatelliteInfoSource *s = 0; - if (d.factory) - s = d.factory->satelliteInfoSource(parent); - if (s) - s->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); - return s; + return createSource_real(obj, parameters, parent); } } - return 0; + return nullptr; } /*! - Creates and returns a source with the given \a parent, + Creates and returns a satellite source with the given \a parent, by loading the plugin named \a sourceName. - Returns 0 if the plugin cannot be found. + Returns nullptr if the plugin cannot be found. + + This method passes \a parameters to the factory to configure the source. + + \since Qt 5.14 */ -QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createSource(const QString &sourceName, QObject *parent) +QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createSource(const QString &sourceName, const QVariantMap ¶meters, QObject *parent) { QHash<QString, QJsonObject> plugins = QGeoPositionInfoSourcePrivate::plugins(); - if (plugins.contains(sourceName)) { - QGeoPositionInfoSourcePrivate d; - d.metaData = plugins.value(sourceName); - d.loadPlugin(); - QGeoSatelliteInfoSource *src = 0; - if (d.factory) - src = d.factory->satelliteInfoSource(parent); - if (src) - src->d->providerName = d.metaData.value(QStringLiteral("Provider")).toString(); - return src; - } - - return 0; + if (plugins.contains(sourceName)) + return createSource_real(plugins.value(sourceName), parameters, parent); + return nullptr; } /*! diff --git a/src/positioning/qgeosatelliteinfosource.h b/src/positioning/qgeosatelliteinfosource.h index 391eefcf..4f073864 100644 --- a/src/positioning/qgeosatelliteinfosource.h +++ b/src/positioning/qgeosatelliteinfosource.h @@ -67,6 +67,8 @@ public: static QGeoSatelliteInfoSource *createDefaultSource(QObject *parent); static QGeoSatelliteInfoSource *createSource(const QString &sourceName, QObject *parent); + static QGeoSatelliteInfoSource *createDefaultSource(const QVariantMap ¶meters, QObject *parent); + static QGeoSatelliteInfoSource *createSource(const QString &sourceName, const QVariantMap ¶meters, QObject *parent); static QStringList availableSources(); QString sourceName() const; @@ -88,9 +90,13 @@ Q_SIGNALS: void requestTimeout(); void error(QGeoSatelliteInfoSource::Error); +protected: + QGeoSatelliteInfoSource(QGeoSatelliteInfoSourcePrivate &dd, QObject *parent); + private: Q_DISABLE_COPY(QGeoSatelliteInfoSource) QGeoSatelliteInfoSourcePrivate *d; + friend class QGeoSatelliteInfoSourcePrivate; }; QT_END_NAMESPACE diff --git a/src/positioning/qgeosatelliteinfosource_p.h b/src/positioning/qgeosatelliteinfosource_p.h new file mode 100644 index 00000000..58001b21 --- /dev/null +++ b/src/positioning/qgeosatelliteinfosource_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 QGEOSATELLITEINFOSOURCE_P_H +#define QGEOSATELLITEINFOSOURCE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtPositioning/private/qpositioningglobal_p.h> +#include <QString> + +QT_BEGIN_NAMESPACE +class QGeoSatelliteInfoSource; +class Q_POSITIONING_PRIVATE_EXPORT QGeoSatelliteInfoSourcePrivate +{ +public: + virtual ~QGeoSatelliteInfoSourcePrivate(); + static QGeoSatelliteInfoSourcePrivate *get(QGeoSatelliteInfoSource &source); + int interval; + QString providerName; +}; + +QT_END_NAMESPACE + +#endif // QGEOSATELLITEINFOSOURCE_P_H diff --git a/src/positioning/qlocationutils.cpp b/src/positioning/qlocationutils.cpp index f5062eb6..fec8ccba 100644 --- a/src/positioning/qlocationutils.cpp +++ b/src/positioning/qlocationutils.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qlocationutils_p.h" #include "qgeopositioninfo.h" +#include "qgeosatelliteinfo.h" #include <QTime> #include <QList> @@ -124,6 +125,25 @@ static void qlocationutils_readGsa(const char *data, int size, QGeoPositionInfo } } +static void qlocationutils_readGsa(const char *data, + int size, + QList<int> &pnrsInUse) +{ + QList<QByteArray> parts = QByteArray::fromRawData(data, size).split(','); + pnrsInUse.clear(); + if (parts.count() <= 2) + return; + bool ok; + for (int i = 3; i <= qMin(14, parts.size()); ++i) { + const QByteArray &pnrString = parts.at(i); + if (pnrString.isEmpty()) + continue; + int pnr = pnrString.toInt(&ok); + if (ok) + pnrsInUse.append(pnr); + } +} + static void qlocationutils_readGll(const char *data, int size, QGeoPositionInfo *info, bool *hasFix) { QByteArray sentence(data, size); @@ -269,6 +289,9 @@ QLocationUtils::NmeaSentence QLocationUtils::getNmeaSentenceType(const char *dat if (data[3] == 'G' && data[4] == 'S' && data[5] == 'A') return NmeaSentenceGSA; + if (data[3] == 'G' && data[4] == 'S' && data[5] == 'V') + return NmeaSentenceGSV; + if (data[3] == 'G' && data[4] == 'L' && data[5] == 'L') return NmeaSentenceGLL; @@ -329,6 +352,85 @@ bool QLocationUtils::getPosInfoFromNmea(const char *data, int size, QGeoPosition } } +QLocationUtils::GSVParseStatus QLocationUtils::getSatInfoFromNmea(const char *data, int size, QList<QGeoSatelliteInfo> &infos) +{ + if (!data || !size) + return GSVNotParsed; + + NmeaSentence nmeaType = getNmeaSentenceType(data, size); + if (nmeaType != NmeaSentenceGSV) + return GSVNotParsed; + + QList<QByteArray> parts = QByteArray::fromRawData(data, size).split(','); + + if (parts.count() <= 3) { + infos.clear(); + return GSVFullyParsed; // Malformed sentence. + } + bool ok; + const int totalSentences = parts.at(1).toInt(&ok); + if (!ok) { + infos.clear(); + return GSVFullyParsed; // Malformed sentence. + } + + const int sentence = parts.at(2).toInt(&ok); + if (!ok) { + infos.clear(); + return GSVFullyParsed; // Malformed sentence. + } + + const int totalSats = parts.at(3).toInt(&ok); + if (!ok) { + infos.clear(); + return GSVFullyParsed; // Malformed sentence. + } + + if (sentence == 1) + infos.clear(); + + const int numSatInSentence = qMin(sentence * 4, totalSats) - (sentence - 1) * 4; + + int field = 4; + for (int i = 0; i < numSatInSentence; ++i) { + QGeoSatelliteInfo info; + const int prn = parts.at(field++).toInt(&ok); + info.setSatelliteIdentifier((ok) ? prn : 0); + const int elevation = parts.at(field++).toInt(&ok); + info.setAttribute(QGeoSatelliteInfo::Elevation, (ok) ? elevation : 0); + const int azimuth = parts.at(field++).toInt(&ok); + info.setAttribute(QGeoSatelliteInfo::Azimuth, (ok) ? azimuth : 0); + const int snr = parts.at(field++).toInt(&ok); + info.setSignalStrength((ok) ? snr : -1); + infos.append(info); + } + + if (sentence == totalSentences) + return GSVFullyParsed; + return GSVPartiallyParsed; +} + +bool QLocationUtils::getSatInUseFromNmea(const char *data, int size, QList<int> &pnrsInUse) +{ + pnrsInUse.clear(); + if (!data || !size) + return false; + + NmeaSentence nmeaType = getNmeaSentenceType(data, size); + if (nmeaType != NmeaSentenceGSA) + return false; + + // Adjust size so that * and following characters are not parsed by the following functions. + for (int i = 0; i < size; ++i) { + if (data[i] == '*') { + size = i; + break; + } + } + qlocationutils_readGsa(data, size, pnrsInUse); + return true; +} + bool QLocationUtils::hasValidNmeaChecksum(const char *data, int size) { int asteriskIndex = -1; diff --git a/src/positioning/qlocationutils_p.h b/src/positioning/qlocationutils_p.h index e3881f6f..e2d739e7 100644 --- a/src/positioning/qlocationutils_p.h +++ b/src/positioning/qlocationutils_p.h @@ -65,6 +65,7 @@ class QTime; class QByteArray; class QGeoPositionInfo; +class QGeoSatelliteInfo; class Q_POSITIONING_PRIVATE_EXPORT QLocationUtils { public: @@ -94,7 +95,8 @@ public: NmeaSentenceGLL, // Lat/Lon data NmeaSentenceRMC, // Recommended minimum data for gps NmeaSentenceVTG, // Vector track an Speed over the Ground - NmeaSentenceZDA // Date and Time + NmeaSentenceZDA, // Date and Time + NmeaSentenceGSV // Per-Satellite Info }; inline static bool isValidLat(double lat) { @@ -282,6 +284,29 @@ public: bool *hasFix = nullptr); /* + Retruns a list of QGeoSatelliteInfo in the view. + + Note: this function has to be called repeatedly until it returns true. + Reason being that GSV sentences can be split into multiple samples, so getting the full data + requires parsing multiple sentences. + */ + enum GSVParseStatus { + GSVNotParsed, + GSVPartiallyParsed, + GSVFullyParsed + }; + static GSVParseStatus getSatInfoFromNmea(const char *data, + int size, + QList<QGeoSatelliteInfo> &infos); + + /* + Parses GSA for satellites in use. + */ + static bool getSatInUseFromNmea(const char *data, + int size, + QList<int> &pnrsInUse); + + /* Returns true if the given NMEA sentence has a valid checksum. */ static bool hasValidNmeaChecksum(const char *data, int size); diff --git a/src/positioningquick/qdeclarativepluginparameter.cpp b/src/positioningquick/qdeclarativepluginparameter.cpp new file mode 100644 index 00000000..678e8a6a --- /dev/null +++ b/src/positioningquick/qdeclarativepluginparameter.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativepluginparameter_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype PluginParameter + \instantiates QDeclarativePluginParameter + \inqmlmodule QtPositioning + \ingroup qml-QtPositioning5-common + \since QtPositioning 5.14 + + \brief The PluginParameter type describes a parameter for a plugin, either + geoservice \l Plugin, or position plugin. + + The PluginParameter object is used to provide a parameter of some kind + to a plugin. Typically these parameters contain details like an application + token for access to a service, or a proxy server to use for network access, + or the serial port to which a serial GPS receiver is connected. + + To set such a parameter, declare a PluginParameter inside an element that accepts + plugin parameters as configuration objects, such as a \l Plugin object, or a + \l PositionSource object, and give it \l{name} and \l{value} properties. A list of valid + parameter names for each plugin is available from the + \l {Qt Location#Plugin References and Parameters}{plugin reference pages} for geoservice plugins, + and \l {Qt Positioning plugins#Default plugins} for position plugins. + + \section2 Example Usage + + The following example shows an instantiation of the \l {Qt Location HERE Plugin}{HERE} plugin + with a mapping API \e app_id and \e token pair specific to the application. + + \code + Plugin { + name: "here" + PluginParameter { name: "here.app_id"; value: "EXAMPLE_API_ID" } + PluginParameter { name: "here.token"; value: "EXAMPLE_TOKEN_123" } + } + \endcode +*/ + +/*! + \qmlproperty string PluginParameter::name + + This property holds the name of the plugin parameter as a single formatted string. + This property is a write-once property. +*/ + +/*! + \qmlproperty QVariant PluginParameter::value + + This property holds the value of the plugin parameter which support different types of values (variant). + This property is a write-once property. +*/ + +QDeclarativePluginParameter::QDeclarativePluginParameter(QObject *parent) + : QObject(parent) {} + +QDeclarativePluginParameter::~QDeclarativePluginParameter() {} + +void QDeclarativePluginParameter::setName(const QString &name) +{ + if (!name_.isEmpty() || name.isEmpty()) + return; + + name_ = name; + + emit nameChanged(name_); + if (value_.isValid()) + emit initialized(); +} + +QString QDeclarativePluginParameter::name() const +{ + return name_; +} + +void QDeclarativePluginParameter::setValue(const QVariant &value) +{ + if (value_.isValid() || !value.isValid() || value.isNull()) + return; + + value_ = value; + + emit valueChanged(value_); + if (!name_.isEmpty()) + emit initialized(); +} + +QVariant QDeclarativePluginParameter::value() const +{ + return value_; +} + +bool QDeclarativePluginParameter::isInitialized() const +{ + return !name_.isEmpty() && value_.isValid(); +} + +QT_END_NAMESPACE diff --git a/src/positioningquick/qdeclarativepluginparameter_p.h b/src/positioningquick/qdeclarativepluginparameter_p.h new file mode 100644 index 00000000..f5035aae --- /dev/null +++ b/src/positioningquick/qdeclarativepluginparameter_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPLUGINPARAMETER_P_H +#define QDECLARATIVEPLUGINPARAMETER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtPositioningQuick/private/qpositioningquickglobal_p.h> +#include <QtQml/qqml.h> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> + +QT_BEGIN_NAMESPACE + +class Q_POSITIONINGQUICK_PRIVATE_EXPORT QDeclarativePluginParameter : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged) + +public: + explicit QDeclarativePluginParameter(QObject *parent = 0); + ~QDeclarativePluginParameter(); + + void setName(const QString &name); + QString name() const; + + void setValue(const QVariant &value); + QVariant value() const; + + bool isInitialized() const; + +Q_SIGNALS: + void nameChanged(const QString &name); + void valueChanged(const QVariant &value); + void initialized(); + +private: + QString name_; + QVariant value_; +}; + + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativePluginParameter) + +#endif // QDECLARATIVEPLUGINPARAMETER_P_H diff --git a/src/positioningquick/qdeclarativeposition_p.h b/src/positioningquick/qdeclarativeposition_p.h index 141c37b7..c2a8d987 100644 --- a/src/positioningquick/qdeclarativeposition_p.h +++ b/src/positioningquick/qdeclarativeposition_p.h @@ -53,11 +53,11 @@ // We mean it. // +#include <QtPositioningQuick/private/qpositioningquickglobal_p.h> +#include <QtPositioning/QGeoPositionInfo> #include <QtCore/QObject> #include <QtCore/QDateTime> #include <QtQml/qqml.h> -#include <QtPositioningQuick/private/qpositioningquickglobal_p.h> -#include <QtPositioning/QGeoPositionInfo> QT_BEGIN_NAMESPACE diff --git a/src/positioningquick/qdeclarativepositionsource.cpp b/src/positioningquick/qdeclarativepositionsource.cpp index c9fd2c8e..cfbcc9da 100644 --- a/src/positioningquick/qdeclarativepositionsource.cpp +++ b/src/positioningquick/qdeclarativepositionsource.cpp @@ -43,7 +43,8 @@ #include <QtCore/QCoreApplication> #include <QtQml/qqmlinfo.h> #include <QtQml/qqml.h> -#include <qnmeapositioninfosource.h> +#include <QtPositioning/qnmeapositioninfosource.h> +#include <qdeclarativepluginparameter_p.h> #include <QFile> #include <QtNetwork/QTcpSocket> #include <QTimer> @@ -109,7 +110,7 @@ QT_BEGIN_NAMESPACE a PositionSource in your application to retrieve local data for users from a REST web service. - \sa {QtPositioning::Position}, {QGeoPositionInfoSource} + \sa {QtPositioning::Position}, {QGeoPositionInfoSource}, {PluginParameter} */ @@ -164,7 +165,7 @@ QString QDeclarativePositionSource::name() const if (m_positionSource) return m_positionSource->sourceName(); else - return QString(); + return m_providerName; } void QDeclarativePositionSource::setName(const QString &newName) @@ -172,15 +173,41 @@ void QDeclarativePositionSource::setName(const QString &newName) if (m_positionSource && m_positionSource->sourceName() == newName) return; + if (m_providerName == newName && m_providerName.isEmpty()) + return; // previously attached to a default source, now requesting the same. + const QString previousName = name(); + m_providerName = newName; + + if (!m_componentComplete || !m_parametersInitialized) { + if (previousName != name()) + emit nameChanged(); + return; + } + + tryAttach(newName, false); +} + +/*! + \internal +*/ +void QDeclarativePositionSource::tryAttach(const QString &newName, bool useFallback) +{ + const QString previousName = name(); + const bool sourceExisted = m_positionSource; + m_providerName = newName; + int previousUpdateInterval = updateInterval(); PositioningMethods previousPositioningMethods = supportedPositioningMethods(); PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods(); - if (newName.isEmpty()) - setSource(QGeoPositionInfoSource::createDefaultSource(this)); - else - setSource(QGeoPositionInfoSource::createSource(newName, this)); + if (newName.isEmpty()) { + setSource(QGeoPositionInfoSource::createDefaultSource(parameterMap(), this)); + } else { + setSource(QGeoPositionInfoSource::createSource(newName, parameterMap(), this)); + if (!m_positionSource && useFallback) + setSource(QGeoPositionInfoSource::createDefaultSource(parameterMap(), this)); + } if (m_positionSource) { connect(m_positionSource, SIGNAL(positionUpdated(QGeoPositionInfo)), @@ -194,7 +221,12 @@ void QDeclarativePositionSource::setName(const QString &newName) m_positionSource->setPreferredPositioningMethods( static_cast<QGeoPositionInfoSource::PositioningMethods>(int(m_preferredPositioningMethods))); - setPosition(m_positionSource->lastKnownPosition()); + const QGeoPositionInfo &lastKnown = m_positionSource->lastKnownPosition(); + if (lastKnown.isValid()) + setPosition(lastKnown); + } else if (m_active) { + m_active = false; + emit activeChanged(); } if (previousUpdateInterval != updateInterval()) @@ -208,9 +240,13 @@ void QDeclarativePositionSource::setName(const QString &newName) emit validityChanged(); - if (m_active) { - m_active = false; - emit activeChanged(); + if (m_active) { // implies m_positionSource + if (!sourceExisted) { + QTimer::singleShot(0, this, SLOT(start())); // delay ensures all properties have been set + } else { + m_active = false; + emit activeChanged(); + } } if (previousName != name()) @@ -232,9 +268,6 @@ bool QDeclarativePositionSource::isValid() const return (m_positionSource != 0); } -/*! - \internal -*/ void QDeclarativePositionSource::setNmeaSource(const QUrl &nmeaSource) { if (nmeaSource.scheme() == QLatin1String("socket")) { @@ -411,6 +444,24 @@ void QDeclarativePositionSource::updateTimeoutReceived() emit updateTimeout(); } +/*! + \internal +*/ +void QDeclarativePositionSource::onParameterInitialized() +{ + m_parametersInitialized = true; + for (QDeclarativePluginParameter *p: qAsConst(m_parameters)) { + if (!p->isInitialized()) { + m_parametersInitialized = false; + break; + } + } + + // If here, componentComplete has been called. + if (m_parametersInitialized) + tryAttach(m_providerName); +} + void QDeclarativePositionSource::setPosition(const QGeoPositionInfo &pi) { m_position.setPosition(pi); @@ -431,6 +482,30 @@ void QDeclarativePositionSource::setSource(QGeoPositionInfoSource *source) } } +bool QDeclarativePositionSource::parametersReady() +{ + for (const QDeclarativePluginParameter *p: qAsConst(m_parameters)) { + if (!p->isInitialized()) + return false; + } + return true; +} + +/*! + \internal +*/ +QVariantMap QDeclarativePositionSource::parameterMap() const +{ + QVariantMap map; + + for (int i = 0; i < m_parameters.size(); ++i) { + QDeclarativePluginParameter *parameter = m_parameters.at(i); + map.insert(parameter->name(), parameter->value()); + } + + return map; +} + /*! \internal */ @@ -717,47 +792,111 @@ QGeoPositionInfoSource *QDeclarativePositionSource::positionSource() const return m_positionSource; } -void QDeclarativePositionSource::componentComplete() +/*! + \qmlproperty list<PluginParameter> PositionSource::parameters + \default + + This property holds the list of plugin parameters. + + \since QtPositioning 5.14 +*/ +QQmlListProperty<QDeclarativePluginParameter> QDeclarativePositionSource::parameters() { - if (!m_positionSource) { - int previousUpdateInterval = updateInterval(); - PositioningMethods previousPositioningMethods = supportedPositioningMethods(); - PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods(); + return QQmlListProperty<QDeclarativePluginParameter>(this, + 0, + parameter_append, + parameter_count, + parameter_at, + parameter_clear); +} - setSource(QGeoPositionInfoSource::createDefaultSource(this)); - if (m_positionSource) { - connect(m_positionSource, SIGNAL(positionUpdated(QGeoPositionInfo)), - this, SLOT(positionUpdateReceived(QGeoPositionInfo))); - connect(m_positionSource, SIGNAL(error(QGeoPositionInfoSource::Error)), - this, SLOT(sourceErrorReceived(QGeoPositionInfoSource::Error))); - connect(m_positionSource, SIGNAL(updateTimeout()), - this, SLOT(updateTimeoutReceived())); +/*! + \internal +*/ +void QDeclarativePositionSource::parameter_append(QQmlListProperty<QDeclarativePluginParameter> *prop, QDeclarativePluginParameter *parameter) +{ + QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object); + p->m_parameters.append(parameter); +} - m_positionSource->setUpdateInterval(m_updateInterval); - m_positionSource->setPreferredPositioningMethods( - static_cast<QGeoPositionInfoSource::PositioningMethods>(int(m_preferredPositioningMethods))); +/*! + \internal +*/ +int QDeclarativePositionSource::parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop) +{ + return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters.count(); +} - setPosition(m_positionSource->lastKnownPosition()); +/*! + \internal +*/ +QDeclarativePluginParameter *QDeclarativePositionSource::parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, int index) +{ + return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters[index]; +} - if (m_active) - QTimer::singleShot(0, this, SLOT(start())); // delay ensures all properties have been set - } else if (m_active) { - m_active = false; - emit activeChanged(); +/*! + \internal +*/ +void QDeclarativePositionSource::parameter_clear(QQmlListProperty<QDeclarativePluginParameter> *prop) +{ + QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object); + p->m_parameters.clear(); +} + + +void QDeclarativePositionSource::componentComplete() +{ + m_componentComplete = true; + m_parametersInitialized = true; + for (QDeclarativePluginParameter *p: qAsConst(m_parameters)) { + if (!p->isInitialized()) { + m_parametersInitialized = false; + connect(p, &QDeclarativePluginParameter::initialized, + this, &QDeclarativePositionSource::onParameterInitialized); } + } - if (previousUpdateInterval != updateInterval()) - emit updateIntervalChanged(); + if (m_parametersInitialized) + tryAttach(m_providerName); +} - if (previousPreferredPositioningMethods != preferredPositioningMethods()) - emit preferredPositioningMethodsChanged(); +/*! + \qmlmethod bool QtLocation::PositionSource::setBackendProperty(string name, Variant value) - if (previousPositioningMethods != supportedPositioningMethods()) - emit supportedPositioningMethodsChanged(); + Sets the backend-specific property named \a name to \a value. + Returns true on success, false otherwise, including if called on an uninitialized PositionSource. + Supported backend-specific properties are listed and described in + \l {Qt Positioning plugins#Default plugins}. - emit validityChanged(); - emit nameChanged(); - } + \since Qt Positioning 5.14 + + \sa backendProperty, QGeoPositionInfoSource::setBackendProperty +*/ +bool QDeclarativePositionSource::setBackendProperty(const QString &name, QVariant value) +{ + if (m_positionSource) + return m_positionSource->setBackendProperty(name, value); + return false; +} + +/*! + \qmlmethod Variant QtLocation::PositionSource::backendProperty(string name) + + Returns the value of the backend-specific property named \a name, if present. + Otherwise, including if called on an uninitialized PositionSource, the return value will be invalid. + Supported backend-specific properties are listed and described in + \l {Qt Positioning plugins#Default plugins}. + + \since Qt Positioning 5.14 + + \sa backendProperty, QGeoPositionInfoSource::setBackendProperty +*/ +QVariant QDeclarativePositionSource::backendProperty(const QString &name) const +{ + if (m_positionSource) + return m_positionSource->backendProperty(name); + return QVariant(); } /*! diff --git a/src/positioningquick/qdeclarativepositionsource_p.h b/src/positioningquick/qdeclarativepositionsource_p.h index 39bcd899..dff0006c 100644 --- a/src/positioningquick/qdeclarativepositionsource_p.h +++ b/src/positioningquick/qdeclarativepositionsource_p.h @@ -51,13 +51,13 @@ // We mean it. // -#include "qdeclarativeposition_p.h" - +#include <QtPositioningQuick/private/qpositioningquickglobal_p.h> +#include <QtPositioningQuick/private/qdeclarativeposition_p.h> #include <QtCore/QObject> #include <QtNetwork/QAbstractSocket> #include <QtQml/QQmlParserStatus> -#include <QtPositioningQuick/private/qpositioningquickglobal_p.h> -#include <QtPositioning/QGeoPositionInfoSource> +#include <QtPositioning/qgeopositioninfosource.h> +#include <QtPositioningQuick/private/qdeclarativepluginparameter_p.h> QT_BEGIN_NAMESPACE @@ -77,8 +77,10 @@ class Q_POSITIONINGQUICK_PRIVATE_EXPORT QDeclarativePositionSource : public QObj Q_PROPERTY(PositioningMethods preferredPositioningMethods READ preferredPositioningMethods WRITE setPreferredPositioningMethods NOTIFY preferredPositioningMethodsChanged) Q_PROPERTY(SourceError sourceError READ sourceError NOTIFY sourceErrorChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QQmlListProperty<QDeclarativePluginParameter> parameters READ parameters REVISION 14) Q_ENUMS(PositioningMethod) + Q_CLASSINFO("DefaultProperty", "parameters") Q_INTERFACES(QQmlParserStatus) public: @@ -122,11 +124,16 @@ public: PositioningMethods preferredPositioningMethods() const; SourceError sourceError() const; QGeoPositionInfoSource *positionSource() const; + QQmlListProperty<QDeclarativePluginParameter> parameters(); + QVariantMap parameterMap() const; // Virtuals from QQmlParserStatus void classBegin() { } void componentComplete(); + Q_INVOKABLE bool setBackendProperty(const QString &name, QVariant value); + Q_INVOKABLE QVariant backendProperty(const QString &name) const; + public Q_SLOTS: void update(); // TODO Qt 6 change to void update(int) void start(); @@ -150,10 +157,18 @@ private Q_SLOTS: void socketConnected(); void socketError(QAbstractSocket::SocketError error); void updateTimeoutReceived(); + void onParameterInitialized(); private: void setPosition(const QGeoPositionInfo &pi); void setSource(QGeoPositionInfoSource *source); + bool parametersReady(); + void tryAttach(const QString &name, bool useFallback = true); + + static void parameter_append(QQmlListProperty<QDeclarativePluginParameter> *prop, QDeclarativePluginParameter *mapObject); + static int parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop); + static QDeclarativePluginParameter *parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, int index); + static void parameter_clear(QQmlListProperty<QDeclarativePluginParameter> *prop); QGeoPositionInfoSource *m_positionSource; QDeclarativePosition m_position; @@ -162,10 +177,14 @@ private: QTcpSocket *m_nmeaSocket; QString m_nmeaFileName; QUrl m_nmeaSource; + QString m_providerName; bool m_active; bool m_singleUpdate; int m_updateInterval; SourceError m_sourceError; + QList<QDeclarativePluginParameter *> m_parameters; + bool m_componentComplete = false; + bool m_parametersInitialized = false; }; QT_END_NAMESPACE diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 745e264b..05559d12 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -86,6 +86,7 @@ SUBDIRS += \ !android: SUBDIRS += \ positionplugin \ + positionpluginV1 \ positionplugintest \ qgeoareamonitor \ qgeopositioninfosource \ diff --git a/tests/auto/declarative_core/tst_plugin.qml b/tests/auto/declarative_core/tst_plugin.qml index 7b880f1d..23c1ff9f 100644 --- a/tests/auto/declarative_core/tst_plugin.qml +++ b/tests/auto/declarative_core/tst_plugin.qml @@ -54,6 +54,7 @@ Item { mapping: Plugin.OfflineMappingFeature; geocoding: Plugin.OfflineGeocodingFeature; places: Plugin.AnyPlacesFeatures; + navigation: Plugin.AnyNavigationFeatures; } } @@ -120,6 +121,7 @@ Item { verify(requiredPlugin.supportsMapping(requiredPlugin.required.mapping)) verify(requiredPlugin.supportsGeocoding(requiredPlugin.required.geocoding)) verify(requiredPlugin.supportsPlaces(requiredPlugin.required.places)) + verify(requiredPlugin.supportsNavigation(requiredPlugin.required.navigation)) } function test_placesFeatures() { diff --git a/tests/auto/declarative_core/tst_positionsource.qml b/tests/auto/declarative_core/tst_positionsource.qml index a663f3ab..7b787a0c 100644 --- a/tests/auto/declarative_core/tst_positionsource.qml +++ b/tests/auto/declarative_core/tst_positionsource.qml @@ -28,7 +28,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtPositioning 5.2 +import QtPositioning 5.14 TestCase { id: testCase @@ -106,6 +106,26 @@ TestCase { SignalSpy { id: directionValidSpy; target: testingSource.position; signalName: "directionValidChanged" } SignalSpy { id: directionSpy; target: testingSource.position; signalName: "directionChanged" } + PositionSource { + id: testingSourceWParams + name: "test.source" + updateInterval: 1000 + PluginParameter { + id: altitudeParameter + name: "test.source.altitude" + value: 42.42 + } + } + + SignalSpy { id: updateSpyWParams; target: testingSourceWParams; signalName: "positionChanged" } + SignalSpy { id: directionValidSpyWParams; target: testingSourceWParams.position; signalName: "directionValidChanged" } + SignalSpy { id: directionSpyWParams; target: testingSourceWParams.position; signalName: "directionChanged" } + + PositionSource { id: testingSourceV1; name: "test.source.v1"; updateInterval: 1000 } + SignalSpy { id: updateSpyV1; target: testingSourceV1; signalName: "positionChanged" } + SignalSpy { id: directionValidSpyV1; target: testingSourceV1.position; signalName: "directionValidChanged" } + SignalSpy { id: directionSpyV1; target: testingSourceV1.position; signalName: "directionChanged" } + function test_updateInterval() { testingSource.updateInterval = 1000; compare(testingSource.updateInterval, 1000); @@ -125,40 +145,83 @@ TestCase { } function test_updates() { - updateSpy.clear(); - - compare(directionValidSpy.count, 0) - compare(directionSpy.count, 0) - - testingSource.active = true; - - tryCompare(updateSpy, "count", 1, 1500); - compare(testingSource.position.coordinate.longitude, 0.1); - compare(testingSource.position.coordinate.latitude, 0.1); - compare(directionValidSpy.count, 1) - compare(directionSpy.count, 1) - fuzzyCompare(testingSource.position.direction, 45, 0.1) - verify(!testingSource.position.speedValid) - verify(isNaN(testingSource.position.speed)) - - tryCompare(updateSpy, "count", 2, 1500); - compare(testingSource.position.coordinate.longitude, 0.2); - compare(testingSource.position.coordinate.latitude, 0.2); - compare(directionValidSpy.count, 1) - compare(directionSpy.count, 2) - fuzzyCompare(testingSource.position.direction, 45, 0.1) - verify(testingSource.position.speedValid) - verify(testingSource.position.speed > 10000) - - testingSource.active = false; + updateSpyV1.clear(); + + compare(directionValidSpyV1.count, 0) + compare(directionSpyV1.count, 0) + + testingSourceV1.active = true; + + tryCompare(updateSpyV1, "count", 1, 1500); + compare(testingSourceV1.position.coordinate.longitude, 0.1); + compare(testingSourceV1.position.coordinate.latitude, 0.1); + compare(directionValidSpyV1.count, 1) + compare(directionSpyV1.count, 1) + fuzzyCompare(testingSourceV1.position.direction, 45, 0.1) + verify(!testingSourceV1.position.speedValid) + verify(isNaN(testingSourceV1.position.speed)) + + tryCompare(updateSpyV1, "count", 2, 1500); + compare(testingSourceV1.position.coordinate.longitude, 0.2); + compare(testingSourceV1.position.coordinate.latitude, 0.2); + compare(directionValidSpyV1.count, 1) + compare(directionSpyV1.count, 2) + fuzzyCompare(testingSourceV1.position.direction, 45, 0.1) + verify(testingSourceV1.position.speedValid) + verify(testingSourceV1.position.speed > 10000) + + testingSourceV1.active = false; + wait(2500); + compare(updateSpyV1.count, 2); + compare(testingSourceV1.position.coordinate.longitude, 0.2); + compare(testingSourceV1.position.coordinate.latitude, 0.2); + compare(directionValidSpyV1.count, 1) + compare(directionSpyV1.count, 2) + fuzzyCompare(testingSourceV1.position.direction, 45, 0.1) + verify(testingSourceV1.position.speedValid) + verify(testingSourceV1.position.speed > 10000) + } + + function test_updates_w_params() { + updateSpyWParams.clear(); + + compare(directionValidSpyWParams.count, 0) + compare(directionSpyWParams.count, 0) + compare(testingSourceWParams.backendProperty("altitude"), altitudeParameter.value) + testingSourceWParams.active = true; + + tryCompare(updateSpyWParams, "count", 1, 1500); + compare(testingSourceWParams.position.coordinate.longitude, 0.1); + compare(testingSourceWParams.position.coordinate.latitude, 0.1); + compare(testingSourceWParams.position.coordinate.altitude, altitudeParameter.value); + compare(directionValidSpyWParams.count, 1) + compare(directionSpyWParams.count, 1) + fuzzyCompare(testingSourceWParams.position.direction, 45, 0.1) + verify(!testingSourceWParams.position.speedValid) + verify(isNaN(testingSourceWParams.position.speed)) + testingSourceWParams.setBackendProperty("altitude", 24.24) + + tryCompare(updateSpyWParams, "count", 2, 1500); + compare(testingSourceWParams.position.coordinate.longitude, 0.2); + compare(testingSourceWParams.position.coordinate.latitude, 0.2); + compare(testingSourceWParams.position.coordinate.altitude, 24.24); + compare(directionValidSpyWParams.count, 1) + compare(directionSpyWParams.count, 2) + fuzzyCompare(testingSourceWParams.position.direction, 45, 0.1) + verify(testingSourceWParams.position.speedValid) + verify(testingSourceWParams.position.speed > 10000) + compare(testingSourceWParams.backendProperty("altitude"), 24.24) + + testingSourceWParams.active = false; wait(2500); - compare(updateSpy.count, 2); - compare(testingSource.position.coordinate.longitude, 0.2); - compare(testingSource.position.coordinate.latitude, 0.2); - compare(directionValidSpy.count, 1) - compare(directionSpy.count, 2) - fuzzyCompare(testingSource.position.direction, 45, 0.1) - verify(testingSource.position.speedValid) - verify(testingSource.position.speed > 10000) + compare(updateSpyWParams.count, 2); + compare(testingSourceWParams.position.coordinate.longitude, 0.2); + compare(testingSourceWParams.position.coordinate.latitude, 0.2); + compare(testingSourceWParams.position.coordinate.altitude, 24.24); + compare(directionValidSpyWParams.count, 1) + compare(directionSpyWParams.count, 2) + fuzzyCompare(testingSourceWParams.position.direction, 45, 0.1) + verify(testingSourceWParams.position.speedValid) + verify(testingSourceWParams.position.speed > 10000) } } diff --git a/tests/auto/declarative_ui/BLACKLIST b/tests/auto/declarative_ui/BLACKLIST deleted file mode 100644 index 4abe024c..00000000 --- a/tests/auto/declarative_ui/BLACKLIST +++ /dev/null @@ -1,20 +0,0 @@ -[MapFlick::test_disable_onFlickStarted_with_disabled] -windows - -[MapFlick::test_flick_down] -windows - -[MapFlick::test_flick_up] -windows - -[MapFlick::test_flick_down_with_filtering] -windows - -[MapFlick::test_disable_onFlickStarted_with_nogesture] -windows - -[MapFlick::test_flick_diagonal] -windows - -[MapFlick::test_flick_up_with_filtering] -windows diff --git a/tests/auto/geotestplugin/geotestplugin.json b/tests/auto/geotestplugin/geotestplugin.json index 52721715..f6218b67 100644 --- a/tests/auto/geotestplugin/geotestplugin.json +++ b/tests/auto/geotestplugin/geotestplugin.json @@ -14,6 +14,7 @@ "OfflinePlacesFeature", "SavePlaceFeature", "SaveCategoryFeature", - "SearchSuggestionsFeature" + "SearchSuggestionsFeature", + "OfflineNavigationFeature" ] } diff --git a/tests/auto/geotestplugin/qgeoserviceproviderplugin_test.h b/tests/auto/geotestplugin/qgeoserviceproviderplugin_test.h index c606fdb0..ac195d69 100644 --- a/tests/auto/geotestplugin/qgeoserviceproviderplugin_test.h +++ b/tests/auto/geotestplugin/qgeoserviceproviderplugin_test.h @@ -34,10 +34,10 @@ QT_USE_NAMESPACE -class QGeoServiceProviderFactoryTest: public QObject, public QGeoServiceProviderFactory +class QGeoServiceProviderFactoryTest: public QObject, public QGeoServiceProviderFactoryV2 { Q_OBJECT - Q_INTERFACES(QGeoServiceProviderFactory) + Q_INTERFACES(QGeoServiceProviderFactoryV2) Q_PLUGIN_METADATA(IID "org.qt-project.qt.geoservice.serviceproviderfactory/5.0" FILE "geotestplugin.json") diff --git a/tests/auto/geotestplugin/qplacemanagerengine_test.h b/tests/auto/geotestplugin/qplacemanagerengine_test.h index 7245ccf1..0c707b65 100644 --- a/tests/auto/geotestplugin/qplacemanagerengine_test.h +++ b/tests/auto/geotestplugin/qplacemanagerengine_test.h @@ -474,9 +474,12 @@ public: results.append(r); } } else if (!query.categories().isEmpty()) { - QSet<QPlaceCategory> categories = query.categories().toSet(); - foreach (const QPlace &place, m_places) { - if (place.categories().toSet().intersect(categories).isEmpty()) + const auto &categoryList = query.categories(); + const QSet<QPlaceCategory> categories(categoryList.cbegin(), categoryList.cend()); + for (const QPlace &place : qAsConst(m_places)) { + const auto &placeCategoryList = place.categories(); + const QSet<QPlaceCategory> placeCategories(placeCategoryList.cbegin(), placeCategoryList.cend()); + if (!placeCategories.intersects(categories)) continue; QPlaceResult r; @@ -571,11 +574,8 @@ public: m_categories.insert(category.categoryId(), category); QStringList children = m_childCategories.value(parentId); - QMutableHashIterator<QString, QStringList> i(m_childCategories); - while (i.hasNext()) { - i.next(); - i.value().removeAll(category.categoryId()); - } + for (QStringList &c : m_childCategories) + c.removeAll(category.categoryId()); if (!children.contains(category.categoryId())) { children.append(category.categoryId()); @@ -611,11 +611,8 @@ public: } else { m_categories.remove(categoryId); - QMutableHashIterator<QString, QStringList> i(m_childCategories); - while (i.hasNext()) { - i.next(); - i.value().removeAll(categoryId); - } + for (auto &c : m_childCategories) + c.removeAll(categoryId); } QMetaObject::invokeMethod(reply, "emitFinished", Qt::QueuedConnection); @@ -634,9 +631,7 @@ public: QString parentCategoryId(const QString &categoryId) const override { - QHashIterator<QString, QStringList> i(m_childCategories); - while (i.hasNext()) { - i.next(); + for (auto i = m_childCategories.cbegin(), end = m_childCategories.cend(); i != end; ++i) { if (i.value().contains(categoryId)) return i.key(); } diff --git a/tests/auto/nokia_services/places_semiauto/tst_places.cpp b/tests/auto/nokia_services/places_semiauto/tst_places.cpp index 2f68ab44..c198c616 100644 --- a/tests/auto/nokia_services/places_semiauto/tst_places.cpp +++ b/tests/auto/nokia_services/places_semiauto/tst_places.cpp @@ -610,9 +610,7 @@ void tst_QPlaceManagerNokia::content() QVERIFY(results.count() > 0); - QMapIterator<int, QPlaceContent> iter(results); - while (iter.hasNext()) { - iter.next(); + for (auto iter = results.cbegin(), end = results.cend(); iter != end; ++iter) { switch (type) { case (QPlaceContent::ImageType): { QPlaceImage image = iter.value(); diff --git a/tests/auto/positionplugin/plugin.cpp b/tests/auto/positionplugin/plugin.cpp index a15a89a5..9d5c7dd5 100644 --- a/tests/auto/positionplugin/plugin.cpp +++ b/tests/auto/positionplugin/plugin.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include <QtPositioning/qgeopositioninfosource.h> +#include <QtPositioning/private/qgeopositioninfosource_p.h> #include <QtPositioning/qgeopositioninfosourcefactory.h> #include <QObject> #include <QtPlugin> @@ -39,7 +40,7 @@ class DummySource : public QGeoPositionInfoSource Q_OBJECT public: - DummySource(QObject *parent=0); + DummySource(const QVariantMap ¶meters, QObject *parent=0); ~DummySource(); void startUpdates(); @@ -65,13 +66,42 @@ private slots: void doTimeout(); }; -DummySource::DummySource(QObject *parent) : - QGeoPositionInfoSource(parent), +class DummySourcePrivate : public QGeoPositionInfoSourcePrivate +{ +public: + bool setBackendProperty(const QString &name, QVariant value) override + { + if (name == QStringLiteral("altitude")) { + m_altitude = value.toReal(); + return true; + } + return false; + } + QVariant backendProperty(const QString &name) const override + { + if (name == QStringLiteral("altitude")) + return m_altitude; + return QVariant(); + } + + qreal m_altitude = 0.0; +}; + +DummySource::DummySource(const QVariantMap ¶meters, QObject *parent) : + QGeoPositionInfoSource(*new DummySourcePrivate, parent), timer(new QTimer(this)), timeoutTimer(new QTimer(this)), singleTimer(new QTimer(this)), lastPosition(QGeoCoordinate(0,0), QDateTime::currentDateTime()) { + DummySourcePrivate *dd = static_cast<DummySourcePrivate *>(QGeoPositionInfoSourcePrivate::get(*this)); + if (parameters.contains(QStringLiteral("test.source.altitude"))) { + const qreal alti = parameters.value(QStringLiteral("test.source.altitude")).toReal(); + dd->m_altitude = alti; + QGeoCoordinate crd = lastPosition.coordinate(); + crd.setAltitude(alti); + lastPosition.setCoordinate(crd); + } timer->setInterval(1000); connect(timer, SIGNAL(timeout()), this, SLOT(updatePosition())); @@ -151,13 +181,15 @@ DummySource::~DummySource() void DummySource::updatePosition() { + DummySourcePrivate *dd = static_cast<DummySourcePrivate *>(QGeoPositionInfoSourcePrivate::get(*this)); timeoutTimer->stop(); singleTimer->stop(); const QDateTime now = QDateTime::currentDateTime(); QGeoCoordinate coord(lastPosition.coordinate().latitude() + 0.1, - lastPosition.coordinate().longitude() + 0.1); + lastPosition.coordinate().longitude() + 0.1, + dd->m_altitude); QGeoPositionInfo info(coord, now); info.setAttribute(QGeoPositionInfo::Direction, lastPosition.coordinate().azimuthTo(coord)); @@ -179,35 +211,55 @@ void DummySource::doTimeout() } -class QGeoPositionInfoSourceFactoryTest : public QObject, public QGeoPositionInfoSourceFactory +class QGeoPositionInfoSourceFactoryTest : public QObject, public QGeoPositionInfoSourceFactoryV2 { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.qt.position.sourcefactory/5.0" FILE "plugin.json") - Q_INTERFACES(QGeoPositionInfoSourceFactory) + Q_INTERFACES(QGeoPositionInfoSourceFactoryV2) public: QGeoPositionInfoSource *positionInfoSource(QObject *parent); QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); QGeoAreaMonitorSource *areaMonitor(QObject *parent); + + QGeoPositionInfoSource *positionInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters); + QGeoSatelliteInfoSource *satelliteInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters); + QGeoAreaMonitorSource *areaMonitorWithParameters(QObject *parent, const QVariantMap ¶meters); }; QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryTest::positionInfoSource(QObject *parent) { - return new DummySource(parent); + return new DummySource(QVariantMap(), parent); } QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryTest::satelliteInfoSource(QObject *parent) { - Q_UNUSED(parent); - // not implemented - return 0; + return satelliteInfoSourceWithParameters(parent, QVariantMap()); } QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryTest::areaMonitor(QObject* parent) { + return areaMonitorWithParameters(parent, QVariantMap()); +} + +QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryTest::positionInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters) +{ + return new DummySource(parameters, parent); +} + +QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryTest::satelliteInfoSourceWithParameters(QObject *parent, const QVariantMap ¶meters) +{ + Q_UNUSED(parent); + Q_UNUSED(parameters) + return nullptr; +} + +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryTest::areaMonitorWithParameters(QObject *parent, const QVariantMap ¶meters) +{ Q_UNUSED(parent); - return 0; + Q_UNUSED(parameters) + return nullptr; } #include "plugin.moc" diff --git a/tests/auto/positionplugin/plugin.json b/tests/auto/positionplugin/plugin.json index 68acaded..a38d2a5a 100644 --- a/tests/auto/positionplugin/plugin.json +++ b/tests/auto/positionplugin/plugin.json @@ -4,6 +4,6 @@ "Position": true, "Satellite": false, "Monitor": false, - "Priority": 0, + "Priority": 1, "Testable": true } diff --git a/tests/auto/positionplugin/positionplugin.pro b/tests/auto/positionplugin/positionplugin.pro index dd04e7fb..84d08ac0 100644 --- a/tests/auto/positionplugin/positionplugin.pro +++ b/tests/auto/positionplugin/positionplugin.pro @@ -1,8 +1,8 @@ TARGET = qtposition_testplugin -QT += positioning +QT += positioning-private PLUGIN_TYPE = position -PLUGIN_CLASS_NAME = TestPositionPlugin +PLUGIN_CLASS_NAME = QGeoPositionInfoSourceFactoryTest PLUGIN_EXTENDS = - load(qt_plugin) diff --git a/tests/auto/positionpluginV1/plugin.cpp b/tests/auto/positionpluginV1/plugin.cpp new file mode 100644 index 00000000..bf8b8234 --- /dev/null +++ b/tests/auto/positionpluginV1/plugin.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtPositioning/qgeopositioninfosource.h> +#include <QtPositioning/qgeopositioninfosourcefactory.h> +#include <QObject> +#include <QtPlugin> +#include <QTimer> + +QT_USE_NAMESPACE + +class DummySource : public QGeoPositionInfoSource +{ + Q_OBJECT + +public: + DummySource(QObject *parent = nullptr); + ~DummySource(); + + void startUpdates(); + void stopUpdates(); + void requestUpdate(int timeout=5000); + + QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const; + PositioningMethods supportedPositioningMethods() const; + + void setUpdateInterval(int msec); + int minimumUpdateInterval() const; + Error error() const; + +private: + QTimer *timer; + QTimer *timeoutTimer; + QTimer *singleTimer; + QGeoPositionInfo lastPosition; + QDateTime lastUpdateTime; + +private slots: + void updatePosition(); + void doTimeout(); +}; + +DummySource::DummySource(QObject *parent) : + QGeoPositionInfoSource(parent), + timer(new QTimer(this)), + timeoutTimer(new QTimer(this)), + singleTimer(new QTimer(this)), + lastPosition(QGeoCoordinate(0,0), QDateTime::currentDateTime()) +{ + timer->setInterval(1000); + connect(timer, SIGNAL(timeout()), + this, SLOT(updatePosition())); + connect(singleTimer, SIGNAL(timeout()), + this, SLOT(updatePosition())); + connect(timeoutTimer, SIGNAL(timeout()), + this, SLOT(doTimeout())); +} + +QGeoPositionInfoSource::Error DummySource::error() const +{ + return QGeoPositionInfoSource::NoError; +} + + +void DummySource::setUpdateInterval(int msec) +{ + if (msec == 0) { + timer->setInterval(1000); + } else if (msec < 1000) { + msec = 1000; + timer->setInterval(msec); + } else { + timer->setInterval(msec); + } + + QGeoPositionInfoSource::setUpdateInterval(msec); +} + +int DummySource::minimumUpdateInterval() const +{ + return 1000; +} + +QGeoPositionInfo DummySource::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const +{ + Q_UNUSED(fromSatellitePositioningMethodsOnly); + return lastPosition; +} + +QGeoPositionInfoSource::PositioningMethods DummySource::supportedPositioningMethods() const +{ + return QGeoPositionInfoSource::AllPositioningMethods; +} + +void DummySource::startUpdates() +{ + timer->start(); +} + +void DummySource::stopUpdates() +{ + timer->stop(); +} + +void DummySource::requestUpdate(int timeout) +{ + if (timeout == 0) + timeout = 5000; + if (timeout < 0) + timeout = 0; + + timeoutTimer->setInterval(timeout); + timeoutTimer->start(); + + if (timer->isActive()) { + timer->stop(); + timer->start(); + } + + singleTimer->setInterval(1000); + singleTimer->start(); +} + +DummySource::~DummySource() +{} + +void DummySource::updatePosition() +{ + timeoutTimer->stop(); + singleTimer->stop(); + + const QDateTime now = QDateTime::currentDateTime(); + + QGeoCoordinate coord(lastPosition.coordinate().latitude() + 0.1, + lastPosition.coordinate().longitude() + 0.1); + + QGeoPositionInfo info(coord, now); + info.setAttribute(QGeoPositionInfo::Direction, lastPosition.coordinate().azimuthTo(coord)); + if (lastUpdateTime.isValid()) { + double speed = lastPosition.coordinate().distanceTo(coord) / lastUpdateTime.msecsTo(now); + info.setAttribute(QGeoPositionInfo::GroundSpeed, 1000 * speed); + } + + lastUpdateTime = now; + lastPosition = info; + emit positionUpdated(info); +} + +void DummySource::doTimeout() +{ + timeoutTimer->stop(); + singleTimer->stop(); + emit updateTimeout(); +} + + +class QGeoPositionInfoSourceFactoryTestV1 : 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); + QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); + QGeoAreaMonitorSource *areaMonitor(QObject *parent); +}; + +QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryTestV1::positionInfoSource(QObject *parent) +{ + return new DummySource(parent); +} + +QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryTestV1::satelliteInfoSource(QObject *parent) +{ + Q_UNUSED(parent); + return nullptr; +} + +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryTestV1::areaMonitor(QObject* parent) +{ + Q_UNUSED(parent); + return nullptr; +} + +#include "plugin.moc" diff --git a/tests/auto/positionpluginV1/plugin.json b/tests/auto/positionpluginV1/plugin.json new file mode 100644 index 00000000..9acf27e7 --- /dev/null +++ b/tests/auto/positionpluginV1/plugin.json @@ -0,0 +1,9 @@ +{ + "Keys": ["test.source.v1"], + "Provider": "test.source.v1", + "Position": true, + "Satellite": false, + "Monitor": false, + "Priority": 0, + "Testable": true +} diff --git a/tests/auto/positionpluginV1/positionpluginV1.pro b/tests/auto/positionpluginV1/positionpluginV1.pro new file mode 100644 index 00000000..925a7e29 --- /dev/null +++ b/tests/auto/positionpluginV1/positionpluginV1.pro @@ -0,0 +1,12 @@ +TARGET = qtposition_testpluginv1 +QT += positioning + +PLUGIN_TYPE = position +PLUGIN_CLASS_NAME = QGeoPositionInfoSourceFactoryTestV1 +PLUGIN_EXTENDS = - +load(qt_plugin) + +SOURCES += plugin.cpp + +OTHER_FILES += \ + plugin.json diff --git a/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp b/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp index 5da6b4d4..c7189278 100644 --- a/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp +++ b/tests/auto/qgeotiledmap/tst_qgeotiledmap.cpp @@ -145,7 +145,7 @@ void tst_QGeoTiledMap::fetchTiles() m_tilesCounter->m_tiles.clear(); m_map->setCameraData(camera); waitForFetch(visibleCount); - QSet<QGeoTileSpec> visible = m_tilesCounter->m_tiles; + const QSet<QGeoTileSpec> visible = m_tilesCounter->m_tiles; m_map->clearData(); m_tilesCounter->m_tiles.clear(); m_map->prefetchData(); @@ -164,9 +164,8 @@ void tst_QGeoTiledMap::fetchTiles() QVERIFY2(visibleCount == visible.size(), "visible count incorrect"); QVERIFY2(prefetchCount == prefetched.size(), "prefetch count incorrect"); - QSetIterator<QGeoTileSpec> i(visible); - while (i.hasNext()) - QVERIFY2(prefetched.contains(i.next()),"visible tile missing from prefetched tiles"); + for (const QGeoTileSpec &tile : visible) + QVERIFY2(prefetched.contains(tile),"visible tile missing from prefetched tiles"); //for zoomLevels wihtout fractions more tiles are fetched for current zoomlevel due to ViewExpansion if (qCeil(zoomLevel) != zoomLevel && style == QGeoTiledMap::PrefetchNeighbourLayer && nearestNeighbourLayer < zoomLevel) diff --git a/tests/auto/qnmeapositioninfosource/tst_qnmeapositioninfosource.cpp b/tests/auto/qnmeapositioninfosource/tst_qnmeapositioninfosource.cpp index 37fe7abc..51f996fb 100644 --- a/tests/auto/qnmeapositioninfosource/tst_qnmeapositioninfosource.cpp +++ b/tests/auto/qnmeapositioninfosource/tst_qnmeapositioninfosource.cpp @@ -32,6 +32,8 @@ #include "tst_qnmeapositioninfosource.h" +#include <QtCore/QDateTime> +#include <QtCore/QElapsedTimer> #include <QtCore/QtNumeric> #ifdef Q_OS_WIN @@ -264,7 +266,7 @@ void tst_QNmeaPositionInfoSource::startUpdates_withTimeout() proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addMSecs(2200)).toLatin1()); proxy->feedBytes(QLocationTestUtils::createRmcSentence(dt.addSecs(9)).toLatin1()); - QTime t; + QElapsedTimer t; t.start(); for (int j = 1; j < 4; ++j) { diff --git a/tests/auto/utils/qlocationtestutils.cpp b/tests/auto/utils/qlocationtestutils.cpp index d6e77855..df595daa 100644 --- a/tests/auto/utils/qlocationtestutils.cpp +++ b/tests/auto/utils/qlocationtestutils.cpp @@ -46,8 +46,7 @@ QString QLocationTestUtils::addNmeaChecksumAndBreaks(const QString &sentence) int result = 0; for (int i=1; i<sentence.length()-1; i++) result ^= sentence[i].toLatin1(); - QString sum; - sum.sprintf("%02x", result); + const QString sum = QString::asprintf("%02x", result); return sentence + sum + "\r\n"; } |