Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdeclarativepositionsource.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <QtCore/QCoreApplication>
8#include <QtQml/qqmlinfo.h>
9#include <QtQml/qqml.h>
10#include <qdeclarativepluginparameter_p.h>
11#include <QFile>
12#include <QtNetwork/QTcpSocket>
13#include <QTimer>
14
15QT_BEGIN_NAMESPACE
16
17/*!
18 \qmltype PositionSource
19 //! \nativetype QDeclarativePositionSource
20 \inqmlmodule QtPositioning
21 \since 5.2
22
23 \brief The PositionSource type provides the device's current position.
24
25 The PositionSource type provides information about the user device's
26 current position. The position is available as a \l{Position} type, which
27 contains all the standard parameters typically available from GPS and other
28 similar systems, including longitude, latitude, speed and accuracy details.
29
30 As different position sources are available on different platforms and
31 devices, these are categorized by their basic type (Satellite, NonSatellite,
32 and AllPositioningMethods). The available methods for the current platform
33 can be enumerated in the \l{supportedPositioningMethods} property.
34
35 To indicate which methods are suitable for your application, set the
36 \l{preferredPositioningMethods} property. If the preferred methods are not
37 available, the default source of location data for the platform will be
38 chosen instead. If no default source is available (because none are installed
39 for the runtime platform, or because it is disabled), the \l{valid} property
40 will be set to false.
41
42 The \l updateInterval property can then be used to indicate how often your
43 application wishes to receive position updates. The \l{start}(),
44 \l{stop}() and \l{update}() methods can be used to control the operation
45 of the PositionSource, as well as the \l{active} property, which when set
46 is equivalent to calling \l{start}() or \l{stop}().
47
48 When the PositionSource is active, position updates can be retrieved
49 either by simply using the \l{position} property in a binding (as the
50 value of another item's property), or by providing an implementation of
51 the \c {onPositionChanged} signal-handler.
52
53 \section2 Example Usage
54
55 The following example shows a simple PositionSource used to receive
56 updates every second and print the longitude and latitude out to
57 the console.
58
59 \code
60 PositionSource {
61 id: src
62 updateInterval: 1000
63 active: true
64
65 onPositionChanged: {
66 var coord = src.position.coordinate;
67 console.log("Coordinate:", coord.longitude, coord.latitude);
68 }
69 }
70 \endcode
71
72 \section2 Controlling Operation State
73
74 As it's mentioned above, PositionSource provides two ways to control its
75 operation state:
76
77 \list
78 \li By using the \l active \l {Qt Bindable Properties}{bindable} property.
79 \li By using \l start() and \l stop() methods.
80 \endlist
81
82 \note It's very important not to mix these approaches. If a bindable
83 \l active property is used to control the PositionSource object, but later
84 \l start() or \l stop() is called from the other part of the code, the
85 binding is broken, which may result in, for example, a UI element that is
86 not connected to any underlying object anymore.
87
88 Consider the following example of \b {bad code} where the \c active property
89 is bound to the CheckBox state, and calling \l stop() in the \c onClicked
90 signal handler breaks that binding.
91
92 \qml
93 Window {
94 width: 640
95 height: 480
96 visible: true
97
98 PositionSource {
99 id: posSource
100 name: "geoclue2"
101 active: cb.checked
102 }
103
104 Column {
105 anchors.centerIn: parent
106 spacing: 20
107 CheckBox {
108 id: cb
109 }
110 Button {
111 id: btn
112 text: "Stop"
113 onClicked: {
114 posSource.stop()
115 }
116 }
117 }
118 }
119 \endqml
120
121 Once the \e Stop button is clicked, \l stop() is executed, and the binding
122 for the \l active property is broken. At this point the CheckBox UI element
123 is no longer controlling the PositionSource object.
124
125 A straightforward fix in this case is to update the CheckBox state from
126 the \c onClicked handler. As soon as the CheckBox is unchecked, the
127 \l active property will be notified, and the PositionSource object's state
128 will update accordingly. The UI will also be in a consistent state.
129
130 \qml
131 Button {
132 id: btn
133 text: "Stop"
134 onClicked: {
135 cb.checked = false
136 }
137 }
138 \endqml
139
140 \note Using \l update() to request a single position update \e {does not}
141 have any effect on the \l active property's bindings, so they can be used
142 together without any problems.
143
144 \sa {QtPositioning::Position}, {QGeoPositionInfoSource}, {PluginParameter},
145 {Qt Bindable Properties}
146
147*/
148
149QDeclarativePositionSource::QDeclarativePositionSource()
150 : m_singleUpdate(0), m_regularUpdates(0), m_componentComplete(0),
151 m_parametersInitialized(0), m_startRequested(0), m_defaultSourceUsed(0)
152{
153 m_position.setValueBypassingBindings(new QDeclarativePosition(this));
154}
155
156QDeclarativePositionSource::~QDeclarativePositionSource()
157{
158 delete m_positionSource;
159}
160
161
162/*!
163 \qmlproperty string PositionSource::name
164
165 This property holds the unique internal name for the plugin currently
166 providing position information.
167
168 Setting the property causes the PositionSource to use a particular positioning provider. If
169 the PositionSource is active at the time that the name property is changed, it will become
170 inactive. If the specified positioning provider cannot be loaded the position source will
171 become invalid.
172
173 Changing the name property may cause the \l {updateInterval}, \l {supportedPositioningMethods}
174 and \l {preferredPositioningMethods} properties to change as well.
175*/
176
177
178QString QDeclarativePositionSource::name() const
179{
180 return m_sourceName;
181}
182
183void QDeclarativePositionSource::setName(const QString &newName)
184{
185 m_sourceName.removeBindingUnlessInWrapper();
186 if (m_positionSource && m_positionSource->sourceName() == newName)
187 return;
188
189 if (newName.isEmpty() && m_defaultSourceUsed)
190 return; // previously attached to a default source, now requesting the same.
191
192 const QString previousName = m_sourceName.valueBypassingBindings();
193
194 if (!m_componentComplete || !m_parametersInitialized) {
195 if (previousName != newName) {
196 m_sourceName.setValueBypassingBindings(newName);
197 m_sourceName.notify();
198 }
199 return;
200 }
201
202 // tryAttach() will update the m_sourceName correctly
203 tryAttach(newName, false);
204}
205
206QBindable<QString> QDeclarativePositionSource::bindableName()
207{
208 return QBindable<QString>(&m_sourceName);
209}
210
211QBindable<QDeclarativePosition *> QDeclarativePositionSource::bindablePosition() const
212{
213 return QBindable<QDeclarativePosition *>(&m_position);
214}
215
216/*!
217 \internal
218*/
219void QDeclarativePositionSource::tryAttach(const QString &newName, bool useFallback)
220{
221 const QString previousName = name();
222 const bool sourceExisted = (m_positionSource != nullptr);
223
224 int previousUpdateInterval = updateInterval();
225 PositioningMethods previousPositioningMethods = supportedPositioningMethods();
226 PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods();
227
228 m_defaultSourceUsed = false;
229
230 if (newName.isEmpty()) {
231 setSource(QGeoPositionInfoSource::createDefaultSource(parameterMap(), this));
232 m_defaultSourceUsed = true;
233 } else {
234 setSource(QGeoPositionInfoSource::createSource(newName, parameterMap(), this));
235 if (!m_positionSource && useFallback) {
236 setSource(QGeoPositionInfoSource::createDefaultSource(parameterMap(), this));
237 m_defaultSourceUsed = true;
238 }
239 }
240
241 if (m_positionSource) {
242 m_sourceName.setValueBypassingBindings(m_positionSource->sourceName());
243
244 connect(m_positionSource, SIGNAL(positionUpdated(QGeoPositionInfo)),
245 this, SLOT(positionUpdateReceived(QGeoPositionInfo)));
246 connect(m_positionSource, SIGNAL(errorOccurred(QGeoPositionInfoSource::Error)),
247 this, SLOT(sourceErrorReceived(QGeoPositionInfoSource::Error)));
248
249 m_positionSource->setUpdateInterval(m_updateInterval);
250 m_positionSource->setPreferredPositioningMethods(
251 static_cast<QGeoPositionInfoSource::PositioningMethods>(int(m_preferredPositioningMethods)));
252
253 if (m_startRequested) {
254 const QGeoPositionInfo &lastKnown = m_positionSource->lastKnownPosition();
255 if (lastKnown.isValid())
256 setPosition(lastKnown);
257 }
258 } else {
259 m_sourceName.setValueBypassingBindings(newName);
260 m_defaultSourceUsed = false;
261 if (m_active) {
262 // We do not want to break the binding here, because we just want to
263 // give the user an opportunity to select another plugin and keep
264 // working.
265 m_active.setValueBypassingBindings(false);
266 m_active.notify();
267 }
268 }
269
270 if (previousUpdateInterval != updateInterval())
271 emit updateIntervalChanged();
272
273 if (previousPreferredPositioningMethods != preferredPositioningMethods())
274 emit preferredPositioningMethodsChanged();
275
276 if (previousPositioningMethods != supportedPositioningMethods())
277 notifySupportedPositioningMethodsChanged();
278
279 const bool sourceCurrentlyExists = (m_positionSource != nullptr);
280 if (sourceExisted != sourceCurrentlyExists) {
281 m_isValid.notify();
282 emit validityChanged();
283 }
284
285 if (m_active) { // implies m_positionSource
286 // If m_active is true, then the previous position source existed!
287 Q_ASSERT(sourceExisted);
288 // New source is set. It should be inactive by default.
289 // But we do not want to break the binding.
290 m_active.setValueBypassingBindings(false);
291 m_active.notify();
292 } else if (m_startRequested) {
293 m_startRequested = false;
294 executeStart();
295 }
296
297 if (previousName != m_sourceName)
298 m_sourceName.notify();
299}
300
301/*!
302 \qmlproperty bool PositionSource::valid
303
304 This property is true if the PositionSource object has acquired a valid
305 backend plugin to provide data. If false, other methods on the PositionSource
306 will have no effect.
307
308 Applications should check this property to determine whether positioning is
309 available and enabled on the runtime platform, and react accordingly.
310*/
311bool QDeclarativePositionSource::isValid() const
312{
313 return m_isValid.value();
314}
315
316QBindable<bool> QDeclarativePositionSource::bindableIsValid() const
317{
318 return QBindable<bool>(&m_isValid);
319}
320
321bool QDeclarativePositionSource::isValidActualComputation() const
322{
323 return m_positionSource != nullptr;
324}
325
326/*!
327 \internal
328*/
329void QDeclarativePositionSource::onParameterInitialized()
330{
331 m_parametersInitialized = true;
332 for (QDeclarativePluginParameter *p: std::as_const(m_parameters)) {
333 if (!p->isInitialized()) {
334 m_parametersInitialized = false;
335 break;
336 }
337 }
338
339 // If here, componentComplete has been called.
340 if (m_parametersInitialized)
341 tryAttach(m_sourceName.value());
342}
343
344void QDeclarativePositionSource::notifySupportedPositioningMethodsChanged()
345{
346 m_supportedPositioningMethods.notify();
347 emit supportedPositioningMethodsChanged();
348}
349
350void QDeclarativePositionSource::setPosition(const QGeoPositionInfo &pi)
351{
352 m_position.value()->setPosition(pi);
353 m_position.notify();
354 emit positionChanged();
355}
356
357void QDeclarativePositionSource::setSource(QGeoPositionInfoSource *source)
358{
359 if (m_positionSource)
360 delete m_positionSource;
361
362 if (!source) {
363 m_positionSource = nullptr;
364 } else {
365 m_positionSource = source;
366 connect(m_positionSource, &QGeoPositionInfoSource::supportedPositioningMethodsChanged,
367 this, &QDeclarativePositionSource::notifySupportedPositioningMethodsChanged);
368 }
369}
370
371bool QDeclarativePositionSource::parametersReady()
372{
373 for (const QDeclarativePluginParameter *p: std::as_const(m_parameters)) {
374 if (!p->isInitialized())
375 return false;
376 }
377 return true;
378}
379
380/*!
381 \internal
382*/
383QVariantMap QDeclarativePositionSource::parameterMap() const
384{
385 QVariantMap map;
386
387 for (const auto *parameter : m_parameters)
388 map.insert(parameter->name(), parameter->value());
389
390 return map;
391}
392
393/*!
394 \internal
395*/
396void QDeclarativePositionSource::setUpdateInterval(int updateInterval)
397{
398 if (m_positionSource) {
399 int previousUpdateInterval = m_positionSource->updateInterval();
400
401 m_updateInterval = updateInterval;
402
403 if (previousUpdateInterval != updateInterval) {
404 m_positionSource->setUpdateInterval(updateInterval);
405 if (previousUpdateInterval != m_positionSource->updateInterval())
406 emit updateIntervalChanged();
407 }
408 } else {
409 if (m_updateInterval != updateInterval) {
410 m_updateInterval = updateInterval;
411 emit updateIntervalChanged();
412 }
413 }
414}
415
416/*!
417 \qmlproperty int PositionSource::updateInterval
418
419 This property holds the desired interval between updates (milliseconds).
420
421 \sa {QGeoPositionInfoSource::updateInterval()}
422*/
423
424int QDeclarativePositionSource::updateInterval() const
425{
426 if (!m_positionSource)
427 return m_updateInterval;
428
429 return m_positionSource->updateInterval();
430}
431
432/*!
433 \qmlproperty enumeration PositionSource::supportedPositioningMethods
434
435 This property holds the supported positioning methods of the
436 current source.
437
438 \value PositionSource.NoPositioningMethods
439 No positioning methods supported (no source).
440 \value PositionSource.SatellitePositioningMethods
441 Satellite-based positioning methods such as GPS are supported.
442 \value PositionSource.NonSatellitePositioningMethods
443 Non-satellite-based methods are supported.
444 \value PositionSource.AllPositioningMethods
445 Both satellite-based and non-satellite positioning methods are supported.
446*/
447
448QDeclarativePositionSource::PositioningMethods
449QDeclarativePositionSource::supportedPositioningMethods() const
450{
451 return m_supportedPositioningMethods.value();
452}
453
454QDeclarativePositionSource::PositioningMethods
455QDeclarativePositionSource::supportedMethodsActualComputation() const
456{
457 if (m_positionSource) {
458 return static_cast<QDeclarativePositionSource::PositioningMethods>(
459 int(m_positionSource->supportedPositioningMethods()));
460 }
461 return QDeclarativePositionSource::NoPositioningMethods;
462}
463
464QBindable<QDeclarativePositionSource::PositioningMethods>
465QDeclarativePositionSource::bindableSupportedPositioningMethods() const
466{
467 return QBindable<PositioningMethods>(&m_supportedPositioningMethods);
468}
469
470/*!
471 \qmlproperty enumeration PositionSource::preferredPositioningMethods
472
473 This property holds the preferred positioning methods of the
474 current source.
475
476 \value PositionSource.NoPositioningMethods
477 No positioning method is preferred.
478 \value PositionSource.SatellitePositioningMethods
479 Satellite-based positioning methods such as GPS should be preferred.
480 \value PositionSource.NonSatellitePositioningMethods
481 Non-satellite-based methods should be preferred.
482 \value PositionSource.AllPositioningMethods
483 Any positioning methods are acceptable.
484*/
485
486void QDeclarativePositionSource::setPreferredPositioningMethods(PositioningMethods methods)
487{
488 if (m_positionSource) {
489 PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods();
490
491 m_preferredPositioningMethods = methods;
492
493 if (previousPreferredPositioningMethods != methods) {
494 m_positionSource->setPreferredPositioningMethods(
495 static_cast<QGeoPositionInfoSource::PositioningMethods>(int(methods)));
496 if (previousPreferredPositioningMethods != m_positionSource->preferredPositioningMethods())
497 emit preferredPositioningMethodsChanged();
498 }
499 } else {
500 if (m_preferredPositioningMethods != methods) {
501 m_preferredPositioningMethods = methods;
502 emit preferredPositioningMethodsChanged();
503 }
504 }
505}
506
507QDeclarativePositionSource::PositioningMethods QDeclarativePositionSource::preferredPositioningMethods() const
508{
509 if (m_positionSource) {
510 return static_cast<QDeclarativePositionSource::PositioningMethods>(
511 int(m_positionSource->preferredPositioningMethods()));
512 }
513 return m_preferredPositioningMethods;
514}
515
516/*!
517 \qmlmethod PositionSource::start()
518
519 Requests updates from the location source.
520 Uses \l updateInterval if set, default interval otherwise.
521 If there is no source available, this method has no effect.
522
523 \note Calling this method breaks the bindings of
524 \l {PositionSource::}{active} property.
525
526 \sa stop, update, active
527*/
528
529void QDeclarativePositionSource::start()
530{
531 if (m_positionSource) {
532 m_active.removeBindingUnlessInWrapper();
533 executeStart();
534 }
535}
536
537/*!
538 \qmlmethod PositionSource::update(int timeout)
539
540 A convenience method to request single update from the location source.
541 If there is no source available, this method has no effect.
542
543 If the position source is not active, it will be activated for as
544 long as it takes to receive an update, or until the request times
545 out. The request timeout period is source-specific.
546
547 The \a timeout is specified in milliseconds. If the \a timeout is zero
548 (the default value), it defaults to a reasonable timeout period as
549 appropriate for the source.
550
551 \sa start, stop, active
552*/
553
554void QDeclarativePositionSource::update(int timeout)
555{
556 if (m_positionSource) {
557 m_singleUpdate = true;
558 if (!m_active) {
559 // Questionable: we do not want this method to break the binding.
560 // Mostly because it can be called while the updates are already
561 // running.
562 m_active.setValueBypassingBindings(true);
563 m_active.notify();
564 }
565 // Use default timeout value. Set active before calling the
566 // update request because on some platforms there may
567 // be results immediately.
568 m_positionSource->requestUpdate(timeout);
569 }
570}
571
572/*!
573 \qmlmethod PositionSource::stop()
574
575 Stops updates from the location source.
576 If there is no source available or it is not active,
577 this method has no effect.
578
579 \note Calling this method breaks the bindings of
580 \l {PositionSource::}{active} property.
581
582 \sa start, update, active
583*/
584
585void QDeclarativePositionSource::stop()
586{
587 if (m_positionSource) {
588 m_positionSource->stopUpdates();
589 m_regularUpdates = false;
590 // Try to break the binding even if we do not actually need to update
591 // the active state. The m_active can be updated later, when the
592 // single update request finishes.
593 m_active.removeBindingUnlessInWrapper();
594 if (m_active && !m_singleUpdate) {
595 m_active.setValueBypassingBindings(false);
596 m_active.notify();
597 }
598 }
599}
600
601/*!
602 \qmlproperty bool PositionSource::active
603
604 This property indicates whether the position source is active.
605 Setting this property to false equals calling \l stop, and
606 setting this property true equals calling \l start.
607
608 \sa start, stop, update
609*/
610void QDeclarativePositionSource::setActive(bool active)
611{
612 // We need to remove binding, if this method is called explicitly.
613 // Other changes to m_active are done inside start() and stop() methods.
614 m_active.removeBindingUnlessInWrapper();
615 if (active == m_active)
616 return;
617
618 if (active) {
619 // If the component is not completed yet, we need to defer the
620 // actual executeStart() call until everything is set up.
621 if (m_componentComplete && m_parametersInitialized)
622 executeStart();
623 else
624 m_startRequested = true;
625 } else {
626 stop();
627 }
628}
629
630bool QDeclarativePositionSource::isActive() const
631{
632 return m_active;
633}
634
635/*!
636 \qmlproperty Position PositionSource::position
637
638 This property holds the last known positional data.
639 It is a read-only property.
640
641 The Position type has different positional member variables,
642 whose validity can be checked with appropriate validity functions
643 (for example sometimes an update does not have speed or altitude data).
644
645 However, whenever a \c {positionChanged} signal has been received, at least
646 position::coordinate::latitude, position::coordinate::longitude, and position::timestamp can
647 be assumed to be valid.
648
649 \sa start, stop, update
650*/
651
652QDeclarativePosition *QDeclarativePositionSource::position()
653{
654 return m_position.value();
655}
656
657void QDeclarativePositionSource::positionUpdateReceived(const QGeoPositionInfo &update)
658{
659 setPosition(update);
660
661 if (m_singleUpdate && m_active) {
662 // we need to reset m_singleUpdate because we got one
663 m_singleUpdate = false;
664 if (!m_regularUpdates) {
665 // but we change the active state only if the regular updates are
666 // also stopped
667 m_active.setValueBypassingBindings(false);
668 m_active.notify();
669 }
670 }
671}
672
673
674/*!
675 \qmlproperty enumeration PositionSource::sourceError
676
677 This property holds the error which last occurred with the PositionSource.
678
679 \value PositionSource.AccessError
680 The connection setup to the remote positioning backend failed because the
681 application lacked the required privileges.
682 \value PositionSource.ClosedError
683 The positioning backend closed the connection, which happens for example in case
684 the user is switching location services to off. As soon as the location service is re-enabled
685 regular updates will resume.
686 \value PositionSource.NoError No error has occurred.
687 \value PositionSource.UnknownSourceError An unidentified error occurred.
688 \value PositionSource.UpdateTimeoutError
689 The current position could not be
690 retrieved within the specified timeout, or this PositionSource determined
691 that it will not be able to provide further regular updates.
692*/
693
694QDeclarativePositionSource::SourceError QDeclarativePositionSource::sourceError() const
695{
696 return m_sourceError;
697}
698
699QBindable<QDeclarativePositionSource::SourceError>
700QDeclarativePositionSource::bindableSourceError() const
701{
702 return QBindable<QDeclarativePositionSource::SourceError>(&m_sourceError);
703}
704
705QGeoPositionInfoSource *QDeclarativePositionSource::positionSource() const
706{
707 return m_positionSource;
708}
709
710/*!
711 \qmlproperty list<PluginParameter> PositionSource::parameters
712 \qmldefault
713
714 This property holds the list of plugin parameters.
715
716 \since QtPositioning 5.14
717*/
718QQmlListProperty<QDeclarativePluginParameter> QDeclarativePositionSource::parameters()
719{
720 return QQmlListProperty<QDeclarativePluginParameter>(this,
721 0,
722 parameter_append,
723 parameter_count,
724 parameter_at,
725 parameter_clear);
726}
727
728/*!
729 \internal
730*/
731void QDeclarativePositionSource::parameter_append(QQmlListProperty<QDeclarativePluginParameter> *prop, QDeclarativePluginParameter *parameter)
732{
733 QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object);
734 p->m_parameters.append(parameter);
735}
736
737/*!
738 \internal
739*/
740qsizetype QDeclarativePositionSource::parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop)
741{
742 return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters.size();
743}
744
745/*!
746 \internal
747*/
748QDeclarativePluginParameter *QDeclarativePositionSource::parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, qsizetype index)
749{
750 return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters[index];
751}
752
753/*!
754 \internal
755*/
756void QDeclarativePositionSource::parameter_clear(QQmlListProperty<QDeclarativePluginParameter> *prop)
757{
758 QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object);
759 p->m_parameters.clear();
760}
761
762void QDeclarativePositionSource::executeStart()
763{
764 if (m_positionSource) {
765 m_positionSource->startUpdates();
766
767 // If this method is called directly from start(), the binding is
768 // already broken there (for the consistency with stop()).
769 // If this method is called by a timer, started in setActive(), we do
770 // not need to break the binding, because it was already done (if
771 // needed).
772
773 m_regularUpdates = true;
774 if (!m_active) {
775 m_active.setValueBypassingBindings(true);
776 m_active.notify();
777 }
778 }
779}
780
781void QDeclarativePositionSource::componentComplete()
782{
783 m_componentComplete = true;
784 m_parametersInitialized = true;
785 for (QDeclarativePluginParameter *p: std::as_const(m_parameters)) {
786 if (!p->isInitialized()) {
787 m_parametersInitialized = false;
788 connect(p, &QDeclarativePluginParameter::initialized,
789 this, &QDeclarativePositionSource::onParameterInitialized,
790 Qt::SingleShotConnection);
791 }
792 }
793
794 if (m_parametersInitialized)
795 tryAttach(m_sourceName.value());
796}
797
798/*!
799 \qmlmethod bool PositionSource::setBackendProperty(string name, Variant value)
800
801 Sets the backend-specific property named \a name to \a value.
802 Returns true on success, false otherwise, including if called on an uninitialized PositionSource.
803 Supported backend-specific properties are listed and described in
804 \l {Qt Positioning plugins#Default plugins}.
805
806 \since Qt Positioning 5.14
807
808 \sa backendProperty, QGeoPositionInfoSource::setBackendProperty
809*/
810bool QDeclarativePositionSource::setBackendProperty(const QString &name, const QVariant &value)
811{
812 if (m_positionSource)
813 return m_positionSource->setBackendProperty(name, value);
814 return false;
815}
816
817/*!
818 \qmlmethod Variant PositionSource::backendProperty(string name)
819
820 Returns the value of the backend-specific property named \a name, if present.
821 Otherwise, including if called on an uninitialized PositionSource, the return value will be invalid.
822 Supported backend-specific properties are listed and described in
823 \l {Qt Positioning plugins#Default plugins}.
824
825 \since Qt Positioning 5.14
826
827 \sa setBackendProperty, QGeoPositionInfoSource::setBackendProperty
828*/
829QVariant QDeclarativePositionSource::backendProperty(const QString &name) const
830{
831 if (m_positionSource)
832 return m_positionSource->backendProperty(name);
833 return QVariant();
834}
835
836QBindable<bool> QDeclarativePositionSource::bindableActive()
837{
838 return QBindable<bool>(&m_active);
839}
840
841/*!
842 \internal
843*/
844void QDeclarativePositionSource::sourceErrorReceived(const QGeoPositionInfoSource::Error error)
845{
846 if (error == QGeoPositionInfoSource::AccessError)
847 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::AccessError);
848 else if (error == QGeoPositionInfoSource::ClosedError)
849 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::ClosedError);
850 else if (error == QGeoPositionInfoSource::UpdateTimeoutError)
851 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::UpdateTimeoutError);
852 else if (error == QGeoPositionInfoSource::NoError)
853 return; //nothing to do
854 else
855 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::UnknownSourceError);
856
857 m_sourceError.notify();
858 emit sourceErrorChanged();
859
860 // if an error occurred during single update, the update is stopped, so we
861 // need to change the active state.
862 if (m_active && m_singleUpdate) {
863 m_singleUpdate = false;
864 if (!m_regularUpdates) {
865 m_active.setValueBypassingBindings(false);
866 m_active.notify();
867 }
868 }
869}
870
871QT_END_NAMESPACE
872
873#include "moc_qdeclarativepositionsource_p.cpp"