Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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>
11#include <QFile>
12#include <QtNetwork/QTcpSocket>
13#include <QTimer>
14
16
20
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
157{
158 delete m_positionSource;
159}
160
161
179{
180 return m_sourceName;
181}
182
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
207{
208 return QBindable<QString>(&m_sourceName);
209}
210
211QBindable<QDeclarativePosition *> QDeclarativePositionSource::bindablePosition() const
212{
213 return QBindable<QDeclarativePosition *>(&m_position);
214}
215
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()) {
232 m_defaultSourceUsed = true;
233 } else {
234 setSource(QGeoPositionInfoSource::createSource(newName, parameterMap(), this));
235 if (!m_positionSource && useFallback) {
237 m_defaultSourceUsed = true;
238 }
239 }
240
241 if (m_positionSource) {
242 m_sourceName.setValueBypassingBindings(m_positionSource->sourceName());
243
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())
272
273 if (previousPreferredPositioningMethods != preferredPositioningMethods())
275
276 if (previousPositioningMethods != supportedPositioningMethods())
277 notifySupportedPositioningMethodsChanged();
278
279 const bool sourceCurrentlyExists = (m_positionSource != nullptr);
280 if (sourceExisted != sourceCurrentlyExists) {
281 m_isValid.notify();
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
312{
313 return m_isValid.value();
314}
315
317{
318 return QBindable<bool>(&m_isValid);
319}
320
321bool QDeclarativePositionSource::isValidActualComputation() const
322{
323 return m_positionSource != nullptr;
324}
325
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();
348}
349
350void QDeclarativePositionSource::setPosition(const QGeoPositionInfo &pi)
351{
352 m_position.value()->setPosition(pi);
353 m_position.notify();
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;
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
384{
386
387 for (const auto *parameter : m_parameters)
388 map.insert(parameter->name(), parameter->value());
389
390 return map;
391}
392
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())
407 }
408 } else {
409 if (m_updateInterval != updateInterval) {
410 m_updateInterval = updateInterval;
412 }
413 }
414}
415
425{
426 if (!m_positionSource)
427 return m_updateInterval;
428
429 return m_positionSource->updateInterval();
430}
431
447QDeclarativePositionSource::PositioningMethods
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 }
461}
462
463QBindable<QDeclarativePositionSource::PositioningMethods>
465{
466 return QBindable<PositioningMethods>(&m_supportedPositioningMethods);
467}
468
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())
496 }
497 } else {
498 if (m_preferredPositioningMethods != methods) {
499 m_preferredPositioningMethods = methods;
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
528{
529 if (m_positionSource) {
530 m_active.removeBindingUnlessInWrapper();
531 executeStart();
532 }
533}
534
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
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
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
629{
630 return m_active;
631}
632
651{
652 return m_position.value();
653}
654
655void QDeclarativePositionSource::positionUpdateReceived(const QGeoPositionInfo &update)
656{
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
696
697QBindable<QDeclarativePositionSource::SourceError>
699{
700 return QBindable<QDeclarativePositionSource::SourceError>(&m_sourceError);
701}
702
704{
705 return m_positionSource;
706}
707
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
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
738qsizetype QDeclarativePositionSource::parameter_count(QQmlListProperty<QDeclarativePluginParameter> *prop)
739{
740 return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters.size();
741}
742
746QDeclarativePluginParameter *QDeclarativePositionSource::parameter_at(QQmlListProperty<QDeclarativePluginParameter> *prop, qsizetype index)
747{
748 return static_cast<QDeclarativePositionSource *>(prop->object)->m_parameters[index];
749}
750
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
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;
787 this, &QDeclarativePositionSource::onParameterInitialized,
789 }
790 }
791
792 if (m_parametersInitialized)
793 tryAttach(m_sourceName.value());
794}
795
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
827QVariant QDeclarativePositionSource::backendProperty(const QString &name) const
828{
829 if (m_positionSource)
830 return m_positionSource->backendProperty(name);
831 return QVariant();
832}
833
835{
836 return QBindable<bool>(&m_active);
837}
838
842void QDeclarativePositionSource::sourceErrorReceived(const QGeoPositionInfoSource::Error error)
843{
845 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::AccessError);
847 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::ClosedError);
849 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::UpdateTimeoutError);
851 return; //nothing to do
852 else
853 m_sourceError.setValueBypassingBindings(QDeclarativePositionSource::UnknownSourceError);
854
855 m_sourceError.notify();
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
870
871#include "moc_qdeclarativepositionsource_p.cpp"
static JNINativeMethod methods[]
void setUpdateInterval(int updateInterval)
QBindable< SourceError > bindableSourceError() const
QBindable< bool > bindableIsValid() const
bool isValid() const
\qmlproperty bool PositionSource::valid
QDeclarativePositionSource()
The PositionSource type provides the device's current position.
QQmlListProperty< QDeclarativePluginParameter > parameters
\qmlproperty list<PluginParameter> PositionSource::parameters \qmldefault
void stop()
\qmlmethod PositionSource::stop()
void setPreferredPositioningMethods(PositioningMethods methods)
\qmlproperty enumeration PositionSource::preferredPositioningMethods
QGeoPositionInfoSource * positionSource() const
QBindable< QDeclarativePosition * > bindablePosition() const
void start()
\qmlmethod PositionSource::start()
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
QBindable< PositioningMethods > bindableSupportedPositioningMethods() const
void setActive(bool active)
\qmlproperty bool PositionSource::active
void update(int timeout=0)
\qmlmethod PositionSource::update(int timeout)
QDeclarativePosition * position
\qmlproperty Position PositionSource::position
\inmodule QtPositioning
virtual void requestUpdate(int timeout=0)=0
Attempts to get the current position and emit positionUpdated() with this information.
virtual void stopUpdates()=0
Stops emitting updates at regular intervals.
virtual QVariant backendProperty(const QString &name) const
Returns the value of the backend-specific property named name, if present.
int updateInterval
This property holds the requested interval in milliseconds between each update.
virtual PositioningMethods supportedPositioningMethods() const =0
Returns the positioning methods available to this source.
virtual bool setBackendProperty(const QString &name, const QVariant &value)
Sets the backend-specific property named name to value.
virtual void startUpdates()=0
Starts emitting updates at regular intervals as specified by setUpdateInterval().
static QGeoPositionInfoSource * createDefaultSource(QObject *parent)
Creates and returns a position source with the given parent that reads from the system's default sour...
virtual void setPreferredPositioningMethods(PositioningMethods methods)
QString sourceName
This property holds the unique name of the position source implementation in use.
virtual QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly=false) const =0
Returns an update containing the last known position, or a null update if none is available.
static QGeoPositionInfoSource * createSource(const QString &sourceName, QObject *parent)
Creates and returns a position source with the given parent, by loading the plugin named sourceName.
void supportedPositioningMethodsChanged()
This signal is emitted when the supported positioning methods changed.
Error
The Error enumeration represents the errors which can occur.
virtual void setUpdateInterval(int msec)
PositioningMethods preferredPositioningMethods
Sets the preferred positioning methods for this source.
\inmodule QtPositioning
qsizetype size() const noexcept
Definition qlist.h:397
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qvariant.h:65
QMap< QString, QString > map
[6]
static void positionUpdated(JNIEnv *env, jobject thiz, QtJniTypes::Location location, jint androidClassKey, jboolean isSingleUpdate)
Combined button and popup list for selecting options.
@ SingleShotConnection
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
n void setPosition(void) \n\
GLuint index
[2]
GLbitfield GLuint64 timeout
[4]
GLuint name
GLsizei GLsizei GLchar * source
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
ptrdiff_t qsizetype
Definition qtypes.h:165