| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 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 "qdeclarativepositionsource_p.h" |
| #include "qdeclarativeposition_p.h" |
| |
| #include <QtCore/QCoreApplication> |
| #include <QtQml/qqmlinfo.h> |
| #include <QtQml/qqml.h> |
| #include <QtPositioning/qnmeapositioninfosource.h> |
| #include <qdeclarativepluginparameter_p.h> |
| #include <QFile> |
| #include <QtNetwork/QTcpSocket> |
| #include <QTimer> |
| |
| QT_BEGIN_NAMESPACE |
| |
| /*! |
| \qmltype PositionSource |
| //! \instantiates QDeclarativePositionSource |
| \inqmlmodule QtPositioning |
| \since 5.2 |
| |
| \brief The PositionSource type provides the device's current position. |
| |
| The PositionSource type provides information about the user device's |
| current position. The position is available as a \l{Position} type, which |
| contains all the standard parameters typically available from GPS and other |
| similar systems, including longitude, latitude, speed and accuracy details. |
| |
| As different position sources are available on different platforms and |
| devices, these are categorized by their basic type (Satellite, NonSatellite, |
| and AllPositioningMethods). The available methods for the current platform |
| can be enumerated in the \l{supportedPositioningMethods} property. |
| |
| To indicate which methods are suitable for your application, set the |
| \l{preferredPositioningMethods} property. If the preferred methods are not |
| available, the default source of location data for the platform will be |
| chosen instead. If no default source is available (because none are installed |
| for the runtime platform, or because it is disabled), the \l{valid} property |
| will be set to false. |
| |
| The \l updateInterval property can then be used to indicate how often your |
| application wishes to receive position updates. The \l{start}(), |
| \l{stop}() and \l{update}() methods can be used to control the operation |
| of the PositionSource, as well as the \l{active} property, which when set |
| is equivalent to calling \l{start}() or \l{stop}(). |
| |
| When the PositionSource is active, position updates can be retrieved |
| either by simply using the \l{position} property in a binding (as the |
| value of another item's property), or by providing an implementation of |
| the \c {onPositionChanged} signal-handler. |
| |
| \section2 Example Usage |
| |
| The following example shows a simple PositionSource used to receive |
| updates every second and print the longitude and latitude out to |
| the console. |
| |
| \code |
| PositionSource { |
| id: src |
| updateInterval: 1000 |
| active: true |
| |
| onPositionChanged: { |
| var coord = src.position.coordinate; |
| console.log("Coordinate:", coord.longitude, coord.latitude); |
| } |
| } |
| \endcode |
| |
| The \l{geoflickr}{GeoFlickr} example application shows how to use |
| a PositionSource in your application to retrieve local data for users |
| from a REST web service. |
| |
| \sa {QtPositioning::Position}, {QGeoPositionInfoSource}, {PluginParameter} |
| |
| */ |
| |
| /*! |
| \qmlsignal PositionSource::updateTimeout() |
| |
| If \l update() was called, this signal is emitted if the current position could not be |
| retrieved within a certain amount of time. |
| |
| If \l start() was called, this signal is emitted if the position engine determines that |
| it is not able to provide further regular updates. |
| |
| \since Qt Positioning 5.5 |
| |
| \sa QGeoPositionInfoSource::updateTimeout() |
| */ |
| |
| |
| QDeclarativePositionSource::QDeclarativePositionSource() |
| : m_positionSource(0), m_preferredPositioningMethods(NoPositioningMethods), m_nmeaFile(0), |
| m_nmeaSocket(0), m_active(false), m_singleUpdate(false), m_updateInterval(0), |
| m_sourceError(NoError) |
| { |
| } |
| |
| QDeclarativePositionSource::~QDeclarativePositionSource() |
| { |
| delete m_nmeaFile; |
| delete m_nmeaSocket; |
| delete m_positionSource; |
| } |
| |
| |
| /*! |
| \qmlproperty string PositionSource::name |
| |
| This property holds the unique internal name for the plugin currently |
| providing position information. |
| |
| Setting the property causes the PositionSource to use a particular positioning provider. If |
| the PositionSource is active at the time that the name property is changed, it will become |
| inactive. If the specified positioning provider cannot be loaded the position source will |
| become invalid. |
| |
| Changing the name property may cause the \l {updateInterval}, \l {supportedPositioningMethods} |
| and \l {preferredPositioningMethods} properties to change as well. |
| */ |
| |
| |
| QString QDeclarativePositionSource::name() const |
| { |
| if (m_positionSource) |
| return m_positionSource->sourceName(); |
| else |
| return m_providerName; |
| } |
| |
| 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(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)), |
| this, SLOT(positionUpdateReceived(QGeoPositionInfo))); |
| connect(m_positionSource, SIGNAL(error(QGeoPositionInfoSource::Error)), |
| this, SLOT(sourceErrorReceived(QGeoPositionInfoSource::Error))); |
| connect(m_positionSource, SIGNAL(updateTimeout()), |
| this, SLOT(updateTimeoutReceived())); |
| |
| m_positionSource->setUpdateInterval(m_updateInterval); |
| m_positionSource->setPreferredPositioningMethods( |
| static_cast<QGeoPositionInfoSource::PositioningMethods>(int(m_preferredPositioningMethods))); |
| |
| const QGeoPositionInfo &lastKnown = m_positionSource->lastKnownPosition(); |
| if (lastKnown.isValid()) |
| setPosition(lastKnown); |
| } else if (m_active) { |
| m_active = false; |
| emit activeChanged(); |
| } |
| |
| if (previousUpdateInterval != updateInterval()) |
| emit updateIntervalChanged(); |
| |
| if (previousPreferredPositioningMethods != preferredPositioningMethods()) |
| emit preferredPositioningMethodsChanged(); |
| |
| if (previousPositioningMethods != supportedPositioningMethods()) |
| emit supportedPositioningMethodsChanged(); |
| |
| emit validityChanged(); |
| |
| 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()) |
| emit nameChanged(); |
| } |
| |
| /*! |
| \qmlproperty bool PositionSource::valid |
| |
| This property is true if the PositionSource object has acquired a valid |
| backend plugin to provide data. If false, other methods on the PositionSource |
| will have no effect. |
| |
| Applications should check this property to determine whether positioning is |
| available and enabled on the runtime platform, and react accordingly. |
| */ |
| bool QDeclarativePositionSource::isValid() const |
| { |
| return (m_positionSource != 0); |
| } |
| |
| void QDeclarativePositionSource::setNmeaSource(const QUrl &nmeaSource) |
| { |
| if (nmeaSource.scheme() == QLatin1String("socket")) { |
| if (m_nmeaSocket |
| && nmeaSource.host() == m_nmeaSocket->peerName() |
| && nmeaSource.port() == m_nmeaSocket->peerPort()) { |
| return; |
| } |
| |
| delete m_nmeaSocket; |
| m_nmeaSocket = new QTcpSocket(); |
| |
| connect(m_nmeaSocket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)> (&QAbstractSocket::error), |
| this, &QDeclarativePositionSource::socketError); |
| connect(m_nmeaSocket, &QTcpSocket::connected, |
| this, &QDeclarativePositionSource::socketConnected); |
| |
| m_nmeaSocket->connectToHost(nmeaSource.host(), nmeaSource.port(), QTcpSocket::ReadOnly); |
| } else { |
| // Strip the filename. This is clumsy but the file may be prefixed in several |
| // ways: "file:///", "qrc:///", "/", "" in platform dependent manner. |
| QString localFileName = nmeaSource.toString(); |
| if (!QFile::exists(localFileName)) { |
| if (localFileName.startsWith(QStringLiteral("qrc:///"))) { |
| localFileName.remove(0, 7); |
| } else if (localFileName.startsWith(QStringLiteral("file:///"))) { |
| localFileName.remove(0, 7); |
| } else if (localFileName.startsWith(QStringLiteral("qrc:/"))) { |
| localFileName.remove(0, 5); |
| } |
| if (!QFile::exists(localFileName) && localFileName.startsWith('/')) { |
| localFileName.remove(0,1); |
| } |
| } |
| if (m_nmeaFileName == localFileName) |
| return; |
| m_nmeaFileName = localFileName; |
| |
| PositioningMethods previousPositioningMethods = supportedPositioningMethods(); |
| |
| // The current position source needs to be deleted |
| // because QNmeaPositionInfoSource can be bound only to a one file. |
| delete m_nmeaSocket; |
| m_nmeaSocket = 0; |
| setSource(nullptr); |
| setPosition(QGeoPositionInfo()); |
| // Create the NMEA source based on the given data. QML has automatically set QUrl |
| // type to point to correct path. If the file is not found, check if the file actually |
| // was an embedded resource file. |
| delete m_nmeaFile; |
| m_nmeaFile = new QFile(localFileName); |
| if (!m_nmeaFile->exists()) { |
| localFileName.prepend(':'); |
| m_nmeaFile->setFileName(localFileName); |
| } |
| if (m_nmeaFile->exists()) { |
| #ifdef QDECLARATIVE_POSITION_DEBUG |
| qDebug() << "QDeclarativePositionSource NMEA File was found: " << localFileName; |
| #endif |
| setSource(new QNmeaPositionInfoSource(QNmeaPositionInfoSource::SimulationMode)); |
| (qobject_cast<QNmeaPositionInfoSource *>(m_positionSource))->setUserEquivalentRangeError(2.5); // it is internally multiplied by 2 in qlocationutils_readGga |
| (qobject_cast<QNmeaPositionInfoSource *>(m_positionSource))->setDevice(m_nmeaFile); |
| 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())); |
| |
| setPosition(m_positionSource->lastKnownPosition()); |
| if (m_active && !m_singleUpdate) { |
| // Keep on updating even though source changed |
| QTimer::singleShot(0, this, SLOT(start())); |
| } |
| } else { |
| qmlWarning(this) << QStringLiteral("Nmea file not found") << localFileName; |
| #ifdef QDECLARATIVE_POSITION_DEBUG |
| qDebug() << "QDeclarativePositionSource NMEA File was not found: " << localFileName; |
| #endif |
| if (m_active) { |
| m_active = false; |
| m_singleUpdate = false; |
| emit activeChanged(); |
| } |
| } |
| |
| if (previousPositioningMethods != supportedPositioningMethods()) |
| emit supportedPositioningMethodsChanged(); |
| } |
| |
| m_nmeaSource = nmeaSource; |
| emit nmeaSourceChanged(); |
| } |
| |
| /*! |
| \internal |
| */ |
| void QDeclarativePositionSource::socketConnected() |
| { |
| #ifdef QDECLARATIVE_POSITION_DEBUG |
| qDebug() << "Socket connected: " << m_nmeaSocket->peerName(); |
| #endif |
| PositioningMethods previousPositioningMethods = supportedPositioningMethods(); |
| |
| // The current position source needs to be deleted |
| // because QNmeaPositionInfoSource can be bound only to a one file. |
| delete m_nmeaFile; |
| m_nmeaFile = 0; |
| setSource(nullptr); |
| |
| setSource(new QNmeaPositionInfoSource(QNmeaPositionInfoSource::RealTimeMode)); |
| (qobject_cast<QNmeaPositionInfoSource *>(m_positionSource))->setDevice(m_nmeaSocket); |
| |
| connect(m_positionSource, &QNmeaPositionInfoSource::positionUpdated, |
| this, &QDeclarativePositionSource::positionUpdateReceived); |
| connect(m_positionSource, SIGNAL(error(QGeoPositionInfoSource::Error)), |
| this, SLOT(sourceErrorReceived(QGeoPositionInfoSource::Error))); |
| connect(m_positionSource, SIGNAL(updateTimeout()), |
| this, SLOT(updateTimeoutReceived())); |
| |
| setPosition(m_positionSource->lastKnownPosition()); |
| |
| if (m_active && !m_singleUpdate) { |
| // Keep on updating even though source changed |
| QTimer::singleShot(0, this, SLOT(start())); |
| } |
| |
| if (previousPositioningMethods != supportedPositioningMethods()) |
| emit supportedPositioningMethodsChanged(); |
| } |
| |
| /*! |
| \internal |
| */ |
| void QDeclarativePositionSource::socketError(QAbstractSocket::SocketError error) |
| { |
| delete m_nmeaSocket; |
| m_nmeaSocket = 0; |
| |
| switch (error) { |
| case QAbstractSocket::UnknownSocketError: |
| m_sourceError = QDeclarativePositionSource::UnknownSourceError; |
| break; |
| case QAbstractSocket::SocketAccessError: |
| m_sourceError = QDeclarativePositionSource::AccessError; |
| break; |
| case QAbstractSocket::RemoteHostClosedError: |
| m_sourceError = QDeclarativePositionSource::ClosedError; |
| break; |
| default: |
| qWarning() << "Connection failed! QAbstractSocket::SocketError" << error; |
| m_sourceError = QDeclarativePositionSource::SocketError; |
| break; |
| } |
| |
| emit sourceErrorChanged(); |
| } |
| |
| |
| void QDeclarativePositionSource::updateTimeoutReceived() |
| { |
| if (!m_active) |
| return; |
| |
| if (m_singleUpdate) { |
| m_singleUpdate = false; |
| |
| // only singleUpdate based timeouts change activity |
| // continuous updates may resume again (see QGeoPositionInfoSource::startUpdates()) |
| m_active = false; |
| emit activeChanged(); |
| } |
| |
| 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); |
| emit positionChanged(); |
| } |
| |
| void QDeclarativePositionSource::setSource(QGeoPositionInfoSource *source) |
| { |
| if (m_positionSource) |
| delete m_positionSource; |
| |
| if (!source) { |
| m_positionSource = nullptr; |
| } else { |
| m_positionSource = source; |
| connect(m_positionSource, &QGeoPositionInfoSource::supportedPositioningMethodsChanged, |
| this, &QDeclarativePositionSource::supportedPositioningMethodsChanged); |
| } |
| } |
| |
| 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 |
| */ |
| void QDeclarativePositionSource::setUpdateInterval(int updateInterval) |
| { |
| if (m_positionSource) { |
| int previousUpdateInterval = m_positionSource->updateInterval(); |
| |
| m_updateInterval = updateInterval; |
| |
| if (previousUpdateInterval != updateInterval) { |
| m_positionSource->setUpdateInterval(updateInterval); |
| if (previousUpdateInterval != m_positionSource->updateInterval()) |
| emit updateIntervalChanged(); |
| } |
| } else { |
| if (m_updateInterval != updateInterval) { |
| m_updateInterval = updateInterval; |
| emit updateIntervalChanged(); |
| } |
| } |
| } |
| |
| /*! |
| \qmlproperty url PositionSource::nmeaSource |
| |
| This property holds the source for NMEA (National Marine Electronics Association) |
| position-specification data (file). One purpose of this property is to be of |
| development convenience. |
| |
| Setting this property will override any other position source. Currently only |
| files local to the .qml -file are supported. The NMEA source is created in simulation mode, |
| meaning that the data and time information in the NMEA source data is used to provide |
| positional updates at the rate at which the data was originally recorded. |
| |
| If nmeaSource has been set for a PositionSource object, there is no way to revert |
| back to non-file sources. |
| */ |
| |
| QUrl QDeclarativePositionSource::nmeaSource() const |
| { |
| return m_nmeaSource; |
| } |
| |
| /*! |
| \qmlproperty int PositionSource::updateInterval |
| |
| This property holds the desired interval between updates (milliseconds). |
| |
| \sa {QGeoPositionInfoSource::updateInterval()} |
| */ |
| |
| int QDeclarativePositionSource::updateInterval() const |
| { |
| if (!m_positionSource) |
| return m_updateInterval; |
| |
| return m_positionSource->updateInterval(); |
| } |
| |
| /*! |
| \qmlproperty enumeration PositionSource::supportedPositioningMethods |
| |
| This property holds the supported positioning methods of the |
| current source. |
| |
| \list |
| \li PositionSource.NoPositioningMethods - No positioning methods supported (no source). |
| \li PositionSource.SatellitePositioningMethods - Satellite-based positioning methods such as GPS are supported. |
| \li PositionSource.NonSatellitePositioningMethods - Non-satellite-based methods are supported. |
| \li PositionSource.AllPositioningMethods - Both satellite-based and non-satellite positioning methods are supported. |
| \endlist |
| |
| */ |
| |
| QDeclarativePositionSource::PositioningMethods QDeclarativePositionSource::supportedPositioningMethods() const |
| { |
| if (m_positionSource) { |
| return static_cast<QDeclarativePositionSource::PositioningMethods>( |
| int(m_positionSource->supportedPositioningMethods())); |
| } |
| return QDeclarativePositionSource::NoPositioningMethods; |
| } |
| |
| /*! |
| \qmlproperty enumeration PositionSource::preferredPositioningMethods |
| |
| This property holds the preferred positioning methods of the |
| current source. |
| |
| \list |
| \li PositionSource.NoPositioningMethods - No positioning method is preferred. |
| \li PositionSource.SatellitePositioningMethods - Satellite-based positioning methods such as GPS should be preferred. |
| \li PositionSource.NonSatellitePositioningMethods - Non-satellite-based methods should be preferred. |
| \li PositionSource.AllPositioningMethods - Any positioning methods are acceptable. |
| \endlist |
| |
| */ |
| |
| void QDeclarativePositionSource::setPreferredPositioningMethods(PositioningMethods methods) |
| { |
| if (m_positionSource) { |
| PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods(); |
| |
| m_preferredPositioningMethods = methods; |
| |
| if (previousPreferredPositioningMethods != methods) { |
| m_positionSource->setPreferredPositioningMethods( |
| static_cast<QGeoPositionInfoSource::PositioningMethods>(int(methods))); |
| if (previousPreferredPositioningMethods != m_positionSource->preferredPositioningMethods()) |
| emit preferredPositioningMethodsChanged(); |
| } |
| } else { |
| if (m_preferredPositioningMethods != methods) { |
| m_preferredPositioningMethods = methods; |
| emit preferredPositioningMethodsChanged(); |
| } |
| } |
| } |
| |
| QDeclarativePositionSource::PositioningMethods QDeclarativePositionSource::preferredPositioningMethods() const |
| { |
| if (m_positionSource) { |
| return static_cast<QDeclarativePositionSource::PositioningMethods>( |
| int(m_positionSource->preferredPositioningMethods())); |
| } |
| return m_preferredPositioningMethods; |
| } |
| |
| /*! |
| \qmlmethod PositionSource::start() |
| |
| Requests updates from the location source. |
| Uses \l updateInterval if set, default interval otherwise. |
| If there is no source available, this method has no effect. |
| |
| \sa stop, update, active |
| */ |
| |
| void QDeclarativePositionSource::start() |
| { |
| if (m_positionSource) |
| m_positionSource->startUpdates(); |
| |
| if (!m_active) { |
| m_active = true; |
| emit activeChanged(); |
| } |
| } |
| |
| /*! |
| \qmlmethod PositionSource::update() |
| |
| A convenience method to request single update from the location source. |
| If there is no source available, this method has no effect. |
| |
| If the position source is not active, it will be activated for as |
| long as it takes to receive an update, or until the request times |
| out. The request timeout period is source-specific. |
| |
| \sa start, stop, active |
| */ |
| |
| void QDeclarativePositionSource::update() |
| { |
| if (m_positionSource) { |
| if (!m_active) { |
| m_active = true; |
| m_singleUpdate = true; |
| emit activeChanged(); |
| } |
| // Use default timeout value. Set active before calling the |
| // update request because on some platforms there may |
| // be results immediately. |
| m_positionSource->requestUpdate(); |
| } |
| } |
| |
| /*! |
| \qmlmethod PositionSource::stop() |
| |
| Stops updates from the location source. |
| If there is no source available or it is not active, |
| this method has no effect. |
| |
| \sa start, update, active |
| */ |
| |
| void QDeclarativePositionSource::stop() |
| { |
| if (m_positionSource) { |
| m_positionSource->stopUpdates(); |
| if (m_active) { |
| m_active = false; |
| emit activeChanged(); |
| } |
| } |
| } |
| |
| /*! |
| \qmlproperty bool PositionSource::active |
| |
| This property indicates whether the position source is active. |
| Setting this property to false equals calling \l stop, and |
| setting this property true equals calling \l start. |
| |
| \sa start, stop, update |
| */ |
| void QDeclarativePositionSource::setActive(bool active) |
| { |
| if (active == m_active) |
| return; |
| |
| if (active) |
| QTimer::singleShot(0, this, SLOT(start())); // delay ensures all properties have been set |
| else |
| stop(); |
| } |
| |
| bool QDeclarativePositionSource::isActive() const |
| { |
| return m_active; |
| } |
| |
| /*! |
| \qmlproperty Position PositionSource::position |
| |
| This property holds the last known positional data. |
| It is a read-only property. |
| |
| The Position type has different positional member variables, |
| whose validity can be checked with appropriate validity functions |
| (for example sometimes an update does not have speed or altitude data). |
| |
| However, whenever a \c {positionChanged} signal has been received, at least |
| position::coordinate::latitude, position::coordinate::longitude, and position::timestamp can |
| be assumed to be valid. |
| |
| \sa start, stop, update |
| */ |
| |
| QDeclarativePosition *QDeclarativePositionSource::position() |
| { |
| return &m_position; |
| } |
| |
| void QDeclarativePositionSource::positionUpdateReceived(const QGeoPositionInfo &update) |
| { |
| setPosition(update); |
| |
| if (m_singleUpdate && m_active) { |
| m_active = false; |
| m_singleUpdate = false; |
| emit activeChanged(); |
| } |
| } |
| |
| |
| /*! |
| \qmlproperty enumeration PositionSource::sourceError |
| |
| This property holds the error which last occurred with the PositionSource. |
| |
| \list |
| \li PositionSource.AccessError - The connection setup to the remote positioning backend failed because the |
| application lacked the required privileges. |
| \li PositionSource.ClosedError - The positioning backend closed the connection, which happens for example in case |
| the user is switching location services to off. As soon as the location service is re-enabled |
| regular updates will resume. |
| \li PositionSource.NoError - No error has occurred. |
| \li PositionSource.UnknownSourceError - An unidentified error occurred. |
| \li PositionSource.SocketError - An error occurred while connecting to an nmea source using a socket. |
| \endlist |
| |
| */ |
| |
| QDeclarativePositionSource::SourceError QDeclarativePositionSource::sourceError() const |
| { |
| return m_sourceError; |
| } |
| |
| QGeoPositionInfoSource *QDeclarativePositionSource::positionSource() const |
| { |
| return m_positionSource; |
| } |
| |
| /*! |
| \qmlproperty list<PluginParameter> PositionSource::parameters |
| \default |
| |
| This property holds the list of plugin parameters. |
| |
| \since QtPositioning 5.14 |
| */ |
| QQmlListProperty<QDeclarativePluginParameter> QDeclarativePositionSource::parameters() |
| { |
| return QQmlListProperty<QDeclarativePluginParameter>(this, |
| 0, |
| parameter_append, |
| parameter_count, |
| parameter_at, |
| parameter_clear); |
| } |
| |
| /*! |
| \internal |
| */ |
| void QDeclarativePositionSource::parameter_append(QQmlListProperty<QDeclarativePluginParameter> *prop, QDeclarativePluginParameter *parameter) |
| { |
| QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object); |
| p->m_parameters.append(parameter); |
| } |
| |
| /*! |
| \internal |
| */ |
| int QDeclarativePositionSource::parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop) |
| { |
| return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters.count(); |
| } |
| |
| /*! |
| \internal |
| */ |
| QDeclarativePluginParameter *QDeclarativePositionSource::parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, int index) |
| { |
| return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters[index]; |
| } |
| |
| /*! |
| \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 (m_parametersInitialized) |
| tryAttach(m_providerName); |
| } |
| |
| /*! |
| \qmlmethod bool QtLocation::PositionSource::setBackendProperty(string name, Variant value) |
| |
| 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}. |
| |
| \since Qt Positioning 5.14 |
| |
| \sa backendProperty, QGeoPositionInfoSource::setBackendProperty |
| */ |
| bool QDeclarativePositionSource::setBackendProperty(const QString &name, const 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(); |
| } |
| |
| /*! |
| \internal |
| */ |
| void QDeclarativePositionSource::sourceErrorReceived(const QGeoPositionInfoSource::Error error) |
| { |
| if (error == QGeoPositionInfoSource::AccessError) |
| m_sourceError = QDeclarativePositionSource::AccessError; |
| else if (error == QGeoPositionInfoSource::ClosedError) |
| m_sourceError = QDeclarativePositionSource::ClosedError; |
| else if (error == QGeoPositionInfoSource::NoError) |
| return; //nothing to do |
| else |
| m_sourceError = QDeclarativePositionSource::UnknownSourceError; |
| |
| emit sourceErrorChanged(); |
| } |
| |
| QT_END_NAMESPACE |