summaryrefslogtreecommitdiff
path: root/src/location/declarativemaps
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2016-04-05 10:54:07 +0200
committerPaolo Angelelli <paolo.angelelli@qt.io>2017-01-26 14:46:08 +0000
commitd83f23e1ef19fe524c50b827ee408523dbb74bdc (patch)
treec04e66302e67c61c2909330ddf0e414a718f67ec /src/location/declarativemaps
parentc062403a894a270101ae821fd73fa848f918ac54 (diff)
downloadqtlocation-d83f23e1ef19fe524c50b827ee408523dbb74bdc.tar.gz
Moving location qml implementation to location/declarative*
QtLocation quick classes and headers are moved out of the import directory. The location quick classes are now in a subdirectory inside the main qtlocation module. This is necessary in order to privately export certain classes, such as Map Items classes, and create an API to inject these objects into QGeoMap to let plugins render the Map Items directly Change-Id: Ia6ba5f07c4eddd3c4c2ce54bf34f1afcd42c2558 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Diffstat (limited to 'src/location/declarativemaps')
-rw-r--r--src/location/declarativemaps/declarativemaps.pri62
-rw-r--r--src/location/declarativemaps/error_messages.cpp52
-rw-r--r--src/location/declarativemaps/error_messages.h55
-rw-r--r--src/location/declarativemaps/locationvaluetypehelper.cpp117
-rw-r--r--src/location/declarativemaps/locationvaluetypehelper_p.h60
-rw-r--r--src/location/declarativemaps/mapitemviewdelegateincubator.cpp54
-rw-r--r--src/location/declarativemaps/mapitemviewdelegateincubator_p.h66
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem.cpp728
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem_p.h134
-rw-r--r--src/location/declarativemaps/qdeclarativegeocodemodel.cpp727
-rw-r--r--src/location/declarativemaps/qdeclarativegeocodemodel_p.h207
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaneuver.cpp201
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaneuver_p.h111
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap.cpp1822
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap_p.h265
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp168
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h94
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase.cpp271
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase_p.h123
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview.cpp541
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview_p.h152
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h87
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapparameter.cpp125
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapparameter_p.h90
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem.cpp366
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem_p.h120
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaptype.cpp136
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaptype_p.h105
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute.cpp277
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute_p.h106
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel.cpp1308
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel_p.h344
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment.cpp164
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment_p.h86
-rw-r--r--src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp821
-rw-r--r--src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h284
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem.cpp743
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem_p.h161
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem.cpp956
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem_p.h197
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem.cpp380
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem_p.h122
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem.cpp149
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem_p.h92
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry.cpp149
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry_p.h150
-rw-r--r--src/location/declarativemaps/qquickgeomapgesturearea.cpp1288
-rw-r--r--src/location/declarativemaps/qquickgeomapgesturearea_p.h318
48 files changed, 15134 insertions, 0 deletions
diff --git a/src/location/declarativemaps/declarativemaps.pri b/src/location/declarativemaps/declarativemaps.pri
new file mode 100644
index 00000000..52e61049
--- /dev/null
+++ b/src/location/declarativemaps/declarativemaps.pri
@@ -0,0 +1,62 @@
+QT += quick-private network positioning-private qml-private core-private gui-private
+
+INCLUDEPATH += declarativemaps
+
+PUBLIC_HEADERS += \
+ declarativemaps/error_messages.h
+
+PRIVATE_HEADERS += \
+ declarativemaps/qdeclarativegeomapitemview_p.h \
+ declarativemaps/qdeclarativegeomapitemview_p_p.h \
+ declarativemaps/qdeclarativegeoserviceprovider_p.h \
+ declarativemaps/qdeclarativegeocodemodel_p.h \
+ declarativemaps/qdeclarativegeoroutemodel_p.h \
+ declarativemaps/qdeclarativegeoroute_p.h \
+ declarativemaps/qdeclarativegeoroutesegment_p.h \
+ declarativemaps/qdeclarativegeomaneuver_p.h \
+ declarativemaps/qdeclarativegeomap_p.h \
+ declarativemaps/qdeclarativegeomaptype_p.h \
+ declarativemaps/qdeclarativegeomapitembase_p.h \
+ declarativemaps/qdeclarativegeomapquickitem_p.h \
+ declarativemaps/qdeclarativecirclemapitem_p.h \
+ declarativemaps/qdeclarativerectanglemapitem_p.h \
+ declarativemaps/qdeclarativepolygonmapitem_p.h \
+ declarativemaps/qdeclarativepolylinemapitem_p.h \
+ declarativemaps/qdeclarativeroutemapitem_p.h \
+ declarativemaps/qdeclarativegeomapparameter_p.h \
+ declarativemaps/qgeomapitemgeometry_p.h \
+ declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h \
+ declarativemaps/locationvaluetypehelper_p.h \
+ declarativemaps/qquickgeomapgesturearea_p.h \
+ declarativemaps/mapitemviewdelegateincubator_p.h \
+ ../imports/positioning/qquickgeocoordinateanimation_p.h
+
+SOURCES += \
+ declarativemaps/qdeclarativegeomapitemview.cpp \
+ declarativemaps/qdeclarativegeoserviceprovider.cpp \
+ declarativemaps/qdeclarativegeocodemodel.cpp \
+ declarativemaps/qdeclarativegeoroutemodel.cpp \
+ declarativemaps/qdeclarativegeoroute.cpp \
+ declarativemaps/qdeclarativegeoroutesegment.cpp \
+ declarativemaps/qdeclarativegeomaneuver.cpp \
+ declarativemaps/qdeclarativegeomap.cpp \
+ declarativemaps/qdeclarativegeomaptype.cpp \
+ declarativemaps/qdeclarativegeomapitembase.cpp \
+ declarativemaps/qdeclarativegeomapquickitem.cpp \
+ declarativemaps/qdeclarativecirclemapitem.cpp \
+ declarativemaps/qdeclarativerectanglemapitem.cpp \
+ declarativemaps/qdeclarativepolygonmapitem.cpp \
+ declarativemaps/qdeclarativepolylinemapitem.cpp \
+ declarativemaps/qdeclarativeroutemapitem.cpp \
+ declarativemaps/qdeclarativegeomapparameter.cpp \
+ declarativemaps/qgeomapitemgeometry.cpp \
+ declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp \
+ declarativemaps/error_messages.cpp \
+ declarativemaps/locationvaluetypehelper.cpp \
+ declarativemaps/qquickgeomapgesturearea.cpp \
+ ../imports/positioning/qquickgeocoordinateanimation.cpp \
+ declarativemaps/mapitemviewdelegateincubator.cpp
+
+LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lpoly2tri$$qtPlatformTargetSuffix() -lclip2tri$$qtPlatformTargetSuffix()
+
+
diff --git a/src/location/declarativemaps/error_messages.cpp b/src/location/declarativemaps/error_messages.cpp
new file mode 100644
index 00000000..a2557f79
--- /dev/null
+++ b/src/location/declarativemaps/error_messages.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** 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 "error_messages.h"
+
+QT_BEGIN_NAMESPACE
+
+const char CONTEXT_NAME[] = "QtLocationQML";
+
+//to-be-translated error string
+
+const char PLUGIN_PROPERTY_NOT_SET[] = QT_TRANSLATE_NOOP("QtLocationQML", "Plugin property is not set.");
+const char PLUGIN_ERROR[] = QT_TRANSLATE_NOOP("QtLocationQML", "Plugin Error (%1): %2");
+const char PLUGIN_PROVIDER_ERROR[] = QT_TRANSLATE_NOOP("QtLocationQML", "Plugin Error (%1): Could not instantiate provider");
+const char PLUGIN_NOT_VALID[] = QT_TRANSLATE_NOOP("QtLocationQML", "Plugin is not valid");
+const char CATEGORIES_NOT_INITIALIZED[] = QT_TRANSLATE_NOOP("QtLocationQML", "Unable to initialize categories");
+const char UNABLE_TO_MAKE_REQUEST[] = QT_TRANSLATE_NOOP("QtLocationQML", "Unable to create request");
+const char INDEX_OUT_OF_RANGE[] = QT_TRANSLATE_NOOP("QtLocationQML", "Index '%1' out of range");
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/error_messages.h b/src/location/declarativemaps/error_messages.h
new file mode 100644
index 00000000..81c43b34
--- /dev/null
+++ b/src/location/declarativemaps/error_messages.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef ERROR_MESSAGES_H
+#define ERROR_MESSAGES_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+extern const char CONTEXT_NAME[];
+extern const char PLUGIN_PROPERTY_NOT_SET[];
+extern const char PLUGIN_ERROR[];
+extern const char PLUGIN_PROVIDER_ERROR[];
+extern const char PLUGIN_NOT_VALID[];
+extern const char CATEGORIES_NOT_INITIALIZED[];
+extern const char UNABLE_TO_MAKE_REQUEST[];
+extern const char INDEX_OUT_OF_RANGE[];
+
+QT_END_NAMESPACE
+
+#endif // ERROR_MESSAGES_H
diff --git a/src/location/declarativemaps/locationvaluetypehelper.cpp b/src/location/declarativemaps/locationvaluetypehelper.cpp
new file mode 100644
index 00000000..4f39e0b4
--- /dev/null
+++ b/src/location/declarativemaps/locationvaluetypehelper.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** 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 "locationvaluetypehelper_p.h"
+
+
+QGeoCoordinate parseCoordinate(const QJSValue &value, bool *ok)
+{
+ QGeoCoordinate c;
+
+ if (value.isObject()) {
+ if (value.hasProperty(QStringLiteral("latitude")))
+ c.setLatitude(value.property(QStringLiteral("latitude")).toNumber());
+ if (value.hasProperty(QStringLiteral("longitude")))
+ c.setLongitude(value.property(QStringLiteral("longitude")).toNumber());
+ if (value.hasProperty(QStringLiteral("altitude")))
+ c.setAltitude(value.property(QStringLiteral("altitude")).toNumber());
+
+ if (ok)
+ *ok = true;
+ }
+
+ return c;
+}
+
+QGeoRectangle parseRectangle(const QJSValue &value, bool *ok)
+{
+ QGeoRectangle r;
+
+ *ok = false;
+
+ if (value.isObject()) {
+ if (value.hasProperty(QStringLiteral("bottomLeft"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("bottomLeft")), ok);
+ if (*ok)
+ r.setBottomLeft(c);
+ }
+ if (value.hasProperty(QStringLiteral("bottomRight"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("bottomRight")), ok);
+ if (*ok)
+ r.setBottomRight(c);
+ }
+ if (value.hasProperty(QStringLiteral("topLeft"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("topLeft")), ok);
+ if (*ok)
+ r.setTopLeft(c);
+ }
+ if (value.hasProperty(QStringLiteral("topRight"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("topRight")), ok);
+ if (*ok)
+ r.setTopRight(c);
+ }
+ if (value.hasProperty(QStringLiteral("center"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("center")), ok);
+ if (*ok)
+ r.setCenter(c);
+ }
+ if (value.hasProperty(QStringLiteral("height")))
+ r.setHeight(value.property(QStringLiteral("height")).toNumber());
+ if (value.hasProperty(QStringLiteral("width")))
+ r.setWidth(value.property(QStringLiteral("width")).toNumber());
+ }
+
+ return r;
+}
+
+QGeoCircle parseCircle(const QJSValue &value, bool *ok)
+{
+ QGeoCircle c;
+
+ *ok = false;
+
+ if (value.isObject()) {
+ if (value.hasProperty(QStringLiteral("center"))) {
+ QGeoCoordinate coord = parseCoordinate(value.property(QStringLiteral("center")), ok);
+ if (*ok)
+ c.setCenter(coord);
+ }
+ if (value.hasProperty(QStringLiteral("radius")))
+ c.setRadius(value.property(QStringLiteral("radius")).toNumber());
+ }
+
+ return c;
+}
diff --git a/src/location/declarativemaps/locationvaluetypehelper_p.h b/src/location/declarativemaps/locationvaluetypehelper_p.h
new file mode 100644
index 00000000..50038e88
--- /dev/null
+++ b/src/location/declarativemaps/locationvaluetypehelper_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef LOCATION_VALUE_TYPE_HELPER
+#define LOCATION_VALUE_TYPE_HELPER
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QJSValue>
+#include <QGeoCoordinate>
+#include <QGeoRectangle>
+#include <QGeoCircle>
+
+QGeoCoordinate parseCoordinate(const QJSValue &value, bool *ok);
+QGeoRectangle parseRectangle(const QJSValue &value, bool *ok);
+QGeoCircle parseCircle(const QJSValue &value, bool *ok);
+
+#endif
diff --git a/src/location/declarativemaps/mapitemviewdelegateincubator.cpp b/src/location/declarativemaps/mapitemviewdelegateincubator.cpp
new file mode 100644
index 00000000..c8500e4b
--- /dev/null
+++ b/src/location/declarativemaps/mapitemviewdelegateincubator.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Jolla Ltd, author: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
+** 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 "mapitemviewdelegateincubator_p.h"
+#include "qdeclarativegeomapitemview_p.h"
+#include "qdeclarativegeomapitemview_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+MapItemViewDelegateIncubator::MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view, QDeclarativeGeoMapItemViewItemData *itemData, bool batched)
+: m_view(view), m_itemData(itemData), m_batched(batched)
+{
+}
+
+void MapItemViewDelegateIncubator::statusChanged(QQmlIncubator::Status status)
+{
+ m_view->incubatorStatusChanged(this, status, m_batched);
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/mapitemviewdelegateincubator_p.h b/src/location/declarativemaps/mapitemviewdelegateincubator_p.h
new file mode 100644
index 00000000..b559c944
--- /dev/null
+++ b/src/location/declarativemaps/mapitemviewdelegateincubator_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Jolla Ltd, author: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
+** 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$
+**
+****************************************************************************/
+#ifndef MAPITEMVIEWDELEGATEINCUBATOR_H
+#define MAPITEMVIEWDELEGATEINCUBATOR_H
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtQml/QQmlIncubator>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGeoMapItemView;
+class QDeclarativeGeoMapItemViewItemData;
+
+class Q_LOCATION_PRIVATE_EXPORT MapItemViewDelegateIncubator : public QQmlIncubator
+{
+public:
+ MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view, QDeclarativeGeoMapItemViewItemData *itemData, bool batched = true);
+
+protected:
+ void statusChanged(Status status) Q_DECL_OVERRIDE;
+
+private:
+ QDeclarativeGeoMapItemView *m_view;
+ QDeclarativeGeoMapItemViewItemData *m_itemData;
+ bool m_batched;
+
+ friend class QDeclarativeGeoMapItemView;
+};
+
+QT_END_NAMESPACE
+
+#endif // MAPITEMVIEWDELEGATEINCUBATOR_H
diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
new file mode 100644
index 00000000..39581dce
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
@@ -0,0 +1,728 @@
+/***************************************************************************
+**
+** 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 "qdeclarativecirclemapitem_p.h"
+#include "qdeclarativepolygonmapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+
+#include "qwebmercator_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <cmath>
+#include <algorithm>
+
+#include <QtCore/QScopedValueRollback>
+#include <QPen>
+#include <QPainter>
+#include <QtGui/private/qtriangulator_p.h>
+
+#include "qdoublevector2d_p.h"
+#include "qlocationutils_p.h"
+#include "qgeocircle.h"
+
+/* poly2tri triangulator includes */
+#include <common/shapes.h>
+#include <sweep/cdt.h>
+
+#include <QtPositioning/private/qclipperutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapCircle
+ \instantiates QDeclarativeCircleMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapCircle type displays a geographic circle on a Map.
+
+ The MapCircle type displays a geographic circle on a Map, which
+ consists of all points that are within a set distance from one
+ central point. Depending on map projection, a geographic circle
+ may not always be a perfect circle on the screen: for instance, in
+ the Mercator projection, circles become ovoid in shape as they near
+ the poles. To display a perfect screen circle around a point, use a
+ MapQuickItem containing a relevant Qt Quick type instead.
+
+ By default, the circle is displayed as a 1 pixel black border with
+ no fill. To change its appearance, use the color, border.color
+ and border.width properties.
+
+ Internally, a MapCircle is implemented as a many-sided polygon. To
+ calculate the radius points it uses a spherical model of the Earth,
+ similar to the atDistanceAndAzimuth method of the \l {coordinate}
+ type. These two things can occasionally have implications for the
+ accuracy of the circle's shape, depending on position and map
+ projection.
+
+ \note Dragging a MapCircle (through the use of \l MouseArea)
+ causes new points to be generated at the same distance (in meters)
+ from the center. This is in contrast to other map items which store
+ their dimensions in terms of latitude and longitude differences between
+ vertices.
+
+ \section2 Performance
+
+ MapCircle performance is almost equivalent to that of a MapPolygon with
+ the same number of vertices. There is a small amount of additional
+ overhead with respect to calculating the vertices first.
+
+ Like the other map objects, MapCircle is normally drawn without a smooth
+ appearance. Setting the opacity property will force the object to be
+ blended, which decreases performance considerably depending on the graphics
+ hardware in use.
+
+ \section2 Example Usage
+
+ The following snippet shows a map containing a MapCircle, centered at
+ the coordinate (-27, 153) with a radius of 5km. The circle is
+ filled in green, with a 3 pixel black border.
+
+ \code
+ Map {
+ MapCircle {
+ center {
+ latitude: -27.5
+ longitude: 153.0
+ }
+ radius: 5000.0
+ color: 'green'
+ border.width: 3
+ }
+ }
+ \endcode
+
+ \image api-mapcircle.png
+*/
+
+#ifdef M_PI
+#undef M_PI
+#endif
+#define M_PI 3.14159265358979323846264338327950288
+
+static const int CircleSamples = 128;
+
+struct Vertex
+{
+ QVector2D position;
+};
+
+QGeoMapCircleGeometry::QGeoMapCircleGeometry()
+{
+}
+
+/*!
+ \internal
+*/
+void QGeoMapCircleGeometry::updateScreenPointsInvert(const QList<QGeoCoordinate> &circlePath, const QGeoMap &map)
+{
+ // Not checking for !screenDirty anymore, as everything is now recalculated.
+ clear();
+ if (map.viewportWidth() == 0 || map.viewportHeight() == 0 || circlePath.size() < 3) // a circle requires at least 3 points;
+ return;
+
+ /*
+ * No special case for no tilting as these items are very rare, and usually at most one per map.
+ *
+ * Approach:
+ * 1) subtract the circle from a rectangle filling the whole map, *in wrapped mercator space*
+ * 2) clip the resulting geometries against the visible region, *in wrapped mercator space*
+ * 3) create a QPainterPath with each of the resulting polygons projected to screen
+ * 4) use qTriangulate() to triangulate the painter path
+ */
+
+ // 1)
+ double topLati = QLocationUtils::mercatorMaxLatitude();
+ double bottomLati = -(QLocationUtils::mercatorMaxLatitude());
+ double leftLongi = QLocationUtils::mapLeftLongitude(map.cameraData().center().longitude());
+ double rightLongi = QLocationUtils::mapRightLongitude(map.cameraData().center().longitude());
+
+ srcOrigin_ = QGeoCoordinate(topLati,leftLongi);
+ QDoubleVector2D tl = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(topLati,leftLongi));
+ QDoubleVector2D tr = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(topLati,rightLongi));
+ QDoubleVector2D br = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(bottomLati,rightLongi));
+ QDoubleVector2D bl = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(bottomLati,leftLongi));
+
+ QList<QDoubleVector2D> fill;
+ fill << tl << tr << br << bl;
+
+ QList<QDoubleVector2D> hole;
+ for (const QGeoCoordinate &c: circlePath)
+ hole << map.geoProjection().geoToWrappedMapProjection(c);
+
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(fill), true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(hole));
+ Paths difference = clipper.execute(c2t::clip2tri::Difference, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+
+ // 2)
+ QDoubleVector2D lb = map.geoProjection().geoToWrappedMapProjection(srcOrigin_);
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ clipper.clearClipper();
+ for (const Path &p: difference)
+ clipper.addSubjectPath(p, true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ with the point with minimum X/Y
+ lb = QDoubleVector2D(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ for (const QDoubleVector2D &p: path) {
+ if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) {
+ lb = p;
+ }
+ }
+ }
+ if (qIsInf(lb.x()))
+ return;
+
+ // Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(tl.x(), lb.x()));
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(lb));
+ } else {
+ clippedPaths = QClipperUtils::pathsToQList(difference);
+ }
+
+ //3)
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(lb);
+
+ QPainterPath ppi;
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+ //point = point - origin; // Do this using ppi.translate()
+
+ if (i == 0) {
+ ppi.moveTo(point.toPointF());
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ ppi.lineTo(point.toPointF());
+ lastAddedPoint = point;
+ }
+ }
+ }
+ ppi.closeSubpath();
+ }
+ ppi.translate(-1 * origin.toPointF());
+
+#if 0 // old poly2tri code, has to be ported to clip2tri in order to work with tilted projections
+ std::vector<p2t::Point*> borderPts;
+ borderPts.reserve(4);
+
+ std::vector<p2t::Point*> curPts;
+ curPts.reserve(ppi.elementCount());
+ for (int i = 0; i < ppi.elementCount(); ++i) {
+ const QPainterPath::Element e = ppi.elementAt(i);
+ if (e.isMoveTo() || i == ppi.elementCount() - 1
+ || (qAbs(e.x - curPts.front()->x) < 0.1
+ && qAbs(e.y - curPts.front()->y) < 0.1)) {
+ if (curPts.size() > 2) {
+ for (int j = 0; j < 4; ++j) {
+ const QPainterPath::Element e2 = ppiBorder.elementAt(j);
+ borderPts.push_back(new p2t::Point(e2.x, e2.y));
+ }
+ p2t::CDT *cdt = new p2t::CDT(borderPts);
+ cdt->AddHole(curPts);
+ cdt->Triangulate();
+ std::vector<p2t::Triangle*> tris = cdt->GetTriangles();
+ screenVertices_.reserve(screenVertices_.size() + int(tris.size()));
+ for (size_t i = 0; i < tris.size(); ++i) {
+ p2t::Triangle *t = tris.at(i);
+ for (int j = 0; j < 3; ++j) {
+ p2t::Point *p = t->GetPoint(j);
+ screenVertices_ << QPointF(p->x, p->y);
+ }
+ }
+ delete cdt;
+ }
+ curPts.clear();
+ curPts.reserve(ppi.elementCount() - i);
+ curPts.push_back(new p2t::Point(e.x, e.y));
+ } else if (e.isLineTo()) {
+ curPts.push_back(new p2t::Point(e.x, e.y));
+ } else {
+ qWarning("Unhandled element type in circle painterpath");
+ }
+ }
+
+ if (curPts.size() > 0) {
+ qDeleteAll(curPts.begin(), curPts.end());
+ curPts.clear();
+ }
+
+ if (borderPts.size() > 0) {
+ qDeleteAll(borderPts.begin(), borderPts.end());
+ borderPts.clear();
+ }
+#else // Using qTriangulate as this case is not frequent, and not many circles including both poles are usually used
+ QTriangleSet ts = qTriangulate(ppi);
+ qreal *vx = ts.vertices.data();
+
+ screenIndices_.reserve(ts.indices.size());
+ screenVertices_.reserve(ts.vertices.size());
+
+ if (ts.indices.type() == QVertexIndexVector::UnsignedInt) {
+ const quint32 *ix = reinterpret_cast<const quint32 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ } else {
+ const quint16 *ix = reinterpret_cast<const quint16 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ }
+ for (int i = 0; i < (ts.vertices.size()/2*2); i += 2)
+ screenVertices_ << QPointF(vx[i], vx[i + 1]);
+#endif
+
+ screenBounds_ = ppi.boundingRect();
+ sourceBounds_ = screenBounds_;
+}
+
+static bool crossEarthPole(const QGeoCoordinate &center, qreal distance)
+{
+ qreal poleLat = 90;
+ QGeoCoordinate northPole = QGeoCoordinate(poleLat, center.longitude());
+ QGeoCoordinate southPole = QGeoCoordinate(-poleLat, center.longitude());
+ // approximate using great circle distance
+ qreal distanceToNorthPole = center.distanceTo(northPole);
+ qreal distanceToSouthPole = center.distanceTo(southPole);
+ if (distanceToNorthPole < distance || distanceToSouthPole < distance)
+ return true;
+ return false;
+}
+
+static void calculatePeripheralPoints(QList<QGeoCoordinate> &path,
+ const QGeoCoordinate &center,
+ qreal distance,
+ int steps)
+{
+ // Calculate points based on great-circle distance
+ // Calculation is the same as GeoCoordinate's atDistanceAndAzimuth function
+ // but tweaked here for computing multiple points
+
+ // pre-calculations
+ steps = qMax(steps, 3);
+ qreal centerLon = center.longitude();
+ qreal latRad = QLocationUtils::radians(center.latitude());
+ qreal lonRad = QLocationUtils::radians(centerLon);
+ qreal cosLatRad = std::cos(latRad);
+ qreal sinLatRad = std::sin(latRad);
+ qreal ratio = (distance / (QLocationUtils::earthMeanRadius()));
+ qreal cosRatio = std::cos(ratio);
+ qreal sinRatio = std::sin(ratio);
+ qreal sinLatRad_x_cosRatio = sinLatRad * cosRatio;
+ qreal cosLatRad_x_sinRatio = cosLatRad * sinRatio;
+ for (int i = 0; i < steps; ++i) {
+ qreal azimuthRad = 2 * M_PI * i / steps;
+ qreal resultLatRad = std::asin(sinLatRad_x_cosRatio
+ + cosLatRad_x_sinRatio * std::cos(azimuthRad));
+ qreal resultLonRad = lonRad + std::atan2(std::sin(azimuthRad) * cosLatRad_x_sinRatio,
+ cosRatio - sinLatRad * std::sin(resultLatRad));
+ qreal lat2 = QLocationUtils::degrees(resultLatRad);
+ qreal lon2 = QLocationUtils::wrapLong(QLocationUtils::degrees(resultLonRad));
+
+ path << QGeoCoordinate(lat2, lon2, center.altitude());
+ }
+}
+
+QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), dirtyMaterial_(true),
+ updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(markSourceDirtyAndUpdate()));
+
+ // assume that circles are not self-intersecting
+ // to speed up processing
+ // FIXME: unfortunately they self-intersect at the poles due to current drawing method
+ // so the line is commented out until fixed
+ //geometry_.setAssumeSimple(true);
+
+}
+
+QDeclarativeCircleMapItem::~QDeclarativeCircleMapItem()
+{
+}
+
+/*!
+ \qmlpropertygroup Location::MapCircle::border
+ \qmlproperty int MapCircle::border.width
+ \qmlproperty color MapCircle::border.color
+
+ This property is part of the border group property.
+ The border property holds the width and color used to draw the border of the circle.
+ The width is in pixels and is independent of the zoom level of the map.
+
+ The default values correspond to a black border with a width of 1 pixel.
+ For no line, use a width of 0 or a transparent color.
+*/
+QDeclarativeMapLineProperties *QDeclarativeCircleMapItem::border()
+{
+ return &border_;
+}
+
+void QDeclarativeCircleMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+void QDeclarativeCircleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map)
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \qmlproperty coordinate MapCircle::center
+
+ This property holds the central point about which the circle is defined.
+
+ \sa radius
+*/
+void QDeclarativeCircleMapItem::setCenter(const QGeoCoordinate &center)
+{
+ if (circle_.center() == center)
+ return;
+
+ circle_.setCenter(center);
+ markSourceDirtyAndUpdate();
+ emit centerChanged(center);
+}
+
+QGeoCoordinate QDeclarativeCircleMapItem::center()
+{
+ return circle_.center();
+}
+
+/*!
+ \qmlproperty color MapCircle::color
+
+ This property holds the fill color of the circle when drawn. For no fill,
+ use a transparent color.
+*/
+void QDeclarativeCircleMapItem::setColor(const QColor &color)
+{
+ if (color_ == color)
+ return;
+ color_ = color;
+ dirtyMaterial_ = true;
+ update();
+ emit colorChanged(color_);
+}
+
+QColor QDeclarativeCircleMapItem::color() const
+{
+ return color_;
+}
+
+/*!
+ \qmlproperty real MapCircle::radius
+
+ This property holds the radius of the circle, in meters on the ground.
+
+ \sa center
+*/
+void QDeclarativeCircleMapItem::setRadius(qreal radius)
+{
+ if (circle_.radius() == radius)
+ return;
+
+ circle_.setRadius(radius);
+ markSourceDirtyAndUpdate();
+ emit radiusChanged(radius);
+}
+
+qreal QDeclarativeCircleMapItem::radius() const
+{
+ return circle_.radius();
+}
+
+/*!
+ \qmlproperty real MapCircle::opacity
+
+ This property holds the opacity of the item. Opacity is specified as a
+ number between 0 (fully transparent) and 1 (fully opaque). The default is 1.
+
+ An item with 0 opacity will still receive mouse events. To stop mouse events, set the
+ visible property of the item to false.
+*/
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativeCircleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+
+ MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
+
+ if (!node)
+ node = new MapPolygonNode();
+
+ //TODO: update only material
+ if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
+ node->update(color_, border_.color(), &geometry_, &borderGeometry_);
+ geometry_.setPreserveGeometry(false);
+ borderGeometry_.setPreserveGeometry(false);
+ geometry_.markClean();
+ borderGeometry_.markClean();
+ dirtyMaterial_ = false;
+ }
+ return node;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCircleMapItem::updatePolish()
+{
+ if (!map() || !circle_.isValid())
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ if (geometry_.isSourceDirty()) {
+ circlePath_.clear();
+ calculatePeripheralPoints(circlePath_, circle_.center(), circle_.radius(), CircleSamples);
+ }
+
+ QList<QGeoCoordinate> originalCirclePath = circlePath_;
+
+ int pathCount = circlePath_.size();
+ bool preserve = preserveCircleGeometry(circlePath_, circle_.center(), circle_.radius());
+ geometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_
+ geometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft());
+
+ bool invertedCircle = false;
+ if (crossEarthPole(circle_.center(), circle_.radius()) && circlePath_.size() == pathCount) {
+ geometry_.updateScreenPointsInvert(circlePath_, *map()); // invert fill area for really huge circles
+ invertedCircle = true;
+ } else {
+ geometry_.updateSourcePoints(*map(), circlePath_);
+ geometry_.updateScreenPoints(*map());
+ }
+
+ borderGeometry_.clear();
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QGeoCoordinate> closedPath = circlePath_;
+ closedPath << closedPath.first();
+
+ if (invertedCircle) {
+ closedPath = originalCirclePath;
+ closedPath << closedPath.first();
+ std::reverse(closedPath.begin(), closedPath.end());
+ }
+
+ borderGeometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_
+ borderGeometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft());
+
+ // Use srcOrigin_ from fill geometry after clipping to ensure that translateToCommonOrigin won't fail.
+ const QGeoCoordinate &geometryOrigin = geometry_.origin();
+
+ borderGeometry_.srcPoints_.clear();
+ borderGeometry_.srcPointTypes_.clear();
+
+ QDoubleVector2D borderLeftBoundWrapped;
+ QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
+ if (clippedPaths.size()) {
+ borderLeftBoundWrapped = map()->geoProjection().geoToWrappedMapProjection(geometryOrigin);
+ borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
+ borderGeometry_.updateScreenPoints(*map(), border_.width());
+ geoms << &borderGeometry_;
+ } else {
+ borderGeometry_.clear();
+ }
+ }
+
+ QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ setWidth(combined.width());
+ setHeight(combined.height());
+
+ setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCircleMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ return;
+
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeCircleMapItem::contains(const QPointF &point) const
+{
+ return (geometry_.contains(point) || borderGeometry_.contains(point));
+}
+
+const QGeoShape &QDeclarativeCircleMapItem::geoShape() const
+{
+ return circle_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCircleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (updatingGeometry_ || newGeometry == oldGeometry) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+
+ QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(width(), height()) / 2;
+ QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(newPoint, false);
+ if (newCoordinate.isValid())
+ setCenter(newCoordinate);
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+bool QDeclarativeCircleMapItem::preserveCircleGeometry (QList<QGeoCoordinate> &path,
+ const QGeoCoordinate &center, qreal distance)
+{
+ // if circle crosses north/south pole, then don't preserve circular shape,
+ if ( crossEarthPole(center, distance)) {
+ updateCirclePathForRendering(path, center, distance);
+ return false;
+ }
+ return true;
+
+}
+
+/*
+ * A workaround for circle path to be drawn correctly using a polygon geometry
+ * This method generates a polygon like
+ * _____________
+ * | |
+ * \ /
+ * | |
+ * / \
+ * | |
+ * -------------
+ *
+ * or a polygon like
+ *
+ * ______________
+ * | ____ |
+ * \__/ \__/
+ */
+void QDeclarativeCircleMapItem::updateCirclePathForRendering(QList<QGeoCoordinate> &path,
+ const QGeoCoordinate &center,
+ qreal distance)
+{
+ qreal poleLat = 90;
+ qreal distanceToNorthPole = center.distanceTo(QGeoCoordinate(poleLat, 0));
+ qreal distanceToSouthPole = center.distanceTo(QGeoCoordinate(-poleLat, 0));
+ bool crossNorthPole = distanceToNorthPole < distance;
+ bool crossSouthPole = distanceToSouthPole < distance;
+
+ QList<int> wrapPathIndex;
+ QDoubleVector2D prev = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(0)));
+
+ for (int i = 1; i <= path.count(); ++i) {
+ int index = i % path.count();
+ QDoubleVector2D point = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(index)));
+ double diff = qAbs(point.x() - prev.x());
+ if (diff > 0.5) {
+ continue;
+ }
+ }
+
+ // find the points in path where wrapping occurs
+ for (int i = 1; i <= path.count(); ++i) {
+ int index = i % path.count();
+ QDoubleVector2D point = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(index)));
+ if ( (qAbs(point.x() - prev.x())) >= 0.5 ) { // TODO: Add a projectionWidth to GeoProjection, perhaps?
+ wrapPathIndex << index;
+ if (wrapPathIndex.size() == 2 || !(crossNorthPole && crossSouthPole))
+ break;
+ }
+ prev = point;
+ }
+ // insert two additional coords at top/bottom map corners of the map for shape
+ // to be drawn correctly
+ if (wrapPathIndex.size() > 0) {
+ qreal newPoleLat = 90;
+ QGeoCoordinate wrapCoord = path.at(wrapPathIndex[0]);
+ if (wrapPathIndex.size() == 2) {
+ QGeoCoordinate wrapCoord2 = path.at(wrapPathIndex[1]);
+ if (wrapCoord2.latitude() > wrapCoord.latitude())
+ newPoleLat = -90;
+ } else if (center.latitude() < 0) {
+ newPoleLat = -90;
+ }
+ for (int i = 0; i < wrapPathIndex.size(); ++i) {
+ int index = wrapPathIndex[i] == 0 ? 0 : wrapPathIndex[i] + i*2;
+ int prevIndex = (index - 1) < 0 ? (path.count() - 1): index - 1;
+ QGeoCoordinate coord0 = path.at(prevIndex);
+ QGeoCoordinate coord1 = path.at(index);
+ coord0.setLatitude(newPoleLat);
+ coord1.setLatitude(newPoleLat);
+ path.insert(index ,coord1);
+ path.insert(index, coord0);
+ newPoleLat = -newPoleLat;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem_p.h b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
new file mode 100644
index 00000000..62bef6d3
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVECIRCLEMAPITEM_H
+#define QDECLARATIVECIRCLEMAPITEM_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+#include <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+#include <QtPositioning/QGeoCircle>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoMapCircleGeometry : public QGeoMapPolygonGeometry
+{
+public:
+ QGeoMapCircleGeometry();
+
+ void updateScreenPointsInvert(const QList<QGeoCoordinate> &circlePath, const QGeoMap &map);
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCircleMapItem : public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+ Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QDeclarativeMapLineProperties *border READ border CONSTANT)
+
+public:
+ explicit QDeclarativeCircleMapItem(QQuickItem *parent = 0);
+ ~QDeclarativeCircleMapItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+
+ QGeoCoordinate center();
+ void setCenter(const QGeoCoordinate &center);
+
+ qreal radius() const;
+ void setRadius(qreal radius);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QDeclarativeMapLineProperties *border();
+
+ bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void centerChanged(const QGeoCoordinate &center);
+ void radiusChanged(qreal radius);
+ void colorChanged(const QColor &color);
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ bool preserveCircleGeometry(QList<QGeoCoordinate> &path, const QGeoCoordinate &center,
+ qreal distance);
+ void updateCirclePathForRendering(QList<QGeoCoordinate> &path, const QGeoCoordinate &center,
+ qreal distance);
+
+private:
+ QGeoCircle circle_;
+ QDeclarativeMapLineProperties border_;
+ QColor color_;
+ QList<QGeoCoordinate> circlePath_;
+ bool dirtyMaterial_;
+ QGeoMapCircleGeometry geometry_;
+ QGeoMapPolylineGeometry borderGeometry_;
+ bool updatingGeometry_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeCircleMapItem)
+
+#endif /* QDECLARATIVECIRCLEMAPITEM_H */
diff --git a/src/location/declarativemaps/qdeclarativegeocodemodel.cpp b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp
new file mode 100644
index 00000000..e92949ee
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp
@@ -0,0 +1,727 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeocodemodel_p.h"
+#include "error_messages.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtQml/QQmlInfo>
+#include <QtPositioning/QGeoCircle>
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/QGeoCodingManager>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype GeocodeModel
+ \instantiates QDeclarativeGeocodeModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-geocoding
+ \since Qt Location 5.5
+
+ \brief The GeocodeModel type provides support for searching operations
+ related to geographic information.
+
+ The GeocodeModel type is used as part of a model/view grouping to
+ match addresses or search strings with geographic locations. How the
+ geographic locations generated are used or displayed is decided by any
+ Views attached to the GeocodeModel (for example a \l MapItemView or \l{ListView}).
+
+ Like \l Map and \l RouteModel, all the data for a GeocodeModel to work
+ comes from a services plugin. This is contained in the \l{plugin} property,
+ and this must be set before the GeocodeModel can do any useful work.
+
+ Once the plugin is set, the \l{query} property can be used to specify the
+ address or search string to match. If \l{autoUpdate} is enabled, the Model
+ will update its output automatically. Otherwise, the \l{update} method may
+ be used. By default, autoUpdate is disabled.
+
+ The data stored and returned in the GeocodeModel consists of \l{Location}
+ objects, as a list with the role name "locationData". See the documentation
+ for \l{Location} for further details on its structure and contents.
+
+ \section2 Example Usage
+
+ The following snippet is two-part, showing firstly the declaration of
+ objects, and secondly a short piece of procedural code using it. We set
+ the geocodeModel's \l{autoUpdate} property to false, and call \l{update} once
+ the query is set up. In this case, as we use a string value in \l{query},
+ only one update would occur, even with autoUpdate enabled. However, if we
+ provided an \l{Address} object we may inadvertently trigger multiple
+ requests whilst setting its properties.
+
+ \code
+ Plugin {
+ id: aPlugin
+ }
+
+ GeocodeModel {
+ id: geocodeModel
+ plugin: aPlugin
+ autoUpdate: false
+ }
+ \endcode
+
+ \code
+ {
+ geocodeModel.query = "53 Brandl St, Eight Mile Plains, Australia"
+ geocodeModel.update()
+ }
+ \endcode
+*/
+
+/*!
+ \qmlsignal QtLocation::GeocodeModel::locationsChanged()
+
+ This signal is emitted when locations in the model have changed.
+
+ \sa count
+*/
+
+
+QDeclarativeGeocodeModel::QDeclarativeGeocodeModel(QObject *parent)
+: QAbstractListModel(parent), autoUpdate_(false), complete_(false), reply_(0), plugin_(0),
+ status_(QDeclarativeGeocodeModel::Null), error_(QDeclarativeGeocodeModel::NoError),
+ address_(0), limit_(-1), offset_(0)
+{
+}
+
+QDeclarativeGeocodeModel::~QDeclarativeGeocodeModel()
+{
+ qDeleteAll(declarativeLocations_);
+ declarativeLocations_.clear();
+ delete reply_;
+}
+
+/*!
+ \internal
+ From QQmlParserStatus
+*/
+void QDeclarativeGeocodeModel::componentComplete()
+{
+ complete_ = true;
+ if (autoUpdate_)
+ update();
+}
+
+/*!
+ \qmlmethod void QtLocation::GeocodeModel::update()
+
+ Instructs the GeocodeModel to update its data. This is most useful
+ when \l autoUpdate is disabled, to force a refresh when the query
+ has been changed.
+*/
+void QDeclarativeGeocodeModel::update()
+{
+ if (!complete_)
+ return;
+
+ if (!plugin_) {
+ setError(EngineNotSetError, tr("Cannot geocode, plugin not set."));
+ return;
+ }
+
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return;
+
+ QGeoCodingManager *geocodingManager = serviceProvider->geocodingManager();
+ if (!geocodingManager) {
+ setError(EngineNotSetError, tr("Cannot geocode, geocode manager not set."));
+ return;
+ }
+ if (!coordinate_.isValid() && (!address_ || address_->address().isEmpty()) &&
+ (searchString_.isEmpty())) {
+ setError(ParseError, tr("Cannot geocode, valid query not set."));
+ return;
+ }
+ abortRequest(); // abort possible previous requests
+ setError(NoError, QString());
+
+ if (coordinate_.isValid()) {
+ setStatus(QDeclarativeGeocodeModel::Loading);
+ reply_ = geocodingManager->reverseGeocode(coordinate_, boundingArea_);
+ if (reply_->isFinished()) {
+ if (reply_->error() == QGeoCodeReply::NoError) {
+ geocodeFinished(reply_);
+ } else {
+ geocodeError(reply_, reply_->error(), reply_->errorString());
+ }
+ }
+ } else if (address_) {
+ setStatus(QDeclarativeGeocodeModel::Loading);
+ reply_ = geocodingManager->geocode(address_->address(), boundingArea_);
+ if (reply_->isFinished()) {
+ if (reply_->error() == QGeoCodeReply::NoError) {
+ geocodeFinished(reply_);
+ } else {
+ geocodeError(reply_, reply_->error(), reply_->errorString());
+ }
+ }
+ } else if (!searchString_.isEmpty()) {
+ setStatus(QDeclarativeGeocodeModel::Loading);
+ reply_ = geocodingManager->geocode(searchString_, limit_, offset_, boundingArea_);
+ if (reply_->isFinished()) {
+ if (reply_->error() == QGeoCodeReply::NoError) {
+ geocodeFinished(reply_);
+ } else {
+ geocodeError(reply_, reply_->error(), reply_->errorString());
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::abortRequest()
+{
+ if (reply_) {
+ reply_->abort();
+ reply_->deleteLater();
+ reply_ = 0;
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::queryContentChanged()
+{
+ if (autoUpdate_)
+ update();
+}
+
+/*!
+ \internal
+ From QAbstractListModel
+*/
+int QDeclarativeGeocodeModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return declarativeLocations_.count();
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeGeocodeModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+ if (index.row() >= declarativeLocations_.count())
+ return QVariant();
+ if (role == QDeclarativeGeocodeModel::LocationRole) {
+ QObject *locationObject = declarativeLocations_.at(index.row());
+ Q_ASSERT(locationObject);
+ return QVariant::fromValue(locationObject);
+ }
+ return QVariant();
+}
+
+QHash<int, QByteArray> QDeclarativeGeocodeModel::roleNames() const
+{
+ QHash<int, QByteArray> roleNames = QAbstractItemModel::roleNames();
+ roleNames.insert(LocationRole, "locationData");
+ return roleNames;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (plugin_ == plugin)
+ return;
+
+ reset(); // reset the model
+ plugin_ = plugin;
+ if (complete_)
+ emit pluginChanged();
+
+ if (!plugin)
+ return;
+
+ if (plugin_->isAttached()) {
+ pluginReady();
+ } else {
+ connect(plugin_, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::pluginReady()
+{
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ QGeoCodingManager *geocodingManager = serviceProvider->geocodingManager();
+
+ if (serviceProvider->error() != QGeoServiceProvider::NoError) {
+ QDeclarativeGeocodeModel::GeocodeError newError = UnknownError;
+ switch (serviceProvider->error()) {
+ case QGeoServiceProvider::NotSupportedError:
+ newError = EngineNotSetError; break;
+ case QGeoServiceProvider::UnknownParameterError:
+ newError = UnknownParameterError; break;
+ case QGeoServiceProvider::MissingRequiredParameterError:
+ newError = MissingRequiredParameterError; break;
+ case QGeoServiceProvider::ConnectionError:
+ newError = CommunicationError; break;
+ default:
+ break;
+ }
+
+ setError(newError, serviceProvider->errorString());
+ return;
+ }
+
+ if (!geocodingManager) {
+ setError(EngineNotSetError,tr("Plugin does not support (reverse) geocoding."));
+ return;
+ }
+
+ connect(geocodingManager, SIGNAL(finished(QGeoCodeReply*)),
+ this, SLOT(geocodeFinished(QGeoCodeReply*)));
+ connect(geocodingManager, SIGNAL(error(QGeoCodeReply*,QGeoCodeReply::Error,QString)),
+ this, SLOT(geocodeError(QGeoCodeReply*,QGeoCodeReply::Error,QString)));
+}
+
+/*!
+ \qmlproperty Plugin QtLocation::GeocodeModel::plugin
+
+ This property holds the plugin that provides the actual geocoding service.
+ Note that all plugins do not necessarily provide geocoding (could for example provide
+ only routing or maps).
+
+ \sa Plugin
+*/
+
+QDeclarativeGeoServiceProvider *QDeclarativeGeocodeModel::plugin() const
+{
+ return plugin_;
+}
+
+void QDeclarativeGeocodeModel::setBounds(const QVariant &boundingArea)
+{
+ QGeoShape s;
+
+ if (boundingArea.userType() == qMetaTypeId<QGeoRectangle>())
+ s = boundingArea.value<QGeoRectangle>();
+ else if (boundingArea.userType() == qMetaTypeId<QGeoCircle>())
+ s = boundingArea.value<QGeoCircle>();
+ else if (boundingArea.userType() == qMetaTypeId<QGeoShape>())
+ s = boundingArea.value<QGeoShape>();
+
+
+ if (boundingArea_ == s)
+ return;
+
+ boundingArea_ = s;
+ emit boundsChanged();
+}
+
+/*!
+ \qmlproperty geoshape QtLocation::GeocodeModel::bounds
+
+ This property holds the bounding area used to limit the results to those
+ within the area. This is particularly useful if query is only partially filled out,
+ as the service will attempt to (reverse) geocode all matches for the specified data.
+
+ Accepted types are \l {georectangle} and
+ \l {geocircle}.
+*/
+QVariant QDeclarativeGeocodeModel::bounds() const
+{
+ if (boundingArea_.type() == QGeoShape::RectangleType)
+ return QVariant::fromValue(QGeoRectangle(boundingArea_));
+ else if (boundingArea_.type() == QGeoShape::CircleType)
+ return QVariant::fromValue(QGeoCircle(boundingArea_));
+ else
+ return QVariant::fromValue(boundingArea_);
+}
+
+void QDeclarativeGeocodeModel::geocodeFinished(QGeoCodeReply *reply)
+{
+ if (reply != reply_ || reply->error() != QGeoCodeReply::NoError)
+ return;
+ int oldCount = declarativeLocations_.count();
+ setLocations(reply->locations());
+ setError(NoError, QString());
+ setStatus(QDeclarativeGeocodeModel::Ready);
+ reply->deleteLater();
+ reply_ = 0;
+ emit locationsChanged();
+ if (oldCount != declarativeLocations_.count())
+ emit countChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::geocodeError(QGeoCodeReply *reply,
+ QGeoCodeReply::Error error,
+ const QString &errorString)
+{
+ if (reply != reply_)
+ return;
+ Q_UNUSED(error);
+ int oldCount = declarativeLocations_.count();
+ if (oldCount > 0) {
+ // Reset the model
+ setLocations(reply->locations());
+ emit locationsChanged();
+ emit countChanged();
+ }
+ setError(static_cast<QDeclarativeGeocodeModel::GeocodeError>(error), errorString);
+ setStatus(QDeclarativeGeocodeModel::Error);
+ reply->deleteLater();
+ reply_ = 0;
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::GeocodeModel::status
+
+ This read-only property holds the current status of the model.
+
+ \list
+ \li GeocodeModel.Null - No geocode requests have been issued or \l reset has been called.
+ \li GeocodeModel.Ready - Geocode request(s) have finished successfully.
+ \li GeocodeModel.Loading - Geocode request has been issued but not yet finished
+ \li GeocodeModel.Error - Geocoding error has occurred, details are in \l error and \l errorString
+ \endlist
+*/
+
+QDeclarativeGeocodeModel::Status QDeclarativeGeocodeModel::status() const
+{
+ return status_;
+}
+
+void QDeclarativeGeocodeModel::setStatus(QDeclarativeGeocodeModel::Status status)
+{
+ if (status_ == status)
+ return;
+ status_ = status;
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::GeocodeModel::error
+
+ This read-only property holds the latest error value of the geocoding request.
+
+ \list
+ \li GeocodeModel.NoError - No error has occurred.
+ \li GeocodeModel.CombinationError - An error occurred while results where being combined from multiple sources.
+ \li GeocodeModel.CommunicationError - An error occurred while communicating with the service provider.
+ \li GeocodeModel.EngineNotSetError - The model's plugin property was not set or there is no geocoding manager associated with the plugin.
+ \li GeocodeModel.MissingRequiredParameterError - A required parameter was not specified.
+ \li GeocodeModel.ParseError - The response from the service provider was in an unrecognizable format.
+ \li GeocodeModel.UnknownError - An error occurred which does not fit into any of the other categories.
+ \li GeocodeModel.UnknownParameterError - The plugin did not recognize one of the parameters it was given.
+ \li GeocodeModel.UnsupportedOptionError - The requested operation is not supported by the geocoding provider.
+ This may happen when the loaded engine does not support a particular geocoding request
+ such as reverse geocoding.
+ \endlist
+*/
+
+QDeclarativeGeocodeModel::GeocodeError QDeclarativeGeocodeModel::error() const
+{
+ return error_;
+}
+
+void QDeclarativeGeocodeModel::setError(GeocodeError error, const QString &errorString)
+{
+ if (error_ == error && errorString_ == errorString)
+ return;
+ error_ = error;
+ errorString_ = errorString;
+ emit errorChanged();
+}
+
+/*!
+ \qmlproperty string QtLocation::GeocodeModel::errorString
+
+ This read-only property holds the textual presentation of the latest geocoding error.
+ If no error has occurred or the model has been reset, an empty string is returned.
+
+ An empty string may also be returned if an error occurred which has no associated
+ textual representation.
+*/
+
+QString QDeclarativeGeocodeModel::errorString() const
+{
+ return errorString_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::setLocations(const QList<QGeoLocation> &locations)
+{
+ beginResetModel();
+ qDeleteAll(declarativeLocations_);
+ declarativeLocations_.clear();
+ for (int i = 0; i < locations.count(); ++i) {
+ QDeclarativeGeoLocation *location = new QDeclarativeGeoLocation(locations.at(i), this);
+ declarativeLocations_.append(location);
+ }
+ endResetModel();
+}
+
+/*!
+ \qmlproperty int QtLocation::GeocodeModel::count
+
+ This property holds how many locations the model currently has.
+ Amongst other uses, you can use this value when accessing locations
+ via the GeocodeModel::get -method.
+*/
+
+int QDeclarativeGeocodeModel::count() const
+{
+ return declarativeLocations_.count();
+}
+
+/*!
+ \qmlmethod Location QtLocation::GeocodeModel::get(int)
+
+ Returns the Location at given index. Use \l count property to check the
+ amount of locations available. The locations are indexed from zero, so the accessible range
+ is 0...(count - 1).
+
+ If you access out of bounds, a zero (null object) is returned and a warning is issued.
+*/
+
+QDeclarativeGeoLocation *QDeclarativeGeocodeModel::get(int index)
+{
+ if (index < 0 || index >= declarativeLocations_.count()) {
+ qmlWarning(this) << QStringLiteral("Index '%1' out of range").arg(index);
+ return 0;
+ }
+ return declarativeLocations_.at(index);
+}
+
+/*!
+ \qmlproperty int QtLocation::GeocodeModel::limit
+
+ This property holds the maximum number of results. The limit and \l offset values are only
+ applicable with free string geocoding (that is they are not considered when using addresses
+ or coordinates in the search query).
+
+ If limit is -1 the entire result set will be returned, otherwise at most limit results will be
+ returned. The limit and \l offset results can be used together to implement paging.
+*/
+
+int QDeclarativeGeocodeModel::limit() const
+{
+ return limit_;
+}
+
+void QDeclarativeGeocodeModel::setLimit(int limit)
+{
+ if (limit == limit_)
+ return;
+ limit_ = limit;
+ if (autoUpdate_) {
+ update();
+ }
+ emit limitChanged();
+}
+
+/*!
+ \qmlproperty int QtLocation::GeocodeModel::offset
+
+ This property tells not to return the first 'offset' number of the results. The \l limit and
+ offset values are only applicable with free string geocoding (that is they are not considered
+ when using addresses or coordinates in the search query).
+
+ The \l limit and offset results can be used together to implement paging.
+*/
+
+int QDeclarativeGeocodeModel::offset() const
+{
+ return offset_;
+}
+
+void QDeclarativeGeocodeModel::setOffset(int offset)
+{
+ if (offset == offset_)
+ return;
+ offset_ = offset;
+ if (autoUpdate_) {
+ update();
+ }
+ emit offsetChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::GeocodeModel::reset()
+
+ Resets the model. All location data is cleared, any outstanding requests
+ are aborted and possible errors are cleared. Model status will be set
+ to GeocodeModel.Null
+*/
+
+void QDeclarativeGeocodeModel::reset()
+{
+ beginResetModel();
+ if (!declarativeLocations_.isEmpty()) {
+ setLocations(QList<QGeoLocation>());
+ emit countChanged();
+ }
+ endResetModel();
+
+ abortRequest();
+ setError(NoError, QString());
+ setStatus(QDeclarativeGeocodeModel::Null);
+}
+
+/*!
+ \qmlmethod void QtLocation::GeocodeModel::cancel()
+
+ Cancels any outstanding requests and clears errors. Model status will be set to either
+ GeocodeModel.Null or GeocodeModel.Ready.
+*/
+void QDeclarativeGeocodeModel::cancel()
+{
+ abortRequest();
+ setError(NoError, QString());
+ setStatus(declarativeLocations_.isEmpty() ? Null : Ready);
+}
+
+/*!
+ \qmlproperty QVariant QtLocation::GeocodeModel::query
+
+ This property holds the data of the geocoding request.
+ The property accepts three types of queries which determine both the data and
+ the type of action to be performed:
+
+ \list
+ \li Address - Geocoding (address to coordinate)
+ \li \l {coordinate} - Reverse geocoding (coordinate to address)
+ \li string - Geocoding (address to coordinate)
+ \endlist
+*/
+
+QVariant QDeclarativeGeocodeModel::query() const
+{
+ return queryVariant_;
+}
+
+void QDeclarativeGeocodeModel::setQuery(const QVariant &query)
+{
+ if (query == queryVariant_)
+ return;
+
+ if (query.userType() == qMetaTypeId<QGeoCoordinate>()) {
+ if (address_) {
+ address_->disconnect(this);
+ address_ = 0;
+ }
+ searchString_.clear();
+
+ coordinate_ = query.value<QGeoCoordinate>();
+ } else if (query.type() == QVariant::String) {
+ searchString_ = query.toString();
+ if (address_) {
+ address_->disconnect(this);
+ address_ = 0;
+ }
+ coordinate_ = QGeoCoordinate();
+ } else if (QObject *object = query.value<QObject *>()) {
+ if (QDeclarativeGeoAddress *address = qobject_cast<QDeclarativeGeoAddress *>(object)) {
+ if (address_)
+ address_->disconnect(this);
+ coordinate_ = QGeoCoordinate();
+ searchString_.clear();
+
+ address_ = address;
+ connect(address_, SIGNAL(countryChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(countryCodeChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(stateChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(countyChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(cityChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(districtChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(streetChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(postalCodeChanged()), this, SLOT(queryContentChanged()));
+ } else {
+ qmlWarning(this) << QStringLiteral("Unsupported query type for geocode model ")
+ << QStringLiteral("(coordinate, string and Address supported).");
+ return;
+ }
+ } else {
+ qmlWarning(this) << QStringLiteral("Unsupported query type for geocode model ")
+ << QStringLiteral("(coordinate, string and Address supported).");
+ return;
+ }
+
+ queryVariant_ = query;
+ emit queryChanged();
+ if (autoUpdate_)
+ update();
+}
+
+/*!
+ \qmlproperty bool QtLocation::GeocodeModel::autoUpdate
+
+ This property controls whether the Model automatically updates in response
+ to changes in its attached query. The default value of this property
+ is false.
+
+ If setting this value to 'true' and using an Address or
+ \l {coordinate} as the query, note that any change at all in the
+ object's properties will trigger a new request to be sent. If you are adjusting many
+ properties of the object whilst autoUpdate is enabled, this can generate large numbers of
+ useless (and later discarded) requests.
+*/
+
+bool QDeclarativeGeocodeModel::autoUpdate() const
+{
+ return autoUpdate_;
+}
+
+void QDeclarativeGeocodeModel::setAutoUpdate(bool update)
+{
+ if (autoUpdate_ == update)
+ return;
+ autoUpdate_ = update;
+ emit autoUpdateChanged();
+}
+
+#include "moc_qdeclarativegeocodemodel_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeocodemodel_p.h b/src/location/declarativemaps/qdeclarativegeocodemodel_p.h
new file mode 100644
index 00000000..6c8f533b
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeocodemodel_p.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOCODEMODEL_H
+#define QDECLARATIVEGEOCODEMODEL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
+
+#include <QtLocation/qgeocodereply.h>
+#include <QtPositioning/private/qdeclarativegeoaddress_p.h>
+#include <QtPositioning/private/qdeclarativegeolocation_p.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlParserStatus>
+#include <QAbstractListModel>
+#include <QPointer>
+
+
+QT_BEGIN_NAMESPACE
+
+class QGeoServiceProvider;
+class QGeoCodingManager;
+class QDeclarativeGeoLocation;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeocodeModel : public QAbstractListModel, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+ Q_ENUMS(GeocodeError)
+
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(bool autoUpdate READ autoUpdate WRITE setAutoUpdate NOTIFY autoUpdateChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged)
+ Q_PROPERTY(int offset READ offset WRITE setOffset NOTIFY offsetChanged)
+ Q_PROPERTY(QVariant query READ query WRITE setQuery NOTIFY queryChanged)
+ Q_PROPERTY(QVariant bounds READ bounds WRITE setBounds NOTIFY boundsChanged)
+ Q_PROPERTY(GeocodeError error READ error NOTIFY errorChanged)
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ enum Status {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ enum GeocodeError {
+ NoError = QGeoCodeReply::NoError,
+ EngineNotSetError = QGeoCodeReply::EngineNotSetError, //TODO Qt6 consider merge with NotSupportedError
+ CommunicationError = QGeoCodeReply::CommunicationError, //TODO Qt6 merge with Map's ConnectionError
+ ParseError = QGeoCodeReply::ParseError,
+ UnsupportedOptionError = QGeoCodeReply::UnsupportedOptionError, //TODO Qt6 consider rename UnsupportedOperationError
+ CombinationError = QGeoCodeReply::CombinationError,
+ UnknownError = QGeoCodeReply::UnknownError,
+ //we leave gap for future QGeoCodeReply errors
+
+ //QGeoServiceProvider related errors start here
+ UnknownParameterError = 100,
+ MissingRequiredParameterError
+ };
+
+ enum Roles {
+ LocationRole = Qt::UserRole + 1
+ };
+
+ explicit QDeclarativeGeocodeModel(QObject *parent = 0);
+ virtual ~QDeclarativeGeocodeModel();
+
+ // From QQmlParserStatus
+ virtual void classBegin() {}
+ virtual void componentComplete();
+
+ // From QAbstractListModel
+ virtual int rowCount(const QModelIndex &parent) const;
+ virtual QVariant data(const QModelIndex &index, int role) const;
+ virtual QHash<int,QByteArray> roleNames() const;
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ void setBounds(const QVariant &boundingArea);
+ QVariant bounds() const;
+
+ Status status() const;
+ QString errorString() const;
+ GeocodeError error() const;
+
+ bool autoUpdate() const;
+ void setAutoUpdate(bool update);
+
+ int count() const;
+ Q_INVOKABLE QDeclarativeGeoLocation *get(int index);
+
+ int limit() const;
+ void setLimit(int limit);
+ int offset() const;
+ void setOffset(int offset);
+
+ QVariant query() const;
+ void setQuery(const QVariant &query);
+ Q_INVOKABLE void reset();
+ Q_INVOKABLE void cancel();
+
+Q_SIGNALS:
+ void countChanged();
+ void pluginChanged();
+ void statusChanged();
+ void errorChanged(); //emitted also for errorString notification
+ void locationsChanged();
+ void autoUpdateChanged();
+ void boundsChanged();
+ void queryChanged();
+ void limitChanged();
+ void offsetChanged();
+
+public Q_SLOTS:
+ void update();
+
+protected Q_SLOTS:
+ void queryContentChanged();
+ void geocodeFinished(QGeoCodeReply *reply);
+ void geocodeError(QGeoCodeReply *reply,
+ QGeoCodeReply::Error error,
+ const QString &errorString);
+ void pluginReady();
+
+protected:
+ QGeoCodingManager *searchManager();
+ void setStatus(Status status);
+ void setError(GeocodeError error, const QString &errorString);
+ bool autoUpdate_;
+ bool complete_;
+
+private:
+ void setLocations(const QList<QGeoLocation> &locations);
+ void abortRequest();
+ QGeoCodeReply *reply_;
+
+ QDeclarativeGeoServiceProvider *plugin_;
+ QGeoShape boundingArea_;
+
+ QList<QDeclarativeGeoLocation *> declarativeLocations_;
+
+ Status status_;
+ QString errorString_;
+ GeocodeError error_;
+ QVariant queryVariant_;
+ QGeoCoordinate coordinate_;
+ QDeclarativeGeoAddress *address_;
+ QString searchString_;
+
+ int limit_;
+ int offset_;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomaneuver.cpp b/src/location/declarativemaps/qdeclarativegeomaneuver.cpp
new file mode 100644
index 00000000..72c38865
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaneuver.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeomaneuver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RouteManeuver
+ \instantiates QDeclarativeGeoManeuver
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The RouteManeuver type represents the information relevant to the
+ point at which two RouteSegments meet.
+
+ RouteSegment instances can be thought of as edges on a routing
+ graph, with RouteManeuver instances as optional labels attached to the
+ vertices of the graph.
+
+ The most interesting information held in a RouteManeuver instance is
+ normally the textual navigation to provide and the position at which to
+ provide it, accessible by \l instructionText and \l position respectively.
+
+ \section1 Example
+
+ The following QML snippet demonstrates how to print information about a
+ route maneuver:
+
+ \snippet declarative/routing.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/routing.qml RouteManeuver
+*/
+
+QDeclarativeGeoManeuver::QDeclarativeGeoManeuver(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QDeclarativeGeoManeuver::QDeclarativeGeoManeuver(const QGeoManeuver &maneuver, QObject *parent)
+ : QObject(parent),
+ maneuver_(maneuver)
+{
+}
+
+QDeclarativeGeoManeuver::~QDeclarativeGeoManeuver() {}
+
+/*!
+ \qmlproperty bool RouteManeuver::valid
+
+ This read-only property holds whether this maneuver is valid or not.
+
+ Invalid maneuvers are used when there is no information
+ that needs to be attached to the endpoint of a QGeoRouteSegment instance.
+*/
+
+bool QDeclarativeGeoManeuver::valid() const
+{
+ return maneuver_.isValid();
+}
+
+/*!
+ \qmlproperty coordinate RouteManeuver::position
+
+ This read-only property holds where the \l instructionText should be displayed.
+
+*/
+
+QGeoCoordinate QDeclarativeGeoManeuver::position() const
+{
+ return maneuver_.position();
+}
+
+/*!
+ \qmlproperty string RouteManeuver::instructionText
+
+ This read-only property holds textual navigation instruction.
+*/
+
+QString QDeclarativeGeoManeuver::instructionText() const
+{
+ return maneuver_.instructionText();
+}
+
+/*!
+ \qmlproperty enumeration RouteManeuver::direction
+
+ Describes the change in direction associated with the instruction text
+ that is associated with a RouteManeuver.
+
+ \list
+ \li RouteManeuver.NoDirection - There is no direction associated with the instruction text
+ \li RouteManeuver.DirectionForward - The instruction indicates that the direction of travel does not need to change
+ \li RouteManeuver.DirectionBearRight - The instruction indicates that the direction of travel should bear to the right
+ \li RouteManeuver.DirectionLightRight - The instruction indicates that a light turn to the right is required
+ \li RouteManeuver.DirectionRight - The instruction indicates that a turn to the right is required
+ \li RouteManeuver.DirectionHardRight - The instruction indicates that a hard turn to the right is required
+ \li RouteManeuver.DirectionUTurnRight - The instruction indicates that a u-turn to the right is required
+ \li RouteManeuver.DirectionUTurnLeft - The instruction indicates that a u-turn to the left is required
+ \li RouteManeuver.DirectionHardLeft - The instruction indicates that a hard turn to the left is required
+ \li RouteManeuver.DirectionLeft - The instruction indicates that a turn to the left is required
+ \li RouteManeuver.DirectionLightLeft - The instruction indicates that a light turn to the left is required
+ \li RouteManeuver.DirectionBearLeft - The instruction indicates that the direction of travel should bear to the left
+ \endlist
+*/
+
+QDeclarativeGeoManeuver::Direction QDeclarativeGeoManeuver::direction() const
+{
+ return QDeclarativeGeoManeuver::Direction(maneuver_.direction());
+}
+
+/*!
+ \qmlproperty int RouteManeuver::timeToNextInstruction
+
+ This read-only property holds the estimated time it will take to travel
+ from the point at which the associated instruction was issued and the
+ point that the next instruction should be issued, in seconds.
+*/
+
+int QDeclarativeGeoManeuver::timeToNextInstruction() const
+{
+ return maneuver_.timeToNextInstruction();
+}
+
+/*!
+ \qmlproperty real RouteManeuver::distanceToNextInstruction
+
+ This read-only property holds the distance, in meters, between the point at which
+ the associated instruction was issued and the point that the next instruction should
+ be issued.
+*/
+
+qreal QDeclarativeGeoManeuver::distanceToNextInstruction() const
+{
+ return maneuver_.distanceToNextInstruction();
+}
+
+/*!
+ \qmlproperty coordinate RouteManeuver::waypoint
+
+ This property holds the waypoint associated with this maneuver.
+ All maneuvers do not have a waypoint associated with them, this
+ can be checked with \l waypointValid.
+
+*/
+
+QGeoCoordinate QDeclarativeGeoManeuver::waypoint() const
+{
+ return maneuver_.waypoint();
+}
+
+/*!
+ \qmlproperty bool RouteManeuver::waypointValid
+
+ This read-only property holds whether this \l waypoint, associated with this
+ maneuver, is valid or not.
+*/
+
+bool QDeclarativeGeoManeuver::waypointValid() const
+{
+ return maneuver_.waypoint().isValid();
+}
+
+#include "moc_qdeclarativegeomaneuver_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomaneuver_p.h b/src/location/declarativemaps/qdeclarativegeomaneuver_p.h
new file mode 100644
index 00000000..0e957a1f
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaneuver_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMANEUVER_H
+#define QDECLARATIVEGEOMANEUVER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/qgeomaneuver.h>
+
+#include <QtPositioning/QGeoCoordinate>
+
+#include <QObject>
+
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoManeuver : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(Direction)
+
+ Q_PROPERTY(bool valid READ valid CONSTANT)
+ Q_PROPERTY(QGeoCoordinate position READ position CONSTANT)
+ Q_PROPERTY(QString instructionText READ instructionText CONSTANT)
+ Q_PROPERTY(Direction direction READ direction CONSTANT)
+ Q_PROPERTY(int timeToNextInstruction READ timeToNextInstruction CONSTANT)
+ Q_PROPERTY(qreal distanceToNextInstruction READ distanceToNextInstruction CONSTANT)
+ Q_PROPERTY(QGeoCoordinate waypoint READ waypoint CONSTANT)
+ Q_PROPERTY(bool waypointValid READ waypointValid CONSTANT)
+
+public:
+ enum Direction {
+ NoDirection = QGeoManeuver::NoDirection,
+ DirectionForward = QGeoManeuver::DirectionForward,
+ DirectionBearRight = QGeoManeuver::DirectionBearRight,
+ DirectionLightRight = QGeoManeuver::DirectionLightRight,
+ DirectionRight = QGeoManeuver::DirectionRight,
+ DirectionHardRight = QGeoManeuver::DirectionHardRight,
+ DirectionUTurnRight = QGeoManeuver::DirectionUTurnRight,
+ DirectionUTurnLeft = QGeoManeuver::DirectionUTurnLeft,
+ DirectionHardLeft = QGeoManeuver::DirectionHardLeft,
+ DirectionLeft = QGeoManeuver::DirectionLeft,
+ DirectionLightLeft = QGeoManeuver::DirectionLightLeft,
+ DirectionBearLeft = QGeoManeuver::DirectionBearLeft
+ };
+
+ explicit QDeclarativeGeoManeuver(QObject *parent = 0);
+ QDeclarativeGeoManeuver(const QGeoManeuver &maneuver, QObject *parent = 0);
+ ~QDeclarativeGeoManeuver();
+
+ bool valid() const;
+ bool waypointValid() const;
+
+ QGeoCoordinate position() const;
+ QString instructionText() const;
+ Direction direction() const;
+ int timeToNextInstruction() const;
+ qreal distanceToNextInstruction() const;
+ QGeoCoordinate waypoint() const;
+
+private:
+ QGeoManeuver maneuver_;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp
new file mode 100644
index 00000000..15d802e6
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomap.cpp
@@ -0,0 +1,1822 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeomap_p.h"
+#include "qdeclarativegeomapquickitem_p.h"
+#include "qdeclarativegeomapcopyrightsnotice_p.h"
+#include "qdeclarativegeoserviceprovider_p.h"
+#include "qdeclarativegeomaptype_p.h"
+#include "qgeomappingmanager_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qgeomap_p.h"
+#include "qdeclarativegeomapparameter_p.h"
+#include <QtPositioning/QGeoCircle>
+#include <QtPositioning/QGeoRectangle>
+#include <QtQuick/QQuickWindow>
+#include <QtQuick/QSGRectangleNode>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQml/qqmlinfo.h>
+#include <cmath>
+
+#ifndef M_PI
+#define M_PI 3.141592653589793238463
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Map
+ \instantiates QDeclarativeGeoMap
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+
+ \brief The Map type displays a map.
+
+ The Map type is used to display a map or image of the Earth, with
+ the capability to also display interactive objects tied to the map's
+ surface.
+
+ There are a variety of different ways to visualize the Earth's surface
+ in a 2-dimensional manner, but all of them involve some kind of projection:
+ a mathematical relationship between the 3D coordinates (latitude, longitude
+ and altitude) and 2D coordinates (X and Y in pixels) on the screen.
+
+ Different sources of map data can use different projections, and from the
+ point of view of the Map type, we treat these as one replaceable unit:
+ the Map plugin. A Map plugin consists of a data source, as well as all other
+ details needed to display its data on-screen.
+
+ The current Map plugin in use is contained in the \l plugin property of
+ the Map item. In order to display any image in a Map item, you will need
+ to set this property. See the \l Plugin type for a description of how
+ to retrieve an appropriate plugin for use.
+
+ The geographic region displayed in the Map item is referred to as its
+ viewport, and this is defined by the properties \l center, and
+ \l zoomLevel. The \l center property contains a \l {coordinate}
+ specifying the center of the viewport, while \l zoomLevel controls the scale of the
+ map. See each of these properties for further details about their values.
+
+ When the map is displayed, each possible geographic coordinate that is
+ visible will map to some pixel X and Y coordinate on the screen. To perform
+ conversions between these two, Map provides the \l toCoordinate and
+ \l fromCoordinate functions, which are of general utility.
+
+ \section2 Map Objects
+
+ Map related objects can be declared within the body of a Map object in Qt Quick and will
+ automatically appear on the Map. To add objects programmatically, first be
+ sure they are created with the Map as their parent (for example in an argument to
+ Component::createObject), and then call the \l addMapItem method on the Map.
+ A corresponding \l removeMapItem method also exists to do the opposite and
+ remove an object from the Map.
+
+ Moving Map objects around, resizing them or changing their shape normally
+ does not involve any special interaction with Map itself -- changing these
+ details about a map object will automatically update the display.
+
+ \section2 Interaction
+
+ The Map type includes support for pinch and flick gestures to control
+ zooming and panning. These are enabled by default, and available at any
+ time by using the \l gesture object. The actual GestureArea is constructed
+ specially at startup and cannot be replaced or destroyed. Its properties
+ can be altered, however, to control its behavior.
+
+ \section2 Performance
+
+ Maps are rendered using OpenGL (ES) and the Qt Scene Graph stack, and as
+ a result perform quite well where GL accelerated hardware is available.
+
+ For "online" Map plugins, network bandwidth and latency can be major
+ contributors to the user's perception of performance. Extensive caching is
+ performed to mitigate this, but such mitigation is not always perfect. For
+ "offline" plugins, the time spent retrieving the stored geographic data
+ and rendering the basic map features can often play a dominant role. Some
+ offline plugins may use hardware acceleration themselves to (partially)
+ avert this.
+
+ In general, large and complex Map items such as polygons and polylines with
+ large numbers of vertices can have an adverse effect on UI performance.
+ Further, more detailed notes on this are in the documentation for each
+ map item type.
+
+ \section2 Example Usage
+
+ The following snippet shows a simple Map and the necessary Plugin type
+ to use it. The map is centered over Oslo, Norway, with zoom level 10.
+
+ \quotefromfile minimal_map/main.qml
+ \skipto import
+ \printuntil }
+ \printline }
+ \skipto Map
+ \printuntil }
+ \printline }
+
+ \image minimal_map.png
+*/
+
+/*!
+ \qmlsignal QtLocation::Map::copyrightLinkActivated(string link)
+
+ This signal is emitted when the user clicks on a \a link in the copyright notice. The
+ application should open the link in a browser or display its contents to the user.
+*/
+
+static const qreal EARTH_MEAN_RADIUS = 6371007.2;
+
+QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent)
+ : QQuickItem(parent),
+ m_plugin(0),
+ m_mappingManager(0),
+ m_activeMapType(0),
+ m_gestureArea(new QQuickGeoMapGestureArea(this)),
+ m_map(0),
+ m_error(QGeoServiceProvider::NoError),
+ m_color(QColor::fromRgbF(0.9, 0.9, 0.9)),
+ m_componentCompleted(false),
+ m_pendingFitViewport(false),
+ m_copyrightsVisible(true),
+ m_maximumViewportLatitude(0.0),
+ m_initialized(false)
+{
+ setAcceptHoverEvents(false);
+ setAcceptedMouseButtons(Qt::LeftButton);
+ setFlags(QQuickItem::ItemHasContents | QQuickItem::ItemClipsChildrenToShape);
+ setFiltersChildMouseEvents(true);
+
+ connect(this, SIGNAL(childrenChanged()), this, SLOT(onMapChildrenChanged()), Qt::QueuedConnection);
+
+ m_activeMapType = new QDeclarativeGeoMapType(QGeoMapType(QGeoMapType::NoMap,
+ tr("No Map"),
+ tr("No Map"), false, false, 0), this);
+ m_cameraData.setCenter(QGeoCoordinate(51.5073,-0.1277)); //London city center
+ m_cameraData.setZoomLevel(8.0);
+}
+
+QDeclarativeGeoMap::~QDeclarativeGeoMap()
+{
+ if (!m_mapViews.isEmpty())
+ qDeleteAll(m_mapViews);
+ // remove any map items associations
+ for (int i = 0; i < m_mapItems.count(); ++i) {
+ if (m_mapItems.at(i))
+ m_mapItems.at(i).data()->setMap(0,0);
+ }
+ m_mapItems.clear();
+
+ delete m_copyrights.data();
+ m_copyrights.clear();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::onMapChildrenChanged()
+{
+ if (!m_componentCompleted || !m_map)
+ return;
+
+ int maxChildZ = 0;
+ QObjectList kids = children();
+ bool foundCopyrights = false;
+
+ for (int i = 0; i < kids.size(); ++i) {
+ QDeclarativeGeoMapCopyrightNotice *copyrights = qobject_cast<QDeclarativeGeoMapCopyrightNotice *>(kids.at(i));
+ if (copyrights) {
+ foundCopyrights = true;
+ } else {
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(kids.at(i));
+ if (mapItem) {
+ if (mapItem->z() > maxChildZ)
+ maxChildZ = mapItem->z();
+ }
+ }
+ }
+
+ QDeclarativeGeoMapCopyrightNotice *copyrights = m_copyrights.data();
+ // if copyrights object not found within the map's children
+ if (!foundCopyrights) {
+ // if copyrights object was deleted!
+ if (!copyrights) {
+ // create a new one and set its parent, re-assign it to the weak pointer, then connect the copyrights-change signal
+ m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this);
+ copyrights = m_copyrights.data();
+ connect(m_map, SIGNAL(copyrightsChanged(QImage)),
+ copyrights, SLOT(copyrightsChanged(QImage)));
+ connect(m_map, SIGNAL(copyrightsChanged(QString)),
+ copyrights, SLOT(copyrightsChanged(QString)));
+ connect(copyrights, SIGNAL(linkActivated(QString)),
+ this, SIGNAL(copyrightLinkActivated(QString)));
+
+ // set visibility of copyright notice
+ copyrights->setCopyrightsVisible(m_copyrightsVisible);
+
+ } else {
+ // just re-set its parent.
+ copyrights->setParent(this);
+ }
+ }
+
+ // put the copyrights notice object at the highest z order
+ copyrights->setCopyrightsZ(maxChildZ + 1);
+}
+
+static QDeclarativeGeoMapType *findMapType(const QList<QDeclarativeGeoMapType *> &types, const QGeoMapType &type)
+{
+ for (int i = 0; i < types.size(); ++i)
+ if (types[i]->mapType() == type)
+ return types[i];
+ return Q_NULLPTR;
+}
+
+void QDeclarativeGeoMap::onSupportedMapTypesChanged()
+{
+ QList<QDeclarativeGeoMapType *> supportedMapTypes;
+ QList<QGeoMapType> types = m_mappingManager->supportedMapTypes();
+ for (int i = 0; i < types.size(); ++i) {
+ // types that are present and get removed will be deleted at QObject destruction
+ QDeclarativeGeoMapType *type = findMapType(m_supportedMapTypes, types[i]);
+ if (!type)
+ type = new QDeclarativeGeoMapType(types[i], this);
+ supportedMapTypes.append(type);
+ }
+ m_supportedMapTypes.swap(supportedMapTypes);
+ if (m_supportedMapTypes.isEmpty()) {
+ m_map->setActiveMapType(QGeoMapType()); // no supported map types: setting an invalid one
+ } else {
+ bool hasMapType = false;
+ foreach (QDeclarativeGeoMapType *declarativeType, m_supportedMapTypes) {
+ if (declarativeType->mapType() == m_map->activeMapType())
+ hasMapType = true;
+ }
+ if (!hasMapType) {
+ QDeclarativeGeoMapType *type = m_supportedMapTypes.at(0);
+ m_activeMapType = type;
+ m_map->setActiveMapType(type->mapType());
+ }
+ }
+
+ emit supportedMapTypesChanged();
+}
+
+void QDeclarativeGeoMap::setError(QGeoServiceProvider::Error error, const QString &errorString)
+{
+ if (m_error == error && m_errorString == errorString)
+ return;
+ m_error = error;
+ m_errorString = errorString;
+ emit errorChanged();
+}
+
+void QDeclarativeGeoMap::initialize()
+{
+ // try to keep change signals in the end
+ bool centerHasChanged = false;
+ bool bearingHasChanged = false;
+ bool tiltHasChanged = false;
+ bool fovHasChanged = false;
+ bool minTiltHasChanged = false;
+ bool maxTiltHasChanged = false;
+ bool minFovHasChanged = false;
+ bool maxFovHasChanged = false;
+
+ QGeoCoordinate center = m_cameraData.center();
+
+ setMinimumZoomLevel(m_map->minimumZoom());
+
+ double bearing = m_cameraData.bearing();
+ double tilt = m_cameraData.tilt();
+ double fov = m_cameraData.fieldOfView(); // Must be 45.0
+ if (m_map->cameraCapabilities().minimumFieldOfView() != 1)
+ minFovHasChanged = true;
+ if (m_map->cameraCapabilities().maximumFieldOfView() != 179)
+ maxFovHasChanged = true;
+ if (m_map->cameraCapabilities().minimumTilt() != 0)
+ minTiltHasChanged = true;
+ if (m_map->cameraCapabilities().maximumTilt() != 89)
+ maxTiltHasChanged = true;
+ if (!m_map->cameraCapabilities().supportsBearing() && bearing != 0.0) {
+ m_cameraData.setBearing(0);
+ bearingHasChanged = true;
+ }
+ if (!m_map->cameraCapabilities().supportsTilting() && tilt != 0.0) {
+ m_cameraData.setTilt(0);
+ tiltHasChanged = true;
+ }
+
+ m_cameraData.setFieldOfView(qBound(m_map->cameraCapabilities().minimumFieldOfView(),
+ fov,
+ m_map->cameraCapabilities().maximumFieldOfView()));
+ if (fov != m_cameraData.fieldOfView())
+ fovHasChanged = true;
+
+ // set latitude boundary check
+ m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
+
+ center.setLatitude(qBound(-m_maximumViewportLatitude, center.latitude(), m_maximumViewportLatitude));
+
+ if (center != m_cameraData.center()) {
+ centerHasChanged = true;
+ m_cameraData.setCenter(center);
+ }
+
+ m_map->setCameraData(m_cameraData);
+
+ m_initialized = true;
+
+ if (centerHasChanged)
+ emit centerChanged(m_cameraData.center());
+
+ if (bearingHasChanged)
+ emit bearingChanged(m_cameraData.bearing());
+
+ if (tiltHasChanged)
+ emit tiltChanged(m_cameraData.tilt());
+
+ if (fovHasChanged)
+ emit fieldOfViewChanged(m_cameraData.fieldOfView());
+
+ if (minTiltHasChanged)
+ emit minimumTiltChanged(m_map->cameraCapabilities().minimumTilt());
+
+ if (maxTiltHasChanged)
+ emit maximumTiltChanged(m_map->cameraCapabilities().maximumTilt());
+
+ if (minFovHasChanged)
+ emit minimumFieldOfViewChanged(m_map->cameraCapabilities().minimumFieldOfView());
+
+ if (maxFovHasChanged)
+ emit maximumFieldOfViewChanged(m_map->cameraCapabilities().maximumFieldOfView());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::pluginReady()
+{
+ QGeoServiceProvider *provider = m_plugin->sharedGeoServiceProvider();
+ m_mappingManager = provider->mappingManager();
+
+ if (provider->error() != QGeoServiceProvider::NoError) {
+ setError(provider->error(), provider->errorString());
+ return;
+ }
+
+ if (!m_mappingManager) {
+ //TODO Should really be EngineNotSetError (see QML GeoCodeModel)
+ setError(QGeoServiceProvider::NotSupportedError, tr("Plugin does not support mapping."));
+ return;
+ }
+
+ if (!m_mappingManager->isInitialized())
+ connect(m_mappingManager, SIGNAL(initialized()), this, SLOT(mappingManagerInitialized()));
+ else
+ mappingManagerInitialized();
+
+ // make sure this is only called once
+ disconnect(this, SLOT(pluginReady()));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::componentComplete()
+{
+ m_componentCompleted = true;
+ populateParameters();
+ populateMap();
+ QQuickItem::componentComplete();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::mousePressEvent(QMouseEvent *event)
+{
+ if (isInteractive())
+ m_gestureArea->handleMousePressEvent(event);
+ else
+ QQuickItem::mousePressEvent(event);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::mouseMoveEvent(QMouseEvent *event)
+{
+ if (isInteractive())
+ m_gestureArea->handleMouseMoveEvent(event);
+ else
+ QQuickItem::mouseMoveEvent(event);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (isInteractive()) {
+ m_gestureArea->handleMouseReleaseEvent(event);
+ } else {
+ QQuickItem::mouseReleaseEvent(event);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::mouseUngrabEvent()
+{
+ if (isInteractive())
+ m_gestureArea->handleMouseUngrabEvent();
+ else
+ QQuickItem::mouseUngrabEvent();
+}
+
+void QDeclarativeGeoMap::touchUngrabEvent()
+{
+ if (isInteractive())
+ m_gestureArea->handleTouchUngrabEvent();
+ else
+ QQuickItem::touchUngrabEvent();
+}
+
+/*!
+ \qmlproperty MapGestureArea QtLocation::Map::gesture
+
+ Contains the MapGestureArea created with the Map. This covers pan, flick and pinch gestures.
+ Use \c{gesture.enabled: true} to enable basic gestures, or see \l{MapGestureArea} for
+ further details.
+*/
+
+QQuickGeoMapGestureArea *QDeclarativeGeoMap::gesture()
+{
+ return m_gestureArea;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::populateMap()
+{
+ QObjectList kids = children();
+ QList<QQuickItem *> quickKids = childItems();
+ for (int i=0; i < quickKids.count(); ++i)
+ kids.append(quickKids.at(i));
+
+ for (int i = 0; i < kids.size(); ++i) {
+ // dispatch items appropriately
+ QDeclarativeGeoMapItemView *mapView = qobject_cast<QDeclarativeGeoMapItemView *>(kids.at(i));
+ if (mapView) {
+ m_mapViews.append(mapView);
+ setupMapView(mapView);
+ continue;
+ }
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(kids.at(i));
+ if (mapItem) {
+ addMapItem(mapItem);
+ }
+ }
+}
+
+void QDeclarativeGeoMap::populateParameters()
+{
+ QObjectList kids = children();
+ QList<QQuickItem *> quickKids = childItems();
+ for (int i = 0; i < quickKids.count(); ++i)
+ kids.append(quickKids.at(i));
+ for (int i = 0; i < kids.size(); ++i) {
+ QDeclarativeGeoMapParameter *mapParameter = qobject_cast<QDeclarativeGeoMapParameter *>(kids.at(i));
+ if (mapParameter)
+ addMapParameter(mapParameter);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::setupMapView(QDeclarativeGeoMapItemView *view)
+{
+ Q_UNUSED(view)
+ view->setMap(this);
+ view->repopulate();
+}
+
+/*!
+ * \internal
+ */
+QSGNode *QDeclarativeGeoMap::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ if (!m_map) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGRectangleNode *root = static_cast<QSGRectangleNode *>(oldNode);
+ if (!root)
+ root = window()->createRectangleNode();
+
+ root->setRect(boundingRect());
+ root->setColor(m_color);
+
+ QSGNode *content = root->childCount() ? root->firstChild() : 0;
+ content = m_map->updateSceneGraph(content, window());
+ if (content && root->childCount() == 0)
+ root->appendChildNode(content);
+
+ return root;
+}
+
+/*!
+ \qmlproperty Plugin QtLocation::Map::plugin
+
+ This property holds the plugin which provides the mapping functionality.
+
+ This is a write-once property. Once the map has a plugin associated with
+ it, any attempted modifications of the plugin will be ignored.
+*/
+
+void QDeclarativeGeoMap::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (m_plugin) {
+ qmlWarning(this) << QStringLiteral("Plugin is a write-once property, and cannot be set again.");
+ return;
+ }
+ m_plugin = plugin;
+ emit pluginChanged(m_plugin);
+
+ if (m_plugin->isAttached()) {
+ pluginReady();
+ } else {
+ connect(m_plugin, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+/*!
+ \internal
+ this function will only be ever called once
+*/
+void QDeclarativeGeoMap::mappingManagerInitialized()
+{
+ m_map = m_mappingManager->createMap(this);
+
+ if (!m_map)
+ return;
+
+ m_gestureArea->setMap(m_map);
+
+ QList<QGeoMapType> types = m_mappingManager->supportedMapTypes();
+ for (int i = 0; i < types.size(); ++i) {
+ QDeclarativeGeoMapType *type = new QDeclarativeGeoMapType(types[i], this);
+ m_supportedMapTypes.append(type);
+ }
+
+ if (!m_supportedMapTypes.isEmpty()) {
+ QDeclarativeGeoMapType *type = m_supportedMapTypes.at(0);
+ m_activeMapType = type;
+ m_map->setActiveMapType(type->mapType());
+ } else {
+ m_map->setActiveMapType(m_activeMapType->mapType());
+ }
+
+ //The zoom level limits are only restricted by the plugins values, if the user has set a more
+ //strict zoom level limit before initialization nothing is done here.
+ //minimum zoom level might be changed to limit gray bundaries
+ //This code assumes that plugins' maximum zoom level will never exceed 30.0
+ if (m_mappingManager->cameraCapabilities().maximumZoomLevelAt256() < m_gestureArea->maximumZoomLevel())
+ setMaximumZoomLevel(m_mappingManager->cameraCapabilities().maximumZoomLevelAt256());
+
+ if (m_mappingManager->cameraCapabilities().minimumZoomLevelAt256() > m_gestureArea->minimumZoomLevel())
+ setMinimumZoomLevel(m_mappingManager->cameraCapabilities().minimumZoomLevelAt256());
+
+
+ // Map tiles are built in this call. m_map->minimumZoom() becomes operational
+ // after this has been called at least once, after creation.
+
+ if (!m_initialized && width() > 0 && height() > 0) {
+ m_map->setViewportSize(QSize(width(), height()));
+ initialize();
+ }
+
+ m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this);
+ connect(m_map, SIGNAL(copyrightsChanged(QImage)),
+ m_copyrights.data(), SLOT(copyrightsChanged(QImage)));
+ connect(m_map, SIGNAL(copyrightsChanged(QString)),
+ m_copyrights.data(), SLOT(copyrightsChanged(QString)));
+ connect(m_copyrights.data(), SIGNAL(linkActivated(QString)),
+ this, SIGNAL(copyrightLinkActivated(QString)));
+ connect(m_map, &QGeoMap::sgNodeChanged, this, &QQuickItem::update);
+
+ // set visibility of copyright notice
+ m_copyrights->setCopyrightsVisible(m_copyrightsVisible);
+
+ // This prefetches a buffer around the map
+ m_map->prefetchData();
+
+ connect(m_mappingManager, SIGNAL(supportedMapTypesChanged()), this, SLOT(onSupportedMapTypesChanged()));
+ emit minimumZoomLevelChanged();
+ emit maximumZoomLevelChanged();
+ emit supportedMapTypesChanged();
+ emit activeMapTypeChanged();
+
+ // Any map items that were added before the plugin was ready
+ // need to have setMap called again
+ foreach (const QPointer<QDeclarativeGeoMapItemBase> &item, m_mapItems) {
+ if (item)
+ item.data()->setMap(this, m_map);
+ }
+
+ // All map parameters that were added before the plugin was ready
+ // need to be added to m_map
+ for (QDeclarativeGeoMapParameter *p : m_mapParameters)
+ m_map->addParameter(p);
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider *QDeclarativeGeoMap::plugin() const
+{
+ return m_plugin;
+}
+
+/*!
+ \internal
+ Sets the gesture areas minimum zoom level. If the camera capabilities
+ has been set this method honors the boundaries set by it.
+ The minimum zoom level will also have a lower bound dependent on the size
+ of the canvas, effectively preventing to display out of bounds areas.
+*/
+void QDeclarativeGeoMap::setMinimumZoomLevel(qreal minimumZoomLevel)
+{
+
+ if (minimumZoomLevel >= 0) {
+ qreal oldMinimumZoomLevel = this->minimumZoomLevel();
+
+ if (m_map) {
+ minimumZoomLevel = qBound(qreal(m_map->cameraCapabilities().minimumZoomLevelAt256()), minimumZoomLevel, maximumZoomLevel());
+ double minimumViewportZoomLevel = m_map->minimumZoom();
+ if (minimumZoomLevel < minimumViewportZoomLevel)
+ minimumZoomLevel = minimumViewportZoomLevel;
+ }
+
+ m_gestureArea->setMinimumZoomLevel(minimumZoomLevel);
+
+ if (zoomLevel() < minimumZoomLevel)
+ setZoomLevel(minimumZoomLevel);
+
+ if (oldMinimumZoomLevel != minimumZoomLevel)
+ emit minimumZoomLevelChanged();
+ }
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::minimumZoomLevel
+
+ This property holds the minimum valid zoom level for the map.
+
+ The minimum zoom level defined by the \l plugin used is a lower bound for
+ this property. However, the returned value is also canvas-size-dependent, and
+ can be higher than the user-specified value, or than the minimum zoom level
+ defined by the plugin used, to prevent the map from being smaller than the
+ viewport in either dimension.
+
+ If a plugin supporting mapping is not set, 0.0 is returned.
+*/
+
+qreal QDeclarativeGeoMap::minimumZoomLevel() const
+{
+ return m_gestureArea->minimumZoomLevel();
+}
+
+/*!
+ \internal
+ Sets the gesture areas maximum zoom level. If the camera capabilities
+ has been set this method honors the boundaries set by it.
+*/
+void QDeclarativeGeoMap::setMaximumZoomLevel(qreal maximumZoomLevel)
+{
+ if (maximumZoomLevel >= 0) {
+ qreal oldMaximumZoomLevel = this->maximumZoomLevel();
+
+ if (m_map)
+ maximumZoomLevel = qBound(minimumZoomLevel(), maximumZoomLevel, qreal(m_map->cameraCapabilities().maximumZoomLevelAt256()));
+
+ m_gestureArea->setMaximumZoomLevel(maximumZoomLevel);
+
+ if (zoomLevel() > maximumZoomLevel)
+ setZoomLevel(maximumZoomLevel);
+
+ if (oldMaximumZoomLevel != maximumZoomLevel)
+ emit maximumZoomLevelChanged();
+ }
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::maximumZoomLevel
+
+ This property holds the maximum valid zoom level for the map.
+
+ The maximum zoom level is defined by the \l plugin used.
+ If a plugin supporting mapping is not set, 30.0 is returned.
+*/
+
+qreal QDeclarativeGeoMap::maximumZoomLevel() const
+{
+ return m_gestureArea->maximumZoomLevel();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::zoomLevel
+
+ This property holds the zoom level for the map.
+
+ Larger values for the zoom level provide more detail. Zoom levels
+ are always non-negative. The default value is 8.0.
+*/
+void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel)
+{
+ if (m_cameraData.zoomLevel() == zoomLevel || zoomLevel < 0)
+ return;
+
+ //small optimization to avoid double setCameraData
+ bool centerHasChanged = false;
+
+ if (m_initialized) {
+ m_cameraData.setZoomLevel(qBound(minimumZoomLevel(), zoomLevel, maximumZoomLevel()));
+ m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
+ QGeoCoordinate coord = m_cameraData.center();
+ coord.setLatitude(qBound(-m_maximumViewportLatitude, coord.latitude(), m_maximumViewportLatitude));
+ if (coord != m_cameraData.center()) {
+ centerHasChanged = true;
+ m_cameraData.setCenter(coord);
+ }
+ m_map->setCameraData(m_cameraData);
+ } else {
+ m_cameraData.setZoomLevel(zoomLevel);
+ }
+
+ if (centerHasChanged)
+ emit centerChanged(m_cameraData.center());
+ emit zoomLevelChanged(m_cameraData.zoomLevel());
+}
+
+qreal QDeclarativeGeoMap::zoomLevel() const
+{
+ return m_cameraData.zoomLevel();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::bearing
+
+ This property holds the bearing for the map.
+ The default value is 0.
+ If the Plugin used for the Map supports bearing, the valid range for this value is between 0 and 360.
+ If the Plugin used for the Map does not support bearing, changing this property will have no effect.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setBearing(qreal bearing)
+{
+ bearing = std::fmod(bearing, qreal(360.0));
+ if (m_map && !m_map->cameraCapabilities().supportsBearing())
+ bearing = 0.0;
+ if (m_cameraData.bearing() == bearing || bearing < 0.0)
+ return;
+
+ m_cameraData.setBearing(bearing);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit bearingChanged(bearing);
+}
+
+qreal QDeclarativeGeoMap::bearing() const
+{
+ return m_cameraData.bearing();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::tilt
+
+ This property holds the tilt for the map.
+ The default value is 0.
+ If the Plugin used for the Map supports tilt, the valid range for this value is
+ [ plugin.minimumTilt, plugin.maximumTilt ].
+ If the Plugin used for the Map does not support tilting, changing this property will have no effect.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setTilt(qreal tilt)
+{
+ tilt = qBound(minimumTilt(), tilt, maximumTilt());
+ if (m_cameraData.tilt() == tilt)
+ return;
+
+ m_cameraData.setTilt(tilt);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit tiltChanged(tilt);
+}
+
+qreal QDeclarativeGeoMap::tilt() const
+{
+ return m_cameraData.tilt();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::fieldOfView
+
+ This property holds the field of view of the camera used to look at the map, in degrees.
+ If the plugin property of the map is not set, or the plugin does not support mapping, the value is 45 degrees.
+
+ Note that changing this value implicitly changes also the distance between the camera and the map,
+ so that, at a tilting angle of 0 degrees, the resulting image is identical for any value used for this property.
+
+ For more information about this parameter, consult the Wikipedia articles about \l {https://en.wikipedia.org/wiki/Field_of_view} {Field of view} and
+ \l {https://en.wikipedia.org/wiki/Angle_of_view} {Angle of view}.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setFieldOfView(qreal fieldOfView)
+{
+ fieldOfView = qBound(minimumFieldOfView(), fieldOfView, maximumFieldOfView());
+ if (m_cameraData.fieldOfView() == fieldOfView)
+ return;
+
+ m_cameraData.setFieldOfView(fieldOfView);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit fieldOfViewChanged(fieldOfView);
+}
+
+qreal QDeclarativeGeoMap::fieldOfView() const
+{
+ return m_cameraData.fieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::minimumFieldOfView
+ This property holds the minimum field of view that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 1.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::minimumFieldOfView() const
+{
+ if (!m_map)
+ return 1;
+ return m_map->cameraCapabilities().minimumFieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::maximumFieldOfView
+ This property holds the maximum field of view that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 179.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::maximumFieldOfView() const
+{
+ if (!m_map)
+ return 179;
+ return m_map->cameraCapabilities().maximumFieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::bearingSupported
+
+ This property indicates if the Map supports bearing.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is false.
+
+ \since Qt Location 5.9
+*/
+bool QDeclarativeGeoMap::isBearingSupported() const
+{
+ if (!m_map)
+ return false;
+ return m_map->cameraCapabilities().supportsBearing();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::tiltingSupported
+
+ This property indicates if the Map supports tilting.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is false.
+
+ \since Qt Location 5.9
+*/
+bool QDeclarativeGeoMap::isTiltingSupported() const
+{
+ if (!m_map)
+ return false;
+ return m_map->cameraCapabilities().supportsTilting();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::minimumTilt
+
+ This property holds the minimum tilt that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 0.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::minimumTilt() const
+{
+ if (!m_map || !m_map->cameraCapabilities().supportsTilting())
+ return 0.0;
+ return m_map->cameraCapabilities().minimumTilt();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::maximumTilt
+
+ This property holds the maximum tilt that the map supports.
+ If the plugin property of the map is not set, this property is 89.
+ If the plugin is set and it does not support mapping, this property is 0.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::maximumTilt() const
+{
+ if (!m_map)
+ return 89.0;
+ else if (!m_map->cameraCapabilities().supportsTilting())
+ return 0.0;
+ return m_map->cameraCapabilities().maximumTilt();
+}
+
+/*!
+ \qmlproperty coordinate QtLocation::Map::center
+
+ This property holds the coordinate which occupies the center of the
+ mapping viewport. Invalid center coordinates are ignored.
+
+ The default value is an arbitrary valid coordinate.
+*/
+void QDeclarativeGeoMap::setCenter(const QGeoCoordinate &center)
+{
+ if (center == m_cameraData.center())
+ return;
+
+ if (!center.isValid())
+ return;
+
+ if (m_initialized) {
+ QGeoCoordinate coord(center);
+ coord.setLatitude(qBound(-m_maximumViewportLatitude, center.latitude(), m_maximumViewportLatitude));
+ m_cameraData.setCenter(coord);
+ m_map->setCameraData(m_cameraData);
+ } else {
+ m_cameraData.setCenter(center);
+ }
+
+ emit centerChanged(m_cameraData.center());
+}
+
+QGeoCoordinate QDeclarativeGeoMap::center() const
+{
+ return m_cameraData.center();
+}
+
+
+/*!
+ \qmlproperty geoshape QtLocation::Map::visibleRegion
+
+ This property holds the region which occupies the viewport of
+ the map. The camera is positioned in the center of the shape, and
+ at the largest integral zoom level possible which allows the
+ whole shape to be visible on the screen. This implies that
+ reading this property back shortly after having been set the
+ returned area is equal or larger than the set area.
+
+ Setting this property implicitly changes the \l center and
+ \l zoomLevel of the map. Any previously set value to those
+ properties will be overridden.
+
+ This property does not provide any change notifications.
+
+ \since 5.6
+*/
+void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape)
+{
+ if (shape.boundingGeoRectangle() == visibleRegion())
+ return;
+
+ m_visibleRegion = shape.boundingGeoRectangle();
+ if (!m_visibleRegion.isValid()
+ || (m_visibleRegion.bottomRight().latitude() >= 85.0) // rect entirely outside web mercator
+ || (m_visibleRegion.topLeft().latitude() <= -85.0)) {
+ // shape invalidated -> nothing to fit anymore
+ m_visibleRegion = QGeoRectangle();
+ m_pendingFitViewport = false;
+ return;
+ }
+
+ if (!m_map || !width() || !height()) {
+ m_pendingFitViewport = true;
+ return;
+ }
+
+ fitViewportToGeoShape();
+}
+
+QGeoShape QDeclarativeGeoMap::visibleRegion() const
+{
+ if (!m_map || !width() || !height())
+ return m_visibleRegion;
+
+ QGeoCoordinate tl = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(0, 0));
+ QGeoCoordinate br = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(width(), height()));
+
+ return QGeoRectangle(tl, br);
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::copyrightsVisible
+
+ This property holds the visibility of the copyrights notice. The notice is usually
+ displayed in the bottom left corner. By default, this property is set to \c true.
+
+ \note Many map providers require the notice to be visible as part of the terms and conditions.
+ Please consult the relevant provider documentation before turning this notice off.
+
+ \since 5.7
+*/
+void QDeclarativeGeoMap::setCopyrightsVisible(bool visible)
+{
+ if (m_copyrightsVisible == visible)
+ return;
+
+ if (!m_copyrights.isNull())
+ m_copyrights->setCopyrightsVisible(visible);
+
+ m_copyrightsVisible = visible;
+ emit copyrightsVisibleChanged(visible);
+}
+
+bool QDeclarativeGeoMap::copyrightsVisible() const
+{
+ return m_copyrightsVisible;
+}
+
+
+
+/*!
+ \qmlproperty color QtLocation::Map::color
+
+ This property holds the background color of the map element.
+
+ \since 5.6
+*/
+void QDeclarativeGeoMap::setColor(const QColor &color)
+{
+ if (color != m_color) {
+ m_color = color;
+ update();
+ emit colorChanged(m_color);
+ }
+}
+
+QColor QDeclarativeGeoMap::color() const
+{
+ return m_color;
+}
+
+// TODO: offer the possibility to specify the margins.
+void QDeclarativeGeoMap::fitViewportToGeoShape()
+{
+ const int margins = 10;
+ if (!m_map || !m_visibleRegion.isValid() || width() <= margins || height() <= margins)
+ return;
+
+ QDoubleVector2D topLeftPoint = m_map->geoProjection().geoToMapProjection(m_visibleRegion.topLeft());
+ QDoubleVector2D bottomRightPoint = m_map->geoProjection().geoToMapProjection(m_visibleRegion.bottomRight());
+ if (bottomRightPoint.x() < topLeftPoint.x()) // crossing the dateline
+ bottomRightPoint.setX(bottomRightPoint.x() + 1.0);
+
+ // find center of the bounding box
+ QDoubleVector2D center = (topLeftPoint + bottomRightPoint) * 0.5;
+ center.setX(center.x() > 1.0 ? center.x() - 1.0 : center.x());
+ QGeoCoordinate centerCoordinate = m_map->geoProjection().mapProjectionToGeo(center);
+
+ // position camera to the center of bounding box
+ setCenter(centerCoordinate);
+
+ // if the shape is empty we just change center position, not zoom
+ double bboxWidth = (bottomRightPoint.x() - topLeftPoint.x()) * m_map->mapWidth();
+ double bboxHeight = (bottomRightPoint.y() - topLeftPoint.y()) * m_map->mapHeight();
+
+ if (bboxHeight == 0.0 && bboxWidth == 0.0)
+ return;
+
+ double zoomRatio = qMax(bboxWidth / (width() - margins),
+ bboxHeight / (height() - margins));
+ zoomRatio = std::log(zoomRatio) / std::log(2.0);
+ double newZoom = qMax<double>(minimumZoomLevel(), zoomLevel() - zoomRatio);
+ setZoomLevel(newZoom);
+}
+
+
+/*!
+ \qmlproperty list<MapType> QtLocation::Map::supportedMapTypes
+
+ This read-only property holds the set of \l{MapType}{map types} supported by this map.
+
+ \sa activeMapType
+*/
+QQmlListProperty<QDeclarativeGeoMapType> QDeclarativeGeoMap::supportedMapTypes()
+{
+ return QQmlListProperty<QDeclarativeGeoMapType>(this, m_supportedMapTypes);
+}
+
+/*!
+ \qmlmethod coordinate QtLocation::Map::toCoordinate(QPointF position, bool clipToViewPort)
+
+ Returns the coordinate which corresponds to the \a position relative to the map item.
+
+ If \a cliptoViewPort is \c true, or not supplied then returns an invalid coordinate if
+ \a position is not within the current viewport.
+*/
+QGeoCoordinate QDeclarativeGeoMap::toCoordinate(const QPointF &position, bool clipToViewPort) const
+{
+ if (m_map)
+ return m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(position), clipToViewPort);
+ else
+ return QGeoCoordinate();
+}
+
+/*!
+ \qmlmethod point QtLocation::Map::fromCoordinate(coordinate coordinate, bool clipToViewPort)
+
+ Returns the position relative to the map item which corresponds to the \a coordinate.
+
+ If \a cliptoViewPort is \c true, or not supplied then returns an invalid QPointF if
+ \a coordinate is not within the current viewport.
+*/
+QPointF QDeclarativeGeoMap::fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort) const
+{
+ if (m_map)
+ return m_map->geoProjection().coordinateToItemPosition(coordinate, clipToViewPort).toPointF();
+ else
+ return QPointF(qQNaN(), qQNaN());
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::pan(int dx, int dy)
+
+ Starts panning the map by \a dx pixels along the x-axis and
+ by \a dy pixels along the y-axis.
+
+ Positive values for \a dx move the map right, negative values left.
+ Positive values for \a dy move the map down, negative values up.
+
+ During panning the \l center, and \l zoomLevel may change.
+*/
+void QDeclarativeGeoMap::pan(int dx, int dy)
+{
+ if (!m_map)
+ return;
+ if (dx == 0 && dy == 0)
+ return;
+
+ QGeoCoordinate coord = m_map->geoProjection().itemPositionToCoordinate(
+ QDoubleVector2D(m_map->viewportWidth() / 2 + dx,
+ m_map->viewportHeight() / 2 + dy));
+ setCenter(coord);
+}
+
+
+/*!
+ \qmlmethod void QtLocation::Map::prefetchData()
+
+ Optional hint that allows the map to prefetch during this idle period
+*/
+void QDeclarativeGeoMap::prefetchData()
+{
+ if (!m_map)
+ return;
+ m_map->prefetchData();
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::clearData()
+
+ Clears map data collected by the currently selected plugin.
+ \note This method will delete cached files.
+ \sa plugin
+*/
+void QDeclarativeGeoMap::clearData()
+{
+ m_map->clearData();
+}
+
+/*!
+ \qmlproperty string QtLocation::Map::errorString
+
+ This read-only property holds the textual presentation of the latest mapping provider error.
+ If no error has occurred, an empty string is returned.
+
+ An empty string may also be returned if an error occurred which has no associated
+ textual representation.
+
+ \sa QGeoServiceProvider::errorString()
+*/
+
+QString QDeclarativeGeoMap::errorString() const
+{
+ return m_errorString;
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::Map::error
+
+ This read-only property holds the last occurred mapping service provider error.
+
+ \list
+ \li Map.NoError - No error has occurred.
+ \li Map.NotSupportedError -The maps plugin property was not set or there is no mapping manager associated with the plugin.
+ \li Map.UnknownParameterError -The plugin did not recognize one of the parameters it was given.
+ \li Map.MissingRequiredParameterError - The plugin did not find one of the parameters it was expecting.
+ \li Map.ConnectionError - The plugin could not connect to its backend service or database.
+ \endlist
+
+ \sa QGeoServiceProvider::Error
+*/
+
+QGeoServiceProvider::Error QDeclarativeGeoMap::error() const
+{
+ return m_error;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::touchEvent(QTouchEvent *event)
+{
+ if (isInteractive()) {
+ m_gestureArea->handleTouchEvent(event);
+ } else {
+ //ignore event so sythesized event is generated;
+ QQuickItem::touchEvent(event);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::wheelEvent(QWheelEvent *event)
+{
+ if (isInteractive())
+ m_gestureArea->handleWheelEvent(event);
+ else
+ QQuickItem::wheelEvent(event);
+
+}
+
+bool QDeclarativeGeoMap::isInteractive()
+{
+ return (m_gestureArea->enabled() && m_gestureArea->acceptedGestures()) || m_gestureArea->isActive();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMap::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ Q_UNUSED(item)
+ if (!isVisible() || !isEnabled() || !isInteractive())
+ return QQuickItem::childMouseEventFilter(item, event);
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ return sendMouseEvent(static_cast<QMouseEvent *>(event));
+ case QEvent::UngrabMouse: {
+ QQuickWindow *win = window();
+ if (!win) break;
+ if (!win->mouseGrabberItem() ||
+ (win->mouseGrabberItem() &&
+ win->mouseGrabberItem() != this)) {
+ // child lost grab, we could even lost
+ // some events if grab already belongs for example
+ // in item in diffrent window , clear up states
+ mouseUngrabEvent();
+ }
+ break;
+ }
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ case QEvent::TouchCancel:
+ if (static_cast<QTouchEvent *>(event)->touchPoints().count() >= 2) {
+ // 1 touch point = handle with MouseEvent (event is always synthesized)
+ // let the synthesized mouse event grab the mouse,
+ // note there is no mouse grabber at this point since
+ // touch event comes first (see Qt::AA_SynthesizeMouseForUnhandledTouchEvents)
+ return sendTouchEvent(static_cast<QTouchEvent *>(event));
+ }
+ default:
+ break;
+ }
+ return QQuickItem::childMouseEventFilter(item, event);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::addMapItem(MapItem item)
+
+ Adds the given \a item to the Map (for example MapQuickItem, MapCircle). If the object
+ already is on the Map, it will not be added again.
+
+ As an example, consider the case where you have a MapCircle representing your current position:
+
+ \snippet declarative/maps.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/maps.qml Map addMapItem MapCircle at current position
+
+ \note MapItemViews cannot be added with this method.
+
+ \sa mapItems, removeMapItem, clearMapItems
+*/
+
+void QDeclarativeGeoMap::addMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ if (!item || item->quickMap())
+ return;
+ item->setParentItem(this);
+ if (m_map)
+ item->setMap(this, m_map);
+ m_mapItems.append(item);
+ emit mapItemsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::addMapParameter(MapParameter parameter)
+
+ Adds a MapParameter object to the map. The effect of this call is dependent
+ on the combination of the content of the MapParameter and the type of
+ underlying QGeoMap. If a MapParameter that is not supported by the underlying
+ QGeoMap gets added, the call has no effect.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, removeMapParameter, mapParameters, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::addMapParameter(QDeclarativeGeoMapParameter *parameter)
+{
+ if (!parameter->isComponentComplete()) {
+ connect(parameter, &QDeclarativeGeoMapParameter::completed, this, &QDeclarativeGeoMap::addMapParameter);
+ return;
+ }
+
+ disconnect(parameter);
+ if (m_mapParameters.contains(parameter))
+ return;
+ parameter->setParent(this);
+ m_mapParameters.insert(parameter); // parameter now owned by QDeclarativeGeoMap
+ if (m_map)
+ m_map->addParameter(parameter);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::removeMapParameter(MapParameter parameter)
+
+ Removes the given MapParameter object from the map.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, addMapParameter, mapParameters, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::removeMapParameter(QDeclarativeGeoMapParameter *parameter)
+{
+ if (!m_mapParameters.contains(parameter))
+ return;
+ if (m_map)
+ m_map->removeParameter(parameter);
+ m_mapParameters.remove(parameter);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::clearMapParameters()
+
+ Removes all map parameters from the map.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, mapParameters, addMapParameter, removeMapParameter, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::clearMapParameters()
+{
+ if (m_map)
+ m_map->clearParameters();
+ m_mapParameters.clear();
+}
+
+/*!
+ \qmlproperty list<MapParameters> QtLocation::Map::mapParameters
+
+ Returns the list of all map parameters in no particular order.
+ These items include map parameters that were declared statically as part of
+ the type declaration, as well as dynamical map parameters (\l addMapParameter).
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, addMapParameter, removeMapParameter, clearMapParameters
+
+ \since 5.9
+*/
+QList<QObject *> QDeclarativeGeoMap::mapParameters()
+{
+ QList<QObject *> ret;
+ for (QDeclarativeGeoMapParameter *p : m_mapParameters)
+ ret << p;
+ return ret;
+}
+
+/*!
+ \qmlproperty list<MapItem> QtLocation::Map::mapItems
+
+ Returns the list of all map items in no particular order.
+ These items include items that were declared statically as part of
+ the type declaration, as well as dynamical items (\l addMapItem,
+ \l MapItemView).
+
+ \sa addMapItem, removeMapItem, clearMapItems
+*/
+
+QList<QObject *> QDeclarativeGeoMap::mapItems()
+{
+ QList<QObject *> ret;
+ foreach (const QPointer<QDeclarativeGeoMapItemBase> &ptr, m_mapItems) {
+ if (ptr)
+ ret << ptr.data();
+ }
+ return ret;
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::removeMapItem(MapItem item)
+
+ Removes the given \a item from the Map (for example MapQuickItem, MapCircle). If
+ the MapItem does not exist or was not previously added to the map, the
+ method does nothing.
+
+ \sa mapItems, addMapItem, clearMapItems
+*/
+void QDeclarativeGeoMap::removeMapItem(QDeclarativeGeoMapItemBase *ptr)
+{
+ if (!ptr || !m_map)
+ return;
+ QPointer<QDeclarativeGeoMapItemBase> item(ptr);
+ if (!m_mapItems.contains(item))
+ return;
+ item.data()->setParentItem(0);
+ item.data()->setMap(0, 0);
+ // these can be optimized for perf, as we already check the 'contains' above
+ m_mapItems.removeOne(item);
+ emit mapItemsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::clearMapItems()
+
+ Removes all items from the map.
+
+ \sa mapItems, addMapItem, removeMapItem
+*/
+void QDeclarativeGeoMap::clearMapItems()
+{
+ if (m_mapItems.isEmpty())
+ return;
+ for (int i = 0; i < m_mapItems.count(); ++i) {
+ if (m_mapItems.at(i)) {
+ m_mapItems.at(i).data()->setParentItem(0);
+ m_mapItems.at(i).data()->setMap(0, 0);
+ }
+ }
+ m_mapItems.clear();
+ emit mapItemsChanged();
+}
+
+/*!
+ \qmlproperty MapType QtLocation::Map::activeMapType
+
+ \brief Access to the currently active \l{MapType}{map type}.
+
+ This property can be set to change the active \l{MapType}{map type}.
+ See the \l{Map::supportedMapTypes}{supportedMapTypes} property for possible values.
+
+ \sa MapType
+*/
+void QDeclarativeGeoMap::setActiveMapType(QDeclarativeGeoMapType *mapType)
+{
+ if (m_activeMapType->mapType() != mapType->mapType()) {
+ m_activeMapType = mapType;
+ if (m_map)
+ m_map->setActiveMapType(mapType->mapType());
+ emit activeMapTypeChanged();
+ }
+}
+
+QDeclarativeGeoMapType * QDeclarativeGeoMap::activeMapType() const
+{
+ return m_activeMapType;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ m_gestureArea->setSize(newGeometry.size());
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+
+ if (!m_map || !newGeometry.size().isValid())
+ return;
+
+ m_map->setViewportSize(newGeometry.size().toSize());
+
+ if (!m_initialized) {
+ initialize();
+ } else {
+ setMinimumZoomLevel(m_map->minimumZoom());
+
+ // Update the center latitudinal threshold
+ double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
+ if (maximumCenterLatitudeAtZoom != m_maximumViewportLatitude) {
+ m_maximumViewportLatitude = maximumCenterLatitudeAtZoom;
+ QGeoCoordinate coord = m_cameraData.center();
+ coord.setLatitude(qBound(-m_maximumViewportLatitude, coord.latitude(), m_maximumViewportLatitude));
+
+ if (coord != m_cameraData.center()) {
+ m_cameraData.setCenter(coord);
+ m_map->setCameraData(m_cameraData);
+ emit centerChanged(m_cameraData.center());
+ }
+ }
+ }
+
+ /*!
+ The fitViewportTo*() functions depend on a valid map geometry.
+ If they were called prior to the first resize they cause
+ the zoomlevel to jump to 0 (showing the world). Therefore the
+ calls were queued up until now.
+
+ Multiple fitViewportTo*() calls replace each other.
+ */
+ if (m_pendingFitViewport && width() && height()) {
+ fitViewportToGeoShape();
+ m_pendingFitViewport = false;
+ }
+
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::fitViewportToMapItems()
+
+ Fits the current viewport to the boundary of all map items. The camera is positioned
+ in the center of the map items, and at the largest integral zoom level possible which
+ allows all map items to be visible on screen
+
+*/
+void QDeclarativeGeoMap::fitViewportToMapItems()
+{
+ fitViewportToMapItemsRefine(true);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
+{
+ if (!m_map)
+ return;
+
+ if (m_mapItems.size() == 0)
+ return;
+
+ double minX = 0;
+ double maxX = 0;
+ double minY = 0;
+ double maxY = 0;
+ double topLeftX = 0;
+ double topLeftY = 0;
+ double bottomRightX = 0;
+ double bottomRightY = 0;
+ bool haveQuickItem = false;
+
+ // find bounds of all map items
+ int itemCount = 0;
+ for (int i = 0; i < m_mapItems.count(); ++i) {
+ if (!m_mapItems.at(i))
+ continue;
+ QDeclarativeGeoMapItemBase *item = m_mapItems.at(i).data();
+ if (!item)
+ continue;
+
+ // skip quick items in the first pass and refine the fit later
+ if (refine) {
+ QDeclarativeGeoMapQuickItem *quickItem =
+ qobject_cast<QDeclarativeGeoMapQuickItem*>(item);
+ if (quickItem) {
+ haveQuickItem = true;
+ continue;
+ }
+ }
+ // Force map items to update immediately. Needed to ensure correct item size and positions
+ // when recursively calling this function.
+ if (item->isPolishScheduled())
+ item->updatePolish();
+
+ topLeftX = item->position().x();
+ topLeftY = item->position().y();
+ bottomRightX = topLeftX + item->width();
+ bottomRightY = topLeftY + item->height();
+
+ if (itemCount == 0) {
+ minX = topLeftX;
+ maxX = bottomRightX;
+ minY = topLeftY;
+ maxY = bottomRightY;
+ } else {
+ minX = qMin(minX, topLeftX);
+ maxX = qMax(maxX, bottomRightX);
+ minY = qMin(minY, topLeftY);
+ maxY = qMax(maxY, bottomRightY);
+ }
+ ++itemCount;
+ }
+
+ if (itemCount == 0) {
+ if (haveQuickItem)
+ fitViewportToMapItemsRefine(false);
+ return;
+ }
+ double bboxWidth = maxX - minX;
+ double bboxHeight = maxY - minY;
+ double bboxCenterX = minX + (bboxWidth / 2.0);
+ double bboxCenterY = minY + (bboxHeight / 2.0);
+
+ // position camera to the center of bounding box
+ QGeoCoordinate coordinate;
+ coordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(bboxCenterX, bboxCenterY), false);
+ setProperty("center", QVariant::fromValue(coordinate));
+
+ // adjust zoom
+ double bboxWidthRatio = bboxWidth / (bboxWidth + bboxHeight);
+ double mapWidthRatio = width() / (width() + height());
+ double zoomRatio;
+
+ if (bboxWidthRatio > mapWidthRatio)
+ zoomRatio = bboxWidth / width();
+ else
+ zoomRatio = bboxHeight / height();
+
+ qreal newZoom = std::log10(zoomRatio) / std::log10(0.5);
+ newZoom = std::floor(qMax(minimumZoomLevel(), (zoomLevel() + newZoom)));
+ setProperty("zoomLevel", QVariant::fromValue(newZoom));
+
+ // as map quick items retain the same screen size after the camera zooms in/out
+ // we refine the viewport again to achieve better results
+ if (refine)
+ fitViewportToMapItemsRefine(false);
+}
+
+bool QDeclarativeGeoMap::sendMouseEvent(QMouseEvent *event)
+{
+ QPointF localPos = mapFromScene(event->windowPos());
+ QQuickWindow *win = window();
+ QQuickItem *grabber = win ? win->mouseGrabberItem() : 0;
+ bool stealEvent = m_gestureArea->isActive();
+
+ if ((stealEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
+ QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos));
+ mouseEvent->setAccepted(false);
+
+ switch (mouseEvent->type()) {
+ case QEvent::MouseMove:
+ m_gestureArea->handleMouseMoveEvent(mouseEvent.data());
+ break;
+ case QEvent::MouseButtonPress:
+ m_gestureArea->handleMousePressEvent(mouseEvent.data());
+ break;
+ case QEvent::MouseButtonRelease:
+ m_gestureArea->handleMouseReleaseEvent(mouseEvent.data());
+ break;
+ default:
+ break;
+ }
+
+ stealEvent = m_gestureArea->isActive();
+ grabber = win ? win->mouseGrabberItem() : 0;
+
+ if (grabber && stealEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ if (stealEvent) {
+ //do not deliver
+ event->setAccepted(true);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeGeoMap::sendTouchEvent(QTouchEvent *event)
+{
+ const QQuickPointerDevice *touchDevice = QQuickPointerDevice::touchDevice(event->device());
+ const QTouchEvent::TouchPoint &point = event->touchPoints().first();
+
+ auto touchPointGrabberItem = [touchDevice](const QTouchEvent::TouchPoint &point) -> QQuickItem* {
+ if (QQuickEventPoint *eventPointer = touchDevice->pointerEvent()->pointById(point.id()))
+ return eventPointer->grabber();
+ return nullptr;
+ };
+
+ QQuickItem *grabber = touchPointGrabberItem(point);
+
+ bool stealEvent = m_gestureArea->isActive();
+ bool containsPoint = contains(mapFromScene(point.scenePos()));
+
+ if ((stealEvent || containsPoint) && (!grabber || !grabber->keepTouchGrab())) {
+ QScopedPointer<QTouchEvent> touchEvent(new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints()));
+ touchEvent->setTimestamp(event->timestamp());
+ touchEvent->setAccepted(false);
+
+ m_gestureArea->handleTouchEvent(touchEvent.data());
+ stealEvent = m_gestureArea->isActive();
+ grabber = touchPointGrabberItem(point);
+
+ if (grabber && stealEvent && !grabber->keepTouchGrab() && grabber != this) {
+ QVector<int> ids;
+ foreach (const QTouchEvent::TouchPoint &tp, event->touchPoints()) {
+ if (!(tp.state() & Qt::TouchPointReleased)) {
+ ids.append(tp.id());
+ }
+ }
+ grabTouchPoints(ids);
+ }
+
+ if (stealEvent) {
+ //do not deliver
+ event->setAccepted(true);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+#include "moc_qdeclarativegeomap_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h
new file mode 100644
index 00000000..ca2ec0a9
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomap_p.h
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAP_H
+#define QDECLARATIVEGEOMAP_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitemview_p.h>
+#include <QtLocation/private/qquickgeomapgesturearea_p.h>
+
+#include <QtLocation/qgeoserviceprovider.h>
+#include <QtLocation/private/qgeocameradata_p.h>
+#include <QtQuick/QQuickItem>
+#include <QtCore/QPointer>
+#include <QtCore/QSet>
+#include <QtGui/QColor>
+#include <QtPositioning/qgeoshape.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGeoServiceProvider;
+class QDeclarativeGeoMapType;
+class QDeclarativeGeoMapCopyrightNotice;
+class QDeclarativeGeoMapParameter;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMap : public QQuickItem
+{
+ Q_OBJECT
+ Q_ENUMS(QGeoServiceProvider::Error)
+ Q_PROPERTY(QQuickGeoMapGestureArea *gesture READ gesture CONSTANT)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(qreal minimumZoomLevel READ minimumZoomLevel WRITE setMinimumZoomLevel NOTIFY minimumZoomLevelChanged)
+ Q_PROPERTY(qreal maximumZoomLevel READ maximumZoomLevel WRITE setMaximumZoomLevel NOTIFY maximumZoomLevelChanged)
+ Q_PROPERTY(qreal zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged)
+
+ Q_PROPERTY(bool bearingSupported READ isBearingSupported NOTIFY bearingSupportChanged)
+ Q_PROPERTY(bool tiltingSupported READ isTiltingSupported NOTIFY tiltingSupportChanged)
+ Q_PROPERTY(qreal minimumTilt READ minimumTilt NOTIFY minimumTiltChanged)
+ Q_PROPERTY(qreal maximumTilt READ maximumTilt NOTIFY maximumTiltChanged)
+ Q_PROPERTY(qreal bearing READ bearing WRITE setBearing NOTIFY bearingChanged)
+ Q_PROPERTY(qreal tilt READ tilt WRITE setTilt NOTIFY tiltChanged)
+ Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged)
+ Q_PROPERTY(qreal minimumFieldOfView READ minimumFieldOfView NOTIFY minimumFieldOfViewChanged)
+ Q_PROPERTY(qreal maximumFieldOfView READ maximumFieldOfView NOTIFY minimumFieldOfViewChanged)
+
+ Q_PROPERTY(QDeclarativeGeoMapType *activeMapType READ activeMapType WRITE setActiveMapType NOTIFY activeMapTypeChanged)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeGeoMapType> supportedMapTypes READ supportedMapTypes NOTIFY supportedMapTypesChanged)
+ Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
+ Q_PROPERTY(QList<QObject *> mapItems READ mapItems NOTIFY mapItemsChanged)
+ Q_PROPERTY(QList<QObject *> mapParameters READ mapParameters)
+ Q_PROPERTY(QGeoServiceProvider::Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(QGeoShape visibleRegion READ visibleRegion WRITE setVisibleRegion)
+ Q_PROPERTY(bool copyrightsVisible READ copyrightsVisible WRITE setCopyrightsVisible NOTIFY copyrightsVisibleChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+
+ explicit QDeclarativeGeoMap(QQuickItem *parent = 0);
+ ~QDeclarativeGeoMap();
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ void setActiveMapType(QDeclarativeGeoMapType *mapType);
+ QDeclarativeGeoMapType *activeMapType() const;
+
+ void setMinimumZoomLevel(qreal minimumZoomLevel);
+ qreal minimumZoomLevel() const;
+
+ void setMaximumZoomLevel(qreal maximumZoomLevel);
+ qreal maximumZoomLevel() const;
+
+ void setZoomLevel(qreal zoomLevel);
+ qreal zoomLevel() const;
+
+ void setBearing(qreal bearing);
+ qreal bearing() const;
+
+ void setTilt(qreal tilt);
+ qreal tilt() const;
+
+ void setFieldOfView(qreal fieldOfView);
+ qreal fieldOfView() const;
+ qreal minimumFieldOfView() const;
+ qreal maximumFieldOfView() const;
+
+ bool isBearingSupported() const;
+ bool isTiltingSupported() const;
+ qreal minimumTilt() const;
+ qreal maximumTilt() const;
+
+ void setCenter(const QGeoCoordinate &center);
+ QGeoCoordinate center() const;
+
+ void setVisibleRegion(const QGeoShape &shape);
+ QGeoShape visibleRegion() const;
+
+ void setCopyrightsVisible(bool visible);
+ bool copyrightsVisible() const;
+
+ void setColor(const QColor &color);
+ QColor color() const;
+
+ QQmlListProperty<QDeclarativeGeoMapType> supportedMapTypes();
+
+ Q_INVOKABLE void removeMapItem(QDeclarativeGeoMapItemBase *item);
+ Q_INVOKABLE void addMapItem(QDeclarativeGeoMapItemBase *item);
+
+ Q_INVOKABLE void clearMapItems();
+ QList<QObject *> mapItems();
+
+ Q_INVOKABLE void addMapParameter(QDeclarativeGeoMapParameter *parameter);
+ Q_INVOKABLE void removeMapParameter(QDeclarativeGeoMapParameter *parameter);
+ Q_INVOKABLE void clearMapParameters();
+ QList<QObject *> mapParameters();
+
+ Q_INVOKABLE QGeoCoordinate toCoordinate(const QPointF &position, bool clipToViewPort = true) const;
+ Q_INVOKABLE QPointF fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort = true) const;
+
+ QQuickGeoMapGestureArea *gesture();
+
+ Q_INVOKABLE void fitViewportToMapItems();
+ Q_INVOKABLE void pan(int dx, int dy);
+ Q_INVOKABLE void prefetchData(); // optional hint for prefetch
+ Q_INVOKABLE void clearData();
+
+ QString errorString() const;
+ QGeoServiceProvider::Error error() const;
+
+Q_SIGNALS:
+ void pluginChanged(QDeclarativeGeoServiceProvider *plugin);
+ void zoomLevelChanged(qreal zoomLevel);
+ void centerChanged(const QGeoCoordinate &coordinate);
+ void activeMapTypeChanged();
+ void supportedMapTypesChanged();
+ void minimumZoomLevelChanged();
+ void maximumZoomLevelChanged();
+ void mapItemsChanged();
+ void errorChanged();
+ void copyrightLinkActivated(const QString &link);
+ void copyrightsVisibleChanged(bool visible);
+ void colorChanged(const QColor &color);
+ void bearingChanged(qreal bearing);
+ void tiltChanged(qreal tilt);
+ void fieldOfViewChanged(qreal fieldOfView);
+ void bearingSupportChanged(bool bearingSupport);
+ void tiltingSupportChanged(bool tiltingSupport);
+ void minimumTiltChanged(qreal minimumTilt);
+ void maximumTiltChanged(qreal maximumTilt);
+ void minimumFieldOfViewChanged(qreal minimumFieldOfView);
+ void maximumFieldOfViewChanged(qreal maximumFieldOfView);
+
+protected:
+ void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE ;
+ void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE ;
+ void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE ;
+ void mouseUngrabEvent() Q_DECL_OVERRIDE ;
+ void touchUngrabEvent() Q_DECL_OVERRIDE;
+ void touchEvent(QTouchEvent *event) Q_DECL_OVERRIDE ;
+ void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE ;
+
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event) Q_DECL_OVERRIDE;
+ bool sendMouseEvent(QMouseEvent *event);
+ bool sendTouchEvent(QTouchEvent *event);
+
+ void componentComplete() Q_DECL_OVERRIDE;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+
+ void setError(QGeoServiceProvider::Error error, const QString &errorString);
+ void initialize();
+private Q_SLOTS:
+ void mappingManagerInitialized();
+ void pluginReady();
+ void onMapChildrenChanged();
+ void onSupportedMapTypesChanged();
+
+private:
+ void setupMapView(QDeclarativeGeoMapItemView *view);
+ void populateMap();
+ void populateParameters();
+ void fitViewportToMapItemsRefine(bool refine);
+ void fitViewportToGeoShape();
+ bool isInteractive();
+
+private:
+ QDeclarativeGeoServiceProvider *m_plugin;
+ QGeoMappingManager *m_mappingManager;
+ QDeclarativeGeoMapType *m_activeMapType;
+ QList<QDeclarativeGeoMapType *> m_supportedMapTypes;
+ QList<QDeclarativeGeoMapItemView *> m_mapViews;
+ QQuickGeoMapGestureArea *m_gestureArea;
+ QGeoMap *m_map;
+ QPointer<QDeclarativeGeoMapCopyrightNotice> m_copyrights;
+ QList<QPointer<QDeclarativeGeoMapItemBase> > m_mapItems;
+ QString m_errorString;
+ QGeoServiceProvider::Error m_error;
+ QGeoRectangle m_visibleRegion;
+ QColor m_color;
+ QGeoCameraData m_cameraData;
+ bool m_componentCompleted;
+ bool m_pendingFitViewport;
+ bool m_copyrightsVisible;
+ double m_maximumViewportLatitude;
+ bool m_initialized;
+ QSet<QDeclarativeGeoMapParameter *> m_mapParameters;
+
+ friend class QDeclarativeGeoMapItem;
+ friend class QDeclarativeGeoMapItemView;
+ friend class QQuickGeoMapGestureArea;
+ Q_DISABLE_COPY(QDeclarativeGeoMap)
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMap)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp
new file mode 100644
index 00000000..7b5a5765
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com>
+** 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 "qdeclarativegeomapcopyrightsnotice_p.h"
+
+#include <QtGui/QTextDocument>
+#include <QtGui/QAbstractTextDocumentLayout>
+#include <QtGui/QPainter>
+#include <QtQuick/private/qquickanchors_p.h>
+#include <QtQuick/private/qquickanchors_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeGeoMapCopyrightNotice::QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent)
+: QQuickPaintedItem(parent), m_copyrightsHtml(0), m_copyrightsVisible(true)
+{
+ QQuickAnchors *anchors = property("anchors").value<QQuickAnchors *>();
+ if (anchors) {
+ anchors->setLeft(QQuickAnchorLine(parent, QQuickAnchors::LeftAnchor));
+ anchors->setBottom(QQuickAnchorLine(parent, QQuickAnchors::BottomAnchor));
+ }
+}
+
+QDeclarativeGeoMapCopyrightNotice::~QDeclarativeGeoMapCopyrightNotice()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::paint(QPainter *painter)
+{
+ painter->drawImage(0, 0, m_copyrightsImage);
+}
+
+void QDeclarativeGeoMapCopyrightNotice::mousePressEvent(QMouseEvent *event)
+{
+ if (m_copyrightsHtml) {
+ m_activeAnchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos());
+ if (!m_activeAnchor.isEmpty())
+ return;
+ }
+
+ QQuickPaintedItem::mousePressEvent(event);
+}
+
+void QDeclarativeGeoMapCopyrightNotice::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (m_copyrightsHtml) {
+ QString anchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos());
+ if (anchor == m_activeAnchor && !anchor.isEmpty()) {
+ emit linkActivated(anchor);
+ m_activeAnchor.clear();
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::setCopyrightsVisible(bool visible)
+{
+ m_copyrightsVisible = visible;
+
+ setVisible(!m_copyrightsImage.isNull() && visible);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::setCopyrightsZ(int copyrightsZ)
+{
+ setZ(copyrightsZ);
+ update();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QImage &copyrightsImage)
+{
+ delete m_copyrightsHtml;
+ m_copyrightsHtml = 0;
+
+ m_copyrightsImage = copyrightsImage;
+
+ setWidth(m_copyrightsImage.width());
+ setHeight(m_copyrightsImage.height());
+
+ setKeepMouseGrab(false);
+ setAcceptedMouseButtons(Qt::NoButton);
+ setVisible(m_copyrightsVisible);
+
+ update();
+}
+
+void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QString &copyrightsHtml)
+{
+ if (copyrightsHtml.isEmpty() || !m_copyrightsVisible) {
+ m_copyrightsImage = QImage();
+ setVisible(false);
+ return;
+ } else {
+ setVisible(true);
+ }
+
+ if (!m_copyrightsHtml)
+ m_copyrightsHtml = new QTextDocument(this);
+
+ m_copyrightsHtml->setHtml(copyrightsHtml);
+
+ m_copyrightsImage = QImage(m_copyrightsHtml->size().toSize(),
+ QImage::Format_ARGB32_Premultiplied);
+ m_copyrightsImage.fill(qPremultiply(qRgba(255, 255, 255, 128)));
+
+ QPainter painter(&m_copyrightsImage);
+ //m_copyrightsHtml->drawContents(&painter); // <- this uses the default application palette, that might have, f.ex., white text
+ QAbstractTextDocumentLayout::PaintContext ctx;
+ ctx.palette.setColor(QPalette::Text, QColor(QStringLiteral("black")));
+ ctx.palette.setColor(QPalette::Link, QColor(QStringLiteral("blue")));
+ m_copyrightsHtml->documentLayout()->draw(&painter, ctx);
+
+ setWidth(m_copyrightsImage.width());
+ setHeight(m_copyrightsImage.height());
+
+ setContentsSize(m_copyrightsImage.size());
+
+ setKeepMouseGrab(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+
+ update();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
new file mode 100644
index 00000000..1aeef7c1
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com>
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPCOPYRIGHTSNOTICE_H
+#define QDECLARATIVEGEOMAPCOPYRIGHTSNOTICE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtGui/QImage>
+#include <QtQuick/QQuickPaintedItem>
+
+QT_BEGIN_NAMESPACE
+
+class QTextDocument;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapCopyrightNotice : public QQuickPaintedItem
+{
+ Q_OBJECT
+
+public:
+ explicit QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent);
+ ~QDeclarativeGeoMapCopyrightNotice();
+
+ void setCopyrightsZ(int copyrightsZ);
+
+ void setCopyrightsVisible(bool visible);
+
+public Q_SLOTS:
+ void copyrightsChanged(const QImage &copyrightsImage);
+ void copyrightsChanged(const QString &copyrightsHtml);
+
+signals:
+ void linkActivated(const QString &link);
+
+protected:
+ void paint(QPainter *painter) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+ void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+
+private:
+ QTextDocument *m_copyrightsHtml;
+ QImage m_copyrightsImage;
+ QString m_activeAnchor;
+ bool m_copyrightsVisible;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
new file mode 100644
index 00000000..93d07386
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeomapitembase_p.h"
+#include "qgeocameradata_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+#include <QtQml/QQmlInfo>
+#include <QtQuick/QSGOpacityNode>
+#include <QtQuick/private/qquickmousearea_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent()
+ : zoomLevelChanged(false),
+ centerChanged(false),
+ mapSizeChanged(false),
+ tiltChanged(false),
+ bearingChanged(false),
+ rollChanged(false)
+{
+}
+
+QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent(const QGeoMapViewportChangeEvent &other)
+{
+ this->operator=(other);
+}
+
+QGeoMapViewportChangeEvent &QGeoMapViewportChangeEvent::operator=(const QGeoMapViewportChangeEvent &other)
+{
+ if (this == &other)
+ return (*this);
+
+ cameraData = other.cameraData;
+ mapSize = other.mapSize;
+ zoomLevelChanged = other.zoomLevelChanged;
+ centerChanged = other.centerChanged;
+ mapSizeChanged = other.mapSizeChanged;
+ tiltChanged = other.tiltChanged;
+ bearingChanged = other.bearingChanged;
+ rollChanged = other.rollChanged;
+
+ return (*this);
+}
+
+QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent)
+: QQuickItem(parent), map_(0), quickMap_(0)
+{
+ setFiltersChildMouseEvents(true);
+ connect(this, SIGNAL(childrenChanged()),
+ this, SLOT(afterChildrenChanged()));
+}
+
+QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase()
+{
+ disconnect(this, SLOT(afterChildrenChanged()));
+ if (quickMap_)
+ quickMap_->removeMapItem(this);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemBase::afterChildrenChanged()
+{
+ QList<QQuickItem *> kids = childItems();
+ if (kids.size() > 0) {
+ bool printedWarning = false;
+ foreach (QQuickItem *i, kids) {
+ if (i->flags() & QQuickItem::ItemHasContents
+ && !qobject_cast<QQuickMouseArea *>(i)) {
+ if (!printedWarning) {
+ qmlWarning(this) << "Geographic map items do not support child items";
+ printedWarning = true;
+ }
+
+ qmlWarning(i) << "deleting this child";
+ i->deleteLater();
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ if (quickMap == quickMap_)
+ return;
+ if (quickMap && quickMap_)
+ return; // don't allow association to more than one map
+ if (quickMap_)
+ quickMap_->disconnect(this);
+ if (map_)
+ map_->disconnect(this);
+
+ quickMap_ = quickMap;
+ map_ = map;
+
+ if (map_ && quickMap_) {
+ connect(map_, SIGNAL(cameraDataChanged(QGeoCameraData)),
+ this, SLOT(baseCameraDataChanged(QGeoCameraData)));
+ connect(quickMap, SIGNAL(heightChanged()), this, SLOT(polishAndUpdate()));
+ connect(quickMap, SIGNAL(widthChanged()), this, SLOT(polishAndUpdate()));
+ lastSize_ = QSizeF(quickMap_->width(), quickMap_->height());
+ lastCameraData_ = map_->cameraData();
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemBase::baseCameraDataChanged(const QGeoCameraData &cameraData)
+{
+ QGeoMapViewportChangeEvent evt;
+ evt.cameraData = cameraData;
+ evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
+
+ if (evt.mapSize != lastSize_)
+ evt.mapSizeChanged = true;
+
+ if (cameraData.bearing() != lastCameraData_.bearing())
+ evt.bearingChanged = true;
+ if (cameraData.center() != lastCameraData_.center())
+ evt.centerChanged = true;
+ if (cameraData.roll() != lastCameraData_.roll())
+ evt.rollChanged = true;
+ if (cameraData.tilt() != lastCameraData_.tilt())
+ evt.tiltChanged = true;
+ if (cameraData.zoomLevel() != lastCameraData_.zoomLevel())
+ evt.zoomLevelChanged = true;
+
+ lastSize_ = evt.mapSize;
+ lastCameraData_ = cameraData;
+
+ afterViewportChanged(evt);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset)
+{
+ if (!map_ || !quickMap_)
+ return;
+
+ QDoubleVector2D wrappedProjection = map_->geoProjection().geoToWrappedMapProjection(coordinate);
+ if (! map_->geoProjection().isProjectable(wrappedProjection))
+ return;
+
+ QDoubleVector2D pos = map_->geoProjection().wrappedMapProjectionToItemPosition(wrappedProjection);
+ QPointF topLeft = pos.toPointF() - offset;
+
+ setPosition(topLeft);
+}
+
+static const double opacityRampMin = 1.5;
+static const double opacityRampMax = 2.5;
+/*!
+ \internal
+*/
+float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const
+{
+ if (quickMap_->zoomLevel() > opacityRampMax)
+ return 1.0;
+ else if (quickMap_->zoomLevel() > opacityRampMin)
+ return quickMap_->zoomLevel() - opacityRampMin;
+ else
+ return 0.0;
+}
+
+bool QDeclarativeGeoMapItemBase::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ Q_UNUSED(item)
+ if (event->type() == QEvent::MouseButtonPress && !contains(static_cast<QMouseEvent*>(event)->pos())) {
+ // This is an evil hack: in case of items that are not rectangles, we never accept the event.
+ // Instead the events are now delivered to QDeclarativeGeoMapItemBase which doesn't to anything with them.
+ // The map below it still works since it filters events and steals the events at some point.
+ event->setAccepted(false);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativeGeoMapItemBase::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *pd)
+{
+ if (!map_ || !quickMap_) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGOpacityNode *opn = static_cast<QSGOpacityNode *>(oldNode);
+ if (!opn)
+ opn = new QSGOpacityNode();
+
+ opn->setOpacity(zoomLevelOpacity());
+
+ QSGNode *oldN = opn->childCount() ? opn->firstChild() : 0;
+ opn->removeAllChildNodes();
+ if (opn->opacity() > 0.0) {
+ QSGNode *n = this->updateMapItemPaintNode(oldN, pd);
+ if (n)
+ opn->appendChildNode(n);
+ } else {
+ delete oldN;
+ }
+
+ return opn;
+}
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ delete oldNode;
+ return 0;
+}
+
+bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
+{
+ return QQuickItemPrivate::get(this)->polishScheduled;
+}
+
+void QDeclarativeGeoMapItemBase::polishAndUpdate()
+{
+ polish();
+ update();
+}
+
+
+#include "moc_qdeclarativegeomapitembase_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
new file mode 100644
index 00000000..82a24233
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPITEMBASE_H
+#define QDECLARATIVEGEOMAPITEMBASE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtQuick/QQuickItem>
+#include <QtPositioning/QGeoShape>
+
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qlocationglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QGeoMapViewportChangeEvent
+{
+public:
+ explicit QGeoMapViewportChangeEvent();
+ QGeoMapViewportChangeEvent(const QGeoMapViewportChangeEvent &other);
+ QGeoMapViewportChangeEvent &operator=(const QGeoMapViewportChangeEvent &other);
+
+ QGeoCameraData cameraData;
+ QSizeF mapSize;
+
+ bool zoomLevelChanged;
+ bool centerChanged;
+ bool mapSizeChanged;
+ bool tiltChanged;
+ bool bearingChanged;
+ bool rollChanged;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QGeoShape geoShape READ geoShape STORED false )
+public:
+ explicit QDeclarativeGeoMapItemBase(QQuickItem *parent = 0);
+ virtual ~QDeclarativeGeoMapItemBase();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map);
+ virtual void setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset);
+
+ QDeclarativeGeoMap *quickMap() { return quickMap_; }
+ QGeoMap *map() { return map_; }
+ virtual const QGeoShape &geoShape() const = 0;
+
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *);
+
+protected Q_SLOTS:
+ virtual void afterChildrenChanged();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) = 0;
+ void polishAndUpdate();
+
+protected:
+ float zoomLevelOpacity() const;
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event);
+ bool isPolishScheduled() const;
+
+private Q_SLOTS:
+ void baseCameraDataChanged(const QGeoCameraData &camera);
+
+private:
+ QGeoMap *map_;
+ QDeclarativeGeoMap *quickMap_;
+
+ QSizeF lastSize_;
+ QGeoCameraData lastCameraData_;
+
+ friend class QDeclarativeGeoMap;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp
new file mode 100644
index 00000000..cb1a4348
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp
@@ -0,0 +1,541 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Jolla Ltd.
+** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
+** 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 "qdeclarativegeomapitemview_p.h"
+#include "qdeclarativegeomapitemview_p_p.h"
+#include "qdeclarativegeomap_p.h"
+#include "qdeclarativegeomapitembase_p.h"
+#include "mapitemviewdelegateincubator_p.h"
+
+#include <QtCore/QAbstractItemModel>
+#include <QtQml/QQmlContext>
+#include <QtQml/QQmlIncubator>
+#include <QtQml/private/qqmlopenmetaobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapItemView
+ \instantiates QDeclarativeGeoMapItemView
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+ \inherits QObject
+
+ \brief The MapItemView is used to populate Map from a model.
+
+ The MapItemView is used to populate Map with MapItems from a model.
+ The MapItemView type only makes sense when contained in a Map,
+ meaning that it has no standalone presentation.
+
+ \section2 Example Usage
+
+ This example demonstrates how to use the MapViewItem object to display
+ a \l{Route}{route} on a \l{Map}{map}:
+
+ \snippet declarative/maps.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/maps.qml MapRoute
+*/
+
+QDeclarativeGeoMapItemView::QDeclarativeGeoMapItemView(QQuickItem *parent)
+ : QObject(parent), componentCompleted_(false), delegate_(0),
+ itemModel_(0), map_(0), fitViewport_(false), m_metaObjectType(0),
+ m_readyIncubators(0), m_repopulating(false)
+{
+}
+
+QDeclarativeGeoMapItemView::~QDeclarativeGeoMapItemView()
+{
+ removeInstantiatedItems();
+ if (m_metaObjectType)
+ m_metaObjectType->release();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::componentComplete()
+{
+ componentCompleted_ = true;
+}
+
+void QDeclarativeGeoMapItemView::incubatorStatusChanged(MapItemViewDelegateIncubator *incubator,
+ QQmlIncubator::Status status,
+ bool batched)
+{
+ if (status == QQmlIncubator::Loading)
+ return;
+
+ QDeclarativeGeoMapItemViewItemData *itemData = incubator->m_itemData;
+ if (!itemData) {
+ // Should never get here
+ qWarning() << "MapItemViewDelegateIncubator incubating invalid itemData";
+ return;
+ }
+
+ switch (status) {
+ case QQmlIncubator::Ready:
+ {
+ QDeclarativeGeoMapItemBase *item = qobject_cast<QDeclarativeGeoMapItemBase *>(incubator->object());
+ if (!item)
+ break;
+ itemData->item = item;
+ if (!itemData->item) {
+ qWarning() << "QDeclarativeGeoMapItemView map item delegate is of unsupported type.";
+ delete incubator->object();
+ } else {
+ if (!batched) {
+ map_->addMapItem(itemData->item);
+ fitViewport();
+ } else {
+ ++m_readyIncubators; // QSemaphore not needed as multiple threads not involved
+
+ if (m_readyIncubators == m_itemDataBatched.size()) {
+
+ // Clearing stuff older than the reset
+ foreach (QDeclarativeGeoMapItemViewItemData *i, m_itemData)
+ removeItemData(i);
+ m_itemData.clear();
+
+ // Adding everthing created after reset was issued
+ foreach (QDeclarativeGeoMapItemViewItemData *i, m_itemDataBatched) {
+ map_->addMapItem(i->item);
+ }
+ m_itemData = m_itemDataBatched;
+ m_itemDataBatched.clear();
+
+ m_readyIncubators = 0;
+ m_repopulating = false;
+
+ fitViewport();
+ }
+ }
+ }
+ delete itemData->incubator;
+ itemData->incubator = 0;
+ break;
+ }
+ case QQmlIncubator::Null:
+ // Should never get here
+ delete itemData->incubator;
+ itemData->incubator = 0;
+ break;
+ case QQmlIncubator::Error:
+ qWarning() << "QDeclarativeGeoMapItemView map item creation failed.";
+ delete itemData->incubator;
+ itemData->incubator = 0;
+ break;
+ default:
+ ;
+ }
+}
+
+/*!
+ \qmlproperty model QtLocation::MapItemView::model
+
+ This property holds the model that provides data used for creating the map items defined by the
+ delegate. Only QAbstractItemModel based models are supported.
+*/
+QVariant QDeclarativeGeoMapItemView::model() const
+{
+ return QVariant::fromValue(itemModel_);
+}
+
+void QDeclarativeGeoMapItemView::setModel(const QVariant &model)
+{
+ QAbstractItemModel *itemModel = model.value<QAbstractItemModel *>();
+ if (itemModel == itemModel_)
+ return;
+
+ if (itemModel_) {
+ disconnect(itemModel_, SIGNAL(modelReset()), this, SLOT(itemModelReset()));
+ disconnect(itemModel_, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(itemModelRowsRemoved(QModelIndex,int,int)));
+ disconnect(itemModel_, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(itemModelRowsInserted(QModelIndex,int,int)));
+ disconnect(itemModel_, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(itemModelRowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ disconnect(itemModel_, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
+ this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>)));
+
+ removeInstantiatedItems(); // this also terminates ongong repopulations.
+ m_metaObjectType->release();
+ m_metaObjectType = 0;
+
+ itemModel_ = 0;
+ }
+
+ if (itemModel) {
+ itemModel_ = itemModel;
+ connect(itemModel_, SIGNAL(modelReset()), this, SLOT(itemModelReset()));
+ connect(itemModel_, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(itemModelRowsRemoved(QModelIndex,int,int)));
+ connect(itemModel_, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(itemModelRowsInserted(QModelIndex,int,int)));
+ connect(itemModel_, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(itemModelRowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ connect(itemModel_, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
+ this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>)));
+
+ m_metaObjectType = new QQmlOpenMetaObjectType(&QObject::staticMetaObject, 0);
+ foreach (const QByteArray &name, itemModel_->roleNames())
+ m_metaObjectType->createProperty(name);
+
+ instantiateAllItems();
+ }
+
+ emit modelChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::itemModelReset()
+{
+ repopulate();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::itemModelRowsInserted(const QModelIndex &index, int start, int end)
+{
+ Q_UNUSED(index)
+
+ if (!componentCompleted_ || !map_ || !delegate_ || !itemModel_)
+ return;
+
+ for (int i = start; i <= end; ++i) {
+ const QModelIndex insertedIndex = itemModel_->index(i, 0, index);
+ // If ran inside a qquickwidget which forces incubators to be synchronous, this call won't happen
+ // with m_repopulating == true while incubators from a model reset are still incubating.
+ // Note that having the model in a different thread is not supported in general.
+ createItemForIndex(insertedIndex, m_repopulating);
+ }
+
+ fitViewport();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::itemModelRowsRemoved(const QModelIndex &index, int start, int end)
+{
+ Q_UNUSED(index)
+
+ if (!componentCompleted_ || !map_ || !delegate_ || !itemModel_)
+ return;
+
+ for (int i = end; i >= start; --i) {
+ if (m_repopulating) {
+ QDeclarativeGeoMapItemViewItemData *itemData = m_itemDataBatched.takeAt(i);
+ if (!itemData)
+ continue;
+ if (itemData->incubator) {
+ if (itemData->incubator->isReady()) {
+ --m_readyIncubators;
+ delete itemData->incubator->object();
+ }
+ itemData->incubator->clear();
+ }
+ delete itemData;
+ } else {
+ QDeclarativeGeoMapItemViewItemData *itemData = m_itemData.takeAt(i);
+ removeItemData(itemData);
+ }
+ }
+
+ fitViewport();
+}
+
+void QDeclarativeGeoMapItemView::itemModelRowsMoved(const QModelIndex &parent, int start, int end,
+ const QModelIndex &destination, int row)
+{
+ Q_UNUSED(parent)
+ Q_UNUSED(start)
+ Q_UNUSED(end)
+ Q_UNUSED(destination)
+ Q_UNUSED(row)
+
+ qWarning() << "QDeclarativeGeoMapItemView does not support models that move rows.";
+}
+
+void QDeclarativeGeoMapItemView::itemModelDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight,
+ const QVector<int> &roles)
+{
+ Q_UNUSED(roles)
+
+ if (!m_itemData.count() || (m_repopulating && !m_itemDataBatched.count()) )
+ return;
+
+ for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
+ const QModelIndex index = itemModel_->index(i, 0);
+ QDeclarativeGeoMapItemViewItemData *itemData;
+ if (m_repopulating)
+ itemData= m_itemDataBatched.at(i);
+ else
+ itemData= m_itemData.at(i);
+
+ QHashIterator<int, QByteArray> iterator(itemModel_->roleNames());
+ while (iterator.hasNext()) {
+ iterator.next();
+
+ QVariant modelData = itemModel_->data(index, iterator.key());
+ if (!modelData.isValid())
+ continue;
+
+ itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()),
+ modelData);
+ itemData->modelDataMeta->setValue(iterator.value(), modelData);
+ }
+ }
+}
+
+/*!
+ \qmlproperty Component QtLocation::MapItemView::delegate
+
+ This property holds the delegate which defines how each item in the
+ model should be displayed. The Component must contain exactly one
+ MapItem -derived object as the root object.
+*/
+QQmlComponent *QDeclarativeGeoMapItemView::delegate() const
+{
+ return delegate_;
+}
+
+void QDeclarativeGeoMapItemView::setDelegate(QQmlComponent *delegate)
+{
+ if (delegate_ == delegate)
+ return;
+
+ delegate_ = delegate;
+
+ repopulate();
+ emit delegateChanged();
+}
+
+/*!
+ \qmlproperty Component QtLocation::MapItemView::autoFitViewport
+
+ This property controls whether to automatically pan and zoom the viewport
+ to display all map items when items are added or removed.
+
+ Defaults to false.
+*/
+bool QDeclarativeGeoMapItemView::autoFitViewport() const
+{
+ return fitViewport_;
+}
+
+void QDeclarativeGeoMapItemView::setAutoFitViewport(const bool &fitViewport)
+{
+ if (fitViewport == fitViewport_)
+ return;
+ fitViewport_ = fitViewport;
+ emit autoFitViewportChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::fitViewport()
+{
+ if (!map_ || !fitViewport_ || m_repopulating)
+ return;
+
+ if (map_->mapItems().size() > 0)
+ map_->fitViewportToMapItems();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::setMap(QDeclarativeGeoMap *map)
+{
+ if (!map || map_) // changing map on the fly not supported
+ return;
+ map_ = map;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::removeInstantiatedItems()
+{
+ if (!map_)
+ return;
+
+ terminateOngoingRepopulation();
+ foreach (QDeclarativeGeoMapItemViewItemData *itemData, m_itemData)
+ removeItemData(itemData);
+ m_itemData.clear();
+}
+
+/*!
+ \internal
+
+ Instantiates all items.
+*/
+void QDeclarativeGeoMapItemView::instantiateAllItems()
+{
+ if (!componentCompleted_ || !map_ || !delegate_ || !itemModel_)
+ return;
+ Q_ASSERT(!m_itemDataBatched.size());
+ m_repopulating = true;
+
+ // QQuickWidget forces incubators to synchronous mode. Thus itemDataChanged gets called during the for loop below.
+ m_itemDataBatched.resize(itemModel_->rowCount());
+ for (int i = 0; i < itemModel_->rowCount(); ++i) {
+ const QModelIndex index = itemModel_->index(i, 0);
+ createItemForIndex(index, true);
+ }
+
+ fitViewport();
+}
+
+void QDeclarativeGeoMapItemView::removeItemData(QDeclarativeGeoMapItemViewItemData *itemData)
+{
+ if (!itemData)
+ return;
+ if (itemData->incubator) {
+ if (itemData->incubator->isReady()) {
+ if (itemData->incubator->object() == itemData->item) {
+ map_->removeMapItem(itemData->item); // removeMapItem checks whether the item is in the map, so it's safe to call.
+ itemData->item = 0;
+ }
+ delete itemData->incubator->object();
+ }
+ itemData->incubator->clear(); // stops ongoing incubation
+ }
+ if (itemData->item)
+ map_->removeMapItem(itemData->item);
+ delete itemData; // destroys the ->item too.
+}
+
+void QDeclarativeGeoMapItemView::terminateOngoingRepopulation()
+{
+ if (m_repopulating) {
+ // Terminate the previous resetting task. Not all incubators finished, but
+ // QQmlIncubatorController operates in the same thread, so it is safe
+ // to check, here, whether incubators are ready or not, without having
+ // to race with them.
+
+ foreach (QDeclarativeGeoMapItemViewItemData *itemData, m_itemDataBatched)
+ removeItemData(itemData);
+
+ m_itemDataBatched.clear();
+ m_readyIncubators = 0;
+ m_repopulating = false;
+ }
+}
+
+/*!
+ \internal
+ Removes and repopulates all items.
+*/
+void QDeclarativeGeoMapItemView::repopulate()
+{
+ if (!itemModel_ || !itemModel_->rowCount()) {
+ removeInstantiatedItems();
+ } else {
+ terminateOngoingRepopulation();
+ instantiateAllItems(); // removal of instantiated item done at incubation completion
+ }
+}
+
+/*!
+ \internal
+
+ Note: this call is async. that is returns to the event loop before returning to the caller.
+ May also trigger incubatorStatusChanged() before returning to the caller if the incubator is fast enough.
+*/
+void QDeclarativeGeoMapItemView::createItemForIndex(const QModelIndex &index, bool batched)
+{
+ // Expected to be already tested by caller.
+ Q_ASSERT(delegate_);
+ Q_ASSERT(itemModel_);
+
+ QDeclarativeGeoMapItemViewItemData *itemData = new QDeclarativeGeoMapItemViewItemData;
+
+ itemData->modelData = new QObject;
+ itemData->modelDataMeta = new QQmlOpenMetaObject(itemData->modelData, m_metaObjectType, false);
+ itemData->context = new QQmlContext(qmlContext(this));
+
+ QHashIterator<int, QByteArray> iterator(itemModel_->roleNames());
+ while (iterator.hasNext()) {
+ iterator.next();
+
+ QVariant modelData = itemModel_->data(index, iterator.key());
+ if (!modelData.isValid())
+ continue;
+
+ itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()),
+ modelData);
+
+ itemData->modelDataMeta->setValue(iterator.value(), modelData);
+ }
+
+ itemData->context->setContextProperty(QLatin1String("model"), itemData->modelData);
+ itemData->context->setContextProperty(QLatin1String("index"), index.row());
+
+ if (batched || m_repopulating) {
+ if (index.row() < m_itemDataBatched.size())
+ m_itemDataBatched.replace(index.row(), itemData);
+ else
+ m_itemDataBatched.insert(index.row(), itemData);
+ } else
+ m_itemData.insert(index.row(), itemData);
+ itemData->incubator = new MapItemViewDelegateIncubator(this, itemData, batched || m_repopulating);
+
+ delegate_->create(*itemData->incubator, itemData->context);
+}
+
+QDeclarativeGeoMapItemViewItemData::~QDeclarativeGeoMapItemViewItemData()
+{
+ delete incubator;
+ delete item;
+ delete context;
+ delete modelData;
+}
+
+#include "moc_qdeclarativegeomapitemview_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h
new file mode 100644
index 00000000..bd696d6e
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Jolla Ltd.
+** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPITEMVIEW_H
+#define QDECLARATIVEGEOMAPITEMVIEW_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtCore/QModelIndex>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlIncubator>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractItemModel;
+class QQmlComponent;
+class QQuickItem;
+class QDeclarativeGeoMap;
+class QDeclarativeGeoMapItemBase;
+class QQmlOpenMetaObject;
+class QQmlOpenMetaObjectType;
+class MapItemViewDelegateIncubator;
+class QDeclarativeGeoMapItemViewItemData;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemView : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+
+ Q_INTERFACES(QQmlParserStatus)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(bool autoFitViewport READ autoFitViewport WRITE setAutoFitViewport NOTIFY autoFitViewportChanged)
+
+public:
+ explicit QDeclarativeGeoMapItemView(QQuickItem *parent = 0);
+ ~QDeclarativeGeoMapItemView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *);
+
+ bool autoFitViewport() const;
+ void setAutoFitViewport(const bool &);
+
+ void setMap(QDeclarativeGeoMap *);
+ void repopulate();
+ void removeInstantiatedItems();
+ void instantiateAllItems();
+
+ qreal zValue();
+ void setZValue(qreal zValue);
+
+ // From QQmlParserStatus
+ virtual void componentComplete();
+ void classBegin() {}
+
+Q_SIGNALS:
+ void modelChanged();
+ void delegateChanged();
+ void autoFitViewportChanged();
+
+protected:
+ void incubatorStatusChanged(MapItemViewDelegateIncubator *incubator,
+ QQmlIncubator::Status status,
+ bool batched);
+
+private Q_SLOTS:
+ void itemModelReset();
+ void itemModelRowsInserted(const QModelIndex &index, int start, int end);
+ void itemModelRowsRemoved(const QModelIndex &index, int start, int end);
+ void itemModelRowsMoved(const QModelIndex &parent, int start, int end,
+ const QModelIndex &destination, int row);
+ void itemModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QVector<int> &roles);
+
+private:
+ void createItemForIndex(const QModelIndex &index, bool batched = false);
+ void fitViewport();
+ void terminateOngoingRepopulation();
+ void removeItemData(QDeclarativeGeoMapItemViewItemData *itemData);
+
+ bool componentCompleted_;
+ QQmlComponent *delegate_;
+ QAbstractItemModel *itemModel_;
+ QDeclarativeGeoMap *map_;
+ QVector<QDeclarativeGeoMapItemViewItemData *> m_itemData;
+ QVector<QDeclarativeGeoMapItemViewItemData *> m_itemDataBatched;
+ bool fitViewport_;
+
+ QQmlOpenMetaObjectType *m_metaObjectType;
+ int m_readyIncubators;
+ bool m_repopulating;
+
+ friend struct QDeclarativeGeoMapItemViewItemData;
+ friend class MapItemViewDelegateIncubator;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapItemView)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h
new file mode 100644
index 00000000..3ad3ceb4
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPITEMVIEW_P_P_H
+#define QDECLARATIVEGEOMAPITEMVIEW_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QModelIndex>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlIncubator>
+#include <QtQml/qqml.h>
+#include <QtQml/private/qqmlopenmetaobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class MapItemViewDelegateIncubator;
+class QDeclarativeGeoMapItemView;
+class QDeclarativeGeoMapItemBase;
+
+class QDeclarativeGeoMapItemViewItemData
+{
+public:
+ QDeclarativeGeoMapItemViewItemData()
+ : incubator(0), item(0), context(0), modelData(0), modelDataMeta(0)
+ {
+ }
+
+ ~QDeclarativeGeoMapItemViewItemData();
+
+ MapItemViewDelegateIncubator *incubator;
+ QDeclarativeGeoMapItemBase *item;
+ QQmlContext *context;
+ QObject *modelData;
+ QQmlOpenMetaObject *modelDataMeta;
+
+ friend class MapItemViewDelegateIncubator;
+ friend class QDeclarativeGeoMapItemView;
+};
+
+Q_DECLARE_TYPEINFO(QDeclarativeGeoMapItemViewItemData, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEGEOMAPITEMVIEW_P_P_H
diff --git a/src/location/declarativemaps/qdeclarativegeomapparameter.cpp b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp
new file mode 100644
index 00000000..88d609f4
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "qdeclarativegeomapparameter_p.h"
+
+#include <QByteArray>
+#include <QMetaObject>
+#include <QMetaProperty>
+#include <QSignalMapper>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapParameter
+ \instantiates QDeclarativeGeoMapParameter
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.9
+
+ \brief The MapParameter type represents a parameter for a Map element.
+ This type provides a mean to specify plugin-dependent optional parameters
+ for a map.
+
+ MapParameters by default contain only the \l type property, and
+ are highly plugin-dependent.
+ For this reason, additional properties have to be defined inside a
+ MapParameter at declaration time, using the QML syntax "property var foo".
+
+ What properties have to be put inside a particular MapParameter type for
+ a particular plugin can be found in the documentation of the plugin.
+ Note that MapProperties are \b optional.
+ By not specifying any of them, the Map will have the default behavior.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+*/
+
+/*!
+ \qmlproperty georectangle QtLocation::MapParameter::type
+
+ Set-once property which holds a string defining the type of the MapParameter
+*/
+
+QDeclarativeGeoMapParameter::QDeclarativeGeoMapParameter(QObject *parent)
+: QGeoMapParameter(parent), m_initialPropertyCount(metaObject()->propertyCount()), m_complete(false)
+{
+
+}
+
+QDeclarativeGeoMapParameter::~QDeclarativeGeoMapParameter()
+{
+}
+
+bool QDeclarativeGeoMapParameter::isComponentComplete() const
+{
+ return m_complete;
+}
+
+int QDeclarativeGeoMapParameter::initialPropertyCount() const
+{
+ return m_initialPropertyCount;
+}
+
+void QDeclarativeGeoMapParameter::classBegin()
+{
+}
+
+void QDeclarativeGeoMapParameter::componentComplete()
+{
+ for (int i = m_initialPropertyCount; i < metaObject()->propertyCount(); ++i) {
+ QMetaProperty property = metaObject()->property(i);
+
+ if (!property.hasNotifySignal()) {
+ return;
+ }
+
+ QSignalMapper *mapper = new QSignalMapper(this);
+ mapper->setMapping(this, i);
+
+ const QByteArray signalName = '2' + property.notifySignal().methodSignature(); // TODO: explain why '2'
+ QObject::connect(this, signalName, mapper, SLOT(map()));
+ QObject::connect(mapper, SIGNAL(mapped(int)), this, SLOT(onPropertyUpdated(int)));
+ }
+ m_complete = true;
+ emit completed(this);
+}
+
+void QDeclarativeGeoMapParameter::onPropertyUpdated(int index)
+{
+ emit propertyUpdated(this, metaObject()->property(index).name());
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapparameter_p.h b/src/location/declarativemaps/qdeclarativegeomapparameter_p.h
new file mode 100644
index 00000000..0f54e1b7
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapparameter_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPPARAMETER_P_H
+#define QDECLARATIVEGEOMAPPARAMETER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qgeomapparameter_p.h>
+#include <QQmlParserStatus>
+#include <qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapParameter : public QGeoMapParameter, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativeGeoMapParameter(QObject *parent = 0);
+ virtual ~QDeclarativeGeoMapParameter();
+
+ bool isComponentComplete() const;
+
+Q_SIGNALS:
+ void completed(QDeclarativeGeoMapParameter *);
+
+protected:
+ int initialPropertyCount() const;
+ // QQmlParserStatus implementation
+ void classBegin() override;
+ void componentComplete() override;
+
+private slots:
+ void onPropertyUpdated(int index);
+
+private:
+ int m_initialPropertyCount;
+ bool m_complete;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapParameter)
+
+#endif // QDECLARATIVEGEOMAPPARAMETER_P_H
diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp
new file mode 100644
index 00000000..b3b8aa8a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeomapquickitem_p.h"
+
+#include <QtCore/QScopedValueRollback>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/QSGOpacityNode>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtQuick/private/qquickmousearea_p.h>
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <QDebug>
+#include <cmath>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapQuickItem
+ \instantiates QDeclarativeGeoMapQuickItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapQuickItem type displays an arbitrary Qt Quick object
+ on a Map.
+
+ The MapQuickItem type is used to place an arbitrary Qt Quick object
+ on a Map at a specified location and size. Compared to floating an item
+ above the Map, a MapQuickItem will follow the panning (and optionally, the
+ zooming) of the Map as if it is on the Map surface.
+
+ The \l{sourceItem} property contains the Qt Quick item to be drawn, which
+ can be any kind of visible type.
+
+ \section2 Positioning and Sizing
+
+ The positioning of the MapQuickItem on the Map is controlled by two
+ properties: \l coordinate and \l anchorPoint. If only \l coordinate is set,
+ it specifies a longitude/latitude coordinate for the item to be placed at.
+ The set coordinate will line up with the top-left corner of the contained
+ item when shown on the screen.
+
+ The \l anchorPoint property provides a way to line up the coordinate with
+ other parts of the item than just the top-left corner, by setting a number
+ of pixels the item will be offset by. A simple way to think about it is
+ to note that the point given by \l anchorPoint on the item itself is the
+ point that will line up with the given \l coordinate when displayed.
+
+ In addition to being anchored to the map, the MapQuickItem can optionally
+ follow the scale of the map, and change size when the Map is zoomed in or
+ zoomed out. This behaviour is controlled by the \l zoomLevel property. The
+ default behaviour if \l zoomLevel is not set is for the item to be drawn
+ "on the screen" rather than "on the map", so that its size remains the same
+ regardless of the zoom level of the Map.
+
+ \section2 Performance
+
+ Performance of a MapQuickItem is normally in the same ballpark as the
+ contained Qt Quick item alone. Overheads added amount to a translation
+ and (possibly) scaling of the original item, as well as a transformation
+ from longitude and latitude to screen position.
+
+ \section2 Limitations
+
+ \note Due to an implementation detail, items placed inside a
+ MapQuickItem will have a \c{parent} item which is not the MapQuickItem.
+ Refer to the MapQuickItem by its \c{id}, and avoid the use of \c{anchor}
+ in the \c{sourceItem}.
+
+ \section2 Example Usage
+
+ The following snippet shows a MapQuickItem containing an Image object,
+ to display a Marker on the Map. This strategy is used to show the map
+ markers in the MapViewer example.
+
+ \snippet mapviewer/map/Marker.qml mqi-top
+ \snippet mapviewer/map/Marker.qml mqi-anchor
+ \snippet mapviewer/map/Marker.qml mqi-closeimage
+ \snippet mapviewer/map/Marker.qml mqi-close
+
+ \image api-mapquickitem.png
+*/
+
+QDeclarativeGeoMapQuickItem::QDeclarativeGeoMapQuickItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), zoomLevel_(0.0),
+ mapAndSourceItemSet_(false), updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ opacityContainer_ = new QQuickItem(this);
+ opacityContainer_->setParentItem(this);
+ opacityContainer_->setFlag(ItemHasContents, true);
+}
+
+QDeclarativeGeoMapQuickItem::~QDeclarativeGeoMapQuickItem() {}
+
+/*!
+ \qmlproperty coordinate MapQuickItem::coordinate
+
+ This property holds the anchor coordinate of the MapQuickItem. The point
+ on the sourceItem that is specified by anchorPoint is kept aligned with
+ this coordinate when drawn on the map.
+
+ In the image below, there are 3 MapQuickItems that are identical except
+ for the value of their anchorPoint properties. The values of anchorPoint
+ for each are written on top of the item.
+
+ \image api-mapquickitem-anchor.png
+*/
+void QDeclarativeGeoMapQuickItem::setCoordinate(const QGeoCoordinate &coordinate)
+{
+ if (coordinate_ == coordinate)
+ return;
+
+ coordinate_ = coordinate;
+ geoshape_.setTopLeft(coordinate_);
+ geoshape_.setBottomRight(coordinate_);
+ // TODO: Handle zoomLevel != 0.0
+
+ polishAndUpdate();
+ emit coordinateChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map && quickMap) {
+ connect(map, SIGNAL(cameraDataChanged(QGeoCameraData)),
+ this, SLOT(polishAndUpdate()));
+ polishAndUpdate();
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (!mapAndSourceItemSet_ || updatingGeometry_ ||
+ newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+
+ QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(x(), y()) + (scaleFactor() * QDoubleVector2D(anchorPoint_)), false);
+ if (newCoordinate.isValid())
+ setCoordinate(newCoordinate);
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+/*!
+ \internal
+*/
+QGeoCoordinate QDeclarativeGeoMapQuickItem::coordinate()
+{
+ return coordinate_;
+}
+
+/*!
+ \qmlproperty object MapQuickItem::sourceItem
+
+ This property holds the source item that will be drawn on the map.
+*/
+void QDeclarativeGeoMapQuickItem::setSourceItem(QQuickItem *sourceItem)
+{
+ if (sourceItem_.data() == sourceItem)
+ return;
+ sourceItem_ = sourceItem;
+
+ polishAndUpdate();
+ emit sourceItemChanged();
+}
+
+QQuickItem *QDeclarativeGeoMapQuickItem::sourceItem()
+{
+ return sourceItem_.data();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::afterChildrenChanged()
+{
+ QList<QQuickItem *> kids = childItems();
+ if (kids.size() > 0) {
+ bool printedWarning = false;
+ foreach (QQuickItem *i, kids) {
+ if (i->flags() & QQuickItem::ItemHasContents
+ && !qobject_cast<QQuickMouseArea *>(i)
+ && sourceItem_.data() != i
+ && opacityContainer_ != i) {
+ if (!printedWarning) {
+ qmlWarning(this) << "Use the sourceItem property for the contained item, direct children are not supported";
+ printedWarning = true;
+ }
+
+ qmlWarning(i) << "deleting this child";
+ i->deleteLater();
+ }
+ }
+ }
+}
+
+/*!
+ \qmlproperty QPointF MapQuickItem::anchorPoint
+
+ This property determines which point on the sourceItem that will be lined
+ up with the coordinate on the map.
+*/
+void QDeclarativeGeoMapQuickItem::setAnchorPoint(const QPointF &anchorPoint)
+{
+ if (anchorPoint == anchorPoint_)
+ return;
+ anchorPoint_ = anchorPoint;
+ polishAndUpdate();
+ emit anchorPointChanged();
+}
+
+QPointF QDeclarativeGeoMapQuickItem::anchorPoint() const
+{
+ return anchorPoint_;
+}
+
+/*!
+ \qmlproperty real MapQuickItem::zoomLevel
+
+ This property controls the scaling behaviour of the contents of the
+ MapQuickItem. In particular, by setting this property it is possible
+ to choose between objects that are drawn on the screen (and sized in
+ screen pixels), and those drawn on the map surface (which change size
+ with the zoom level of the map).
+
+ The default value for this property is 0.0, which corresponds to drawing
+ the object on the screen surface. If set to another value, the object will
+ be drawn on the map surface instead. The value (if not zero) specifies the
+ zoomLevel at which the object will be visible at a scale of 1:1 (ie, where
+ object pixels and screen pixels are the same). At zoom levels lower than
+ this, the object will appear smaller, and at higher zoom levels, appear
+ larger. This is in contrast to when this property is set to zero, where
+ the object remains the same size on the screen at all zoom levels.
+*/
+void QDeclarativeGeoMapQuickItem::setZoomLevel(qreal zoomLevel)
+{
+ if (zoomLevel == zoomLevel_)
+ return;
+ zoomLevel_ = zoomLevel;
+ // TODO: update geoshape_!
+ polishAndUpdate();
+ emit zoomLevelChanged();
+}
+
+qreal QDeclarativeGeoMapQuickItem::zoomLevel() const
+{
+ return zoomLevel_;
+}
+
+const QGeoShape &QDeclarativeGeoMapQuickItem::geoShape() const
+{
+ // TODO: return a QGeoRectangle representing the bounding geo rectangle of the quick item
+ // when zoomLevel_ is != 0.0
+ return geoshape_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::updatePolish()
+{
+ if (!quickMap() && sourceItem_) {
+ mapAndSourceItemSet_ = false;
+ sourceItem_.data()->setParentItem(0);
+ return;
+ }
+
+ if (!quickMap() || !map() || !sourceItem_) {
+ mapAndSourceItemSet_ = false;
+ return;
+ }
+
+ if (!mapAndSourceItemSet_ && quickMap() && map() && sourceItem_) {
+ mapAndSourceItemSet_ = true;
+ sourceItem_.data()->setParentItem(opacityContainer_);
+ sourceItem_.data()->setTransformOrigin(QQuickItem::TopLeft);
+ connect(sourceItem_.data(), SIGNAL(xChanged()),
+ this, SLOT(polishAndUpdate()));
+ connect(sourceItem_.data(), SIGNAL(yChanged()),
+ this, SLOT(polishAndUpdate()));
+ connect(sourceItem_.data(), SIGNAL(widthChanged()),
+ this, SLOT(polishAndUpdate()));
+ connect(sourceItem_.data(), SIGNAL(heightChanged()),
+ this, SLOT(polishAndUpdate()));
+ }
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ opacityContainer_->setOpacity(zoomLevelOpacity());
+
+ sourceItem_.data()->setScale(scaleFactor());
+ sourceItem_.data()->setPosition(QPointF(0,0));
+ setWidth(sourceItem_.data()->width());
+ setHeight(sourceItem_.data()->height());
+ setPositionOnMap(coordinate(), scaleFactor() * anchorPoint_);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapQuickItem::scaleFactor()
+{
+ qreal scale = 1.0;
+ // use 1+x to avoid fuzzy compare against zero
+ if (!qFuzzyCompare(1.0 + zoomLevel_, 1.0))
+ scale = std::pow(0.5, zoomLevel_ - map()->cameraData().zoomLevel());
+ return scale;
+}
+
+#include "moc_qdeclarativegeomapquickitem_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h
new file mode 100644
index 00000000..2d910167
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPQUICKITEM_H
+#define QDECLARATIVEGEOMAPQUICKITEM_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtQuick/QQuickItem>
+#include <QtQuick/QSGNode>
+
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtPositioning/qgeoshape.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapQuickItem : public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+ Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged)
+ Q_PROPERTY(QPointF anchorPoint READ anchorPoint WRITE setAnchorPoint NOTIFY anchorPointChanged)
+ Q_PROPERTY(qreal zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged)
+ Q_PROPERTY(QQuickItem *sourceItem READ sourceItem WRITE setSourceItem NOTIFY sourceItemChanged)
+
+public:
+ explicit QDeclarativeGeoMapQuickItem(QQuickItem *parent = 0);
+ ~QDeclarativeGeoMapQuickItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+
+ void setCoordinate(const QGeoCoordinate &coordinate);
+ QGeoCoordinate coordinate();
+
+ void setSourceItem(QQuickItem *sourceItem);
+ QQuickItem *sourceItem();
+
+ void setAnchorPoint(const QPointF &anchorPoint);
+ QPointF anchorPoint() const;
+
+ void setZoomLevel(qreal zoomLevel);
+ qreal zoomLevel() const;
+
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void coordinateChanged();
+ void sourceItemChanged();
+ void anchorPointChanged();
+ void zoomLevelChanged();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ virtual void afterChildrenChanged() Q_DECL_OVERRIDE;
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ qreal scaleFactor();
+ QGeoCoordinate coordinate_;
+ QGeoRectangle geoshape_;
+ QPointer<QQuickItem> sourceItem_;
+ QQuickItem *opacityContainer_;
+ QPointF anchorPoint_;
+ qreal zoomLevel_;
+ bool mapAndSourceItemSet_;
+ bool updatingGeometry_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapQuickItem)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomaptype.cpp b/src/location/declarativemaps/qdeclarativegeomaptype.cpp
new file mode 100644
index 00000000..0b90ec3a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaptype.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeomaptype_p.h"
+#include <qnumeric.h>
+#include <QtQml/qqml.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapType
+ \instantiates QDeclarativeGeoMapType
+ \inherits QObject
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapType type holds information about a map type.
+
+ This includes the map type's \l name and \l description, the \l style and
+ a flag to indicate if the map type is optimized for mobile devices (\l mobile).
+*/
+
+QDeclarativeGeoMapType::QDeclarativeGeoMapType(const QGeoMapType mapType, QObject *parent)
+ : QObject(parent),
+ mapType_(mapType) {}
+
+QDeclarativeGeoMapType::~QDeclarativeGeoMapType() {}
+
+/*!
+ \qmlproperty enumeration MapType::style
+
+ This read-only property gives access to the style of the map type.
+
+ \list
+ \li MapType.NoMap - No map.
+ \li MapType.StreetMap - A street map.
+ \li MapType.SatelliteMapDay - A map with day-time satellite imagery.
+ \li MapType.SatelliteMapNight - A map with night-time satellite imagery.
+ \li MapType.TerrainMap - A terrain map.
+ \li MapType.HybridMap - A map with satellite imagery and street information.
+ \li MapType.GrayStreetMap - A gray-shaded street map.
+ \li MapType.PedestrianMap - A street map suitable for pedestriants.
+ \li MapType.CarNavigationMap - A street map suitable for car navigation.
+ \li MapType.CycleMap - A street map suitable for cyclists.
+ \li MapType.CustomMap - A custom map type.
+ \endlist
+*/
+QDeclarativeGeoMapType::MapStyle QDeclarativeGeoMapType::style() const
+{
+ return QDeclarativeGeoMapType::MapStyle(mapType_.style());
+}
+
+/*!
+ \qmlproperty string MapType::name
+
+ This read-only property holds the name of the map type as a single formatted string.
+*/
+QString QDeclarativeGeoMapType::name() const
+{
+ return mapType_.name();
+}
+
+/*!
+ \qmlproperty string MapType::description
+
+ This read-only property holds the description of the map type as a single formatted string.
+*/
+QString QDeclarativeGeoMapType::description() const
+{
+ return mapType_.description();
+}
+
+/*!
+ \qmlproperty bool MapType::mobile
+
+ \brief Whether the map type is optimized for the use on a mobile device.
+
+ Map types for mobile devices usually have higher constrast to counteract the
+ effects of sunlight and a reduced color for improved readability.
+*/
+bool QDeclarativeGeoMapType::mobile() const
+{
+ return mapType_.mobile();
+}
+
+/*!
+ \qmlproperty bool MapType::night
+ \since Qt Location 5.4
+
+ \brief Whether the map type is optimized for use at night.
+
+ Map types suitable for use at night usually have a dark background.
+*/
+bool QDeclarativeGeoMapType::night() const
+{
+ return mapType_.night();
+}
+
+#include "moc_qdeclarativegeomaptype_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomaptype_p.h b/src/location/declarativemaps/qdeclarativegeomaptype_p.h
new file mode 100644
index 00000000..7b449aa0
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaptype_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPTYPE_H
+#define QDECLARATIVEGEOMAPTYPE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtCore/QObject>
+#include <QtQml/qqml.h>
+#include <QtLocation/private/qgeomaptype_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapType : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(MapStyle)
+
+ Q_PROPERTY(MapStyle style READ style CONSTANT)
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString description READ description CONSTANT)
+ Q_PROPERTY(bool mobile READ mobile CONSTANT)
+ Q_PROPERTY(bool night READ night CONSTANT REVISION 1)
+
+public:
+ enum MapStyle {
+ NoMap = QGeoMapType::NoMap,
+ StreetMap = QGeoMapType::StreetMap,
+ SatelliteMapDay = QGeoMapType::SatelliteMapDay,
+ SatelliteMapNight = QGeoMapType::SatelliteMapNight,
+ TerrainMap = QGeoMapType::TerrainMap,
+ HybridMap = QGeoMapType::HybridMap,
+ TransitMap = QGeoMapType::TransitMap,
+ GrayStreetMap = QGeoMapType::GrayStreetMap,
+ PedestrianMap = QGeoMapType::PedestrianMap,
+ CarNavigationMap = QGeoMapType::CarNavigationMap,
+ CycleMap = QGeoMapType::CycleMap,
+ CustomMap = 100
+ };
+
+ QDeclarativeGeoMapType(const QGeoMapType mapType, QObject *parent = 0);
+ ~QDeclarativeGeoMapType();
+
+ MapStyle style() const;
+ QString name() const;
+ QString description() const;
+ bool mobile() const;
+ bool night() const;
+
+ const QGeoMapType mapType() { return mapType_; }
+
+private:
+ QGeoMapType mapType_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapType)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeoroute.cpp b/src/location/declarativemaps/qdeclarativegeoroute.cpp
new file mode 100644
index 00000000..fd6378da
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroute.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** 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 <QtQml/QQmlEngine>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtPositioning/QGeoRectangle>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Route
+ \instantiates QDeclarativeGeoRoute
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 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)
+{
+ this->init();
+}
+
+QDeclarativeGeoRoute::QDeclarativeGeoRoute(const QGeoRoute &route, QObject *parent)
+ : QObject(parent),
+ route_(route)
+{
+ this->init();
+}
+
+QDeclarativeGeoRoute::~QDeclarativeGeoRoute() {}
+
+void QDeclarativeGeoRoute::init()
+{
+ QGeoRouteSegment segment = route_.firstRouteSegment();
+ while (segment.isValid()) {
+ QDeclarativeGeoRouteSegment *routeSegment = new QDeclarativeGeoRouteSegment(segment, this);
+ QQmlEngine::setContextForObject(routeSegment, QQmlEngine::contextForObject(this));
+ segments_.append(routeSegment);
+ segment = segment.nextRouteSegment();
+ }
+}
+
+/*!
+ \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 QJSValue 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->putIndexed(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)
+{
+ static_cast<QDeclarativeGeoRoute *>(prop->object)->appendSegment(segment);
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeGeoRoute::segments_count(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop)
+{
+ return static_cast<QDeclarativeGeoRoute *>(prop->object)->segments_.count();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoRouteSegment *QDeclarativeGeoRoute::segments_at(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, int index)
+{
+ return static_cast<QDeclarativeGeoRoute *>(prop->object)->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();
+}
+
+#include "moc_qdeclarativegeoroute_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeoroute_p.h b/src/location/declarativemaps/qdeclarativegeoroute_p.h
new file mode 100644
index 00000000..e4501770
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroute_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOROUTE_H
+#define QDECLARATIVEGEOROUTE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoroutesegment_p.h>
+
+#include <QtCore/QObject>
+#include <QtQml/QQmlListProperty>
+#include <QtLocation/QGeoRoute>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRoute : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QGeoRectangle bounds READ bounds CONSTANT)
+ Q_PROPERTY(int travelTime READ travelTime CONSTANT)
+ Q_PROPERTY(qreal distance READ distance CONSTANT)
+ Q_PROPERTY(QJSValue path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeGeoRouteSegment> segments READ segments CONSTANT)
+
+public:
+ explicit QDeclarativeGeoRoute(QObject *parent = 0);
+ QDeclarativeGeoRoute(const QGeoRoute &route, QObject *parent = 0);
+ ~QDeclarativeGeoRoute();
+
+ QGeoRectangle bounds() const;
+ int travelTime() const;
+ qreal distance() const;
+
+ QJSValue path() const;
+ void setPath(const QJSValue &value);
+
+ QQmlListProperty<QDeclarativeGeoRouteSegment> segments();
+
+ void appendSegment(QDeclarativeGeoRouteSegment *segment);
+ void clearSegments();
+
+Q_SIGNALS:
+ void pathChanged();
+
+private:
+ static void segments_append(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, QDeclarativeGeoRouteSegment *segment);
+ static int segments_count(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop);
+ static QDeclarativeGeoRouteSegment *segments_at(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, int index);
+ static void segments_clear(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop);
+
+ void init();
+ QList<QGeoCoordinate> routePath();
+
+ QGeoRoute route_;
+ QList<QDeclarativeGeoRouteSegment *> segments_;
+ friend class QDeclarativeRouteMapItem;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
new file mode 100644
index 00000000..90796412
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
@@ -0,0 +1,1308 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeoroutemodel_p.h"
+#include "qdeclarativegeoroute_p.h"
+#include "error_messages.h"
+#include "locationvaluetypehelper_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtQml/QQmlEngine>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtLocation/QGeoRoutingManager>
+#include <QtPositioning/QGeoRectangle>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RouteModel
+ \instantiates QDeclarativeGeoRouteModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The RouteModel type provides access to routes.
+
+ The RouteModel type is used as part of a model/view grouping to retrieve
+ geographic routes from a backend provider. Routes include data about driving
+ directions between two points, walking directions with multiple waypoints,
+ and various other similar concepts. It functions much like other Model
+ types in QML (see for example \l {Models and Views in Qt Quick#ListModel}{ListModel} and
+ \l XmlListModel), and interacts with views such as \l MapItemView, and \l{ListView}.
+
+ Like \l Map and \l GeocodeModel, all the data for a RouteModel to work comes
+ from a services plugin. This is contained in the \l{plugin} property, and
+ this must be set before the RouteModel can do any useful work.
+
+ Once the plugin is set, create a \l RouteQuery with the appropriate
+ waypoints and other settings, and set the RouteModel's \l{query}
+ property. If \l autoUpdate is enabled, the update will being automatically.
+ Otherwise, the \l{update} method may be used. By default, autoUpdate is
+ disabled.
+
+ The data stored and returned in the RouteModel consists of \l Route objects,
+ as a list with the role name "routeData". See the documentation for \l Route
+ for further details on its structure and contents.
+
+ \section2 Example Usage
+
+ The following snippet is two-part, showing firstly the declaration of
+ objects, and secondly a short piece of procedural code using it. We set
+ the routeModel's \l{autoUpdate} property to false, and call \l{update} once
+ the query is set up, to avoid useless extra requests halfway through the
+ set up of the query.
+
+ \code
+ Plugin {
+ id: aPlugin
+ name: "osm"
+ }
+
+ RouteQuery {
+ id: aQuery
+ }
+
+ RouteModel {
+ id: routeModel
+ plugin: aPlugin
+ query: aQuery
+ autoUpdate: false
+ }
+ \endcode
+
+ \code
+ {
+ aQuery.addWaypoint(...)
+ aQuery.addWaypoint(...)
+ aQuery.travelModes = ...
+ routeModel.update()
+ }
+ \endcode
+
+*/
+
+QDeclarativeGeoRouteModel::QDeclarativeGeoRouteModel(QObject *parent)
+ : QAbstractListModel(parent),
+ complete_(false),
+ plugin_(0),
+ routeQuery_(0),
+ autoUpdate_(false),
+ status_(QDeclarativeGeoRouteModel::Null),
+ error_(QDeclarativeGeoRouteModel::NoError)
+{
+}
+
+QDeclarativeGeoRouteModel::~QDeclarativeGeoRouteModel()
+{
+ if (!routes_.empty()) {
+ qDeleteAll(routes_);
+ routes_.clear();
+ }
+}
+
+/*!
+ \qmlproperty int QtLocation::RouteModel::count
+
+ This property holds how many routes the model currently has.
+ Amongst other uses, you can use this value when accessing routes
+ via the QtLocation::RouteModel::get -method.
+*/
+
+int QDeclarativeGeoRouteModel::count() const
+{
+ return routes_.count();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteModel::reset()
+
+ Resets the model. All route data is cleared, any outstanding requests
+ are aborted and possible errors are cleared. Model status will be set
+ to RouteModel.Null
+*/
+
+void QDeclarativeGeoRouteModel::reset()
+{
+ if (!routes_.isEmpty()) {
+ beginResetModel();
+ qDeleteAll(routes_);
+ routes_.clear();
+ emit countChanged();
+ emit routesChanged();
+ endResetModel();
+ }
+
+ emit abortRequested();
+ setError(NoError, QString());
+ setStatus(QDeclarativeGeoRouteModel::Null);
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteModel::cancel()
+
+ Cancels any outstanding requests and clears errors. Model status will be set to either
+ RouteModel.Null or RouteModel.Ready.
+*/
+void QDeclarativeGeoRouteModel::cancel()
+{
+ emit abortRequested();
+ setError(NoError, QString());
+ setStatus(routes_.isEmpty() ? Null : Ready);
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteModel::get(int)
+
+ Returns the Route at given index. Use \l count property to check the
+ amount of routes available. The routes are indexed from zero, so the accessible range
+ is 0...(count - 1).
+
+ If you access out of bounds, a zero (null object) is returned and a warning is issued.
+*/
+
+QDeclarativeGeoRoute *QDeclarativeGeoRouteModel::get(int index)
+{
+ if (index < 0 || index >= routes_.count()) {
+ qmlWarning(this) << QStringLiteral("Index '%1' out of range").arg(index);
+ return 0;
+ }
+ return routes_.at(index);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::componentComplete()
+{
+ complete_ = true;
+ if (autoUpdate_) {
+ update();
+ }
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeGeoRouteModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return routes_.count();
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeGeoRouteModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ qmlWarning(this) << QStringLiteral("Error in indexing route model's data (invalid index).");
+ return QVariant();
+ }
+
+ if (index.row() >= routes_.count()) {
+ qmlWarning(this) << QStringLiteral("Fatal error in indexing route model's data (index overflow).");
+ return QVariant();
+ }
+
+ if (role == RouteRole) {
+ QObject *route = routes_.at(index.row());
+ return QVariant::fromValue(route);
+ }
+ return QVariant();
+}
+
+QHash<int, QByteArray> QDeclarativeGeoRouteModel::roleNames() const
+{
+ QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
+ roleNames.insert(RouteRole, "routeData");
+ return roleNames;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (plugin_ == plugin)
+ return;
+
+ reset(); // reset the model
+
+ if (plugin_)
+ disconnect(plugin_, SIGNAL(localesChanged()), this, SIGNAL(measurementSystemChanged()));
+ if (plugin)
+ connect(plugin, SIGNAL(localesChanged()), this, SIGNAL(measurementSystemChanged()));
+
+ plugin_ = plugin;
+
+ if (complete_)
+ emit pluginChanged();
+
+ if (!plugin)
+ return;
+
+ if (plugin_->isAttached()) {
+ pluginReady();
+ } else {
+ connect(plugin_, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::pluginReady()
+{
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ QGeoRoutingManager *routingManager = serviceProvider->routingManager();
+
+ if (serviceProvider->error() != QGeoServiceProvider::NoError) {
+ QDeclarativeGeoRouteModel::RouteError newError = UnknownError;
+ switch (serviceProvider->error()) {
+ case QGeoServiceProvider::NotSupportedError:
+ newError = EngineNotSetError; break;
+ case QGeoServiceProvider::UnknownParameterError:
+ newError = UnknownParameterError; break;
+ case QGeoServiceProvider::MissingRequiredParameterError:
+ newError = MissingRequiredParameterError; break;
+ case QGeoServiceProvider::ConnectionError:
+ newError = CommunicationError; break;
+ default:
+ break;
+ }
+
+ setError(newError, serviceProvider->errorString());
+ return;
+ }
+
+ if (!routingManager) {
+ setError(EngineNotSetError, tr("Plugin does not support routing."));
+ return;
+ }
+
+ connect(routingManager, SIGNAL(finished(QGeoRouteReply*)),
+ this, SLOT(routingFinished(QGeoRouteReply*)));
+ connect(routingManager, SIGNAL(error(QGeoRouteReply*,QGeoRouteReply::Error,QString)),
+ this, SLOT(routingError(QGeoRouteReply*,QGeoRouteReply::Error,QString)));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::queryDetailsChanged()
+{
+ if (autoUpdate_ && complete_)
+ update();
+}
+
+/*!
+ \qmlproperty Plugin QtLocation::RouteModel::plugin
+
+ This property holds the plugin that providers the actual
+ routing service. Note that all plugins do not necessarily
+ provide routing (could for example provide only geocoding or maps).
+
+ A valid plugin must be set before the RouteModel can perform any useful
+ operations.
+
+ \sa Plugin
+*/
+
+QDeclarativeGeoServiceProvider *QDeclarativeGeoRouteModel::plugin() const
+{
+ return plugin_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::setQuery(QDeclarativeGeoRouteQuery *query)
+{
+ if (!query || query == routeQuery_)
+ return;
+ if (routeQuery_)
+ routeQuery_->disconnect(this);
+ routeQuery_ = query;
+ connect(query, SIGNAL(queryDetailsChanged()), this, SLOT(queryDetailsChanged()));
+ if (complete_) {
+ emit queryChanged();
+ if (autoUpdate_)
+ update();
+ }
+}
+
+/*!
+ \qmlproperty RouteQuery QtLocation::RouteModel::query
+
+ This property holds the data of the route request.
+ The primary data are the waypoint coordinates and possible further
+ preferences (means of traveling, things to avoid on route etc).
+*/
+
+QDeclarativeGeoRouteQuery *QDeclarativeGeoRouteModel::query() const
+{
+ return routeQuery_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::setAutoUpdate(bool autoUpdate)
+{
+ if (autoUpdate_ == autoUpdate)
+ return;
+ autoUpdate_ = autoUpdate;
+ if (complete_)
+ emit autoUpdateChanged();
+}
+
+/*!
+ \qmlproperty bool QtLocation::RouteModel::autoUpdate
+
+ This property controls whether the Model automatically updates in response
+ to changes in its attached RouteQuery. The default value of this property
+ is false.
+
+ If setting this value to 'true', note that any change at all in
+ the RouteQuery object set in the \l{query} property will trigger a new
+ request to be sent. If you are adjusting many properties of the RouteQuery
+ with autoUpdate enabled, this can generate large numbers of useless (and
+ later discarded) requests.
+*/
+
+bool QDeclarativeGeoRouteModel::autoUpdate() const
+{
+ return autoUpdate_;
+}
+
+/*!
+ \qmlproperty Locale::MeasurementSystem QtLocation::RouteModel::measurementSystem
+
+ This property holds the measurement system which will be used when calculating the route. This
+ property is changed when the \l {QtLocation::Plugin::locales}{Plugin::locales} property of
+ \l {QtLocation::RouteModel::plugin}{plugin} changes.
+
+ If setting this property it must be set after the \l {QtLocation::RouteModel::plugin}{plugin}
+ property is set.
+*/
+void QDeclarativeGeoRouteModel::setMeasurementSystem(QLocale::MeasurementSystem ms)
+{
+ if (!plugin_)
+ return;
+
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return;
+
+ QGeoRoutingManager *routingManager = serviceProvider->routingManager();
+ if (!routingManager)
+ return;
+
+ if (routingManager->measurementSystem() == ms)
+ return;
+
+ routingManager->setMeasurementSystem(ms);
+ emit measurementSystemChanged();
+}
+
+QLocale::MeasurementSystem QDeclarativeGeoRouteModel::measurementSystem() const
+{
+ if (!plugin_)
+ return QLocale().measurementSystem();
+
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ if (!serviceProvider) {
+ if (plugin_->locales().isEmpty())
+ return QLocale().measurementSystem();
+
+ return QLocale(plugin_->locales().first()).measurementSystem();
+ }
+
+ QGeoRoutingManager *routingManager = serviceProvider->routingManager();
+ if (!routingManager) {
+ if (plugin_->locales().isEmpty())
+ return QLocale().measurementSystem();
+
+ return QLocale(plugin_->locales().first()).measurementSystem();
+ }
+
+ return routingManager->measurementSystem();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::setStatus(QDeclarativeGeoRouteModel::Status status)
+{
+ if (status_ == status)
+ return;
+
+ status_ = status;
+
+ if (complete_)
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::RouteModel::status
+
+ This read-only property holds the current status of the model.
+
+ \list
+ \li RouteModel.Null - No route requests have been issued or \l reset has been called.
+ \li RouteModel.Ready - Route request(s) have finished successfully.
+ \li RouteModel.Loading - Route request has been issued but not yet finished
+ \li RouteModel.Error - Routing error has occurred, details are in \l error and \l errorString
+ \endlist
+*/
+
+QDeclarativeGeoRouteModel::Status QDeclarativeGeoRouteModel::status() const
+{
+ return status_;
+}
+
+/*!
+ \qmlproperty string QtLocation::RouteModel::errorString
+
+ This read-only property holds the textual presentation of the latest routing error.
+ If no error has occurred or the model has been reset, an empty string is returned.
+
+ An empty string may also be returned if an error occurred which has no associated
+ textual representation.
+*/
+
+QString QDeclarativeGeoRouteModel::errorString() const
+{
+ return errorString_;
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::RouteModel::error
+
+ This read-only property holds the latest error value of the routing request.
+
+ \list
+ \li RouteModel.NoError - No error has occurred.
+ \li RouteModel.CommunicationError - An error occurred while communicating with the service provider.
+ \li RouteModel.EngineNotSetError - The model's plugin property was not set or there is no routing manager associated with the plugin.
+ \li RouteModel.MissingRequiredParameterError - A required parameter was not specified.
+ \li RouteModel.ParseError - The response from the service provider was in an unrecognizable format.
+ \li RouteModel.UnknownError - An error occurred which does not fit into any of the other categories.
+ \li RouteModel.UnknownParameterError - The plugin did not recognize one of the parameters it was given.
+ \li RouteModel.UnsupportedOptionError - The requested operation is not supported by the routing provider.
+ This may happen when the loaded engine does not support a particular
+ type of routing request.
+ \endlist
+*/
+
+QDeclarativeGeoRouteModel::RouteError QDeclarativeGeoRouteModel::error() const
+{
+ return error_;
+}
+
+void QDeclarativeGeoRouteModel::setError(RouteError error, const QString& errorString)
+{
+ if (error_ == error && errorString_ == errorString)
+ return;
+ error_ = error;
+ errorString_ = errorString;
+ emit errorChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteModel::update()
+
+ Instructs the RouteModel to update its data. This is most useful
+ when \l autoUpdate is disabled, to force a refresh when the query
+ has been changed.
+*/
+void QDeclarativeGeoRouteModel::update()
+{
+ if (!complete_)
+ return;
+
+ if (!plugin_) {
+ setError(EngineNotSetError, tr("Cannot route, plugin not set."));
+ return;
+ }
+
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return;
+
+ QGeoRoutingManager *routingManager = serviceProvider->routingManager();
+ if (!routingManager) {
+ setError(EngineNotSetError, tr("Cannot route, route manager not set."));
+ return;
+ }
+ if (!routeQuery_) {
+ setError(ParseError,"Cannot route, valid query not set.");
+ return;
+ }
+ emit abortRequested(); // Clear previous requests
+ QGeoRouteRequest request = routeQuery_->routeRequest();
+ if (request.waypoints().count() < 2) {
+ setError(ParseError,tr("Not enough waypoints for routing."));
+ return;
+ }
+
+ setError(NoError, QString());
+
+ QGeoRouteReply *reply = routingManager->calculateRoute(request);
+ setStatus(QDeclarativeGeoRouteModel::Loading);
+ if (!reply->isFinished()) {
+ connect(this, &QDeclarativeGeoRouteModel::abortRequested, reply, &QGeoRouteReply::abort);
+ } else {
+ if (reply->error() == QGeoRouteReply::NoError) {
+ routingFinished(reply);
+ } else {
+ routingError(reply, reply->error(), reply->errorString());
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::routingFinished(QGeoRouteReply *reply)
+{
+ if (!reply)
+ return;
+ reply->deleteLater();
+ if (reply->error() != QGeoRouteReply::NoError)
+ return;
+
+ beginResetModel();
+ int oldCount = routes_.count();
+ qDeleteAll(routes_);
+ // Convert routes to declarative
+ routes_.clear();
+ for (int i = 0; i < reply->routes().size(); ++i) {
+ QDeclarativeGeoRoute *route = new QDeclarativeGeoRoute(reply->routes().at(i), this);
+ QQmlEngine::setContextForObject(route, QQmlEngine::contextForObject(this));
+ routes_.append(route);
+ }
+ endResetModel();
+
+ setError(NoError, QString());
+ setStatus(QDeclarativeGeoRouteModel::Ready);
+
+ if (oldCount != 0 || routes_.count() != 0)
+ emit routesChanged();
+ if (oldCount != routes_.count())
+ emit countChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::routingError(QGeoRouteReply *reply,
+ QGeoRouteReply::Error error,
+ const QString &errorString)
+{
+ if (!reply)
+ return;
+ reply->deleteLater();
+ setError(static_cast<QDeclarativeGeoRouteModel::RouteError>(error), errorString);
+ setStatus(QDeclarativeGeoRouteModel::Error);
+}
+
+
+/*!
+ \qmltype RouteQuery
+ \instantiates QDeclarativeGeoRouteQuery
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The RouteQuery type is used to provide query parameters to a
+ RouteModel.
+
+ A RouteQuery contains all the parameters necessary to make a request
+ to a routing service, which can then populate the contents of a RouteModel.
+
+ These parameters describe key details of the route, such as \l waypoints to
+ pass through, \l excludedAreas to avoid, the \l travelModes in use, as well
+ as detailed preferences on how to optimize the route and what features
+ to prefer or avoid along the path (such as toll roads, highways, etc).
+
+ RouteQuery objects are used exclusively to fill out the value of a
+ RouteModel's \l{RouteModel::query}{query} property, which can then begin
+ the retrieval process to populate the model.
+
+ \section2 Example Usage
+
+ The following snipped shows an incomplete example of creating a RouteQuery
+ object and setting it as the value of a RouteModel's \l{RouteModel::query}{query}
+ property.
+
+ \code
+ RouteQuery {
+ id: aQuery
+ }
+
+ RouteModel {
+ query: aQuery
+ autoUpdate: false
+ }
+ \endcode
+
+ For a more complete example, see the documentation for the \l{RouteModel}
+ type, and the Mapviewer example.
+
+ \sa RouteModel
+
+*/
+
+QDeclarativeGeoRouteQuery::QDeclarativeGeoRouteQuery(QObject *parent)
+: QObject(parent), complete_(false), m_excludedAreaCoordinateChanged(false)
+{
+}
+
+QDeclarativeGeoRouteQuery::~QDeclarativeGeoRouteQuery()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteQuery::componentComplete()
+{
+ complete_ = true;
+}
+
+/*!
+ \qmlproperty QList<FeatureType> RouteQuery::featureTypes
+
+ List of features that will be considered when planning the
+ route. Features with a weight of NeutralFeatureWeight will not be returned.
+
+ \list
+ \li RouteQuery.NoFeature - No features will be taken into account when planning the route
+ \li RouteQuery.TollFeature - Consider tollways when planning the route
+ \li RouteQuery.HighwayFeature - Consider highways when planning the route
+ \li RouteQuery.PublicTransitFeature - Consider public transit when planning the route
+ \li RouteQuery.FerryFeature - Consider ferries when planning the route
+ \li RouteQuery.TunnelFeature - Consider tunnels when planning the route
+ \li RouteQuery.DirtRoadFeature - Consider dirt roads when planning the route
+ \li RouteQuery.ParksFeature - Consider parks when planning the route
+ \li RouteQuery.MotorPoolLaneFeature - Consider motor pool lanes when planning the route
+ \endlist
+
+ \sa setFeatureWeight, featureWeight
+*/
+
+QList<int> QDeclarativeGeoRouteQuery::featureTypes()
+{
+ QList<int> list;
+
+ for (int i = 0; i < request_.featureTypes().count(); ++i) {
+ list.append(static_cast<int>(request_.featureTypes().at(i)));
+ }
+ return list;
+}
+
+/*!
+ \qmlproperty int RouteQuery::numberAlternativeRoutes
+
+ The number of alternative routes requested when requesting routes.
+ The default value is 0.
+*/
+
+
+int QDeclarativeGeoRouteQuery::numberAlternativeRoutes() const
+{
+ return request_.numberAlternativeRoutes();
+}
+
+void QDeclarativeGeoRouteQuery::setNumberAlternativeRoutes(int numberAlternativeRoutes)
+{
+ if (numberAlternativeRoutes == request_.numberAlternativeRoutes())
+ return;
+
+ request_.setNumberAlternativeRoutes(numberAlternativeRoutes);
+
+ if (complete_) {
+ emit numberAlternativeRoutesChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlproperty QJSValue RouteQuery::waypoints
+
+
+ The waypoint coordinates of the desired route.
+ The waypoints should be given in order from origin to destination.
+ Two or more coordinates are needed.
+
+ Waypoints can be set as part of the RouteQuery type declaration or
+ dynamically with the functions provided.
+
+ \sa addWaypoint, removeWaypoint, clearWaypoints
+*/
+
+QJSValue QDeclarativeGeoRouteQuery::waypoints()
+{
+ QQmlContext *context = QQmlEngine::contextForObject(parent());
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> waypointArray(scope, v4->newArrayObject(request_.waypoints().length()));
+ for (int i = 0; i < request_.waypoints().length(); ++i) {
+ const QGeoCoordinate &c = request_.waypoints().at(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ waypointArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, waypointArray.asReturnedValue());
+}
+
+void QDeclarativeGeoRouteQuery::setWaypoints(const QJSValue &value)
+{
+ if (!value.isArray())
+ return;
+
+ QList<QGeoCoordinate> waypointList;
+ 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 waypoint type";
+ return;
+ }
+
+ waypointList.append(c);
+ }
+
+ if (request_.waypoints() == waypointList)
+ return;
+
+ request_.setWaypoints(waypointList);
+
+ emit waypointsChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlproperty list<georectangle> RouteQuery::excludedAreas
+
+ Areas that the route must not cross.
+
+ Excluded areas can be set as part of the \l RouteQuery type declaration or
+ dynamically with the functions provided.
+
+ \sa addExcludedArea, removeExcludedArea, clearExcludedAreas
+*/
+QJSValue QDeclarativeGeoRouteQuery::excludedAreas() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(parent());
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> excludedAreasArray(scope, v4->newArrayObject(request_.excludeAreas().length()));
+ for (int i = 0; i < request_.excludeAreas().length(); ++i) {
+ const QGeoRectangle &r = request_.excludeAreas().at(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(r)));
+ excludedAreasArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, excludedAreasArray.asReturnedValue());
+}
+
+void QDeclarativeGeoRouteQuery::setExcludedAreas(const QJSValue &value)
+{
+ if (!value.isArray())
+ return;
+
+ QList<QGeoRectangle> excludedAreasList;
+ quint32 length = value.property(QStringLiteral("length")).toUInt();
+ for (quint32 i = 0; i < length; ++i) {
+ bool ok;
+ QGeoRectangle r = parseRectangle(value.property(i), &ok);
+
+ if (!ok || !r.isValid()) {
+ qmlWarning(this) << "Unsupported area type";
+ return;
+ }
+
+ excludedAreasList.append(r);
+ }
+
+ if (request_.excludeAreas() == excludedAreasList)
+ return;
+
+ request_.setExcludeAreas(excludedAreasList);
+
+ emit excludedAreasChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::addExcludedArea(georectangle)
+
+ Adds the given area to excluded areas (areas that the route must not cross).
+ Same area can only be added once.
+
+ \sa removeExcludedArea, clearExcludedAreas
+*/
+
+
+void QDeclarativeGeoRouteQuery::addExcludedArea(const QGeoRectangle &area)
+{
+ if (!area.isValid())
+ return;
+
+ QList<QGeoRectangle> excludedAreas = request_.excludeAreas();
+
+ if (excludedAreas.contains(area))
+ return;
+
+ excludedAreas.append(area);
+
+ request_.setExcludeAreas(excludedAreas);
+
+ if (complete_) {
+ emit excludedAreasChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::removeExcludedArea(georectangle)
+
+ Removes the given area to excluded areas (areas that the route must not cross).
+
+ \sa addExcludedArea, clearExcludedAreas
+*/
+
+void QDeclarativeGeoRouteQuery::removeExcludedArea(const QGeoRectangle &area)
+{
+ if (!area.isValid())
+ return;
+
+ QList<QGeoRectangle> excludedAreas = request_.excludeAreas();
+
+ int index = excludedAreas.lastIndexOf(area);
+ if (index == -1) {
+ qmlWarning(this) << QStringLiteral("Cannot remove nonexistent area.");
+ return;
+ }
+ excludedAreas.removeAt(index);
+ request_.setExcludeAreas(excludedAreas);
+
+ emit excludedAreasChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::clearExcludedAreas()
+
+ Clears all excluded areas (areas that the route must not cross).
+
+ \sa addExcludedArea, removeExcludedArea
+*/
+
+void QDeclarativeGeoRouteQuery::clearExcludedAreas()
+{
+ if (request_.excludeAreas().isEmpty())
+ return;
+
+ request_.setExcludeAreas(QList<QGeoRectangle>());
+
+ emit excludedAreasChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::addWaypoint(coordinate)
+
+ Appends a coordinate to the list of waypoints. Same coordinate
+ can be set multiple times.
+
+ \sa removeWaypoint, clearWaypoints
+*/
+void QDeclarativeGeoRouteQuery::addWaypoint(const QGeoCoordinate &waypoint)
+{
+ if (!waypoint.isValid()) {
+ qmlWarning(this) << QStringLiteral("Not adding invalid waypoint.");
+ return;
+ }
+
+ QList<QGeoCoordinate> waypoints = request_.waypoints();
+ waypoints.append(waypoint);
+ request_.setWaypoints(waypoints);
+
+ if (complete_) {
+ emit waypointsChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::removeWaypoint(coordinate)
+
+ Removes the given from the list of waypoints. In case same coordinate
+ appears multiple times, the most recently added coordinate instance is
+ removed.
+
+ \sa addWaypoint, clearWaypoints
+*/
+void QDeclarativeGeoRouteQuery::removeWaypoint(const QGeoCoordinate &waypoint)
+{
+ QList<QGeoCoordinate> waypoints = request_.waypoints();
+
+ int index = waypoints.lastIndexOf(waypoint);
+ if (index == -1) {
+ qmlWarning(this) << QStringLiteral("Cannot remove nonexistent waypoint.");
+ return;
+ }
+
+ waypoints.removeAt(index);
+
+ request_.setWaypoints(waypoints);
+
+ emit waypointsChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::clearWaypoints()
+
+ Clears all waypoints.
+
+ \sa removeWaypoint, addWaypoint
+*/
+void QDeclarativeGeoRouteQuery::clearWaypoints()
+{
+ if (request_.waypoints().isEmpty())
+ return;
+
+ request_.setWaypoints(QList<QGeoCoordinate>());
+
+ emit waypointsChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::setFeatureWeight(FeatureType, FeatureWeight)
+
+ Defines the weight to associate with a feature during the planning of a
+ route.
+
+ Following lists the possible feature weights:
+
+ \list
+ \li RouteQuery.NeutralFeatureWeight - The presence or absence of the feature will not affect the planning of the route
+ \li RouteQuery.PreferFeatureWeight - Routes which contain the feature will be preferred over those that do not
+ \li RouteQuery.RequireFeatureWeight - Only routes which contain the feature will be considered, otherwise no route will be returned
+ \li RouteQuery.AvoidFeatureWeight - Routes which do not contain the feature will be preferred over those that do
+ \li RouteQuery.DisallowFeatureWeight - Only routes which do not contain the feature will be considered, otherwise no route will be returned
+ \endlist
+
+ \sa featureTypes, resetFeatureWeights, featureWeight
+
+*/
+
+void QDeclarativeGeoRouteQuery::setFeatureWeight(FeatureType featureType, FeatureWeight featureWeight)
+{
+ if (featureType == NoFeature && !request_.featureTypes().isEmpty()) {
+ resetFeatureWeights();
+ return;
+ }
+
+ // Check if the weight changes, as we need to signal it
+ FeatureWeight originalWeight = static_cast<FeatureWeight>(request_.featureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType)));
+ if (featureWeight == originalWeight)
+ return;
+
+ request_.setFeatureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType),
+ static_cast<QGeoRouteRequest::FeatureWeight>(featureWeight));
+ if (complete_ && ((originalWeight == NeutralFeatureWeight) || (featureWeight == NeutralFeatureWeight))) {
+ // featureTypes should now give a different list, because the original and new weight
+ // were not same, and other one was neutral weight
+ emit featureTypesChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::resetFeatureWeights()
+
+ Resets all feature weights to their default state (NeutralFeatureWeight).
+
+ \sa featureTypes, setFeatureWeight, featureWeight
+*/
+void QDeclarativeGeoRouteQuery::resetFeatureWeights()
+{
+ // reset all feature types.
+ QList<QGeoRouteRequest::FeatureType> featureTypes = request_.featureTypes();
+ for (int i = 0; i < featureTypes.count(); ++i) {
+ request_.setFeatureWeight(featureTypes.at(i), QGeoRouteRequest::NeutralFeatureWeight);
+ }
+ if (complete_) {
+ emit featureTypesChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlmethod FeatureWeight QtLocation::RouteQuery::featureWeight(FeatureType featureType)
+
+ Gets the weight for the \a featureType.
+
+ \sa featureTypes, setFeatureWeight, resetFeatureWeights
+*/
+
+int QDeclarativeGeoRouteQuery::featureWeight(FeatureType featureType)
+{
+ return request_.featureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteQuery::setTravelModes(QDeclarativeGeoRouteQuery::TravelModes travelModes)
+{
+ QGeoRouteRequest::TravelModes reqTravelModes;
+
+ if (travelModes & QDeclarativeGeoRouteQuery::CarTravel)
+ reqTravelModes |= QGeoRouteRequest::CarTravel;
+ if (travelModes & QDeclarativeGeoRouteQuery::PedestrianTravel)
+ reqTravelModes |= QGeoRouteRequest::PedestrianTravel;
+ if (travelModes & QDeclarativeGeoRouteQuery::BicycleTravel)
+ reqTravelModes |= QGeoRouteRequest::BicycleTravel;
+ if (travelModes & QDeclarativeGeoRouteQuery::PublicTransitTravel)
+ reqTravelModes |= QGeoRouteRequest::PublicTransitTravel;
+ if (travelModes & QDeclarativeGeoRouteQuery::TruckTravel)
+ reqTravelModes |= QGeoRouteRequest::TruckTravel;
+
+ if (reqTravelModes == request_.travelModes())
+ return;
+
+ request_.setTravelModes(reqTravelModes);
+
+ if (complete_) {
+ emit travelModesChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+
+/*!
+ \qmlproperty enumeration RouteQuery::segmentDetail
+
+ The level of detail which will be used in the representation of routing segments.
+
+ \list
+ \li RouteQuery.NoSegmentData - No segment data should be included with the route
+ \li RouteQuery.BasicSegmentData - Basic segment data will be included with the route
+ \endlist
+
+ The default value is RouteQuery.BasicSegmentData
+*/
+
+void QDeclarativeGeoRouteQuery::setSegmentDetail(SegmentDetail segmentDetail)
+{
+ if (static_cast<QGeoRouteRequest::SegmentDetail>(segmentDetail) == request_.segmentDetail())
+ return;
+ request_.setSegmentDetail(static_cast<QGeoRouteRequest::SegmentDetail>(segmentDetail));
+ if (complete_) {
+ emit segmentDetailChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+QDeclarativeGeoRouteQuery::SegmentDetail QDeclarativeGeoRouteQuery::segmentDetail() const
+{
+ return static_cast<QDeclarativeGeoRouteQuery::SegmentDetail>(request_.segmentDetail());
+}
+
+/*!
+ \qmlproperty enumeration RouteQuery::maneuverDetail
+
+ The level of detail which will be used in the representation of routing maneuvers.
+
+ \list
+ \li RouteQuery.NoManeuvers - No maneuvers should be included with the route
+ \li RouteQuery.BasicManeuvers - Basic maneuvers will be included with the route
+ \endlist
+
+ The default value is RouteQuery.BasicManeuvers
+*/
+
+void QDeclarativeGeoRouteQuery::setManeuverDetail(ManeuverDetail maneuverDetail)
+{
+ if (static_cast<QGeoRouteRequest::ManeuverDetail>(maneuverDetail) == request_.maneuverDetail())
+ return;
+ request_.setManeuverDetail(static_cast<QGeoRouteRequest::ManeuverDetail>(maneuverDetail));
+ if (complete_) {
+ emit maneuverDetailChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+QDeclarativeGeoRouteQuery::ManeuverDetail QDeclarativeGeoRouteQuery::maneuverDetail() const
+{
+ return static_cast<QDeclarativeGeoRouteQuery::ManeuverDetail>(request_.maneuverDetail());
+}
+
+/*!
+ \qmlproperty enumeration RouteQuery::travelModes
+
+ The travel modes which should be considered during the planning of the route.
+ Values can be combined with OR ('|') -operator.
+
+ \list
+ \li RouteQuery.CarTravel - The route will be optimized for someone who is driving a car
+ \li RouteQuery.PedestrianTravel - The route will be optimized for someone who is walking
+ \li RouteQuery.BicycleTravel - The route will be optimized for someone who is riding a bicycle
+ \li RouteQuery.PublicTransitTravel - The route will be optimized for someone who is making use of public transit
+ \li RouteQuery.TruckTravel - The route will be optimized for someone who is driving a truck
+ \endlist
+
+ The default value is RouteQuery.CarTravel
+*/
+
+QDeclarativeGeoRouteQuery::TravelModes QDeclarativeGeoRouteQuery::travelModes() const
+{
+ QGeoRouteRequest::TravelModes reqTravelModes = request_.travelModes();
+ QDeclarativeGeoRouteQuery::TravelModes travelModes;
+
+ if (reqTravelModes & QGeoRouteRequest::CarTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::CarTravel;
+ if (reqTravelModes & QGeoRouteRequest::PedestrianTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::PedestrianTravel;
+ if (reqTravelModes & QGeoRouteRequest::BicycleTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::BicycleTravel;
+ if (reqTravelModes & QGeoRouteRequest::PublicTransitTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::PublicTransitTravel;
+ if (reqTravelModes & QGeoRouteRequest::TruckTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::TruckTravel;
+
+ return travelModes;
+}
+
+/*!
+ \qmlproperty enumeration RouteQuery::routeOptimizations
+
+ The route optimizations which should be considered during the planning of the route.
+ Values can be combined with OR ('|') -operator.
+
+ \list
+ \li RouteQuery.ShortestRoute - Minimize the length of the journey
+ \li RouteQuery.FastestRoute - Minimize the traveling time for the journey
+ \li RouteQuery.MostEconomicRoute - Minimize the cost of the journey
+ \li RouteQuery.MostScenicRoute - Maximize the scenic potential of the journey
+ \endlist
+
+ The default value is RouteQuery.FastestRoute
+*/
+
+QDeclarativeGeoRouteQuery::RouteOptimizations QDeclarativeGeoRouteQuery::routeOptimizations() const
+{
+ QGeoRouteRequest::RouteOptimizations reqOptimizations = request_.routeOptimization();
+ QDeclarativeGeoRouteQuery::RouteOptimizations optimization;
+
+ if (reqOptimizations & QGeoRouteRequest::ShortestRoute)
+ optimization |= QDeclarativeGeoRouteQuery::ShortestRoute;
+ if (reqOptimizations & QGeoRouteRequest::FastestRoute)
+ optimization |= QDeclarativeGeoRouteQuery::FastestRoute;
+ if (reqOptimizations & QGeoRouteRequest::MostEconomicRoute)
+ optimization |= QDeclarativeGeoRouteQuery::MostEconomicRoute;
+ if (reqOptimizations & QGeoRouteRequest::MostScenicRoute)
+ optimization |= QDeclarativeGeoRouteQuery::MostScenicRoute;
+
+ return optimization;
+}
+
+void QDeclarativeGeoRouteQuery::setRouteOptimizations(QDeclarativeGeoRouteQuery::RouteOptimizations optimization)
+{
+ QGeoRouteRequest::RouteOptimizations reqOptimizations;
+
+ if (optimization & QDeclarativeGeoRouteQuery::ShortestRoute)
+ reqOptimizations |= QGeoRouteRequest::ShortestRoute;
+ if (optimization & QDeclarativeGeoRouteQuery::FastestRoute)
+ reqOptimizations |= QGeoRouteRequest::FastestRoute;
+ if (optimization & QDeclarativeGeoRouteQuery::MostEconomicRoute)
+ reqOptimizations |= QGeoRouteRequest::MostEconomicRoute;
+ if (optimization & QDeclarativeGeoRouteQuery::MostScenicRoute)
+ reqOptimizations |= QGeoRouteRequest::MostScenicRoute;
+
+ if (reqOptimizations == request_.routeOptimization())
+ return;
+
+ request_.setRouteOptimization(reqOptimizations);
+
+ if (complete_) {
+ emit routeOptimizationsChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+QGeoRouteRequest QDeclarativeGeoRouteQuery::routeRequest() const
+{
+ return request_;
+}
+
+void QDeclarativeGeoRouteQuery::excludedAreaCoordinateChanged()
+{
+ if (!m_excludedAreaCoordinateChanged) {
+ m_excludedAreaCoordinateChanged = true;
+ QMetaObject::invokeMethod(this, "doCoordinateChanged", Qt::QueuedConnection);
+ }
+}
+
+void QDeclarativeGeoRouteQuery::doCoordinateChanged()
+{
+ m_excludedAreaCoordinateChanged = false;
+ emit queryDetailsChanged();
+}
+
+#include "moc_qdeclarativegeoroutemodel_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h b/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h
new file mode 100644
index 00000000..3dfd2ce6
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h
@@ -0,0 +1,344 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOROUTEMODEL_H
+#define QDECLARATIVEGEOROUTEMODEL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
+
+#include <QtPositioning/QGeoCoordinate>
+#include <QtPositioning/QGeoRectangle>
+
+#include <qgeorouterequest.h>
+#include <qgeoroutereply.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/private/qv4engine_p.h>
+#include <QAbstractListModel>
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoServiceProvider;
+class QGeoRoutingManager;
+class QDeclarativeGeoRoute;
+class QDeclarativeGeoRouteQuery;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteModel : public QAbstractListModel, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+ Q_ENUMS(RouteError)
+
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(QDeclarativeGeoRouteQuery *query READ query WRITE setQuery NOTIFY queryChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(bool autoUpdate READ autoUpdate WRITE setAutoUpdate NOTIFY autoUpdateChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(RouteError error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QLocale::MeasurementSystem measurementSystem READ measurementSystem WRITE setMeasurementSystem NOTIFY measurementSystemChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ enum Roles {
+ RouteRole = Qt::UserRole + 500
+ };
+
+ enum Status {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ enum RouteError {
+ NoError = QGeoRouteReply::NoError,
+ EngineNotSetError = QGeoRouteReply::EngineNotSetError,
+ CommunicationError = QGeoRouteReply::CommunicationError,
+ ParseError = QGeoRouteReply::ParseError,
+ UnsupportedOptionError = QGeoRouteReply::UnsupportedOptionError,
+ UnknownError = QGeoRouteReply::UnknownError,
+ //we leave gap for future QGeoRouteReply errors
+
+ //QGeoServiceProvider related errors start here
+ UnknownParameterError = 100,
+ MissingRequiredParameterError
+ };
+
+ explicit QDeclarativeGeoRouteModel(QObject *parent = 0);
+ ~QDeclarativeGeoRouteModel();
+
+ // From QQmlParserStatus
+ void classBegin() {}
+ void componentComplete();
+
+ // From QAbstractListModel
+ int rowCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ virtual QHash<int,QByteArray> roleNames() const;
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ void setQuery(QDeclarativeGeoRouteQuery *query);
+ QDeclarativeGeoRouteQuery *query() const;
+
+ void setAutoUpdate(bool autoUpdate);
+ bool autoUpdate() const;
+
+ void setMeasurementSystem(QLocale::MeasurementSystem ms);
+ QLocale::MeasurementSystem measurementSystem() const;
+
+ Status status() const;
+ QString errorString() const;
+ RouteError error() const;
+
+ int count() const;
+ Q_INVOKABLE QDeclarativeGeoRoute *get(int index);
+ Q_INVOKABLE void reset();
+ Q_INVOKABLE void cancel();
+
+Q_SIGNALS:
+ void countChanged();
+ void pluginChanged();
+ void queryChanged();
+ void autoUpdateChanged();
+ void statusChanged();
+ void errorChanged(); //emitted also for errorString notification
+ void routesChanged();
+ void measurementSystemChanged();
+ void abortRequested();
+
+public Q_SLOTS:
+ void update();
+
+private Q_SLOTS:
+ void routingFinished(QGeoRouteReply *reply);
+ void routingError(QGeoRouteReply *reply,
+ QGeoRouteReply::Error error,
+ const QString &errorString);
+ void queryDetailsChanged();
+ void pluginReady();
+
+private:
+ void setStatus(Status status);
+ void setError(RouteError error, const QString &errorString);
+
+ bool complete_;
+
+ QDeclarativeGeoServiceProvider *plugin_;
+ QDeclarativeGeoRouteQuery *routeQuery_;
+
+ QList<QDeclarativeGeoRoute *> routes_;
+ bool autoUpdate_;
+ Status status_;
+ QString errorString_;
+ RouteError error_;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteQuery : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_ENUMS(TravelMode)
+ Q_ENUMS(FeatureType)
+ Q_ENUMS(FeatureWeight)
+ Q_ENUMS(SegmentDetail)
+ Q_ENUMS(ManeuverDetail)
+ Q_ENUMS(RouteOptimization)
+ Q_FLAGS(RouteOptimizations)
+ Q_FLAGS(ManeuverDetails)
+ Q_FLAGS(SegmentDetails)
+ Q_FLAGS(TravelModes)
+
+ Q_PROPERTY(int numberAlternativeRoutes READ numberAlternativeRoutes WRITE setNumberAlternativeRoutes NOTIFY numberAlternativeRoutesChanged)
+ Q_PROPERTY(TravelModes travelModes READ travelModes WRITE setTravelModes NOTIFY travelModesChanged)
+ Q_PROPERTY(RouteOptimizations routeOptimizations READ routeOptimizations WRITE setRouteOptimizations NOTIFY routeOptimizationsChanged)
+ Q_PROPERTY(SegmentDetail segmentDetail READ segmentDetail WRITE setSegmentDetail NOTIFY segmentDetailChanged)
+ Q_PROPERTY(ManeuverDetail maneuverDetail READ maneuverDetail WRITE setManeuverDetail NOTIFY maneuverDetailChanged)
+ Q_PROPERTY(QJSValue waypoints READ waypoints WRITE setWaypoints NOTIFY waypointsChanged)
+ Q_PROPERTY(QJSValue excludedAreas READ excludedAreas WRITE setExcludedAreas NOTIFY excludedAreasChanged)
+ Q_PROPERTY(QList<int> featureTypes READ featureTypes NOTIFY featureTypesChanged)
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+
+ explicit QDeclarativeGeoRouteQuery(QObject *parent = 0);
+ ~QDeclarativeGeoRouteQuery();
+
+ // From QQmlParserStatus
+ void classBegin() {}
+ void componentComplete();
+
+ QGeoRouteRequest routeRequest() const;
+
+ enum TravelMode {
+ CarTravel = QGeoRouteRequest::CarTravel,
+ PedestrianTravel = QGeoRouteRequest::PedestrianTravel,
+ BicycleTravel = QGeoRouteRequest::BicycleTravel,
+ PublicTransitTravel = QGeoRouteRequest::PublicTransitTravel,
+ TruckTravel = QGeoRouteRequest::TruckTravel
+ };
+ Q_DECLARE_FLAGS(TravelModes, TravelMode)
+
+ enum FeatureType {
+ NoFeature = QGeoRouteRequest::NoFeature,
+ TollFeature = QGeoRouteRequest::TollFeature,
+ HighwayFeature = QGeoRouteRequest::HighwayFeature,
+ PublicTransitFeature = QGeoRouteRequest::PublicTransitFeature,
+ FerryFeature = QGeoRouteRequest::FerryFeature,
+ TunnelFeature = QGeoRouteRequest::TunnelFeature,
+ DirtRoadFeature = QGeoRouteRequest::DirtRoadFeature,
+ ParksFeature = QGeoRouteRequest::ParksFeature,
+ MotorPoolLaneFeature = QGeoRouteRequest::MotorPoolLaneFeature
+ };
+ Q_DECLARE_FLAGS(FeatureTypes, FeatureType)
+
+ enum FeatureWeight {
+ NeutralFeatureWeight = QGeoRouteRequest::NeutralFeatureWeight,
+ PreferFeatureWeight = QGeoRouteRequest::PreferFeatureWeight,
+ RequireFeatureWeight = QGeoRouteRequest::RequireFeatureWeight,
+ AvoidFeatureWeight = QGeoRouteRequest::AvoidFeatureWeight,
+ DisallowFeatureWeight = QGeoRouteRequest::DisallowFeatureWeight
+ };
+ Q_DECLARE_FLAGS(FeatureWeights, FeatureWeight)
+
+ enum RouteOptimization {
+ ShortestRoute = QGeoRouteRequest::ShortestRoute,
+ FastestRoute = QGeoRouteRequest::FastestRoute,
+ MostEconomicRoute = QGeoRouteRequest::MostEconomicRoute,
+ MostScenicRoute = QGeoRouteRequest::MostScenicRoute
+ };
+ Q_DECLARE_FLAGS(RouteOptimizations, RouteOptimization)
+
+ enum SegmentDetail {
+ NoSegmentData = 0x0000,
+ BasicSegmentData = 0x0001
+ };
+ Q_DECLARE_FLAGS(SegmentDetails, SegmentDetail)
+
+ enum ManeuverDetail {
+ NoManeuvers = 0x0000,
+ BasicManeuvers = 0x0001
+ };
+ Q_DECLARE_FLAGS(ManeuverDetails, ManeuverDetail)
+
+ void setNumberAlternativeRoutes(int numberAlternativeRoutes);
+ int numberAlternativeRoutes() const;
+
+ //QList<FeatureType> featureTypes();
+ QList<int> featureTypes();
+
+
+ QJSValue waypoints();
+ void setWaypoints(const QJSValue &value);
+
+ // READ functions for list properties
+ QJSValue excludedAreas() const;
+ void setExcludedAreas(const QJSValue &value);
+
+ Q_INVOKABLE void addWaypoint(const QGeoCoordinate &waypoint);
+ Q_INVOKABLE void removeWaypoint(const QGeoCoordinate &waypoint);
+ Q_INVOKABLE void clearWaypoints();
+
+ Q_INVOKABLE void addExcludedArea(const QGeoRectangle &area);
+ Q_INVOKABLE void removeExcludedArea(const QGeoRectangle &area);
+ Q_INVOKABLE void clearExcludedAreas();
+
+ Q_INVOKABLE void setFeatureWeight(FeatureType featureType, FeatureWeight featureWeight);
+ Q_INVOKABLE int featureWeight(FeatureType featureType);
+ Q_INVOKABLE void resetFeatureWeights();
+
+ /*
+ feature weights
+ */
+
+ void setTravelModes(TravelModes travelModes);
+ TravelModes travelModes() const;
+
+ void setSegmentDetail(SegmentDetail segmentDetail);
+ SegmentDetail segmentDetail() const;
+
+ void setManeuverDetail(ManeuverDetail maneuverDetail);
+ ManeuverDetail maneuverDetail() const;
+
+ void setRouteOptimizations(RouteOptimizations optimization);
+ RouteOptimizations routeOptimizations() const;
+
+Q_SIGNALS:
+ void numberAlternativeRoutesChanged();
+ void travelModesChanged();
+ void routeOptimizationsChanged();
+
+ void waypointsChanged();
+ void excludedAreasChanged();
+
+ void featureTypesChanged();
+ void maneuverDetailChanged();
+ void segmentDetailChanged();
+
+ void queryDetailsChanged();
+
+private Q_SLOTS:
+ void excludedAreaCoordinateChanged();
+
+private:
+ Q_INVOKABLE void doCoordinateChanged();
+
+ QGeoRouteRequest request_;
+ bool complete_;
+ bool m_excludedAreaCoordinateChanged;
+
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
new file mode 100644
index 00000000..acfe2441
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeoroutesegment_p.h"
+
+#include <QtQml/QQmlEngine>
+#include <QtQml/private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RouteSegment
+ \instantiates QDeclarativeGeoRouteSegment
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The RouteSegment type represents a segment of a Route.
+
+ A RouteSegment instance has information about the physical layout
+ of the route segment, the length of the route and estimated time required
+ to traverse the route segment and optional RouteManeuvers associated with
+ the end of the route segment.
+
+ RouteSegment instances can be thought of as edges on a routing
+ graph, with RouteManeuver instances as optional labels attached to the
+ vertices of the graph.
+
+ The primary means of acquiring Route objects is via Routes via \l RouteModel.
+
+ \section1 Example
+
+ The following QML snippet demonstrates how to print information about a
+ route segment:
+
+ \snippet declarative/routing.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/routing.qml RouteSegment
+*/
+
+QDeclarativeGeoRouteSegment::QDeclarativeGeoRouteSegment(QObject *parent)
+ : QObject(parent)
+{
+ maneuver_ = new QDeclarativeGeoManeuver(this);
+}
+
+QDeclarativeGeoRouteSegment::QDeclarativeGeoRouteSegment(const QGeoRouteSegment &segment,
+ QObject *parent)
+ : QObject(parent),
+ segment_(segment)
+{
+ maneuver_ = new QDeclarativeGeoManeuver(segment_.maneuver(), this);
+}
+
+QDeclarativeGeoRouteSegment::~QDeclarativeGeoRouteSegment() {}
+
+/*!
+ \qmlproperty int QtLocation::RouteSegment::travelTime
+
+ Read-only property which holds the estimated amount of time it will take to
+ traverse this segment, in seconds.
+
+*/
+
+int QDeclarativeGeoRouteSegment::travelTime() const
+{
+ return segment_.travelTime();
+}
+
+/*!
+ \qmlproperty real QtLocation::RouteSegment::distance
+
+ Read-only property which holds the distance covered by this segment of the route, in meters.
+
+*/
+
+qreal QDeclarativeGeoRouteSegment::distance() const
+{
+ return segment_.distance();
+}
+
+/*!
+ \qmlproperty RouteManeuver QtLocation::RouteSegment::maneuver
+
+ Read-only property which holds the maneuver for this route segment.
+
+ Will return invalid maneuver if no information has been attached to the endpoint
+ of this route segment.
+*/
+
+QDeclarativeGeoManeuver *QDeclarativeGeoRouteSegment::maneuver() const
+{
+ return maneuver_;
+}
+
+/*!
+ \qmlproperty QJSValue QtLocation::RouteSegment::path
+
+ Read-only property which holds the geographical coordinates of this segment.
+ 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 QDeclarativeGeoRouteSegment::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(segment_.path().length()));
+ for (int i = 0; i < segment_.path().length(); ++i) {
+ const QGeoCoordinate &c = segment_.path().at(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ pathArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, pathArray.asReturnedValue());
+}
+
+#include "moc_qdeclarativegeoroutesegment_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeoroutesegment_p.h b/src/location/declarativemaps/qdeclarativegeoroutesegment_p.h
new file mode 100644
index 00000000..c3203ef0
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutesegment_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOROUTESEGMENT_H
+#define QDECLARATIVEGEOROUTESEGMENT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomaneuver_p.h>
+
+#include <QtCore/QObject>
+#include <QtQml/qjsvalue.h>
+#include <QtLocation/QGeoRouteSegment>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteSegment : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int travelTime READ travelTime CONSTANT)
+ Q_PROPERTY(qreal distance READ distance CONSTANT)
+ Q_PROPERTY(QJSValue path READ path CONSTANT)
+ Q_PROPERTY(QDeclarativeGeoManeuver *maneuver READ maneuver CONSTANT)
+
+public:
+ explicit QDeclarativeGeoRouteSegment(QObject *parent = 0);
+ QDeclarativeGeoRouteSegment(const QGeoRouteSegment &segment, QObject *parent = 0);
+ ~QDeclarativeGeoRouteSegment();
+
+ int travelTime() const;
+ qreal distance() const;
+ QJSValue path() const;
+ QDeclarativeGeoManeuver *maneuver() const;
+
+private:
+ QGeoRouteSegment segment_;
+ QDeclarativeGeoManeuver *maneuver_;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp
new file mode 100644
index 00000000..994b4913
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp
@@ -0,0 +1,821 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeoserviceprovider_p.h"
+#include <QtQml/QQmlInfo>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Plugin
+ \instantiates QDeclarativeGeoServiceProvider
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-common
+ \since Qt Location 5.5
+
+ \brief The Plugin type describes a Location based services plugin.
+
+ The Plugin type is used to declaratively specify which available
+ GeoServices plugin should be used for various tasks in the Location API.
+ Plugins are used by \l Map, \l RouteModel, and \l GeocodeModel
+ types, as well as a variety of others.
+
+ Plugins recognized by the system have a \l name property, a simple string
+ normally indicating the name of the service that the Plugin retrieves
+ data from. They also have a variety of features, which can be test for using the
+ \l {supportsRouting()}, \l {supportsGeocoding()}, \l {supportsMapping()} and
+ \l {supportsPlaces()} methods.
+
+ When a Plugin object is created, it is "detached" and not associated with
+ any actual service plugin. Once it has received information via setting
+ its \l name, \l preferred, or \l required properties, it will choose an
+ appropriate service plugin to attach to. Plugin objects can only be
+ attached once; to use multiple plugins, create multiple Plugin objects.
+
+ \section2 Example Usage
+
+ The following snippet shows a Plugin object being created with the
+ \l required and \l preferred properties set. This Plugin will attach to the
+ first found plugin that supports both mapping and geocoding, and will
+ prefer plugins named "here" or "osm" to any others.
+
+ \code
+ Plugin {
+ id: plugin
+ preferred: ["here", "osm"]
+ required: Plugin.AnyMappingFeatures | Plugin.AnyGeocodingFeatures
+ }
+ \endcode
+*/
+
+QDeclarativeGeoServiceProvider::QDeclarativeGeoServiceProvider(QObject *parent)
+: QObject(parent),
+ sharedProvider_(0),
+ required_(new QDeclarativeGeoServiceProviderRequirements),
+ complete_(false),
+ experimental_(false)
+{
+ locales_.append(QLocale().name());
+}
+
+QDeclarativeGeoServiceProvider::~QDeclarativeGeoServiceProvider()
+{
+ delete required_;
+ delete sharedProvider_;
+}
+
+
+
+/*!
+ \qmlproperty string Plugin::name
+
+ This property holds the name of the plugin. Setting this property
+ will cause the Plugin to only attach to a plugin with exactly this
+ name. The value of \l required will be ignored.
+*/
+void QDeclarativeGeoServiceProvider::setName(const QString &name)
+{
+ if (name_ == name)
+ return;
+
+ name_ = name;
+ delete sharedProvider_;
+ sharedProvider_ = new QGeoServiceProvider(name_, parameterMap());
+ sharedProvider_->setLocale(locales_.at(0));
+ sharedProvider_->setAllowExperimental(experimental_);
+
+ emit nameChanged(name_);
+ emit attached();
+}
+
+QString QDeclarativeGeoServiceProvider::name() const
+{
+ return name_;
+}
+
+
+/*!
+ \qmlproperty stringlist Plugin::availableServiceProviders
+
+ This property holds a list of all available service plugins' names. This
+ can be used to manually enumerate the available plugins if the
+ control provided by \l name and \l required is not sufficient for your
+ needs.
+*/
+QStringList QDeclarativeGeoServiceProvider::availableServiceProviders()
+{
+ return QGeoServiceProvider::availableServiceProviders();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProvider::componentComplete()
+{
+ complete_ = true;
+ if (!name_.isEmpty()) {
+ return;
+ }
+
+ if (!prefer_.isEmpty()
+ || required_->mappingRequirements() != NoMappingFeatures
+ || required_->routingRequirements() != NoRoutingFeatures
+ || required_->geocodingRequirements() != NoGeocodingFeatures
+ || required_->placesRequirements() != NoPlacesFeatures) {
+
+ QStringList providers = QGeoServiceProvider::availableServiceProviders();
+
+ /* first check any preferred plugins */
+ foreach (const QString &name, prefer_) {
+ if (providers.contains(name)) {
+ // so we don't try it again later
+ providers.removeAll(name);
+
+ QGeoServiceProvider sp(name, parameterMap(), experimental_);
+ if (required_->matches(&sp)) {
+ setName(name);
+ return;
+ }
+ }
+ }
+
+ /* then try the rest */
+ foreach (const QString &name, providers) {
+ QGeoServiceProvider sp(name, parameterMap(), experimental_);
+ if (required_->matches(&sp)) {
+ setName(name);
+ return;
+ }
+ }
+
+ qmlWarning(this) << "Could not find a plugin with the required features to attach to";
+ }
+}
+
+/*!
+ \qmlmethod bool Plugin::supportsGeocoding(GeocodingFeatures features)
+
+ This method returns a boolean indicating whether the specified set of \a features are supported
+ by the geo service provider plugin. True is returned if all specified \a features are
+ supported; otherwise false is returned.
+
+ The \a features parameter can be any flag combination of:
+ \table
+ \header
+ \li Feature
+ \li Description
+ \row
+ \li Plugin.NoGeocodingFeatures
+ \li No geocoding features are supported.
+ \row
+ \li Plugin.OnlineGeocodingFeature
+ \li Online geocoding is supported.
+ \row
+ \li Plugin.OfflineGeocodingFeature
+ \li Offline geocoding is supported.
+ \row
+ \li Plugin.ReverseGeocodingFeature
+ \li Reverse geocoding is supported.
+ \row
+ \li Plugin.LocalizedGeocodingFeature
+ \li Supports returning geocoding results with localized addresses.
+ \row
+ \li Plugin.AnyGeocodingFeatures
+ \li Matches a geo service provider that provides any geocoding features.
+ \endtable
+*/
+bool QDeclarativeGeoServiceProvider::supportsGeocoding(const GeocodingFeatures &feature) const
+{
+ QGeoServiceProvider *sp = sharedGeoServiceProvider();
+ QGeoServiceProvider::GeocodingFeatures f =
+ static_cast<QGeoServiceProvider::GeocodingFeature>(int(feature));
+ if (f == QGeoServiceProvider::AnyGeocodingFeatures)
+ return (sp && (sp->geocodingFeatures() != QGeoServiceProvider::NoGeocodingFeatures));
+ else
+ return (sp && (sp->geocodingFeatures() & f) == f);
+}
+
+/*!
+ \qmlmethod bool Plugin::supportsMapping(MappingFeatures features)
+
+ This method returns a boolean indicating whether the specified set of \a features are supported
+ by the geo service provider plugin. True is returned if all specified \a features are
+ supported; otherwise false is returned.
+
+ The \a features parameter can be any flag combination of:
+ \table
+ \header
+ \li Feature
+ \li Description
+ \row
+ \li Plugin.NoMappingFeatures
+ \li No mapping features are supported.
+ \row
+ \li Plugin.OnlineMappingFeature
+ \li Online mapping is supported.
+ \row
+ \li Plugin.OfflineMappingFeature
+ \li Offline mapping is supported.
+ \row
+ \li Plugin.LocalizedMappingFeature
+ \li Supports returning localized map data.
+ \row
+ \li Plugin.AnyMappingFeatures
+ \li Matches a geo service provider that provides any mapping features.
+ \endtable
+*/
+bool QDeclarativeGeoServiceProvider::supportsMapping(const MappingFeatures &feature) const
+{
+ QGeoServiceProvider *sp = sharedGeoServiceProvider();
+ QGeoServiceProvider::MappingFeatures f =
+ static_cast<QGeoServiceProvider::MappingFeature>(int(feature));
+ if (f == QGeoServiceProvider::AnyMappingFeatures)
+ return (sp && (sp->mappingFeatures() != QGeoServiceProvider::NoMappingFeatures));
+ else
+ return (sp && (sp->mappingFeatures() & f) == f);
+}
+
+/*!
+ \qmlmethod bool Plugin::supportsRouting(RoutingFeatures features)
+
+ This method returns a boolean indicating whether the specified set of \a features are supported
+ by the geo service provider plugin. True is returned if all specified \a features are
+ supported; otherwise false is returned.
+
+ The \a features parameter can be any flag combination of:
+ \table
+ \header
+ \li Feature
+ \li Description
+ \row
+ \li Plugin.NoRoutingFeatures
+ \li No routing features are supported.
+ \row
+ \li Plugin.OnlineRoutingFeature
+ \li Online routing is supported.
+ \row
+ \li Plugin.OfflineRoutingFeature
+ \li Offline routing is supported.
+ \row
+ \li Plugin.LocalizedRoutingFeature
+ \li Supports returning routes with localized addresses and instructions.
+ \row
+ \li Plugin.RouteUpdatesFeature
+ \li Updating an existing route based on the current position is supported.
+ \row
+ \li Plugin.AlternativeRoutesFeature
+ \li Supports returning alternative routes.
+ \row
+ \li Plugin.ExcludeAreasRoutingFeature
+ \li Supports specifying a areas which the returned route must not cross.
+ \row
+ \li Plugin.AnyRoutingFeatures
+ \li Matches a geo service provider that provides any routing features.
+ \endtable
+*/
+bool QDeclarativeGeoServiceProvider::supportsRouting(const RoutingFeatures &feature) const
+{
+ QGeoServiceProvider *sp = sharedGeoServiceProvider();
+ QGeoServiceProvider::RoutingFeatures f =
+ static_cast<QGeoServiceProvider::RoutingFeature>(int(feature));
+ if (f == QGeoServiceProvider::AnyRoutingFeatures)
+ return (sp && (sp->routingFeatures() != QGeoServiceProvider::NoRoutingFeatures));
+ else
+ return (sp && (sp->routingFeatures() & f) == f);
+}
+
+/*!
+ \qmlmethod bool Plugin::supportsPlaces(PlacesFeatures features)
+
+ This method returns a boolean indicating whether the specified set of \a features are supported
+ by the geo service provider plugin. True is returned if all specified \a features are
+ supported; otherwise false is returned.
+
+ The \a features parameter can be any flag combination of:
+ \table
+ \header
+ \li Feature
+ \li Description
+ \row
+ \li Plugin.NoPlacesFeatures
+ \li No places features are supported.
+ \row
+ \li Plugin.OnlinePlacesFeature
+ \li Online places is supported.
+ \row
+ \li Plugin.OfflinePlacesFeature
+ \li Offline places is supported.
+ \row
+ \li Plugin.SavePlaceFeature
+ \li Saving categories is supported.
+ \row
+ \li Plugin.RemovePlaceFeature
+ \li Removing or deleting places is supported.
+ \row
+ \li Plugin.PlaceRecommendationsFeature
+ \li Searching for recommended places similar to another place is supported.
+ \row
+ \li Plugin.SearchSuggestionsFeature
+ \li Search suggestions is supported.
+ \row
+ \li Plugin.LocalizedPlacesFeature
+ \li Supports returning localized place data.
+ \row
+ \li Plugin.NotificationsFeature
+ \li Notifications of place and category changes is supported.
+ \row
+ \li Plugin.PlaceMatchingFeature
+ \li Supports matching places from two different geo service providers.
+ \row
+ \li Plugin.AnyPlacesFeatures
+ \li Matches a geo service provider that provides any places features.
+ \endtable
+*/
+bool QDeclarativeGeoServiceProvider::supportsPlaces(const PlacesFeatures &features) const
+{
+ QGeoServiceProvider *sp = sharedGeoServiceProvider();
+ QGeoServiceProvider::PlacesFeatures f =
+ static_cast<QGeoServiceProvider::PlacesFeature>(int(features));
+ if (f == QGeoServiceProvider::AnyPlacesFeatures)
+ return (sp && (sp->placesFeatures() != QGeoServiceProvider::NoPlacesFeatures));
+ else
+ return (sp && (sp->placesFeatures() & f) == f);
+}
+
+/*!
+ \qmlproperty enumeration Plugin::required
+
+ This property contains the set of features that will be required by the
+ Plugin object when choosing which service plugin to attach to. If the
+ \l name property is set, this has no effect.
+
+ Any of the following values or a bitwise combination of multiple values
+ may be set:
+
+ \list
+ \li Plugin.NoFeatures
+ \li Plugin.GeocodingFeature
+ \li Plugin.ReverseGeocodingFeature
+ \li Plugin.RoutingFeature
+ \li Plugin.MappingFeature
+ \li Plugin.AnyPlacesFeature
+ \endlist
+*/
+QDeclarativeGeoServiceProviderRequirements *QDeclarativeGeoServiceProvider::requirements() const
+{
+ return required_;
+}
+
+/*!
+ \qmlproperty stringlist Plugin::preferred
+
+ This property contains an ordered list of preferred plugin names, which
+ will be checked for the required features set in \l{Plugin::required}{required}
+ before any other available plugins are checked.
+*/
+QStringList QDeclarativeGeoServiceProvider::preferred() const
+{
+ return prefer_;
+}
+
+void QDeclarativeGeoServiceProvider::setPreferred(const QStringList &val)
+{
+ prefer_ = val;
+ emit preferredChanged(prefer_);
+}
+
+/*!
+ \qmlproperty bool Plugin::isAttached
+
+ This property indicates if the Plugin item is attached to a geoservice provider plugin.
+*/
+bool QDeclarativeGeoServiceProvider::isAttached() const
+{
+ return (sharedProvider_ != 0);
+}
+
+/*!
+ \qmlproperty bool Plugin::allowExperimental
+
+ This property indicates if experimental plugins can be used.
+*/
+bool QDeclarativeGeoServiceProvider::allowExperimental() const
+{
+ return experimental_;
+}
+
+void QDeclarativeGeoServiceProvider::setAllowExperimental(bool allow)
+{
+ if (experimental_ == allow)
+ return;
+
+ experimental_ = allow;
+ if (sharedProvider_)
+ sharedProvider_->setAllowExperimental(allow);
+
+ emit allowExperimentalChanged(allow);
+}
+
+/*!
+ \internal
+*/
+QGeoServiceProvider *QDeclarativeGeoServiceProvider::sharedGeoServiceProvider() const
+{
+ return sharedProvider_;
+}
+
+/*!
+ \qmlproperty stringlist Plugin::locales
+
+ This property contains an ordered list of preferred plugin locales. If the first locale cannot be accommodated, then
+ the backend falls back to using the second, and so on. By default the locales property contains the system locale.
+
+ The locales are specified as strings which have the format
+ "language[_script][_country]" or "C", where:
+
+ \list
+ \li language is a lowercase, two-letter, ISO 639 language code,
+ \li script is a titlecase, four-letter, ISO 15924 script code,
+ \li country is an uppercase, two- or three-letter, ISO 3166 country code (also "419" as defined by United Nations),
+ \li the "C" locale is identical in behavior to English/UnitedStates as per QLocale
+ \endlist
+
+ If the first specified locale cannot be accommodated, the \l {Plugin} falls back to the next and so forth.
+ Some \l {Plugin} backends may not support a set of locales which are rigidly defined. An arbitrary
+ example is that some \l {Place}'s in France could have French and English localizations, while
+ certain areas in America may only have the English localization available. In the above scenario,
+ the set of supported locales is context dependent on the search location.
+
+ If the \l {Plugin} cannot accommodate any of the preferred locales, the manager falls
+ back to using a supported language that is backend specific.
+
+ For \l {Plugin}'s that do not support locales, the locales list is always empty.
+
+ The following code demonstrates how to set a single and multiple locales:
+ \snippet declarative/plugin.qml Plugin locale
+*/
+QStringList QDeclarativeGeoServiceProvider::locales() const
+{
+ return locales_;
+}
+
+void QDeclarativeGeoServiceProvider::setLocales(const QStringList &locales)
+{
+ if (locales_ == locales)
+ return;
+
+ locales_ = locales;
+
+ if (locales_.isEmpty())
+ locales_.append(QLocale().name());
+
+ if (sharedProvider_)
+ sharedProvider_->setLocale(locales_.at(0));
+
+ emit localesChanged();
+}
+
+/*!
+ \qmlproperty list<PluginParameter> Plugin::parameters
+ \default
+
+ This property holds the list of plugin parameters.
+*/
+QQmlListProperty<QDeclarativeGeoServiceProviderParameter> QDeclarativeGeoServiceProvider::parameters()
+{
+ return QQmlListProperty<QDeclarativeGeoServiceProviderParameter>(this,
+ 0,
+ parameter_append,
+ parameter_count,
+ parameter_at,
+ parameter_clear);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProvider::parameter_append(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, QDeclarativeGeoServiceProviderParameter *parameter)
+{
+ QDeclarativeGeoServiceProvider *p = static_cast<QDeclarativeGeoServiceProvider *>(prop->object);
+ p->parameters_.append(parameter);
+ if (p->sharedProvider_)
+ p->sharedProvider_->setParameters(p->parameterMap());
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeGeoServiceProvider::parameter_count(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop)
+{
+ return static_cast<QDeclarativeGeoServiceProvider *>(prop->object)->parameters_.count();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProviderParameter *QDeclarativeGeoServiceProvider::parameter_at(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, int index)
+{
+ return static_cast<QDeclarativeGeoServiceProvider *>(prop->object)->parameters_[index];
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProvider::parameter_clear(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop)
+{
+ QDeclarativeGeoServiceProvider *p = static_cast<QDeclarativeGeoServiceProvider *>(prop->object);
+ p->parameters_.clear();
+ if (p->sharedProvider_)
+ p->sharedProvider_->setParameters(p->parameterMap());
+}
+
+/*!
+ \internal
+*/
+QVariantMap QDeclarativeGeoServiceProvider::parameterMap() const
+{
+ QVariantMap map;
+
+ for (int i = 0; i < parameters_.size(); ++i) {
+ QDeclarativeGeoServiceProviderParameter *parameter = parameters_.at(i);
+ map.insert(parameter->name(), parameter->value());
+ }
+
+ return map;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+
+QDeclarativeGeoServiceProviderRequirements::QDeclarativeGeoServiceProviderRequirements(QObject *parent)
+ : QObject(parent),
+ mapping_(QDeclarativeGeoServiceProvider::NoMappingFeatures),
+ routing_(QDeclarativeGeoServiceProvider::NoRoutingFeatures),
+ geocoding_(QDeclarativeGeoServiceProvider::NoGeocodingFeatures),
+ places_(QDeclarativeGeoServiceProvider::NoPlacesFeatures)
+{
+}
+
+QDeclarativeGeoServiceProviderRequirements::~QDeclarativeGeoServiceProviderRequirements()
+{
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider::MappingFeatures QDeclarativeGeoServiceProviderRequirements::mappingRequirements() const
+{
+ return mapping_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProviderRequirements::setMappingRequirements(const QDeclarativeGeoServiceProvider::MappingFeatures &features)
+{
+ if (mapping_ == features)
+ return;
+
+ mapping_ = features;
+ emit mappingRequirementsChanged(mapping_);
+ emit requirementsChanged();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider::RoutingFeatures QDeclarativeGeoServiceProviderRequirements::routingRequirements() const
+{
+ return routing_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProviderRequirements::setRoutingRequirements(const QDeclarativeGeoServiceProvider::RoutingFeatures &features)
+{
+ if (routing_ == features)
+ return;
+
+ routing_ = features;
+ emit routingRequirementsChanged(routing_);
+ emit requirementsChanged();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider::GeocodingFeatures QDeclarativeGeoServiceProviderRequirements::geocodingRequirements() const
+{
+ return geocoding_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProviderRequirements::setGeocodingRequirements(const QDeclarativeGeoServiceProvider::GeocodingFeatures &features)
+{
+ if (geocoding_ == features)
+ return;
+
+ geocoding_ = features;
+ emit geocodingRequirementsChanged(geocoding_);
+ emit requirementsChanged();
+}
+
+/*!
+ \internal
+
+ */
+QDeclarativeGeoServiceProvider::PlacesFeatures QDeclarativeGeoServiceProviderRequirements::placesRequirements() const
+{
+ return places_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProviderRequirements::setPlacesRequirements(const QDeclarativeGeoServiceProvider::PlacesFeatures &features)
+{
+ if (places_ == features)
+ return;
+
+ places_ = features;
+ emit placesRequirementsChanged(places_);
+ emit requirementsChanged();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoServiceProviderRequirements::matches(const QGeoServiceProvider *provider) const
+{
+ QGeoServiceProvider::MappingFeatures mapping =
+ static_cast<QGeoServiceProvider::MappingFeatures>(int(mapping_));
+
+ // extra curlies here to avoid "dangling" else, which could belong to either if
+ // same goes for all the rest of these blocks
+ if (mapping == QGeoServiceProvider::AnyMappingFeatures) {
+ if (provider->mappingFeatures() == QGeoServiceProvider::NoMappingFeatures)
+ return false;
+ } else {
+ if ((provider->mappingFeatures() & mapping) != mapping)
+ return false;
+ }
+
+ QGeoServiceProvider::RoutingFeatures routing =
+ static_cast<QGeoServiceProvider::RoutingFeatures>(int(routing_));
+
+ if (routing == QGeoServiceProvider::AnyRoutingFeatures) {
+ if (provider->routingFeatures() == QGeoServiceProvider::NoRoutingFeatures)
+ return false;
+ } else {
+ if ((provider->routingFeatures() & routing) != routing)
+ return false;
+ }
+
+ QGeoServiceProvider::GeocodingFeatures geocoding =
+ static_cast<QGeoServiceProvider::GeocodingFeatures>(int(geocoding_));
+
+ if (geocoding == QGeoServiceProvider::AnyGeocodingFeatures) {
+ if (provider->geocodingFeatures() == QGeoServiceProvider::NoGeocodingFeatures)
+ return false;
+ } else {
+ if ((provider->geocodingFeatures() & geocoding) != geocoding)
+ return false;
+ }
+
+ QGeoServiceProvider::PlacesFeatures places =
+ static_cast<QGeoServiceProvider::PlacesFeatures>(int(places_));
+
+ if (places == QGeoServiceProvider::AnyPlacesFeatures) {
+ if (provider->placesFeatures() == QGeoServiceProvider::NoPlacesFeatures)
+ return false;
+ } else {
+ if ((provider->placesFeatures() & places) != places)
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+
+/*!
+ \qmltype PluginParameter
+ \instantiates QDeclarativeGeoServiceProviderParameter
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-common
+ \since Qt Location 5.5
+
+ \brief The PluginParameter type describes a parameter to a \l Plugin.
+
+ The PluginParameter object is used to provide a parameter of some kind
+ to a Plugin. Typically these parameters contain details like an application
+ token for access to a service, or a proxy server to use for network access.
+
+ To set such a parameter, declare a PluginParameter inside a \l Plugin
+ object, and give it \l{name} and \l{value} properties. A list of valid
+ parameter names for each plugin is available from the
+ \l {Qt Location#Plugin References and Parameters}{plugin reference pages}.
+
+ \section2 Example Usage
+
+ The following example shows an instantiation of the \l {Qt Location HERE Plugin}{HERE} plugin
+ with a mapping API \e app_id and \e token pair specific to the application.
+
+ \code
+ Plugin {
+ name: "here"
+ PluginParameter { name: "here.app_id"; value: "EXAMPLE_API_ID" }
+ PluginParameter { name: "here.token"; value: "EXAMPLE_TOKEN_123" }
+ }
+ \endcode
+*/
+
+QDeclarativeGeoServiceProviderParameter::QDeclarativeGeoServiceProviderParameter(QObject *parent)
+ : QObject(parent) {}
+
+QDeclarativeGeoServiceProviderParameter::~QDeclarativeGeoServiceProviderParameter() {}
+
+/*!
+ \qmlproperty string PluginParameter::name
+
+ This property holds the name of the plugin parameter as a single formatted string.
+*/
+void QDeclarativeGeoServiceProviderParameter::setName(const QString &name)
+{
+ if (name_ == name)
+ return;
+
+ name_ = name;
+
+ emit nameChanged(name_);
+}
+
+QString QDeclarativeGeoServiceProviderParameter::name() const
+{
+ return name_;
+}
+
+/*!
+ \qmlproperty QVariant PluginParameter::value
+
+ This property holds the value of the plugin parameter which support different types of values (variant).
+*/
+void QDeclarativeGeoServiceProviderParameter::setValue(const QVariant &value)
+{
+ if (value_ == value)
+ return;
+
+ value_ = value;
+
+ emit valueChanged(value_);
+}
+
+QVariant QDeclarativeGeoServiceProviderParameter::value() const
+{
+ return value_;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+
+#include "moc_qdeclarativegeoserviceprovider_p.cpp"
+
+QT_END_NAMESPACE
+
diff --git a/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h b/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h
new file mode 100644
index 00000000..bcf67124
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEQGEOSERVICEPROVIDER_H
+#define QDECLARATIVEQGEOSERVICEPROVIDER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlListProperty>
+#include <QtLocation/QGeoServiceProvider>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProviderParameter : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ explicit QDeclarativeGeoServiceProviderParameter(QObject *parent = 0);
+ ~QDeclarativeGeoServiceProviderParameter();
+
+ void setName(const QString &name);
+ QString name() const;
+
+ void setValue(const QVariant &value);
+ QVariant value() const;
+
+Q_SIGNALS:
+ void nameChanged(const QString &name);
+ void valueChanged(const QVariant &value);
+
+private:
+ QString name_;
+ QVariant value_;
+};
+
+class QDeclarativeGeoServiceProviderRequirements;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProvider : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_ENUMS(RoutingFeature)
+ Q_ENUMS(GeocodingFeature)
+ Q_ENUMS(MappingFeature)
+ Q_ENUMS(PlacesFeature)
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QStringList availableServiceProviders READ availableServiceProviders CONSTANT)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> parameters READ parameters)
+ Q_PROPERTY(QDeclarativeGeoServiceProviderRequirements *required READ requirements)
+ Q_PROPERTY(QStringList locales READ locales WRITE setLocales NOTIFY localesChanged)
+ Q_PROPERTY(QStringList preferred READ preferred WRITE setPreferred NOTIFY preferredChanged)
+ Q_PROPERTY(bool allowExperimental READ allowExperimental WRITE setAllowExperimental NOTIFY allowExperimentalChanged)
+ Q_PROPERTY(bool isAttached READ isAttached NOTIFY attached)
+
+ Q_CLASSINFO("DefaultProperty", "parameters")
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativeGeoServiceProvider(QObject *parent = Q_NULLPTR);
+ ~QDeclarativeGeoServiceProvider();
+
+ enum RoutingFeature {
+ NoRoutingFeatures = QGeoServiceProvider::NoRoutingFeatures,
+ OnlineRoutingFeature = QGeoServiceProvider::OnlineRoutingFeature,
+ OfflineRoutingFeature = QGeoServiceProvider::OfflineRoutingFeature,
+ LocalizedRoutingFeature = QGeoServiceProvider::LocalizedRoutingFeature,
+ RouteUpdatesFeature = QGeoServiceProvider::RouteUpdatesFeature,
+ AlternativeRoutesFeature = QGeoServiceProvider::AlternativeRoutesFeature,
+ ExcludeAreasRoutingFeature = QGeoServiceProvider::ExcludeAreasRoutingFeature,
+ AnyRoutingFeatures = QGeoServiceProvider::AnyRoutingFeatures
+ };
+
+ enum GeocodingFeature {
+ NoGeocodingFeatures = QGeoServiceProvider::NoGeocodingFeatures,
+ OnlineGeocodingFeature = QGeoServiceProvider::OnlineGeocodingFeature,
+ OfflineGeocodingFeature = QGeoServiceProvider::OfflineGeocodingFeature,
+ ReverseGeocodingFeature = QGeoServiceProvider::ReverseGeocodingFeature,
+ LocalizedGeocodingFeature = QGeoServiceProvider::LocalizedGeocodingFeature,
+ AnyGeocodingFeatures = QGeoServiceProvider::AnyGeocodingFeatures
+ };
+
+ enum MappingFeature {
+ NoMappingFeatures = QGeoServiceProvider::NoMappingFeatures,
+ OnlineMappingFeature = QGeoServiceProvider::OnlineMappingFeature,
+ OfflineMappingFeature = QGeoServiceProvider::OfflineMappingFeature,
+ LocalizedMappingFeature = QGeoServiceProvider::LocalizedMappingFeature,
+ AnyMappingFeatures = QGeoServiceProvider::AnyMappingFeatures
+ };
+
+ enum PlacesFeature {
+ NoPlacesFeatures = QGeoServiceProvider::NoPlacesFeatures,
+ OnlinePlacesFeature = QGeoServiceProvider::OnlinePlacesFeature,
+ OfflinePlacesFeature = QGeoServiceProvider::OfflinePlacesFeature,
+ SavePlaceFeature = QGeoServiceProvider::SavePlaceFeature,
+ RemovePlaceFeature = QGeoServiceProvider::RemovePlaceFeature,
+ SaveCategoryFeature = QGeoServiceProvider::SaveCategoryFeature,
+ RemoveCategoryFeature = QGeoServiceProvider::RemoveCategoryFeature,
+ PlaceRecommendationsFeature = QGeoServiceProvider::PlaceRecommendationsFeature,
+ SearchSuggestionsFeature = QGeoServiceProvider::SearchSuggestionsFeature,
+ LocalizedPlacesFeature = QGeoServiceProvider::LocalizedPlacesFeature,
+ NotificationsFeature = QGeoServiceProvider::NotificationsFeature,
+ PlaceMatchingFeature = QGeoServiceProvider::PlaceMatchingFeature,
+ AnyPlacesFeatures = QGeoServiceProvider::AnyPlacesFeatures
+ };
+
+ Q_DECLARE_FLAGS(RoutingFeatures, RoutingFeature)
+ Q_FLAGS(RoutingFeatures)
+
+ Q_DECLARE_FLAGS(GeocodingFeatures, GeocodingFeature)
+ Q_FLAGS(GeocodingFeatures)
+
+ Q_DECLARE_FLAGS(MappingFeatures, MappingFeature)
+ Q_FLAGS(MappingFeatures)
+
+ Q_DECLARE_FLAGS(PlacesFeatures, PlacesFeature)
+ Q_FLAGS(PlacesFeatures)
+
+ // From QQmlParserStatus
+ virtual void classBegin() {}
+ virtual void componentComplete();
+
+ void setName(const QString &name);
+ QString name() const;
+
+ QQmlListProperty<QDeclarativeGeoServiceProviderParameter> parameters();
+ QVariantMap parameterMap() const;
+
+ QStringList availableServiceProviders();
+
+ QDeclarativeGeoServiceProviderRequirements *requirements() const;
+
+ QStringList preferred() const;
+ void setPreferred(const QStringList &val);
+
+ QGeoServiceProvider *sharedGeoServiceProvider() const;
+
+ Q_INVOKABLE bool supportsRouting(const RoutingFeatures &feature = AnyRoutingFeatures) const;
+ Q_INVOKABLE bool supportsGeocoding(const GeocodingFeatures &feature = AnyGeocodingFeatures) const;
+ Q_INVOKABLE bool supportsMapping(const MappingFeatures &feature = AnyMappingFeatures) const;
+ Q_INVOKABLE bool supportsPlaces(const PlacesFeatures &feature = AnyPlacesFeatures) const;
+
+ QStringList locales() const;
+ void setLocales(const QStringList &locales);
+
+ bool isAttached() const;
+
+ void setAllowExperimental(bool allow);
+ bool allowExperimental() const;
+
+Q_SIGNALS:
+ void nameChanged(const QString &name);
+ void localesChanged();
+ void attached();
+ void preferredChanged(const QStringList &preferences);
+ void allowExperimentalChanged(bool allow);
+
+private:
+ static void parameter_append(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, QDeclarativeGeoServiceProviderParameter *mapObject);
+ static int parameter_count(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop);
+ static QDeclarativeGeoServiceProviderParameter *parameter_at(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, int index);
+ static void parameter_clear(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop);
+
+ QGeoServiceProvider *sharedProvider_;
+ QString name_;
+ QList<QDeclarativeGeoServiceProviderParameter *> parameters_;
+ QDeclarativeGeoServiceProviderRequirements *required_;
+ bool complete_;
+ bool experimental_;
+ QStringList locales_;
+ QStringList prefer_;
+ Q_DISABLE_COPY(QDeclarativeGeoServiceProvider)
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProviderRequirements : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QDeclarativeGeoServiceProvider::MappingFeatures mapping
+ READ mappingRequirements WRITE setMappingRequirements
+ NOTIFY mappingRequirementsChanged)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider::RoutingFeatures routing
+ READ routingRequirements WRITE setRoutingRequirements
+ NOTIFY routingRequirementsChanged)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider::GeocodingFeatures geocoding
+ READ geocodingRequirements WRITE setGeocodingRequirements
+ NOTIFY geocodingRequirementsChanged)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider::PlacesFeatures places
+ READ placesRequirements WRITE setPlacesRequirements
+ NOTIFY placesRequirementsChanged)
+
+public:
+ explicit QDeclarativeGeoServiceProviderRequirements(QObject *parent = 0);
+ ~QDeclarativeGeoServiceProviderRequirements();
+
+ QDeclarativeGeoServiceProvider::MappingFeatures mappingRequirements() const;
+ void setMappingRequirements(const QDeclarativeGeoServiceProvider::MappingFeatures &features);
+
+ QDeclarativeGeoServiceProvider::RoutingFeatures routingRequirements() const;
+ void setRoutingRequirements(const QDeclarativeGeoServiceProvider::RoutingFeatures &features);
+
+ QDeclarativeGeoServiceProvider::GeocodingFeatures geocodingRequirements() const;
+ void setGeocodingRequirements(const QDeclarativeGeoServiceProvider::GeocodingFeatures &features);
+
+ QDeclarativeGeoServiceProvider::PlacesFeatures placesRequirements() const;
+ void setPlacesRequirements(const QDeclarativeGeoServiceProvider::PlacesFeatures &features);
+
+ Q_INVOKABLE bool matches(const QGeoServiceProvider *provider) const;
+
+Q_SIGNALS:
+ void mappingRequirementsChanged(const QDeclarativeGeoServiceProvider::MappingFeatures &features);
+ void routingRequirementsChanged(const QDeclarativeGeoServiceProvider::RoutingFeatures &features);
+ void geocodingRequirementsChanged(const QDeclarativeGeoServiceProvider::GeocodingFeatures &features);
+ void placesRequirementsChanged(const QDeclarativeGeoServiceProvider::PlacesFeatures &features);
+
+ void requirementsChanged();
+
+private:
+ QDeclarativeGeoServiceProvider::MappingFeatures mapping_;
+ QDeclarativeGeoServiceProvider::RoutingFeatures routing_;
+ QDeclarativeGeoServiceProvider::GeocodingFeatures geocoding_;
+ QDeclarativeGeoServiceProvider::PlacesFeatures places_;
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoServiceProviderParameter)
+QML_DECLARE_TYPE(QDeclarativeGeoServiceProviderRequirements)
+QML_DECLARE_TYPE(QDeclarativeGeoServiceProvider)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
new file mode 100644
index 00000000..3f05957a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
@@ -0,0 +1,743 @@
+/****************************************************************************
+ **
+ ** 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 "qdeclarativepolygonmapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qlocationutils_p.h"
+#include "error_messages.h"
+#include "locationvaluetypehelper_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <QtCore/QScopedValueRollback>
+#include <QtGui/private/qtriangulator_p.h>
+#include <QtQml/QQmlInfo>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QPainter>
+#include <QPainterPath>
+#include <qnumeric.h>
+
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtPositioning/private/qclipperutils_p.h>
+
+/* poly2tri triangulator includes */
+#include <clip2tri.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapPolygon
+ \instantiates QDeclarativePolygonMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapPolygon type displays a polygon on a Map
+
+ The MapPolygon type displays a polygon on a Map, specified in terms of an ordered list of
+ \l {QtPositioning::coordinate}{coordinates}. For best appearance and results, polygons should be
+ simple (not self-intersecting).
+
+ The \l {QtPositioning::coordinate}{coordinates} on the path cannot be directly changed after
+ being added to the Polygon. Instead, copy the \l path into a var, modify the copy and reassign
+ the copy back to the \l path.
+
+ \code
+ var path = mapPolygon.path;
+ path[0].latitude = 5;
+ mapPolygon.path = path;
+ \endcode
+
+ Coordinates can also be added and removed at any time using the \l addCoordinate and
+ \l removeCoordinate methods.
+
+ For drawing rectangles with "straight" edges (same latitude across one
+ edge, same latitude across the other), the \l MapRectangle type provides
+ a simpler, two-point API.
+
+ By default, the polygon is displayed as a 1 pixel black border with no
+ fill. To change its appearance, use the \l color, \l border.color and
+ \l border.width properties.
+
+ \note Since MapPolygons are geographic items, dragging a MapPolygon
+ (through the use of \l MouseArea) causes its vertices to be
+ recalculated in the geographic coordinate space. The edges retain the
+ same geographic lengths (latitude and longitude differences between the
+ vertices), but they remain straight. Apparent stretching of the item occurs
+ when dragged to a different latitude.
+
+ \section2 Performance
+
+ MapPolygons have a rendering cost that is O(n) with respect to the number
+ of vertices. This means that the per frame cost of having a Polygon on the
+ Map grows in direct proportion to the number of points on the Polygon. There
+ is an additional triangulation cost (approximately O(n log n)) which is
+ currently paid with each frame, but in future may be paid only upon adding
+ or removing points.
+
+ Like the other map objects, MapPolygon is normally drawn without a smooth
+ appearance. Setting the \l {Item::opacity}{opacity} property will force the object to
+ be blended, which decreases performance considerably depending on the hardware in use.
+
+ \section2 Example Usage
+
+ The following snippet shows a MapPolygon being used to display a triangle,
+ with three vertices near Brisbane, Australia. The triangle is filled in
+ green, with a 1 pixel black border.
+
+ \code
+ Map {
+ MapPolygon {
+ color: 'green'
+ path: [
+ { latitude: -27, longitude: 153.0 },
+ { latitude: -27, longitude: 154.1 },
+ { latitude: -28, longitude: 153.5 }
+ ]
+ }
+ }
+ \endcode
+
+ \image api-mappolygon.png
+*/
+
+QGeoMapPolygonGeometry::QGeoMapPolygonGeometry()
+: assumeSimple_(false)
+{
+}
+
+/*!
+ \internal
+*/
+void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path)
+{
+ if (!sourceDirty_)
+ return;
+
+ srcPath_ = QPainterPath();
+
+ // build the actual path
+ // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints
+ srcOrigin_ = geoLeftBound_;
+ double unwrapBelowX = 0;
+ QDoubleVector2D leftBoundWrapped = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(geoLeftBound_));
+ if (preserveGeometry_)
+ unwrapBelowX = leftBoundWrapped.x();
+
+ QList<QDoubleVector2D> wrappedPath;
+ wrappedPath.reserve(path.size());
+ QDoubleVector2D wrappedLeftBound(qInf(), qInf());
+ // 1)
+ for (int i = 0; i < path.size(); ++i) {
+ const QGeoCoordinate &coord = path.at(i);
+ if (!coord.isValid())
+ continue;
+
+ QDoubleVector2D wrappedProjection = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(coord));
+
+ // We can get NaN if the map isn't set up correctly, or the projection
+ // is faulty -- probably best thing to do is abort
+ if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y()))
+ return;
+
+ const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x());
+ // unwrap x to preserve geometry if moved to border of map
+ if (preserveGeometry_ && isPointLessThanUnwrapBelowX) {
+ double distance = wrappedProjection.x() - unwrapBelowX;
+ if (distance < 0.0)
+ distance += 1.0;
+ wrappedProjection.setX(unwrapBelowX + distance);
+ }
+ if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) {
+ wrappedLeftBound = wrappedProjection;
+ }
+ wrappedPath.append(wrappedProjection);
+ }
+
+ // 2)
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X
+ QDoubleVector2D lb(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths)
+ for (const QDoubleVector2D &p: path)
+ if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y()))
+ // y-minimization needed to find the same point on polygon and border
+ lb = p;
+
+ if (qIsInf(lb.x())) // e.g., when the polygon is clipped entirely
+ return;
+
+ // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(wrappedLeftBound.x(), lb.x()));
+ leftBoundWrapped = lb;
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(lb));
+ } else {
+ clippedPaths.append(wrappedPath);
+ }
+
+ // 3)
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(leftBoundWrapped);
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+ point = point - origin; // (0,0) if point == geoLeftBound_
+
+ if (i == 0) {
+ srcPath_.moveTo(point.toPointF());
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ srcPath_.lineTo(point.toPointF());
+ lastAddedPoint = point;
+ }
+ }
+ }
+ srcPath_.closeSubpath();
+ }
+
+ if (!assumeSimple_)
+ srcPath_ = srcPath_.simplified();
+
+ sourceBounds_ = srcPath_.boundingRect();
+}
+
+/*!
+ \internal
+*/
+void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map)
+{
+ if (!screenDirty_)
+ return;
+
+ if (map.viewportWidth() == 0 || map.viewportHeight() == 0) {
+ clear();
+ return;
+ }
+
+ QDoubleVector2D origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false);
+
+ // Create the viewport rect in the same coordinate system
+ // as the actual points
+ QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight());
+ viewport.translate(-1 * origin.toPointF());
+
+ QPainterPath vpPath;
+ vpPath.addRect(viewport);
+
+ // The geometry has already been clipped against the visible region projection in wrapped mercator space.
+ QPainterPath ppi = srcPath_;
+ clear();
+
+ // a polygon requires at least 3 points;
+ if (ppi.elementCount() < 3)
+ return;
+
+ // TODO: move this to clip2tri, and remove the code below.
+ // For clip2tri use the intersection between the the viewport AND the map as clipping region.
+
+ // Intersection between the viewport and a concave polygon can create multiple polygons
+ // joined by a line at the viewport border, and poly2tri does not triangulate this very well
+ // so use the full src path if the resulting polygon is concave.
+ if (clipToViewport_) {
+ int changeInX = 0;
+ int changeInY = 0;
+ QPainterPath::Element e1 = ppi.elementAt(1);
+ QPainterPath::Element e = ppi.elementAt(0);
+ QVector2D edgeA(e1.x - e.x ,e1.y - e.y);
+ for (int i = 2; i <= ppi.elementCount(); ++i) {
+ e = ppi.elementAt(i % ppi.elementCount());
+ if (e.x == e1.x && e.y == e1.y)
+ continue;
+ QVector2D edgeB(e.x - e1.x, e.y - e1.y);
+ if ((edgeA.x() < 0) == (edgeB.x() >= 0))
+ changeInX++;
+ if ((edgeA.y() < 0) == (edgeB.y() >= 0))
+ changeInY++;
+ edgeA = edgeB;
+ e1 = e;
+ }
+ if (changeInX > 2 || changeInY > 2) // polygon is concave
+ ppi = srcPath_;
+ }
+
+ // translate the path into top-left-centric coordinates
+ QRectF bb = ppi.boundingRect();
+ ppi.translate(-bb.left(), -bb.top());
+ firstPointOffset_ = -1 * bb.topLeft();
+
+ ppi.closeSubpath();
+
+ screenOutline_ = ppi;
+
+#if 0 // TODO: This code appears to crash seldomly in presence of tilt. Requires further investigation
+ std::vector<std::vector<c2t::Point>> clipperPoints;
+ clipperPoints.push_back(std::vector<c2t::Point>());
+ std::vector<c2t::Point> &curPts = clipperPoints.front();
+ curPts.reserve(ppi.elementCount());
+ for (int i = 0; i < ppi.elementCount(); ++i) {
+ const QPainterPath::Element e = ppi.elementAt(i);
+ if (e.isMoveTo() || i == ppi.elementCount() - 1
+ || (qAbs(e.x - curPts.front().x) < 0.1
+ && qAbs(e.y - curPts.front().y) < 0.1)) {
+ if (curPts.size() > 2) {
+ c2t::clip2tri *cdt = new c2t::clip2tri();
+ std::vector<c2t::Point> outputTriangles;
+ cdt->triangulate(clipperPoints, outputTriangles, std::vector<c2t::Point>());
+ for (size_t i = 0; i < outputTriangles.size(); ++i) {
+ screenVertices_ << QPointF(outputTriangles[i].x, outputTriangles[i].y);
+ }
+ delete cdt;
+ }
+ curPts.clear();
+ curPts.reserve(ppi.elementCount() - i);
+ curPts.push_back( c2t::Point(e.x, e.y));
+ } else if (e.isLineTo()) {
+ curPts.push_back( c2t::Point(e.x, e.y));
+ } else {
+ qWarning("Unhandled element type in polygon painterpath");
+ }
+ }
+#else // Old qTriangulate()-based code.
+ QTriangleSet ts = qTriangulate(ppi);
+ qreal *vx = ts.vertices.data();
+
+ screenIndices_.reserve(ts.indices.size());
+ screenVertices_.reserve(ts.vertices.size());
+
+ if (ts.indices.type() == QVertexIndexVector::UnsignedInt) {
+ const quint32 *ix = reinterpret_cast<const quint32 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ } else {
+ const quint16 *ix = reinterpret_cast<const quint16 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ }
+ for (int i = 0; i < (ts.vertices.size()/2*2); i += 2)
+ screenVertices_ << QPointF(vx[i], vx[i + 1]);
+#endif
+
+ screenBounds_ = ppi.boundingRect();
+}
+
+QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), dirtyMaterial_(true),
+ updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(handleBorderUpdated()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(handleBorderUpdated()));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::handleBorderUpdated()
+{
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+QDeclarativePolygonMapItem::~QDeclarativePolygonMapItem()
+{
+}
+
+/*!
+ \qmlpropertygroup Location::MapPolygon::border
+ \qmlproperty int MapPolygon::border.width
+ \qmlproperty color MapPolygon::border.color
+
+ This property is part of the border property group. The border property
+ group holds the width and color used to draw the border of the polygon.
+
+ The width is in pixels and is independent of the zoom level of the map.
+
+ The default values correspond to a black border with a width of 1 pixel.
+ For no line, use a width of 0 or a transparent color.
+*/
+
+QDeclarativeMapLineProperties *QDeclarativePolygonMapItem::border()
+{
+ return &border_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map) {
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+ }
+}
+
+/*!
+ \qmlproperty list<coordinate> MapPolygon::path
+
+ This property holds the ordered list of coordinates which
+ define the polygon.
+
+ \sa addCoordinate, removeCoordinate
+*/
+QJSValue QDeclarativePolygonMapItem::path() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(this);
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(geopath_.path().length()));
+ for (int i = 0; i < geopath_.path().length(); ++i) {
+ const QGeoCoordinate &c = geopath_.coordinateAt(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ pathArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, pathArray.asReturnedValue());
+}
+
+void QDeclarativePolygonMapItem::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);
+ }
+
+ // Equivalent to QDeclarativePolylineMapItem::setPathFromGeoList
+ if (geopath_.path() == pathList)
+ return;
+
+ geopath_.setPath(pathList);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolygon::addCoordinate(coordinate)
+
+ Adds a coordinate to the path.
+
+ \sa removeCoordinate, path
+*/
+
+void QDeclarativePolygonMapItem::addCoordinate(const QGeoCoordinate &coordinate)
+{
+ geopath_.addCoordinate(coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolygon::removeCoordinate(coordinate)
+
+ Removes \a coordinate from the path. If there are multiple instances of the
+ same coordinate, the one added last is removed.
+
+ If \a coordinate is not in the path this method does nothing.
+
+ \sa addCoordinate, path
+*/
+void QDeclarativePolygonMapItem::removeCoordinate(const QGeoCoordinate &coordinate)
+{
+ int length = geopath_.path().length();
+ geopath_.removeCoordinate(coordinate);
+ if (geopath_.path().length() == length)
+ return;
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlproperty color MapPolygon::color
+
+ This property holds the color used to fill the polygon.
+
+ The default value is transparent.
+*/
+
+QColor QDeclarativePolygonMapItem::color() const
+{
+ return color_;
+}
+
+void QDeclarativePolygonMapItem::setColor(const QColor &color)
+{
+ if (color_ == color)
+ return;
+
+ color_ = color;
+ dirtyMaterial_ = true;
+ update();
+ emit colorChanged(color_);
+}
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativePolygonMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
+
+ if (!node)
+ node = new MapPolygonNode();
+
+ //TODO: update only material
+ if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
+ node->update(color_, border_.color(), &geometry_, &borderGeometry_);
+ geometry_.setPreserveGeometry(false);
+ borderGeometry_.setPreserveGeometry(false);
+ geometry_.markClean();
+ borderGeometry_.markClean();
+ dirtyMaterial_ = false;
+ }
+ return node;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::updatePolish()
+{
+ if (!map() || geopath_.path().length() == 0)
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ geometry_.updateSourcePoints(*map(), geopath_.path());
+ geometry_.updateScreenPoints(*map());
+
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+ borderGeometry_.clear();
+
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QGeoCoordinate> closedPath = geopath_.path();
+ closedPath << closedPath.first();
+
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+
+ const QGeoCoordinate &geometryOrigin = geometry_.origin();
+
+ borderGeometry_.srcPoints_.clear();
+ borderGeometry_.srcPointTypes_.clear();
+
+ QDoubleVector2D borderLeftBoundWrapped;
+ QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
+ if (clippedPaths.size()) {
+ borderLeftBoundWrapped = map()->geoProjection().geoToWrappedMapProjection(geometryOrigin);
+ borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
+ borderGeometry_.updateScreenPoints(*map(), border_.width());
+
+ geoms << &borderGeometry_;
+ } else {
+ borderGeometry_.clear();
+ }
+ }
+
+ QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ setWidth(combined.width());
+ setHeight(combined.height());
+
+ setPositionOnMap(geometry_.origin(), -1 * geometry_.sourceBoundingBox().topLeft());
+}
+
+void QDeclarativePolygonMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ return;
+
+ geometry_.setPreserveGeometry(true, geometry_.geoLeftBound());
+ borderGeometry_.setPreserveGeometry(true, borderGeometry_.geoLeftBound());
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativePolygonMapItem::contains(const QPointF &point) const
+{
+ return (geometry_.contains(point) || borderGeometry_.contains(point));
+}
+
+const QGeoShape &QDeclarativePolygonMapItem::geoShape() const
+{
+ return geopath_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+ // TODO: change the algorithm to preserve the distances and size!
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
+
+ geopath_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+//////////////////////////////////////////////////////////////////////
+
+MapPolygonNode::MapPolygonNode() :
+ border_(new MapPolylineNode()),
+ geometry_(QSGGeometry::defaultAttributes_Point2D(), 0),
+ blocked_(true)
+{
+ geometry_.setDrawingMode(QSGGeometry::DrawTriangles);
+ QSGGeometryNode::setMaterial(&fill_material_);
+ QSGGeometryNode::setGeometry(&geometry_);
+
+ appendChildNode(border_);
+}
+
+MapPolygonNode::~MapPolygonNode()
+{
+}
+
+/*!
+ \internal
+*/
+bool MapPolygonNode::isSubtreeBlocked() const
+{
+ return blocked_;
+}
+
+/*!
+ \internal
+*/
+void MapPolygonNode::update(const QColor &fillColor, const QColor &borderColor,
+ const QGeoMapItemGeometry *fillShape,
+ const QGeoMapItemGeometry *borderShape)
+{
+ /* Do the border update first */
+ border_->update(borderColor, borderShape);
+
+ /* If we have neither fill nor border with valid points, block the whole
+ * tree. We can't just block the fill without blocking the border too, so
+ * we're a little conservative here (maybe at the expense of rendering
+ * accuracy) */
+ if (fillShape->size() == 0) {
+ if (borderShape->size() == 0) {
+ blocked_ = true;
+ return;
+ } else {
+ blocked_ = false;
+ }
+ } else {
+ blocked_ = false;
+ }
+
+ QSGGeometry *fill = QSGGeometryNode::geometry();
+ fillShape->allocateAndFill(fill);
+ markDirty(DirtyGeometry);
+
+ if (fillColor != fill_material_.color()) {
+ fill_material_.setColor(fillColor);
+ setMaterial(&fill_material_);
+ markDirty(DirtyMaterial);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
new file mode 100644
index 00000000..cb4de6b9
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPOLYGONMAPITEM
+#define QDECLARATIVEPOLYGONMAPITEM
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qgeomapitemgeometry_p.h>
+
+#include <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+
+QT_BEGIN_NAMESPACE
+
+class MapPolygonNode;
+
+class QGeoMapPolygonGeometry : public QGeoMapItemGeometry
+{
+public:
+ QGeoMapPolygonGeometry();
+
+ inline void setAssumeSimple(bool value) { assumeSimple_ = value; }
+
+ void updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path);
+
+ void updateScreenPoints(const QGeoMap &map);
+
+protected:
+ QPainterPath srcPath_;
+ bool assumeSimple_;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItem : public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QJSValue path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QDeclarativeMapLineProperties *border READ border CONSTANT)
+
+public:
+ explicit QDeclarativePolygonMapItem(QQuickItem *parent = 0);
+ ~QDeclarativePolygonMapItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+ //from QuickItem
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+
+ Q_INVOKABLE void addCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void removeCoordinate(const QGeoCoordinate &coordinate);
+
+ QJSValue path() const;
+ void setPath(const QJSValue &value);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QDeclarativeMapLineProperties *border();
+
+ bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void pathChanged();
+ void colorChanged(const QColor &color);
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
+ void handleBorderUpdated();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ void pathPropertyChanged();
+
+ QGeoPath geopath_;
+ QDeclarativeMapLineProperties border_;
+ QColor color_;
+ bool dirtyMaterial_;
+ QGeoMapPolygonGeometry geometry_;
+ QGeoMapPolylineGeometry borderGeometry_;
+ bool updatingGeometry_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class MapPolygonNode : public QSGGeometryNode
+{
+
+public:
+ MapPolygonNode();
+ ~MapPolygonNode();
+
+ void update(const QColor &fillColor, const QColor &borderColor,
+ const QGeoMapItemGeometry *fillShape,
+ const QGeoMapItemGeometry *borderShape);
+
+ bool isSubtreeBlocked() const;
+
+private:
+ QSGFlatColorMaterial fill_material_;
+ MapPolylineNode *border_;
+ QSGGeometry geometry_;
+ bool blocked_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePolygonMapItem)
+
+#endif /* QDECLARATIVEPOLYGONMAPITEM_H_ */
diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
new file mode 100644
index 00000000..601af6ee
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
@@ -0,0 +1,956 @@
+/****************************************************************************
+ **
+ ** 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 "qdeclarativepolylinemapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qlocationutils_p.h"
+#include "error_messages.h"
+#include "locationvaluetypehelper_p.h"
+#include "qdoublevector2d_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <QtCore/QScopedValueRollback>
+#include <QtQml/QQmlInfo>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPainterPathStroker>
+#include <qnumeric.h>
+
+#include <QtGui/private/qvectorpath_p.h>
+#include <QtGui/private/qtriangulatingstroker_p.h>
+#include <QtGui/private/qtriangulator_p.h>
+
+#include <QtPositioning/private/qclipperutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapPolyline
+ \instantiates QDeclarativePolylineMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+
+ \brief The MapPolyline type displays a polyline on a map.
+
+ The MapPolyline type displays a polyline on a map, specified in terms of an ordered list of
+ \l {coordinate}{coordinates}. The \l {coordinate}{coordinates} on
+ the path cannot be directly changed after being added to the Polyline. Instead, copy the
+ \l path into a var, modify the copy and reassign the copy back to the \l path.
+
+ \code
+ var path = mapPolyline.path;
+ path[0].latitude = 5;
+ mapPolyline.path = path;
+ \endcode
+
+ Coordinates can also be added and removed at any time using the \l addCoordinate and
+ \l removeCoordinate methods.
+
+ By default, the polyline is displayed as a 1-pixel thick black line. This
+ can be changed using the \l line.width and \l line.color properties.
+
+ \section2 Performance
+
+ MapPolylines have a rendering cost that is O(n) with respect to the number
+ of vertices. This means that the per frame cost of having a polyline on
+ the Map grows in direct proportion to the number of points in the polyline.
+
+ Like the other map objects, MapPolyline is normally drawn without a smooth
+ appearance. Setting the \l {Item::opacity}{opacity} property will force the object to
+ be blended, which decreases performance considerably depending on the hardware in use.
+
+ \note MapPolylines are implemented using the OpenGL GL_LINES
+ primitive. There have been occasional reports of issues and rendering
+ inconsistencies on some (particularly quite old) platforms. No workaround
+ is yet available for these issues.
+
+ \section2 Example Usage
+
+ The following snippet shows a MapPolyline with 4 points, making a shape
+ like the top part of a "question mark" (?), near Brisbane, Australia.
+ The line drawn is 3 pixels in width and green in color.
+
+ \code
+ Map {
+ MapPolyline {
+ line.width: 3
+ line.color: 'green'
+ path: [
+ { latitude: -27, longitude: 153.0 },
+ { latitude: -27, longitude: 154.1 },
+ { latitude: -28, longitude: 153.5 },
+ { latitude: -29, longitude: 153.5 }
+ ]
+ }
+ }
+ \endcode
+
+ \image api-mappolyline.png
+*/
+
+QDeclarativeMapLineProperties::QDeclarativeMapLineProperties(QObject *parent) :
+ QObject(parent),
+ width_(1.0),
+ color_(Qt::black)
+{
+}
+
+/*!
+ \internal
+*/
+QColor QDeclarativeMapLineProperties::color() const
+{
+ return color_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeMapLineProperties::setColor(const QColor &color)
+{
+ if (color_ == color)
+ return;
+
+ color_ = color;
+ emit colorChanged(color_);
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeMapLineProperties::width() const
+{
+ return width_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeMapLineProperties::setWidth(qreal width)
+{
+ if (width_ == width)
+ return;
+
+ width_ = width;
+ emit widthChanged(width_);
+}
+
+struct Vertex
+{
+ QVector2D position;
+};
+
+QGeoMapPolylineGeometry::QGeoMapPolylineGeometry()
+{
+}
+
+QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ QDoubleVector2D &leftBoundWrapped)
+{
+ /*
+ * Approach:
+ * 1) project coordinates to wrapped web mercator, and do unwrapBelowX
+ * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons)
+ * 2.1) recalculate the origin and geoLeftBound to prevent these parameters from ending in unprojectable areas
+ * 2.2) ensure the left bound does not wrap around due to QGeoCoordinate <-> clipper conversions
+ */
+
+ srcOrigin_ = geoLeftBound_;
+
+ double unwrapBelowX = 0;
+ leftBoundWrapped = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(geoLeftBound_));
+ if (preserveGeometry_)
+ unwrapBelowX = leftBoundWrapped.x();
+
+ QList<QDoubleVector2D> wrappedPath;
+ wrappedPath.reserve(path.size());
+ QDoubleVector2D wrappedLeftBound(qInf(), qInf());
+ // 1)
+ for (int i = 0; i < path.size(); ++i) {
+ const QGeoCoordinate &coord = path.at(i);
+ if (!coord.isValid())
+ continue;
+
+ QDoubleVector2D wrappedProjection = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(coord));
+
+ // We can get NaN if the map isn't set up correctly, or the projection
+ // is faulty -- probably best thing to do is abort
+ if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y()))
+ return QList<QList<QDoubleVector2D> >();
+
+ const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x());
+ // unwrap x to preserve geometry if moved to border of map
+ if (preserveGeometry_ && isPointLessThanUnwrapBelowX) {
+ double distance = wrappedProjection.x() - unwrapBelowX;
+ if (distance < 0.0)
+ distance += 1.0;
+ wrappedProjection.setX(unwrapBelowX + distance);
+ }
+ if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) {
+ wrappedLeftBound = wrappedProjection;
+ }
+ wrappedPath.append(wrappedProjection);
+ }
+
+ // 2)
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), false);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X
+ QDoubleVector2D lb(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ for (const QDoubleVector2D &p: path) {
+ if (p == leftBoundWrapped) {
+ lb = p;
+ break;
+ } else if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) {
+ // y-minimization needed to find the same point on polygon and border
+ lb = p;
+ }
+ }
+ }
+ if (qIsInf(lb.x()))
+ return QList<QList<QDoubleVector2D> >();
+
+ // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(wrappedLeftBound.x(), lb.x()));
+ leftBoundWrapped = lb;
+ } else {
+ clippedPaths.append(wrappedPath);
+ }
+
+ return clippedPaths;
+}
+
+void QGeoMapPolylineGeometry::pathToScreen(const QGeoMap &map,
+ const QList<QList<QDoubleVector2D> > &clippedPaths,
+ const QDoubleVector2D &leftBoundWrapped)
+{
+ // 3) project the resulting geometry to screen position and calculate screen bounds
+ double minX = qInf();
+ double minY = qInf();
+ double maxX = -qInf();
+ double maxY = -qInf();
+
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(leftBoundWrapped));
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(leftBoundWrapped);
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+
+ point = point - origin; // (0,0) if point == geoLeftBound_
+
+ minX = qMin(point.x(), minX);
+ minY = qMin(point.y(), minY);
+ maxX = qMax(point.x(), maxX);
+ maxY = qMax(point.y(), maxY);
+
+ if (i == 0) {
+ srcPoints_ << point.x() << point.y();
+ srcPointTypes_ << QPainterPath::MoveToElement;
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ srcPoints_ << point.x() << point.y();
+ srcPointTypes_ << QPainterPath::LineToElement;
+ lastAddedPoint = point;
+ }
+ }
+ }
+ }
+
+ sourceBounds_ = QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
+}
+
+/*!
+ \internal
+*/
+void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ const QGeoCoordinate geoLeftBound)
+{
+ if (!sourceDirty_)
+ return;
+
+ geoLeftBound_ = geoLeftBound;
+
+ // clear the old data and reserve enough memory
+ srcPoints_.clear();
+ srcPoints_.reserve(path.size() * 2);
+ srcPointTypes_.clear();
+ srcPointTypes_.reserve(path.size());
+
+ /*
+ * Approach:
+ * 1) project coordinates to wrapped web mercator, and do unwrapBelowX
+ * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons)
+ * 3) project the resulting geometry to screen position and calculate screen bounds
+ */
+
+ QDoubleVector2D leftBoundWrapped;
+ // 1, 2)
+ const QList<QList<QDoubleVector2D> > &clippedPaths = clipPath(map, path, leftBoundWrapped);
+
+ // 3)
+ pathToScreen(map, clippedPaths, leftBoundWrapped);
+}
+
+////////////////////////////////////////////////////////////////////////////
+#if 0 // Old polyline to viewport clipping code. Retaining it for now.
+/* Polyline clip */
+
+enum ClipPointType {
+ InsidePoint = 0x00,
+ LeftPoint = 0x01,
+ RightPoint = 0x02,
+ BottomPoint = 0x04,
+ TopPoint = 0x08
+};
+
+static inline int clipPointType(qreal x, qreal y, const QRectF &rect)
+{
+ int type = InsidePoint;
+ if (x < rect.left())
+ type |= LeftPoint;
+ else if (x > rect.right())
+ type |= RightPoint;
+ if (y < rect.top())
+ type |= TopPoint;
+ else if (y > rect.bottom())
+ type |= BottomPoint;
+ return type;
+}
+
+static void clipSegmentToRect(qreal x0, qreal y0, qreal x1, qreal y1,
+ const QRectF &clipRect,
+ QVector<qreal> &outPoints,
+ QVector<QPainterPath::ElementType> &outTypes)
+{
+ int type0 = clipPointType(x0, y0, clipRect);
+ int type1 = clipPointType(x1, y1, clipRect);
+ bool accept = false;
+
+ while (true) {
+ if (!(type0 | type1)) {
+ accept = true;
+ break;
+ } else if (type0 & type1) {
+ break;
+ } else {
+ qreal x = 0.0;
+ qreal y = 0.0;
+ int outsideType = type0 ? type0 : type1;
+
+ if (outsideType & BottomPoint) {
+ x = x0 + (x1 - x0) * (clipRect.bottom() - y0) / (y1 - y0);
+ y = clipRect.bottom() - 0.1;
+ } else if (outsideType & TopPoint) {
+ x = x0 + (x1 - x0) * (clipRect.top() - y0) / (y1 - y0);
+ y = clipRect.top() + 0.1;
+ } else if (outsideType & RightPoint) {
+ y = y0 + (y1 - y0) * (clipRect.right() - x0) / (x1 - x0);
+ x = clipRect.right() - 0.1;
+ } else if (outsideType & LeftPoint) {
+ y = y0 + (y1 - y0) * (clipRect.left() - x0) / (x1 - x0);
+ x = clipRect.left() + 0.1;
+ }
+
+ if (outsideType == type0) {
+ x0 = x;
+ y0 = y;
+ type0 = clipPointType(x0, y0, clipRect);
+ } else {
+ x1 = x;
+ y1 = y;
+ type1 = clipPointType(x1, y1, clipRect);
+ }
+ }
+ }
+
+ if (accept) {
+ if (outPoints.size() >= 2) {
+ qreal lastX, lastY;
+ lastY = outPoints.at(outPoints.size() - 1);
+ lastX = outPoints.at(outPoints.size() - 2);
+
+ if (!qFuzzyCompare(lastY, y0) || !qFuzzyCompare(lastX, x0)) {
+ outTypes << QPainterPath::MoveToElement;
+ outPoints << x0 << y0;
+ }
+ } else {
+ outTypes << QPainterPath::MoveToElement;
+ outPoints << x0 << y0;
+ }
+
+ outTypes << QPainterPath::LineToElement;
+ outPoints << x1 << y1;
+ }
+}
+
+static void clipPathToRect(const QVector<qreal> &points,
+ const QVector<QPainterPath::ElementType> &types,
+ const QRectF &clipRect,
+ QVector<qreal> &outPoints,
+ QVector<QPainterPath::ElementType> &outTypes)
+{
+ outPoints.clear();
+ outPoints.reserve(points.size());
+ outTypes.clear();
+ outTypes.reserve(types.size());
+
+ qreal lastX, lastY;
+ for (int i = 0; i < types.size(); ++i) {
+ if (i > 0 && types[i] != QPainterPath::MoveToElement) {
+ qreal x = points[i * 2], y = points[i * 2 + 1];
+ clipSegmentToRect(lastX, lastY, x, y, clipRect, outPoints, outTypes);
+ }
+
+ lastX = points[i * 2];
+ lastY = points[i * 2 + 1];
+ }
+}
+#endif
+/*!
+ \internal
+*/
+void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
+ qreal strokeWidth)
+{
+ if (!screenDirty_)
+ return;
+
+ QPointF origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false).toPointF();
+
+ if (!qIsFinite(origin.x()) || !qIsFinite(origin.y()) || srcPointTypes_.size() < 2) { // the line might have been clipped away.
+ clear();
+ return;
+ }
+
+ // Create the viewport rect in the same coordinate system
+ // as the actual points
+ QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight());
+ viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth, strokeWidth);
+ viewport.translate(-1 * origin);
+
+ // The geometry has already been clipped against the visible region projection in wrapped mercator space.
+ QVector<qreal> points = srcPoints_;
+ QVector<QPainterPath::ElementType> types = srcPointTypes_;
+
+ QVectorPath vp(points.data(), types.size(), types.data());
+ QTriangulatingStroker ts;
+ // viewport is not used in the call below.
+ ts.process(vp, QPen(QBrush(Qt::black), strokeWidth), viewport, QPainter::Qt4CompatiblePainting);
+
+ clear();
+
+ // Nothing is on the screen
+ if (ts.vertexCount() == 0)
+ return;
+
+ // QTriangulatingStroker#vertexCount is actually the length of the array,
+ // not the number of vertices
+ screenVertices_.reserve(ts.vertexCount());
+
+ QRectF bb;
+
+ QPointF pt;
+ const float *vs = ts.vertices();
+ for (int i = 0; i < (ts.vertexCount()/2*2); i += 2) {
+ pt = QPointF(vs[i], vs[i + 1]);
+ screenVertices_ << pt;
+
+ if (!qIsFinite(pt.x()) || !qIsFinite(pt.y()))
+ break;
+
+ if (!bb.contains(pt)) {
+ if (pt.x() < bb.left())
+ bb.setLeft(pt.x());
+
+ if (pt.x() > bb.right())
+ bb.setRight(pt.x());
+
+ if (pt.y() < bb.top())
+ bb.setTop(pt.y());
+
+ if (pt.y() > bb.bottom())
+ bb.setBottom(pt.y());
+ }
+ }
+
+ screenBounds_ = bb;
+ this->translate( -1 * sourceBounds_.topLeft());
+}
+
+QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), dirtyMaterial_(true), updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ QObject::connect(&line_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(updateAfterLinePropertiesChanged()));
+ QObject::connect(&line_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(updateAfterLinePropertiesChanged()));
+}
+
+QDeclarativePolylineMapItem::~QDeclarativePolylineMapItem()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged()
+{
+ // mark dirty just in case we're a width change
+ geometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map) {
+ geometry_.markSourceDirty();
+ polishAndUpdate();
+ }
+}
+
+/*!
+ \qmlproperty list<coordinate> MapPolyline::path
+
+ This property holds the ordered list of coordinates which
+ define the polyline.
+*/
+
+QJSValue QDeclarativePolylineMapItem::path() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(this);
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(geopath_.path().length()));
+ for (int i = 0; i < geopath_.path().length(); ++i) {
+ const QGeoCoordinate &c = geopath_.coordinateAt(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ pathArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, pathArray.asReturnedValue());
+}
+
+void QDeclarativePolylineMapItem::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);
+ }
+
+ setPathFromGeoList(pathList);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::setPathFromGeoList(const QList<QGeoCoordinate> &path)
+{
+ if (geopath_.path() == path)
+ return;
+
+ geopath_.setPath(path);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod int MapPolyline::pathLength()
+
+ Returns the number of coordinates of the polyline.
+
+ \since Qt Location 5.6
+
+ \sa path
+*/
+int QDeclarativePolylineMapItem::pathLength() const
+{
+ return geopath_.path().length();
+}
+
+/*!
+ \qmlmethod void MapPolyline::addCoordinate(coordinate)
+
+ Adds a coordinate to the end of the path.
+
+ \sa insertCoordinate, removeCoordinate, path
+*/
+void QDeclarativePolylineMapItem::addCoordinate(const QGeoCoordinate &coordinate)
+{
+ geopath_.addCoordinate(coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolyline::insertCoordinate(index, coordinate)
+
+ Inserts a \a coordinate to the path at the given \a index.
+
+ \since Qt Location 5.6
+
+ \sa addCoordinate, removeCoordinate, path
+*/
+void QDeclarativePolylineMapItem::insertCoordinate(int index, const QGeoCoordinate &coordinate)
+{
+ if (index < 0 || index > geopath_.path().length())
+ return;
+
+ geopath_.insertCoordinate(index, coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolyline::replaceCoordinate(index, coordinate)
+
+ Replaces the coordinate in the current path at the given \a index
+ with the new \a coordinate.
+
+ \since Qt Location 5.6
+
+ \sa addCoordinate, insertCoordinate, removeCoordinate, path
+*/
+void QDeclarativePolylineMapItem::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
+{
+ if (index < 0 || index >= geopath_.path().length())
+ return;
+
+ geopath_.replaceCoordinate(index, coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod coordinate MapPolyline::coordinateAt(index)
+
+ Gets the coordinate of the polyline at the given \a index.
+ If the index is outside the path's bounds then an invalid
+ coordinate is returned.
+
+ \since Qt Location 5.6
+*/
+QGeoCoordinate QDeclarativePolylineMapItem::coordinateAt(int index) const
+{
+ if (index < 0 || index >= geopath_.path().length())
+ return QGeoCoordinate();
+
+ return geopath_.coordinateAt(index);
+}
+
+/*!
+ \qmlmethod coordinate MapPolyline::containsCoordinate(coordinate)
+
+ Returns true if the given \a coordinate is part of the path.
+
+ \since Qt Location 5.6
+*/
+bool QDeclarativePolylineMapItem::containsCoordinate(const QGeoCoordinate &coordinate)
+{
+ return geopath_.containsCoordinate(coordinate);
+}
+
+/*!
+ \qmlmethod void MapPolyline::removeCoordinate(coordinate)
+
+ Removes \a coordinate from the path. If there are multiple instances of the
+ same coordinate, the one added last is removed.
+
+ If \a coordinate is not in the path this method does nothing.
+
+ \sa addCoordinate, insertCoordinate, path
+*/
+void QDeclarativePolylineMapItem::removeCoordinate(const QGeoCoordinate &coordinate)
+{
+ int length = geopath_.path().length();
+ geopath_.removeCoordinate(coordinate);
+ if (geopath_.path().length() == length)
+ return;
+ geometry_.markSourceDirty();
+ polishAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolyline::removeCoordinate(index)
+
+ Removes a coordinate from the path at the given \a index.
+
+ If \a index is invalid then this method does nothing.
+
+ \since Qt Location 5.6
+
+ \sa addCoordinate, insertCoordinate, path
+*/
+void QDeclarativePolylineMapItem::removeCoordinate(int index)
+{
+ if (index < 0 || index >= geopath_.path().length())
+ return;
+
+ geopath_.removeCoordinate(index);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlpropertygroup Location::MapPolyline::line
+ \qmlproperty int MapPolyline::line.width
+ \qmlproperty color MapPolyline::line.color
+
+ This property is part of the line property group. The line
+ property group holds the width and color used to draw the line.
+
+ The width is in pixels and is independent of the zoom level of the map.
+ The default values correspond to a black border with a width of 1 pixel.
+
+ For no line, use a width of 0 or a transparent color.
+*/
+
+QDeclarativeMapLineProperties *QDeclarativePolylineMapItem::line()
+{
+ return &line_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+ // TODO: change the algorithm to preserve the distances and size!
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
+
+ geopath_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ return;
+
+ geometry_.setPreserveGeometry(true, geometry_.geoLeftBound());
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::updatePolish()
+{
+ if (!map() || geopath_.path().length() == 0)
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ geometry_.updateSourcePoints(*map(), geopath_.path(), geopath_.boundingGeoRectangle().topLeft());
+ geometry_.updateScreenPoints(*map(), line_.width());
+
+ setWidth(geometry_.sourceBoundingBox().width());
+ setHeight(geometry_.sourceBoundingBox().height());
+
+ setPositionOnMap(geometry_.origin(), -1 * geometry_.sourceBoundingBox().topLeft());
+}
+
+void QDeclarativePolylineMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativePolylineMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+
+ MapPolylineNode *node = static_cast<MapPolylineNode *>(oldNode);
+
+ if (!node) {
+ node = new MapPolylineNode();
+ }
+
+ //TODO: update only material
+ if (geometry_.isScreenDirty() || dirtyMaterial_ || !oldNode) {
+ node->update(line_.color(), &geometry_);
+ geometry_.setPreserveGeometry(false);
+ geometry_.markClean();
+ dirtyMaterial_ = false;
+ }
+ return node;
+}
+
+bool QDeclarativePolylineMapItem::contains(const QPointF &point) const
+{
+ QVector<QPointF> vertices = geometry_.vertices();
+ QPolygonF tri;
+ for (int i = 0; i < vertices.size(); ++i) {
+ tri << vertices[i];
+ if (tri.size() == 3) {
+ if (tri.containsPoint(point,Qt::OddEvenFill))
+ return true;
+ tri.remove(0);
+ }
+ }
+
+ return false;
+}
+
+const QGeoShape &QDeclarativePolylineMapItem::geoShape() const
+{
+ return geopath_;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+/*!
+ \internal
+*/
+MapPolylineNode::MapPolylineNode() :
+ geometry_(QSGGeometry::defaultAttributes_Point2D(),0),
+ blocked_(true)
+{
+ geometry_.setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ QSGGeometryNode::setMaterial(&fill_material_);
+ QSGGeometryNode::setGeometry(&geometry_);
+}
+
+
+/*!
+ \internal
+*/
+MapPolylineNode::~MapPolylineNode()
+{
+}
+
+/*!
+ \internal
+*/
+bool MapPolylineNode::isSubtreeBlocked() const
+{
+ return blocked_;
+}
+
+/*!
+ \internal
+*/
+void MapPolylineNode::update(const QColor &fillColor,
+ const QGeoMapItemGeometry *shape)
+{
+ if (shape->size() == 0) {
+ blocked_ = true;
+ return;
+ } else {
+ blocked_ = false;
+ }
+
+ QSGGeometry *fill = QSGGeometryNode::geometry();
+ shape->allocateAndFill(fill);
+ markDirty(DirtyGeometry);
+
+ if (fillColor != fill_material_.color()) {
+ fill_material_.setColor(fillColor);
+ setMaterial(&fill_material_);
+ markDirty(DirtyMaterial);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
new file mode 100644
index 00000000..abc1df2f
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPOLYLINEMAPITEM
+#define QDECLARATIVEPOLYLINEMAPITEM
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qgeomapitemgeometry_p.h>
+
+#include <QtPositioning/QGeoPath>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+
+QT_BEGIN_NAMESPACE
+
+class MapPolylineNode;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeMapLineProperties : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+
+public:
+ explicit QDeclarativeMapLineProperties(QObject *parent = 0);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ qreal width() const;
+ void setWidth(qreal width);
+
+Q_SIGNALS:
+ void widthChanged(qreal width);
+ void colorChanged(const QColor &color);
+
+private:
+ qreal width_;
+ QColor color_;
+};
+
+class QGeoMapPolylineGeometry : public QGeoMapItemGeometry
+{
+public:
+ QGeoMapPolylineGeometry();
+
+ void updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ const QGeoCoordinate geoLeftBound);
+
+ void updateScreenPoints(const QGeoMap &map,
+ qreal strokeWidth);
+
+protected:
+ QList<QList<QDoubleVector2D> > clipPath(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ QDoubleVector2D &leftBoundWrapped);
+
+ void pathToScreen(const QGeoMap &map,
+ const QList<QList<QDoubleVector2D> > &clippedPaths,
+ const QDoubleVector2D &leftBoundWrapped);
+
+private:
+ QVector<qreal> srcPoints_;
+ QVector<QPainterPath::ElementType> srcPointTypes_;
+
+ friend class QDeclarativeCircleMapItem;
+ friend class QDeclarativePolygonMapItem;
+ friend class QDeclarativeRectangleMapItem;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItem : public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QJSValue path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QDeclarativeMapLineProperties *line READ line CONSTANT)
+
+public:
+ explicit QDeclarativePolylineMapItem(QQuickItem *parent = 0);
+ ~QDeclarativePolylineMapItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+ //from QuickItem
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+
+ Q_INVOKABLE int pathLength() const;
+ Q_INVOKABLE void addCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void insertCoordinate(int index, const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void replaceCoordinate(int index, const QGeoCoordinate &coordinate);
+ Q_INVOKABLE QGeoCoordinate coordinateAt(int index) const;
+ Q_INVOKABLE bool containsCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void removeCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void removeCoordinate(int index);
+
+ QJSValue path() const;
+ virtual void setPath(const QJSValue &value);
+
+ bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+ QDeclarativeMapLineProperties *line();
+
+Q_SIGNALS:
+ void pathChanged();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void setPathFromGeoList(const QList<QGeoCoordinate> &path);
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
+ void updateAfterLinePropertiesChanged();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ void pathPropertyChanged();
+
+ QGeoPath geopath_;
+ QDeclarativeMapLineProperties line_;
+ QColor color_;
+ bool dirtyMaterial_;
+ QGeoMapPolylineGeometry geometry_;
+ bool updatingGeometry_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class MapPolylineNode : public QSGGeometryNode
+{
+
+public:
+ MapPolylineNode();
+ ~MapPolylineNode();
+
+ void update(const QColor &fillColor, const QGeoMapItemGeometry *shape);
+ bool isSubtreeBlocked() const;
+
+private:
+ QSGFlatColorMaterial fill_material_;
+ QSGGeometry geometry_;
+ bool blocked_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeMapLineProperties)
+QML_DECLARE_TYPE(QDeclarativePolylineMapItem)
+
+#endif /* QDECLARATIVEPOLYLINEMAPITEM_H_ */
diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
new file mode 100644
index 00000000..8abd58dd
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** 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 "qdeclarativerectanglemapitem_p.h"
+#include "qdeclarativepolygonmapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qlocationutils_p.h"
+#include <QPainterPath>
+#include <qnumeric.h>
+#include <QRectF>
+#include <QPointF>
+#include <QtLocation/private/qgeomap_p.h>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtCore/QScopedValueRollback>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapRectangle
+ \instantiates QDeclarativeRectangleMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapRectangle type displays a rectangle on a Map.
+
+ The MapRectangle type displays a rectangle on a Map. Rectangles are a
+ special case of Polygon with exactly 4 vertices and 4 "straight" edges. In
+ this case, "straight" means that the top-left point has the same latitude
+ as the top-right point (the top edge), and the bottom-left point has the
+ same latitude as the bottom-right point (the bottom edge). Similarly, the
+ points on the left side have the same longitude, and the points on the
+ right side have the same longitude.
+
+ To specify the rectangle, it requires a \l topLeft and \l bottomRight point,
+ both given by a \l {coordinate}.
+
+ By default, the rectangle is displayed with transparent fill and a 1-pixel
+ thick black border. This can be changed using the \l color, \l border.color
+ and \l border.width properties.
+
+ \note Similar to the \l MapPolygon type, MapRectangles are geographic
+ items, thus dragging a MapRectangle causes its vertices to be recalculated
+ in the geographic coordinate space. Apparent stretching of the item
+ occurs when dragged to the a different latitude, however, its edges
+ remain straight.
+
+ \section2 Performance
+
+ MapRectangles have a rendering cost identical to a MapPolygon with 4
+ vertices.
+
+ Like the other map objects, MapRectangle is normally drawn without a smooth
+ appearance. Setting the \l opacity property will force the object to be
+ blended, which decreases performance considerably depending on the hardware
+ in use.
+
+ \section2 Example Usage
+
+ The following snippet shows a map containing a MapRectangle, spanning
+ from (-27, 153) to (-28, 153.5), near Brisbane, Australia. The rectangle
+ is filled in green, with a 2 pixel black border.
+
+ \code
+ Map {
+ MapRectangle {
+ color: 'green'
+ border.width: 2
+ topLeft {
+ latitude: -27
+ longitude: 153
+ }
+ bottomRight {
+ latitude: -28
+ longitude: 153.5
+ }
+ }
+ }
+ \endcode
+
+ \image api-maprectangle.png
+*/
+
+QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), dirtyMaterial_(true),
+ updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(markSourceDirtyAndUpdate()));
+}
+
+QDeclarativeRectangleMapItem::~QDeclarativeRectangleMapItem()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map)
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \qmlpropertygroup Location::MapRectangle::border
+ \qmlproperty int MapRectangle::border.width
+ \qmlproperty color MapRectangle::border.color
+
+ This property is part of the border property group. The border property group
+ holds the width and color used to draw the border of the rectangle.
+ The width is in pixels and is independent of the zoom level of the map.
+
+ The default values correspond to a black border with a width of 1 pixel.
+ For no line, use a width of 0 or a transparent color.
+*/
+QDeclarativeMapLineProperties *QDeclarativeRectangleMapItem::border()
+{
+ return &border_;
+}
+
+/*!
+ \qmlproperty coordinate MapRectangle::topLeft
+
+ This property holds the top-left coordinate of the MapRectangle which
+ can be used to retrieve its longitude, latitude and altitude.
+*/
+void QDeclarativeRectangleMapItem::setTopLeft(const QGeoCoordinate &topLeft)
+{
+ if (rectangle_.topLeft() == topLeft)
+ return;
+
+ rectangle_.setTopLeft(topLeft);
+
+ markSourceDirtyAndUpdate();
+ emit topLeftChanged(topLeft);
+}
+
+QGeoCoordinate QDeclarativeRectangleMapItem::topLeft()
+{
+ return rectangle_.topLeft();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \qmlproperty coordinate MapRectangle::bottomRight
+
+ This property holds the bottom-right coordinate of the MapRectangle which
+ can be used to retrieve its longitude, latitude and altitude.
+*/
+void QDeclarativeRectangleMapItem::setBottomRight(const QGeoCoordinate &bottomRight)
+{
+ if (rectangle_.bottomRight() == bottomRight)
+ return;
+
+ rectangle_.setBottomRight(bottomRight);
+
+ markSourceDirtyAndUpdate();
+ emit bottomRightChanged(bottomRight);
+}
+
+QGeoCoordinate QDeclarativeRectangleMapItem::bottomRight()
+{
+ return rectangle_.bottomRight();
+}
+
+/*!
+ \qmlproperty color MapRectangle::color
+
+ This property holds the fill color of the rectangle. For no fill, use
+ a transparent color.
+*/
+QColor QDeclarativeRectangleMapItem::color() const
+{
+ return color_;
+}
+
+void QDeclarativeRectangleMapItem::setColor(const QColor &color)
+{
+ if (color_ == color)
+ return;
+ color_ = color;
+ dirtyMaterial_ = true;
+ polishAndUpdate();
+ emit colorChanged(color_);
+}
+
+/*!
+ \qmlproperty real MapRectangle::opacity
+
+ This property holds the opacity of the item. Opacity is specified as a
+ number between 0 (fully transparent) and 1 (fully opaque). The default is 1.
+
+ An item with 0 opacity will still receive mouse events. To stop mouse events, set the
+ visible property of the item to false.
+*/
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativeRectangleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+
+ MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
+
+ if (!node) {
+ node = new MapPolygonNode();
+ }
+
+ //TODO: update only material
+ if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
+ node->update(color_, border_.color(), &geometry_, &borderGeometry_);
+ geometry_.setPreserveGeometry(false);
+ borderGeometry_.setPreserveGeometry(false);
+ geometry_.markClean();
+ borderGeometry_.markClean();
+ dirtyMaterial_ = false;
+ }
+ return node;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::updatePolish()
+{
+ if (!map() || !topLeft().isValid() || !bottomRight().isValid())
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ QList<QGeoCoordinate> path;
+ path << rectangle_.topLeft();
+ path << QGeoCoordinate(rectangle_.topLeft().latitude(), rectangle_.bottomRight().longitude());
+ path << rectangle_.bottomRight();
+ path << QGeoCoordinate(rectangle_.bottomRight().latitude(), rectangle_.topLeft().longitude());
+
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ geometry_.updateSourcePoints(*map(), path);
+ geometry_.updateScreenPoints(*map());
+
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+ borderGeometry_.clear();
+
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QGeoCoordinate> closedPath = path;
+ closedPath << closedPath.first();
+
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ const QGeoCoordinate &geometryOrigin = geometry_.origin();
+
+ borderGeometry_.srcPoints_.clear();
+ borderGeometry_.srcPointTypes_.clear();
+
+ QDoubleVector2D borderLeftBoundWrapped;
+ QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
+ if (clippedPaths.size()) {
+ borderLeftBoundWrapped = map()->geoProjection().geoToWrappedMapProjection(geometryOrigin);
+ borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
+ borderGeometry_.updateScreenPoints(*map(), border_.width());
+
+ geoms << &borderGeometry_;
+ } else {
+ borderGeometry_.clear();
+ }
+ }
+
+ QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ setWidth(combined.width());
+ setHeight(combined.height());
+
+ setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ return;
+
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeRectangleMapItem::contains(const QPointF &point) const
+{
+ return (geometry_.contains(point) || borderGeometry_.contains(point));
+}
+
+const QGeoShape &QDeclarativeRectangleMapItem::geoShape() const
+{
+ return rectangle_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+ // TODO: change the algorithm to preserve the distances and size
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
+
+ rectangle_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ markSourceDirtyAndUpdate();
+ emit topLeftChanged(rectangle_.topLeft());
+ emit bottomRightChanged(rectangle_.bottomRight());
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
new file mode 100644
index 00000000..6e6ea5b1
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVERECTANGLEMAPITEM_H_
+#define QDECLARATIVERECTANGLEMAPITEM_H_
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qgeomapitemgeometry_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+
+#include <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItem: public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QGeoCoordinate topLeft READ topLeft WRITE setTopLeft NOTIFY topLeftChanged)
+ Q_PROPERTY(QGeoCoordinate bottomRight READ bottomRight WRITE setBottomRight NOTIFY bottomRightChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QDeclarativeMapLineProperties *border READ border)
+
+public:
+ explicit QDeclarativeRectangleMapItem(QQuickItem *parent = 0);
+ ~QDeclarativeRectangleMapItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+ //from QuickItem
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+
+ QGeoCoordinate topLeft();
+ void setTopLeft(const QGeoCoordinate &center);
+
+ QGeoCoordinate bottomRight();
+ void setBottomRight(const QGeoCoordinate &center);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QDeclarativeMapLineProperties *border();
+
+ bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void topLeftChanged(const QGeoCoordinate &topLeft);
+ void bottomRightChanged(const QGeoCoordinate &bottomRight);
+ void colorChanged(const QColor &color);
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ QGeoRectangle rectangle_;
+ QDeclarativeMapLineProperties border_;
+ QColor color_;
+ bool dirtyMaterial_;
+ QGeoMapPolygonGeometry geometry_;
+ QGeoMapPolylineGeometry borderGeometry_;
+ bool updatingGeometry_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeRectangleMapItem)
+
+#endif /* QDECLARATIVERECTANGLEMAPITEM_H_ */
diff --git a/src/location/declarativemaps/qdeclarativeroutemapitem.cpp b/src/location/declarativemaps/qdeclarativeroutemapitem.cpp
new file mode 100644
index 00000000..1fbeeeb7
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativeroutemapitem.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** 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 "qdeclarativeroutemapitem_p.h"
+#include "qdeclarativepolylinemapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qdeclarativegeoroute_p.h"
+
+#include <QtQml/QQmlInfo>
+#include <QtGui/QPainter>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapRoute
+ \instantiates QDeclarativeRouteMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+
+ \brief The MapRoute type displays a Route on a Map.
+
+ The MapRoute type displays a Route obtained through a RouteModel or
+ other means, on the Map as a Polyline following the path of the Route.
+
+ MapRoute is really a \l MapPolyline, but with the path specified using the
+ \l route property instead of directly in \l {coordinate}{coordinates}.
+
+ By default, the route is displayed as a 1-pixel thick black line. This can
+ be changed using the \l line.width and \l line.color properties.
+
+ \section2 Performance
+
+ For notes about the performance on MapRoute, refer to the documentation for
+ \l MapPolyline.
+
+ \section2 Example Usage
+
+ Here is how to draw a \l{Route}{route} on a \l{Map}{map}:
+
+ \snippet declarative/maps.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/maps.qml MapRoute
+*/
+
+/*!
+ \qmlpropertygroup Location::MapRoute::line
+ \qmlproperty int MapRoute::line.width
+ \qmlproperty color MapRoute::line.color
+
+ This property is part of the line property group. The line
+ property group holds the width and color used to draw the line.
+
+ The width is in pixels and is independent of the zoom level of the map.
+ The default values correspond to a black border with a width of 1 pixel.
+
+ For no line, use a width of 0 or a transparent color.
+*/
+
+
+QDeclarativeRouteMapItem::QDeclarativeRouteMapItem(QQuickItem *parent)
+: QDeclarativePolylineMapItem(parent), route_(0)
+{
+ setFlag(ItemHasContents, true);
+}
+
+QDeclarativeRouteMapItem::~QDeclarativeRouteMapItem()
+{
+}
+
+/*!
+ \qmlproperty Route MapRoute::route
+
+ This property holds the route to be drawn which can be used
+ to represent one geographical route.
+*/
+QDeclarativeGeoRoute *QDeclarativeRouteMapItem::route() const
+{
+ return route_;
+}
+
+void QDeclarativeRouteMapItem::setRoute(QDeclarativeGeoRoute *route)
+{
+ if (route_ == route)
+ return;
+
+ route_ = route;
+
+ connect(route_, SIGNAL(pathChanged()), this, SLOT(updateRoutePath()));
+
+ if (route_)
+ setPathFromGeoList(route_->routePath());
+
+ emit routeChanged(route_);
+}
+
+void QDeclarativeRouteMapItem::updateRoutePath()
+{
+ setPathFromGeoList(route_->routePath());
+}
+
+/*!
+ \internal void QDeclarativeRouteMapItem::setPath(const QJSValue &value)
+
+ Used to disable path property on the RouteMapItem
+ */
+void QDeclarativeRouteMapItem::setPath(const QJSValue &value)
+{
+ Q_UNUSED(value);
+ qWarning() << "Can not set the path on QDeclarativeRouteMapItem."
+ << "Please use the route property instead.";
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativeroutemapitem_p.h b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
new file mode 100644
index 00000000..ad959837
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEROUTEMAPITEM_H_
+#define QDECLARATIVEROUTEMAPITEM_H_
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QPen>
+#include <QBrush>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGeoRoute;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRouteMapItem : public QDeclarativePolylineMapItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeGeoRoute *route READ route WRITE setRoute NOTIFY routeChanged)
+
+public:
+ explicit QDeclarativeRouteMapItem(QQuickItem *parent = 0);
+ ~QDeclarativeRouteMapItem();
+
+ QDeclarativeGeoRoute *route() const;
+ void setRoute(QDeclarativeGeoRoute *route);
+
+Q_SIGNALS:
+ void routeChanged(const QDeclarativeGeoRoute *route);
+
+private slots:
+ void updateRoutePath();
+
+protected:
+ void setPath(const QJSValue &value) Q_DECL_OVERRIDE;
+
+private:
+ QDeclarativeGeoRoute *route_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeRouteMapItem)
+
+#endif /* QDECLARATIVEROUTEMAPITEM_H_ */
diff --git a/src/location/declarativemaps/qgeomapitemgeometry.cpp b/src/location/declarativemaps/qgeomapitemgeometry.cpp
new file mode 100644
index 00000000..80f3e218
--- /dev/null
+++ b/src/location/declarativemaps/qgeomapitemgeometry.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** 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 "qgeomapitemgeometry_p.h"
+#include "qdeclarativegeomap_p.h"
+#include "qlocationutils_p.h"
+#include <QtQuick/QSGGeometry>
+#include "qdoublevector2d_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QGeoMapItemGeometry::QGeoMapItemGeometry()
+: sourceDirty_(true), screenDirty_(true), clipToViewport_(true), preserveGeometry_(false)
+{
+}
+
+/*!
+ \internal
+*/
+void QGeoMapItemGeometry::translate(const QPointF &offset)
+{
+ for (int i = 0; i < screenVertices_.size(); ++i)
+ screenVertices_[i] += offset;
+
+ firstPointOffset_ += offset;
+ screenOutline_.translate(offset);
+ screenBounds_.translate(offset);
+}
+
+/*!
+ \internal
+*/
+void QGeoMapItemGeometry::allocateAndFill(QSGGeometry *geom) const
+{
+ const QVector<QPointF> &vx = screenVertices_;
+ const QVector<quint32> &ix = screenIndices_;
+
+ if (isIndexed()) {
+ geom->allocate(vx.size(), ix.size());
+ if (geom->indexType() == QSGGeometry::UnsignedShortType) {
+ quint16 *its = geom->indexDataAsUShort();
+ for (int i = 0; i < ix.size(); ++i)
+ its[i] = ix[i];
+ } else if (geom->indexType() == QSGGeometry::UnsignedIntType) {
+ quint32 *its = geom->indexDataAsUInt();
+ for (int i = 0; i < ix.size(); ++i)
+ its[i] = ix[i];
+ }
+ } else {
+ geom->allocate(vx.size());
+ }
+
+ QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D();
+ for (int i = 0; i < vx.size(); ++i)
+ pts[i].set(vx[i].x(), vx[i].y());
+}
+
+/*!
+ \internal
+*/
+QRectF QGeoMapItemGeometry::translateToCommonOrigin(const QList<QGeoMapItemGeometry *> &geoms)
+{
+ QGeoCoordinate origin = geoms.at(0)->origin();
+
+ QPainterPath brects;
+
+ // first get max offset
+ QPointF maxOffset = geoms.at(0)->firstPointOffset();
+ foreach (QGeoMapItemGeometry *g, geoms) {
+#ifndef QT_NO_DEBUG
+ //Q_ASSERT(g->origin() == origin); // this might fail on clipper clipping inaccuracies, so better to remove it in production
+ if (!qFuzzyCompare(origin.latitude(), g->origin().latitude())) {
+ qWarning("translateToCommonOrigin: Origins differ!");
+ }
+ if (!qFuzzyCompare(origin.longitude(), g->origin().longitude())) {
+ qWarning("translateToCommonOrigin: Origins differ!");
+ }
+#endif
+ QPointF o = g->firstPointOffset();
+ maxOffset.setX(qMax(o.x(), maxOffset.x()));
+ maxOffset.setY(qMax(o.y(), maxOffset.y()));
+ }
+
+ // then translate everything
+ foreach (QGeoMapItemGeometry *g, geoms) {
+ g->translate(maxOffset - g->firstPointOffset());
+ brects.addRect(g->sourceBoundingBox());
+ }
+
+ return brects.boundingRect();
+}
+
+/*!
+ \internal
+*/
+double QGeoMapItemGeometry::geoDistanceToScreenWidth(const QGeoMap &map,
+ const QGeoCoordinate &fromCoord,
+ const QGeoCoordinate &toCoord)
+{
+ // Do not wrap around half the globe
+ Q_ASSERT(!qFuzzyCompare(fromCoord.longitude(), toCoord.longitude()));
+
+ QGeoCoordinate mapMid = map.geoProjection().itemPositionToCoordinate(QDoubleVector2D(map.viewportWidth()/2.0, 0));
+ double halfGeoDist = toCoord.longitude() - fromCoord.longitude();
+ if (toCoord.longitude() < fromCoord.longitude())
+ halfGeoDist += 360;
+ halfGeoDist /= 2.0;
+ QGeoCoordinate geoDelta = QGeoCoordinate(0,
+ QLocationUtils::wrapLong(mapMid.longitude() + halfGeoDist));
+ QDoubleVector2D halfScreenDist = map.geoProjection().coordinateToItemPosition(geoDelta, false)
+ - QDoubleVector2D(map.viewportWidth()/2.0, 0);
+ return halfScreenDist.x() * 2.0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qgeomapitemgeometry_p.h b/src/location/declarativemaps/qgeomapitemgeometry_p.h
new file mode 100644
index 00000000..595107ae
--- /dev/null
+++ b/src/location/declarativemaps/qgeomapitemgeometry_p.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+ **
+ ** 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$
+ **
+ ****************************************************************************/
+
+#ifndef QGEOMAPITEMGEOMETRY_H
+#define QGEOMAPITEMGEOMETRY_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QPainterPath>
+#include <QPointF>
+#include <QRectF>
+#include <QVector>
+#include <QGeoCoordinate>
+#include <QVector2D>
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+
+class QSGGeometry;
+class QGeoMap;
+
+class QGeoMapItemGeometry
+{
+public:
+ QGeoMapItemGeometry();
+
+ inline bool isSourceDirty() const { return sourceDirty_; }
+ inline bool isScreenDirty() const { return screenDirty_; }
+ inline void markSourceDirty() { sourceDirty_ = true; screenDirty_ = true; }
+ inline void markScreenDirty() { screenDirty_ = true; clipToViewport_ = true; }
+ inline void markFullScreenDirty() { screenDirty_ = true; clipToViewport_ = false;}
+ inline void markClean() { screenDirty_ = (sourceDirty_ = false); clipToViewport_ = true;}
+
+ inline void setPreserveGeometry(bool value, const QGeoCoordinate &geoLeftBound = QGeoCoordinate())
+ {
+ preserveGeometry_ = value;
+ if (preserveGeometry_)
+ geoLeftBound_ = geoLeftBound;
+ }
+ inline QGeoCoordinate geoLeftBound() { return geoLeftBound_; }
+
+ inline QRectF sourceBoundingBox() const { return sourceBounds_; }
+ inline QRectF screenBoundingBox() const { return screenBounds_; }
+
+ inline QPointF firstPointOffset() const { return firstPointOffset_; }
+ void translate(const QPointF &offset);
+
+ inline const QGeoCoordinate &origin() const { return srcOrigin_; }
+
+ inline bool contains(const QPointF &screenPoint) const {
+ return screenOutline_.contains(screenPoint);
+ }
+
+ inline QVector2D vertex(quint32 index) const {
+ return QVector2D(screenVertices_[index]);
+ }
+
+ inline QVector<QPointF> vertices() const { return screenVertices_; }
+ inline QVector<quint32> indices() const { return screenIndices_; }
+
+ inline bool isIndexed() const { return (!screenIndices_.isEmpty()); }
+
+ /* Size is # of triangles */
+ inline quint32 size() const
+ {
+ if (isIndexed())
+ return screenIndices_.size() / 3;
+ else
+ return screenVertices_.size() / 3;
+ }
+
+ inline void clear() { firstPointOffset_ = QPointF(0,0);
+ screenVertices_.clear(); screenIndices_.clear(); }
+
+ void allocateAndFill(QSGGeometry *geom) const;
+
+ double geoDistanceToScreenWidth(const QGeoMap &map,
+ const QGeoCoordinate &fromCoord,
+ const QGeoCoordinate &toCoord);
+
+ static QRectF translateToCommonOrigin(const QList<QGeoMapItemGeometry *> &geoms);
+
+
+protected:
+ bool sourceDirty_;
+ bool screenDirty_;
+ bool clipToViewport_;
+ bool preserveGeometry_;
+ QGeoCoordinate geoLeftBound_;
+
+ QPointF firstPointOffset_;
+
+ QPainterPath screenOutline_;
+
+ QRectF sourceBounds_;
+ QRectF screenBounds_;
+
+ QGeoCoordinate srcOrigin_;
+
+ QVector<QPointF> screenVertices_;
+ QVector<quint32> screenIndices_;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOMAPITEMGEOMETRY_H
diff --git a/src/location/declarativemaps/qquickgeomapgesturearea.cpp b/src/location/declarativemaps/qquickgeomapgesturearea.cpp
new file mode 100644
index 00000000..7b9a48f1
--- /dev/null
+++ b/src/location/declarativemaps/qquickgeomapgesturearea.cpp
@@ -0,0 +1,1288 @@
+/****************************************************************************
+**
+** 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 "qquickgeomapgesturearea_p.h"
+#include "qquickgeocoordinateanimation_p.h"
+#include "qdeclarativegeomap_p.h"
+#include "error_messages.h"
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/qevent.h>
+#include <QtGui/QWheelEvent>
+#include <QtGui/QStyleHints>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/QQuickWindow>
+#include <QPropertyAnimation>
+#include <QDebug>
+#include "math.h"
+#include "qgeomap_p.h"
+#include "qdoublevector2d_p.h"
+
+#define QML_MAP_FLICK_DEFAULTMAXVELOCITY 2500
+#define QML_MAP_FLICK_MINIMUMDECELERATION 500
+#define QML_MAP_FLICK_DEFAULTDECELERATION 2500
+#define QML_MAP_FLICK_MAXIMUMDECELERATION 10000
+
+#define QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD 50
+// FlickThreshold determines how far the "mouse" must have moved
+// before we perform a flick.
+static const int FlickThreshold = 20;
+// Really slow flicks can be annoying.
+const qreal MinimumFlickVelocity = 75.0;
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \qmltype MapPinchEvent
+ \instantiates QGeoMapPinchEvent
+ \inqmlmodule QtLocation
+
+ \brief MapPinchEvent type provides basic information about pinch event.
+
+ MapPinchEvent type provides basic information about pinch event. They are
+ present in handlers of MapPinch (for example pinchStarted/pinchUpdated). Events are only
+ guaranteed to be valid for the duration of the handler.
+
+ Except for the \l accepted property, all properties are read-only.
+
+ \section2 Example Usage
+
+ The following example enables the pinch gesture on a map and reacts to the
+ finished event.
+
+ \code
+ Map {
+ id: map
+ gesture.enabled: true
+ gesture.onPinchFinished:{
+ var coordinate1 = map.toCoordinate(gesture.point1)
+ var coordinate2 = map.toCoordinate(gesture.point2)
+ console.log("Pinch started at:")
+ console.log(" Points (" + gesture.point1.x + ", " + gesture.point1.y + ") - (" + gesture.point2.x + ", " + gesture.point2.y + ")")
+ console.log(" Coordinates (" + coordinate1.latitude + ", " + coordinate1.longitude + ") - (" + coordinate2.latitude + ", " + coordinate2.longitude + ")")
+ }
+ }
+ \endcode
+
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+*/
+
+/*!
+ \qmlproperty QPoint QtLocation::MapPinchEvent::center
+
+ This read-only property holds the current center point.
+*/
+
+/*!
+ \qmlproperty real QtLocation::MapPinchEvent::angle
+
+ This read-only property holds the current angle between the two points in
+ the range -180 to 180. Positive values for the angles mean counter-clockwise
+ while negative values mean the clockwise direction. Zero degrees is at the
+ 3 o'clock position.
+*/
+
+/*!
+ \qmlproperty QPoint QtLocation::MapPinchEvent::point1
+ \qmlproperty QPoint QtLocation::MapPinchEvent::point2
+
+ These read-only properties hold the actual touch points generating the pinch.
+ The points are not in any particular order.
+*/
+
+/*!
+ \qmlproperty int QtLocation::MapPinchEvent::pointCount
+
+ This read-only property holds the number of points currently touched.
+ The MapPinch will not react until two touch points have initiated a gesture,
+ but will remain active until all touch points have been released.
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapPinchEvent::accepted
+
+ Setting this property to false in the \c MapPinch::onPinchStarted handler
+ will result in no further pinch events being generated, and the gesture
+ ignored.
+*/
+
+/*!
+ \qmltype MapGestureArea
+ \instantiates QQuickGeoMapGestureArea
+
+ \inqmlmodule QtLocation
+
+ \brief The MapGestureArea type provides Map gesture interaction.
+
+ MapGestureArea objects are used as part of a Map, to provide for panning,
+ flicking and pinch-to-zoom gesture used on touch displays.
+
+ A MapGestureArea is automatically created with a new Map and available with
+ the \l{Map::gesture}{gesture} property. This is the only way
+ to create a MapGestureArea, and once created this way cannot be destroyed
+ without its parent Map.
+
+ The two most commonly used properties of the MapGestureArea are the \l enabled
+ and \l acceptedGestures properties. Both of these must be set before a
+ MapGestureArea will have any effect upon interaction with the Map.
+ The \l flickDeceleration property controls how quickly the map pan slows after contact
+ is released while panning the map.
+
+ \section2 Performance
+
+ The MapGestureArea, when enabled, must process all incoming touch events in
+ order to track the shape and size of the "pinch". The overhead added on
+ touch events can be considered constant time.
+
+ \section2 Example Usage
+
+ The following example enables the pinch and pan gestures on the map, but not flicking. So the
+ map scrolling will halt immediately on releasing the mouse button / touch.
+
+ \code
+ Map {
+ gesture.enabled: true
+ gesture.acceptedGestures: MapGestureArea.PinchGesture | MapGestureArea.PanGesture
+ }
+ \endcode
+
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::enabled
+
+ This property holds whether the gestures are enabled.
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::pinchActive
+
+ This read-only property holds whether pinch gesture is active.
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::panActive
+
+ This read-only property holds whether pan gesture is active.
+
+ \note Change notifications for this property were introduced in Qt 5.5.
+*/
+
+/*!
+ \qmlproperty real QtLocation::MapGestureArea::maximumZoomLevelChange
+
+ This property holds the maximum zoom level change per pinch, essentially
+ meant to be used for setting the zoom sensitivity.
+
+ It is an indicative measure calculated from the dimensions of the
+ map area, roughly corresponding how much zoom level could change with
+ maximum pinch zoom. Default value is 4.0, maximum value is 10.0
+*/
+
+/*!
+ \qmlproperty real MapGestureArea::flickDeceleration
+
+ This property holds the rate at which a flick will decelerate.
+
+ The default value is 2500.
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::pinchStarted(PinchEvent event)
+
+ This signal is emitted when a pinch gesture is started.
+
+ The corresponding handler is \c onPinchStarted.
+
+ \sa pinchUpdated, pinchFinished
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::pinchUpdated(PinchEvent event)
+
+ This signal is emitted as the user's fingers move across the map,
+ after the \l pinchStarted signal is emitted.
+
+ The corresponding handler is \c onPinchUpdated.
+
+ \sa pinchStarted, pinchFinished
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::pinchFinished(PinchEvent event)
+
+ This signal is emitted at the end of a pinch gesture.
+
+ The corresponding handler is \c onPinchFinished.
+
+ \sa pinchStarted, pinchUpdated
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::panStarted()
+
+ This signal is emitted when the map begins to move due to user
+ interaction. Typically this means that the user is dragging a finger -
+ or a mouse with one of more mouse buttons pressed - on the map.
+
+ The corresponding handler is \c onPanStarted.
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::panFinished()
+
+ This signal is emitted when the map stops moving due to user
+ interaction. If a flick was generated, this signal is
+ emitted before flick starts. If a flick was not
+ generated, this signal is emitted when the
+ user stops dragging - that is a mouse or touch release.
+
+ The corresponding handler is \c onPanFinished.
+
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::flickStarted()
+
+ This signal is emitted when the map is flicked. A flick
+ starts from the point where the mouse or touch was released,
+ while still in motion.
+
+ The corresponding handler is \c onFlichStarted.
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::flickFinished()
+
+ This signal is emitted when the map stops moving due to a flick.
+
+ The corresponding handler is \c onFlickFinished.
+*/
+
+QQuickGeoMapGestureArea::QQuickGeoMapGestureArea(QDeclarativeGeoMap *map)
+ : QQuickItem(map),
+ m_map(0),
+ m_declarativeMap(map),
+ m_enabled(true),
+ m_acceptedGestures(PinchGesture | PanGesture | FlickGesture),
+ m_preventStealing(false),
+ m_panEnabled(true)
+{
+ m_flick.m_enabled = true,
+ m_flick.m_maxVelocity = QML_MAP_FLICK_DEFAULTMAXVELOCITY;
+ m_flick.m_deceleration = QML_MAP_FLICK_DEFAULTDECELERATION;
+ m_flick.m_animation = 0;
+ m_touchPointState = touchPoints0;
+ m_pinchState = pinchInactive;
+ m_flickState = flickInactive;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setMap(QGeoMap *map)
+{
+ if (m_map || !map)
+ return;
+
+ m_map = map;
+ m_flick.m_animation = new QQuickGeoCoordinateAnimation(this);
+ m_flick.m_animation->setTargetObject(m_declarativeMap);
+ m_flick.m_animation->setProperty(QStringLiteral("center"));
+ m_flick.m_animation->setEasing(QEasingCurve(QEasingCurve::OutQuad));
+ connect(m_flick.m_animation, &QQuickAbstractAnimation::stopped, this, &QQuickGeoMapGestureArea::handleFlickAnimationStopped);
+}
+
+/*!
+ \qmlproperty bool QtQuick::MapGestureArea::preventStealing
+ This property holds whether the mouse events may be stolen from this
+ MapGestureArea.
+
+ If a Map is placed within an item that filters child mouse
+ and touch events, such as Flickable, the mouse and touch events
+ may be stolen from the MapGestureArea if a gesture is recognized
+ by the parent item, e.g. a flick gesture. If preventStealing is
+ set to true, no item will steal the mouse and touch events.
+
+ Note that setting preventStealing to true once an item has started
+ stealing events will have no effect until the next press event.
+
+ By default this property is false.
+*/
+
+bool QQuickGeoMapGestureArea::preventStealing() const
+{
+ return m_preventStealing;
+}
+
+void QQuickGeoMapGestureArea::setPreventStealing(bool prevent)
+{
+ if (prevent != m_preventStealing) {
+ m_preventStealing = prevent;
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing && m_enabled);
+ m_declarativeMap->setKeepTouchGrab(m_preventStealing && m_enabled);
+ emit preventStealingChanged();
+ }
+}
+
+QQuickGeoMapGestureArea::~QQuickGeoMapGestureArea()
+{
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::MapGestureArea::acceptedGestures
+
+ This property holds the gestures that will be active. By default
+ the zoom, pan and flick gestures are enabled.
+
+ \list
+ \li MapGestureArea.NoGesture - Don't support any additional gestures (value: 0x0000).
+ \li MapGestureArea.PinchGesture - Support the map pinch gesture (value: 0x0001).
+ \li MapGestureArea.PanGesture - Support the map pan gesture (value: 0x0002).
+ \li MapGestureArea.FlickGesture - Support the map flick gesture (value: 0x0004).
+ \endlist
+*/
+
+QQuickGeoMapGestureArea::AcceptedGestures QQuickGeoMapGestureArea::acceptedGestures() const
+{
+ return m_acceptedGestures;
+}
+
+
+void QQuickGeoMapGestureArea::setAcceptedGestures(AcceptedGestures acceptedGestures)
+{
+ if (acceptedGestures == m_acceptedGestures)
+ return;
+ m_acceptedGestures = acceptedGestures;
+
+ setPanEnabled(acceptedGestures & PanGesture);
+ setFlickEnabled(acceptedGestures & FlickGesture);
+ setPinchEnabled(acceptedGestures & PinchGesture);
+
+ emit acceptedGesturesChanged();
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::isPinchActive() const
+{
+ return m_pinchState == pinchActive;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::isPanActive() const
+{
+ return m_flickState == panActive || m_flickState == flickActive;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::enabled() const
+{
+ return m_enabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setEnabled(bool enabled)
+{
+ if (enabled == m_enabled)
+ return;
+ m_enabled = enabled;
+
+ if (enabled) {
+ setPanEnabled(m_acceptedGestures & PanGesture);
+ setFlickEnabled(m_acceptedGestures & FlickGesture);
+ setPinchEnabled(m_acceptedGestures & PinchGesture);
+ } else {
+ setPanEnabled(false);
+ setFlickEnabled(false);
+ setPinchEnabled(false);
+ }
+
+ emit enabledChanged();
+}
+
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::pinchEnabled() const
+{
+ return m_pinch.m_enabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setPinchEnabled(bool enabled)
+{
+ if (enabled == m_pinch.m_enabled)
+ return;
+ m_pinch.m_enabled = enabled;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::panEnabled() const
+{
+ return m_panEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setPanEnabled(bool enabled)
+{
+ if (enabled == m_flick.m_enabled)
+ return;
+ m_panEnabled = enabled;
+
+ // unlike the pinch, the pan existing functionality is to stop immediately
+ if (!enabled)
+ stopPan();
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::flickEnabled() const
+{
+ return m_flick.m_enabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setFlickEnabled(bool enabled)
+{
+ if (enabled == m_flick.m_enabled)
+ return;
+ m_flick.m_enabled = enabled;
+ // unlike the pinch, the flick existing functionality is to stop immediately
+ if (!enabled) {
+ stopFlick();
+ }
+}
+
+/*!
+ \internal
+ Used internally to set the minimum zoom level of the gesture area.
+ The caller is responsible to only send values that are valid
+ for the map plugin. Negative values are ignored.
+ */
+void QQuickGeoMapGestureArea::setMinimumZoomLevel(qreal min)
+{
+ if (min >= 0)
+ m_pinch.m_zoom.m_minimum = min;
+}
+
+/*!
+ \internal
+ */
+qreal QQuickGeoMapGestureArea::minimumZoomLevel() const
+{
+ return m_pinch.m_zoom.m_minimum;
+}
+
+/*!
+ \internal
+ Used internally to set the maximum zoom level of the gesture area.
+ The caller is responsible to only send values that are valid
+ for the map plugin. Negative values are ignored.
+ */
+void QQuickGeoMapGestureArea::setMaximumZoomLevel(qreal max)
+{
+ if (max >= 0)
+ m_pinch.m_zoom.m_maximum = max;
+}
+
+/*!
+ \internal
+ */
+qreal QQuickGeoMapGestureArea::maximumZoomLevel() const
+{
+ return m_pinch.m_zoom.m_maximum;
+}
+
+/*!
+ \internal
+*/
+qreal QQuickGeoMapGestureArea::maximumZoomLevelChange() const
+{
+ return m_pinch.m_zoom.maximumChange;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setMaximumZoomLevelChange(qreal maxChange)
+{
+ if (maxChange == m_pinch.m_zoom.maximumChange || maxChange < 0.1 || maxChange > 10.0)
+ return;
+ m_pinch.m_zoom.maximumChange = maxChange;
+ emit maximumZoomLevelChangeChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QQuickGeoMapGestureArea::flickDeceleration() const
+{
+ return m_flick.m_deceleration;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setFlickDeceleration(qreal deceleration)
+{
+ if (deceleration < QML_MAP_FLICK_MINIMUMDECELERATION)
+ deceleration = QML_MAP_FLICK_MINIMUMDECELERATION;
+ else if (deceleration > QML_MAP_FLICK_MAXIMUMDECELERATION)
+ deceleration = QML_MAP_FLICK_MAXIMUMDECELERATION;
+ if (deceleration == m_flick.m_deceleration)
+ return;
+ m_flick.m_deceleration = deceleration;
+ emit flickDecelerationChanged();
+}
+
+/*!
+ \internal
+*/
+QTouchEvent::TouchPoint* createTouchPointFromMouseEvent(QMouseEvent *event, Qt::TouchPointState state)
+{
+ // this is only partially filled. But since it is only partially used it works
+ // more robust would be to store a list of QPointFs rather than TouchPoints
+ QTouchEvent::TouchPoint* newPoint = new QTouchEvent::TouchPoint();
+ newPoint->setPos(event->localPos());
+ newPoint->setScenePos(event->windowPos());
+ newPoint->setScreenPos(event->screenPos());
+ newPoint->setState(state);
+ newPoint->setId(0);
+ return newPoint;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleMousePressEvent(QMouseEvent *event)
+{
+ m_mousePoint.reset(createTouchPointFromMouseEvent(event, Qt::TouchPointPressed));
+ if (m_touchPoints.isEmpty()) update();
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleMouseMoveEvent(QMouseEvent *event)
+{
+ m_mousePoint.reset(createTouchPointFromMouseEvent(event, Qt::TouchPointMoved));
+ if (m_touchPoints.isEmpty()) update();
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleMouseReleaseEvent(QMouseEvent *event)
+{
+ if (!m_mousePoint.isNull()) {
+ //this looks super ugly , however is required in case we do not get synthesized MouseReleaseEvent
+ //and we reset the point already in handleTouchUngrabEvent
+ m_mousePoint.reset(createTouchPointFromMouseEvent(event, Qt::TouchPointReleased));
+ if (m_touchPoints.isEmpty()) update();
+ }
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleMouseUngrabEvent()
+{
+
+ if (m_touchPoints.isEmpty() && !m_mousePoint.isNull()) {
+ m_mousePoint.reset();
+ update();
+ } else {
+ m_mousePoint.reset();
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleTouchUngrabEvent()
+{
+ m_touchPoints.clear();
+ //this is needed since in some cases mouse release is not delivered
+ //(second touch point breaks mouse synthesized events)
+ m_mousePoint.reset();
+ update();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleTouchEvent(QTouchEvent *event)
+{
+ m_touchPoints.clear();
+ m_mousePoint.reset();
+
+ for (int i = 0; i < event->touchPoints().count(); ++i) {
+ auto point = event->touchPoints().at(i);
+ if (point.state() != Qt::TouchPointReleased)
+ m_touchPoints << point;
+ }
+ if (event->touchPoints().count() >= 2)
+ event->accept();
+ else
+ event->ignore();
+ update();
+}
+
+void QQuickGeoMapGestureArea::handleWheelEvent(QWheelEvent *event)
+{
+ if (!m_map)
+ return;
+
+ QGeoCoordinate wheelGeoPos = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(event->posF()), false);
+ QPointF preZoomPoint = m_map->geoProjection().coordinateToItemPosition(wheelGeoPos, false).toPointF();
+
+ double zoomLevelDelta = event->angleDelta().y() * qreal(0.001);
+ m_declarativeMap->setZoomLevel(m_declarativeMap->zoomLevel() + zoomLevelDelta);
+ QPointF postZoomPoint = m_map->geoProjection().coordinateToItemPosition(wheelGeoPos, false).toPointF();
+
+ if (preZoomPoint != postZoomPoint)
+ {
+ qreal dx = postZoomPoint.x() - preZoomPoint.x();
+ qreal dy = postZoomPoint.y() - preZoomPoint.y();
+ QPointF mapCenterPoint(m_map->viewportWidth() / 2.0 + dx, m_map->viewportHeight() / 2.0 + dy);
+
+ QGeoCoordinate mapCenterCoordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(mapCenterPoint), false);
+ m_declarativeMap->setCenter(mapCenterCoordinate);
+ }
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::clearTouchData()
+{
+ m_velocityX = 0;
+ m_velocityY = 0;
+ m_sceneCenter.setX(0);
+ m_sceneCenter.setY(0);
+ m_touchCenterCoord.setLongitude(0);
+ m_touchCenterCoord.setLatitude(0);
+ m_startCoord.setLongitude(0);
+ m_startCoord.setLatitude(0);
+}
+
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateVelocityList(const QPointF &pos)
+{
+ // Take velocity samples every sufficient period of time, used later to determine the flick
+ // duration and speed (when mouse is released).
+ qreal elapsed = qreal(m_lastPosTime.elapsed());
+
+ if (elapsed >= QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD) {
+ elapsed /= 1000.;
+ int dyFromLastPos = pos.y() - m_lastPos.y();
+ int dxFromLastPos = pos.x() - m_lastPos.x();
+ m_lastPos = pos;
+ m_lastPosTime.restart();
+ qreal velX = qreal(dxFromLastPos) / elapsed;
+ qreal velY = qreal(dyFromLastPos) / elapsed;
+ m_velocityX = qBound<qreal>(-m_flick.m_maxVelocity, velX, m_flick.m_maxVelocity);
+ m_velocityY = qBound<qreal>(-m_flick.m_maxVelocity, velY, m_flick.m_maxVelocity);
+ }
+}
+
+/*!
+ \internal
+*/
+
+bool QQuickGeoMapGestureArea::isActive() const
+{
+ return isPanActive() || isPinchActive();
+}
+
+/*!
+ \internal
+*/
+// simplify the gestures by using a state-machine format (easy to move to a future state machine)
+void QQuickGeoMapGestureArea::update()
+{
+ if (!m_map)
+ return;
+
+ // First state machine is for the number of touch points
+
+ //combine touch with mouse event
+ m_allPoints.clear();
+ m_allPoints << m_touchPoints;
+ if (m_allPoints.isEmpty() && !m_mousePoint.isNull())
+ m_allPoints << *m_mousePoint.data();
+
+ touchPointStateMachine();
+
+ // Parallel state machine for pinch
+ if (isPinchActive() || (m_enabled && m_pinch.m_enabled && (m_acceptedGestures & (PinchGesture))))
+ pinchStateMachine();
+
+ // Parallel state machine for pan (since you can pan at the same time as pinching)
+ // The stopPan function ensures that pan stops immediately when disabled,
+ // but the line below allows pan continue its current gesture if you disable
+ // the whole gesture (enabled_ flag), this keeps the enabled_ consistent with the pinch
+ if (isPanActive() || (m_enabled && m_flick.m_enabled && (m_acceptedGestures & (PanGesture | FlickGesture))))
+ panStateMachine();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::touchPointStateMachine()
+{
+ // Transitions:
+ switch (m_touchPointState) {
+ case touchPoints0:
+ if (m_allPoints.count() == 1) {
+ clearTouchData();
+ startOneTouchPoint();
+ m_touchPointState = touchPoints1;
+ } else if (m_allPoints.count() >= 2) {
+ clearTouchData();
+ startTwoTouchPoints();
+ m_touchPointState = touchPoints2;
+ }
+ break;
+ case touchPoints1:
+ if (m_allPoints.count() == 0) {
+ m_touchPointState = touchPoints0;
+ } else if (m_allPoints.count() == 2) {
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ startTwoTouchPoints();
+ m_touchPointState = touchPoints2;
+ }
+ break;
+ case touchPoints2:
+ if (m_allPoints.count() == 0) {
+ m_touchPointState = touchPoints0;
+ } else if (m_allPoints.count() == 1) {
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ startOneTouchPoint();
+ m_touchPointState = touchPoints1;
+ }
+ break;
+ };
+
+ // Update
+ switch (m_touchPointState) {
+ case touchPoints0:
+ break; // do nothing if no touch points down
+ case touchPoints1:
+ updateOneTouchPoint();
+ break;
+ case touchPoints2:
+ updateTwoTouchPoints();
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startOneTouchPoint()
+{
+ m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_lastPos = m_sceneStartPoint1;
+ m_lastPosTime.start();
+ QGeoCoordinate startCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneStartPoint1), false);
+ // ensures a smooth transition for panning
+ m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() -
+ m_touchCenterCoord.longitude());
+ m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() -
+ m_touchCenterCoord.latitude());
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateOneTouchPoint()
+{
+ m_sceneCenter = mapFromScene(m_allPoints.at(0).scenePos());
+ updateVelocityList(m_sceneCenter);
+}
+
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startTwoTouchPoints()
+{
+ m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_sceneStartPoint2 = mapFromScene(m_allPoints.at(1).scenePos());
+ QPointF startPos = (m_sceneStartPoint1 + m_sceneStartPoint2) * 0.5;
+ m_lastPos = startPos;
+ m_lastPosTime.start();
+ QGeoCoordinate startCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(startPos), false);
+ m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() -
+ m_touchCenterCoord.longitude());
+ m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() -
+ m_touchCenterCoord.latitude());
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateTwoTouchPoints()
+{
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ qreal dx = p1.x() - p2.x();
+ qreal dy = p1.y() - p2.y();
+ m_distanceBetweenTouchPoints = sqrt(dx * dx + dy * dy);
+ m_sceneCenter = (p1 + p2) / 2;
+ updateVelocityList(m_sceneCenter);
+
+ m_twoTouchAngle = QLineF(p1, p2).angle();
+ if (m_twoTouchAngle > 180)
+ m_twoTouchAngle -= 360;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::pinchStateMachine()
+{
+ PinchState lastState = m_pinchState;
+ // Transitions:
+ switch (m_pinchState) {
+ case pinchInactive:
+ if (m_allPoints.count() >= 2) {
+ if (canStartPinch()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startPinch();
+ m_pinchState = pinchActive;
+ } else {
+ m_pinchState = pinchInactiveTwoPoints;
+ }
+ }
+ break;
+ case pinchInactiveTwoPoints:
+ if (m_allPoints.count() <= 1) {
+ m_pinchState = pinchInactive;
+ } else {
+ if (canStartPinch()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startPinch();
+ m_pinchState = pinchActive;
+ }
+ }
+ break;
+ case pinchActive:
+ if (m_allPoints.count() <= 1) {
+ m_pinchState = pinchInactive;
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_declarativeMap->setKeepTouchGrab(m_preventStealing);
+ endPinch();
+ }
+ break;
+ }
+ // This line implements an exclusive state machine, where the transitions and updates don't
+ // happen on the same frame
+ if (m_pinchState != lastState) {
+ emit pinchActiveChanged();
+ return;
+ }
+
+ // Update
+ switch (m_pinchState) {
+ case pinchInactive:
+ case pinchInactiveTwoPoints:
+ break; // do nothing
+ case pinchActive:
+ updatePinch();
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::canStartPinch()
+{
+ const int startDragDistance = qApp->styleHints()->startDragDistance();
+
+ if (m_allPoints.count() >= 2) {
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ if (qAbs(p1.x()-m_sceneStartPoint1.x()) > startDragDistance
+ || qAbs(p1.y()-m_sceneStartPoint1.y()) > startDragDistance
+ || qAbs(p2.x()-m_sceneStartPoint2.x()) > startDragDistance
+ || qAbs(p2.y()-m_sceneStartPoint2.y()) > startDragDistance) {
+ m_pinch.m_event.setCenter(mapFromScene(m_sceneCenter));
+ m_pinch.m_event.setAngle(m_twoTouchAngle);
+ m_pinch.m_event.setPoint1(p1);
+ m_pinch.m_event.setPoint2(p2);
+ m_pinch.m_event.setPointCount(m_allPoints.count());
+ m_pinch.m_event.setAccepted(true);
+ emit pinchStarted(&m_pinch.m_event);
+ return m_pinch.m_event.accepted();
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startPinch()
+{
+ m_pinch.m_startDist = m_distanceBetweenTouchPoints;
+ m_pinch.m_zoom.m_previous = m_declarativeMap->zoomLevel();
+ m_pinch.m_lastAngle = m_twoTouchAngle;
+
+ m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePos());
+
+ m_pinch.m_zoom.m_start = m_declarativeMap->zoomLevel();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updatePinch()
+{
+ // Calculate the new zoom level if we have distance ( >= 2 touchpoints), otherwise stick with old.
+ qreal newZoomLevel = m_pinch.m_zoom.m_previous;
+ if (m_distanceBetweenTouchPoints) {
+ newZoomLevel =
+ // How much further/closer the current touchpoints are (in pixels) compared to pinch start
+ ((m_distanceBetweenTouchPoints - m_pinch.m_startDist) *
+ // How much one pixel corresponds in units of zoomlevel (and multiply by above delta)
+ (m_pinch.m_zoom.maximumChange / ((width() + height()) / 2))) +
+ // Add to starting zoom level. Sign of (dist-pinchstartdist) takes care of zoom in / out
+ m_pinch.m_zoom.m_start;
+ }
+
+ m_pinch.m_event.setCenter(mapFromScene(m_sceneCenter));
+ m_pinch.m_event.setAngle(m_twoTouchAngle);
+
+ m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePos());
+ m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1);
+ m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2);
+ m_pinch.m_event.setPointCount(m_allPoints.count());
+ m_pinch.m_event.setAccepted(true);
+
+ m_pinch.m_lastAngle = m_twoTouchAngle;
+ emit pinchUpdated(&m_pinch.m_event);
+
+ if (m_acceptedGestures & PinchGesture) {
+ // Take maximum and minimumzoomlevel into account
+ qreal perPinchMinimumZoomLevel = qMax(m_pinch.m_zoom.m_start - m_pinch.m_zoom.maximumChange, m_pinch.m_zoom.m_minimum);
+ qreal perPinchMaximumZoomLevel = qMin(m_pinch.m_zoom.m_start + m_pinch.m_zoom.maximumChange, m_pinch.m_zoom.m_maximum);
+ newZoomLevel = qMin(qMax(perPinchMinimumZoomLevel, newZoomLevel), perPinchMaximumZoomLevel);
+ m_declarativeMap->setZoomLevel(newZoomLevel);
+ m_pinch.m_zoom.m_previous = newZoomLevel;
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::endPinch()
+{
+ QPointF p1 = mapFromScene(m_pinch.m_lastPoint1);
+ QPointF p2 = mapFromScene(m_pinch.m_lastPoint2);
+ m_pinch.m_event.setCenter((p1 + p2) / 2);
+ m_pinch.m_event.setAngle(m_pinch.m_lastAngle);
+ m_pinch.m_event.setPoint1(p1);
+ m_pinch.m_event.setPoint2(p2);
+ m_pinch.m_event.setAccepted(true);
+ m_pinch.m_event.setPointCount(0);
+ emit pinchFinished(&m_pinch.m_event);
+ m_pinch.m_startDist = 0;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::panStateMachine()
+{
+ FlickState lastState = m_flickState;
+
+ // Transitions
+ switch (m_flickState) {
+ case flickInactive:
+ if (canStartPan()) {
+ // Update startCoord_ to ensure smooth start for panning when going over startDragDistance
+ QGeoCoordinate newStartCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ m_startCoord.setLongitude(newStartCoord.longitude());
+ m_startCoord.setLatitude(newStartCoord.latitude());
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_flickState = panActive;
+ }
+ break;
+ case panActive:
+ if (m_allPoints.count() == 0) {
+ if (!tryStartFlick())
+ {
+ m_flickState = flickInactive;
+ // mark as inactive for use by camera
+ if (m_pinchState == pinchInactive) {
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_map->prefetchData();
+ }
+ emit panFinished();
+ } else {
+ m_flickState = flickActive;
+ emit panFinished();
+ emit flickStarted();
+ }
+ }
+ break;
+ case flickActive:
+ if (m_allPoints.count() > 0) { // re touched before movement ended
+ stopFlick();
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_flickState = panActive;
+ }
+ break;
+ }
+
+ if (m_flickState != lastState)
+ emit panActiveChanged();
+
+ // Update
+ switch (m_flickState) {
+ case flickInactive: // do nothing
+ break;
+ case panActive:
+ updatePan();
+ // this ensures 'panStarted' occurs after the pan has actually started
+ if (lastState != panActive)
+ emit panStarted();
+ break;
+ case flickActive:
+ break;
+ }
+}
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::canStartPan()
+{
+ if (m_allPoints.count() == 0 || (m_acceptedGestures & PanGesture) == 0)
+ return false;
+
+ // Check if thresholds for normal panning are met.
+ // (normal panning vs flicking: flicking will start from mouse release event).
+ const int startDragDistance = qApp->styleHints()->startDragDistance() * 2;
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ int dyFromPress = int(p1.y() - m_sceneStartPoint1.y());
+ int dxFromPress = int(p1.x() - m_sceneStartPoint1.x());
+ if ((qAbs(dyFromPress) >= startDragDistance || qAbs(dxFromPress) >= startDragDistance))
+ return true;
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updatePan()
+{
+ QPointF startPoint = m_map->geoProjection().coordinateToItemPosition(m_startCoord, false).toPointF();
+ int dx = static_cast<int>(m_sceneCenter.x() - startPoint.x());
+ int dy = static_cast<int>(m_sceneCenter.y() - startPoint.y());
+ QPointF mapCenterPoint;
+ mapCenterPoint.setY(m_map->viewportHeight() / 2.0 - dy);
+ mapCenterPoint.setX(m_map->viewportWidth() / 2.0 - dx);
+ QGeoCoordinate animationStartCoordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(mapCenterPoint), false);
+ m_declarativeMap->setCenter(animationStartCoordinate);
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::tryStartFlick()
+{
+ if ((m_acceptedGestures & FlickGesture) == 0)
+ return false;
+ // if we drag then pause before release we should not cause a flick.
+ qreal velocityX = 0.0;
+ qreal velocityY = 0.0;
+ if (m_lastPosTime.elapsed() < QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD) {
+ velocityY = m_velocityY;
+ velocityX = m_velocityX;
+ }
+ int flickTimeY = 0;
+ int flickTimeX = 0;
+ int flickPixelsX = 0;
+ int flickPixelsY = 0;
+ if (qAbs(velocityY) > MinimumFlickVelocity && qAbs(m_sceneCenter.y() - m_sceneStartPoint1.y()) > FlickThreshold) {
+ // calculate Y flick animation values
+ qreal acceleration = m_flick.m_deceleration;
+ if ((velocityY > 0.0f) == (m_flick.m_deceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+ flickTimeY = static_cast<int>(-1000 * velocityY / acceleration);
+ flickPixelsY = (flickTimeY * velocityY) / (1000.0 * 2);
+ }
+ if (qAbs(velocityX) > MinimumFlickVelocity && qAbs(m_sceneCenter.x() - m_sceneStartPoint1.x()) > FlickThreshold) {
+ // calculate X flick animation values
+ qreal acceleration = m_flick.m_deceleration;
+ if ((velocityX > 0.0f) == (m_flick.m_deceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+ flickTimeX = static_cast<int>(-1000 * velocityX / acceleration);
+ flickPixelsX = (flickTimeX * velocityX) / (1000.0 * 2);
+ }
+ int flickTime = qMax(flickTimeY, flickTimeX);
+ if (flickTime > 0) {
+ startFlick(flickPixelsX, flickPixelsY, flickTime);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startFlick(int dx, int dy, int timeMs)
+{
+ if (!m_flick.m_animation)
+ return;
+ if (timeMs < 0)
+ return;
+
+ QGeoCoordinate animationStartCoordinate = m_declarativeMap->center();
+
+ if (m_flick.m_animation->isRunning())
+ m_flick.m_animation->stop();
+ QGeoCoordinate animationEndCoordinate = m_declarativeMap->center();
+ m_flick.m_animation->setDuration(timeMs);
+
+ double zoom = pow(2.0, m_declarativeMap->zoomLevel());
+ double longitude = animationStartCoordinate.longitude() - (dx / zoom);
+ double latitude = animationStartCoordinate.latitude() + (dy / zoom);
+
+ if (dx > 0)
+ m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::East);
+ else
+ m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::West);
+
+ //keep animation in correct bounds
+ if (latitude > 85.05113)
+ latitude = 85.05113;
+ else if (latitude < -85.05113)
+ latitude = -85.05113;
+
+ if (longitude > 180)
+ longitude = longitude - 360;
+ else if (longitude < -180)
+ longitude = longitude + 360;
+
+ animationEndCoordinate.setLongitude(longitude);
+ animationEndCoordinate.setLatitude(latitude);
+
+ m_flick.m_animation->setFrom(animationStartCoordinate);
+ m_flick.m_animation->setTo(animationEndCoordinate);
+ m_flick.m_animation->start();
+}
+
+void QQuickGeoMapGestureArea::stopPan()
+{
+ if (m_flickState == flickActive) {
+ stopFlick();
+ } else if (m_flickState == panActive) {
+ m_velocityX = 0;
+ m_velocityY = 0;
+ m_flickState = flickInactive;
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ emit panFinished();
+ emit panActiveChanged();
+ m_map->prefetchData();
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::stopFlick()
+{
+ if (!m_flick.m_animation)
+ return;
+ m_velocityX = 0;
+ m_velocityY = 0;
+ if (m_flick.m_animation->isRunning())
+ m_flick.m_animation->stop();
+ else
+ handleFlickAnimationStopped();
+}
+
+void QQuickGeoMapGestureArea::handleFlickAnimationStopped()
+{
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ if (m_flickState == flickActive) {
+ m_flickState = flickInactive;
+ emit flickFinished();
+ emit panActiveChanged();
+ m_map->prefetchData();
+ }
+}
+
+#include "moc_qquickgeomapgesturearea_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qquickgeomapgesturearea_p.h b/src/location/declarativemaps/qquickgeomapgesturearea_p.h
new file mode 100644
index 00000000..5d3efc8d
--- /dev/null
+++ b/src/location/declarativemaps/qquickgeomapgesturearea_p.h
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QQUICKGEOMAPGESTUREAREA_P_H
+#define QQUICKGEOMAPGESTUREAREA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtQuick/QQuickItem>
+#include <QTouchEvent>
+#include <QDebug>
+#include <QElapsedTimer>
+#include <QtPositioning/qgeocoordinate.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsSceneMouseEvent;
+class QQuickGeoCoordinateAnimation;
+class QDeclarativeGeoMap;
+class QTouchEvent;
+class QWheelEvent;
+class QGeoMap;
+
+class Q_LOCATION_PRIVATE_EXPORT QGeoMapPinchEvent : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPointF center READ center)
+ Q_PROPERTY(qreal angle READ angle)
+ Q_PROPERTY(QPointF point1 READ point1)
+ Q_PROPERTY(QPointF point2 READ point2)
+ Q_PROPERTY(int pointCount READ pointCount)
+ Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+
+public:
+ QGeoMapPinchEvent(const QPointF &center, qreal angle,
+ const QPointF &point1, const QPointF &point2,
+ int pointCount = 0, bool accepted = true)
+ : QObject(), m_center(center), m_angle(angle),
+ m_point1(point1), m_point2(point2),
+ m_pointCount(pointCount), m_accepted(accepted) {}
+ QGeoMapPinchEvent()
+ : QObject(),
+ m_angle(0.0),
+ m_pointCount(0),
+ m_accepted(true) {}
+
+ QPointF center() const { return m_center; }
+ void setCenter(const QPointF &center) { m_center = center; }
+ qreal angle() const { return m_angle; }
+ void setAngle(qreal angle) { m_angle = angle; }
+ QPointF point1() const { return m_point1; }
+ void setPoint1(const QPointF &p) { m_point1 = p; }
+ QPointF point2() const { return m_point2; }
+ void setPoint2(const QPointF &p) { m_point2 = p; }
+ int pointCount() const { return m_pointCount; }
+ void setPointCount(int count) { m_pointCount = count; }
+ bool accepted() const { return m_accepted; }
+ void setAccepted(bool a) { m_accepted = a; }
+
+private:
+ QPointF m_center;
+ qreal m_angle;
+ QPointF m_point1;
+ QPointF m_point2;
+ int m_pointCount;
+ bool m_accepted;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QQuickGeoMapGestureArea: public QQuickItem
+{
+ Q_OBJECT
+ Q_ENUMS(GeoMapGesture)
+ Q_FLAGS(AcceptedGestures)
+
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool pinchActive READ isPinchActive NOTIFY pinchActiveChanged)
+ Q_PROPERTY(bool panActive READ isPanActive NOTIFY panActiveChanged)
+ Q_PROPERTY(AcceptedGestures acceptedGestures READ acceptedGestures WRITE setAcceptedGestures NOTIFY acceptedGesturesChanged)
+ Q_PROPERTY(qreal maximumZoomLevelChange READ maximumZoomLevelChange WRITE setMaximumZoomLevelChange NOTIFY maximumZoomLevelChangeChanged)
+ Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
+ Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged REVISION 1)
+
+public:
+ QQuickGeoMapGestureArea(QDeclarativeGeoMap *map);
+ ~QQuickGeoMapGestureArea();
+
+ enum GeoMapGesture {
+ NoGesture = 0x0000,
+ PinchGesture = 0x0001,
+ PanGesture = 0x0002,
+ FlickGesture = 0x004
+ };
+
+ Q_DECLARE_FLAGS(AcceptedGestures, GeoMapGesture)
+
+ AcceptedGestures acceptedGestures() const;
+ void setAcceptedGestures(AcceptedGestures acceptedGestures);
+
+ bool isPinchActive() const;
+ bool isPanActive() const;
+ bool isActive() const;
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+ qreal maximumZoomLevelChange() const;
+ void setMaximumZoomLevelChange(qreal maxChange);
+
+ qreal flickDeceleration() const;
+ void setFlickDeceleration(qreal deceleration);
+
+ void handleTouchEvent(QTouchEvent *event);
+ void handleWheelEvent(QWheelEvent *event);
+ void handleMousePressEvent(QMouseEvent *event);
+ void handleMouseMoveEvent(QMouseEvent *event);
+ void handleMouseReleaseEvent(QMouseEvent *event);
+ void handleMouseUngrabEvent();
+ void handleTouchUngrabEvent();
+
+ void setMinimumZoomLevel(qreal min);
+ qreal minimumZoomLevel() const;
+
+ void setMaximumZoomLevel(qreal max);
+ qreal maximumZoomLevel() const;
+
+ void setMap(QGeoMap *map);
+
+ bool preventStealing() const;
+ void setPreventStealing(bool prevent);
+
+Q_SIGNALS:
+ void panActiveChanged();
+ void pinchActiveChanged();
+ void enabledChanged();
+ void maximumZoomLevelChangeChanged();
+ void acceptedGesturesChanged();
+ void flickDecelerationChanged();
+ void pinchStarted(QGeoMapPinchEvent *pinch);
+ void pinchUpdated(QGeoMapPinchEvent *pinch);
+ void pinchFinished(QGeoMapPinchEvent *pinch);
+ void panStarted();
+ void panFinished();
+ void flickStarted();
+ void flickFinished();
+ void preventStealingChanged();
+private:
+ void update();
+
+ // Create general data relating to the touch points
+ void touchPointStateMachine();
+ void startOneTouchPoint();
+ void updateOneTouchPoint();
+ void startTwoTouchPoints();
+ void updateTwoTouchPoints();
+
+ // All pinch related code, which encompasses zoom
+ void pinchStateMachine();
+ bool canStartPinch();
+ void startPinch();
+ void updatePinch();
+ void endPinch();
+
+ // Pan related code (regardles of number of touch points),
+ // includes the flick based panning after letting go
+ void panStateMachine();
+ bool canStartPan();
+ void updatePan();
+ bool tryStartFlick();
+ void startFlick(int dx, int dy, int timeMs = 0);
+ void stopFlick();
+
+ bool pinchEnabled() const;
+ void setPinchEnabled(bool enabled);
+ bool panEnabled() const;
+ void setPanEnabled(bool enabled);
+ bool flickEnabled() const;
+ void setFlickEnabled(bool enabled);
+
+private Q_SLOTS:
+ void handleFlickAnimationStopped();
+
+
+private:
+ void stopPan();
+ void clearTouchData();
+ void updateVelocityList(const QPointF &pos);
+
+private:
+ QGeoMap *m_map;
+ QDeclarativeGeoMap *m_declarativeMap;
+ bool m_enabled;
+
+ struct Pinch
+ {
+ Pinch() : m_enabled(true), m_startDist(0), m_lastAngle(0.0) {}
+
+ QGeoMapPinchEvent m_event;
+ bool m_enabled;
+ struct Zoom
+ {
+ Zoom() : m_minimum(0.0), m_maximum(30.0), m_start(0.0), m_previous(0.0),
+ maximumChange(4.0) {}
+ qreal m_minimum;
+ qreal m_maximum;
+ qreal m_start;
+ qreal m_previous;
+ qreal maximumChange;
+ } m_zoom;
+
+ QPointF m_lastPoint1;
+ QPointF m_lastPoint2;
+ qreal m_startDist;
+ qreal m_lastAngle;
+ } m_pinch;
+
+ AcceptedGestures m_acceptedGestures;
+
+ struct Pan
+ {
+ qreal m_maxVelocity;
+ qreal m_deceleration;
+ QQuickGeoCoordinateAnimation *m_animation;
+ bool m_enabled;
+ } m_flick;
+
+
+ // these are calculated regardless of gesture or number of touch points
+ qreal m_velocityX;
+ qreal m_velocityY;
+ QElapsedTimer m_lastPosTime;
+ QPointF m_lastPos;
+ QList<QTouchEvent::TouchPoint> m_allPoints;
+ QList<QTouchEvent::TouchPoint> m_touchPoints;
+ QScopedPointer<QTouchEvent::TouchPoint> m_mousePoint;
+ QPointF m_sceneStartPoint1;
+
+ // only set when two points in contact
+ QPointF m_sceneStartPoint2;
+ QGeoCoordinate m_startCoord;
+ QGeoCoordinate m_touchCenterCoord;
+ qreal m_twoTouchAngle;
+ qreal m_distanceBetweenTouchPoints;
+ QPointF m_sceneCenter;
+ bool m_preventStealing;
+ bool m_panEnabled;
+
+ // prototype state machine...
+ enum TouchPointState
+ {
+ touchPoints0,
+ touchPoints1,
+ touchPoints2
+ } m_touchPointState;
+
+ enum PinchState
+ {
+ pinchInactive,
+ pinchInactiveTwoPoints,
+ pinchActive
+ } m_pinchState;
+
+ enum FlickState
+ {
+ flickInactive,
+ panActive,
+ flickActive
+ } m_flickState;
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QQuickGeoMapGestureArea)
+
+#endif // QQUICKGEOMAPGESTUREAREA_P_H