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
qdeclarativesatellitesource.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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
5
7
8/*!
9 \qmltype SatelliteSource
10 \inqmlmodule QtPositioning
11 \since 6.5
12 \brief The SatelliteSource class provides the satellite information.
13
14 The SatelliteSource class provides information about satellites in use and
15 satellites in view. This class is a QML representation of
16 \l QGeoSatelliteInfoSource.
17
18 Like its C++ equivalent, the class supports different plugins. Use the
19 \l name property to specify the name of the plugin to be used, and provide
20 \l {PluginParameter}s, if required. If the \l name property is not set,
21 a default plugin will be used. See \l {Qt Positioning Plugins} for more
22 information on the available plugins.
23
24 Use the \l valid property to check the SatelliteSource state.
25
26 Use the \l updateInterval property to indicate how often your application
27 wants to receive the satellite information updates. The \l start(),
28 \l stop() and \l update() methods can be used to control the operation
29 of the SatelliteSource, as well as the \l active property, which when set
30 is equivalent to calling \l start() or \l stop().
31
32 When the SatelliteSource is active, satellite information updates can
33 be retrieved using the \l satellitesInView and \l satellitesInUse
34 properties.
35
36 If an error happens during satellite information updates, use the
37 \l sourceError property to get the actual error code.
38
39 \section2 Example Usage
40
41 The following example shows a SatelliteSource which is using the
42 \l {Qt Positioning NMEA plugin}{NMEA} plugin to receive satellite
43 information updates every second and print the amount of satellites
44 in view and satellites in use to the console.
45
46 \qml
47 SatelliteSource {
48 id: source
49 name: "nmea"
50 active: true
51 updateInterval: 1000
52 PluginParameter { name: "nmea.source"; value: "serial:/dev/ttyACM0" }
53
54 onSatellitesInUseChanged: {
55 console.log("Satellites in use:", source.satellitesInUse.length)
56 }
57 onSatellitesInViewChanged: {
58 console.log("Satellites in view:", source.satellitesInView.length)
59 }
60 }
61 \endqml
62
63 \sa QGeoSatelliteInfoSource, PluginParameter, geoSatelliteInfo
64*/
65
66QDeclarativeSatelliteSource::QDeclarativeSatelliteSource()
67 : m_active(0), m_componentComplete(0), m_parametersInitialized(0),
68 m_startRequested(0), m_defaultSourceUsed(0), m_regularUpdates(0),
69 m_singleUpdate(0), m_singleUpdateRequested(0)
70{
71}
72
73QDeclarativeSatelliteSource::~QDeclarativeSatelliteSource()
74{
75 if (m_source)
76 m_source->disconnect(this);
77}
78
79/*!
80 \qmlproperty bool SatelliteSource::active
81
82 This property indicates whether the satellite source is active.
83 Setting this property to \c false equals calling \l stop, and
84 setting this property to \c true equals calling \l start.
85
86 \sa start, stop, update
87*/
88bool QDeclarativeSatelliteSource::isActive() const
89{
90 return m_active;
91}
92
93/*!
94 \qmlproperty bool SatelliteSource::valid
95 \readonly
96
97 This property is \c true if the SatelliteSource object has acquired a valid
98 backend plugin to provide data, and \c false otherwise.
99
100 Applications should check this property to determine whether providing
101 satellite information is available and enabled on the runtime platform,
102 and react accordingly.
103*/
104bool QDeclarativeSatelliteSource::isValid() const
105{
106 return m_source != nullptr;
107}
108
109/*!
110 \qmlproperty int SatelliteSource::updateInterval
111
112 This property holds the desired interval between updates in milliseconds.
113*/
114int QDeclarativeSatelliteSource::updateInterval() const
115{
116 return m_source ? m_source->updateInterval() : m_updateInterval;
117}
118
119/*!
120 \qmlproperty enumeration SatelliteSource::sourceError
121 \readonly
122
123 This property holds the error which last occurred with the backend data
124 provider.
125
126 \list
127 \li SatelliteSource.AccessError - The connection setup to the satellite
128 backend failed because the application lacked the required
129 privileges.
130 \li SatelliteSource.ClosedError - The satellite backend closed the
131 connection, which happens for example in case the user is switching
132 location services to off.
133 \li SatelliteSource.NoError - No error has occurred.
134 \li SatelliteSource.UnknownSourceError - An unidentified error occurred.
135 \li SatelliteSource.UpdateTimeoutError - The satellite information
136 could not be retrieved within the specified timeout.
137 \endlist
138*/
139QDeclarativeSatelliteSource::SourceError QDeclarativeSatelliteSource::sourceError() const
140{
141 return m_error;
142}
143
144/*!
145 \qmlproperty string SatelliteSource::name
146
147 This property holds the unique internal name for the plugin currently
148 providing satellite information.
149
150 Setting the property causes the SatelliteSource to use a particular
151 backend plugin. If the SatelliteSource is active at the time that the name
152 property is changed, it will become inactive. If the specified backend
153 cannot be loaded the satellite source will become invalid.
154
155 Changing the name property may cause the \l updateInterval property
156 to change as well.
157*/
158QString QDeclarativeSatelliteSource::name() const
159{
160 return m_source ? m_source->sourceName() : m_name;
161}
162
163/*!
164 \qmlproperty list<PluginParameter> SatelliteSource::parameters
165 \readonly
166 \qmldefault
167
168 This property holds the list of plugin parameters.
169
170 \sa PluginParameter
171*/
172QQmlListProperty<QDeclarativePluginParameter> QDeclarativeSatelliteSource::parameters()
173{
174 return QQmlListProperty<QDeclarativePluginParameter>(this, nullptr,
175 parameter_append,
176 parameter_count,
177 parameter_at,
178 parameter_clear);
179}
180
181/*!
182 \qmlproperty list<geoSatelliteInfo> SatelliteSource::satellitesInUse
183 \readonly
184
185 This property holds the list of satellites that are currently in use.
186 These are the satellites that are used to get a "fix" - that
187 is, those used to determine the current position.
188*/
189QList<QGeoSatelliteInfo> QDeclarativeSatelliteSource::satellitesInUse() const
190{
191 return m_satellitesInUse;
192}
193
194/*!
195 \qmlproperty list<geoSatelliteInfo> SatelliteSource::satellitesInView
196 \readonly
197
198 This property holds the list of satellites that are currently in view.
199*/
200QList<QGeoSatelliteInfo> QDeclarativeSatelliteSource::satellitesInView() const
201{
202 return m_satellitesInView;
203}
204
205void QDeclarativeSatelliteSource::setUpdateInterval(int updateInterval)
206{
207 if (m_updateInterval == updateInterval)
208 return;
209
210 const auto oldInterval = m_updateInterval;
211
212 if (m_source) {
213 m_source->setUpdateInterval(updateInterval);
214 // The above call can set some other interval, for example if desired
215 // updateInterval is less than minimum supported update interval. So
216 // we need to read the value back explicitly.
217 m_updateInterval = m_source->updateInterval();
218 } else {
219 m_updateInterval = updateInterval;
220 }
221 if (oldInterval != m_updateInterval)
222 emit updateIntervalChanged();
223}
224
225void QDeclarativeSatelliteSource::setActive(bool active)
226{
227 if (active == m_active)
228 return;
229
230 if (active)
231 start();
232 else
233 stop();
234}
235
236void QDeclarativeSatelliteSource::setName(const QString &name)
237{
238 if ((m_name == name) || (name.isEmpty() && m_defaultSourceUsed))
239 return;
240
241 if (m_componentComplete && m_parametersInitialized) {
242 createSource(name); // it will update name and emit, if needed
243 } else {
244 m_name = name;
245 emit nameChanged();
246 }
247}
248
249void QDeclarativeSatelliteSource::componentComplete()
250{
251 m_componentComplete = true;
252 m_parametersInitialized = true;
253 for (QDeclarativePluginParameter *p: std::as_const(m_parameters)) {
254 if (!p->isInitialized()) {
255 m_parametersInitialized = false;
256 connect(p, &QDeclarativePluginParameter::initialized,
257 this, &QDeclarativeSatelliteSource::onParameterInitialized,
258 Qt::SingleShotConnection);
259 }
260 }
261
262 if (m_parametersInitialized)
263 createSource(m_name);
264}
265
266/*!
267 \qmlmethod bool SatelliteSource::setBackendProperty(string name, var value)
268
269 Sets the backend-specific property named \a name to \a value.
270 Returns true on success, false otherwise, including if called on an
271 uninitialized SatelliteSource.
272*/
273bool QDeclarativeSatelliteSource::setBackendProperty(const QString &name, const QVariant &value)
274{
275 if (m_source)
276 return m_source->setBackendProperty(name, value);
277 return false;
278}
279
280/*!
281 \qmlmethod var SatelliteSource::backendProperty(string name)
282
283 Returns the value of the backend-specific property named \a name, if
284 present. Otherwise, including if called on an uninitialized SatelliteSource,
285 the return value will be invalid.
286*/
287QVariant QDeclarativeSatelliteSource::backendProperty(const QString &name) const
288{
289 return m_source ? m_source->backendProperty(name) : QVariant{};
290}
291
292/*!
293 \qmlmethod SatelliteSource::update(int timeout = 0)
294
295 A convenience method to request a single update from the satellite source.
296 If there is no source available, this method has no effect.
297
298 If the satellite source is not active, it will be activated for as
299 long as it takes to receive an update, or until the request times
300 out. The request timeout period is plugin-specific.
301
302 The \a timeout is specified in milliseconds. If the \a timeout is zero
303 (the default value), it defaults to a reasonable timeout period as
304 appropriate for the source.
305
306 \sa start, stop, active
307*/
308void QDeclarativeSatelliteSource::update(int timeout)
309{
310 if (m_componentComplete && m_parametersInitialized) {
311 executeSingleUpdate(timeout);
312 } else {
313 m_singleUpdateDesiredTimeout = timeout;
314 m_singleUpdateRequested = true;
315 }
316}
317
318/*!
319 \qmlmethod SatelliteSource::start()
320
321 Requests updates from the satellite source. Uses \l updateInterval if set,
322 default interval otherwise. If there is no source available, this method
323 has no effect.
324
325 \sa stop, update, active
326*/
327void QDeclarativeSatelliteSource::start()
328{
329 if (m_componentComplete && m_parametersInitialized)
330 executeStart();
331 else
332 m_startRequested = true;
333}
334
335/*!
336 \qmlmethod SatelliteSource::stop()
337
338 Stops updates from the satellite source. If there is no source available or
339 it is not active, this method has no effect.
340
341 \sa start, update, active
342*/
343void QDeclarativeSatelliteSource::stop()
344{
345 if (m_source) {
346 m_source->stopUpdates();
347 m_regularUpdates = false;
348
349 if (m_active && !m_singleUpdate) {
350 m_active = false;
351 emit activeChanged();
352 }
353 } else {
354 m_startRequested = false;
355 }
356}
357
358void QDeclarativeSatelliteSource::sourceErrorReceived(const QGeoSatelliteInfoSource::Error error)
359{
360 const auto oldError = m_error;
361 m_error = static_cast<SourceError>(error);
362 if (m_error != oldError)
363 emit sourceErrorChanged();
364
365 // if an error occurred during single update, the update is stopped, so we
366 // need to change the active state.
367 if (m_singleUpdate) {
368 m_singleUpdate = false;
369 if (m_active && !m_regularUpdates) {
370 m_active = false;
371 emit activeChanged();
372 }
373 }
374}
375
376void QDeclarativeSatelliteSource::onParameterInitialized()
377{
378 m_parametersInitialized = true;
379 for (QDeclarativePluginParameter *p: std::as_const(m_parameters)) {
380 if (!p->isInitialized()) {
381 m_parametersInitialized = false;
382 break;
383 }
384 }
385
386 // m_componentComplete == true here
387 if (m_parametersInitialized)
388 createSource(m_name);
389}
390
391void QDeclarativeSatelliteSource::satellitesInViewUpdateReceived(const QList<QGeoSatelliteInfo> &satellites)
392{
393 m_satellitesInView = satellites;
394 emit satellitesInViewChanged();
395 handleSingleUpdateReceived();
396}
397
398void QDeclarativeSatelliteSource::satellitesInUseUpdateReceived(const QList<QGeoSatelliteInfo> &satellites)
399{
400 m_satellitesInUse = satellites;
401 emit satellitesInUseChanged();
402 handleSingleUpdateReceived();
403}
404
405QVariantMap QDeclarativeSatelliteSource::parameterMap() const
406{
407 QVariantMap map;
408 for (const auto *parameter : std::as_const(m_parameters))
409 map.insert(parameter->name(), parameter->value());
410 return map;
411}
412
413void QDeclarativeSatelliteSource::createSource(const QString &newName)
414{
415 if (m_source && m_source->sourceName() == newName)
416 return;
417
418 const auto oldName = name();
419 const bool oldIsValid = isValid();
420 const bool oldActive = isActive();
421 const auto oldUpdateInterval = updateInterval();
422
423 if (m_source) {
424 m_source->disconnect(this);
425 m_source->stopUpdates();
426 m_source.reset(nullptr);
427 m_active = false;
428 }
429
430 if (!newName.isEmpty()) {
431 m_source.reset(QGeoSatelliteInfoSource::createSource(newName, parameterMap(), nullptr));
432 m_defaultSourceUsed = false;
433 } else {
434 m_source.reset(QGeoSatelliteInfoSource::createDefaultSource(parameterMap(), nullptr));
435 m_defaultSourceUsed = true;
436 }
437
438 if (m_source) {
439 connect(m_source.get(), &QGeoSatelliteInfoSource::errorOccurred,
440 this, &QDeclarativeSatelliteSource::sourceErrorReceived);
441 connect(m_source.get(), &QGeoSatelliteInfoSource::satellitesInViewUpdated,
442 this, &QDeclarativeSatelliteSource::satellitesInViewUpdateReceived);
443 connect(m_source.get(), &QGeoSatelliteInfoSource::satellitesInUseUpdated,
444 this, &QDeclarativeSatelliteSource::satellitesInUseUpdateReceived);
445
446 m_name = m_source->sourceName();
447 m_source->setUpdateInterval(m_updateInterval);
448 m_updateInterval = m_source->updateInterval();
449 } else {
450 m_name = newName;
451 m_defaultSourceUsed = false;
452 }
453
454 if (oldName != name())
455 emit nameChanged();
456
457 if (oldIsValid != isValid())
458 emit validityChanged();
459
460 if (oldActive != isActive())
461 emit activeChanged();
462
463 if (oldUpdateInterval != updateInterval())
464 emit updateIntervalChanged();
465
466 if (m_startRequested) {
467 m_startRequested = false;
468 executeStart();
469 }
470 if (m_singleUpdateRequested) {
471 m_singleUpdateRequested = false;
472 executeSingleUpdate(m_singleUpdateDesiredTimeout);
473 }
474}
475
476void QDeclarativeSatelliteSource::handleSingleUpdateReceived()
477{
478 if (m_singleUpdate) {
479 m_singleUpdate = false;
480 if (m_active && !m_regularUpdates) {
481 m_active = false;
482 emit activeChanged();
483 }
484 }
485}
486
487void QDeclarativeSatelliteSource::executeStart()
488{
489 if (m_source) {
490 m_regularUpdates = true;
491 if (!m_active) {
492 m_active = true;
493 emit activeChanged();
494 }
495 m_source->startUpdates();
496 }
497}
498
499void QDeclarativeSatelliteSource::executeSingleUpdate(int timeout)
500{
501 if (m_source) {
502 m_singleUpdate = true;
503 if (!m_active) {
504 m_active = true;
505 emit activeChanged();
506 }
507 m_source->requestUpdate(timeout);
508 }
509}
510
511void QDeclarativeSatelliteSource::parameter_append(PluginParameterProperty *prop,
512 QDeclarativePluginParameter *parameter)
513{
514 auto *src = static_cast<QDeclarativeSatelliteSource *>(prop->object);
515 src->m_parameters.append(parameter);
516}
517
518qsizetype QDeclarativeSatelliteSource::parameter_count(PluginParameterProperty *prop)
519{
520 return static_cast<QDeclarativeSatelliteSource *>(prop->object)->m_parameters.size();
521}
522
523QDeclarativePluginParameter *
524QDeclarativeSatelliteSource::parameter_at(PluginParameterProperty *prop, qsizetype index)
525{
526 return static_cast<QDeclarativeSatelliteSource *>(prop->object)->m_parameters[index];
527}
528
529void QDeclarativeSatelliteSource::parameter_clear(PluginParameterProperty *prop)
530{
531 auto *src = static_cast<QDeclarativeSatelliteSource *>(prop->object);
532 src->m_parameters.clear();
533}
534
535QT_END_NAMESPACE