| /**************************************************************************** |
| ** |
| ** Copyright (C) 2015 The Qt Company Ltd. |
| ** Contact: http://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtLocation module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL3$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see http://www.qt.io/terms-conditions. For further |
| ** information use the contact form at http://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or later as published by the Free |
| ** Software Foundation and appearing in the file LICENSE.GPL included in |
| ** the packaging of this file. Please review the following information to |
| ** ensure the GNU General Public License version 2.0 requirements will be |
| ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qdeclarativegeoroute_p.h" |
| #include "locationvaluetypehelper_p.h" |
| #include <QtLocation/private/qgeomap_p.h> |
| #include <QtLocation/private/qgeoroute_p.h> |
| #include <QtLocation/private/qdeclarativegeoroutemodel_p.h> |
| |
| #include <QtQml/QQmlEngine> |
| #include <QtQml/qqmlinfo.h> |
| #include <QtQml/private/qqmlengine_p.h> |
| #include <QtQml/private/qv4scopedvalue_p.h> |
| #include <QtQml/private/qv4arrayobject_p.h> |
| #include <QtPositioning/QGeoRectangle> |
| |
| QT_BEGIN_NAMESPACE |
| |
| /*! |
| \qmltype Route |
| \instantiates QDeclarativeGeoRoute |
| \inqmlmodule QtLocation |
| \ingroup qml-QtLocation5-routing |
| \since QtLocation 5.5 |
| |
| \brief The Route type represents one geographical route. |
| |
| A Route type contains high level information about a route, such |
| as the length the route, the estimated travel time for the route, |
| and enough information to render a basic image of the route on a map. |
| |
| The QGeoRoute object also contains a list of \l RouteSegment objects which |
| describe subsections of the route in greater detail. |
| |
| The primary means of acquiring Route objects is \l RouteModel. |
| |
| \section1 Example |
| |
| This example shows how to display a route's maneuvers in a ListView: |
| |
| \snippet declarative/routing.qml QtQuick import |
| \snippet declarative/maps.qml QtLocation import |
| \codeline |
| \snippet declarative/routing.qml Route Maneuver List1 |
| \snippet declarative/routing.qml Route Maneuver List2 |
| \snippet declarative/routing.qml Route Maneuver List3 |
| |
| */ |
| |
| QDeclarativeGeoRoute::QDeclarativeGeoRoute(QObject *parent) |
| : QObject(parent) |
| { |
| } |
| |
| QDeclarativeGeoRoute::QDeclarativeGeoRoute(const QGeoRoute &route, QObject *parent) |
| : QObject(parent), route_(route) |
| { |
| } |
| |
| QDeclarativeGeoRoute::~QDeclarativeGeoRoute() {} |
| |
| void QDeclarativeGeoRoute::initSegments(unsigned int lastIndex) // -1 turns it into unsigned int max |
| { |
| if (!segmentsDirty_) |
| return; |
| |
| const bool isLeg = qobject_cast<QDeclarativeGeoRoute *>(parent()); |
| QGeoRouteSegment segment = route_.firstRouteSegment(); |
| unsigned int idx = 0; |
| unsigned int initialListSize = static_cast<unsigned int>(segments_.size()); |
| while (segment.isValid()) { |
| if (idx >= initialListSize) { |
| QDeclarativeGeoRouteSegment *routeSegment = new QDeclarativeGeoRouteSegment(segment, this); |
| QQmlEngine::setContextForObject(routeSegment, QQmlEngine::contextForObject(this)); |
| segments_.append(routeSegment); |
| } |
| if (isLeg && segment.isLegLastSegment()) { |
| segmentsDirty_ = false; |
| return; |
| } |
| ++idx; |
| segment = segment.nextRouteSegment(); |
| if (idx > lastIndex && segment.isValid()) // Do not clean segmentsDirty_ if there are still segments to initialize |
| return; |
| } |
| segmentsDirty_ = false; |
| } |
| |
| /*! |
| \internal |
| */ |
| QList<QGeoCoordinate> QDeclarativeGeoRoute::routePath() |
| { |
| return route_.path(); |
| } |
| |
| /*! |
| \qmlproperty georectangle QtLocation::Route::bounds |
| |
| Read-only property which holds a bounding box which encompasses the entire route. |
| |
| */ |
| |
| QGeoRectangle QDeclarativeGeoRoute::bounds() const |
| { |
| return route_.bounds(); |
| } |
| |
| /*! |
| \qmlproperty int QtLocation::Route::travelTime |
| |
| Read-only property which holds the estimated amount of time it will take to |
| traverse this route, in seconds. |
| |
| */ |
| |
| int QDeclarativeGeoRoute::travelTime() const |
| { |
| return route_.travelTime(); |
| } |
| |
| /*! |
| \qmlproperty real QtLocation::Route::distance |
| |
| Read-only property which holds distance covered by this route, in meters. |
| */ |
| |
| qreal QDeclarativeGeoRoute::distance() const |
| { |
| return route_.distance(); |
| } |
| |
| /*! |
| \qmlproperty list<coordinate> QtLocation::Route::path |
| |
| Read-only property which holds the geographical coordinates of this route. |
| Coordinates are listed in the order in which they would be traversed by someone |
| traveling along this segment of the route. |
| |
| To access individual segments you can use standard list accessors: 'path.length' |
| indicates the number of objects and 'path[index starting from zero]' gives |
| the actual object. |
| |
| \sa QtPositioning::coordinate |
| */ |
| |
| QJSValue QDeclarativeGeoRoute::path() const |
| { |
| QQmlContext *context = QQmlEngine::contextForObject(parent()); |
| QQmlEngine *engine = context->engine(); |
| QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine); |
| |
| QV4::Scope scope(v4); |
| QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(route_.path().length())); |
| for (int i = 0; i < route_.path().length(); ++i) { |
| const QGeoCoordinate &c = route_.path().at(i); |
| |
| QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c))); |
| pathArray->put(i, cv); |
| } |
| |
| return QJSValue(v4, pathArray.asReturnedValue()); |
| } |
| |
| void QDeclarativeGeoRoute::setPath(const QJSValue &value) |
| { |
| if (!value.isArray()) |
| return; |
| |
| QList<QGeoCoordinate> pathList; |
| quint32 length = value.property(QStringLiteral("length")).toUInt(); |
| for (quint32 i = 0; i < length; ++i) { |
| bool ok; |
| QGeoCoordinate c = parseCoordinate(value.property(i), &ok); |
| |
| if (!ok || !c.isValid()) { |
| qmlWarning(this) << "Unsupported path type"; |
| return; |
| } |
| |
| pathList.append(c); |
| } |
| |
| if (route_.path() == pathList) |
| return; |
| |
| route_.setPath(pathList); |
| |
| emit pathChanged(); |
| } |
| |
| /*! |
| \qmlproperty list<RouteSegment> QtLocation::Route::segments |
| |
| Read-only property which holds the list of \l RouteSegment objects of this route. |
| |
| To access individual segments you can use standard list accessors: 'segments.length' |
| indicates the number of objects and 'segments[index starting from zero]' gives |
| the actual objects. |
| |
| \sa RouteSegment |
| */ |
| |
| QQmlListProperty<QDeclarativeGeoRouteSegment> QDeclarativeGeoRoute::segments() |
| { |
| return QQmlListProperty<QDeclarativeGeoRouteSegment>(this, 0, segments_append, segments_count, |
| segments_at, segments_clear); |
| } |
| |
| /*! |
| \internal |
| */ |
| void QDeclarativeGeoRoute::segments_append(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, |
| QDeclarativeGeoRouteSegment *segment) |
| { |
| QDeclarativeGeoRoute *declRoute = static_cast<QDeclarativeGeoRoute *>(prop->object); |
| declRoute->initSegments(); |
| declRoute->appendSegment(segment); |
| } |
| |
| /*! |
| \internal |
| */ |
| int QDeclarativeGeoRoute::segments_count(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop) |
| { |
| QDeclarativeGeoRoute *declRoute = static_cast<QDeclarativeGeoRoute *>(prop->object); |
| return declRoute->segmentsCount(); |
| } |
| |
| /*! |
| \internal |
| */ |
| QDeclarativeGeoRouteSegment *QDeclarativeGeoRoute::segments_at(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, int index) |
| { |
| QDeclarativeGeoRoute *declRoute = static_cast<QDeclarativeGeoRoute *>(prop->object); |
| declRoute->initSegments(index); // init only what's needed. |
| return declRoute->segments_.at(index); |
| } |
| |
| /*! |
| \internal |
| */ |
| void QDeclarativeGeoRoute::segments_clear(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop) |
| { |
| static_cast<QDeclarativeGeoRoute *>(prop->object)->clearSegments(); |
| } |
| |
| /*! |
| \internal |
| */ |
| void QDeclarativeGeoRoute::appendSegment(QDeclarativeGeoRouteSegment *segment) |
| { |
| segments_.append(segment); |
| } |
| |
| /*! |
| \internal |
| */ |
| void QDeclarativeGeoRoute::clearSegments() |
| { |
| segments_.clear(); |
| } |
| |
| /*! |
| \qmlmethod int QtLocation::Route::segmentsCount() |
| |
| Returns the number of segments in the route |
| |
| \sa RouteSegment |
| |
| \since 5.11 |
| */ |
| |
| int QDeclarativeGeoRoute::segmentsCount() const |
| { |
| return qMax(route_.d_ptr->segmentsCount(), segments_.count()); |
| } |
| |
| const QGeoRoute &QDeclarativeGeoRoute::route() const |
| { |
| return route_; |
| } |
| |
| /*! |
| \qmlproperty RouteQuery QtLocation::Route::routeQuery |
| |
| Returns the route query associated with this route. |
| |
| \since 5.11 |
| */ |
| QDeclarativeGeoRouteQuery *QDeclarativeGeoRoute::routeQuery() |
| { |
| if (!routeQuery_) |
| routeQuery_ = new QDeclarativeGeoRouteQuery(route_.request(), this); |
| return routeQuery_; |
| } |
| |
| /*! |
| \qmlproperty list<Route> QtLocation::Route::legs |
| |
| Returns the route legs associated with this route. |
| Route legs are the sub-routes between each two adjacent waypoints. |
| The result may be empty, if this level of detail is not supported by the |
| backend. |
| |
| \since QtLocation 5.12 |
| */ |
| QList<QObject *> QDeclarativeGeoRoute::legs() |
| { |
| // route_.routeLegs() is expected not to change. |
| // The following if condition is expected to be run only once. |
| if (route_.routeLegs().size() != legs_.size()) { |
| legs_.clear(); |
| QList<QGeoRouteLeg> rlegs = route_.routeLegs(); |
| for (const QGeoRouteLeg &r: rlegs) { |
| QDeclarativeGeoRouteLeg *dr = new QDeclarativeGeoRouteLeg(r, this); |
| legs_.append(dr); |
| } |
| } |
| return legs_; |
| } |
| |
| /*! |
| \qmlproperty Object Route::extendedAttributes |
| |
| This property holds the extended attributes of the route and is a map. |
| These attributes are plugin specific, and can be empty. |
| |
| Consult the \l {Qt Location#Plugin References and Parameters}{plugin documentation} |
| for what attributes are supported and how they should be used. |
| |
| Note, due to limitations of the QQmlPropertyMap, it is not possible |
| to declaratively specify the attributes in QML, assignment of attributes keys |
| and values can only be accomplished by JavaScript. |
| |
| \since QtLocation 5.13 |
| */ |
| QQmlPropertyMap *QDeclarativeGeoRoute::extendedAttributes() const |
| { |
| if (!m_extendedAttributes) { |
| QDeclarativeGeoRoute *self = const_cast<QDeclarativeGeoRoute *>(this); |
| self->m_extendedAttributes = new QQmlPropertyMap(self); |
| // Fill it |
| const QVariantMap &xAttrs = route_.extendedAttributes(); |
| const QStringList &keys = xAttrs.keys(); |
| for (const QString &key: keys) |
| self->m_extendedAttributes->insert(key, xAttrs.value(key)); |
| } |
| return m_extendedAttributes; |
| } |
| |
| /*! |
| \qmlmethod bool QtLocation::Route::equals(Route other) |
| |
| This method performs deep comparison if the present route |
| is identical to the \a other route. |
| Returns \c true if the routes are equal. |
| |
| \since 5.12 |
| */ |
| bool QDeclarativeGeoRoute::equals(QDeclarativeGeoRoute *other) const |
| { |
| return route_ == other->route_; |
| } |
| |
| /*! |
| \qmltype RouteLeg |
| \instantiates QDeclarativeGeoRouteLeg |
| \inqmlmodule QtLocation |
| \ingroup qml-QtLocation5-routing |
| \since QtLocation 5.12 |
| |
| \brief The RouteLeg type represents a leg of a Route, that is the portion |
| of a route between one waypoint and the next. |
| |
| \note Since RouteLeg is a subclass of Route, QtLocation::Route::legs will |
| return an empty list if accessed on a route leg. |
| */ |
| |
| /*! |
| \qmlproperty int QtLocation::RouteLeg::legIndex |
| |
| Read-only property which holds the index of the leg within the containing Route's list of QtLocation::Route::legs . |
| */ |
| |
| /*! |
| \qmlproperty Route QtLocation::RouteLeg::overallRoute |
| |
| Read-only property which holds the Route that contains this leg. |
| */ |
| |
| |
| QDeclarativeGeoRouteLeg::QDeclarativeGeoRouteLeg(QObject *parent) |
| : QDeclarativeGeoRoute(parent) |
| { |
| |
| } |
| |
| QDeclarativeGeoRouteLeg::QDeclarativeGeoRouteLeg(const QGeoRouteLeg &routeLeg, QObject *parent) |
| : QDeclarativeGeoRoute(routeLeg, parent), m_routeLeg(routeLeg) |
| { |
| |
| } |
| |
| QDeclarativeGeoRouteLeg::~QDeclarativeGeoRouteLeg() |
| { |
| |
| } |
| |
| int QDeclarativeGeoRouteLeg::legIndex() const |
| { |
| return m_routeLeg.legIndex(); |
| } |
| |
| QObject *QDeclarativeGeoRouteLeg::overallRoute() const |
| { |
| QDeclarativeGeoRoute *containingRoute = qobject_cast<QDeclarativeGeoRoute *>(parent()); |
| if (Q_UNLIKELY(!containingRoute)) |
| return new QDeclarativeGeoRoute(m_routeLeg.overallRoute(), parent()); |
| return containingRoute; |
| } |
| |
| QT_END_NAMESPACE |