diff options
29 files changed, 855 insertions, 119 deletions
diff --git a/dist/changes-5.13.0 b/dist/changes-5.13.0 new file mode 100644 index 00000000..564a37ec --- /dev/null +++ b/dist/changes-5.13.0 @@ -0,0 +1,46 @@ +Qt 5.13 introduces many new features and improvements as well as bugfixes +over the 5.12.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* QtLocation * +**************************************************************************** + + - Added a GeoJSON parser which can be used to annotate maps with tracks, + polygonal boundaries, etc. + - GeoJSON returned in Nominatim queries is now converted into the corresponding + geoshapes using QGeoJson. + - GeoJSON returned in Nominatim queries is now converted into the corresponding + geoshapes using QGeoJson. + - Introduced Qt.labs.location QtLocationLabs singleton type, offering tech-preview + map related API. + - Added departure time attribute to route queries. + - Introduced QGeoMapObject::geoShape property. + - Additional navigation information now exposed via Navigator. + - Fixed crash when removing items from MapboxGL maps. + - Renamed MapIconObject.size to MapIconObject.iconSize. + - Added Map.fitViewportToGeoShape(shape, margins). + - Added Navigator currentRouteLeg property. + - Introduced extendedAttributes property to Geo Location types. + - Introduced extendedAttributes property to Geo Routes types. + +**************************************************************************** +* QtPositioning * +**************************************************************************** + +- Added holes support to QGeoPolygon, currently rendered only when using the + MapboxGL backend. + 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/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/declarativeplaces/qdeclarativesearchresultmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp index 4cfd26dd..c620b9f7 100644 --- a/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp +++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp @@ -973,16 +973,15 @@ QList<QPlaceSearchResult> QDeclarativeSearchResultModel::resultsFromPages() cons void QDeclarativeSearchResultModel::removePageRow(int row) { - QMapIterator<int, QList<QPlaceSearchResult>> i(m_pages); + QMutableMapIterator<int, QList<QPlaceSearchResult>> i(m_pages); int scanned = 0; while (i.hasNext()) { i.next(); - QList<QPlaceSearchResult> page = i.value(); + 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/qtlocation.qdocconf b/src/location/doc/qtlocation.qdocconf index 0c43bfa7..0ffbe4d6 100644 --- a/src/location/doc/qtlocation.qdocconf +++ b/src/location/doc/qtlocation.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qtlocation.qdocconf) project = QtLocation description = Qt Location Reference Documentation diff --git a/src/location/labs/qdeclarativenavigator.cpp b/src/location/labs/qdeclarativenavigator.cpp index 89b5abef..ae273774 100644 --- a/src/location/labs/qdeclarativenavigator.cpp +++ b/src/location/labs/qdeclarativenavigator.cpp @@ -352,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 @@ -510,6 +516,8 @@ bool QDeclarativeNavigator::ensureEngine() &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; @@ -534,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(); @@ -704,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) @@ -720,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 3c168c70..24ff798f 100644 --- a/src/location/labs/qdeclarativenavigator_p.h +++ b/src/location/labs/qdeclarativenavigator_p.h @@ -149,6 +149,8 @@ public: NavigationError error() const; QString errorString() const; + Q_INVOKABLE void recalculateRoutes(); + signals: void navigatorReadyChanged(bool ready); void trackPositionSourceChanged(bool trackPositionSource); diff --git a/src/location/labs/qdeclarativenavigator_p_p.h b/src/location/labs/qdeclarativenavigator_p_p.h index 04b8b1ef..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; }; 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 9089316f..8d2c9a99 100644 --- a/src/location/maps/qnavigationmanagerengine_p.h +++ b/src/location/maps/qnavigationmanagerengine_p.h @@ -98,10 +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; @@ -120,6 +122,7 @@ signals: void nextManeuverIconChanged(); void progressInformationChanged(); void isOnRouteChanged(); + void alternativeRoutesChanged(); private: QScopedPointer<QAbstractNavigatorPrivate> d; diff --git a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp index 58092ea3..043f7682 100644 --- a/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp +++ b/src/plugins/position/serialnmea/qgeopositioninfosourcefactory_serialnmea.cpp @@ -49,18 +49,22 @@ Q_LOGGING_CATEGORY(lcSerial, "qt.positioning.serialnmea") class NmeaSource : public QNmeaPositionInfoSource { public: - NmeaSource(QObject *parent); + NmeaSource(QObject *parent, const QVariantMap ¶meters); bool isValid() const { return !m_port.isNull(); } private: QScopedPointer<QSerialPort> m_port; }; -NmeaSource::NmeaSource(QObject *parent) +NmeaSource::NmeaSource(QObject *parent, const QVariantMap ¶meters) : QNmeaPositionInfoSource(RealTimeMode, parent), m_port(new QSerialPort) { - 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"); if (requestedPort.isEmpty()) { const QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts(); qCDebug(lcSerial) << "Found" << ports.count() << "serial ports"; @@ -110,18 +114,35 @@ NmeaSource::NmeaSource(QObject *parent) 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) { + 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) +{ Q_UNUSED(parent); + Q_UNUSED(parameters) return nullptr; } -QGeoAreaMonitorSource *QGeoPositionInfoSourceFactorySerialNmea::areaMonitor(QObject *parent) +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/positioning/doc/qtpositioning.qdocconf b/src/positioning/doc/qtpositioning.qdocconf index 3f6438ef..41a06c49 100644 --- a/src/positioning/doc/qtpositioning.qdocconf +++ b/src/positioning/doc/qtpositioning.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qtlocation.qdocconf) project = QtPositioning description = Qt Positioning Reference Documentation diff --git a/src/positioning/qgeopositioninfosource.cpp b/src/positioning/qgeopositioninfosource.cpp index 29a0d019..69fcdef0 100644 --- a/src/positioning/qgeopositioninfosource.cpp +++ b/src/positioning/qgeopositioninfosource.cpp @@ -108,6 +108,11 @@ QGeoPositionInfoSourcePrivate *QGeoPositionInfoSourcePrivate::get(const QGeoPosi return source.d; } +QGeoPositionInfoSourcePrivate::~QGeoPositionInfoSourcePrivate() +{ + +} + void QGeoPositionInfoSourcePrivate::loadMeta() { metaData = plugins().value(providerName); @@ -128,6 +133,16 @@ void QGeoPositionInfoSourcePrivate::loadPlugin() 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) { static QHash<QString, QJsonObject> plugins; @@ -216,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. @@ -382,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 23b3ac46..eaf5e106 100644 --- a/src/positioning/qgeopositioninfosource.h +++ b/src/positioning/qgeopositioninfosource.h @@ -87,6 +87,9 @@ 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); @@ -106,6 +109,9 @@ Q_SIGNALS: void error(QGeoPositionInfoSource::Error); void supportedPositioningMethodsChanged(); +protected: + QGeoPositionInfoSource(QGeoPositionInfoSourcePrivate &dd, QObject *parent); + private: Q_DISABLE_COPY(QGeoPositionInfoSource) QGeoPositionInfoSourcePrivate *d; diff --git a/src/positioning/qgeopositioninfosource_p.h b/src/positioning/qgeopositioninfosource_p.h index f5f85ec9..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,10 +61,11 @@ 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; @@ -74,6 +76,8 @@ public: 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/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 c6daaae5..dff0006c 100644 --- a/src/positioningquick/qdeclarativepositionsource_p.h +++ b/src/positioningquick/qdeclarativepositionsource_p.h @@ -56,7 +56,8 @@ #include <QtCore/QObject> #include <QtNetwork/QAbstractSocket> #include <QtQml/QQmlParserStatus> -#include <QtPositioning/QGeoPositionInfoSource> +#include <QtPositioning/qgeopositioninfosource.h> +#include <QtPositioningQuick/private/qdeclarativepluginparameter_p.h> QT_BEGIN_NAMESPACE @@ -76,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: @@ -121,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(); @@ -149,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; @@ -161,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_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/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 |