summaryrefslogtreecommitdiffstats
path: root/src/location/declarativemaps
diff options
context:
space:
mode:
Diffstat (limited to 'src/location/declarativemaps')
-rw-r--r--src/location/declarativemaps/declarativemaps.pri65
-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.h77
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem.cpp689
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem_p.h136
-rw-r--r--src/location/declarativemaps/qdeclarativegeocodemodel.cpp725
-rw-r--r--src/location/declarativemaps/qdeclarativegeocodemodel_p.h207
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaneuver.cpp199
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaneuver_p.h111
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap.cpp2152
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap_p.h292
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp316
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h116
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase.cpp284
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase_p.h132
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp148
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h69
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview.cpp539
-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.cpp422
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem_p.h135
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaptype.cpp134
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaptype_p.h105
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute.cpp275
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute_p.h106
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel.cpp1306
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel_p.h344
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment.cpp162
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment_p.h86
-rw-r--r--src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp819
-rw-r--r--src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h284
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem.cpp741
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem_p.h164
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem.cpp991
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem_p.h200
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem.cpp397
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem_p.h126
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem.cpp148
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem_p.h92
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry.cpp140
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry_p.h150
-rw-r--r--src/location/declarativemaps/qquickgeomapgesturearea.cpp1819
-rw-r--r--src/location/declarativemaps/qquickgeomapgesturearea_p.h397
50 files changed, 16592 insertions, 0 deletions
diff --git a/src/location/declarativemaps/declarativemaps.pri b/src/location/declarativemaps/declarativemaps.pri
new file mode 100644
index 00000000..1da5c7b8
--- /dev/null
+++ b/src/location/declarativemaps/declarativemaps.pri
@@ -0,0 +1,65 @@
+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/qdeclarativegeomapitemgroup_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 \
+ declarativemaps/qdeclarativegeomapitemgroup.cpp \
+ ../imports/positioning/qquickgeocoordinateanimation.cpp \
+ declarativemaps/mapitemviewdelegateincubator.cpp
+
+load(qt_build_paths)
+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..f03ae405
--- /dev/null
+++ b/src/location/declarativemaps/mapitemviewdelegateincubator_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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
+
+//
+// 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 <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..274225c0
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
@@ -0,0 +1,689 @@
+/***************************************************************************
+**
+** 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 "qwebmercator_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <qmath.h>
+#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
+*/
+
+static const int CircleSamples = 128;
+
+struct Vertex
+{
+ QVector2D position;
+};
+
+QGeoMapCircleGeometry::QGeoMapCircleGeometry()
+{
+}
+
+/*!
+ \internal
+*/
+void QGeoMapCircleGeometry::updateScreenPointsInvert(const QList<QDoubleVector2D> &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 QDoubleVector2D &c: circlePath)
+ hole << map.geoProjection().wrapMapProjection(c);
+
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(fill), true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(hole));
+ Paths difference = clipper.execute(c2t::clip2tri::Difference, QtClipperLib::pftEvenOdd, QtClipperLib::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, QtClipperLib::pftEvenOdd, QtClipperLib::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());
+
+ 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]);
+
+ 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), border_(this), 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)
+ return;
+ updateCirclePath();
+ 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);
+ updateCirclePath();
+ 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);
+ updateCirclePath();
+ 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;
+
+ QList<QDoubleVector2D> circlePath = 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<QDoubleVector2D> closedPath = circlePath;
+ closedPath << closedPath.first();
+
+ if (invertedCircle) {
+ closedPath = circlePath_;
+ 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
+*/
+void QDeclarativeCircleMapItem::updateCirclePath()
+{
+ if (!map())
+ return;
+ QList<QGeoCoordinate> path;
+ calculatePeripheralPoints(path, circle_.center(), circle_.radius(), CircleSamples);
+ circlePath_.clear();
+ for (const QGeoCoordinate &c : path)
+ circlePath_ << map()->geoProjection().geoToMapProjection(c);
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeCircleMapItem::contains(const QPointF &point) const
+{
+ return (geometry_.contains(point) || borderGeometry_.contains(point));
+}
+
+const QGeoShape &QDeclarativeCircleMapItem::geoShape() const
+{
+ return circle_;
+}
+
+QGeoMap::ItemType QDeclarativeCircleMapItem::itemType() const
+{
+ return QGeoMap::MapCircle;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCircleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (!map() || !circle_.isValid() || 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<QDoubleVector2D> &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<QDoubleVector2D> &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(path.at(0));
+
+ for (int i = 1; i <= path.count(); ++i) {
+ int index = i % path.count();
+ QDoubleVector2D point = map()->geoProjection().wrapMapProjection(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(path.at(index));
+ if ( (qAbs(point.x() - prev.x())) >= 0.5 ) {
+ 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 = 0; // 90 latitude
+ QDoubleVector2D wrapCoord = path.at(wrapPathIndex[0]);
+ if (wrapPathIndex.size() == 2) {
+ QDoubleVector2D wrapCoord2 = path.at(wrapPathIndex[1]);
+ if (wrapCoord2.y() < wrapCoord.y())
+ newPoleLat = 1; // -90 latitude
+ } else if (center.latitude() < 0) {
+ newPoleLat = 1; // -90 latitude
+ }
+ 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;
+ QDoubleVector2D coord0 = path.at(prevIndex);
+ QDoubleVector2D coord1 = path.at(index);
+ coord0.setY(newPoleLat);
+ coord1.setY(newPoleLat);
+ path.insert(index ,coord1);
+ path.insert(index, coord0);
+ newPoleLat = 1.0 - 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..511e3b17
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
@@ -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$
+**
+****************************************************************************/
+
+#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<QDoubleVector2D> &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;
+ QGeoMap::ItemType itemType() 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:
+ void updateCirclePath();
+ bool preserveCircleGeometry(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
+ qreal distance);
+ void updateCirclePathForRendering(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
+ qreal distance);
+
+private:
+ QGeoCircle circle_;
+ QDeclarativeMapLineProperties border_;
+ QColor color_;
+ QList<QDoubleVector2D> 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..f7422ec2
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp
@@ -0,0 +1,725 @@
+/****************************************************************************
+**
+** 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();
+}
+
+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..b1c67167
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaneuver.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** 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();
+}
+
+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..1638d1c8
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomap.cpp
@@ -0,0 +1,2152 @@
+/****************************************************************************
+**
+** 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 14.
+
+ \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.
+*/
+
+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),
+ m_userMinimumZoomLevel(qQNaN()),
+ m_userMaximumZoomLevel(qQNaN()),
+ m_userMinimumTilt(qQNaN()),
+ m_userMaximumTilt(qQNaN()),
+ m_userMinimumFieldOfView(qQNaN()),
+ m_userMaximumFieldOfView(qQNaN())
+{
+ 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);
+
+ m_cameraCapabilities.setTileSize(256);
+ m_cameraCapabilities.setSupportsBearing(true);
+ m_cameraCapabilities.setSupportsTilting(true);
+ m_cameraCapabilities.setMinimumZoomLevel(0);
+ m_cameraCapabilities.setMaximumZoomLevel(30);
+ m_cameraCapabilities.setMinimumTilt(0);
+ m_cameraCapabilities.setMaximumTilt(89.5);
+ m_cameraCapabilities.setMinimumFieldOfView(1);
+ m_cameraCapabilities.setMaximumFieldOfView(179);
+
+ m_minimumTilt = m_cameraCapabilities.minimumTilt();
+ m_maximumTilt = m_cameraCapabilities.maximumTilt();
+ m_minimumFieldOfView = m_cameraCapabilities.minimumFieldOfView();
+ m_maximumFieldOfView = m_cameraCapabilities.maximumFieldOfView();
+}
+
+QDeclarativeGeoMap::~QDeclarativeGeoMap()
+{
+ // Removing map parameters and map items from m_map
+ if (m_map) {
+ m_map->clearParameters();
+ m_map->clearMapItems();
+ }
+
+ 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();
+
+ for (auto g: qAsConst(m_mapItemGroups)) {
+ if (!g)
+ continue;
+ const QList<QQuickItem *> quickKids = g->childItems();
+ for (auto c: quickKids) {
+ QDeclarativeGeoMapItemBase *itemBase = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
+ if (itemBase)
+ itemBase->setMap(0,0);
+ }
+ }
+ m_mapItemGroups.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);
+ m_copyrights->onCopyrightsStyleSheetChanged(m_map->copyrightsStyleSheet());
+
+ copyrights = m_copyrights.data();
+
+ connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)),
+ copyrights, SLOT(copyrightsChanged(QImage)));
+ connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)),
+ this, SIGNAL(copyrightsChanged(QImage)));
+
+ connect(m_map.data(), SIGNAL(copyrightsChanged(QString)),
+ copyrights, SLOT(copyrightsChanged(QString)));
+ connect(m_map.data(), SIGNAL(copyrightsChanged(QString)),
+ this, SIGNAL(copyrightsChanged(QString)));
+
+ connect(m_map.data(), SIGNAL(copyrightsStyleSheetChanged(QString)),
+ copyrights, SLOT(onCopyrightsStyleSheetChanged(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();
+}
+
+/*!
+ \internal
+ Called when the mapping manager is initialized AND the declarative element has a valid size > 0
+*/
+void QDeclarativeGeoMap::initialize()
+{
+ // try to keep change signals in the end
+ bool centerHasChanged = false;
+ bool bearingHasChanged = false;
+ bool tiltHasChanged = false;
+ bool fovHasChanged = false;
+
+ QGeoCoordinate center = m_cameraData.center();
+
+ if (qIsNaN(m_userMinimumZoomLevel))
+ setMinimumZoomLevel(m_map->minimumZoom(), false);
+ else
+ setMinimumZoomLevel(qMax<qreal>(m_map->minimumZoom(), m_userMinimumZoomLevel), false);
+
+ double bearing = m_cameraData.bearing();
+ double tilt = m_cameraData.tilt();
+ double fov = m_cameraData.fieldOfView(); // Must be 45.0
+
+ if (!m_cameraCapabilities.supportsBearing() && bearing != 0.0) {
+ m_cameraData.setBearing(0);
+ bearingHasChanged = true;
+ }
+ if (!m_cameraCapabilities.supportsTilting() && tilt != 0.0) {
+ m_cameraData.setTilt(0);
+ tiltHasChanged = true;
+ }
+
+ m_cameraData.setFieldOfView(qBound(m_cameraCapabilities.minimumFieldOfView(),
+ fov,
+ m_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());
+
+ emit mapReadyChanged(true);
+
+ if (m_copyrights)
+ update();
+}
+
+/*!
+ \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
+
+ This may happen before mappingManagerInitialized()
+*/
+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);
+ continue;
+ }
+ // Allow to add to the map Map items contained inside a parent QQuickItem, but only those at one level of nesting.
+ QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast<QDeclarativeGeoMapItemGroup *>(kids.at(i));
+ if (itemGroup) {
+ addMapItemGroup(itemGroup);
+ continue;
+ }
+ }
+}
+
+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
+*/
+void QDeclarativeGeoMap::onCameraCapabilitiesChanged(const QGeoCameraCapabilities &oldCameraCapabilities)
+{
+ if (m_map->cameraCapabilities() == oldCameraCapabilities)
+ return;
+ m_cameraCapabilities = m_map->cameraCapabilities();
+
+ //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_cameraCapabilities.maximumZoomLevelAt256() < m_gestureArea->maximumZoomLevel()) {
+ setMaximumZoomLevel(m_cameraCapabilities.maximumZoomLevelAt256(), false);
+ } else if (m_cameraCapabilities.maximumZoomLevelAt256() > m_gestureArea->maximumZoomLevel()) {
+ if (qIsNaN(m_userMaximumZoomLevel)) {
+ // If the user didn't set anything
+ setMaximumZoomLevel(m_cameraCapabilities.maximumZoomLevelAt256(), false);
+ } else { // Try to set what the user requested
+ // Else if the user set something larger, but that got clamped by the previous camera caps
+ setMaximumZoomLevel(qMin<qreal>(m_cameraCapabilities.maximumZoomLevelAt256(),
+ m_userMaximumZoomLevel), false);
+ }
+ }
+
+ if (m_cameraCapabilities.minimumZoomLevelAt256() > m_gestureArea->minimumZoomLevel()) {
+ setMinimumZoomLevel(m_cameraCapabilities.minimumZoomLevelAt256(), false);
+ } else if (m_cameraCapabilities.minimumZoomLevelAt256() < m_gestureArea->minimumZoomLevel()) {
+ if (qIsNaN(m_userMinimumZoomLevel)) {
+ // If the user didn't set anything, trying to set the new caps.
+ setMinimumZoomLevel(m_cameraCapabilities.minimumZoomLevelAt256(), false);
+ } else { // Try to set what the user requested
+ // Else if the user set a minimum, m_gestureArea->minimumZoomLevel() might be larger
+ // because of different reasons. Resetting it, as if it ends to be the same,
+ // no signal will be emitted.
+ setMinimumZoomLevel(qMax<qreal>(m_cameraCapabilities.minimumZoomLevelAt256(),
+ m_userMinimumZoomLevel), false);
+ }
+ }
+
+ // Tilt
+ if (m_cameraCapabilities.maximumTilt() < m_maximumTilt) {
+ setMaximumTilt(m_cameraCapabilities.maximumTilt(), false);
+ } else if (m_cameraCapabilities.maximumTilt() > m_maximumTilt) {
+ if (qIsNaN(m_userMaximumTilt))
+ setMaximumTilt(m_cameraCapabilities.maximumTilt(), false);
+ else // Try to set what the user requested
+ setMaximumTilt(qMin<qreal>(m_cameraCapabilities.maximumTilt(), m_userMaximumTilt), false);
+ }
+
+ if (m_cameraCapabilities.minimumTilt() > m_minimumTilt) {
+ setMinimumTilt(m_cameraCapabilities.minimumTilt(), false);
+ } else if (m_cameraCapabilities.minimumTilt() < m_minimumTilt) {
+ if (qIsNaN(m_userMinimumTilt))
+ setMinimumTilt(m_cameraCapabilities.minimumTilt(), false);
+ else // Try to set what the user requested
+ setMinimumTilt(qMax<qreal>(m_cameraCapabilities.minimumTilt(), m_userMinimumTilt), false);
+ }
+
+ // FoV
+ if (m_cameraCapabilities.maximumFieldOfView() < m_maximumFieldOfView) {
+ setMaximumFieldOfView(m_cameraCapabilities.maximumFieldOfView(), false);
+ } else if (m_cameraCapabilities.maximumFieldOfView() > m_maximumFieldOfView) {
+ if (qIsNaN(m_userMaximumFieldOfView))
+ setMaximumFieldOfView(m_cameraCapabilities.maximumFieldOfView(), false);
+ else // Try to set what the user requested
+ setMaximumFieldOfView(qMin<qreal>(m_cameraCapabilities.maximumFieldOfView(), m_userMaximumFieldOfView), false);
+ }
+
+ if (m_cameraCapabilities.minimumFieldOfView() > m_minimumFieldOfView) {
+ setMinimumFieldOfView(m_cameraCapabilities.minimumFieldOfView(), false);
+ } else if (m_cameraCapabilities.minimumFieldOfView() < m_minimumFieldOfView) {
+ if (qIsNaN(m_userMinimumFieldOfView))
+ setMinimumFieldOfView(m_cameraCapabilities.minimumFieldOfView(), false);
+ else // Try to set what the user requested
+ setMinimumFieldOfView(qMax<qreal>(m_cameraCapabilities.minimumFieldOfView(), m_userMinimumFieldOfView), false);
+ }
+}
+
+
+/*!
+ \internal
+ this function will only be ever called once
+*/
+void QDeclarativeGeoMap::mappingManagerInitialized()
+{
+ m_map = QPointer<QGeoMap>(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());
+ }
+
+ // Update camera capabilities
+ onCameraCapabilitiesChanged(m_cameraCapabilities);
+
+ // Map tiles are built in this call. m_map->minimumZoom() becomes operational
+ // after this has been called at least once, after creation.
+ // However, getting into the following block may fire a copyrightsChanged that would get lost,
+ // as the connections are set up after.
+ QString copyrightString;
+ QImage copyrightImage;
+ if (!m_initialized && width() > 0 && height() > 0) {
+ QMetaObject::Connection copyrightStringCatcherConnection =
+ connect(m_map.data(),
+ QOverload<const QString &>::of(&QGeoMap::copyrightsChanged),
+ [&copyrightString](const QString &copy){ copyrightString = copy; });
+ QMetaObject::Connection copyrightImageCatcherConnection =
+ connect(m_map.data(),
+ QOverload<const QImage &>::of(&QGeoMap::copyrightsChanged),
+ [&copyrightImage](const QImage &copy){ copyrightImage = copy; });
+ m_map->setViewportSize(QSize(width(), height()));
+ initialize();
+ QObject::disconnect(copyrightStringCatcherConnection);
+ QObject::disconnect(copyrightImageCatcherConnection);
+ }
+
+ m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this);
+ m_copyrights->onCopyrightsStyleSheetChanged(m_map->copyrightsStyleSheet());
+
+ connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)),
+ m_copyrights.data(), SLOT(copyrightsChanged(QImage)));
+ connect(m_map.data(), SIGNAL(copyrightsChanged(QImage)),
+ this, SIGNAL(copyrightsChanged(QImage)));
+
+ connect(m_map.data(), SIGNAL(copyrightsChanged(QString)),
+ m_copyrights.data(), SLOT(copyrightsChanged(QString)));
+ connect(m_map.data(), SIGNAL(copyrightsChanged(QString)),
+ this, SIGNAL(copyrightsChanged(QString)));
+
+ if (!copyrightString.isEmpty())
+ emit m_map.data()->copyrightsChanged(copyrightString);
+ else if (!copyrightImage.isNull())
+ emit m_map.data()->copyrightsChanged(copyrightImage);
+
+ connect(m_map.data(), SIGNAL(copyrightsStyleSheetChanged(QString)),
+ m_copyrights.data(), SLOT(onCopyrightsStyleSheetChanged(QString)));
+
+ connect(m_copyrights.data(), SIGNAL(linkActivated(QString)),
+ this, SIGNAL(copyrightLinkActivated(QString)));
+ connect(m_map.data(), &QGeoMap::sgNodeChanged, this, &QQuickItem::update);
+ connect(m_map.data(), &QGeoMap::cameraCapabilitiesChanged, this, &QDeclarativeGeoMap::onCameraCapabilitiesChanged);
+
+ // 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
+ for (const QPointer<QDeclarativeGeoMapItemBase> &item : qAsConst(m_mapItems)) {
+ if (item) {
+ item->setMap(this, m_map);
+ m_map->addMapItem(item.data()); // m_map filters out what is not supported.
+ }
+ }
+
+ // Any map item groups that were added before the plugin was ready
+ // need to have setMap called again on their children map items
+ for (auto g: qAsConst(m_mapItemGroups)) {
+ const QList<QQuickItem *> quickKids = g->childItems();
+ for (auto c: quickKids) {
+ QDeclarativeGeoMapItemBase *itemBase = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
+ if (itemBase)
+ itemBase->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 : qAsConst(m_mapParameters))
+ m_map->addParameter(p);
+
+ if (m_initialized)
+ update();
+}
+
+/*!
+ \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, bool userSet)
+{
+
+ if (minimumZoomLevel >= 0) {
+ if (userSet)
+ m_userMinimumZoomLevel = minimumZoomLevel;
+ qreal oldMinimumZoomLevel = this->minimumZoomLevel();
+
+ minimumZoomLevel = qBound(qreal(m_cameraCapabilities.minimumZoomLevelAt256()), minimumZoomLevel, maximumZoomLevel());
+ if (m_map)
+ minimumZoomLevel = qMax<qreal>(minimumZoomLevel, m_map->minimumZoom());
+
+ m_gestureArea->setMinimumZoomLevel(minimumZoomLevel);
+
+ if (zoomLevel() < minimumZoomLevel && (m_gestureArea->enabled() || !m_cameraCapabilities.overzoomEnabled()))
+ 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 the \l plugin property is not set or the plugin does not support mapping, this property is \c 0.
+*/
+
+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, bool userSet)
+{
+ if (maximumZoomLevel >= 0) {
+ if (userSet)
+ m_userMaximumZoomLevel = maximumZoomLevel;
+ qreal oldMaximumZoomLevel = this->maximumZoomLevel();
+
+ maximumZoomLevel = qBound(minimumZoomLevel(), maximumZoomLevel, qreal(m_cameraCapabilities.maximumZoomLevelAt256()));
+
+ m_gestureArea->setMaximumZoomLevel(maximumZoomLevel);
+
+ if (zoomLevel() > maximumZoomLevel && (m_gestureArea->enabled() || !m_cameraCapabilities.overzoomEnabled()))
+ 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 the \l plugin property is not set or the plugin does not support mapping, this property is \c 30.
+*/
+
+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. Depending on the plugin in use,
+ values outside the [minimumZoomLevel, maximumZoomLevel] range, which represent the range for which
+ tiles are available, may be accepted, or clamped.
+*/
+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<qreal>(m_cameraCapabilities.overzoomEnabled() ? 0 : minimumZoomLevel(), zoomLevel,
+ m_cameraCapabilities.overzoomEnabled() ? 30 : 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 (bearing < 0.0)
+ bearing += 360.0;
+ if (m_map && !m_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, in degrees.
+ The default value is 0.
+ The valid range for this value is [ minimumTilt, maximumTilt ].
+ If the Plugin used for the Map does not support tilting, changing this property will have no effect.
+
+ \sa minimumTilt, maximumTilt
+
+ \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();
+}
+
+void QDeclarativeGeoMap::setMinimumTilt(qreal minimumTilt, bool userSet)
+{
+ if (minimumTilt >= 0) {
+ if (userSet)
+ m_userMinimumTilt = minimumTilt;
+ qreal oldMinimumTilt = this->minimumTilt();
+
+ m_minimumTilt = qBound(m_cameraCapabilities.minimumTilt(),
+ minimumTilt,
+ m_cameraCapabilities.maximumTilt());
+
+ if (tilt() < m_minimumTilt)
+ setTilt(m_minimumTilt);
+
+ if (oldMinimumTilt != m_minimumTilt)
+ emit minimumTiltChanged(m_minimumTilt);
+ }
+}
+
+/*!
+ \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}.
+
+ \sa minimumFieldOfView, maximumFieldOfView
+
+ \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();
+}
+
+void QDeclarativeGeoMap::setMinimumFieldOfView(qreal minimumFieldOfView, bool userSet)
+{
+ if (minimumFieldOfView > 0 && minimumFieldOfView < 180.0) {
+ if (userSet)
+ m_userMinimumFieldOfView = minimumFieldOfView;
+ qreal oldMinimumFoV = this->minimumFieldOfView();
+
+ m_minimumFieldOfView = qBound(m_cameraCapabilities.minimumFieldOfView(),
+ minimumFieldOfView,
+ m_cameraCapabilities.maximumFieldOfView());
+
+ if (fieldOfView() < m_minimumFieldOfView)
+ setFieldOfView(m_minimumFieldOfView);
+
+ if (oldMinimumFoV != m_minimumFieldOfView)
+ emit minimumFieldOfViewChanged(m_minimumFieldOfView);
+ }
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::minimumFieldOfView
+
+ This property holds the minimum valid field of view for the map, in degrees.
+
+ The minimum tilt field of view by the \l plugin used is a lower bound for
+ this property.
+ If the \l plugin property is not set or the plugin does not support mapping, this property is \c 1.
+
+ \sa fieldOfView, maximumFieldOfView
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::minimumFieldOfView() const
+{
+ return m_minimumFieldOfView;
+}
+
+void QDeclarativeGeoMap::setMaximumFieldOfView(qreal maximumFieldOfView, bool userSet)
+{
+ if (maximumFieldOfView > 0 && maximumFieldOfView < 180.0) {
+ if (userSet)
+ m_userMaximumFieldOfView = maximumFieldOfView;
+ qreal oldMaximumFoV = this->maximumFieldOfView();
+
+ m_maximumFieldOfView = qBound(m_cameraCapabilities.minimumFieldOfView(),
+ maximumFieldOfView,
+ m_cameraCapabilities.maximumFieldOfView());
+
+ if (fieldOfView() > m_maximumFieldOfView)
+ setFieldOfView(m_maximumFieldOfView);
+
+ if (oldMaximumFoV != m_maximumFieldOfView)
+ emit maximumFieldOfViewChanged(m_maximumFieldOfView);
+ }
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::maximumFieldOfView
+
+ This property holds the maximum valid field of view for the map, in degrees.
+
+ The minimum tilt field of view by the \l plugin used is an upper bound for
+ this property.
+ If the \l plugin property is not set or the plugin does not support mapping, this property is \c 179.
+
+ \sa fieldOfView, minimumFieldOfView
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::maximumFieldOfView() const
+{
+ return m_maximumFieldOfView;
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::minimumTilt
+
+ This property holds the minimum valid tilt for the map, in degrees.
+
+ The minimum tilt defined by the \l plugin used is a lower bound for
+ this property.
+ If the \l plugin property is not set or the plugin does not support mapping, this property is \c 0.
+
+ \sa tilt, maximumTilt
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::minimumTilt() const
+{
+ return m_minimumTilt;
+}
+
+void QDeclarativeGeoMap::setMaximumTilt(qreal maximumTilt, bool userSet)
+{
+ if (maximumTilt >= 0) {
+ if (userSet)
+ m_userMaximumTilt = maximumTilt;
+ qreal oldMaximumTilt = this->maximumTilt();
+
+ m_maximumTilt = qBound(m_cameraCapabilities.minimumTilt(),
+ maximumTilt,
+ m_cameraCapabilities.maximumTilt());
+
+ if (tilt() > m_maximumTilt)
+ setTilt(m_maximumTilt);
+
+ if (oldMaximumTilt != m_maximumTilt)
+ emit maximumTiltChanged(m_maximumTilt);
+ }
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::maximumTilt
+
+ This property holds the maximum valid tilt for the map, in degrees.
+
+ The maximum tilt defined by the \l plugin used is an upper bound for
+ this property.
+ If the \l plugin property is not set or the plugin does not support mapping, this property is \c 89.5.
+
+ \sa tilt, minimumTilt
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::maximumTilt() const
+{
+ return m_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;
+}
+
+/*!
+ \qmlproperty color QtLocation::Map::mapReady
+
+ This property holds whether the map has been successfully initialized and is ready to be used.
+ Some methods, such as \l fromCoordinate and \l toCoordinate, will not work before the map is ready.
+ Due to the architecture of the \l Map, it's advised to use the signal emitted for this property
+ in place of \l {QtQml::Component::completed()}{Component.onCompleted}, to make sure that everything behaves as expected.
+
+ \since 5.9
+*/
+bool QDeclarativeGeoMap::mapReady() const
+{
+ return m_initialized;
+}
+
+// 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;
+ // If the item comes from a MapItemGroup, do not reparent it.
+ if (!qobject_cast<QDeclarativeGeoMapItemGroup *>(item->parentItem()))
+ item->setParentItem(this);
+ m_mapItems.append(item);
+ if (m_map) {
+ item->setMap(this, m_map);
+ m_map->addMapItem(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.append(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.removeOne(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 : qAsConst(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;
+ m_map->removeMapItem(ptr);
+ QPointer<QDeclarativeGeoMapItemBase> item(ptr);
+ if (!m_mapItems.contains(item))
+ return;
+ if (item->parentItem() == this)
+ item->setParentItem(0);
+ item->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 and item groups from the map.
+
+ \sa mapItems, addMapItem, removeMapItem, addMapItemGroup, removeMapItemGroup
+*/
+void QDeclarativeGeoMap::clearMapItems()
+{
+ m_map->clearMapItems();
+ if (m_mapItems.isEmpty())
+ return;
+ for (auto i : qAsConst(m_mapItems)) {
+ if (i) {
+ i->setMap(0, 0);
+ if (i->parentItem() == this)
+ i->setParentItem(0);
+ }
+ }
+ m_mapItems.clear();
+ m_mapItemGroups.clear();
+ emit mapItemsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::addMapItemGroup(MapItemGroup itemGroup)
+
+ Adds the map items contained in the given \a itemGroup to the Map
+ (for example MapQuickItem, MapCircle). These items will be reparented, and the map
+ will be their new parent. Property bindings defined using \e{parent.} inside a MapItemGroup
+ will therefore not work.
+
+ \sa MapItemGroup, removeMapItemGroup
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup)
+{
+ if (!itemGroup)
+ return;
+
+ QPointer<QDeclarativeGeoMapItemGroup> g(itemGroup);
+ if (m_mapItemGroups.contains(g))
+ return;
+
+ m_mapItemGroups.append(g);
+ const QList<QQuickItem *> quickKids = g->childItems();
+ for (auto c: quickKids) {
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
+ if (mapItem)
+ addMapItem(mapItem);
+ }
+ itemGroup->setParentItem(this);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::removeMapItemGroup(MapItemGroup itemGroup)
+
+ Removes \a itemGroup and the items contained therein from the Map.
+
+ \sa MapItemGroup, addMapItemGroup
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup)
+{
+ if (!itemGroup)
+ return;
+
+ QPointer<QDeclarativeGeoMapItemGroup> g(itemGroup);
+ if (!m_mapItemGroups.removeOne(g))
+ return;
+
+ const QList<QQuickItem *> quickKids = itemGroup->childItems();
+ for (auto c: quickKids) {
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
+ if (mapItem)
+ removeMapItem(mapItem);
+ }
+ itemGroup->setParentItem(0);
+}
+
+/*!
+ \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(), false);
+
+ // 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.
+
+ \sa fitViewportToVisibleMapItems
+*/
+void QDeclarativeGeoMap::fitViewportToMapItems()
+{
+ fitViewportToMapItemsRefine(true, false);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::fitViewportToVisibleMapItems()
+
+ Fits the current viewport to the boundary of all \b visible 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.
+
+ \sa fitViewportToMapItems
+*/
+void QDeclarativeGeoMap::fitViewportToVisibleMapItems()
+{
+ fitViewportToMapItemsRefine(true, true);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine, bool onlyVisible)
+{
+ 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 || (onlyVisible && (!item->isVisible() || item->mapItemOpacity() <= 0.0)))
+ 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.
+ // TODO: See if we really need updatePolish on delegated items, in particular
+ // in relation to
+ // a) fitViewportToMapItems
+ // b) presence of MouseArea
+ 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, onlyVisible);
+ 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, onlyVisible);
+}
+
+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() && !grabber->keepTouchGrab()))) {
+ 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->keepTouchGrab() && 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;
+}
+
+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..f08998e2
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomap_p.h
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** 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/private/qdeclarativegeomapitemgroup_p.h>
+#include <QtLocation/qgeoserviceprovider.h>
+#include <QtLocation/private/qgeocameradata_p.h>
+#include <QtLocation/private/qgeocameracapabilities_p.h>
+#include <QtQuick/QQuickItem>
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+#include <QtGui/QColor>
+#include <QtPositioning/qgeoshape.h>
+#include <QtLocation/private/qgeomap_p.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(qreal tilt READ tilt WRITE setTilt NOTIFY tiltChanged)
+ Q_PROPERTY(qreal minimumTilt READ minimumTilt WRITE setMinimumTilt NOTIFY minimumTiltChanged)
+ Q_PROPERTY(qreal maximumTilt READ maximumTilt WRITE setMaximumTilt NOTIFY maximumTiltChanged)
+
+ Q_PROPERTY(qreal bearing READ bearing WRITE setBearing NOTIFY bearingChanged)
+
+ Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged)
+ Q_PROPERTY(qreal minimumFieldOfView READ minimumFieldOfView WRITE setMinimumFieldOfView NOTIFY minimumFieldOfViewChanged)
+ Q_PROPERTY(qreal maximumFieldOfView READ maximumFieldOfView WRITE setMaximumFieldOfView 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_PROPERTY(bool mapReady READ mapReady NOTIFY mapReadyChanged)
+ 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, bool userSet = true);
+ qreal minimumZoomLevel() const;
+
+ void setMaximumZoomLevel(qreal maximumZoomLevel, bool userSet = true);
+ 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 setMinimumTilt(qreal minimumTilt, bool userSet = true);
+ qreal minimumTilt() const;
+ void setMaximumTilt(qreal maximumTilt, bool userSet = true);
+ qreal maximumTilt() const;
+
+ void setFieldOfView(qreal fieldOfView);
+ qreal fieldOfView() const;
+ void setMinimumFieldOfView(qreal minimumFieldOfView, bool userSet = true);
+ qreal minimumFieldOfView() const;
+ void setMaximumFieldOfView(qreal maximumFieldOfView, bool userSet = true);
+ qreal maximumFieldOfView() 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;
+
+ bool mapReady() const;
+
+ QQmlListProperty<QDeclarativeGeoMapType> supportedMapTypes();
+
+ Q_INVOKABLE void removeMapItem(QDeclarativeGeoMapItemBase *item);
+ Q_INVOKABLE void addMapItem(QDeclarativeGeoMapItemBase *item);
+
+ Q_INVOKABLE void addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup);
+ Q_INVOKABLE void removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup);
+
+ 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 fitViewportToVisibleMapItems();
+ 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 minimumTiltChanged(qreal minimumTilt);
+ void maximumTiltChanged(qreal maximumTilt);
+ void minimumFieldOfViewChanged(qreal minimumFieldOfView);
+ void maximumFieldOfViewChanged(qreal maximumFieldOfView);
+ void copyrightsChanged(const QImage &copyrightsImage);
+ void copyrightsChanged(const QString &copyrightsHtml);
+ void mapReadyChanged(bool ready);
+
+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();
+ void onCameraCapabilitiesChanged(const QGeoCameraCapabilities &oldCameraCapabilities);
+
+private:
+ void setupMapView(QDeclarativeGeoMapItemView *view);
+ void populateMap();
+ void populateParameters();
+ void fitViewportToMapItemsRefine(bool refine, bool onlyVisible);
+ 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;
+ QPointer<QGeoMap> m_map;
+ QPointer<QDeclarativeGeoMapCopyrightNotice> m_copyrights;
+ QList<QPointer<QDeclarativeGeoMapItemBase> > m_mapItems;
+ QList<QPointer<QDeclarativeGeoMapItemGroup> > m_mapItemGroups;
+ 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;
+ QList<QDeclarativeGeoMapParameter *> m_mapParameters;
+ QGeoCameraCapabilities m_cameraCapabilities;
+ qreal m_userMinimumZoomLevel;
+ qreal m_userMaximumZoomLevel;
+
+ qreal m_minimumTilt;
+ qreal m_maximumTilt;
+ qreal m_userMinimumTilt;
+ qreal m_userMaximumTilt;
+
+ qreal m_minimumFieldOfView;
+ qreal m_maximumFieldOfView;
+ qreal m_userMinimumFieldOfView;
+ qreal m_userMaximumFieldOfView;
+
+ friend class QDeclarativeGeoMapItem;
+ friend class QDeclarativeGeoMapItemView;
+ friend class QQuickGeoMapGestureArea;
+ friend class QDeclarativeGeoMapCopyrightNotice;
+ 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..fdfb645a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** 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>
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapCopyrightNotice
+ \instantiates QDeclarativeGeoMapCopyrightNotice
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.9
+
+ \brief The MapCopyrightNotice item displays the current valid
+ copyright notice for a Map element.
+
+ This object can be used to place an additional copyright notices
+ programmatically.
+
+ Note that declaring a MapCopyrightNotice inside a QtLocation::Map element
+ is not possible, like for any other QQuickItem.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+*/
+
+/*!
+ \qmlproperty Map QtLocation::MapCopyrightNotice::mapSource
+
+ This property holds the current map source providing the copyright data shown
+ in this notice.
+ In order to let the MapCopyrightNotice display a copyright, this property must
+ be set, as it is the only data source for this element.
+*/
+
+/*!
+ \qmlproperty string QtLocation::MapCopyrightNotice::styleSheet
+
+ This property holds the current css2.1 style sheet used to style the copyright notice, if in HTML form.
+
+ Example:
+ \code
+ MapCopyrightNotice {
+ mapSource: myMap
+ styleSheet: "body { color : green; font-family: \"Lucida\"; font-size: 8px} a{ font-size: 8px; color:#A62900}"
+ }
+ \endcode
+*/
+
+QDeclarativeGeoMapCopyrightNotice::QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent)
+: QQuickPaintedItem(parent), m_copyrightsHtml(0), m_copyrightsVisible(true), m_mapSource(0),
+ m_userDefinedStyleSheet(false)
+{
+ // If this item is constructed inside the map, automatically anchor it where it always used to be.
+ if (qobject_cast<QDeclarativeGeoMap *>(parent))
+ anchorToBottomLeft();
+}
+
+QDeclarativeGeoMapCopyrightNotice::~QDeclarativeGeoMapCopyrightNotice()
+{
+}
+
+void QDeclarativeGeoMapCopyrightNotice::anchorToBottomLeft()
+{
+ if (!parent())
+ return;
+ QQuickAnchors *anchors = property("anchors").value<QQuickAnchors *>();
+ if (anchors) {
+ anchors->setLeft(QQuickAnchorLine(qobject_cast<QQuickItem *>(parent()), QQuickAnchors::LeftAnchor));
+ anchors->setBottom(QQuickAnchorLine(qobject_cast<QQuickItem *>(parent()), QQuickAnchors::BottomAnchor));
+ }
+}
+
+void QDeclarativeGeoMapCopyrightNotice::setMapSource(QDeclarativeGeoMap *mapSource)
+{
+ if (m_mapSource == mapSource)
+ return;
+
+ if (m_mapSource) {
+ // disconnect this object from current map source
+ m_mapSource->disconnect(this);
+ m_mapSource->m_map->disconnect(this);
+ m_copyrightsHtml->clear();
+ m_copyrightsImage = QImage();
+ m_mapSource = Q_NULLPTR;
+ }
+
+ if (mapSource) {
+ m_mapSource = mapSource;
+ // First update the copyright. Only Image will do here, no need to store HTML right away.
+ if (!mapSource->m_copyrights->m_copyrightsImage.isNull())
+ m_copyrightsImage = mapSource->m_copyrights->m_copyrightsImage;
+
+ connect(m_mapSource, SIGNAL(copyrightsChanged(QImage)),
+ this, SLOT(copyrightsChanged(QImage)));
+ connect(m_mapSource, SIGNAL(copyrightsChanged(QString)),
+ this, SLOT(copyrightsChanged(QString)));
+ connect(m_mapSource->m_map, SIGNAL(copyrightsStyleSheetChanged(QString)),
+ this, SLOT(onCopyrightsStyleSheetChanged(QString)));
+ connect(this, SIGNAL(linkActivated(QString)),
+ m_mapSource, SIGNAL(copyrightLinkActivated(QString)));
+
+ onCopyrightsStyleSheetChanged(m_mapSource->m_map->copyrightsStyleSheet());
+ }
+
+ update();
+ emit mapSourceChanged();
+}
+
+QDeclarativeGeoMap *QDeclarativeGeoMapCopyrightNotice::mapSource()
+{
+ return m_mapSource;
+}
+
+QString QDeclarativeGeoMapCopyrightNotice::styleSheet() const
+{
+ return m_styleSheet;
+}
+
+void QDeclarativeGeoMapCopyrightNotice::setStyleSheet(const QString &styleSheet)
+{
+ m_userDefinedStyleSheet = true;
+
+ if (styleSheet == m_styleSheet)
+ return;
+
+ m_styleSheet = styleSheet;
+ if (!m_html.isEmpty() && m_copyrightsHtml) {
+ delete m_copyrightsHtml;
+ createCopyright();
+ m_copyrightsHtml->setHtml(m_html);
+ }
+ rasterizeHtmlAndUpdate();
+ emit styleSheetChanged(m_styleSheet);
+}
+
+/*!
+ \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();
+ }
+ }
+}
+
+void QDeclarativeGeoMapCopyrightNotice::rasterizeHtmlAndUpdate()
+{
+ if (!m_copyrightsHtml || m_copyrightsHtml->isEmpty())
+ return;
+
+ m_copyrightsImage = QImage(m_copyrightsHtml->size().toSize(),
+ QImage::Format_ARGB32_Premultiplied);
+
+ m_copyrightsImage.fill(qPremultiply(QColor(Qt::transparent).rgba()));
+ QPainter painter(&m_copyrightsImage);
+ QAbstractTextDocumentLayout::PaintContext ctx;
+ ctx.palette.setColor(QPalette::Text, QStringLiteral("black"));
+ m_copyrightsHtml->documentLayout()->draw(&painter, ctx);
+
+ setImplicitSize(m_copyrightsImage.width(), m_copyrightsImage.height());
+ setContentsSize(m_copyrightsImage.size());
+
+ setKeepMouseGrab(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+
+ update();
+}
+
+void QDeclarativeGeoMapCopyrightNotice::createCopyright()
+{
+ m_copyrightsHtml = new QTextDocument(this);
+ if (!m_styleSheet.isEmpty())
+ m_copyrightsHtml->setDefaultStyleSheet(m_styleSheet);
+
+ // The default 4 makes the copyright too wide and tall.
+ m_copyrightsHtml->setDocumentMargin(0);
+}
+
+/*!
+ \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;
+
+ setImplicitSize(m_copyrightsImage.width(), m_copyrightsImage.height());
+
+ setKeepMouseGrab(false);
+ setAcceptedMouseButtons(Qt::NoButton);
+ setVisible(m_copyrightsVisible);
+
+ update();
+}
+
+void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QString &copyrightsHtml)
+{
+ if (copyrightsHtml.isEmpty()) {
+ setVisible(false);
+ return;
+ } else if (!m_copyrightsVisible) {
+ setVisible(false);
+ } else {
+ setVisible(true);
+ }
+
+ // Divfy, so we can style the background. The extra <span> is a
+ // workaround to QTBUG-58838 and should be removed when it gets fixed.
+ m_html = QStringLiteral("<div id='copyright-root'><span>") + copyrightsHtml + QStringLiteral("</span></div>");
+
+ if (!m_copyrightsHtml)
+ createCopyright();
+
+ m_copyrightsHtml->setHtml(m_html);
+ rasterizeHtmlAndUpdate();
+}
+
+void QDeclarativeGeoMapCopyrightNotice::onCopyrightsStyleSheetChanged(const QString &styleSheet)
+{
+ if (m_userDefinedStyleSheet || styleSheet == m_styleSheet)
+ return;
+
+ m_styleSheet = styleSheet;
+ if (!m_html.isEmpty() && m_copyrightsHtml) {
+ delete m_copyrightsHtml;
+ createCopyright();
+ m_copyrightsHtml->setHtml(m_html);
+ }
+ rasterizeHtmlAndUpdate();
+ emit styleSheetChanged(m_styleSheet);
+}
+
+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..b09d7c1d
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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 QDeclarativeGeoMap;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapCopyrightNotice : public QQuickPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QDeclarativeGeoMap *mapSource READ mapSource WRITE setMapSource NOTIFY mapSourceChanged)
+ Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet NOTIFY styleSheetChanged)
+
+public:
+ QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent = Q_NULLPTR);
+ ~QDeclarativeGeoMapCopyrightNotice();
+
+ void setCopyrightsZ(int copyrightsZ);
+
+ void setCopyrightsVisible(bool visible);
+ void anchorToBottomLeft();
+
+ void setMapSource(QDeclarativeGeoMap *mapSource);
+ QDeclarativeGeoMap *mapSource();
+
+ QString styleSheet() const;
+ void setStyleSheet(const QString &styleSheet);
+
+public Q_SLOTS:
+ void copyrightsChanged(const QImage &copyrightsImage);
+ void copyrightsChanged(const QString &copyrightsHtml);
+ void onCopyrightsStyleSheetChanged(const QString &styleSheet);
+
+signals:
+ void linkActivated(const QString &link);
+ void mapSourceChanged();
+ void backgroundColorChanged(const QColor &color);
+ void styleSheetChanged(const QString &styleSheet);
+
+protected:
+ void paint(QPainter *painter) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+ void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+ void rasterizeHtmlAndUpdate();
+
+private:
+ void createCopyright();
+
+ QTextDocument *m_copyrightsHtml;
+ QString m_html;
+ QImage m_copyrightsImage;
+ QString m_activeAnchor;
+ bool m_copyrightsVisible;
+ QDeclarativeGeoMap *m_mapSource;
+ QColor m_backgroundColor;
+ QString m_styleSheet;
+ bool m_userDefinedStyleSheet;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
new file mode 100644
index 00000000..729825fd
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
@@ -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$
+**
+****************************************************************************/
+
+#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), parentGroup_(0)
+{
+ setFiltersChildMouseEvents(true);
+ connect(this, SIGNAL(childrenChanged()),
+ this, SLOT(afterChildrenChanged()));
+ // Changing opacity on a mapItemGroup should affect also the opacity on the children.
+ // This must be notified to plugins, if they are to render the item.
+ connect(this, &QQuickItem::opacityChanged, this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
+ parentGroup_ = qobject_cast<QDeclarativeGeoMapItemGroup *>(parent);
+ if (parentGroup_)
+ connect(qobject_cast<QDeclarativeGeoMapItemGroup *>(parent), &QQuickItem::opacityChanged,
+ this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
+}
+
+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_ || map_->supportedMapItemTypes() & itemType()) {
+ if (oldNode)
+ delete oldNode;
+ oldNode = 0;
+ 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;
+}
+
+qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const
+{
+ if (parentGroup_)
+ return parentGroup_->opacity() * opacity();
+ return opacity();
+}
+
+bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
+{
+ return QQuickItemPrivate::get(this)->polishScheduled;
+}
+
+void QDeclarativeGeoMapItemBase::polishAndUpdate()
+{
+ polish();
+ update();
+}
+
+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..edb97c10
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** 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>
+#include <QtLocation/private/qgeomap_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 *);
+
+ virtual QGeoMap::ItemType itemType() const = 0;
+ qreal mapItemOpacity() const;
+
+Q_SIGNALS:
+ void mapItemOpacityChanged();
+
+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_;
+
+ QDeclarativeGeoMapItemGroup *parentGroup_;
+
+ friend class QDeclarativeGeoMap;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp b/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp
new file mode 100644
index 00000000..ee382353
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** 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 "qdeclarativegeomapitemgroup_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapItemGroup
+ \instantiates QDeclarativeGeoMapItemGroup
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.9
+
+ \brief The MapItemGroup type is a container for map items.
+
+ Its purpose is to enable code modularization by allowing the usage
+ of qml files containing map elements related to each other, and
+ the associated bindings.
+
+ \note The release of this API with Qt 5.9 is a Technology Preview.
+
+ \section2 Example Usage
+
+ The following snippet shows how to use a MapItemGroup to create a MapCircle, centered at
+ the coordinate (63, -18) with a radius of 100km, filled in red, surrounded by an ondulated green border,
+ both contained in a semitransparent blue circle with a MouseArea that moves the whole group.
+ This group is defined in a separate file named PolygonGroup.qml:
+
+ \code
+ import QtQuick 2.4
+ import QtPositioning 5.6
+ import QtLocation 5.9
+
+ MapItemGroup {
+ id: itemGroup
+ property alias position: mainCircle.center
+ property var radius: 100 * 1000
+ property var borderHeightPct : 0.3
+
+ MapCircle {
+ id: mainCircle
+ center : QtPositioning.coordinate(40, 0)
+ radius: itemGroup.radius * (1.0 + borderHeightPct)
+ opacity: 0.05
+ visible: true
+ color: 'blue'
+
+ MouseArea{
+ anchors.fill: parent
+ drag.target: parent
+ id: maItemGroup
+ }
+ }
+
+ MapCircle {
+ id: groupCircle
+ center: itemGroup.position
+ radius: itemGroup.radius
+ color: 'crimson'
+
+ onCenterChanged: {
+ groupPolyline.populateBorder();
+ }
+ }
+
+ MapPolyline {
+ id: groupPolyline
+ line.color: 'green'
+ line.width: 3
+
+ function populateBorder() {
+ groupPolyline.path = [] // clearing the path
+ var waveLength = 8.0;
+ var waveAmplitude = groupCircle.radius * borderHeightPct;
+ for (var i=0; i <= 360; i++) {
+ var wavePhase = (i/360.0 * 2.0 * Math.PI )* waveLength
+ var waveHeight = (Math.cos(wavePhase) + 1.0) / 2.0
+ groupPolyline.addCoordinate(groupCircle.center.atDistanceAndAzimuth(groupCircle.radius + waveAmplitude * waveHeight , i))
+ }
+ }
+
+ Component.onCompleted: {
+ populateBorder()
+ }
+ }
+ }
+ \endcode
+
+ PolygonGroup.qml is now a reusable component that can then be used in a Map as:
+
+ \code
+ Map {
+ id: map
+ PolygonGroup {
+ id: polygonGroup
+ position: QtPositioning.coordinate(63,-18)
+ }
+ }
+ \endcode
+
+ \image api-mapitemgroup.png
+*/
+
+QDeclarativeGeoMapItemGroup::QDeclarativeGeoMapItemGroup(QQuickItem *parent): QQuickItem(parent)
+{
+
+}
+
+QDeclarativeGeoMapItemGroup::~QDeclarativeGeoMapItemGroup()
+{
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h b/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h
new file mode 100644
index 00000000..1b008d71
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVEGEOMAPITEMGROUP_P_H
+#define QDECLARATIVEGEOMAPITEMGROUP_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>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemGroup : public QQuickItem
+{
+ Q_OBJECT
+public:
+ explicit QDeclarativeGeoMapItemGroup(QQuickItem *parent = 0);
+ virtual ~QDeclarativeGeoMapItemGroup();
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapItemGroup)
+
+#endif // QDECLARATIVEGEOMAPITEMGROUP_P_H
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp
new file mode 100644
index 00000000..a17bf672
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp
@@ -0,0 +1,539 @@
+/****************************************************************************
+**
+** 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;
+}
+
+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..8c83e37d
--- /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 class 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..a0e05436
--- /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 string 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..0976bd06
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp
@@ -0,0 +1,422 @@
+/****************************************************************************
+**
+** 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
+*/
+
+QMapQuickItemMatrix4x4::QMapQuickItemMatrix4x4(QObject *parent) : QQuickTransform(parent) { }
+
+void QMapQuickItemMatrix4x4::setMatrix(const QMatrix4x4 &matrix)
+{
+ if (m_matrix == matrix)
+ return;
+ m_matrix = matrix;
+ update();
+}
+
+void QMapQuickItemMatrix4x4::applyTo(QMatrix4x4 *matrix) const
+{
+ *matrix *= m_matrix;
+}
+
+
+QDeclarativeGeoMapQuickItem::QDeclarativeGeoMapQuickItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), zoomLevel_(0.0),
+ mapAndSourceItemSet_(false), updatingGeometry_(false), matrix_(nullptr)
+{
+ setFlag(ItemHasContents, true);
+ opacityContainer_ = new QQuickItem(this);
+ opacityContainer_->setParentItem(this);
+ opacityContainer_->setFlag(ItemHasContents, true);
+ setFiltersChildMouseEvents(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();
+ }
+}
+// See QQuickMultiPointTouchArea::childMouseEventFilter for reference
+bool QDeclarativeGeoMapQuickItem::childMouseEventFilter(QQuickItem *receiver, QEvent *event)
+{
+ if (isEnabled() && isVisible()) {
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::TouchBegin:
+ dragStartCoordinate_ = coordinate_;
+ default:
+ break;
+ }
+ }
+ return QQuickItem::childMouseEventFilter(receiver, event);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (!mapAndSourceItemSet_ || updatingGeometry_ ||
+ newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+
+ QGeoCoordinate newCoordinate;
+ // with zoomLevel set the anchorPoint has to be factored into the transformation to properly transform around it.
+ if (zoomLevel_ != 0.0) {
+ // When dragStartCoordinate_ can't be projected to screen, dragging must be disabled.
+ if (!map()->geoProjection().isProjectable(map()->geoProjection().geoToWrappedMapProjection(dragStartCoordinate_)))
+ return;
+
+ QDoubleVector2D pos = map()->geoProjection().coordinateToItemPosition(dragStartCoordinate_, false);
+ // oldGeometry.topLeft() is always intended to be (0,0), even when for some reason it's not.
+ pos.setX(pos.x() + newGeometry.topLeft().x());
+ pos.setY(pos.y() + newGeometry.topLeft().y());
+ newCoordinate = map()->geoProjection().itemPositionToCoordinate(pos, false);
+ } else {
+ newCoordinate = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(x(), y()) + 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_;
+}
+
+QGeoMap::ItemType QDeclarativeGeoMapQuickItem::itemType() const
+{
+ return QGeoMap::MapQuickItem;
+}
+
+/*!
+ \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());
+
+ setWidth(sourceItem_.data()->width());
+ setHeight(sourceItem_.data()->height());
+ if (zoomLevel_ != 0.0) { // zoom level initialized to 0.0. If it's different, it has been set explicitly.
+ if (!matrix_) {
+ matrix_ = new QMapQuickItemMatrix4x4(this);
+ matrix_->appendToItem(opacityContainer_);
+ }
+ matrix_->setMatrix(map()->geoProjection().quickItemTransformation(coordinate(), anchorPoint_, zoomLevel_));
+ setPosition(QPointF(0,0));
+ } else {
+ if (matrix_)
+ matrix_->setMatrix(QMatrix4x4());
+ setPositionOnMap(coordinate(), 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;
+}
+
+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..2035a997
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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 QMapQuickItemMatrix4x4 : public QQuickTransform
+{
+public:
+ QMapQuickItemMatrix4x4(QObject *parent = nullptr);
+
+ void setMatrix(const QMatrix4x4& matrix);
+ void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE;
+
+ QMatrix4x4 m_matrix;
+};
+
+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;
+ QGeoMap::ItemType itemType() 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;
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event) 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 dragStartCoordinate_;
+ QGeoCoordinate coordinate_;
+ QGeoRectangle geoshape_;
+ QPointer<QQuickItem> sourceItem_;
+ QQuickItem *opacityContainer_;
+ QPointF anchorPoint_;
+ qreal zoomLevel_;
+ bool mapAndSourceItemSet_;
+ bool updatingGeometry_;
+ QMapQuickItemMatrix4x4 *matrix_;
+};
+
+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..86444aa4
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaptype.cpp
@@ -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$
+**
+****************************************************************************/
+
+#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();
+}
+
+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..bce0af80
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroute.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** 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();
+}
+
+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..135323e6
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
@@ -0,0 +1,1306 @@
+/****************************************************************************
+**
+** 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#Models}{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, tr("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();
+}
+
+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..77a8a41a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** 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());
+}
+
+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..54f70c11
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp
@@ -0,0 +1,819 @@
+/****************************************************************************
+**
+** 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_;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+
+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..0b93a294
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
@@ -0,0 +1,741 @@
+/****************************************************************************
+ **
+ ** 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 "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<QDoubleVector2D> &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 QDoubleVector2D &coord = path.at(i);
+ QDoubleVector2D wrappedProjection = map.geoProjection().wrapMapProjection(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, QtClipperLib::pftEvenOdd, QtClipperLib::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;
+
+ // 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;
+
+ 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]);
+
+ screenBounds_ = ppi.boundingRect();
+}
+
+QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), border_(this), 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) {
+ regenerateCache();
+ 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);
+
+ regenerateCache();
+ 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)
+{
+ if (!coordinate.isValid())
+ return;
+
+ geopath_.addCoordinate(coordinate);
+ updateCache();
+ 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;
+
+ regenerateCache();
+ 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(), geopathProjected_);
+ geometry_.updateScreenPoints(*map());
+
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+ borderGeometry_.clear();
+
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QDoubleVector2D> closedPath = geopathProjected_;
+ 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
+*/
+void QDeclarativePolygonMapItem::regenerateCache()
+{
+ if (!map())
+ return;
+ geopathProjected_.clear();
+ geopathProjected_.reserve(geopath_.path().size());
+ for (const QGeoCoordinate &c : geopath_.path())
+ geopathProjected_ << map()->geoProjection().geoToMapProjection(c);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::updateCache()
+{
+ if (!map())
+ return;
+ geopathProjected_ << map()->geoProjection().geoToMapProjection(geopath_.path().last());
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativePolygonMapItem::contains(const QPointF &point) const
+{
+ return (geometry_.contains(point) || borderGeometry_.contains(point));
+}
+
+const QGeoShape &QDeclarativePolygonMapItem::geoShape() const
+{
+ return geopath_;
+}
+
+QGeoMap::ItemType QDeclarativePolygonMapItem::itemType() const
+{
+ return QGeoMap::MapPolygon;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (!map() || !geopath_.isValid() || 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);
+ regenerateCache();
+ 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..a928ae39
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
@@ -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$
+**
+****************************************************************************/
+
+#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<QDoubleVector2D> &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;
+ QGeoMap::ItemType itemType() 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 regenerateCache();
+ void updateCache();
+
+ QGeoPath geopath_;
+ QList<QDoubleVector2D> geopathProjected_;
+ 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..7c75cd7a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
@@ -0,0 +1,991 @@
+/****************************************************************************
+ **
+ ** 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 "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<QDoubleVector2D> &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 QDoubleVector2D &coord = path.at(i);
+ QDoubleVector2D wrappedProjection = map.geoProjection().wrapMapProjection(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<QDoubleVector2D> &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), line_(this), 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) {
+ regenerateCache();
+ 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);
+
+ regenerateCache();
+ 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)
+{
+ if (!coordinate.isValid())
+ return;
+
+ geopath_.addCoordinate(coordinate);
+
+ updateCache();
+ 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);
+
+ regenerateCache();
+ 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);
+
+ regenerateCache();
+ 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;
+
+ regenerateCache();
+ markSourceDirtyAndUpdate();
+ 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);
+
+ regenerateCache();
+ 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 (!map() || !geopath_.isValid() || 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);
+ regenerateCache();
+ 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::regenerateCache()
+{
+ if (!map())
+ return;
+ geopathProjected_.clear();
+ geopathProjected_.reserve(geopath_.path().size());
+ for (const QGeoCoordinate &c : geopath_.path())
+ geopathProjected_ << map()->geoProjection().geoToMapProjection(c);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::updateCache()
+{
+ if (!map())
+ return;
+ geopathProjected_ << map()->geoProjection().geoToMapProjection(geopath_.path().last());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::updatePolish()
+{
+ if (!map() || geopath_.path().length() == 0)
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ geometry_.updateSourcePoints(*map(), geopathProjected_, 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_;
+}
+
+QGeoMap::ItemType QDeclarativePolylineMapItem::itemType() const
+{
+ return QGeoMap::MapPolyline;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+/*!
+ \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..ec57c980
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** 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<QDoubleVector2D> &path,
+ const QGeoCoordinate geoLeftBound);
+
+ void updateScreenPoints(const QGeoMap &map,
+ qreal strokeWidth);
+
+protected:
+ QList<QList<QDoubleVector2D> > clipPath(const QGeoMap &map,
+ const QList<QDoubleVector2D> &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;
+ QGeoMap::ItemType itemType() 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 regenerateCache();
+ void updateCache();
+
+ QGeoPath geopath_;
+ QList<QDoubleVector2D> geopathProjected_;
+ 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..79750416
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
@@ -0,0 +1,397 @@
+/****************************************************************************
+**
+** 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 "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), border_(this), 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)
+ return;
+ updatePath();
+ 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);
+ updatePath();
+ 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);
+ updatePath();
+ 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;
+
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ geometry_.updateSourcePoints(*map(), pathMercator_);
+ geometry_.updateScreenPoints(*map());
+
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+ borderGeometry_.clear();
+
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QDoubleVector2D> closedPath = pathMercator_;
+ 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_;
+}
+
+QGeoMap::ItemType QDeclarativeRectangleMapItem::itemType() const
+{
+ return QGeoMap::MapRectangle;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::updatePath()
+{
+ if (!map())
+ return;
+ pathMercator_.clear();
+ pathMercator_ << map()->geoProjection().geoToMapProjection(rectangle_.topLeft());
+ pathMercator_ << map()->geoProjection().geoToMapProjection(
+ QGeoCoordinate(rectangle_.topLeft().latitude(), rectangle_.bottomRight().longitude()));
+ pathMercator_ << map()->geoProjection().geoToMapProjection(rectangle_.bottomRight());
+ pathMercator_ << map()->geoProjection().geoToMapProjection(
+ QGeoCoordinate(rectangle_.bottomRight().latitude(), rectangle_.topLeft().longitude()));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (!map() || !rectangle_.isValid() || 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);
+ updatePath();
+ 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..ca7ca9b7
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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 <QtPositioning/private/qdoublevector2d_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;
+ QGeoMap::ItemType itemType() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void topLeftChanged(const QGeoCoordinate &topLeft);
+ void bottomRightChanged(const QGeoCoordinate &bottomRight);
+ void colorChanged(const QColor &color);
+
+protected:
+ void updatePath();
+ 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_;
+ QList<QDoubleVector2D> pathMercator_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+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..7e88b9cf
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativeroutemapitem.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** 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 "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..2883c2bb
--- /dev/null
+++ b/src/location/declarativemaps/qgeomapitemgeometry.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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) {
+ 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..992fa21e
--- /dev/null
+++ b/src/location/declarativemaps/qquickgeomapgesturearea.cpp
@@ -0,0 +1,1819 @@
+/****************************************************************************
+**
+** 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 <cmath>
+#include "qgeomap_p.h"
+#include "qdoublevector2d_p.h"
+#include "qlocationutils_p.h"
+#include <QtGui/QMatrix4x4>
+
+
+#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 38
+// 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.
+static const qreal MinimumFlickVelocity = 75.0;
+// Tolerance for detecting two finger sliding start
+static const qreal MaximumParallelPosition = 40.0; // in degrees
+// Tolerance for detecting parallel sliding
+static const qreal MaximumParallelSlidingAngle = 4.0; // in degrees
+// Tolerance for starting rotation
+static const qreal MinimumRotationStartingAngle = 15.0; // in degrees
+// Tolerance for starting pinch
+static const qreal MinimumPinchDelta = 40; // in pixels
+// Tolerance for starting tilt when sliding vertical
+static const qreal MinimumPanToTiltDelta = 80; // in pixels;
+
+static qreal distanceBetweenTouchPoints(const QPointF &p1, const QPointF &p2)
+{
+ return QLineF(p1, p2).length();
+}
+
+// Returns the new map center after anchoring coordinate to anchorPoint on the screen
+// Approach: find the displacement in (wrapped) mercator space, and apply that to the center
+static QGeoCoordinate anchorCoordinateToPoint(QGeoMap &map, const QGeoCoordinate &coordinate, const QPointF &anchorPoint)
+{
+ QDoubleVector2D centerProj = map.geoProjection().geoToWrappedMapProjection(map.cameraData().center());
+ QDoubleVector2D coordProj = map.geoProjection().geoToWrappedMapProjection(coordinate);
+
+ QDoubleVector2D anchorProj = map.geoProjection().itemPositionToWrappedMapProjection(QDoubleVector2D(anchorPoint));
+ // Y-clamping done in mercatorToCoord
+ return map.geoProjection().wrappedMapProjectionToGeo(centerProj + coordProj - anchorProj);
+}
+
+static qreal angleFromPoints(const QPointF &p1, const QPointF &p2)
+{
+ return QLineF(p1, p2).angle();
+}
+
+// Keeps it in +- 180
+static qreal touchAngle(const QPointF &p1, const QPointF &p2)
+{
+ qreal angle = angleFromPoints(p1, p2);
+ if (angle > 180)
+ angle -= 360;
+ return angle;
+}
+
+// Deals with angles crossing the +-180 edge, assumes that the delta can't be > 180
+static qreal angleDelta(const qreal angle1, const qreal angle2)
+{
+ qreal delta = angle1 - angle2;
+ if (delta > 180.0) // detect crossing angle1 positive, angle2 negative, rotation counterclockwise, difference negative
+ delta = angle1 - angle2 - 360.0;
+ else if (delta < -180.0) // detect crossing angle1 negative, angle2 positive, rotation clockwise, difference positive
+ delta = angle1 - angle2 + 360.0;
+
+ return delta;
+}
+
+static bool pointDragged(const QPointF &pOld, const QPointF &pNew)
+{
+ static const int startDragDistance = qApp->styleHints()->startDragDistance();
+ return ( qAbs(pNew.x() - pOld.x()) > startDragDistance
+ || qAbs(pNew.y() - pOld.y()) > startDragDistance);
+}
+
+static qreal vectorSize(const QPointF &vector)
+{
+ return std::sqrt(vector.x() * vector.x() + vector.y() * vector.y());
+}
+
+// This linearizes the angles around 0, and keep it linear around 180, allowing to differentiate
+// touch angles that are supposed to be parallel (0 or 180 depending on what finger goes first)
+static qreal touchAngleTilting(const QPointF &p1, const QPointF &p2)
+{
+ qreal angle = angleFromPoints(p1, p2);
+ if (angle > 270)
+ angle -= 360;
+ return angle;
+}
+
+static bool movingParallelVertical(const QPointF &p1old, const QPointF &p1new, const QPointF &p2old, const QPointF &p2new)
+{
+ if (!pointDragged(p1old, p1new) || !pointDragged(p2old, p2new))
+ return false;
+
+ QPointF v1 = p1new - p1old;
+ QPointF v2 = p2new - p2old;
+ qreal v1v2size = vectorSize(v1 + v2);
+
+ if (v1v2size < vectorSize(v1) || v1v2size < vectorSize(v2)) // going in opposite directions
+ return false;
+
+ const qreal newAngle = touchAngleTilting(p1new, p2new);
+ const qreal oldAngle = touchAngleTilting(p1old, p2old);
+ const qreal angleDiff = angleDelta(newAngle, oldAngle);
+
+ if (qAbs(angleDiff) > MaximumParallelSlidingAngle)
+ return false;
+
+ return true;
+}
+
+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, as well as two finger rotation
+ and two finger parallel vertical sliding to tilt the map.
+
+ 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 the pinch gesture is active.
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::panActive
+
+ This read-only property holds whether the pan gesture is active.
+
+ \note Change notifications for this property were introduced in Qt 5.5.
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::rotationActive
+
+ This read-only property holds whether the two-finger rotation gesture is active.
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::tiltActive
+
+ This read-only property holds whether the two-finger tilt gesture is active.
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \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.
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::rotationStarted(PinchEvent event)
+
+ This signal is emitted when a two-finger rotation gesture is started.
+
+ The corresponding handler is \c onRotationStarted.
+
+ \sa rotationUpdated, rotationFinished
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::rotationUpdated(PinchEvent event)
+
+ This signal is emitted as the user's fingers move across the map,
+ after the \l rotationStarted signal is emitted.
+
+ The corresponding handler is \c onRotationUpdated.
+
+ \sa rotationStarted, rotationFinished
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::rotationFinished(PinchEvent event)
+
+ This signal is emitted at the end of a two-finger rotation gesture.
+
+ The corresponding handler is \c onRotationFinished.
+
+ \sa rotationStarted, rotationUpdated
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::tiltStarted(PinchEvent event)
+
+ This signal is emitted when a two-finger tilt gesture is started.
+
+ The corresponding handler is \c onTiltStarted.
+
+ \sa tiltUpdated, tiltFinished
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::tiltUpdated(PinchEvent event)
+
+ This signal is emitted as the user's fingers move across the map,
+ after the \l tiltStarted signal is emitted.
+
+ The corresponding handler is \c onTiltUpdated.
+
+ \sa tiltStarted, tiltFinished
+
+ \since Qt Location 5.9
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::tiltFinished(PinchEvent event)
+
+ This signal is emitted at the end of a two-finger tilt gesture.
+
+ The corresponding handler is \c onTiltFinished.
+
+ \sa tiltStarted, tiltUpdated
+
+ \since Qt Location 5.9
+*/
+
+QQuickGeoMapGestureArea::QQuickGeoMapGestureArea(QDeclarativeGeoMap *map)
+ : QQuickItem(map),
+ m_map(0),
+ m_declarativeMap(map),
+ m_enabled(true),
+ m_acceptedGestures(PinchGesture | PanGesture | FlickGesture | RotationGesture | TiltGesture),
+ m_preventStealing(false)
+{
+ m_touchPointState = touchPoints0;
+ m_pinchState = pinchInactive;
+ m_flickState = flickInactive;
+ m_rotationState = rotationInactive;
+ m_tiltState = tiltInactive;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setMap(QPointer<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).
+ \li MapGestureArea.RotationGesture - Support the map rotation gesture (value: 0x0008).
+ \li MapGestureArea.TiltGesture - Support the map tilt gesture (value: 0x0010).
+ \endlist
+*/
+
+QQuickGeoMapGestureArea::AcceptedGestures QQuickGeoMapGestureArea::acceptedGestures() const
+{
+ return m_acceptedGestures;
+}
+
+
+void QQuickGeoMapGestureArea::setAcceptedGestures(AcceptedGestures acceptedGestures)
+{
+ if (acceptedGestures == m_acceptedGestures)
+ return;
+ m_acceptedGestures = acceptedGestures;
+
+ if (enabled()) {
+ setPanEnabled(acceptedGestures & PanGesture);
+ setFlickEnabled(acceptedGestures & FlickGesture);
+ setPinchEnabled(acceptedGestures & PinchGesture);
+ setRotationEnabled(acceptedGestures & RotationGesture);
+ setTiltEnabled(acceptedGestures & TiltGesture);
+ }
+
+ emit acceptedGesturesChanged();
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::isPinchActive() const
+{
+ return m_pinchState == pinchActive;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::isRotationActive() const
+{
+ return m_rotationState == rotationActive;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::isTiltActive() const
+{
+ return m_tiltState == tiltActive;
+}
+
+/*!
+ \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);
+ setRotationEnabled(m_acceptedGestures & RotationGesture);
+ setTiltEnabled(m_acceptedGestures & TiltGesture);
+ } else {
+ setPanEnabled(false);
+ setFlickEnabled(false);
+ setPinchEnabled(false);
+ setRotationEnabled(false);
+ setTiltEnabled(false);
+ }
+
+ emit enabledChanged();
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::pinchEnabled() const
+{
+ return m_pinch.m_pinchEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setPinchEnabled(bool enabled)
+{
+ m_pinch.m_pinchEnabled = enabled;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::rotationEnabled() const
+{
+ return m_pinch.m_rotationEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setRotationEnabled(bool enabled)
+{
+ m_pinch.m_rotationEnabled = enabled;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::tiltEnabled() const
+{
+ return m_pinch.m_tiltEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setTiltEnabled(bool enabled)
+{
+ m_pinch.m_tiltEnabled = enabled;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::panEnabled() const
+{
+ return m_flick.m_panEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setPanEnabled(bool enabled)
+{
+ if (enabled == m_flick.m_panEnabled)
+ return;
+ m_flick.m_panEnabled = enabled;
+
+ // unlike the pinch, the pan existing functionality is to stop immediately
+ if (!enabled) {
+ stopPan();
+ m_flickState = flickInactive;
+ }
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::flickEnabled() const
+{
+ return m_flick.m_flickEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setFlickEnabled(bool enabled)
+{
+ if (enabled == m_flick.m_flickEnabled)
+ return;
+ m_flick.m_flickEnabled = enabled;
+ // unlike the pinch, the flick existing functionality is to stop immediately
+ if (!enabled) {
+ bool stateActive = (m_flickState != flickInactive);
+ stopFlick();
+ if (stateActive) {
+ if (m_flick.m_panEnabled)
+ m_flickState = panActive;
+ else
+ m_flickState = flickInactive;
+ }
+ }
+}
+
+/*!
+ \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)
+{
+ // TODO: remove m_zoom.m_minimum and m_maximum and use m_declarativeMap directly instead.
+ 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;
+
+ const QGeoCoordinate &wheelGeoPos = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(event->posF()), false);
+ const QPointF &preZoomPoint = event->posF();
+
+ const double zoomLevelDelta = event->angleDelta().y() * qreal(0.001);
+ // Gesture area should always honor maxZL, but Map might not.
+ m_declarativeMap->setZoomLevel(qMin<qreal>(m_declarativeMap->zoomLevel() + zoomLevelDelta, maximumZoomLevel()));
+ const QPointF &postZoomPoint = m_map->geoProjection().coordinateToItemPosition(wheelGeoPos, false).toPointF();
+
+ if (preZoomPoint != postZoomPoint) // need to re-anchor the wheel geoPos to the event position
+ m_declarativeMap->setCenter(anchorCoordinateToPoint(*m_map, wheelGeoPos, preZoomPoint));
+
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::clearTouchData()
+{
+ m_flickVector = QVector2D();
+ m_touchPointsCentroid.setX(0);
+ m_touchPointsCentroid.setY(0);
+ m_touchCenterCoord.setLongitude(0);
+ m_touchCenterCoord.setLatitude(0);
+ m_startCoord.setLongitude(0);
+ m_startCoord.setLatitude(0);
+}
+
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateFlickParameters(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.;
+ qreal vel = distanceBetweenTouchPoints(pos, m_lastPos) / elapsed;
+ m_flickVector = (QVector2D(pos) - QVector2D(m_lastPos)).normalized();
+ m_flickVector *= qBound<qreal>(-m_flick.m_maxVelocity, vel, m_flick.m_maxVelocity);
+
+ m_lastPos = pos;
+ m_lastPosTime.restart();
+ }
+}
+
+void QQuickGeoMapGestureArea::setTouchPointState(const QQuickGeoMapGestureArea::TouchPointState state)
+{
+ m_touchPointState = state;
+}
+
+void QQuickGeoMapGestureArea::setFlickState(const QQuickGeoMapGestureArea::FlickState state)
+{
+ m_flickState = state;
+}
+
+void QQuickGeoMapGestureArea::setTiltState(const QQuickGeoMapGestureArea::TiltState state)
+{
+ m_tiltState = state;
+}
+
+void QQuickGeoMapGestureArea::setRotationState(const QQuickGeoMapGestureArea::RotationState state)
+{
+ m_rotationState = state;
+}
+
+void QQuickGeoMapGestureArea::setPinchState(const QQuickGeoMapGestureArea::PinchState state)
+{
+ m_pinchState = state;
+}
+
+/*!
+ \internal
+*/
+
+bool QQuickGeoMapGestureArea::isActive() const
+{
+ return isPanActive() || isPinchActive() || isRotationActive() || isTiltActive();
+}
+
+/*!
+ \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 tilt. Tilt goes first as it blocks anything else, when started.
+ // But tilting can also only start if nothing else is active.
+ if (isTiltActive() || m_pinch.m_tiltEnabled)
+ tiltStateMachine();
+
+ // Parallel state machine for pinch
+ if (isPinchActive() || m_pinch.m_pinchEnabled)
+ pinchStateMachine();
+
+ // Parallel state machine for rotation.
+ if (isRotationActive() || m_pinch.m_rotationEnabled)
+ rotationStateMachine();
+
+ // 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 isPanActive() below allows pan continue its current gesture if you disable
+ // the whole gesture.
+ // Pan goes last because it does reanchoring in updatePan() which makes the map
+ // properly rotate around the touch point centroid.
+ if (isPanActive() || m_flick.m_flickEnabled || m_flick.m_panEnabled)
+ panStateMachine();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::touchPointStateMachine()
+{
+ // Transitions:
+ switch (m_touchPointState) {
+ case touchPoints0:
+ if (m_allPoints.count() == 1) {
+ clearTouchData();
+ startOneTouchPoint();
+ setTouchPointState(touchPoints1);
+ } else if (m_allPoints.count() >= 2) {
+ clearTouchData();
+ startTwoTouchPoints();
+ setTouchPointState(touchPoints2);
+ }
+ break;
+ case touchPoints1:
+ if (m_allPoints.count() == 0) {
+ setTouchPointState(touchPoints0);
+ } else if (m_allPoints.count() == 2) {
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_touchPointsCentroid), false);
+ startTwoTouchPoints();
+ setTouchPointState(touchPoints2);
+ }
+ break;
+ case touchPoints2:
+ if (m_allPoints.count() == 0) {
+ setTouchPointState(touchPoints0);
+ } else if (m_allPoints.count() == 1) {
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_touchPointsCentroid), false);
+ startOneTouchPoint();
+ setTouchPointState(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_touchPointsCentroid = mapFromScene(m_allPoints.at(0).scenePos());
+ updateFlickParameters(m_touchPointsCentroid);
+}
+
+/*!
+ \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());
+ m_twoTouchAngleStart = touchAngle(m_sceneStartPoint1, m_sceneStartPoint2); // Initial angle used for calculating rotation
+ m_distanceBetweenTouchPointsStart = distanceBetweenTouchPoints(m_sceneStartPoint1, m_sceneStartPoint2);
+ m_twoTouchPointsCentroidStart = (m_sceneStartPoint1 + m_sceneStartPoint2) / 2;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateTwoTouchPoints()
+{
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ m_distanceBetweenTouchPoints = distanceBetweenTouchPoints(p1, p2);
+ m_touchPointsCentroid = (p1 + p2) / 2;
+ updateFlickParameters(m_touchPointsCentroid);
+
+ m_twoTouchAngle = touchAngle(p1, p2);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::tiltStateMachine()
+{
+ TiltState lastState = m_tiltState;
+ // Transitions:
+ switch (m_tiltState) {
+ case tiltInactive:
+ if (m_allPoints.count() >= 2) {
+ if (!isRotationActive() && !isPinchActive() && canStartTilt()) { // only gesture that can be overridden: pan/flick
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startTilt();
+ setTiltState(tiltActive);
+ } else {
+ setTiltState(tiltInactiveTwoPoints);
+ }
+ }
+ break;
+ case tiltInactiveTwoPoints:
+ if (m_allPoints.count() <= 1) {
+ setTiltState(tiltInactive);
+ } else {
+ if (!isRotationActive() && !isPinchActive() && canStartTilt()) { // only gesture that can be overridden: pan/flick
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startTilt();
+ setTiltState(tiltActive);
+ }
+ }
+ break;
+ case tiltActive:
+ if (m_allPoints.count() <= 1) {
+ setTiltState(tiltInactive);
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_declarativeMap->setKeepTouchGrab(m_preventStealing);
+ endTilt();
+ }
+ break;
+ }
+ // This line implements an exclusive state machine, where the transitions and updates don't
+ // happen on the same frame
+ if (m_tiltState != lastState) {
+ emit tiltActiveChanged();
+ return;
+ }
+
+ // Update
+ switch (m_tiltState) {
+ case tiltInactive:
+ case tiltInactiveTwoPoints:
+ break; // do nothing
+ case tiltActive:
+ updateTilt();
+ break;
+ }
+}
+
+bool validateTouchAngleForTilting(const qreal angle)
+{
+ return ((qAbs(angle) - 180.0) < MaximumParallelPosition) || (qAbs(angle) < MaximumParallelPosition);
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::canStartTilt()
+{
+ if (m_allPoints.count() >= 2) {
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ if (validateTouchAngleForTilting(m_twoTouchAngle)
+ && movingParallelVertical(m_sceneStartPoint1, p1, m_sceneStartPoint2, p2)
+ && qAbs(m_twoTouchPointsCentroidStart.y() - m_touchPointsCentroid.y()) > MinimumPanToTiltDelta) {
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ 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 tiltStarted(&m_pinch.m_event);
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startTilt()
+{
+ if (isPanActive()) {
+ stopPan();
+ setFlickState(flickInactive);
+ }
+
+ m_pinch.m_tilt.m_startTouchCentroid = m_touchPointsCentroid;
+ m_pinch.m_tilt.m_startTilt = m_declarativeMap->tilt();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateTilt()
+{
+ // Calculate the new tilt
+ qreal verticalDisplacement = (m_touchPointsCentroid - m_pinch.m_tilt.m_startTouchCentroid).y();
+
+ // Approach: 10pixel = 1 degree.
+ qreal tilt = verticalDisplacement / 10.0;
+ qreal newTilt = m_pinch.m_tilt.m_startTilt - tilt;
+ m_declarativeMap->setTilt(newTilt);
+
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ 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);
+
+ emit tiltUpdated(&m_pinch.m_event);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::endTilt()
+{
+ 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 tiltFinished(&m_pinch.m_event);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::rotationStateMachine()
+{
+ RotationState lastState = m_rotationState;
+ // Transitions:
+ switch (m_rotationState) {
+ case rotationInactive:
+ if (m_allPoints.count() >= 2) {
+ if (!isTiltActive() && canStartRotation()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startRotation();
+ setRotationState(rotationActive);
+ } else {
+ setRotationState(rotationInactiveTwoPoints);
+ }
+ }
+ break;
+ case rotationInactiveTwoPoints:
+ if (m_allPoints.count() <= 1) {
+ setRotationState(rotationInactive);
+ } else {
+ if (!isTiltActive() && canStartRotation()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startRotation();
+ setRotationState(rotationActive);
+ }
+ }
+ break;
+ case rotationActive:
+ if (m_allPoints.count() <= 1) {
+ setRotationState(rotationInactive);
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_declarativeMap->setKeepTouchGrab(m_preventStealing);
+ endRotation();
+ }
+ break;
+ }
+ // This line implements an exclusive state machine, where the transitions and updates don't
+ // happen on the same frame
+ if (m_rotationState != lastState) {
+ emit rotationActiveChanged();
+ return;
+ }
+
+ // Update
+ switch (m_rotationState) {
+ case rotationInactive:
+ case rotationInactiveTwoPoints:
+ break; // do nothing
+ case rotationActive:
+ updateRotation();
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::canStartRotation()
+{
+ if (m_allPoints.count() >= 2) {
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ if (pointDragged(m_sceneStartPoint1, p1) || pointDragged(m_sceneStartPoint2, p2)) {
+ qreal delta = angleDelta(m_twoTouchAngleStart, m_twoTouchAngle);
+ if (qAbs(delta) < MinimumRotationStartingAngle) {
+ return false;
+ }
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ 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 rotationStarted(&m_pinch.m_event);
+ return m_pinch.m_event.accepted();
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startRotation()
+{
+ m_pinch.m_rotation.m_startBearing = m_declarativeMap->bearing();
+ m_pinch.m_rotation.m_previousTouchAngle = m_twoTouchAngle;
+ m_pinch.m_rotation.m_totalAngle = 0.0;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateRotation()
+{
+ // Calculate the new bearing
+ qreal angle = angleDelta(m_pinch.m_rotation.m_previousTouchAngle, m_twoTouchAngle);
+ if (qAbs(angle) < 0.2) // avoiding too many updates
+ return;
+
+ m_pinch.m_rotation.m_previousTouchAngle = m_twoTouchAngle;
+ m_pinch.m_rotation.m_totalAngle += angle;
+ qreal newBearing = m_pinch.m_rotation.m_startBearing - m_pinch.m_rotation.m_totalAngle;
+ m_declarativeMap->setBearing(newBearing);
+
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ 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);
+
+ emit rotationUpdated(&m_pinch.m_event);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::endRotation()
+{
+ 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 rotationFinished(&m_pinch.m_event);
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::pinchStateMachine()
+{
+ PinchState lastState = m_pinchState;
+ // Transitions:
+ switch (m_pinchState) {
+ case pinchInactive:
+ if (m_allPoints.count() >= 2) {
+ if (!isTiltActive() && canStartPinch()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startPinch();
+ setPinchState(pinchActive);
+ } else {
+ setPinchState(pinchInactiveTwoPoints);
+ }
+ }
+ break;
+ case pinchInactiveTwoPoints:
+ if (m_allPoints.count() <= 1) {
+ setPinchState(pinchInactive);
+ } else {
+ if (!isTiltActive() && canStartPinch()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startPinch();
+ setPinchState(pinchActive);
+ }
+ }
+ break;
+ case pinchActive:
+ if (m_allPoints.count() <= 1) { // Once started, pinch goes off only when finger(s) are release
+ setPinchState(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()
+{
+ if (m_allPoints.count() >= 2) {
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ if (qAbs(m_distanceBetweenTouchPoints - m_distanceBetweenTouchPointsStart) > MinimumPinchDelta) {
+ m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
+ 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_touchPointsCentroid));
+ 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(qMin<qreal>(newZoomLevel, maximumZoomLevel()));
+ 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 (!isTiltActive() && canStartPan()) {
+ // Update startCoord_ to ensure smooth start for panning when going over startDragDistance
+ QGeoCoordinate newStartCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_touchPointsCentroid), false);
+ m_startCoord.setLongitude(newStartCoord.longitude());
+ m_startCoord.setLatitude(newStartCoord.latitude());
+ m_declarativeMap->setKeepMouseGrab(true);
+ setFlickState(panActive);
+ }
+ break;
+ case panActive:
+ if (m_allPoints.count() == 0) {
+ if (!tryStartFlick())
+ {
+ setFlickState(flickInactive);
+ // mark as inactive for use by camera
+ if (m_pinchState == pinchInactive && m_rotationState == rotationInactive && m_tiltState == tiltInactive) {
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_map->prefetchData();
+ }
+ emit panFinished();
+ } else {
+ setFlickState(flickActive);
+ emit panFinished();
+ emit flickStarted();
+ }
+ }
+ break;
+ case flickActive:
+ if (m_allPoints.count() > 0) { // re touched before movement ended
+ stopFlick();
+ m_declarativeMap->setKeepMouseGrab(true);
+ setFlickState(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()
+{
+ QGeoCoordinate animationStartCoordinate = anchorCoordinateToPoint(*m_map, m_startCoord, m_touchPointsCentroid);
+ 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 flickSpeed = 0.0;
+ if (m_lastPosTime.elapsed() < QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD)
+ flickSpeed = m_flickVector.length();
+
+ int flickTime = 0;
+ int flickPixels = 0;
+ QVector2D flickVector;
+
+ if (qAbs(flickSpeed) > MinimumFlickVelocity
+ && distanceBetweenTouchPoints(m_touchPointsCentroid, m_sceneStartPoint1) > FlickThreshold) {
+ qreal acceleration = m_flick.m_deceleration;
+ if ((flickSpeed > 0.0f) == (m_flick.m_deceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+ flickTime = static_cast<int>(-1000 * flickSpeed / acceleration);
+ flickPixels = (flickTime * flickSpeed) / 2000.0;
+ flickVector = m_flickVector.normalized() * flickPixels;
+ }
+
+ if (flickTime > 0) {
+ startFlick(flickVector.x(), flickVector.y(), 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);
+
+ QPointF delta(dx, dy);
+ QMatrix4x4 matBearing;
+ matBearing.rotate(m_map->cameraData().bearing(), 0, 0, 1);
+ delta = matBearing * delta;
+
+ double zoom = pow(2.0, m_declarativeMap->zoomLevel());
+ double longitude = animationStartCoordinate.longitude() - (delta.x() / zoom);
+ double latitude = animationStartCoordinate.latitude() + (delta.y() / zoom);
+
+ if (delta.x() > 0)
+ m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::East);
+ else
+ m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::West);
+
+ //keep animation in correct bounds
+ animationEndCoordinate.setLongitude(QLocationUtils::wrapLong(longitude));
+ animationEndCoordinate.setLatitude(QLocationUtils::clipLat(latitude, QLocationUtils::mercatorMaxLatitude()));
+
+ 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_flickVector = QVector2D();
+ setFlickState(flickInactive);
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ emit panFinished();
+ emit panActiveChanged();
+ m_map->prefetchData();
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::stopFlick()
+{
+ if (!m_flick.m_animation)
+ return;
+ m_flickVector = QVector2D();
+ 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) {
+ setFlickState(flickInactive);
+ emit flickFinished();
+ emit panActiveChanged();
+ m_map->prefetchData();
+ }
+}
+
+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..320c0fbe
--- /dev/null
+++ b/src/location/declarativemaps/qquickgeomapgesturearea_p.h
@@ -0,0 +1,397 @@
+/****************************************************************************
+**
+** 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 <QtCore/QPointer>
+#include <QtQuick/QQuickItem>
+#include <QTouchEvent>
+#include <QDebug>
+#include <QElapsedTimer>
+#include <QtPositioning/qgeocoordinate.h>
+#include <QtGui/QVector2D>
+
+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(bool rotationActive READ isRotationActive NOTIFY rotationActiveChanged)
+ Q_PROPERTY(bool tiltActive READ isTiltActive NOTIFY tiltActiveChanged)
+ 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 = 0x0004,
+ RotationGesture = 0x0008,
+ TiltGesture = 0x0010
+ };
+
+ Q_DECLARE_FLAGS(AcceptedGestures, GeoMapGesture)
+
+ AcceptedGestures acceptedGestures() const;
+ void setAcceptedGestures(AcceptedGestures acceptedGestures);
+
+ bool isPinchActive() const;
+ bool isRotationActive() const;
+ bool isTiltActive() 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(QPointer<QGeoMap> map);
+
+ bool preventStealing() const;
+ void setPreventStealing(bool prevent);
+
+Q_SIGNALS:
+ void panActiveChanged();
+ void pinchActiveChanged();
+ void rotationActiveChanged();
+ void tiltActiveChanged();
+ 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 rotationStarted(QGeoMapPinchEvent *pinch);
+ void rotationUpdated(QGeoMapPinchEvent *pinch);
+ void rotationFinished(QGeoMapPinchEvent *pinch);
+ void tiltStarted(QGeoMapPinchEvent *pinch);
+ void tiltUpdated(QGeoMapPinchEvent *pinch);
+ void tiltFinished(QGeoMapPinchEvent *pinch);
+ void preventStealingChanged();
+private:
+ void update();
+
+ // Create general data relating to the touch points
+ void touchPointStateMachine();
+ void startOneTouchPoint();
+ void updateOneTouchPoint();
+ void startTwoTouchPoints();
+ void updateTwoTouchPoints();
+
+ // All two fingers vertical parallel panning related code, which encompasses tilting
+ void tiltStateMachine();
+ bool canStartTilt();
+ void startTilt();
+ void updateTilt();
+ void endTilt();
+
+ // All two fingers rotation related code, which encompasses rotation
+ void rotationStateMachine();
+ bool canStartRotation();
+ void startRotation();
+ void updateRotation();
+ void endRotation();
+
+ // 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 rotationEnabled() const;
+ void setRotationEnabled(bool enabled);
+ bool tiltEnabled() const;
+ void setTiltEnabled(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 updateFlickParameters(const QPointF &pos);
+
+private:
+ QPointer<QGeoMap> m_map;
+ QDeclarativeGeoMap *m_declarativeMap;
+ bool m_enabled;
+
+ // This should be intended as a "two fingers gesture" struct
+ struct Pinch
+ {
+ Pinch() : m_pinchEnabled(true), m_rotationEnabled(true), m_tiltEnabled(true),
+ m_startDist(0), m_lastAngle(0.0) {}
+
+ QGeoMapPinchEvent m_event;
+ bool m_pinchEnabled;
+ bool m_rotationEnabled;
+ bool m_tiltEnabled;
+ 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;
+
+ struct Rotation
+ {
+ Rotation() : m_startBearing(0.0), m_previousTouchAngle(0.0), m_totalAngle(0.0) {}
+ qreal m_startBearing;
+ qreal m_previousTouchAngle; // needed for detecting crossing +- 180 in a safer way
+ qreal m_totalAngle;
+ } m_rotation;
+
+ struct Tilt
+ {
+ Tilt() {}
+ QPointF m_startTouchCentroid;
+ qreal m_startTilt;
+ } m_tilt;
+
+ QPointF m_lastPoint1;
+ QPointF m_lastPoint2;
+ qreal m_startDist;
+ qreal m_lastAngle;
+ } m_pinch;
+
+ AcceptedGestures m_acceptedGestures;
+
+ struct Pan
+ {
+ Pan() : m_maxVelocity(2500), m_deceleration(2500), m_animation(0), m_flickEnabled(true), m_panEnabled(true) {}
+
+ qreal m_maxVelocity;
+ qreal m_deceleration;
+ QQuickGeoCoordinateAnimation *m_animation;
+ bool m_flickEnabled;
+ bool m_panEnabled;
+ } m_flick;
+
+
+ // these are calculated regardless of gesture or number of touch points
+ QVector2D m_flickVector;
+ QElapsedTimer m_lastPosTime;
+ QPointF m_lastPos;
+ QVector<QTouchEvent::TouchPoint> m_allPoints;
+ QVector<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_twoTouchAngleStart;
+ qreal m_distanceBetweenTouchPoints;
+ qreal m_distanceBetweenTouchPointsStart;
+ QPointF m_twoTouchPointsCentroidStart;
+ QPointF m_touchPointsCentroid;
+ bool m_preventStealing;
+ bool m_panEnabled;
+
+private:
+ // prototype state machine...
+ enum TouchPointState
+ {
+ touchPoints0,
+ touchPoints1,
+ touchPoints2
+ } m_touchPointState;
+
+ enum PinchState
+ {
+ pinchInactive,
+ pinchInactiveTwoPoints,
+ pinchActive
+ } m_pinchState;
+
+ enum RotationState
+ {
+ rotationInactive,
+ rotationInactiveTwoPoints,
+ rotationActive
+ } m_rotationState;
+
+ enum TiltState
+ {
+ tiltInactive,
+ tiltInactiveTwoPoints,
+ tiltActive
+ } m_tiltState;
+
+ enum FlickState
+ {
+ flickInactive,
+ panActive,
+ flickActive
+ } m_flickState;
+
+ inline void setTouchPointState(const TouchPointState state);
+ inline void setFlickState(const FlickState state);
+ inline void setTiltState(const TiltState state);
+ inline void setRotationState(const RotationState state);
+ inline void setPinchState(const PinchState state);
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QQuickGeoMapGestureArea)
+
+#endif // QQUICKGEOMAPGESTUREAREA_P_H