1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtLocation module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 
37 #include "qdeclarativegeoroutemodel_p.h"
38 #include "qdeclarativegeoroute_p.h"
39 #include "error_messages_p.h"
40 #include "locationvaluetypehelper_p.h"
41 
42 #include <QtCore/QCoreApplication>
43 #include <QtQml/QQmlEngine>
44 #include <QtQml/qqmlinfo.h>
45 #include <QtQml/private/qqmlengine_p.h>
46 #include <QtQml/private/qv4scopedvalue_p.h>
47 #include <QtQml/private/qv4arrayobject_p.h>
48 #include <QtLocation/QGeoRoutingManager>
49 #include <QtPositioning/QGeoRectangle>
50 #include "qdeclarativegeomapparameter_p.h"
51 
52 QT_BEGIN_NAMESPACE
53 
compareFloats(qreal a,qreal b)54 static bool compareFloats(qreal a, qreal b)
55 {
56     return (qIsNaN(a) && qIsNaN(b))
57            || a == b;
58 }
59 
compareParameterList(const QList<QDeclarativeGeoMapParameter * > & a,const QList<QDeclarativeGeoMapParameter * > & b)60 static bool compareParameterList(const QList<QDeclarativeGeoMapParameter *> &a, const QList<QDeclarativeGeoMapParameter *> &b)
61 {
62     if (a.size() != b.size())
63         return false;
64     if (a != b) {
65         for (int i = 0; i < a.size(); ++i) {
66             if (! (*a.at(i) == *b.at(i)))
67                 return false;
68         }
69     }
70     return true;
71 }
72 
findWaypoint(const QList<QDeclarativeGeoWaypoint * > & waypoints,const QDeclarativeGeoWaypoint * w)73 static int findWaypoint(const QList<QDeclarativeGeoWaypoint *> &waypoints, const QDeclarativeGeoWaypoint *w)
74 {
75     for (int i = waypoints.size() - 1; i >= 0; --i) {
76         if (waypoints.at(i) == w || *waypoints.at(i) == *w)
77             return i;
78     }
79     return -1;
80 }
81 
findWaypoint(const QList<QDeclarativeGeoWaypoint * > & waypoints,const QGeoCoordinate & c)82 static int findWaypoint(const QList<QDeclarativeGeoWaypoint *> &waypoints, const QGeoCoordinate &c)
83 {
84     for (int i = waypoints.size() - 1; i >= 0; --i) {
85         if (waypoints.at(i)->coordinate() == c)
86             return i;
87     }
88     return -1;
89 }
90 
waypointCoordinates(const QList<QDeclarativeGeoWaypoint * > & waypoints)91 static QList<QGeoCoordinate> waypointCoordinates(const QList<QDeclarativeGeoWaypoint *> &waypoints)
92 {
93     QList<QGeoCoordinate> res;
94     for (const QDeclarativeGeoWaypoint *w: waypoints)
95         res << w->coordinate();
96     return res;
97 }
98 
waypointMetadata(const QList<QDeclarativeGeoWaypoint * > & waypoints)99 static QList<QVariantMap> waypointMetadata(const QList<QDeclarativeGeoWaypoint *> &waypoints)
100 {
101     QList<QVariantMap> res;
102     for (QDeclarativeGeoWaypoint *w: waypoints)
103         res << w->metadata();
104     return res;
105 }
106 
107 /*!
108     \qmltype RouteModel
109     \instantiates QDeclarativeGeoRouteModel
110     \inqmlmodule QtLocation
111     \ingroup qml-QtLocation5-routing
112     \since QtLocation 5.5
113 
114     \brief The RouteModel type provides access to routes.
115 
116     The RouteModel type is used as part of a model/view grouping to retrieve
117     geographic routes from a backend provider. Routes include data about driving
118     directions between two points, walking directions with multiple waypoints,
119     and various other similar concepts. It functions much like other Model
120     types in QML (see for example \l {Models and Views in Qt Quick#Models}{ListModel}
121     and \l {QtQuick.XmlListModel::XmlListModel}{XmlListModel}), and interacts with
122     views such as \l MapItemView, and \l{ListView}.
123 
124     Like \l Map and \l GeocodeModel, all the data for a RouteModel to work comes
125     from a services plugin. This is contained in the \l{plugin} property, and
126     this must be set before the RouteModel can do any useful work.
127 
128     Once the plugin is set, create a \l RouteQuery with the appropriate
129     waypoints and other settings, and set the RouteModel's \l{query}
130     property. If \l autoUpdate is enabled, the update will being automatically.
131     Otherwise, the \l{update} method may be used. By default, autoUpdate is
132     disabled.
133 
134     The data stored and returned in the RouteModel consists of \l Route objects,
135     as a list with the role name "routeData". See the documentation for \l Route
136     for further details on its structure and contents.
137 
138     \section2 Example Usage
139 
140     The following snippet is two-part, showing firstly the declaration of
141     objects, and secondly a short piece of procedural code using it. We set
142     the routeModel's \l{autoUpdate} property to false, and call \l{update} once
143     the query is set up, to avoid useless extra requests halfway through the
144     set up of the query.
145 
146     \code
147     Plugin {
148         id: aPlugin
149         name: "osm"
150     }
151 
152     RouteQuery {
153         id: aQuery
154     }
155 
156     RouteModel {
157         id: routeModel
158         plugin: aPlugin
159         query: aQuery
160         autoUpdate: false
161     }
162     \endcode
163 
164     \code
165     {
166         aQuery.addWaypoint(...)
167         aQuery.addWaypoint(...)
168         aQuery.travelModes = ...
169         routeModel.update()
170     }
171     \endcode
172 
173 */
174 
QDeclarativeGeoRouteModel(QObject * parent)175 QDeclarativeGeoRouteModel::QDeclarativeGeoRouteModel(QObject *parent)
176     : QAbstractListModel(parent),
177       complete_(false),
178       plugin_(0),
179       routeQuery_(0),
180       autoUpdate_(false),
181       status_(QDeclarativeGeoRouteModel::Null),
182       error_(QDeclarativeGeoRouteModel::NoError)
183 {
184 }
185 
~QDeclarativeGeoRouteModel()186 QDeclarativeGeoRouteModel::~QDeclarativeGeoRouteModel()
187 {
188     if (!routes_.empty()) {
189         qDeleteAll(routes_);
190         routes_.clear();
191     }
192 }
193 
194 /*!
195     \qmlproperty int QtLocation::RouteModel::count
196 
197     This property holds how many routes the model currently has.
198     Amongst other uses, you can use this value when accessing routes
199     via the QtLocation::RouteModel::get -method.
200 */
201 
count() const202 int QDeclarativeGeoRouteModel::count() const
203 {
204     return routes_.count();
205 }
206 
207 /*!
208     \qmlmethod void QtLocation::RouteModel::reset()
209 
210     Resets the model. All route data is cleared, any outstanding requests
211     are aborted and possible errors are cleared. Model status will be set
212     to RouteModel.Null
213 */
214 
reset()215 void QDeclarativeGeoRouteModel::reset()
216 {
217     if (!routes_.isEmpty()) {
218         beginResetModel();
219         qDeleteAll(routes_);
220         routes_.clear();
221         emit countChanged();
222         emit routesChanged();
223         endResetModel();
224     }
225 
226     emit abortRequested();
227     setError(NoError, QString());
228     setStatus(QDeclarativeGeoRouteModel::Null);
229 }
230 
231 /*!
232     \qmlmethod void QtLocation::RouteModel::cancel()
233 
234     Cancels any outstanding requests and clears errors.  Model status will be set to either
235     RouteModel.Null or RouteModel.Ready.
236 */
cancel()237 void QDeclarativeGeoRouteModel::cancel()
238 {
239     emit abortRequested();
240     setError(NoError, QString());
241     setStatus(routes_.isEmpty() ? Null : Ready);
242 }
243 
244 /*!
245     \qmlmethod Route QtLocation::RouteModel::get(int index)
246 
247     Returns the Route at the specified \a index. Use the \l count
248     property to check the amount of routes available. The routes
249     are indexed from zero, so the accessible range is 0...(count - 1).
250 
251     If you access out of bounds, a zero (null object) is returned and
252     a warning is issued.
253 */
254 
get(int index)255 QDeclarativeGeoRoute *QDeclarativeGeoRouteModel::get(int index)
256 {
257     if (index < 0 || index >= routes_.count()) {
258         qmlWarning(this) << QStringLiteral("Index '%1' out of range").arg(index);
259         return 0;
260     }
261     return routes_.at(index);
262 }
263 
264 /*!
265     \internal
266 */
componentComplete()267 void QDeclarativeGeoRouteModel::componentComplete()
268 {
269     complete_ = true;
270     if (autoUpdate_) {
271         update();
272     }
273 }
274 
275 /*!
276     \internal
277 */
rowCount(const QModelIndex & parent) const278 int QDeclarativeGeoRouteModel::rowCount(const QModelIndex &parent) const
279 {
280     Q_UNUSED(parent);
281     return routes_.count();
282 }
283 
284 /*!
285     \internal
286 */
data(const QModelIndex & index,int role) const287 QVariant QDeclarativeGeoRouteModel::data(const QModelIndex &index, int role) const
288 {
289     if (!index.isValid()) {
290         qmlWarning(this) << QStringLiteral("Error in indexing route model's data (invalid index).");
291         return QVariant();
292     }
293 
294     if (index.row() >= routes_.count()) {
295         qmlWarning(this) << QStringLiteral("Fatal error in indexing route model's data (index overflow).");
296         return QVariant();
297     }
298 
299     if (role == RouteRole) {
300         QObject *route = routes_.at(index.row());
301         return QVariant::fromValue(route);
302     }
303     return QVariant();
304 }
305 
roleNames() const306 QHash<int, QByteArray> QDeclarativeGeoRouteModel::roleNames() const
307 {
308     QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
309     roleNames.insert(RouteRole, "routeData");
310     return roleNames;
311 }
312 
313 /*!
314     \internal
315 */
setPlugin(QDeclarativeGeoServiceProvider * plugin)316 void QDeclarativeGeoRouteModel::setPlugin(QDeclarativeGeoServiceProvider *plugin)
317 {
318     if (plugin_ == plugin)
319         return;
320 
321     reset(); // reset the model
322 
323     if (plugin_)
324         disconnect(plugin_, SIGNAL(localesChanged()), this, SIGNAL(measurementSystemChanged()));
325     if (plugin)
326         connect(plugin, SIGNAL(localesChanged()), this, SIGNAL(measurementSystemChanged()));
327 
328     plugin_ = plugin;
329 
330     if (complete_)
331         emit pluginChanged();
332 
333     if (!plugin)
334         return;
335 
336     if (plugin_->isAttached()) {
337         pluginReady();
338     } else {
339         connect(plugin_, SIGNAL(attached()),
340                 this, SLOT(pluginReady()));
341     }
342 }
343 
344 /*!
345     \internal
346 */
pluginReady()347 void QDeclarativeGeoRouteModel::pluginReady()
348 {
349     QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
350     QGeoRoutingManager *routingManager = serviceProvider->routingManager();
351 
352     if (serviceProvider->routingError() != QGeoServiceProvider::NoError) {
353         QDeclarativeGeoRouteModel::RouteError newError = UnknownError;
354         switch (serviceProvider->routingError()) {
355         case QGeoServiceProvider::NotSupportedError:
356             newError = EngineNotSetError; break;
357         case QGeoServiceProvider::UnknownParameterError:
358             newError = UnknownParameterError; break;
359         case QGeoServiceProvider::MissingRequiredParameterError:
360             newError = MissingRequiredParameterError; break;
361         case QGeoServiceProvider::ConnectionError:
362             newError = CommunicationError; break;
363         default:
364             break;
365         }
366 
367         setError(newError, serviceProvider->routingErrorString());
368         return;
369     }
370 
371     if (!routingManager) {
372         setError(EngineNotSetError, tr("Plugin does not support routing."));
373         return;
374     }
375 
376     connect(routingManager, SIGNAL(finished(QGeoRouteReply*)),
377             this, SLOT(routingFinished(QGeoRouteReply*)));
378     connect(routingManager, SIGNAL(error(QGeoRouteReply*,QGeoRouteReply::Error,QString)),
379             this, SLOT(routingError(QGeoRouteReply*,QGeoRouteReply::Error,QString)));
380 }
381 
382 /*!
383     \internal
384 */
queryDetailsChanged()385 void QDeclarativeGeoRouteModel::queryDetailsChanged()
386 {
387     if (autoUpdate_ && complete_)
388         update();
389 }
390 
391 /*!
392     \qmlproperty Plugin QtLocation::RouteModel::plugin
393 
394     This property holds the plugin that providers the actual
395     routing service. Note that all plugins do not necessarily
396     provide routing (could for example provide only geocoding or maps).
397 
398     A valid plugin must be set before the RouteModel can perform any useful
399     operations.
400 
401     \sa Plugin
402 */
403 
plugin() const404 QDeclarativeGeoServiceProvider *QDeclarativeGeoRouteModel::plugin() const
405 {
406     return plugin_;
407 }
408 
409 /*!
410     \internal
411 */
setQuery(QDeclarativeGeoRouteQuery * query)412 void QDeclarativeGeoRouteModel::setQuery(QDeclarativeGeoRouteQuery *query)
413 {
414     if (!query || query == routeQuery_)
415         return;
416     if (routeQuery_)
417         routeQuery_->disconnect(this);
418     routeQuery_ = query;
419     connect(query, SIGNAL(queryDetailsChanged()), this, SLOT(queryDetailsChanged()));
420     if (complete_) {
421         emit queryChanged();
422         if (autoUpdate_)
423             update();
424     }
425 }
426 
427 /*!
428     \qmlproperty RouteQuery QtLocation::RouteModel::query
429 
430     This property holds the data of the route request.
431     The primary data are the waypoint coordinates and possible further
432     preferences (means of traveling, things to avoid on route etc).
433 */
434 
query() const435 QDeclarativeGeoRouteQuery *QDeclarativeGeoRouteModel::query() const
436 {
437     return routeQuery_;
438 }
439 
440 /*!
441     \internal
442 */
setAutoUpdate(bool autoUpdate)443 void QDeclarativeGeoRouteModel::setAutoUpdate(bool autoUpdate)
444 {
445     if (autoUpdate_ == autoUpdate)
446         return;
447     autoUpdate_ = autoUpdate;
448     if (complete_)
449         emit autoUpdateChanged();
450 }
451 
452 /*!
453     \qmlproperty bool QtLocation::RouteModel::autoUpdate
454 
455     This property controls whether the Model automatically updates in response
456     to changes in its attached RouteQuery. The default value of this property
457     is false.
458 
459     If setting this value to 'true', note that any change at all in
460     the RouteQuery object set in the \l{query} property will trigger a new
461     request to be sent. If you are adjusting many properties of the RouteQuery
462     with autoUpdate enabled, this can generate large numbers of useless (and
463     later discarded) requests.
464 */
465 
autoUpdate() const466 bool QDeclarativeGeoRouteModel::autoUpdate() const
467 {
468     return autoUpdate_;
469 }
470 
471 /*!
472     \qmlproperty Locale::MeasurementSystem QtLocation::RouteModel::measurementSystem
473 
474     This property holds the measurement system which will be used when calculating the route. This
475     property is changed when the \l {QtLocation::Plugin::locales}{Plugin::locales} property of
476     \l {QtLocation::RouteModel::plugin}{plugin} changes.
477 
478     If setting this property it must be set after the \l {QtLocation::RouteModel::plugin}{plugin}
479     property is set.
480 */
setMeasurementSystem(QLocale::MeasurementSystem ms)481 void QDeclarativeGeoRouteModel::setMeasurementSystem(QLocale::MeasurementSystem ms)
482 {
483     if (!plugin_)
484         return;
485 
486     QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
487     if (!serviceProvider)
488         return;
489 
490     QGeoRoutingManager *routingManager = serviceProvider->routingManager();
491     if (!routingManager)
492         return;
493 
494     if (routingManager->measurementSystem() == ms)
495         return;
496 
497     routingManager->setMeasurementSystem(ms);
498     emit measurementSystemChanged();
499 }
500 
measurementSystem() const501 QLocale::MeasurementSystem QDeclarativeGeoRouteModel::measurementSystem() const
502 {
503     if (!plugin_)
504         return QLocale().measurementSystem();
505 
506     QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
507     if (!serviceProvider) {
508         if (plugin_->locales().isEmpty())
509             return QLocale().measurementSystem();
510 
511         return QLocale(plugin_->locales().first()).measurementSystem();
512     }
513 
514     QGeoRoutingManager *routingManager = serviceProvider->routingManager();
515     if (!routingManager) {
516         if (plugin_->locales().isEmpty())
517             return QLocale().measurementSystem();
518 
519         return QLocale(plugin_->locales().first()).measurementSystem();
520     }
521 
522     return routingManager->measurementSystem();
523 }
524 
525 /*!
526     \internal
527 */
setStatus(QDeclarativeGeoRouteModel::Status status)528 void QDeclarativeGeoRouteModel::setStatus(QDeclarativeGeoRouteModel::Status status)
529 {
530     if (status_ == status)
531         return;
532 
533     status_ = status;
534 
535     if (complete_)
536         emit statusChanged();
537 }
538 
539 /*!
540     \qmlproperty enumeration QtLocation::RouteModel::status
541 
542     This read-only property holds the current status of the model.
543 
544     \list
545     \li RouteModel.Null - No route requests have been issued or \l reset has been called.
546     \li RouteModel.Ready - Route request(s) have finished successfully.
547     \li RouteModel.Loading - Route request has been issued but not yet finished
548     \li RouteModel.Error - Routing error has occurred, details are in \l error and \l errorString
549     \endlist
550 */
551 
status() const552 QDeclarativeGeoRouteModel::Status QDeclarativeGeoRouteModel::status() const
553 {
554     return status_;
555 }
556 
557 /*!
558     \qmlproperty string QtLocation::RouteModel::errorString
559 
560     This read-only property holds the textual presentation of the latest routing error.
561     If no error has occurred or the model has been reset, an empty string is returned.
562 
563     An empty string may also be returned if an error occurred which has no associated
564     textual representation.
565 */
566 
errorString() const567 QString QDeclarativeGeoRouteModel::errorString() const
568 {
569     return errorString_;
570 }
571 
572 /*!
573     \qmlproperty enumeration QtLocation::RouteModel::error
574 
575     This read-only property holds the latest error value of the routing request.
576 
577     \list
578     \li RouteModel.NoError - No error has occurred.
579     \li RouteModel.CommunicationError - An error occurred while communicating with the service provider.
580     \li RouteModel.EngineNotSetError - The model's plugin property was not set or there is no routing manager associated with the plugin.
581     \li RouteModel.MissingRequiredParameterError - A required parameter was not specified.
582     \li RouteModel.ParseError - The response from the service provider was in an unrecognizable format.
583     \li RouteModel.UnknownError - An error occurred which does not fit into any of the other categories.
584     \li RouteModel.UnknownParameterError - The plugin did not recognize one of the parameters it was given.
585     \li RouteModel.UnsupportedOptionError - The requested operation is not supported by the routing provider.
586                                             This may happen when the loaded engine does not support a particular
587                                             type of routing request.
588     \endlist
589 */
590 
error() const591 QDeclarativeGeoRouteModel::RouteError QDeclarativeGeoRouteModel::error() const
592 {
593     return error_;
594 }
595 
setError(RouteError error,const QString & errorString)596 void QDeclarativeGeoRouteModel::setError(RouteError error, const QString& errorString)
597 {
598     if (error_ == error && errorString_ == errorString)
599         return;
600     error_ = error;
601     errorString_ = errorString;
602     emit errorChanged();
603 }
604 
605 /*!
606     \qmlmethod void QtLocation::RouteModel::update()
607 
608     Instructs the RouteModel to update its data. This is most useful
609     when \l autoUpdate is disabled, to force a refresh when the query
610     has been changed.
611 */
update()612 void QDeclarativeGeoRouteModel::update()
613 {
614     if (!complete_)
615         return;
616 
617     if (!plugin_) {
618         setError(EngineNotSetError, tr("Cannot route, plugin not set."));
619         return;
620     }
621 
622     QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
623     if (!serviceProvider)
624         return;
625 
626     QGeoRoutingManager *routingManager = serviceProvider->routingManager();
627     if (!routingManager) {
628         setError(EngineNotSetError, tr("Cannot route, route manager not set."));
629         return;
630     }
631     if (!routeQuery_) {
632         setError(ParseError, tr("Cannot route, valid query not set."));
633         return;
634     }
635     emit abortRequested(); // Clear previous requests
636     QGeoRouteRequest request = routeQuery_->routeRequest();
637     if (request.waypoints().count() < 2) {
638         setError(ParseError,tr("Not enough waypoints for routing."));
639         return;
640     }
641 
642     setError(NoError, QString());
643 
644     QGeoRouteReply *reply = routingManager->calculateRoute(request);
645     setStatus(QDeclarativeGeoRouteModel::Loading);
646     if (!reply->isFinished()) {
647         connect(this, &QDeclarativeGeoRouteModel::abortRequested, reply, &QGeoRouteReply::abort);
648     } else {
649         if (reply->error() == QGeoRouteReply::NoError) {
650             routingFinished(reply);
651         } else {
652             routingError(reply, reply->error(), reply->errorString());
653         }
654     }
655 }
656 
657 /*!
658     \internal
659 */
routingFinished(QGeoRouteReply * reply)660 void QDeclarativeGeoRouteModel::routingFinished(QGeoRouteReply *reply)
661 {
662     if (!reply)
663         return;
664     reply->deleteLater();
665     if (reply->error() != QGeoRouteReply::NoError)
666         return;
667 
668     beginResetModel();
669     int oldCount = routes_.count();
670     qDeleteAll(routes_);
671     // Convert routes to declarative
672     routes_.clear();
673     for (int i = 0; i < reply->routes().size(); ++i) {
674         QDeclarativeGeoRoute *route = new QDeclarativeGeoRoute(reply->routes().at(i), this);
675         QQmlEngine::setContextForObject(route, QQmlEngine::contextForObject(this));
676         routes_.append(route);
677     }
678     endResetModel();
679 
680     setError(NoError, QString());
681     setStatus(QDeclarativeGeoRouteModel::Ready);
682 
683     if (oldCount != 0 || routes_.count() != 0)
684         emit routesChanged();
685     if (oldCount != routes_.count())
686         emit countChanged();
687 }
688 
689 /*!
690     \internal
691 */
routingError(QGeoRouteReply * reply,QGeoRouteReply::Error error,const QString & errorString)692 void QDeclarativeGeoRouteModel::routingError(QGeoRouteReply *reply,
693                                                QGeoRouteReply::Error error,
694                                                const QString &errorString)
695 {
696     if (!reply)
697         return;
698     reply->deleteLater();
699     setError(static_cast<QDeclarativeGeoRouteModel::RouteError>(error), errorString);
700     setStatus(QDeclarativeGeoRouteModel::Error);
701 }
702 
703 
704 /*!
705     \qmltype RouteQuery
706     \instantiates QDeclarativeGeoRouteQuery
707     \inqmlmodule QtLocation
708     \ingroup qml-QtLocation5-routing
709     \since QtLocation 5.5
710 
711     \brief The RouteQuery type is used to provide query parameters to a
712            RouteModel.
713 
714     A RouteQuery is used to pack all the parameters necessary to make a request
715     to a routing service, which can then populate the contents of a RouteModel.
716 
717     These parameters describe key details of the route, such as \l waypoints to
718     pass through, \l excludedAreas to avoid, the \l travelModes in use, as well
719     as detailed preferences on how to optimize the route and what features
720     to prefer or avoid along the path (such as toll roads, highways, etc).
721 
722     RouteQuery objects are used exclusively to fill out the value of a
723     RouteModel's \l{RouteModel::query}{query} property, which can then begin
724     the retrieval process to populate the model.
725 
726     Some plugins might allow or require specific parameters to operate.
727     In order to specify these plugin-specific parameters, MapParameter elements
728     can be nested inside a RouteQuery.
729 
730     \section2 Example Usage
731 
732     The following snipped shows an incomplete example of creating a RouteQuery
733     object and setting it as the value of a RouteModel's \l{RouteModel::query}{query}
734     property.
735 
736     \code
737     RouteQuery {
738         id: aQuery
739     }
740 
741     RouteModel {
742         query: aQuery
743         autoUpdate: false
744     }
745     \endcode
746 
747     For a more complete example, see the documentation for the \l{RouteModel}
748     type, and the Mapviewer example.
749 
750     \sa RouteModel
751 
752 */
753 
QDeclarativeGeoRouteQuery(QObject * parent)754 QDeclarativeGeoRouteQuery::QDeclarativeGeoRouteQuery(QObject *parent)
755 :   QObject(parent), complete_(false), m_excludedAreaCoordinateChanged(false)
756 {
757 }
758 
QDeclarativeGeoRouteQuery(const QGeoRouteRequest & request,QObject * parent)759 QDeclarativeGeoRouteQuery::QDeclarativeGeoRouteQuery(const QGeoRouteRequest &request, QObject *parent)
760 :   QObject(parent), request_(request), complete_(false), m_excludedAreaCoordinateChanged(false)
761 {
762     // Extra params assumed to be already set in the request.
763     // Init waypoints
764     const QList<QGeoCoordinate> wpts = request_.waypoints();
765     const QList<QVariantMap> meta = request_.waypointsMetadata();
766     for (int i = 0; i < wpts.size(); ++i) {
767         QDeclarativeGeoWaypoint *w = new QDeclarativeGeoWaypoint(this);
768         w->setCoordinate(wpts.at(i));
769         w->setMetadata(meta.at(i));
770         m_waypoints << w;
771     }
772 }
773 
~QDeclarativeGeoRouteQuery()774 QDeclarativeGeoRouteQuery::~QDeclarativeGeoRouteQuery()
775 {
776 }
777 
778 /*!
779     \internal
780 */
componentComplete()781 void QDeclarativeGeoRouteQuery::componentComplete()
782 {
783     complete_ = true;
784 }
785 
786 /*!
787     \qmlproperty QList<FeatureType> RouteQuery::featureTypes
788 
789     List of features that will be considered when planning the
790     route. Features with a weight of NeutralFeatureWeight will not be returned.
791 
792     \list
793     \li RouteQuery.NoFeature - No features will be taken into account when planning the route
794     \li RouteQuery.TollFeature - Consider tollways when planning the route
795     \li RouteQuery.HighwayFeature - Consider highways when planning the route
796     \li RouteQuery.PublicTransitFeature - Consider public transit when planning the route
797     \li RouteQuery.FerryFeature - Consider ferries when planning the route
798     \li RouteQuery.TunnelFeature - Consider tunnels when planning the route
799     \li RouteQuery.DirtRoadFeature - Consider dirt roads when planning the route
800     \li RouteQuery.ParksFeature - Consider parks when planning the route
801     \li RouteQuery.MotorPoolLaneFeature - Consider motor pool lanes when planning the route
802     \li RouteQuery.TrafficFeature - Consider traffic when planning the route
803     \endlist
804 
805     \sa setFeatureWeight, featureWeight
806 */
807 
featureTypes()808 QList<int> QDeclarativeGeoRouteQuery::featureTypes()
809 {
810     QList<int> list;
811 
812     for (int i = 0; i < request_.featureTypes().count(); ++i) {
813         list.append(static_cast<int>(request_.featureTypes().at(i)));
814     }
815     return list;
816 }
817 
818 /*!
819     \qmlproperty int RouteQuery::numberAlternativeRoutes
820 
821     The number of alternative routes requested when requesting routes.
822     The default value is 0.
823 */
824 
825 
numberAlternativeRoutes() const826 int QDeclarativeGeoRouteQuery::numberAlternativeRoutes() const
827 {
828     return request_.numberAlternativeRoutes();
829 }
830 
setNumberAlternativeRoutes(int numberAlternativeRoutes)831 void QDeclarativeGeoRouteQuery::setNumberAlternativeRoutes(int numberAlternativeRoutes)
832 {
833     if (numberAlternativeRoutes == request_.numberAlternativeRoutes())
834         return;
835 
836     request_.setNumberAlternativeRoutes(numberAlternativeRoutes);
837 
838     if (complete_) {
839         emit numberAlternativeRoutesChanged();
840         emit queryDetailsChanged();
841     }
842 }
843 
844 /*!
845     \qmlproperty list<coordinate> RouteQuery::waypoints
846 
847 
848     The coordinates of the waypoints for the desired route.
849     The waypoints should be given in order from origin to destination.
850     Two or more coordinates are needed.
851 
852     Waypoints can be set as part of the RouteQuery type declaration or
853     dynamically with the functions provided.
854 
855     When setting this property to a list of waypoints, each waypoint
856     can be either a \l coordinate or a \l Waypoint, interchangeably.
857     If a \l coordinate is passed, it will be internally converted to a
858     \l Waypoint.
859 
860     This property, however, always contains a list of coordinates.
861 
862     \sa waypointObjects, addWaypoint, removeWaypoint, clearWaypoints
863 */
864 
waypoints()865 QVariantList QDeclarativeGeoRouteQuery::waypoints()
866 {
867     QVariantList res;
868 
869     for (const auto &w : m_waypoints)
870         res << QVariant::fromValue(w->coordinate());
871 
872     return res;
873 }
874 
875 /*!
876     \qmlmethod list<Waypoint> QtLocation::RouteQuery::waypointObjects()
877 
878     This method can be used to retrieve the list of Waypoint objects
879     relative to RouteQuery::waypoints.
880 
881     \sa waypointObjects, addWaypoint, removeWaypoint, clearWaypoints
882 */
waypointObjects()883 QVariantList QDeclarativeGeoRouteQuery::waypointObjects()
884 {
885     QVariantList res;
886 
887     for (const auto &w : m_waypoints)
888         res << QVariant::fromValue(w);
889 
890     return res;
891 }
892 
setWaypoints(const QVariantList & value)893 void QDeclarativeGeoRouteQuery::setWaypoints(const QVariantList &value)
894 {
895     QList<QDeclarativeGeoWaypoint *> waypointList;
896     bool allWaypoints = true;
897 
898     for (const auto &w: value) {
899         // First, test if this is already a QDeclarativeGeoWaypoint
900         // From QVariant to QObject *
901         QDeclarativeGeoWaypoint *waypoint = nullptr;
902         QObject *obj = qvariant_cast<QObject *>(w);
903         waypoint = qobject_cast<QDeclarativeGeoWaypoint *>(obj);
904 
905         if (waypoint) {
906             waypointList << waypoint;
907             continue;
908         }
909 
910         // if here, w is not a Waypoint, so either a QGeoCoordinate or a variant map, so a waypoint has to be instantiated.
911         allWaypoints = false;
912 
913         QGeoCoordinate c = parseCoordinate(w);
914         if (!c.isValid()) {
915             qmlWarning(this) << QStringLiteral("Invalid waypoint");
916             flushWaypoints(waypointList);
917             return;
918         }
919 
920         waypoint = new QDeclarativeGeoWaypoint(this);
921         waypoint->setCoordinate(c);
922         waypointList << waypoint;
923 
924     }
925 
926     if (allWaypoints && m_waypoints == waypointList)
927         return;
928 
929     flushWaypoints(m_waypoints);
930     m_waypoints = waypointList;
931     for (const QDeclarativeGeoWaypoint *w: qAsConst(m_waypoints))
932         connect(w, &QDeclarativeGeoWaypoint::waypointDetailsChanged, this, &QDeclarativeGeoRouteQuery::waypointChanged);
933 
934     waypointChanged();
935 }
936 
937 /*!
938     \qmlproperty list<georectangle> RouteQuery::excludedAreas
939 
940     Areas that the route must not cross.
941 
942     Excluded areas can be set as part of the \l RouteQuery type declaration or
943     dynamically with the functions provided.
944 
945     \sa addExcludedArea, removeExcludedArea, clearExcludedAreas
946 */
excludedAreas() const947 QJSValue QDeclarativeGeoRouteQuery::excludedAreas() const
948 {
949     QQmlContext *context = QQmlEngine::contextForObject(parent());
950     QQmlEngine *engine = context->engine();
951     QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
952 
953     QV4::Scope scope(v4);
954     QV4::Scoped<QV4::ArrayObject> excludedAreasArray(scope, v4->newArrayObject(request_.excludeAreas().length()));
955     for (int i = 0; i < request_.excludeAreas().length(); ++i) {
956         const QGeoRectangle &r = request_.excludeAreas().at(i);
957 
958         QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(r)));
959         excludedAreasArray->put(i, cv);
960     }
961 
962     return QJSValue(v4, excludedAreasArray.asReturnedValue());
963 }
964 
setExcludedAreas(const QJSValue & value)965 void QDeclarativeGeoRouteQuery::setExcludedAreas(const QJSValue &value)
966 {
967     if (!value.isArray())
968         return;
969 
970     QList<QGeoRectangle> excludedAreasList;
971     quint32 length = value.property(QStringLiteral("length")).toUInt();
972     for (quint32 i = 0; i < length; ++i) {
973         bool ok;
974         QGeoRectangle r = parseRectangle(value.property(i), &ok);
975 
976         if (!ok || !r.isValid()) {
977             qmlWarning(this) << QStringLiteral("Unsupported area type");
978             return;
979         }
980 
981         excludedAreasList.append(r);
982     }
983 
984     if (request_.excludeAreas() == excludedAreasList)
985         return;
986 
987     request_.setExcludeAreas(excludedAreasList);
988 
989     if (complete_) {
990         emit excludedAreasChanged();
991         emit queryDetailsChanged();
992     }
993 }
994 
995 /*!
996     \qmlmethod void QtLocation::RouteQuery::addExcludedArea(georectangle area)
997 
998     Adds the specified georectangle \a area to the excluded areas
999     (areas that the route must not cross).
1000     The same area can only be added once.
1001 
1002     \sa removeExcludedArea, clearExcludedAreas
1003 */
1004 
1005 
addExcludedArea(const QGeoRectangle & area)1006 void QDeclarativeGeoRouteQuery::addExcludedArea(const QGeoRectangle &area)
1007 {
1008     if (!area.isValid())
1009         return;
1010 
1011     QList<QGeoRectangle> excludedAreas = request_.excludeAreas();
1012 
1013     if (excludedAreas.contains(area))
1014         return;
1015 
1016     excludedAreas.append(area);
1017 
1018     request_.setExcludeAreas(excludedAreas);
1019 
1020     if (complete_) {
1021         emit excludedAreasChanged();
1022         emit queryDetailsChanged();
1023     }
1024 }
1025 
1026 /*!
1027     \qmlmethod void QtLocation::RouteQuery::removeExcludedArea(georectangle area)
1028 
1029     Removes the given \a area from excluded areas (areas that the route must not cross).
1030 
1031     \sa addExcludedArea, clearExcludedAreas
1032 */
1033 
removeExcludedArea(const QGeoRectangle & area)1034 void QDeclarativeGeoRouteQuery::removeExcludedArea(const QGeoRectangle &area)
1035 {
1036     if (!area.isValid())
1037         return;
1038 
1039     QList<QGeoRectangle> excludedAreas = request_.excludeAreas();
1040 
1041     int index = excludedAreas.lastIndexOf(area);
1042     if (index == -1) {
1043         qmlWarning(this) << QStringLiteral("Cannot remove nonexistent area.");
1044         return;
1045     }
1046     excludedAreas.removeAt(index);
1047     request_.setExcludeAreas(excludedAreas);
1048 
1049     if (complete_) {
1050         emit excludedAreasChanged();
1051         emit queryDetailsChanged();
1052     }
1053 }
1054 
1055 /*!
1056     \qmlmethod void QtLocation::RouteQuery::clearExcludedAreas()
1057 
1058     Clears all excluded areas (areas that the route must not cross).
1059 
1060     \sa addExcludedArea, removeExcludedArea
1061 */
1062 
clearExcludedAreas()1063 void QDeclarativeGeoRouteQuery::clearExcludedAreas()
1064 {
1065     if (request_.excludeAreas().isEmpty())
1066         return;
1067 
1068     request_.setExcludeAreas(QList<QGeoRectangle>());
1069 
1070     if (complete_) {
1071         emit excludedAreasChanged();
1072         emit queryDetailsChanged();
1073     }
1074 }
1075 
1076 /*!
1077     \qmlmethod void QtLocation::RouteQuery::addWaypoint(coordinate)
1078 
1079     Appends a coordinate to the list of waypoints. Same coordinate
1080     can be set multiple times.
1081     The \a coordinate argument can be a \l coordinate or a \l Waypoint.
1082     If a \l coordinate is used, it will be internally converted to a
1083     \l Waypoint.
1084 
1085     \sa removeWaypoint, clearWaypoints
1086 */
addWaypoint(const QVariant & waypoint)1087 void QDeclarativeGeoRouteQuery::addWaypoint(const QVariant &waypoint)
1088 {
1089     QDeclarativeGeoWaypoint *w = nullptr;
1090     QObject *obj = qvariant_cast<QObject *>(waypoint);
1091     w = qobject_cast<QDeclarativeGeoWaypoint *>(obj);
1092 
1093     if (w) {
1094         if (! w->isValid()) {
1095             qmlWarning(this) << QStringLiteral("Invalid waypoint");
1096             return;
1097         }
1098 
1099         m_waypoints << w;
1100         connect(w, &QDeclarativeGeoWaypoint::waypointDetailsChanged, this, &QDeclarativeGeoRouteQuery::waypointChanged);
1101         waypointChanged();
1102         return;
1103     }
1104 
1105     // if here, waypoint is not a Waypoint, so either a QGeoCoordinate or a variant map, so a waypoint has to be instantiated.
1106 
1107     QGeoCoordinate c = parseCoordinate(waypoint);
1108     if (!c.isValid()) {
1109         qmlWarning(this) << QStringLiteral("Invalid coordinate as waypoint");
1110         return;
1111     }
1112 
1113     w = new QDeclarativeGeoWaypoint(this);
1114     w->setCoordinate(c);
1115     m_waypoints << w;
1116     connect(w, &QDeclarativeGeoWaypoint::waypointDetailsChanged, this, &QDeclarativeGeoRouteQuery::waypointChanged);
1117     waypointChanged();
1118 }
1119 
1120 /*!
1121     \qmlmethod void QtLocation::RouteQuery::removeWaypoint(coordinate)
1122 
1123     Removes the given \a coordinate from the list of waypoints. If the
1124     same coordinate appears multiple times, the most recently added
1125     coordinate instance is removed.
1126 
1127     \sa addWaypoint, clearWaypoints
1128 */
removeWaypoint(const QVariant & waypoint)1129 void QDeclarativeGeoRouteQuery::removeWaypoint(const QVariant &waypoint)
1130 {
1131     QDeclarativeGeoWaypoint *w = nullptr;
1132     QObject *obj = qvariant_cast<QObject *>(waypoint);
1133     w = qobject_cast<QDeclarativeGeoWaypoint *>(obj);
1134 
1135     if (w) {
1136         if (!w->isValid()) {
1137             qmlWarning(this) << QStringLiteral("Invalid waypoint");
1138             return;
1139         }
1140 
1141         int idx = findWaypoint(m_waypoints, w);
1142         if (idx >= 0) {
1143             QDeclarativeGeoWaypoint *toRemove = m_waypoints.takeAt(idx);
1144             toRemove->disconnect(this);
1145             if (toRemove->parent() == this)
1146                 delete toRemove;
1147 
1148             waypointChanged();
1149         } else {
1150             qmlWarning(this) << QStringLiteral("Cannot remove nonexistent waypoint.");
1151         }
1152         return;
1153     }
1154 
1155     QGeoCoordinate c = parseCoordinate(waypoint);
1156     if (!c.isValid()) {
1157         qmlWarning(this) << QStringLiteral("Invalid coordinate as waypoint");
1158         return;
1159     }
1160 
1161     int idx = findWaypoint(m_waypoints, c);
1162     if (idx >= 0) {
1163         QDeclarativeGeoWaypoint *toRemove = m_waypoints.takeAt(idx);
1164         toRemove->disconnect(this);
1165         if (toRemove->parent() == this)
1166             delete toRemove;
1167 
1168         waypointChanged();
1169     } else {
1170         qmlWarning(this) << QStringLiteral("Cannot remove nonexistent waypoint.");
1171     }
1172 }
1173 
1174 /*!
1175     \qmlmethod void QtLocation::RouteQuery::clearWaypoints()
1176 
1177     Clears all waypoints.
1178 
1179     \sa removeWaypoint, addWaypoint
1180 */
clearWaypoints()1181 void QDeclarativeGeoRouteQuery::clearWaypoints()
1182 {
1183     if (m_waypoints.isEmpty())
1184         return;
1185 
1186     flushWaypoints(m_waypoints);
1187     waypointChanged();
1188 }
1189 
flushWaypoints(QList<QDeclarativeGeoWaypoint * > & waypoints)1190 void QDeclarativeGeoRouteQuery::flushWaypoints(QList<QDeclarativeGeoWaypoint *> &waypoints)
1191 {
1192     for (const QDeclarativeGeoWaypoint *w : qAsConst(waypoints)) {
1193         w->disconnect(this);
1194         if (w->parent() == this) // w has been created internally as a result of adding a QGeoCoordinate
1195             delete w;
1196     }
1197     waypoints.clear();
1198 }
1199 
1200 /*!
1201     \qmlmethod void QtLocation::RouteQuery::setFeatureWeight(FeatureType feature, FeatureWeight weight)
1202 
1203     Defines the \a weight  to associate with a \a feature during the planning
1204     of a route.
1205 
1206     Following lists the possible feature weights:
1207 
1208     \value RouteQuery.NeutralFeatureWeight
1209     The presence or absence of the feature does not affect the planning of the
1210     route
1211 
1212     \value RouteQuery.PreferFeatureWeight
1213     Routes which contain the feature are preferred over those that do not
1214 
1215     \value RouteQuery.RequireFeatureWeight
1216     Only routes which contain the feature are considered, otherwise no
1217     route will be returned
1218 
1219     \value RouteQuery.AvoidFeatureWeight
1220     Routes which do not contain the feature are preferred over those that
1221     do
1222 
1223     \value RouteQuery.DisallowFeatureWeight
1224     Only routes which do not contain the feature are considered, otherwise
1225     no route will be returned
1226 
1227     \sa featureTypes, resetFeatureWeights, featureWeight
1228 
1229 */
1230 
setFeatureWeight(FeatureType featureType,FeatureWeight featureWeight)1231 void QDeclarativeGeoRouteQuery::setFeatureWeight(FeatureType featureType, FeatureWeight featureWeight)
1232 {
1233     if (featureType == NoFeature && !request_.featureTypes().isEmpty()) {
1234         resetFeatureWeights();
1235         return;
1236     }
1237 
1238     // Check if the weight changes, as we need to signal it
1239     FeatureWeight originalWeight = static_cast<FeatureWeight>(request_.featureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType)));
1240     if (featureWeight == originalWeight)
1241         return;
1242 
1243     request_.setFeatureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType),
1244                               static_cast<QGeoRouteRequest::FeatureWeight>(featureWeight));
1245     if (complete_ && ((originalWeight == NeutralFeatureWeight) || (featureWeight == NeutralFeatureWeight))) {
1246         // featureTypes should now give a different list, because the original and new weight
1247         // were not same, and other one was neutral weight
1248         emit featureTypesChanged();
1249         emit queryDetailsChanged();
1250     }
1251 }
1252 
1253 /*!
1254     \qmlmethod void QtLocation::RouteQuery::resetFeatureWeights()
1255 
1256     Resets all feature weights to their default state (NeutralFeatureWeight).
1257 
1258     \sa featureTypes, setFeatureWeight, featureWeight
1259 */
resetFeatureWeights()1260 void QDeclarativeGeoRouteQuery::resetFeatureWeights()
1261 {
1262     // reset all feature types.
1263     QList<QGeoRouteRequest::FeatureType> featureTypes = request_.featureTypes();
1264     for (int i = 0; i < featureTypes.count(); ++i) {
1265         request_.setFeatureWeight(featureTypes.at(i), QGeoRouteRequest::NeutralFeatureWeight);
1266     }
1267     if (complete_) {
1268         emit featureTypesChanged();
1269         emit queryDetailsChanged();
1270     }
1271 }
1272 
1273 /*!
1274     \qmlmethod FeatureWeight QtLocation::RouteQuery::featureWeight(FeatureType featureType)
1275 
1276     Gets the weight for the \a featureType.
1277 
1278     \sa featureTypes, setFeatureWeight, resetFeatureWeights
1279 */
1280 
featureWeight(FeatureType featureType)1281 int QDeclarativeGeoRouteQuery::featureWeight(FeatureType featureType)
1282 {
1283     return request_.featureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType));
1284 }
1285 
1286 /*!
1287     \internal
1288 */
setTravelModes(QDeclarativeGeoRouteQuery::TravelModes travelModes)1289 void QDeclarativeGeoRouteQuery::setTravelModes(QDeclarativeGeoRouteQuery::TravelModes travelModes)
1290 {
1291     QGeoRouteRequest::TravelModes reqTravelModes;
1292 
1293     if (travelModes & QDeclarativeGeoRouteQuery::CarTravel)
1294         reqTravelModes |= QGeoRouteRequest::CarTravel;
1295     if (travelModes & QDeclarativeGeoRouteQuery::PedestrianTravel)
1296         reqTravelModes |= QGeoRouteRequest::PedestrianTravel;
1297     if (travelModes & QDeclarativeGeoRouteQuery::BicycleTravel)
1298         reqTravelModes |= QGeoRouteRequest::BicycleTravel;
1299     if (travelModes & QDeclarativeGeoRouteQuery::PublicTransitTravel)
1300         reqTravelModes |= QGeoRouteRequest::PublicTransitTravel;
1301     if (travelModes & QDeclarativeGeoRouteQuery::TruckTravel)
1302         reqTravelModes |= QGeoRouteRequest::TruckTravel;
1303 
1304     if (reqTravelModes == request_.travelModes())
1305         return;
1306 
1307     request_.setTravelModes(reqTravelModes);
1308 
1309     if (complete_) {
1310         emit travelModesChanged();
1311         emit queryDetailsChanged();
1312     }
1313 }
1314 
1315 
1316 /*!
1317     \qmlproperty enumeration RouteQuery::segmentDetail
1318 
1319     The level of detail which will be used in the representation of routing segments.
1320 
1321     \value RouteQuery.NoSegmentData
1322     No segment data should be included with the route
1323 
1324     \value RouteQuery.BasicSegmentData
1325     Basic segment data will be included with the route
1326 
1327     The default value is \c {RouteQuery.BasicSegmentData}.
1328 */
1329 
setSegmentDetail(SegmentDetail segmentDetail)1330 void QDeclarativeGeoRouteQuery::setSegmentDetail(SegmentDetail segmentDetail)
1331 {
1332     if (static_cast<QGeoRouteRequest::SegmentDetail>(segmentDetail) == request_.segmentDetail())
1333         return;
1334     request_.setSegmentDetail(static_cast<QGeoRouteRequest::SegmentDetail>(segmentDetail));
1335     if (complete_) {
1336         emit segmentDetailChanged();
1337         emit queryDetailsChanged();
1338     }
1339 }
1340 
segmentDetail() const1341 QDeclarativeGeoRouteQuery::SegmentDetail QDeclarativeGeoRouteQuery::segmentDetail() const
1342 {
1343     return static_cast<QDeclarativeGeoRouteQuery::SegmentDetail>(request_.segmentDetail());
1344 }
1345 
1346 /*!
1347     \qmlproperty enumeration RouteQuery::maneuverDetail
1348 
1349     The level of detail which will be used in the representation of routing maneuvers.
1350 
1351     \value RouteQuery.NoManeuvers
1352     No maneuvers should be included with the route
1353 
1354     \value RouteQuery.BasicManeuvers
1355     Basic maneuvers will be included with the route
1356 
1357     The default value is \c {RouteQuery.BasicManeuvers}.
1358 */
1359 
setManeuverDetail(ManeuverDetail maneuverDetail)1360 void QDeclarativeGeoRouteQuery::setManeuverDetail(ManeuverDetail maneuverDetail)
1361 {
1362     if (static_cast<QGeoRouteRequest::ManeuverDetail>(maneuverDetail) == request_.maneuverDetail())
1363         return;
1364     request_.setManeuverDetail(static_cast<QGeoRouteRequest::ManeuverDetail>(maneuverDetail));
1365     if (complete_) {
1366         emit maneuverDetailChanged();
1367         emit queryDetailsChanged();
1368     }
1369 }
1370 
maneuverDetail() const1371 QDeclarativeGeoRouteQuery::ManeuverDetail QDeclarativeGeoRouteQuery::maneuverDetail() const
1372 {
1373     return static_cast<QDeclarativeGeoRouteQuery::ManeuverDetail>(request_.maneuverDetail());
1374 }
1375 
1376 /*!
1377     \qmlproperty enumeration RouteQuery::travelModes
1378 
1379     The travel modes which should be considered during the planning of the route.
1380     Values can be combined with OR ('|') -operator.
1381 
1382     \value RouteQuery.CarTravel
1383     The route will be optimized for someone who is driving a car
1384 
1385     \value RouteQuery.PedestrianTravel
1386     The route will be optimized for someone who is walking
1387 
1388     \value RouteQuery.BicycleTravel
1389     The route will be optimized for someone who is riding a bicycle
1390 
1391     \value RouteQuery.PublicTransit
1392     Travel The route will be optimized for someone who is making use of public transit
1393 
1394     \value RouteQuery.TruckTravel
1395     The route will be optimized for someone who is driving a truck
1396 
1397     The default value is \c {RouteQuery.CarTravel}.
1398 */
1399 
travelModes() const1400 QDeclarativeGeoRouteQuery::TravelModes QDeclarativeGeoRouteQuery::travelModes() const
1401 {
1402     QGeoRouteRequest::TravelModes reqTravelModes = request_.travelModes();
1403     QDeclarativeGeoRouteQuery::TravelModes travelModes;
1404 
1405     if (reqTravelModes & QGeoRouteRequest::CarTravel)
1406         travelModes |= QDeclarativeGeoRouteQuery::CarTravel;
1407     if (reqTravelModes & QGeoRouteRequest::PedestrianTravel)
1408         travelModes |= QDeclarativeGeoRouteQuery::PedestrianTravel;
1409     if (reqTravelModes & QGeoRouteRequest::BicycleTravel)
1410         travelModes |= QDeclarativeGeoRouteQuery::BicycleTravel;
1411     if (reqTravelModes & QGeoRouteRequest::PublicTransitTravel)
1412         travelModes |= QDeclarativeGeoRouteQuery::PublicTransitTravel;
1413     if (reqTravelModes & QGeoRouteRequest::TruckTravel)
1414         travelModes |= QDeclarativeGeoRouteQuery::TruckTravel;
1415 
1416     return travelModes;
1417 }
1418 
1419 /*!
1420     \qmlproperty enumeration RouteQuery::routeOptimizations
1421 
1422     The route optimizations which should be considered during the planning of the route.
1423     Values can be combined with OR ('|') -operator.
1424 
1425 
1426     \value RouteQuery.ShortestRoute
1427     Minimize the length of the journey
1428 
1429     \value RouteQuery.FastestRoute
1430     Minimize the traveling time for the journey
1431 
1432     \value RouteQuery.MostEconomicRoute
1433     Minimize the cost of the journey
1434 
1435     \value RouteQuery.MostScenicRoute
1436     Maximize the scenic potential of the journey
1437 
1438     The default value is \c {RouteQuery.FastestRoute}.
1439 */
1440 
routeOptimizations() const1441 QDeclarativeGeoRouteQuery::RouteOptimizations QDeclarativeGeoRouteQuery::routeOptimizations() const
1442 {
1443     QGeoRouteRequest::RouteOptimizations reqOptimizations = request_.routeOptimization();
1444     QDeclarativeGeoRouteQuery::RouteOptimizations optimization;
1445 
1446     if (reqOptimizations & QGeoRouteRequest::ShortestRoute)
1447         optimization |= QDeclarativeGeoRouteQuery::ShortestRoute;
1448     if (reqOptimizations & QGeoRouteRequest::FastestRoute)
1449         optimization |= QDeclarativeGeoRouteQuery::FastestRoute;
1450     if (reqOptimizations & QGeoRouteRequest::MostEconomicRoute)
1451         optimization |= QDeclarativeGeoRouteQuery::MostEconomicRoute;
1452     if (reqOptimizations & QGeoRouteRequest::MostScenicRoute)
1453         optimization |= QDeclarativeGeoRouteQuery::MostScenicRoute;
1454 
1455     return optimization;
1456 }
1457 
1458 /*!
1459     \qmlproperty date RouteQuery::departureTime
1460 
1461     The departure time to be used when querying for the route.
1462     The default value is an invalid date, meaning no departure time will be used in the query.
1463 
1464     \since 5.13
1465 */
setDepartureTime(const QDateTime & departureTime)1466 void QDeclarativeGeoRouteQuery::setDepartureTime(const QDateTime &departureTime)
1467 {
1468     if (departureTime == request_.departureTime())
1469         return;
1470 
1471     request_.setDepartureTime(departureTime);
1472     if (complete_) {
1473         emit departureTimeChanged();
1474         emit queryDetailsChanged();
1475     }
1476 }
1477 
departureTime() const1478 QDateTime QDeclarativeGeoRouteQuery::departureTime() const
1479 {
1480     return request_.departureTime();
1481 }
1482 
setRouteOptimizations(QDeclarativeGeoRouteQuery::RouteOptimizations optimization)1483 void QDeclarativeGeoRouteQuery::setRouteOptimizations(QDeclarativeGeoRouteQuery::RouteOptimizations optimization)
1484 {
1485     QGeoRouteRequest::RouteOptimizations reqOptimizations;
1486 
1487     if (optimization & QDeclarativeGeoRouteQuery::ShortestRoute)
1488         reqOptimizations |= QGeoRouteRequest::ShortestRoute;
1489     if (optimization & QDeclarativeGeoRouteQuery::FastestRoute)
1490         reqOptimizations |= QGeoRouteRequest::FastestRoute;
1491     if (optimization & QDeclarativeGeoRouteQuery::MostEconomicRoute)
1492         reqOptimizations |= QGeoRouteRequest::MostEconomicRoute;
1493     if (optimization & QDeclarativeGeoRouteQuery::MostScenicRoute)
1494         reqOptimizations |= QGeoRouteRequest::MostScenicRoute;
1495 
1496     if (reqOptimizations == request_.routeOptimization())
1497         return;
1498 
1499     request_.setRouteOptimization(reqOptimizations);
1500 
1501     if (complete_) {
1502         emit routeOptimizationsChanged();
1503         emit queryDetailsChanged();
1504     }
1505 }
1506 
1507 /*!
1508     \internal
1509 */
routeRequest()1510 QGeoRouteRequest QDeclarativeGeoRouteQuery::routeRequest()
1511 {
1512     if (m_extraParametersChanged) {
1513         m_extraParametersChanged = false;
1514         // Update extra params into request
1515         const QList<QDeclarativeGeoMapParameter *> params = quickChildren<QDeclarativeGeoMapParameter>();
1516         QVariantMap extraParameters;
1517         for (const QDeclarativeGeoMapParameter *p: params)
1518             extraParameters[p->type()] = p->toVariantMap();
1519         request_.setExtraParameters(extraParameters);
1520     }
1521     if (m_waypointsChanged) {
1522         m_waypointsChanged = false;
1523         // Update waypoints and metadata into request
1524         request_.setWaypoints(waypointCoordinates(m_waypoints));
1525         request_.setWaypointsMetadata(waypointMetadata(m_waypoints));
1526     }
1527     return request_;
1528 }
1529 
1530 
1531 /*!
1532     \qmlproperty VariantMap RouteQuery::extraParameters
1533     \readonly
1534 
1535     The route query extra parameters. This property is read only. If the query is
1536     defined by the user, these can be set by using MapParameters.
1537     If the route query comes from the engine via signals, the query is intended to be read-only.
1538 
1539     \since 5.11
1540 */
extraParameters()1541 QVariantMap QDeclarativeGeoRouteQuery::extraParameters()
1542 {
1543     return routeRequest().extraParameters();
1544 }
1545 
excludedAreaCoordinateChanged()1546 void QDeclarativeGeoRouteQuery::excludedAreaCoordinateChanged()
1547 {
1548     if (!m_excludedAreaCoordinateChanged) {
1549         m_excludedAreaCoordinateChanged = true;
1550         QMetaObject::invokeMethod(this, "doCoordinateChanged", Qt::QueuedConnection);
1551     }
1552 }
1553 
extraParameterChanged()1554 void QDeclarativeGeoRouteQuery::extraParameterChanged()
1555 {
1556     m_extraParametersChanged = true;
1557     if (complete_) {
1558         emit extraParametersChanged();
1559         emit queryDetailsChanged();
1560     }
1561 }
1562 
waypointChanged()1563 void QDeclarativeGeoRouteQuery::waypointChanged()
1564 {
1565     m_waypointsChanged = true;
1566     if (complete_) {
1567         emit waypointsChanged();
1568         emit queryDetailsChanged();
1569     }
1570 }
1571 
append(QQmlListProperty<QObject> * p,QObject * v)1572 void QDeclarativeGeoRouteQuery::append(QQmlListProperty<QObject> *p, QObject *v)
1573 {
1574     QDeclarativeGeoRouteQuery *query = static_cast<QDeclarativeGeoRouteQuery*>(p->object);
1575     query->m_children.append(v);
1576 
1577     QDeclarativeGeoMapParameter *param = qobject_cast<QDeclarativeGeoMapParameter *>(v);
1578     if (param) {
1579         query->m_extraParametersChanged = true;
1580         query->connect(param, &QGeoMapParameter::propertyUpdated,
1581                        query, &QDeclarativeGeoRouteQuery::extraParameterChanged);
1582         if (query->complete_) {
1583             emit query->extraParametersChanged();
1584             emit query->queryDetailsChanged();
1585         }
1586     }
1587 }
1588 
count(QQmlListProperty<QObject> * p)1589 int QDeclarativeGeoRouteQuery::count(QQmlListProperty<QObject> *p)
1590 {
1591     return static_cast<QDeclarativeGeoRouteQuery*>(p->object)->m_children.count();
1592 }
1593 
at(QQmlListProperty<QObject> * p,int idx)1594 QObject *QDeclarativeGeoRouteQuery::at(QQmlListProperty<QObject> *p, int idx)
1595 {
1596     return static_cast<QDeclarativeGeoRouteQuery*>(p->object)->m_children.at(idx);
1597 }
1598 
clear(QQmlListProperty<QObject> * p)1599 void QDeclarativeGeoRouteQuery::clear(QQmlListProperty<QObject> *p)
1600 {
1601     QDeclarativeGeoRouteQuery *query = static_cast<QDeclarativeGeoRouteQuery*>(p->object);
1602     for (auto kid : qAsConst(query->m_children)) {
1603         auto val = qobject_cast<QDeclarativeGeoMapParameter *>(kid);
1604         if (val) {
1605             val->disconnect(val, nullptr, query, nullptr);
1606             query->m_extraParametersChanged = true;
1607         }
1608     }
1609     query->m_children.clear();
1610     if (query->m_extraParametersChanged && query->complete_) {
1611         emit query->extraParametersChanged();
1612         emit query->queryDetailsChanged();
1613     }
1614 }
1615 
declarativeChildren()1616 QQmlListProperty<QObject> QDeclarativeGeoRouteQuery::declarativeChildren()
1617 {
1618     return QQmlListProperty<QObject>(this, nullptr,
1619                                            &QDeclarativeGeoRouteQuery::append,
1620                                            &QDeclarativeGeoRouteQuery::count,
1621                                            &QDeclarativeGeoRouteQuery::at,
1622                                            &QDeclarativeGeoRouteQuery::clear);
1623 }
1624 
doCoordinateChanged()1625 void QDeclarativeGeoRouteQuery::doCoordinateChanged()
1626 {
1627     m_excludedAreaCoordinateChanged = false;
1628     if (complete_)
1629         emit queryDetailsChanged();
1630 }
1631 
1632 /*!
1633     \qmltype Waypoint
1634     \instantiates QDeclarativeGeoWaypoint
1635     \inqmlmodule QtLocation
1636     \ingroup qml-QtLocation5-routing
1637     \since QtLocation 5.11
1638 
1639     \brief The Waypoint type provides a mean to specify a waypoint in a \l RouteQuery
1640     in a more detailed way than by using a simple \l coordinate.
1641 
1642     A Waypoint is a type that allows to specify properties of a waypoint in a \l RouteQuery,
1643     such as the waypoint coordinate, or the angle of approach to the waypoint.
1644 
1645     Additional information that are backend-specific can be specified by nesting \l MapParameter
1646     elements.
1647 
1648     Changing properties of the waypoint or of its nested MapParameteters will cause the containing
1649     \l RouteQuery to emit the queryDetailsChanged signal.
1650 
1651     \section2 Example Usage
1652 
1653     \code
1654     Plugin {
1655         id: aPlugin
1656         name: "osm"
1657     }
1658 
1659     Waypoint {
1660         id: waypointStart
1661         coordinate: ...
1662         bearing: ...
1663     }
1664     Waypoint {
1665         id: waypointFinish
1666         coordinate: ...
1667         bearing: ...
1668     }
1669 
1670     RouteQuery {
1671         id: aQuery
1672         Component.onCompleted: {
1673             travelModes = RouteQuery.CarTravel
1674             addWaypoint(waypointStart)
1675             var aWaypoint = Qt.createQmlObject ('import QtLocation 5.11; Waypoint { ... }', ...)
1676             addWaypoint(aWaypoint)
1677             addWaypoint(waypointFinish)
1678         }
1679     }
1680 
1681     RouteModel {
1682         id: routeModel
1683         plugin: aPlugin
1684         query: aQuery
1685         autoUpdate: true
1686     }
1687     \endcode
1688 
1689     \sa RouteQuery
1690 */
1691 
1692 
1693 /*
1694  *
1695     At the time of adding this class (2017.11), 3 routing services are natively supported in Qt: Esri, Here and OSRM.
1696     Waypoint documentation for each of these:
1697     Esri: http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#//02r300000036000000 ,  called "stop"
1698     HERE: https://developer.here.com/documentation/routing/topics/resource-param-type-waypoint.html
1699     OSRM: https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md , under Request Options
1700  *
1701  */
1702 
1703 
convertWaypointToCoordinate(const QDeclarativeGeoWaypoint * value)1704 static QGeoCoordinate convertWaypointToCoordinate(const QDeclarativeGeoWaypoint *value)
1705 {
1706     return value->coordinate();
1707 }
1708 
1709 struct WaypointVariantConversions
1710 {
WaypointVariantConversionsWaypointVariantConversions1711     WaypointVariantConversions()
1712     {
1713         QMetaType::registerConverter<QDeclarativeGeoWaypoint *, QGeoCoordinate>(convertWaypointToCoordinate);
1714     }
1715 };
1716 
Q_GLOBAL_STATIC(WaypointVariantConversions,initWaypointConversions)1717 Q_GLOBAL_STATIC(WaypointVariantConversions, initWaypointConversions)
1718 
1719 
1720 QDeclarativeGeoWaypoint::QDeclarativeGeoWaypoint(QObject *parent) : QGeoCoordinateObject(parent)
1721 {
1722     initWaypointConversions();
1723     connect(this, &QGeoCoordinateObject::coordinateChanged,
1724             this, &QDeclarativeGeoWaypoint::waypointDetailsChanged);
1725 }
1726 
~QDeclarativeGeoWaypoint()1727 QDeclarativeGeoWaypoint::~QDeclarativeGeoWaypoint()
1728 {
1729 
1730 }
1731 
operator ==(const QDeclarativeGeoWaypoint & other) const1732 bool QDeclarativeGeoWaypoint::operator==(const QDeclarativeGeoWaypoint &other) const
1733 {
1734     const QList<QDeclarativeGeoMapParameter *> params = quickChildren<QDeclarativeGeoMapParameter>();
1735     const QList<QDeclarativeGeoMapParameter *> otherParams = other.quickChildren<QDeclarativeGeoMapParameter>();
1736 
1737     return coordinate() == other.coordinate() &&
1738            compareFloats(m_bearing, other.bearing()) &&
1739            compareParameterList(params, otherParams);
1740 }
1741 
1742 /*!
1743     \qmlproperty coordinate Waypoint::coordinate
1744 
1745     The waypoint's coordinate. The default value is undefined.
1746 */
1747 
1748 
1749 /*!
1750     \qmlproperty real Waypoint::latitude
1751 
1752     The latitude of the waypoint's coordinate. The default value is NaN.
1753     Changing this property will affect the \l Waypoint::coordinate property as well.
1754 */
latitude() const1755 qreal QDeclarativeGeoWaypoint::latitude() const
1756 {
1757     return m_coordinate.latitude();
1758 }
1759 
setLatitude(qreal latitude)1760 void QDeclarativeGeoWaypoint::setLatitude(qreal latitude)
1761 {
1762     if (compareFloats(latitude, m_coordinate.latitude()))
1763         return;
1764 
1765     m_coordinate.setLatitude(latitude);
1766     if (m_complete) {
1767         emit coordinateChanged();
1768         emit waypointDetailsChanged();
1769     }
1770 }
1771 
1772 /*!
1773     \qmlproperty real Waypoint::longitude
1774 
1775     The longitude of the waypoint's coordinate. The default value is NaN.
1776     Changing this property will affect the \l Waypoint::coordinate property as well.
1777 */
longitude() const1778 qreal QDeclarativeGeoWaypoint::longitude() const
1779 {
1780     return m_coordinate.longitude();
1781 }
1782 
setLongitude(qreal longitude)1783 void QDeclarativeGeoWaypoint::setLongitude(qreal longitude)
1784 {
1785     if (compareFloats(longitude, m_coordinate.longitude()))
1786         return;
1787 
1788     m_coordinate.setLongitude(longitude);
1789     if (m_complete) {
1790         emit coordinateChanged();
1791         emit waypointDetailsChanged();
1792     }
1793 }
1794 
1795 /*!
1796     \qmlproperty real Waypoint::altitude
1797 
1798     The altitude of the waypoint's coordinate. The default value is NaN.
1799     Changing this property will affect the \l Waypoint::coordinate property as well.
1800 */
altitude() const1801 qreal QDeclarativeGeoWaypoint::altitude() const
1802 {
1803     return m_coordinate.altitude();
1804 }
1805 
setAltitude(qreal altitude)1806 void QDeclarativeGeoWaypoint::setAltitude(qreal altitude)
1807 {
1808     if (compareFloats(altitude, m_coordinate.altitude()))
1809         return;
1810 
1811     m_coordinate.setAltitude(altitude);
1812     if (m_complete) {
1813         emit coordinateChanged();
1814         emit waypointDetailsChanged();
1815     }
1816 }
1817 
isValid() const1818 bool QDeclarativeGeoWaypoint::isValid() const
1819 {
1820     return m_coordinate.isValid();
1821 }
1822 
1823 /*!
1824     \qmlproperty real Waypoint::bearing
1825 
1826     The bearing specifying the angle of approach of the waypoint, that is the bearing with which the waypoint is to be approached.
1827     This information may be used by the provider to filter the road segment the waypoint will be placed on, and,
1828     depending on the provider and the \l {QGeoRouteRequest::TravelMode} {travel mode} used, to restrict the maneuvers
1829     allowed at the waypoint, potentially making the provider calculating and returning a different route.
1830 
1831     If set to NaN, this value will not be considered.
1832 
1833     The default value is NaN.
1834 */
bearing() const1835 qreal QDeclarativeGeoWaypoint::bearing() const
1836 {
1837     return m_bearing;
1838 }
1839 
setBearing(qreal bearing)1840 void QDeclarativeGeoWaypoint::setBearing(qreal bearing)
1841 {
1842     if (compareFloats(bearing, m_bearing))
1843         return;
1844 
1845     m_bearing = bearing;
1846 
1847     // Bearing is actually packed into QGeoRouteRequest::waypointMetadata() together with the extra parameters
1848     m_metadataChanged = true;
1849     if (m_complete) {
1850         emit bearingChanged();
1851         emit waypointDetailsChanged();
1852     }
1853 }
1854 
1855 /*!
1856     \qmlproperty VariantMap Waypoint::metadata
1857     \readonly
1858 
1859     The waypoint metadata. This property is read only. If the waypoint is
1860     defined by the user, these can be set by using MapParameters.
1861     If the waypoint comes from the engine via signals, or as part of a read-only route query,
1862     the waypoint is intended to be read-only.
1863 */
metadata()1864 QVariantMap QDeclarativeGeoWaypoint::metadata()
1865 {
1866     if (m_metadataChanged) {
1867         m_metadataChanged = false;
1868         m_metadata.clear();
1869         // Update metadata
1870         const QList<QDeclarativeGeoMapParameter *> params = quickChildren<QDeclarativeGeoMapParameter>();
1871         QVariantMap extraParameters;
1872         for (const QDeclarativeGeoMapParameter *p: params)
1873             extraParameters[p->type()] = p->toVariantMap();
1874         m_metadata[QStringLiteral("extra")] = extraParameters;
1875         m_metadata[QStringLiteral("bearing")] = m_bearing;
1876     }
1877     return m_metadata;
1878 }
1879 
1880 // Used only by QDeclarativeGeoRouteRequest
setMetadata(const QVariantMap & meta)1881 void QDeclarativeGeoWaypoint::setMetadata(const QVariantMap &meta)
1882 {
1883     m_metadata = meta;
1884     if (m_metadata.contains(QStringLiteral("bearing")) && m_metadata.value(QStringLiteral("bearing")).canConvert<double>())
1885         m_bearing = m_metadata.value(QStringLiteral("bearing")).toDouble();
1886     m_metadataChanged = false;
1887 }
1888 
extraParameterChanged()1889 void QDeclarativeGeoWaypoint::extraParameterChanged()
1890 {
1891     m_metadataChanged = true;
1892     if (m_complete) {
1893         emit extraParametersChanged();
1894         emit waypointDetailsChanged();
1895     }
1896 }
1897 
append(QQmlListProperty<QObject> * p,QObject * v)1898 void QDeclarativeGeoWaypoint::append(QQmlListProperty<QObject> *p, QObject *v)
1899 {
1900     QDeclarativeGeoWaypoint *waypoint = static_cast<QDeclarativeGeoWaypoint*>(p->object);
1901     waypoint->m_children.append(v);
1902 
1903     QDeclarativeGeoMapParameter *param = qobject_cast<QDeclarativeGeoMapParameter *>(v);
1904     if (param) {
1905         waypoint->connect(param, &QGeoMapParameter::propertyUpdated,
1906                        waypoint, &QDeclarativeGeoWaypoint::extraParameterChanged);
1907         waypoint->extraParameterChanged();
1908     }
1909 }
1910 
count(QQmlListProperty<QObject> * p)1911 int QDeclarativeGeoWaypoint::count(QQmlListProperty<QObject> *p)
1912 {
1913     return static_cast<QDeclarativeGeoWaypoint*>(p->object)->m_children.count();
1914 }
1915 
at(QQmlListProperty<QObject> * p,int idx)1916 QObject *QDeclarativeGeoWaypoint::at(QQmlListProperty<QObject> *p, int idx)
1917 {
1918     return static_cast<QDeclarativeGeoWaypoint*>(p->object)->m_children.at(idx);
1919 }
1920 
clear(QQmlListProperty<QObject> * p)1921 void QDeclarativeGeoWaypoint::clear(QQmlListProperty<QObject> *p)
1922 {
1923     QDeclarativeGeoWaypoint *waypoint = static_cast<QDeclarativeGeoWaypoint*>(p->object);
1924     for (auto kid : qAsConst(waypoint->m_children)) {
1925         auto val = qobject_cast<QDeclarativeGeoMapParameter *>(kid);
1926         if (val) {
1927             val->disconnect(waypoint);
1928             waypoint->m_metadataChanged = true;
1929         }
1930     }
1931     waypoint->m_children.clear();
1932     if (waypoint->m_metadataChanged && waypoint->m_complete) {
1933         emit waypoint->extraParametersChanged();
1934         emit waypoint->waypointDetailsChanged();
1935     }
1936 }
1937 
declarativeChildren()1938 QQmlListProperty<QObject> QDeclarativeGeoWaypoint::declarativeChildren()
1939 {
1940     return QQmlListProperty<QObject>(this, nullptr,
1941                                      &QDeclarativeGeoWaypoint::append,
1942                                      &QDeclarativeGeoWaypoint::count,
1943                                      &QDeclarativeGeoWaypoint::at,
1944                                      &QDeclarativeGeoWaypoint::clear);
1945 }
1946 
1947 QT_END_NAMESPACE
1948