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 \list
439 \li PositionSource.NoPositioningMethods - No positioning methods supported (no source).
440 \li PositionSource.SatellitePositioningMethods - Satellite-based positioning methods such as GPS are supported.
441 \li PositionSource.NonSatellitePositioningMethods - Non-satellite-based methods are supported.
442 \li PositionSource.AllPositioningMethods - Both satellite-based and non-satellite positioning methods are supported.
443 \endlist
444
445*/
446
447QDeclarativePositionSource::PositioningMethods
448QDeclarativePositionSource::supportedPositioningMethods() const
449{
450 return m_supportedPositioningMethods.value();
451}
452
453QDeclarativePositionSource::PositioningMethods
454QDeclarativePositionSource::supportedMethodsActualComputation() const
455{
456 if (m_positionSource) {
457 return static_cast<QDeclarativePositionSource::PositioningMethods>(
458 int(m_positionSource->supportedPositioningMethods()));
459 }
460 return QDeclarativePositionSource::NoPositioningMethods;
461}
462
463QBindable<QDeclarativePositionSource::PositioningMethods>
464QDeclarativePositionSource::bindableSupportedPositioningMethods() const
465{
466 return QBindable<PositioningMethods>(&m_supportedPositioningMethods);
467}
468
469/*!
470 \qmlproperty enumeration PositionSource::preferredPositioningMethods
471
472 This property holds the preferred positioning methods of the
473 current source.
474
475 \list
476 \li PositionSource.NoPositioningMethods - No positioning method is preferred.
477 \li PositionSource.SatellitePositioningMethods - Satellite-based positioning methods such as GPS should be preferred.
478 \li PositionSource.NonSatellitePositioningMethods - Non-satellite-based methods should be preferred.
479 \li PositionSource.AllPositioningMethods - Any positioning methods are acceptable.
480 \endlist
481
482*/
483
484void QDeclarativePositionSource::setPreferredPositioningMethods(PositioningMethods methods)
485{
486 if (m_positionSource) {
487 PositioningMethods previousPreferredPositioningMethods = preferredPositioningMethods();
488
489 m_preferredPositioningMethods = methods;
490
491 if (previousPreferredPositioningMethods != methods) {
492 m_positionSource->setPreferredPositioningMethods(
493 static_cast<QGeoPositionInfoSource::PositioningMethods>(int(methods)));
494 if (previousPreferredPositioningMethods != m_positionSource->preferredPositioningMethods())
495 emit preferredPositioningMethodsChanged();
496 }
497 } else {
498 if (m_preferredPositioningMethods != methods) {
499 m_preferredPositioningMethods = methods;
500 emit preferredPositioningMethodsChanged();
501 }
502 }
503}
504
505QDeclarativePositionSource::PositioningMethods QDeclarativePositionSource::preferredPositioningMethods() const
506{
507 if (m_positionSource) {
508 return static_cast<QDeclarativePositionSource::PositioningMethods>(
509 int(m_positionSource->preferredPositioningMethods()));
510 }
511 return m_preferredPositioningMethods;
512}
513
514/*!
515 \qmlmethod PositionSource::start()
516
517 Requests updates from the location source.
518 Uses \l updateInterval if set, default interval otherwise.
519 If there is no source available, this method has no effect.
520
521 \note Calling this method breaks the bindings of
522 \l {PositionSource::}{active} property.
523
524 \sa stop, update, active
525*/
526
527void QDeclarativePositionSource::start()
528{
529 if (m_positionSource) {
530 m_active.removeBindingUnlessInWrapper();
531 executeStart();
532 }
533}
534
535/*!
536 \qmlmethod PositionSource::update(int timeout)
537
538 A convenience method to request single update from the location source.
539 If there is no source available, this method has no effect.
540
541 If the position source is not active, it will be activated for as
542 long as it takes to receive an update, or until the request times
543 out. The request timeout period is source-specific.
544
545 The \a timeout is specified in milliseconds. If the \a timeout is zero
546 (the default value), it defaults to a reasonable timeout period as
547 appropriate for the source.
548
549 \sa start, stop, active
550*/
551
552void QDeclarativePositionSource::update(int timeout)
553{
554 if (m_positionSource) {
555 m_singleUpdate = true;
556 if (!m_active) {
557 // Questionable: we do not want this method to break the binding.
558 // Mostly because it can be called while the updates are already
559 // running.
560 m_active.setValueBypassingBindings(true);
561 m_active.notify();
562 }
563 // Use default timeout value. Set active before calling the
564 // update request because on some platforms there may
565 // be results immediately.
566 m_positionSource->requestUpdate(timeout);
567 }
568}
569
570/*!
571 \qmlmethod PositionSource::stop()
572
573 Stops updates from the location source.
574 If there is no source available or it is not active,
575 this method has no effect.
576
577 \note Calling this method breaks the bindings of
578 \l {PositionSource::}{active} property.
579
580 \sa start, update, active
581*/
582
583void QDeclarativePositionSource::stop()
584{
585 if (m_positionSource) {
586 m_positionSource->stopUpdates();
587 m_regularUpdates = false;
588 // Try to break the binding even if we do not actually need to update
589 // the active state. The m_active can be updated later, when the
590 // single update request finishes.
591 m_active.removeBindingUnlessInWrapper();
592 if (m_active && !m_singleUpdate) {
593 m_active.setValueBypassingBindings(false);
594 m_active.notify();
595 }
596 }
597}
598
599/*!
600 \qmlproperty bool PositionSource::active
601
602 This property indicates whether the position source is active.
603 Setting this property to false equals calling \l stop, and
604 setting this property true equals calling \l start.
605
606 \sa start, stop, update
607*/
608void QDeclarativePositionSource::setActive(bool active)
609{
610 // We need to remove binding, if this method is called explicitly.
611 // Other changes to m_active are done inside start() and stop() methods.
612 m_active.removeBindingUnlessInWrapper();
613 if (active == m_active)
614 return;
615
616 if (active) {
617 // If the component is not completed yet, we need to defer the
618 // actual executeStart() call until everything is set up.
619 if (m_componentComplete && m_parametersInitialized)
620 executeStart();
621 else
622 m_startRequested = true;
623 } else {
624 stop();
625 }
626}
627
628bool QDeclarativePositionSource::isActive() const
629{
630 return m_active;
631}
632
633/*!
634 \qmlproperty Position PositionSource::position
635
636 This property holds the last known positional data.
637 It is a read-only property.
638
639 The Position type has different positional member variables,
640 whose validity can be checked with appropriate validity functions
641 (for example sometimes an update does not have speed or altitude data).
642
643 However, whenever a \c {positionChanged} signal has been received, at least
644 position::coordinate::latitude, position::coordinate::longitude, and position::timestamp can
645 be assumed to be valid.
646
647 \sa start, stop, update
648*/
649
650QDeclarativePosition *QDeclarativePositionSource::position()
651{
652 return m_position.value();
653}
654
655void QDeclarativePositionSource::positionUpdateReceived(const QGeoPositionInfo &update)
656{
657 setPosition(update);
658
659 if (m_singleUpdate && m_active) {
660 // we need to reset m_singleUpdate because we got one
661 m_singleUpdate = false;
662 if (!m_regularUpdates) {
663 // but we change the active state only if the regular updates are
664 // also stopped
665 m_active.setValueBypassingBindings(false);
666 m_active.notify();
667 }
668 }
669}
670
671
672/*!
673 \qmlproperty enumeration PositionSource::sourceError
674
675 This property holds the error which last occurred with the PositionSource.
676
677 \list
678 \li PositionSource.AccessError - The connection setup to the remote positioning backend failed because the
679 application lacked the required privileges.
680 \li PositionSource.ClosedError - The positioning backend closed the connection, which happens for example in case
681 the user is switching location services to off. As soon as the location service is re-enabled
682 regular updates will resume.
683 \li PositionSource.NoError - No error has occurred.
684 \li PositionSource.UnknownSourceError - An unidentified error occurred.
685 \li PositionSource.UpdateTimeoutError - The current position could not be
686 retrieved within the specified timeout, or this PositionSource determined
687 that it will not be able to provide further regular updates.
688 \endlist
689
690*/
691
692QDeclarativePositionSource::SourceError QDeclarativePositionSource::sourceError() const
693{
694 return m_sourceError;
695}
696
697QBindable<QDeclarativePositionSource::SourceError>
698QDeclarativePositionSource::bindableSourceError() const
699{
700 return QBindable<QDeclarativePositionSource::SourceError>(&m_sourceError);
701}
702
703QGeoPositionInfoSource *QDeclarativePositionSource::positionSource() const
704{
705 return m_positionSource;
706}
707
708/*!
709 \qmlproperty list<PluginParameter> PositionSource::parameters
710 \qmldefault
711
712 This property holds the list of plugin parameters.
713
714 \since QtPositioning 5.14
715*/
716QQmlListProperty<QDeclarativePluginParameter> QDeclarativePositionSource::parameters()
717{
718 return QQmlListProperty<QDeclarativePluginParameter>(this,
719 0,
720 parameter_append,
721 parameter_count,
722 parameter_at,
723 parameter_clear);
724}
725
726/*!
727 \internal
728*/
729void QDeclarativePositionSource::parameter_append(QQmlListProperty<QDeclarativePluginParameter> *prop, QDeclarativePluginParameter *parameter)
730{
731 QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object);
732 p->m_parameters.append(parameter);
733}
734
735/*!
736 \internal
737*/
738qsizetype QDeclarativePositionSource::parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop)
739{
740 return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters.size();
741}
742
743/*!
744 \internal
745*/
746QDeclarativePluginParameter *QDeclarativePositionSource::parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, qsizetype index)
747{
748 return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters[index];
749}
750
751/*!
752 \internal
753*/
754void QDeclarativePositionSource::parameter_clear(QQmlListProperty<QDeclarativePluginParameter> *prop)
755{
756 QDeclarativePositionSource *p = static_cast<QDeclarativePositionSource *>(prop->object);
757 p->m_parameters.clear();
758}
759
760void QDeclarativePositionSource::executeStart()
761{
762 if (m_positionSource) {
763 m_positionSource->startUpdates();
764
765 // If this method is called directly from start(), the binding is
766 // already broken there (for the consistency with stop()).
767 // If this method is called by a timer, started in setActive(), we do
768 // not need to break the binding, because it was already done (if
769 // needed).
770
771 m_regularUpdates = true;
772 if (!m_active) {
773 m_active.setValueBypassingBindings(true);
774 m_active.notify();
775 }
776 }
777}
778
779void QDeclarativePositionSource::componentComplete()
780{
781 m_componentComplete = true;
782 m_parametersInitialized = true;
783 for (QDeclarativePluginParameter *p: std::as_const(m_parameters)) {
784 if (!p->isInitialized()) {
785 m_parametersInitialized = false;
786 connect(p, &QDeclarativePluginParameter::initialized,
787 this, &QDeclarativePositionSource::onParameterInitialized,
788 Qt::SingleShotConnection);
789 }
790 }
791
792 if (m_parametersInitialized)
793 tryAttach(m_sourceName.value());
794}
795
796/*!
797 \qmlmethod bool PositionSource::setBackendProperty(string name, Variant value)
798
799 Sets the backend-specific property named \a name to \a value.
800 Returns true on success, false otherwise, including if called on an uninitialized PositionSource.
801 Supported backend-specific properties are listed and described in
802 \l {Qt Positioning plugins#Default plugins}.
803
804 \since Qt Positioning 5.14
805
806 \sa backendProperty, QGeoPositionInfoSource::setBackendProperty
807*/
808bool QDeclarativePositionSource::setBackendProperty(const QString &name, const QVariant &value)
809{
810 if (m_positionSource)
811 return m_positionSource->setBackendProperty(name, value);
812 return false;
813}
814
815/*!
816 \qmlmethod Variant PositionSource::backendProperty(string name)
817
818 Returns the value of the backend-specific property named \a name, if present.
819 Otherwise, including if called on an uninitialized PositionSource, the return value will be invalid.
820 Supported backend-specific properties are listed and described in
821 \l {Qt Positioning plugins#Default plugins}.
822
823 \since Qt Positioning 5.14
824
825 \sa backendProperty, QGeoPositionInfoSource::setBackendProperty
826*/
827QVariant QDeclarativePositionSource::backendProperty(const QString &name) const
828{
829 if (m_positionSource)
830 return m_positionSource->backendProperty(name);
831 return QVariant();
832}
833
834QBindable<bool> QDeclarativePositionSource::bindableActive()
835{
836 return QBindable<bool>(&m_active);
837}
838
839/*!
840 \internal
841*/
842void QDeclarativePositionSource::sourceErrorReceived(const QGeoPositionInfoSource::Error error)
843{
844 if (error == QGeoPositionInfoSource::AccessError)
845 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::AccessError);
846 else if (error == QGeoPositionInfoSource::ClosedError)
847 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::ClosedError);
848 else if (error == QGeoPositionInfoSource::UpdateTimeoutError)
849 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::UpdateTimeoutError);
850 else if (error == QGeoPositionInfoSource::NoError)
851 return; //nothing to do
852 else
853 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::UnknownSourceError);
854
855 m_sourceError.notify();
856 emit sourceErrorChanged();
857
858 // if an error occurred during single update, the update is stopped, so we
859 // need to change the active state.
860 if (m_active && m_singleUpdate) {
861 m_singleUpdate = false;
862 if (!m_regularUpdates) {
863 m_active.setValueBypassingBindings(false);
864 m_active.notify();
865 }
866 }
867}
868
869QT_END_NAMESPACE
870
871#include "moc_qdeclarativepositionsource_p.cpp"