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 "qdeclarativegeoroute_p.h"
38#include "locationvaluetypehelper_p.h"
39#include <QtLocation/private/qgeomap_p.h>
40#include <QtLocation/private/qgeoroute_p.h>
41#include <QtLocation/private/qdeclarativegeoroutemodel_p.h>
42
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 <QtPositioning/QGeoRectangle>
49
50QT_BEGIN_NAMESPACE
51
52/*!
53 \qmltype Route
54 \instantiates QDeclarativeGeoRoute
55 \inqmlmodule QtLocation
56 \ingroup qml-QtLocation5-routing
57 \since QtLocation 5.5
58
59 \brief The Route type represents one geographical route.
60
61 A Route type contains high level information about a route, such
62 as the length the route, the estimated travel time for the route,
63 and enough information to render a basic image of the route on a map.
64
65 The QGeoRoute object also contains a list of \l RouteSegment objects which
66 describe subsections of the route in greater detail.
67
68 The primary means of acquiring Route objects is \l RouteModel.
69
70 \section1 Example
71
72 This example shows how to display a route's maneuvers in a ListView:
73
74 \snippet declarative/routing.qml QtQuick import
75 \snippet declarative/maps.qml QtLocation import
76 \codeline
77 \snippet declarative/routing.qml Route Maneuver List1
78 \snippet declarative/routing.qml Route Maneuver List2
79 \snippet declarative/routing.qml Route Maneuver List3
80
81*/
82
83QDeclarativeGeoRoute::QDeclarativeGeoRoute(QObject *parent)
84 : QObject(parent)
85{
86}
87
88QDeclarativeGeoRoute::QDeclarativeGeoRoute(const QGeoRoute &route, QObject *parent)
89 : QObject(parent), route_(route)
90{
91}
92
93QDeclarativeGeoRoute::~QDeclarativeGeoRoute() {}
94
95void QDeclarativeGeoRoute::initSegments(unsigned int lastIndex) // -1 turns it into unsigned int max
96{
97 if (!segmentsDirty_)
98 return;
99
100 const bool isLeg = qobject_cast<QDeclarativeGeoRoute *>(object: parent());
101 QGeoRouteSegment segment = route_.firstRouteSegment();
102 unsigned int idx = 0;
103 unsigned int initialListSize = static_cast<unsigned int>(segments_.size());
104 while (segment.isValid()) {
105 if (idx >= initialListSize) {
106 QDeclarativeGeoRouteSegment *routeSegment = new QDeclarativeGeoRouteSegment(segment, this);
107 QQmlEngine::setContextForObject(routeSegment, QQmlEngine::contextForObject(this));
108 segments_.append(t: routeSegment);
109 }
110 if (isLeg && segment.isLegLastSegment()) {
111 segmentsDirty_ = false;
112 return;
113 }
114 ++idx;
115 segment = segment.nextRouteSegment();
116 if (idx > lastIndex && segment.isValid()) // Do not clean segmentsDirty_ if there are still segments to initialize
117 return;
118 }
119 segmentsDirty_ = false;
120}
121
122/*!
123 \internal
124*/
125QList<QGeoCoordinate> QDeclarativeGeoRoute::routePath()
126{
127 return route_.path();
128}
129
130/*!
131 \qmlproperty georectangle QtLocation::Route::bounds
132
133 Read-only property which holds a bounding box which encompasses the entire route.
134
135*/
136
137QGeoRectangle QDeclarativeGeoRoute::bounds() const
138{
139 return route_.bounds();
140}
141
142/*!
143 \qmlproperty int QtLocation::Route::travelTime
144
145 Read-only property which holds the estimated amount of time it will take to
146 traverse this route, in seconds.
147
148*/
149
150int QDeclarativeGeoRoute::travelTime() const
151{
152 return route_.travelTime();
153}
154
155/*!
156 \qmlproperty real QtLocation::Route::distance
157
158 Read-only property which holds distance covered by this route, in meters.
159*/
160
161qreal QDeclarativeGeoRoute::distance() const
162{
163 return route_.distance();
164}
165
166/*!
167 \qmlproperty list<coordinate> QtLocation::Route::path
168
169 Read-only property which holds the geographical coordinates of this route.
170 Coordinates are listed in the order in which they would be traversed by someone
171 traveling along this segment of the route.
172
173 To access individual segments you can use standard list accessors: 'path.length'
174 indicates the number of objects and 'path[index starting from zero]' gives
175 the actual object.
176
177 \sa QtPositioning::coordinate
178*/
179
180QJSValue QDeclarativeGeoRoute::path() const
181{
182 QQmlContext *context = QQmlEngine::contextForObject(parent());
183 QQmlEngine *engine = context->engine();
184 QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(e: engine);
185
186 QV4::Scope scope(v4);
187 QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(count: route_.path().length()));
188 for (int i = 0; i < route_.path().length(); ++i) {
189 const QGeoCoordinate &c = route_.path().at(i);
190
191 QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(value: c)));
192 pathArray->put(idx: i, v: cv);
193 }
194
195 return QJSValue(v4, pathArray.asReturnedValue());
196}
197
198void QDeclarativeGeoRoute::setPath(const QJSValue &value)
199{
200 if (!value.isArray())
201 return;
202
203 QList<QGeoCoordinate> pathList;
204 quint32 length = value.property(QStringLiteral("length")).toUInt();
205 for (quint32 i = 0; i < length; ++i) {
206 bool ok;
207 QGeoCoordinate c = parseCoordinate(value: value.property(arrayIndex: i), ok: &ok);
208
209 if (!ok || !c.isValid()) {
210 qmlWarning(me: this) << "Unsupported path type";
211 return;
212 }
213
214 pathList.append(t: c);
215 }
216
217 if (route_.path() == pathList)
218 return;
219
220 route_.setPath(pathList);
221
222 emit pathChanged();
223}
224
225/*!
226 \qmlproperty list<RouteSegment> QtLocation::Route::segments
227
228 Read-only property which holds the list of \l RouteSegment objects of this route.
229
230 To access individual segments you can use standard list accessors: 'segments.length'
231 indicates the number of objects and 'segments[index starting from zero]' gives
232 the actual objects.
233
234 \sa RouteSegment
235*/
236
237QQmlListProperty<QDeclarativeGeoRouteSegment> QDeclarativeGeoRoute::segments()
238{
239 return QQmlListProperty<QDeclarativeGeoRouteSegment>(this, 0, segments_append, segments_count,
240 segments_at, segments_clear);
241}
242
243/*!
244 \internal
245*/
246void QDeclarativeGeoRoute::segments_append(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop,
247 QDeclarativeGeoRouteSegment *segment)
248{
249 QDeclarativeGeoRoute *declRoute = static_cast<QDeclarativeGeoRoute *>(prop->object);
250 declRoute->initSegments();
251 declRoute->appendSegment(segment);
252}
253
254/*!
255 \internal
256*/
257int QDeclarativeGeoRoute::segments_count(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop)
258{
259 QDeclarativeGeoRoute *declRoute = static_cast<QDeclarativeGeoRoute *>(prop->object);
260 return declRoute->segmentsCount();
261}
262
263/*!
264 \internal
265*/
266QDeclarativeGeoRouteSegment *QDeclarativeGeoRoute::segments_at(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, int index)
267{
268 QDeclarativeGeoRoute *declRoute = static_cast<QDeclarativeGeoRoute *>(prop->object);
269 declRoute->initSegments(lastIndex: index); // init only what's needed.
270 return declRoute->segments_.at(i: index);
271}
272
273/*!
274 \internal
275*/
276void QDeclarativeGeoRoute::segments_clear(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop)
277{
278 static_cast<QDeclarativeGeoRoute *>(prop->object)->clearSegments();
279}
280
281/*!
282 \internal
283*/
284void QDeclarativeGeoRoute::appendSegment(QDeclarativeGeoRouteSegment *segment)
285{
286 segments_.append(t: segment);
287}
288
289/*!
290 \internal
291*/
292void QDeclarativeGeoRoute::clearSegments()
293{
294 segments_.clear();
295}
296
297/*!
298 \qmlmethod int QtLocation::Route::segmentsCount()
299
300 Returns the number of segments in the route
301
302 \sa RouteSegment
303
304 \since 5.11
305*/
306
307int QDeclarativeGeoRoute::segmentsCount() const
308{
309 return qMax(a: route_.d_ptr->segmentsCount(), b: segments_.count());
310}
311
312const QGeoRoute &QDeclarativeGeoRoute::route() const
313{
314 return route_;
315}
316
317/*!
318 \qmlproperty RouteQuery QtLocation::Route::routeQuery
319
320 Returns the route query associated with this route.
321
322 \since 5.11
323*/
324QDeclarativeGeoRouteQuery *QDeclarativeGeoRoute::routeQuery()
325{
326 if (!routeQuery_)
327 routeQuery_ = new QDeclarativeGeoRouteQuery(route_.request(), this);
328 return routeQuery_;
329}
330
331/*!
332 \qmlproperty list<Route> QtLocation::Route::legs
333
334 Returns the route legs associated with this route.
335 Route legs are the sub-routes between each two adjacent waypoints.
336 The result may be empty, if this level of detail is not supported by the
337 backend.
338
339 \since QtLocation 5.12
340*/
341QList<QObject *> QDeclarativeGeoRoute::legs()
342{
343 // route_.routeLegs() is expected not to change.
344 // The following if condition is expected to be run only once.
345 if (route_.routeLegs().size() != legs_.size()) {
346 legs_.clear();
347 QList<QGeoRouteLeg> rlegs = route_.routeLegs();
348 for (const QGeoRouteLeg &r: rlegs) {
349 QDeclarativeGeoRouteLeg *dr = new QDeclarativeGeoRouteLeg(r, this);
350 legs_.append(t: dr);
351 }
352 }
353 return legs_;
354}
355
356/*!
357 \qmlproperty Object Route::extendedAttributes
358
359 This property holds the extended attributes of the route and is a map.
360 These attributes are plugin specific, and can be empty.
361
362 Consult the \l {Qt Location#Plugin References and Parameters}{plugin documentation}
363 for what attributes are supported and how they should be used.
364
365 Note, due to limitations of the QQmlPropertyMap, it is not possible
366 to declaratively specify the attributes in QML, assignment of attributes keys
367 and values can only be accomplished by JavaScript.
368
369 \since QtLocation 5.13
370*/
371QQmlPropertyMap *QDeclarativeGeoRoute::extendedAttributes() const
372{
373 if (!m_extendedAttributes) {
374 QDeclarativeGeoRoute *self = const_cast<QDeclarativeGeoRoute *>(this);
375 self->m_extendedAttributes = new QQmlPropertyMap(self);
376 // Fill it
377 const QVariantMap &xAttrs = route_.extendedAttributes();
378 const QStringList &keys = xAttrs.keys();
379 for (const QString &key: keys)
380 self->m_extendedAttributes->insert(key, value: xAttrs.value(akey: key));
381 }
382 return m_extendedAttributes;
383}
384
385/*!
386 \qmlmethod bool QtLocation::Route::equals(Route other)
387
388 This method performs deep comparison if the present route
389 is identical to the \a other route.
390 Returns \c true if the routes are equal.
391
392 \since 5.12
393*/
394bool QDeclarativeGeoRoute::equals(QDeclarativeGeoRoute *other) const
395{
396 return route_ == other->route_;
397}
398
399/*!
400 \qmltype RouteLeg
401 \instantiates QDeclarativeGeoRouteLeg
402 \inqmlmodule QtLocation
403 \ingroup qml-QtLocation5-routing
404 \since QtLocation 5.12
405
406 \brief The RouteLeg type represents a leg of a Route, that is the portion
407 of a route between one waypoint and the next.
408
409 \note Since RouteLeg is a subclass of Route, QtLocation::Route::legs will
410 return an empty list if accessed on a route leg.
411*/
412
413/*!
414 \qmlproperty int QtLocation::RouteLeg::legIndex
415
416 Read-only property which holds the index of the leg within the containing Route's list of QtLocation::Route::legs .
417*/
418
419/*!
420 \qmlproperty Route QtLocation::RouteLeg::overallRoute
421
422 Read-only property which holds the Route that contains this leg.
423*/
424
425
426QDeclarativeGeoRouteLeg::QDeclarativeGeoRouteLeg(QObject *parent)
427 : QDeclarativeGeoRoute(parent)
428{
429
430}
431
432QDeclarativeGeoRouteLeg::QDeclarativeGeoRouteLeg(const QGeoRouteLeg &routeLeg, QObject *parent)
433 : QDeclarativeGeoRoute(routeLeg, parent), m_routeLeg(routeLeg)
434{
435
436}
437
438QDeclarativeGeoRouteLeg::~QDeclarativeGeoRouteLeg()
439{
440
441}
442
443int QDeclarativeGeoRouteLeg::legIndex() const
444{
445 return m_routeLeg.legIndex();
446}
447
448QObject *QDeclarativeGeoRouteLeg::overallRoute() const
449{
450 QDeclarativeGeoRoute *containingRoute = qobject_cast<QDeclarativeGeoRoute *>(object: parent());
451 if (Q_UNLIKELY(!containingRoute))
452 return new QDeclarativeGeoRoute(m_routeLeg.overallRoute(), parent());
453 return containingRoute;
454}
455
456QT_END_NAMESPACE
457

source code of qtlocation/src/location/declarativemaps/qdeclarativegeoroute.cpp