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
qdeclarativegeoroutemodel.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
6
7#include <QtCore/QCoreApplication>
8#include <QtQml/QQmlEngine>
9#include <QtQml/qqmlinfo.h>
10#include <QtLocation/QGeoRoutingManager>
11#include <QtPositioning/QGeoRectangle>
12
14
15/*!
16 \qmltype RouteModel
17 \nativetype QDeclarativeGeoRouteModel
18 \inqmlmodule QtLocation
19 \ingroup qml-QtLocation5-routing
20 \since QtLocation 5.5
21
22 \brief The RouteModel type provides access to routes.
23
24 The RouteModel type is used as part of a model/view grouping to retrieve
25 geographic routes from a backend provider. Routes include data about driving
26 directions between two points, walking directions with multiple waypoints,
27 and various other similar concepts. It functions much like other Model
28 types in QML (see for example \l {Models and Views in Qt Quick#Models}{ListModel}),
29 and interacts with views such as \l MapItemView, and \l{ListView}.
30
31 Like \l Map and \l GeocodeModel, all the data for a RouteModel to work comes
32 from a services plugin. This is contained in the \l{plugin} property, and
33 this must be set before the RouteModel can do any useful work.
34
35 Once the plugin is set, create a \l RouteQuery with the appropriate
36 waypoints and other settings, and set the RouteModel's \l{query}
37 property. If \l autoUpdate is enabled, the update will being automatically.
38 Otherwise, the \l{update} method may be used. By default, autoUpdate is
39 disabled.
40
41 The data stored and returned in the RouteModel consists of \l route objects,
42 as a list with the role name "routeData". See the documentation for \l route
43 for further details on its structure and contents.
44
45 \section2 Example Usage
46
47 The following snippet is two-part, showing firstly the declaration of
48 objects, and secondly a short piece of procedural code using it. We set
49 the routeModel's \l{autoUpdate} property to false, and call \l{update} once
50 the query is set up, to avoid useless extra requests halfway through the
51 set up of the query.
52
53 \code
54 Plugin {
55 id: aPlugin
56 name: "osm"
57 }
58
59 RouteQuery {
60 id: aQuery
61 }
62
63 RouteModel {
64 id: routeModel
65 plugin: aPlugin
66 query: aQuery
67 autoUpdate: false
68 }
69 \endcode
70
71 \code
72 {
73 aQuery.addWaypoint(...)
74 aQuery.addWaypoint(...)
75 aQuery.travelModes = ...
76 routeModel.update()
77 }
78 \endcode
79
80*/
81
82QDeclarativeGeoRouteModel::QDeclarativeGeoRouteModel(QObject *parent)
83 : QAbstractListModel(parent)
84{
85}
86
87/*!
88 \qmlproperty int QtLocation::RouteModel::count
89
90 This property holds how many routes the model currently has.
91 Amongst other uses, you can use this value when accessing routes
92 via the QtLocation::RouteModel::get -method.
93*/
94
95int QDeclarativeGeoRouteModel::count() const
96{
97 return routes_.count();
98}
99
100/*!
101 \qmlmethod void QtLocation::RouteModel::reset()
102
103 Resets the model. All route data is cleared, any outstanding requests
104 are aborted and possible errors are cleared. Model status will be set
105 to RouteModel.Null
106*/
107
108void QDeclarativeGeoRouteModel::reset()
109{
110 if (!routes_.isEmpty()) {
111 beginResetModel();
112 routes_.clear();
113 emit countChanged();
114 emit routesChanged();
115 endResetModel();
116 }
117
118 emit abortRequested();
119 setError(NoError, QString());
120 setStatus(QDeclarativeGeoRouteModel::Null);
121}
122
123/*!
124 \qmlmethod void QtLocation::RouteModel::cancel()
125
126 Cancels any outstanding requests and clears errors. Model status will be set to either
127 RouteModel.Null or RouteModel.Ready.
128*/
129void QDeclarativeGeoRouteModel::cancel()
130{
131 emit abortRequested();
132 setError(NoError, QString());
133 setStatus(routes_.isEmpty() ? Null : Ready);
134}
135
136/*!
137 \qmlmethod route QtLocation::RouteModel::get(int index)
138
139 Returns the route at the specified \a index. Use the \l count
140 property to check the amount of routes available. The routes
141 are indexed from zero, so the accessible range is 0...(count - 1).
142
143 If you access out of bounds, an empty route is returned and
144 a warning is issued.
145*/
146
147QGeoRoute QDeclarativeGeoRouteModel::get(int index)
148{
149 if (index < 0 || index >= routes_.count()) {
150 qmlWarning(this) << QStringLiteral("Index '%1' out of range").arg(index);
151 return QGeoRoute();
152 }
153 return routes_.at(index);
154}
155
156/*!
157 \internal
158*/
159void QDeclarativeGeoRouteModel::componentComplete()
160{
161 complete_ = true;
162 if (autoUpdate_) {
163 update();
164 }
165}
166
167/*!
168 \internal
169*/
170int QDeclarativeGeoRouteModel::rowCount(const QModelIndex &parent) const
171{
172 Q_UNUSED(parent);
173 return routes_.count();
174}
175
176/*!
177 \internal
178*/
179QVariant QDeclarativeGeoRouteModel::data(const QModelIndex &index, int role) const
180{
181 if (!index.isValid()) {
182 qmlWarning(this) << QStringLiteral("Error in indexing route model's data (invalid index).");
183 return QVariant();
184 }
185
186 if (index.row() >= routes_.count()) {
187 qmlWarning(this) << QStringLiteral("Fatal error in indexing route model's data (index overflow).");
188 return QVariant();
189 }
190
191 if (role == RouteRole)
192 return QVariant::fromValue(routes_.at(index.row()));
193 return QVariant();
194}
195
196QHash<int, QByteArray> QDeclarativeGeoRouteModel::roleNames() const
197{
198 QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
199 roleNames.insert(RouteRole, "routeData");
200 return roleNames;
201}
202
203/*!
204 \internal
205*/
206void QDeclarativeGeoRouteModel::setPlugin(QDeclarativeGeoServiceProvider *plugin)
207{
208 if (plugin_ == plugin)
209 return;
210
211 reset(); // reset the model
212
213 if (plugin_) {
214 disconnect(plugin_, &QDeclarativeGeoServiceProvider::localesChanged,
215 this, &QDeclarativeGeoRouteModel::measurementSystemChanged);
216 }
217 if (plugin) {
218 connect(plugin, &QDeclarativeGeoServiceProvider::localesChanged,
219 this, &QDeclarativeGeoRouteModel::measurementSystemChanged);
220 }
221
222 plugin_ = plugin;
223
224 if (complete_)
225 emit pluginChanged();
226
227 if (!plugin)
228 return;
229
230 if (plugin_->isAttached()) {
231 pluginReady();
232 } else {
233 connect(plugin_, &QDeclarativeGeoServiceProvider::attached,
234 this, &QDeclarativeGeoRouteModel::pluginReady);
235 }
236}
237
238/*!
239 \internal
240*/
241void QDeclarativeGeoRouteModel::pluginReady()
242{
243 QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
244 QGeoRoutingManager *routingManager = serviceProvider->routingManager();
245
246 if (serviceProvider->routingError() != QGeoServiceProvider::NoError) {
247 QDeclarativeGeoRouteModel::RouteError newError = UnknownError;
248 switch (serviceProvider->routingError()) {
249 case QGeoServiceProvider::NotSupportedError:
250 newError = EngineNotSetError; break;
251 case QGeoServiceProvider::UnknownParameterError:
252 newError = UnknownParameterError; break;
253 case QGeoServiceProvider::MissingRequiredParameterError:
254 newError = MissingRequiredParameterError; break;
255 case QGeoServiceProvider::ConnectionError:
256 newError = CommunicationError; break;
257 default:
258 break;
259 }
260
261 setError(newError, serviceProvider->routingErrorString());
262 return;
263 }
264
265 if (!routingManager) {
266 setError(EngineNotSetError, tr("Plugin does not support routing."));
267 return;
268 }
269
270 connect(routingManager, &QGeoRoutingManager::finished,
271 this, &QDeclarativeGeoRouteModel::routingFinished);
272 connect(routingManager, &QGeoRoutingManager::errorOccurred,
273 this, &QDeclarativeGeoRouteModel::routingError);
274}
275
276/*!
277 \internal
278*/
279void QDeclarativeGeoRouteModel::queryDetailsChanged()
280{
281 if (autoUpdate_ && complete_)
282 update();
283}
284
285/*!
286 \qmlproperty Plugin QtLocation::RouteModel::plugin
287
288 This property holds the plugin that providers the actual
289 routing service. Note that all plugins do not necessarily
290 provide routing (could for example provide only geocoding or maps).
291
292 A valid plugin must be set before the RouteModel can perform any useful
293 operations.
294
295 \sa Plugin
296*/
297
298QDeclarativeGeoServiceProvider *QDeclarativeGeoRouteModel::plugin() const
299{
300 return plugin_;
301}
302
303/*!
304 \internal
305*/
306void QDeclarativeGeoRouteModel::setQuery(QDeclarativeGeoRouteQuery *query)
307{
308 if (!query || query == routeQuery_)
309 return;
310 if (routeQuery_)
311 routeQuery_->disconnect(this);
312 routeQuery_ = query;
313 connect(query, &QDeclarativeGeoRouteQuery::queryDetailsChanged,
314 this, &QDeclarativeGeoRouteModel::queryDetailsChanged);
315 if (complete_) {
316 emit queryChanged();
317 if (autoUpdate_)
318 update();
319 }
320}
321
322/*!
323 \qmlproperty RouteQuery QtLocation::RouteModel::query
324
325 This property holds the data of the route request.
326 The primary data are the waypoint coordinates and possible further
327 preferences (means of traveling, things to avoid on route etc).
328*/
329
330QDeclarativeGeoRouteQuery *QDeclarativeGeoRouteModel::query() const
331{
332 return routeQuery_;
333}
334
335/*!
336 \internal
337*/
338void QDeclarativeGeoRouteModel::setAutoUpdate(bool autoUpdate)
339{
340 if (autoUpdate_ == autoUpdate)
341 return;
342 autoUpdate_ = autoUpdate;
343 if (complete_)
344 emit autoUpdateChanged();
345}
346
347/*!
348 \qmlproperty bool QtLocation::RouteModel::autoUpdate
349
350 This property controls whether the Model automatically updates in response
351 to changes in its attached RouteQuery. The default value of this property
352 is false.
353
354 If setting this value to 'true', note that any change at all in
355 the RouteQuery object set in the \l{query} property will trigger a new
356 request to be sent. If you are adjusting many properties of the RouteQuery
357 with autoUpdate enabled, this can generate large numbers of useless (and
358 later discarded) requests.
359*/
360
361bool QDeclarativeGeoRouteModel::autoUpdate() const
362{
363 return autoUpdate_;
364}
365
366/*!
367 \qmlproperty Locale::MeasurementSystem QtLocation::RouteModel::measurementSystem
368
369 This property holds the measurement system which will be used when calculating the route. This
370 property is changed when the \l {QtLocation::Plugin::locales}{Plugin::locales} property of
371 \l {QtLocation::RouteModel::plugin}{plugin} changes.
372
373 If setting this property it must be set after the \l {QtLocation::RouteModel::plugin}{plugin}
374 property is set.
375*/
376void QDeclarativeGeoRouteModel::setMeasurementSystem(QLocale::MeasurementSystem ms)
377{
378 if (!plugin_)
379 return;
380
381 QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
382 if (!serviceProvider)
383 return;
384
385 QGeoRoutingManager *routingManager = serviceProvider->routingManager();
386 if (!routingManager)
387 return;
388
389 if (routingManager->measurementSystem() == ms)
390 return;
391
392 routingManager->setMeasurementSystem(ms);
393 emit measurementSystemChanged();
394}
395
396QLocale::MeasurementSystem QDeclarativeGeoRouteModel::measurementSystem() const
397{
398 if (!plugin_)
399 return QLocale().measurementSystem();
400
401 QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
402 if (!serviceProvider) {
403 if (plugin_->locales().isEmpty())
404 return QLocale().measurementSystem();
405
406 return QLocale(plugin_->locales().first()).measurementSystem();
407 }
408
409 QGeoRoutingManager *routingManager = serviceProvider->routingManager();
410 if (!routingManager) {
411 if (plugin_->locales().isEmpty())
412 return QLocale().measurementSystem();
413
414 return QLocale(plugin_->locales().first()).measurementSystem();
415 }
416
417 return routingManager->measurementSystem();
418}
419
420/*!
421 \internal
422*/
423void QDeclarativeGeoRouteModel::setStatus(QDeclarativeGeoRouteModel::Status status)
424{
425 if (status_ == status)
426 return;
427
428 status_ = status;
429
430 if (complete_)
431 emit statusChanged();
432}
433
434/*!
435 \qmlproperty enumeration QtLocation::RouteModel::status
436
437 This read-only property holds the current status of the model.
438
439 \list
440 \li RouteModel.Null - No route requests have been issued or \l reset has been called.
441 \li RouteModel.Ready - Route request(s) have finished successfully.
442 \li RouteModel.Loading - Route request has been issued but not yet finished
443 \li RouteModel.Error - Routing error has occurred, details are in \l error and \l errorString
444 \endlist
445*/
446
447QDeclarativeGeoRouteModel::Status QDeclarativeGeoRouteModel::status() const
448{
449 return status_;
450}
451
452/*!
453 \qmlproperty string QtLocation::RouteModel::errorString
454
455 This read-only property holds the textual presentation of the latest routing error.
456 If no error has occurred or the model has been reset, an empty string is returned.
457
458 An empty string may also be returned if an error occurred which has no associated
459 textual representation.
460*/
461
462QString QDeclarativeGeoRouteModel::errorString() const
463{
464 return errorString_;
465}
466
467/*!
468 \qmlproperty enumeration QtLocation::RouteModel::error
469
470 This read-only property holds the latest error value of the routing request.
471
472 \list
473 \li RouteModel.NoError - No error has occurred.
474 \li RouteModel.CommunicationError - An error occurred while communicating with the service provider.
475 \li RouteModel.EngineNotSetError - The model's plugin property was not set or there is no routing manager associated with the plugin.
476 \li RouteModel.MissingRequiredParameterError - A required parameter was not specified.
477 \li RouteModel.ParseError - The response from the service provider was in an unrecognizable format.
478 \li RouteModel.UnknownError - An error occurred which does not fit into any of the other categories.
479 \li RouteModel.UnknownParameterError - The plugin did not recognize one of the parameters it was given.
480 \li RouteModel.UnsupportedOptionError - The requested operation is not supported by the routing provider.
481 This may happen when the loaded engine does not support a particular
482 type of routing request.
483 \endlist
484*/
485
486QDeclarativeGeoRouteModel::RouteError QDeclarativeGeoRouteModel::error() const
487{
488 return error_;
489}
490
491void QDeclarativeGeoRouteModel::setError(RouteError error, const QString& errorString)
492{
493 if (error_ == error && errorString_ == errorString)
494 return;
495 error_ = error;
496 errorString_ = errorString;
497 emit errorChanged();
498}
499
500/*!
501 \qmlmethod void QtLocation::RouteModel::update()
502
503 Instructs the RouteModel to update its data. This is most useful
504 when \l autoUpdate is disabled, to force a refresh when the query
505 has been changed.
506*/
507void QDeclarativeGeoRouteModel::update()
508{
509 if (!complete_)
510 return;
511
512 if (!plugin_) {
513 setError(EngineNotSetError, tr("Cannot route, plugin not set."));
514 return;
515 }
516
517 QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
518 if (!serviceProvider)
519 return;
520
521 QGeoRoutingManager *routingManager = serviceProvider->routingManager();
522 if (!routingManager) {
523 setError(EngineNotSetError, tr("Cannot route, route manager not set."));
524 return;
525 }
526 if (!routeQuery_) {
527 setError(ParseError, tr("Cannot route, valid query not set."));
528 return;
529 }
530 emit abortRequested(); // Clear previous requests
531 QGeoRouteRequest request = routeQuery_->routeRequest();
532 if (request.waypoints().count() < 2) {
533 setError(ParseError,tr("Not enough waypoints for routing."));
534 return;
535 }
536
537 setError(NoError, QString());
538
539 QGeoRouteReply *reply = routingManager->calculateRoute(request);
540 setStatus(QDeclarativeGeoRouteModel::Loading);
541 if (!reply->isFinished()) {
542 connect(this, &QDeclarativeGeoRouteModel::abortRequested, reply, &QGeoRouteReply::abort);
543 } else {
544 if (reply->error() == QGeoRouteReply::NoError) {
545 routingFinished(reply);
546 } else {
547 routingError(reply, reply->error(), reply->errorString());
548 }
549 }
550}
551
552/*!
553 \internal
554*/
555void QDeclarativeGeoRouteModel::routingFinished(QGeoRouteReply *reply)
556{
557 if (!reply)
558 return;
559 reply->deleteLater();
560 if (reply->error() != QGeoRouteReply::NoError)
561 return;
562
563 beginResetModel();
564 const int oldCount = routes_.count();
565 routes_ = reply->routes();
566 endResetModel();
567
568 setError(NoError, QString());
569 setStatus(QDeclarativeGeoRouteModel::Ready);
570
571 if (oldCount != 0 || routes_.count() != 0)
572 emit routesChanged();
573 if (oldCount != routes_.count())
574 emit countChanged();
575}
576
577/*!
578 \internal
579*/
580void QDeclarativeGeoRouteModel::routingError(QGeoRouteReply *reply,
581 QGeoRouteReply::Error error,
582 const QString &errorString)
583{
584 if (!reply)
585 return;
586 reply->deleteLater();
587 setError(static_cast<QDeclarativeGeoRouteModel::RouteError>(error), errorString);
588 setStatus(QDeclarativeGeoRouteModel::Error);
589}
590
591
592/*!
593 \qmltype RouteQuery
594 \nativetype QDeclarativeGeoRouteQuery
595 \inqmlmodule QtLocation
596 \ingroup qml-QtLocation5-routing
597 \since QtLocation 5.5
598
599 \brief The RouteQuery type is used to provide query parameters to a
600 RouteModel.
601
602 A RouteQuery is used to pack all the parameters necessary to make a request
603 to a routing service, which can then populate the contents of a RouteModel.
604
605 These parameters describe key details of the route, such as \l waypoints to
606 pass through, \l excludedAreas to avoid, the \l travelModes in use, as well
607 as detailed preferences on how to optimize the route and what features
608 to prefer or avoid along the path (such as toll roads, highways, etc).
609
610 RouteQuery objects are used exclusively to fill out the value of a
611 RouteModel's \l{RouteModel::query}{query} property, which can then begin
612 the retrieval process to populate the model.
613
614 Some plugins might allow or require specific parameters to operate.
615 In order to specify these plugin-specific parameters, MapParameter elements
616 can be nested inside a RouteQuery.
617
618 \section2 Example Usage
619
620 The following snipped shows an incomplete example of creating a RouteQuery
621 object and setting it as the value of a RouteModel's \l{RouteModel::query}{query}
622 property.
623
624 \code
625 RouteQuery {
626 id: aQuery
627 }
628
629 RouteModel {
630 query: aQuery
631 autoUpdate: false
632 }
633 \endcode
634
635 For a more complete example, see the documentation for the \l{RouteModel}
636 type, and the Mapviewer example.
637
638 \sa RouteModel
639
640*/
641
642QDeclarativeGeoRouteQuery::QDeclarativeGeoRouteQuery(QObject *parent)
643 : QObject(parent)
644{
645}
646
647QDeclarativeGeoRouteQuery::QDeclarativeGeoRouteQuery(const QGeoRouteRequest &request, QObject *parent)
648 : QObject(parent), request_(request)
649{
650 // Extra params assumed to be already set in the request.
651 // Init waypoints
652 m_waypoints = request_.waypoints();
653}
654
655QDeclarativeGeoRouteQuery::~QDeclarativeGeoRouteQuery()
656{
657}
658
659/*!
660 \internal
661*/
662void QDeclarativeGeoRouteQuery::componentComplete()
663{
664 complete_ = true;
665}
666
667/*!
668 \qmlproperty QList<FeatureType> RouteQuery::featureTypes
669
670 List of features that will be considered when planning the
671 route. Features with a weight of NeutralFeatureWeight will not be returned.
672
673 \list
674 \li RouteQuery.NoFeature - No features will be taken into account when planning the route
675 \li RouteQuery.TollFeature - Consider tollways when planning the route
676 \li RouteQuery.HighwayFeature - Consider highways when planning the route
677 \li RouteQuery.PublicTransitFeature - Consider public transit when planning the route
678 \li RouteQuery.FerryFeature - Consider ferries when planning the route
679 \li RouteQuery.TunnelFeature - Consider tunnels when planning the route
680 \li RouteQuery.DirtRoadFeature - Consider dirt roads when planning the route
681 \li RouteQuery.ParksFeature - Consider parks when planning the route
682 \li RouteQuery.MotorPoolLaneFeature - Consider motor pool lanes when planning the route
683 \li RouteQuery.TrafficFeature - Consider traffic when planning the route
684 \endlist
685
686 \sa setFeatureWeight, featureWeight
687*/
688
689QList<int> QDeclarativeGeoRouteQuery::featureTypes() const
690{
691 QList<int> list;
692
693 const auto featureTypes = request_.featureTypes();
694 for (const auto &featureType : featureTypes)
695 list.append(static_cast<int>(featureType));
696 return list;
697}
698
699/*!
700 \qmlproperty int RouteQuery::numberAlternativeRoutes
701
702 The number of alternative routes requested when requesting routes.
703 The default value is 0.
704*/
705
706
707int QDeclarativeGeoRouteQuery::numberAlternativeRoutes() const
708{
709 return request_.numberAlternativeRoutes();
710}
711
712void QDeclarativeGeoRouteQuery::setNumberAlternativeRoutes(int numberAlternativeRoutes)
713{
714 if (numberAlternativeRoutes == request_.numberAlternativeRoutes())
715 return;
716
717 request_.setNumberAlternativeRoutes(numberAlternativeRoutes);
718
719 if (complete_) {
720 emit numberAlternativeRoutesChanged();
721 emit queryDetailsChanged();
722 }
723}
724
725/*!
726 \qmlproperty list<coordinate> RouteQuery::waypoints
727
728 The coordinates of the waypoints for the desired route.
729 The waypoints should be given in order from origin to destination.
730 Two or more coordinates are needed.
731
732 Waypoints can be set as part of the RouteQuery type declaration or
733 dynamically with the functions provided.
734
735 \sa addWaypoint, removeWaypoint, clearWaypoints
736*/
737
738QList<QGeoCoordinate> QDeclarativeGeoRouteQuery::waypoints() const
739{
740 return m_waypoints;
741}
742
743void QDeclarativeGeoRouteQuery::setWaypoints(const QList<QGeoCoordinate> &value)
744{
745 if (m_waypoints == value)
746 return;
747
748 m_waypoints = value;
749 waypointChanged();
750}
751
752/*!
753 \qmlproperty list<georectangle> RouteQuery::excludedAreas
754
755 Areas that the route must not cross.
756
757 Excluded areas can be set as part of the \l RouteQuery type declaration or
758 dynamically with the functions provided.
759
760 \sa addExcludedArea, removeExcludedArea, clearExcludedAreas
761*/
762QList<QGeoRectangle> QDeclarativeGeoRouteQuery::excludedAreas() const
763{
764 return request_.excludeAreas();
765}
766
767void QDeclarativeGeoRouteQuery::setExcludedAreas(const QList<QGeoRectangle> &value)
768{
769 if (request_.excludeAreas() == value)
770 return;
771
772 request_.setExcludeAreas(value);
773
774 if (complete_) {
775 emit excludedAreasChanged();
776 emit queryDetailsChanged();
777 }
778}
779
780/*!
781 \qmlmethod void QtLocation::RouteQuery::addExcludedArea(georectangle area)
782
783 Adds the specified georectangle \a area to the excluded areas
784 (areas that the route must not cross).
785 The same area can only be added once.
786
787 \sa removeExcludedArea, clearExcludedAreas
788*/
789
790
791void QDeclarativeGeoRouteQuery::addExcludedArea(const QGeoRectangle &area)
792{
793 if (!area.isValid())
794 return;
795
796 QList<QGeoRectangle> excludedAreas = request_.excludeAreas();
797
798 if (excludedAreas.contains(area))
799 return;
800
801 excludedAreas.append(area);
802
803 request_.setExcludeAreas(excludedAreas);
804
805 if (complete_) {
806 emit excludedAreasChanged();
807 emit queryDetailsChanged();
808 }
809}
810
811/*!
812 \qmlmethod void QtLocation::RouteQuery::removeExcludedArea(georectangle area)
813
814 Removes the given \a area from excluded areas (areas that the route must not cross).
815
816 \sa addExcludedArea, clearExcludedAreas
817*/
818
819void QDeclarativeGeoRouteQuery::removeExcludedArea(const QGeoRectangle &area)
820{
821 if (!area.isValid())
822 return;
823
824 QList<QGeoRectangle> excludedAreas = request_.excludeAreas();
825
826 int index = excludedAreas.lastIndexOf(area);
827 if (index == -1) {
828 qmlWarning(this) << QStringLiteral("Cannot remove nonexistent area.");
829 return;
830 }
831 excludedAreas.removeAt(index);
832 request_.setExcludeAreas(excludedAreas);
833
834 if (complete_) {
835 emit excludedAreasChanged();
836 emit queryDetailsChanged();
837 }
838}
839
840/*!
841 \qmlmethod void QtLocation::RouteQuery::clearExcludedAreas()
842
843 Clears all excluded areas (areas that the route must not cross).
844
845 \sa addExcludedArea, removeExcludedArea
846*/
847
848void QDeclarativeGeoRouteQuery::clearExcludedAreas()
849{
850 if (request_.excludeAreas().isEmpty())
851 return;
852
853 request_.setExcludeAreas(QList<QGeoRectangle>());
854
855 if (complete_) {
856 emit excludedAreasChanged();
857 emit queryDetailsChanged();
858 }
859}
860
861/*!
862 \qmlmethod void QtLocation::RouteQuery::addWaypoint(coordinate)
863
864 Appends the given \a coordinate to the list of waypoints. The same
865 coordinate can be set multiple times.
866
867 \sa removeWaypoint, clearWaypoints
868*/
869void QDeclarativeGeoRouteQuery::addWaypoint(const QGeoCoordinate &waypoint)
870{
871 if (!waypoint.isValid()) {
872 qmlWarning(this) << QStringLiteral("Invalid coordinate as waypoint");
873 return;
874 }
875
876 m_waypoints << waypoint;
877 waypointChanged();
878}
879
880/*!
881 \qmlmethod void QtLocation::RouteQuery::removeWaypoint(coordinate)
882
883 Removes the given \a coordinate from the list of waypoints. If the
884 same coordinate appears multiple times, the most recently added
885 coordinate instance is removed.
886
887 \sa addWaypoint, clearWaypoints
888*/
889void QDeclarativeGeoRouteQuery::removeWaypoint(const QGeoCoordinate &waypoint)
890{
891 if (!waypoint.isValid()) {
892 qmlWarning(this) << QStringLiteral("Invalid coordinate as waypoint");
893 return;
894 }
895
896 if (qsizetype idx = m_waypoints.lastIndexOf(waypoint); idx >= 0) {
897 m_waypoints.remove(idx);
898 waypointChanged();
899 } else {
900 qmlWarning(this) << QStringLiteral("Cannot remove nonexistent waypoint.");
901 }
902}
903
904/*!
905 \qmlmethod void QtLocation::RouteQuery::clearWaypoints()
906
907 Clears all waypoints.
908
909 \sa removeWaypoint, addWaypoint
910*/
911void QDeclarativeGeoRouteQuery::clearWaypoints()
912{
913 if (m_waypoints.isEmpty())
914 return;
915
916 m_waypoints.clear();
917 waypointChanged();
918}
919
920/*!
921 \qmlmethod void QtLocation::RouteQuery::setFeatureWeight(FeatureType feature, FeatureWeight weight)
922
923 Defines the \a weight to associate with a \a feature during the planning
924 of a route.
925
926 Following lists the possible feature weights:
927
928 \value RouteQuery.NeutralFeatureWeight
929 The presence or absence of the feature does not affect the planning of the
930 route
931
932 \value RouteQuery.PreferFeatureWeight
933 Routes which contain the feature are preferred over those that do not
934
935 \value RouteQuery.RequireFeatureWeight
936 Only routes which contain the feature are considered, otherwise no
937 route will be returned
938
939 \value RouteQuery.AvoidFeatureWeight
940 Routes which do not contain the feature are preferred over those that
941 do
942
943 \value RouteQuery.DisallowFeatureWeight
944 Only routes which do not contain the feature are considered, otherwise
945 no route will be returned
946
947 \sa featureTypes, resetFeatureWeights, featureWeight
948
949*/
950
951void QDeclarativeGeoRouteQuery::setFeatureWeight(FeatureType featureType, FeatureWeight featureWeight)
952{
953 if (featureType == NoFeature && !request_.featureTypes().isEmpty()) {
954 resetFeatureWeights();
955 return;
956 }
957
958 // Check if the weight changes, as we need to signal it
959 FeatureWeight originalWeight = static_cast<FeatureWeight>(request_.featureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType)));
960 if (featureWeight == originalWeight)
961 return;
962
963 request_.setFeatureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType),
964 static_cast<QGeoRouteRequest::FeatureWeight>(featureWeight));
965 if (complete_ && ((originalWeight == NeutralFeatureWeight) || (featureWeight == NeutralFeatureWeight))) {
966 // featureTypes should now give a different list, because the original and new weight
967 // were not same, and other one was neutral weight
968 emit featureTypesChanged();
969 emit queryDetailsChanged();
970 }
971}
972
973/*!
974 \qmlmethod void QtLocation::RouteQuery::resetFeatureWeights()
975
976 Resets all feature weights to their default state (NeutralFeatureWeight).
977
978 \sa featureTypes, setFeatureWeight, featureWeight
979*/
980void QDeclarativeGeoRouteQuery::resetFeatureWeights()
981{
982 // reset all feature types.
983 const auto featureTypes = request_.featureTypes();
984 for (const auto &featureType : featureTypes)
985 request_.setFeatureWeight(featureType, QGeoRouteRequest::NeutralFeatureWeight);
986 if (complete_) {
987 emit featureTypesChanged();
988 emit queryDetailsChanged();
989 }
990}
991
992/*!
993 \qmlmethod FeatureWeight QtLocation::RouteQuery::featureWeight(FeatureType featureType)
994
995 Gets the weight for the \a featureType.
996
997 \sa featureTypes, setFeatureWeight, resetFeatureWeights
998*/
999
1000int QDeclarativeGeoRouteQuery::featureWeight(FeatureType featureType)
1001{
1002 return request_.featureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType));
1003}
1004
1005/*!
1006 \internal
1007*/
1008void QDeclarativeGeoRouteQuery::setTravelModes(QDeclarativeGeoRouteQuery::TravelModes travelModes)
1009{
1010 QGeoRouteRequest::TravelModes reqTravelModes;
1011
1012 if (travelModes & QDeclarativeGeoRouteQuery::CarTravel)
1013 reqTravelModes |= QGeoRouteRequest::CarTravel;
1014 if (travelModes & QDeclarativeGeoRouteQuery::PedestrianTravel)
1015 reqTravelModes |= QGeoRouteRequest::PedestrianTravel;
1016 if (travelModes & QDeclarativeGeoRouteQuery::BicycleTravel)
1017 reqTravelModes |= QGeoRouteRequest::BicycleTravel;
1018 if (travelModes & QDeclarativeGeoRouteQuery::PublicTransitTravel)
1019 reqTravelModes |= QGeoRouteRequest::PublicTransitTravel;
1020 if (travelModes & QDeclarativeGeoRouteQuery::TruckTravel)
1021 reqTravelModes |= QGeoRouteRequest::TruckTravel;
1022
1023 if (reqTravelModes == request_.travelModes())
1024 return;
1025
1026 request_.setTravelModes(reqTravelModes);
1027
1028 if (complete_) {
1029 emit travelModesChanged();
1030 emit queryDetailsChanged();
1031 }
1032}
1033
1034
1035/*!
1036 \qmlproperty enumeration RouteQuery::segmentDetail
1037
1038 The level of detail which will be used in the representation of routing segments.
1039
1040 \value RouteQuery.NoSegmentData
1041 No segment data should be included with the route
1042
1043 \value RouteQuery.BasicSegmentData
1044 Basic segment data will be included with the route
1045
1046 The default value is \c {RouteQuery.BasicSegmentData}.
1047*/
1048
1049void QDeclarativeGeoRouteQuery::setSegmentDetail(SegmentDetail segmentDetail)
1050{
1051 if (static_cast<QGeoRouteRequest::SegmentDetail>(segmentDetail) == request_.segmentDetail())
1052 return;
1053 request_.setSegmentDetail(static_cast<QGeoRouteRequest::SegmentDetail>(segmentDetail));
1054 if (complete_) {
1055 emit segmentDetailChanged();
1056 emit queryDetailsChanged();
1057 }
1058}
1059
1060QDeclarativeGeoRouteQuery::SegmentDetail QDeclarativeGeoRouteQuery::segmentDetail() const
1061{
1062 return static_cast<QDeclarativeGeoRouteQuery::SegmentDetail>(request_.segmentDetail());
1063}
1064
1065/*!
1066 \qmlproperty enumeration RouteQuery::maneuverDetail
1067
1068 The level of detail which will be used in the representation of routing maneuvers.
1069
1070 \value RouteQuery.NoManeuvers
1071 No maneuvers should be included with the route
1072
1073 \value RouteQuery.BasicManeuvers
1074 Basic maneuvers will be included with the route
1075
1076 The default value is \c {RouteQuery.BasicManeuvers}.
1077*/
1078
1079void QDeclarativeGeoRouteQuery::setManeuverDetail(ManeuverDetail maneuverDetail)
1080{
1081 if (static_cast<QGeoRouteRequest::ManeuverDetail>(maneuverDetail) == request_.maneuverDetail())
1082 return;
1083 request_.setManeuverDetail(static_cast<QGeoRouteRequest::ManeuverDetail>(maneuverDetail));
1084 if (complete_) {
1085 emit maneuverDetailChanged();
1086 emit queryDetailsChanged();
1087 }
1088}
1089
1090QDeclarativeGeoRouteQuery::ManeuverDetail QDeclarativeGeoRouteQuery::maneuverDetail() const
1091{
1092 return static_cast<QDeclarativeGeoRouteQuery::ManeuverDetail>(request_.maneuverDetail());
1093}
1094
1095/*!
1096 \qmlproperty enumeration RouteQuery::travelModes
1097
1098 The travel modes which should be considered during the planning of the route.
1099 Values can be combined with OR ('|') -operator.
1100
1101 \value RouteQuery.CarTravel
1102 The route will be optimized for someone who is driving a car
1103
1104 \value RouteQuery.PedestrianTravel
1105 The route will be optimized for someone who is walking
1106
1107 \value RouteQuery.BicycleTravel
1108 The route will be optimized for someone who is riding a bicycle
1109
1110 \value RouteQuery.PublicTransit
1111 Travel The route will be optimized for someone who is making use of public transit
1112
1113 \value RouteQuery.TruckTravel
1114 The route will be optimized for someone who is driving a truck
1115
1116 The default value is \c {RouteQuery.CarTravel}.
1117*/
1118
1119QDeclarativeGeoRouteQuery::TravelModes QDeclarativeGeoRouteQuery::travelModes() const
1120{
1121 QGeoRouteRequest::TravelModes reqTravelModes = request_.travelModes();
1122 QDeclarativeGeoRouteQuery::TravelModes travelModes;
1123
1124 if (reqTravelModes & QGeoRouteRequest::CarTravel)
1125 travelModes |= QDeclarativeGeoRouteQuery::CarTravel;
1126 if (reqTravelModes & QGeoRouteRequest::PedestrianTravel)
1127 travelModes |= QDeclarativeGeoRouteQuery::PedestrianTravel;
1128 if (reqTravelModes & QGeoRouteRequest::BicycleTravel)
1129 travelModes |= QDeclarativeGeoRouteQuery::BicycleTravel;
1130 if (reqTravelModes & QGeoRouteRequest::PublicTransitTravel)
1131 travelModes |= QDeclarativeGeoRouteQuery::PublicTransitTravel;
1132 if (reqTravelModes & QGeoRouteRequest::TruckTravel)
1133 travelModes |= QDeclarativeGeoRouteQuery::TruckTravel;
1134
1135 return travelModes;
1136}
1137
1138/*!
1139 \qmlproperty enumeration RouteQuery::routeOptimizations
1140
1141 The route optimizations which should be considered during the planning of the route.
1142 Values can be combined with OR ('|') -operator.
1143
1144
1145 \value RouteQuery.ShortestRoute
1146 Minimize the length of the journey
1147
1148 \value RouteQuery.FastestRoute
1149 Minimize the traveling time for the journey
1150
1151 \value RouteQuery.MostEconomicRoute
1152 Minimize the cost of the journey
1153
1154 \value RouteQuery.MostScenicRoute
1155 Maximize the scenic potential of the journey
1156
1157 The default value is \c {RouteQuery.FastestRoute}.
1158*/
1159
1160QDeclarativeGeoRouteQuery::RouteOptimizations QDeclarativeGeoRouteQuery::routeOptimizations() const
1161{
1162 QGeoRouteRequest::RouteOptimizations reqOptimizations = request_.routeOptimization();
1163 QDeclarativeGeoRouteQuery::RouteOptimizations optimization;
1164
1165 if (reqOptimizations & QGeoRouteRequest::ShortestRoute)
1166 optimization |= QDeclarativeGeoRouteQuery::ShortestRoute;
1167 if (reqOptimizations & QGeoRouteRequest::FastestRoute)
1168 optimization |= QDeclarativeGeoRouteQuery::FastestRoute;
1169 if (reqOptimizations & QGeoRouteRequest::MostEconomicRoute)
1170 optimization |= QDeclarativeGeoRouteQuery::MostEconomicRoute;
1171 if (reqOptimizations & QGeoRouteRequest::MostScenicRoute)
1172 optimization |= QDeclarativeGeoRouteQuery::MostScenicRoute;
1173
1174 return optimization;
1175}
1176
1177/*!
1178 \qmlproperty date RouteQuery::departureTime
1179
1180 The departure time to be used when querying for the route.
1181 The default value is an invalid date, meaning no departure time will be used in the query.
1182
1183 \since 5.13
1184*/
1185void QDeclarativeGeoRouteQuery::setDepartureTime(const QDateTime &departureTime)
1186{
1187 if (departureTime == request_.departureTime())
1188 return;
1189
1190 request_.setDepartureTime(departureTime);
1191 if (complete_) {
1192 emit departureTimeChanged();
1193 emit queryDetailsChanged();
1194 }
1195}
1196
1197QDateTime QDeclarativeGeoRouteQuery::departureTime() const
1198{
1199 return request_.departureTime();
1200}
1201
1202void QDeclarativeGeoRouteQuery::setRouteOptimizations(QDeclarativeGeoRouteQuery::RouteOptimizations optimization)
1203{
1204 QGeoRouteRequest::RouteOptimizations reqOptimizations;
1205
1206 if (optimization & QDeclarativeGeoRouteQuery::ShortestRoute)
1207 reqOptimizations |= QGeoRouteRequest::ShortestRoute;
1208 if (optimization & QDeclarativeGeoRouteQuery::FastestRoute)
1209 reqOptimizations |= QGeoRouteRequest::FastestRoute;
1210 if (optimization & QDeclarativeGeoRouteQuery::MostEconomicRoute)
1211 reqOptimizations |= QGeoRouteRequest::MostEconomicRoute;
1212 if (optimization & QDeclarativeGeoRouteQuery::MostScenicRoute)
1213 reqOptimizations |= QGeoRouteRequest::MostScenicRoute;
1214
1215 if (reqOptimizations == request_.routeOptimization())
1216 return;
1217
1218 request_.setRouteOptimization(reqOptimizations);
1219
1220 if (complete_) {
1221 emit routeOptimizationsChanged();
1222 emit queryDetailsChanged();
1223 }
1224}
1225
1226/*!
1227 \internal
1228*/
1229QGeoRouteRequest QDeclarativeGeoRouteQuery::routeRequest() const
1230{
1231 if (m_waypointsChanged) {
1232 m_waypointsChanged = false;
1233 // Update waypoints and metadata into request
1234 request_.setWaypoints(m_waypoints);
1235 }
1236 return request_;
1237}
1238
1239void QDeclarativeGeoRouteQuery::excludedAreaCoordinateChanged()
1240{
1241 if (!m_excludedAreaCoordinateChanged) {
1242 m_excludedAreaCoordinateChanged = true;
1243 QMetaObject::invokeMethod(this, "doCoordinateChanged", Qt::QueuedConnection);
1244 }
1245}
1246
1247void QDeclarativeGeoRouteQuery::waypointChanged()
1248{
1249 m_waypointsChanged = true;
1250 if (complete_) {
1251 emit waypointsChanged();
1252 emit queryDetailsChanged();
1253 }
1254}
1255
1256void QDeclarativeGeoRouteQuery::doCoordinateChanged()
1257{
1258 m_excludedAreaCoordinateChanged = false;
1259 if (complete_)
1260 emit queryDetailsChanged();
1261}
1262
1263QT_END_NAMESPACE