1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtPositioning module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qdeclarativepositionsource_p.h"
41#include "qdeclarativeposition_p.h"
42
43#include <QtCore/QCoreApplication>
44#include <QtQml/qqmlinfo.h>
45#include <QtQml/qqml.h>
46#include <QtPositioning/qnmeapositioninfosource.h>
47#include <qdeclarativepluginparameter_p.h>
48#include <QFile>
49#include <QtNetwork/QTcpSocket>
50#include <QTimer>
51
52QT_BEGIN_NAMESPACE
53
54/*!
55 \qmltype PositionSource
56 //! \instantiates QDeclarativePositionSource
57 \inqmlmodule QtPositioning
58 \since 5.2
59
60 \brief The PositionSource type provides the device's current position.
61
62 The PositionSource type provides information about the user device's
63 current position. The position is available as a \l{Position} type, which
64 contains all the standard parameters typically available from GPS and other
65 similar systems, including longitude, latitude, speed and accuracy details.
66
67 As different position sources are available on different platforms and
68 devices, these are categorized by their basic type (Satellite, NonSatellite,
69 and AllPositioningMethods). The available methods for the current platform
70 can be enumerated in the \l{supportedPositioningMethods} property.
71
72 To indicate which methods are suitable for your application, set the
73 \l{preferredPositioningMethods} property. If the preferred methods are not
74 available, the default source of location data for the platform will be
75 chosen instead. If no default source is available (because none are installed
76 for the runtime platform, or because it is disabled), the \l{valid} property
77 will be set to false.
78
79 The \l updateInterval property can then be used to indicate how often your
80 application wishes to receive position updates. The \l{start}(),
81 \l{stop}() and \l{update}() methods can be used to control the operation
82 of the PositionSource, as well as the \l{active} property, which when set
83 is equivalent to calling \l{start}() or \l{stop}().
84
85 When the PositionSource is active, position updates can be retrieved
86 either by simply using the \l{position} property in a binding (as the
87 value of another item's property), or by providing an implementation of
88 the \c {onPositionChanged} signal-handler.
89
90 \section2 Example Usage
91
92 The following example shows a simple PositionSource used to receive
93 updates every second and print the longitude and latitude out to
94 the console.
95
96 \code
97 PositionSource {
98 id: src
99 updateInterval: 1000
100 active: true
101
102 onPositionChanged: {
103 var coord = src.position.coordinate;
104 console.log("Coordinate:", coord.longitude, coord.latitude);
105 }
106 }
107 \endcode
108
109 The \l{geoflickr}{GeoFlickr} example application shows how to use
110 a PositionSource in your application to retrieve local data for users
111 from a REST web service.
112
113 \sa {QtPositioning::Position}, {QGeoPositionInfoSource}, {PluginParameter}
114
115*/
116
117/*!
118 \qmlsignal PositionSource::updateTimeout()
119
120 If \l update() was called, this signal is emitted if the current position could not be
121 retrieved within a certain amount of time.
122
123 If \l start() was called, this signal is emitted if the position engine determines that
124 it is not able to provide further regular updates.
125
126 \since Qt Positioning 5.5
127
128 \sa QGeoPositionInfoSource::updateTimeout()
129*/
130
131
132QDeclarativePositionSource::QDeclarativePositionSource()
133: m_positionSource(0), m_preferredPositioningMethods(NoPositioningMethods), m_nmeaFile(0),
134 m_nmeaSocket(0), m_active(false), m_singleUpdate(false), m_updateInterval(0),
135 m_sourceError(NoError)
136{
137}
138
139QDeclarativePositionSource::~QDeclarativePositionSource()
140{
141 delete m_nmeaFile;
142 delete m_nmeaSocket;
143 delete m_positionSource;
144}
145
146
147/*!
148 \qmlproperty string PositionSource::name
149
150 This property holds the unique internal name for the plugin currently
151 providing position information.
152
153 Setting the property causes the PositionSource to use a particular positioning provider. If
154 the PositionSource is active at the time that the name property is changed, it will become
155 inactive. If the specified positioning provider cannot be loaded the position source will
156 become invalid.
157
158 Changing the name property may cause the \l {updateInterval}, \l {supportedPositioningMethods}
159 and \l {preferredPositioningMethods} properties to change as well.
160*/
161
162
163QString QDeclarativePositionSource::name() const
164{
165 if (m_positionSource)
166 return m_positionSource->sourceName();
167 else
168 return m_providerName;
169}
170
171void QDeclarativePositionSource::setName(const QString &newName)
172{
173 if (m_positionSource && m_positionSource->sourceName() == newName)
174 return;
175
176 if (m_providerName == newName && m_providerName.isEmpty())
177 return; // previously attached to a default source, now requesting the same.
178
179 const QString previousName = name();
180 m_providerName = newName;
181
182 if (!m_componentComplete || !m_parametersInitialized) {
183 if (previousName != name())
184 emit nameChanged();
185 return;
186 }
187
188 tryAttach(name: newName, useFallback: false);
189}
190
191/*!
192 \internal
193*/
194void QDeclarativePositionSource::tryAttach(const QString &newName, bool useFallback)
195{
196 if (m_nmeaFile != nullptr || m_nmeaSocket != nullptr) {
197 if (!m_providerName.isEmpty())
198 qWarning(msg: "Both nmeaSource and name parameters are specified. nmeaSource will be used.");
199 return;
200 }
201
202 const QString previousName = name();
203 const bool sourceExisted = m_positionSource;
204 m_providerName = newName;
205
206 int previousUpdateInterval = updateInterval();
207 PositioningMethods previousPositioningMethods = supportedPositioningMethods();
208 PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods();
209
210 if (newName.isEmpty()) {
211 setSource(QGeoPositionInfoSource::createDefaultSource(parameters: parameterMap(), parent: this));
212 } else {
213 setSource(QGeoPositionInfoSource::createSource(sourceName: newName, parameters: parameterMap(), parent: this));
214 if (!m_positionSource && useFallback)
215 setSource(QGeoPositionInfoSource::createDefaultSource(parameters: parameterMap(), parent: this));
216 }
217
218 if (m_positionSource) {
219 connect(sender: m_positionSource, SIGNAL(positionUpdated(QGeoPositionInfo)),
220 receiver: this, SLOT(positionUpdateReceived(QGeoPositionInfo)));
221 connect(sender: m_positionSource, SIGNAL(error(QGeoPositionInfoSource::Error)),
222 receiver: this, SLOT(sourceErrorReceived(QGeoPositionInfoSource::Error)));
223 connect(sender: m_positionSource, SIGNAL(updateTimeout()),
224 receiver: this, SLOT(updateTimeoutReceived()));
225
226 m_positionSource->setUpdateInterval(m_updateInterval);
227 m_positionSource->setPreferredPositioningMethods(
228 static_cast<QGeoPositionInfoSource::PositioningMethods>(int(m_preferredPositioningMethods)));
229
230 const QGeoPositionInfo &lastKnown = m_positionSource->lastKnownPosition();
231 if (lastKnown.isValid())
232 setPosition(lastKnown);
233 } else if (m_active) {
234 m_active = false;
235 emit activeChanged();
236 }
237
238 if (previousUpdateInterval != updateInterval())
239 emit updateIntervalChanged();
240
241 if (previousPreferredPositioningMethods != preferredPositioningMethods())
242 emit preferredPositioningMethodsChanged();
243
244 if (previousPositioningMethods != supportedPositioningMethods())
245 emit supportedPositioningMethodsChanged();
246
247 emit validityChanged();
248
249 if (m_active) { // implies m_positionSource
250 if (!sourceExisted) {
251 QTimer::singleShot(msec: 0, receiver: this, SLOT(start())); // delay ensures all properties have been set
252 } else {
253 m_active = false;
254 emit activeChanged();
255 }
256 }
257
258 if (previousName != name())
259 emit nameChanged();
260}
261
262/*!
263 \qmlproperty bool PositionSource::valid
264
265 This property is true if the PositionSource object has acquired a valid
266 backend plugin to provide data. If false, other methods on the PositionSource
267 will have no effect.
268
269 Applications should check this property to determine whether positioning is
270 available and enabled on the runtime platform, and react accordingly.
271*/
272bool QDeclarativePositionSource::isValid() const
273{
274 return (m_positionSource != 0);
275}
276
277void QDeclarativePositionSource::setNmeaSource(const QUrl &nmeaSource)
278{
279 if (nmeaSource.scheme() == QLatin1String("socket")) {
280 if (m_nmeaSocket
281 && nmeaSource.host() == m_nmeaSocket->peerName()
282 && nmeaSource.port() == m_nmeaSocket->peerPort()) {
283 return;
284 }
285
286 delete m_nmeaSocket;
287 m_nmeaSocket = new QTcpSocket();
288
289 connect(sender: m_nmeaSocket, signal: &QAbstractSocket::errorOccurred,
290 receiver: this, slot: &QDeclarativePositionSource::socketError);
291 connect(sender: m_nmeaSocket, signal: &QTcpSocket::connected,
292 receiver: this, slot: &QDeclarativePositionSource::socketConnected);
293
294 m_nmeaSocket->connectToHost(hostName: nmeaSource.host(), port: nmeaSource.port(), mode: QTcpSocket::ReadOnly);
295 } else {
296 // Strip the filename. This is clumsy but the file may be prefixed in several
297 // ways: "file:///", "qrc:///", "/", "" in platform dependent manner.
298 QString localFileName = nmeaSource.toString();
299 if (!QFile::exists(fileName: localFileName)) {
300 if (localFileName.startsWith(QStringLiteral("qrc:///"))) {
301 localFileName.remove(i: 0, len: 7);
302 } else if (localFileName.startsWith(QStringLiteral("file:///"))) {
303 localFileName.remove(i: 0, len: 7);
304 } else if (localFileName.startsWith(QStringLiteral("qrc:/"))) {
305 localFileName.remove(i: 0, len: 5);
306 }
307 if (!QFile::exists(fileName: localFileName) && localFileName.startsWith(c: '/')) {
308 localFileName.remove(i: 0,len: 1);
309 }
310 }
311 if (m_nmeaFileName == localFileName)
312 return;
313 m_nmeaFileName = localFileName;
314
315 PositioningMethods previousPositioningMethods = supportedPositioningMethods();
316
317 // The current position source needs to be deleted
318 // because QNmeaPositionInfoSource can be bound only to a one file.
319 delete m_nmeaSocket;
320 m_nmeaSocket = 0;
321 setSource(nullptr);
322 setPosition(QGeoPositionInfo());
323 // Create the NMEA source based on the given data. QML has automatically set QUrl
324 // type to point to correct path. If the file is not found, check if the file actually
325 // was an embedded resource file.
326 delete m_nmeaFile;
327 m_nmeaFile = new QFile(localFileName);
328 if (!m_nmeaFile->exists()) {
329 localFileName.prepend(c: ':');
330 m_nmeaFile->setFileName(localFileName);
331 }
332 if (m_nmeaFile->exists()) {
333#ifdef QDECLARATIVE_POSITION_DEBUG
334 qDebug() << "QDeclarativePositionSource NMEA File was found: " << localFileName;
335#endif
336 setSource(new QNmeaPositionInfoSource(QNmeaPositionInfoSource::SimulationMode));
337 (qobject_cast<QNmeaPositionInfoSource *>(object: m_positionSource))->setUserEquivalentRangeError(2.5); // it is internally multiplied by 2 in qlocationutils_readGga
338 (qobject_cast<QNmeaPositionInfoSource *>(object: m_positionSource))->setDevice(m_nmeaFile);
339 connect(sender: m_positionSource, SIGNAL(positionUpdated(QGeoPositionInfo)),
340 receiver: this, SLOT(positionUpdateReceived(QGeoPositionInfo)));
341 connect(sender: m_positionSource, SIGNAL(error(QGeoPositionInfoSource::Error)),
342 receiver: this, SLOT(sourceErrorReceived(QGeoPositionInfoSource::Error)));
343 connect(sender: m_positionSource, SIGNAL(updateTimeout()),
344 receiver: this, SLOT(updateTimeoutReceived()));
345
346 setPosition(m_positionSource->lastKnownPosition());
347 if (m_active && !m_singleUpdate) {
348 // Keep on updating even though source changed
349 QTimer::singleShot(msec: 0, receiver: this, SLOT(start()));
350 }
351 } else {
352 qmlWarning(me: this) << QStringLiteral("Nmea file not found") << localFileName;
353#ifdef QDECLARATIVE_POSITION_DEBUG
354 qDebug() << "QDeclarativePositionSource NMEA File was not found: " << localFileName;
355#endif
356 if (m_active) {
357 m_active = false;
358 m_singleUpdate = false;
359 emit activeChanged();
360 }
361 }
362
363 if (previousPositioningMethods != supportedPositioningMethods())
364 emit supportedPositioningMethodsChanged();
365 }
366
367 m_nmeaSource = nmeaSource;
368 emit nmeaSourceChanged();
369}
370
371/*!
372 \internal
373*/
374void QDeclarativePositionSource::socketConnected()
375{
376#ifdef QDECLARATIVE_POSITION_DEBUG
377 qDebug() << "Socket connected: " << m_nmeaSocket->peerName();
378#endif
379 PositioningMethods previousPositioningMethods = supportedPositioningMethods();
380
381 // The current position source needs to be deleted
382 // because QNmeaPositionInfoSource can be bound only to a one file.
383 delete m_nmeaFile;
384 m_nmeaFile = 0;
385 setSource(nullptr);
386
387 setSource(new QNmeaPositionInfoSource(QNmeaPositionInfoSource::RealTimeMode));
388 (qobject_cast<QNmeaPositionInfoSource *>(object: m_positionSource))->setDevice(m_nmeaSocket);
389
390 connect(sender: m_positionSource, signal: &QNmeaPositionInfoSource::positionUpdated,
391 receiver: this, slot: &QDeclarativePositionSource::positionUpdateReceived);
392 connect(sender: m_positionSource, SIGNAL(error(QGeoPositionInfoSource::Error)),
393 receiver: this, SLOT(sourceErrorReceived(QGeoPositionInfoSource::Error)));
394 connect(sender: m_positionSource, SIGNAL(updateTimeout()),
395 receiver: this, SLOT(updateTimeoutReceived()));
396
397 setPosition(m_positionSource->lastKnownPosition());
398
399 if (m_active && !m_singleUpdate) {
400 // Keep on updating even though source changed
401 QTimer::singleShot(msec: 0, receiver: this, SLOT(start()));
402 }
403
404 if (previousPositioningMethods != supportedPositioningMethods())
405 emit supportedPositioningMethodsChanged();
406}
407
408/*!
409 \internal
410*/
411void QDeclarativePositionSource::socketError(QAbstractSocket::SocketError error)
412{
413 m_nmeaSocket->deleteLater();
414 m_nmeaSocket = nullptr;
415
416 switch (error) {
417 case QAbstractSocket::UnknownSocketError:
418 m_sourceError = QDeclarativePositionSource::UnknownSourceError;
419 break;
420 case QAbstractSocket::SocketAccessError:
421 m_sourceError = QDeclarativePositionSource::AccessError;
422 break;
423 case QAbstractSocket::RemoteHostClosedError:
424 m_sourceError = QDeclarativePositionSource::ClosedError;
425 break;
426 default:
427 qWarning() << "Connection failed! QAbstractSocket::SocketError" << error;
428 m_sourceError = QDeclarativePositionSource::SocketError;
429 break;
430 }
431
432 emit sourceErrorChanged();
433}
434
435
436void QDeclarativePositionSource::updateTimeoutReceived()
437{
438 if (!m_active)
439 return;
440
441 if (m_singleUpdate) {
442 m_singleUpdate = false;
443
444 // only singleUpdate based timeouts change activity
445 // continuous updates may resume again (see QGeoPositionInfoSource::startUpdates())
446 m_active = false;
447 emit activeChanged();
448 }
449
450 emit updateTimeout();
451}
452
453/*!
454 \internal
455*/
456void QDeclarativePositionSource::onParameterInitialized()
457{
458 m_parametersInitialized = true;
459 for (QDeclarativePluginParameter *p: qAsConst(t&: m_parameters)) {
460 if (!p->isInitialized()) {
461 m_parametersInitialized = false;
462 break;
463 }
464 }
465
466 // If here, componentComplete has been called.
467 if (m_parametersInitialized)
468 tryAttach(newName: m_providerName);
469}
470
471void QDeclarativePositionSource::setPosition(const QGeoPositionInfo &pi)
472{
473 m_position.setPosition(pi);
474 emit positionChanged();
475}
476
477void QDeclarativePositionSource::setSource(QGeoPositionInfoSource *source)
478{
479 if (m_positionSource)
480 delete m_positionSource;
481
482 if (!source) {
483 m_positionSource = nullptr;
484 } else {
485 m_positionSource = source;
486 connect(sender: m_positionSource, signal: &QGeoPositionInfoSource::supportedPositioningMethodsChanged,
487 receiver: this, slot: &QDeclarativePositionSource::supportedPositioningMethodsChanged);
488 }
489}
490
491bool QDeclarativePositionSource::parametersReady()
492{
493 for (const QDeclarativePluginParameter *p: qAsConst(t&: m_parameters)) {
494 if (!p->isInitialized())
495 return false;
496 }
497 return true;
498}
499
500/*!
501 \internal
502*/
503QVariantMap QDeclarativePositionSource::parameterMap() const
504{
505 QVariantMap map;
506
507 for (int i = 0; i < m_parameters.size(); ++i) {
508 QDeclarativePluginParameter *parameter = m_parameters.at(i);
509 map.insert(akey: parameter->name(), avalue: parameter->value());
510 }
511
512 return map;
513}
514
515/*!
516 \internal
517*/
518void QDeclarativePositionSource::setUpdateInterval(int updateInterval)
519{
520 if (m_positionSource) {
521 int previousUpdateInterval = m_positionSource->updateInterval();
522
523 m_updateInterval = updateInterval;
524
525 if (previousUpdateInterval != updateInterval) {
526 m_positionSource->setUpdateInterval(updateInterval);
527 if (previousUpdateInterval != m_positionSource->updateInterval())
528 emit updateIntervalChanged();
529 }
530 } else {
531 if (m_updateInterval != updateInterval) {
532 m_updateInterval = updateInterval;
533 emit updateIntervalChanged();
534 }
535 }
536}
537
538/*!
539 \qmlproperty url PositionSource::nmeaSource
540
541 This property holds the source for NMEA (National Marine Electronics Association)
542 position-specification data (file). One purpose of this property is to be of
543 development convenience.
544
545 Setting this property will override any other position source. Currently only
546 files local to the .qml -file are supported. The NMEA source is created in simulation mode,
547 meaning that the data and time information in the NMEA source data is used to provide
548 positional updates at the rate at which the data was originally recorded.
549
550 If nmeaSource has been set for a PositionSource object, there is no way to revert
551 back to non-file sources.
552*/
553
554QUrl QDeclarativePositionSource::nmeaSource() const
555{
556 return m_nmeaSource;
557}
558
559/*!
560 \qmlproperty int PositionSource::updateInterval
561
562 This property holds the desired interval between updates (milliseconds).
563
564 \sa {QGeoPositionInfoSource::updateInterval()}
565*/
566
567int QDeclarativePositionSource::updateInterval() const
568{
569 if (!m_positionSource)
570 return m_updateInterval;
571
572 return m_positionSource->updateInterval();
573}
574
575/*!
576 \qmlproperty enumeration PositionSource::supportedPositioningMethods
577
578 This property holds the supported positioning methods of the
579 current source.
580
581 \list
582 \li PositionSource.NoPositioningMethods - No positioning methods supported (no source).
583 \li PositionSource.SatellitePositioningMethods - Satellite-based positioning methods such as GPS are supported.
584 \li PositionSource.NonSatellitePositioningMethods - Non-satellite-based methods are supported.
585 \li PositionSource.AllPositioningMethods - Both satellite-based and non-satellite positioning methods are supported.
586 \endlist
587
588*/
589
590QDeclarativePositionSource::PositioningMethods QDeclarativePositionSource::supportedPositioningMethods() const
591{
592 if (m_positionSource) {
593 return static_cast<QDeclarativePositionSource::PositioningMethods>(
594 int(m_positionSource->supportedPositioningMethods()));
595 }
596 return QDeclarativePositionSource::NoPositioningMethods;
597}
598
599/*!
600 \qmlproperty enumeration PositionSource::preferredPositioningMethods
601
602 This property holds the preferred positioning methods of the
603 current source.
604
605 \list
606 \li PositionSource.NoPositioningMethods - No positioning method is preferred.
607 \li PositionSource.SatellitePositioningMethods - Satellite-based positioning methods such as GPS should be preferred.
608 \li PositionSource.NonSatellitePositioningMethods - Non-satellite-based methods should be preferred.
609 \li PositionSource.AllPositioningMethods - Any positioning methods are acceptable.
610 \endlist
611
612*/
613
614void QDeclarativePositionSource::setPreferredPositioningMethods(PositioningMethods methods)
615{
616 if (m_positionSource) {
617 PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods();
618
619 m_preferredPositioningMethods = methods;
620
621 if (previousPreferredPositioningMethods != methods) {
622 m_positionSource->setPreferredPositioningMethods(
623 static_cast<QGeoPositionInfoSource::PositioningMethods>(int(methods)));
624 if (previousPreferredPositioningMethods != m_positionSource->preferredPositioningMethods())
625 emit preferredPositioningMethodsChanged();
626 }
627 } else {
628 if (m_preferredPositioningMethods != methods) {
629 m_preferredPositioningMethods = methods;
630 emit preferredPositioningMethodsChanged();
631 }
632 }
633}
634
635QDeclarativePositionSource::PositioningMethods QDeclarativePositionSource::preferredPositioningMethods() const
636{
637 if (m_positionSource) {
638 return static_cast<QDeclarativePositionSource::PositioningMethods>(
639 int(m_positionSource->preferredPositioningMethods()));
640 }
641 return m_preferredPositioningMethods;
642}
643
644/*!
645 \qmlmethod PositionSource::start()
646
647 Requests updates from the location source.
648 Uses \l updateInterval if set, default interval otherwise.
649 If there is no source available, this method has no effect.
650
651 \sa stop, update, active
652*/
653
654void QDeclarativePositionSource::start()
655{
656 if (m_positionSource)
657 m_positionSource->startUpdates();
658
659 if (!m_active) {
660 m_active = true;
661 emit activeChanged();
662 }
663}
664
665/*!
666 \qmlmethod PositionSource::update()
667
668 A convenience method to request single update from the location source.
669 If there is no source available, this method has no effect.
670
671 If the position source is not active, it will be activated for as
672 long as it takes to receive an update, or until the request times
673 out. The request timeout period is source-specific.
674
675 \sa start, stop, active
676*/
677
678void QDeclarativePositionSource::update()
679{
680 if (m_positionSource) {
681 if (!m_active) {
682 m_active = true;
683 m_singleUpdate = true;
684 emit activeChanged();
685 }
686 // Use default timeout value. Set active before calling the
687 // update request because on some platforms there may
688 // be results immediately.
689 m_positionSource->requestUpdate();
690 }
691}
692
693/*!
694 \qmlmethod PositionSource::stop()
695
696 Stops updates from the location source.
697 If there is no source available or it is not active,
698 this method has no effect.
699
700 \sa start, update, active
701*/
702
703void QDeclarativePositionSource::stop()
704{
705 if (m_positionSource) {
706 m_positionSource->stopUpdates();
707 if (m_active) {
708 m_active = false;
709 emit activeChanged();
710 }
711 }
712}
713
714/*!
715 \qmlproperty bool PositionSource::active
716
717 This property indicates whether the position source is active.
718 Setting this property to false equals calling \l stop, and
719 setting this property true equals calling \l start.
720
721 \sa start, stop, update
722*/
723void QDeclarativePositionSource::setActive(bool active)
724{
725 if (active == m_active)
726 return;
727
728 if (active)
729 QTimer::singleShot(msec: 0, receiver: this, SLOT(start())); // delay ensures all properties have been set
730 else
731 stop();
732}
733
734bool QDeclarativePositionSource::isActive() const
735{
736 return m_active;
737}
738
739/*!
740 \qmlproperty Position PositionSource::position
741
742 This property holds the last known positional data.
743 It is a read-only property.
744
745 The Position type has different positional member variables,
746 whose validity can be checked with appropriate validity functions
747 (for example sometimes an update does not have speed or altitude data).
748
749 However, whenever a \c {positionChanged} signal has been received, at least
750 position::coordinate::latitude, position::coordinate::longitude, and position::timestamp can
751 be assumed to be valid.
752
753 \sa start, stop, update
754*/
755
756QDeclarativePosition *QDeclarativePositionSource::position()
757{
758 return &m_position;
759}
760
761void QDeclarativePositionSource::positionUpdateReceived(const QGeoPositionInfo &update)
762{
763 setPosition(update);
764
765 if (m_singleUpdate && m_active) {
766 m_active = false;
767 m_singleUpdate = false;
768 emit activeChanged();
769 }
770}
771
772
773/*!
774 \qmlproperty enumeration PositionSource::sourceError
775
776 This property holds the error which last occurred with the PositionSource.
777
778 \list
779 \li PositionSource.AccessError - The connection setup to the remote positioning backend failed because the
780 application lacked the required privileges.
781 \li PositionSource.ClosedError - The positioning backend closed the connection, which happens for example in case
782 the user is switching location services to off. As soon as the location service is re-enabled
783 regular updates will resume.
784 \li PositionSource.NoError - No error has occurred.
785 \li PositionSource.UnknownSourceError - An unidentified error occurred.
786 \li PositionSource.SocketError - An error occurred while connecting to an nmea source using a socket.
787 \endlist
788
789*/
790
791QDeclarativePositionSource::SourceError QDeclarativePositionSource::sourceError() const
792{
793 return m_sourceError;
794}
795
796QGeoPositionInfoSource *QDeclarativePositionSource::positionSource() const
797{
798 return m_positionSource;
799}
800
801/*!
802 \qmlproperty list<PluginParameter> PositionSource::parameters
803 \default
804
805 This property holds the list of plugin parameters.
806
807 \since QtPositioning 5.14
808*/
809QQmlListProperty<QDeclarativePluginParameter> QDeclarativePositionSource::parameters()
810{
811 return QQmlListProperty<QDeclarativePluginParameter>(this,
812 0,
813 parameter_append,
814 parameter_count,
815 parameter_at,
816 parameter_clear);
817}
818
819/*!
820 \internal
821*/
822void QDeclarativePositionSource::parameter_append(QQmlListProperty<QDeclarativePluginParameter> *prop, QDeclarativePluginParameter *parameter)
823{
824 QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object);
825 p->m_parameters.append(t: parameter);
826}
827
828/*!
829 \internal
830*/
831int QDeclarativePositionSource::parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop)
832{
833 return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters.count();
834}
835
836/*!
837 \internal
838*/
839QDeclarativePluginParameter *QDeclarativePositionSource::parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, int index)
840{
841 return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters[index];
842}
843
844/*!
845 \internal
846*/
847void QDeclarativePositionSource::parameter_clear(QQmlListProperty<QDeclarativePluginParameter> *prop)
848{
849 QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object);
850 p->m_parameters.clear();
851}
852
853
854void QDeclarativePositionSource::componentComplete()
855{
856 m_componentComplete = true;
857 m_parametersInitialized = true;
858 for (QDeclarativePluginParameter *p: qAsConst(t&: m_parameters)) {
859 if (!p->isInitialized()) {
860 m_parametersInitialized = false;
861 connect(sender: p, signal: &QDeclarativePluginParameter::initialized,
862 receiver: this, slot: &QDeclarativePositionSource::onParameterInitialized);
863 }
864 }
865
866 if (m_parametersInitialized)
867 tryAttach(newName: m_providerName);
868}
869
870/*!
871 \qmlmethod bool QtLocation::PositionSource::setBackendProperty(string name, Variant value)
872
873 Sets the backend-specific property named \a name to \a value.
874 Returns true on success, false otherwise, including if called on an uninitialized PositionSource.
875 Supported backend-specific properties are listed and described in
876 \l {Qt Positioning plugins#Default plugins}.
877
878 \since Qt Positioning 5.14
879
880 \sa backendProperty, QGeoPositionInfoSource::setBackendProperty
881*/
882bool QDeclarativePositionSource::setBackendProperty(const QString &name, const QVariant &value)
883{
884 if (m_positionSource)
885 return m_positionSource->setBackendProperty(name, value);
886 return false;
887}
888
889/*!
890 \qmlmethod Variant QtLocation::PositionSource::backendProperty(string name)
891
892 Returns the value of the backend-specific property named \a name, if present.
893 Otherwise, including if called on an uninitialized PositionSource, the return value will be invalid.
894 Supported backend-specific properties are listed and described in
895 \l {Qt Positioning plugins#Default plugins}.
896
897 \since Qt Positioning 5.14
898
899 \sa backendProperty, QGeoPositionInfoSource::setBackendProperty
900*/
901QVariant QDeclarativePositionSource::backendProperty(const QString &name) const
902{
903 if (m_positionSource)
904 return m_positionSource->backendProperty(name);
905 return QVariant();
906}
907
908/*!
909 \internal
910*/
911void QDeclarativePositionSource::sourceErrorReceived(const QGeoPositionInfoSource::Error error)
912{
913 if (error == QGeoPositionInfoSource::AccessError)
914 m_sourceError = QDeclarativePositionSource::AccessError;
915 else if (error == QGeoPositionInfoSource::ClosedError)
916 m_sourceError = QDeclarativePositionSource::ClosedError;
917 else if (error == QGeoPositionInfoSource::NoError)
918 return; //nothing to do
919 else
920 m_sourceError = QDeclarativePositionSource::UnknownSourceError;
921
922 emit sourceErrorChanged();
923}
924
925QT_END_NAMESPACE
926

source code of qtlocation/src/positioningquick/qdeclarativepositionsource.cpp