summaryrefslogtreecommitdiff
path: root/src/location
diff options
context:
space:
mode:
Diffstat (limited to 'src/location')
-rw-r--r--src/location/declarativemaps/declarativemaps.pri62
-rw-r--r--src/location/declarativemaps/error_messages.cpp52
-rw-r--r--src/location/declarativemaps/error_messages.h55
-rw-r--r--src/location/declarativemaps/locationvaluetypehelper.cpp117
-rw-r--r--src/location/declarativemaps/locationvaluetypehelper_p.h60
-rw-r--r--src/location/declarativemaps/mapitemviewdelegateincubator.cpp54
-rw-r--r--src/location/declarativemaps/mapitemviewdelegateincubator_p.h66
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem.cpp728
-rw-r--r--src/location/declarativemaps/qdeclarativecirclemapitem_p.h134
-rw-r--r--src/location/declarativemaps/qdeclarativegeocodemodel.cpp727
-rw-r--r--src/location/declarativemaps/qdeclarativegeocodemodel_p.h207
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaneuver.cpp201
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaneuver_p.h111
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap.cpp1822
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap_p.h265
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp168
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h94
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase.cpp271
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitembase_p.h123
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview.cpp541
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview_p.h152
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h87
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapparameter.cpp125
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapparameter_p.h90
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem.cpp366
-rw-r--r--src/location/declarativemaps/qdeclarativegeomapquickitem_p.h120
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaptype.cpp136
-rw-r--r--src/location/declarativemaps/qdeclarativegeomaptype_p.h105
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute.cpp277
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroute_p.h106
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel.cpp1308
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutemodel_p.h344
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment.cpp164
-rw-r--r--src/location/declarativemaps/qdeclarativegeoroutesegment_p.h86
-rw-r--r--src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp821
-rw-r--r--src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h284
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem.cpp743
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem_p.h161
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem.cpp956
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem_p.h197
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem.cpp380
-rw-r--r--src/location/declarativemaps/qdeclarativerectanglemapitem_p.h122
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem.cpp149
-rw-r--r--src/location/declarativemaps/qdeclarativeroutemapitem_p.h92
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry.cpp149
-rw-r--r--src/location/declarativemaps/qgeomapitemgeometry_p.h150
-rw-r--r--src/location/declarativemaps/qquickgeomapgesturearea.cpp1288
-rw-r--r--src/location/declarativemaps/qquickgeomapgesturearea_p.h318
-rw-r--r--src/location/declarativeplaces/declarativeplaces.pri51
-rw-r--r--src/location/declarativeplaces/qdeclarativecategory.cpp458
-rw-r--r--src/location/declarativeplaces/qdeclarativecategory_p.h153
-rw-r--r--src/location/declarativeplaces/qdeclarativecontactdetail.cpp223
-rw-r--r--src/location/declarativeplaces/qdeclarativecontactdetail_p.h104
-rw-r--r--src/location/declarativeplaces/qdeclarativeperiod_p.h98
-rw-r--r--src/location/declarativeplaces/qdeclarativeplace.cpp1229
-rw-r--r--src/location/declarativeplaces/qdeclarativeplace_p.h262
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceattribute.cpp221
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceattribute_p.h95
-rw-r--r--src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp397
-rw-r--r--src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h126
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp169
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h65
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceicon.cpp250
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceicon_p.h104
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp170
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h78
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceuser.cpp139
-rw-r--r--src/location/declarativeplaces/qdeclarativeplaceuser_p.h92
-rw-r--r--src/location/declarativeplaces/qdeclarativeratings.cpp153
-rw-r--r--src/location/declarativeplaces/qdeclarativeratings_p.h98
-rw-r--r--src/location/declarativeplaces/qdeclarativereviewmodel.cpp183
-rw-r--r--src/location/declarativeplaces/qdeclarativereviewmodel_p.h78
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp362
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h148
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp917
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h179
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp353
-rw-r--r--src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h104
-rw-r--r--src/location/declarativeplaces/qdeclarativesupplier.cpp221
-rw-r--r--src/location/declarativeplaces/qdeclarativesupplier_p.h111
-rw-r--r--src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp689
-rw-r--r--src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h166
-rw-r--r--src/location/location.pro17
83 files changed, 23392 insertions, 5 deletions
diff --git a/src/location/declarativemaps/declarativemaps.pri b/src/location/declarativemaps/declarativemaps.pri
new file mode 100644
index 00000000..52e61049
--- /dev/null
+++ b/src/location/declarativemaps/declarativemaps.pri
@@ -0,0 +1,62 @@
+QT += quick-private network positioning-private qml-private core-private gui-private
+
+INCLUDEPATH += declarativemaps
+
+PUBLIC_HEADERS += \
+ declarativemaps/error_messages.h
+
+PRIVATE_HEADERS += \
+ declarativemaps/qdeclarativegeomapitemview_p.h \
+ declarativemaps/qdeclarativegeomapitemview_p_p.h \
+ declarativemaps/qdeclarativegeoserviceprovider_p.h \
+ declarativemaps/qdeclarativegeocodemodel_p.h \
+ declarativemaps/qdeclarativegeoroutemodel_p.h \
+ declarativemaps/qdeclarativegeoroute_p.h \
+ declarativemaps/qdeclarativegeoroutesegment_p.h \
+ declarativemaps/qdeclarativegeomaneuver_p.h \
+ declarativemaps/qdeclarativegeomap_p.h \
+ declarativemaps/qdeclarativegeomaptype_p.h \
+ declarativemaps/qdeclarativegeomapitembase_p.h \
+ declarativemaps/qdeclarativegeomapquickitem_p.h \
+ declarativemaps/qdeclarativecirclemapitem_p.h \
+ declarativemaps/qdeclarativerectanglemapitem_p.h \
+ declarativemaps/qdeclarativepolygonmapitem_p.h \
+ declarativemaps/qdeclarativepolylinemapitem_p.h \
+ declarativemaps/qdeclarativeroutemapitem_p.h \
+ declarativemaps/qdeclarativegeomapparameter_p.h \
+ declarativemaps/qgeomapitemgeometry_p.h \
+ declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h \
+ declarativemaps/locationvaluetypehelper_p.h \
+ declarativemaps/qquickgeomapgesturearea_p.h \
+ declarativemaps/mapitemviewdelegateincubator_p.h \
+ ../imports/positioning/qquickgeocoordinateanimation_p.h
+
+SOURCES += \
+ declarativemaps/qdeclarativegeomapitemview.cpp \
+ declarativemaps/qdeclarativegeoserviceprovider.cpp \
+ declarativemaps/qdeclarativegeocodemodel.cpp \
+ declarativemaps/qdeclarativegeoroutemodel.cpp \
+ declarativemaps/qdeclarativegeoroute.cpp \
+ declarativemaps/qdeclarativegeoroutesegment.cpp \
+ declarativemaps/qdeclarativegeomaneuver.cpp \
+ declarativemaps/qdeclarativegeomap.cpp \
+ declarativemaps/qdeclarativegeomaptype.cpp \
+ declarativemaps/qdeclarativegeomapitembase.cpp \
+ declarativemaps/qdeclarativegeomapquickitem.cpp \
+ declarativemaps/qdeclarativecirclemapitem.cpp \
+ declarativemaps/qdeclarativerectanglemapitem.cpp \
+ declarativemaps/qdeclarativepolygonmapitem.cpp \
+ declarativemaps/qdeclarativepolylinemapitem.cpp \
+ declarativemaps/qdeclarativeroutemapitem.cpp \
+ declarativemaps/qdeclarativegeomapparameter.cpp \
+ declarativemaps/qgeomapitemgeometry.cpp \
+ declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp \
+ declarativemaps/error_messages.cpp \
+ declarativemaps/locationvaluetypehelper.cpp \
+ declarativemaps/qquickgeomapgesturearea.cpp \
+ ../imports/positioning/qquickgeocoordinateanimation.cpp \
+ declarativemaps/mapitemviewdelegateincubator.cpp
+
+LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lpoly2tri$$qtPlatformTargetSuffix() -lclip2tri$$qtPlatformTargetSuffix()
+
+
diff --git a/src/location/declarativemaps/error_messages.cpp b/src/location/declarativemaps/error_messages.cpp
new file mode 100644
index 00000000..a2557f79
--- /dev/null
+++ b/src/location/declarativemaps/error_messages.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "error_messages.h"
+
+QT_BEGIN_NAMESPACE
+
+const char CONTEXT_NAME[] = "QtLocationQML";
+
+//to-be-translated error string
+
+const char PLUGIN_PROPERTY_NOT_SET[] = QT_TRANSLATE_NOOP("QtLocationQML", "Plugin property is not set.");
+const char PLUGIN_ERROR[] = QT_TRANSLATE_NOOP("QtLocationQML", "Plugin Error (%1): %2");
+const char PLUGIN_PROVIDER_ERROR[] = QT_TRANSLATE_NOOP("QtLocationQML", "Plugin Error (%1): Could not instantiate provider");
+const char PLUGIN_NOT_VALID[] = QT_TRANSLATE_NOOP("QtLocationQML", "Plugin is not valid");
+const char CATEGORIES_NOT_INITIALIZED[] = QT_TRANSLATE_NOOP("QtLocationQML", "Unable to initialize categories");
+const char UNABLE_TO_MAKE_REQUEST[] = QT_TRANSLATE_NOOP("QtLocationQML", "Unable to create request");
+const char INDEX_OUT_OF_RANGE[] = QT_TRANSLATE_NOOP("QtLocationQML", "Index '%1' out of range");
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/error_messages.h b/src/location/declarativemaps/error_messages.h
new file mode 100644
index 00000000..81c43b34
--- /dev/null
+++ b/src/location/declarativemaps/error_messages.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ERROR_MESSAGES_H
+#define ERROR_MESSAGES_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+extern const char CONTEXT_NAME[];
+extern const char PLUGIN_PROPERTY_NOT_SET[];
+extern const char PLUGIN_ERROR[];
+extern const char PLUGIN_PROVIDER_ERROR[];
+extern const char PLUGIN_NOT_VALID[];
+extern const char CATEGORIES_NOT_INITIALIZED[];
+extern const char UNABLE_TO_MAKE_REQUEST[];
+extern const char INDEX_OUT_OF_RANGE[];
+
+QT_END_NAMESPACE
+
+#endif // ERROR_MESSAGES_H
diff --git a/src/location/declarativemaps/locationvaluetypehelper.cpp b/src/location/declarativemaps/locationvaluetypehelper.cpp
new file mode 100644
index 00000000..4f39e0b4
--- /dev/null
+++ b/src/location/declarativemaps/locationvaluetypehelper.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "locationvaluetypehelper_p.h"
+
+
+QGeoCoordinate parseCoordinate(const QJSValue &value, bool *ok)
+{
+ QGeoCoordinate c;
+
+ if (value.isObject()) {
+ if (value.hasProperty(QStringLiteral("latitude")))
+ c.setLatitude(value.property(QStringLiteral("latitude")).toNumber());
+ if (value.hasProperty(QStringLiteral("longitude")))
+ c.setLongitude(value.property(QStringLiteral("longitude")).toNumber());
+ if (value.hasProperty(QStringLiteral("altitude")))
+ c.setAltitude(value.property(QStringLiteral("altitude")).toNumber());
+
+ if (ok)
+ *ok = true;
+ }
+
+ return c;
+}
+
+QGeoRectangle parseRectangle(const QJSValue &value, bool *ok)
+{
+ QGeoRectangle r;
+
+ *ok = false;
+
+ if (value.isObject()) {
+ if (value.hasProperty(QStringLiteral("bottomLeft"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("bottomLeft")), ok);
+ if (*ok)
+ r.setBottomLeft(c);
+ }
+ if (value.hasProperty(QStringLiteral("bottomRight"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("bottomRight")), ok);
+ if (*ok)
+ r.setBottomRight(c);
+ }
+ if (value.hasProperty(QStringLiteral("topLeft"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("topLeft")), ok);
+ if (*ok)
+ r.setTopLeft(c);
+ }
+ if (value.hasProperty(QStringLiteral("topRight"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("topRight")), ok);
+ if (*ok)
+ r.setTopRight(c);
+ }
+ if (value.hasProperty(QStringLiteral("center"))) {
+ QGeoCoordinate c = parseCoordinate(value.property(QStringLiteral("center")), ok);
+ if (*ok)
+ r.setCenter(c);
+ }
+ if (value.hasProperty(QStringLiteral("height")))
+ r.setHeight(value.property(QStringLiteral("height")).toNumber());
+ if (value.hasProperty(QStringLiteral("width")))
+ r.setWidth(value.property(QStringLiteral("width")).toNumber());
+ }
+
+ return r;
+}
+
+QGeoCircle parseCircle(const QJSValue &value, bool *ok)
+{
+ QGeoCircle c;
+
+ *ok = false;
+
+ if (value.isObject()) {
+ if (value.hasProperty(QStringLiteral("center"))) {
+ QGeoCoordinate coord = parseCoordinate(value.property(QStringLiteral("center")), ok);
+ if (*ok)
+ c.setCenter(coord);
+ }
+ if (value.hasProperty(QStringLiteral("radius")))
+ c.setRadius(value.property(QStringLiteral("radius")).toNumber());
+ }
+
+ return c;
+}
diff --git a/src/location/declarativemaps/locationvaluetypehelper_p.h b/src/location/declarativemaps/locationvaluetypehelper_p.h
new file mode 100644
index 00000000..50038e88
--- /dev/null
+++ b/src/location/declarativemaps/locationvaluetypehelper_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LOCATION_VALUE_TYPE_HELPER
+#define LOCATION_VALUE_TYPE_HELPER
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QJSValue>
+#include <QGeoCoordinate>
+#include <QGeoRectangle>
+#include <QGeoCircle>
+
+QGeoCoordinate parseCoordinate(const QJSValue &value, bool *ok);
+QGeoRectangle parseRectangle(const QJSValue &value, bool *ok);
+QGeoCircle parseCircle(const QJSValue &value, bool *ok);
+
+#endif
diff --git a/src/location/declarativemaps/mapitemviewdelegateincubator.cpp b/src/location/declarativemaps/mapitemviewdelegateincubator.cpp
new file mode 100644
index 00000000..c8500e4b
--- /dev/null
+++ b/src/location/declarativemaps/mapitemviewdelegateincubator.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Jolla Ltd, author: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mapitemviewdelegateincubator_p.h"
+#include "qdeclarativegeomapitemview_p.h"
+#include "qdeclarativegeomapitemview_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+MapItemViewDelegateIncubator::MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view, QDeclarativeGeoMapItemViewItemData *itemData, bool batched)
+: m_view(view), m_itemData(itemData), m_batched(batched)
+{
+}
+
+void MapItemViewDelegateIncubator::statusChanged(QQmlIncubator::Status status)
+{
+ m_view->incubatorStatusChanged(this, status, m_batched);
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/mapitemviewdelegateincubator_p.h b/src/location/declarativemaps/mapitemviewdelegateincubator_p.h
new file mode 100644
index 00000000..b559c944
--- /dev/null
+++ b/src/location/declarativemaps/mapitemviewdelegateincubator_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Jolla Ltd, author: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef MAPITEMVIEWDELEGATEINCUBATOR_H
+#define MAPITEMVIEWDELEGATEINCUBATOR_H
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtQml/QQmlIncubator>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGeoMapItemView;
+class QDeclarativeGeoMapItemViewItemData;
+
+class Q_LOCATION_PRIVATE_EXPORT MapItemViewDelegateIncubator : public QQmlIncubator
+{
+public:
+ MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view, QDeclarativeGeoMapItemViewItemData *itemData, bool batched = true);
+
+protected:
+ void statusChanged(Status status) Q_DECL_OVERRIDE;
+
+private:
+ QDeclarativeGeoMapItemView *m_view;
+ QDeclarativeGeoMapItemViewItemData *m_itemData;
+ bool m_batched;
+
+ friend class QDeclarativeGeoMapItemView;
+};
+
+QT_END_NAMESPACE
+
+#endif // MAPITEMVIEWDELEGATEINCUBATOR_H
diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem.cpp b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
new file mode 100644
index 00000000..39581dce
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem.cpp
@@ -0,0 +1,728 @@
+/***************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativecirclemapitem_p.h"
+#include "qdeclarativepolygonmapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+
+#include "qwebmercator_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <cmath>
+#include <algorithm>
+
+#include <QtCore/QScopedValueRollback>
+#include <QPen>
+#include <QPainter>
+#include <QtGui/private/qtriangulator_p.h>
+
+#include "qdoublevector2d_p.h"
+#include "qlocationutils_p.h"
+#include "qgeocircle.h"
+
+/* poly2tri triangulator includes */
+#include <common/shapes.h>
+#include <sweep/cdt.h>
+
+#include <QtPositioning/private/qclipperutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapCircle
+ \instantiates QDeclarativeCircleMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapCircle type displays a geographic circle on a Map.
+
+ The MapCircle type displays a geographic circle on a Map, which
+ consists of all points that are within a set distance from one
+ central point. Depending on map projection, a geographic circle
+ may not always be a perfect circle on the screen: for instance, in
+ the Mercator projection, circles become ovoid in shape as they near
+ the poles. To display a perfect screen circle around a point, use a
+ MapQuickItem containing a relevant Qt Quick type instead.
+
+ By default, the circle is displayed as a 1 pixel black border with
+ no fill. To change its appearance, use the color, border.color
+ and border.width properties.
+
+ Internally, a MapCircle is implemented as a many-sided polygon. To
+ calculate the radius points it uses a spherical model of the Earth,
+ similar to the atDistanceAndAzimuth method of the \l {coordinate}
+ type. These two things can occasionally have implications for the
+ accuracy of the circle's shape, depending on position and map
+ projection.
+
+ \note Dragging a MapCircle (through the use of \l MouseArea)
+ causes new points to be generated at the same distance (in meters)
+ from the center. This is in contrast to other map items which store
+ their dimensions in terms of latitude and longitude differences between
+ vertices.
+
+ \section2 Performance
+
+ MapCircle performance is almost equivalent to that of a MapPolygon with
+ the same number of vertices. There is a small amount of additional
+ overhead with respect to calculating the vertices first.
+
+ Like the other map objects, MapCircle is normally drawn without a smooth
+ appearance. Setting the opacity property will force the object to be
+ blended, which decreases performance considerably depending on the graphics
+ hardware in use.
+
+ \section2 Example Usage
+
+ The following snippet shows a map containing a MapCircle, centered at
+ the coordinate (-27, 153) with a radius of 5km. The circle is
+ filled in green, with a 3 pixel black border.
+
+ \code
+ Map {
+ MapCircle {
+ center {
+ latitude: -27.5
+ longitude: 153.0
+ }
+ radius: 5000.0
+ color: 'green'
+ border.width: 3
+ }
+ }
+ \endcode
+
+ \image api-mapcircle.png
+*/
+
+#ifdef M_PI
+#undef M_PI
+#endif
+#define M_PI 3.14159265358979323846264338327950288
+
+static const int CircleSamples = 128;
+
+struct Vertex
+{
+ QVector2D position;
+};
+
+QGeoMapCircleGeometry::QGeoMapCircleGeometry()
+{
+}
+
+/*!
+ \internal
+*/
+void QGeoMapCircleGeometry::updateScreenPointsInvert(const QList<QGeoCoordinate> &circlePath, const QGeoMap &map)
+{
+ // Not checking for !screenDirty anymore, as everything is now recalculated.
+ clear();
+ if (map.viewportWidth() == 0 || map.viewportHeight() == 0 || circlePath.size() < 3) // a circle requires at least 3 points;
+ return;
+
+ /*
+ * No special case for no tilting as these items are very rare, and usually at most one per map.
+ *
+ * Approach:
+ * 1) subtract the circle from a rectangle filling the whole map, *in wrapped mercator space*
+ * 2) clip the resulting geometries against the visible region, *in wrapped mercator space*
+ * 3) create a QPainterPath with each of the resulting polygons projected to screen
+ * 4) use qTriangulate() to triangulate the painter path
+ */
+
+ // 1)
+ double topLati = QLocationUtils::mercatorMaxLatitude();
+ double bottomLati = -(QLocationUtils::mercatorMaxLatitude());
+ double leftLongi = QLocationUtils::mapLeftLongitude(map.cameraData().center().longitude());
+ double rightLongi = QLocationUtils::mapRightLongitude(map.cameraData().center().longitude());
+
+ srcOrigin_ = QGeoCoordinate(topLati,leftLongi);
+ QDoubleVector2D tl = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(topLati,leftLongi));
+ QDoubleVector2D tr = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(topLati,rightLongi));
+ QDoubleVector2D br = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(bottomLati,rightLongi));
+ QDoubleVector2D bl = map.geoProjection().geoToWrappedMapProjection(QGeoCoordinate(bottomLati,leftLongi));
+
+ QList<QDoubleVector2D> fill;
+ fill << tl << tr << br << bl;
+
+ QList<QDoubleVector2D> hole;
+ for (const QGeoCoordinate &c: circlePath)
+ hole << map.geoProjection().geoToWrappedMapProjection(c);
+
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(fill), true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(hole));
+ Paths difference = clipper.execute(c2t::clip2tri::Difference, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+
+ // 2)
+ QDoubleVector2D lb = map.geoProjection().geoToWrappedMapProjection(srcOrigin_);
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ clipper.clearClipper();
+ for (const Path &p: difference)
+ clipper.addSubjectPath(p, true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ with the point with minimum X/Y
+ lb = QDoubleVector2D(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ for (const QDoubleVector2D &p: path) {
+ if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) {
+ lb = p;
+ }
+ }
+ }
+ if (qIsInf(lb.x()))
+ return;
+
+ // Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(tl.x(), lb.x()));
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(lb));
+ } else {
+ clippedPaths = QClipperUtils::pathsToQList(difference);
+ }
+
+ //3)
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(lb);
+
+ QPainterPath ppi;
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+ //point = point - origin; // Do this using ppi.translate()
+
+ if (i == 0) {
+ ppi.moveTo(point.toPointF());
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ ppi.lineTo(point.toPointF());
+ lastAddedPoint = point;
+ }
+ }
+ }
+ ppi.closeSubpath();
+ }
+ ppi.translate(-1 * origin.toPointF());
+
+#if 0 // old poly2tri code, has to be ported to clip2tri in order to work with tilted projections
+ std::vector<p2t::Point*> borderPts;
+ borderPts.reserve(4);
+
+ std::vector<p2t::Point*> curPts;
+ curPts.reserve(ppi.elementCount());
+ for (int i = 0; i < ppi.elementCount(); ++i) {
+ const QPainterPath::Element e = ppi.elementAt(i);
+ if (e.isMoveTo() || i == ppi.elementCount() - 1
+ || (qAbs(e.x - curPts.front()->x) < 0.1
+ && qAbs(e.y - curPts.front()->y) < 0.1)) {
+ if (curPts.size() > 2) {
+ for (int j = 0; j < 4; ++j) {
+ const QPainterPath::Element e2 = ppiBorder.elementAt(j);
+ borderPts.push_back(new p2t::Point(e2.x, e2.y));
+ }
+ p2t::CDT *cdt = new p2t::CDT(borderPts);
+ cdt->AddHole(curPts);
+ cdt->Triangulate();
+ std::vector<p2t::Triangle*> tris = cdt->GetTriangles();
+ screenVertices_.reserve(screenVertices_.size() + int(tris.size()));
+ for (size_t i = 0; i < tris.size(); ++i) {
+ p2t::Triangle *t = tris.at(i);
+ for (int j = 0; j < 3; ++j) {
+ p2t::Point *p = t->GetPoint(j);
+ screenVertices_ << QPointF(p->x, p->y);
+ }
+ }
+ delete cdt;
+ }
+ curPts.clear();
+ curPts.reserve(ppi.elementCount() - i);
+ curPts.push_back(new p2t::Point(e.x, e.y));
+ } else if (e.isLineTo()) {
+ curPts.push_back(new p2t::Point(e.x, e.y));
+ } else {
+ qWarning("Unhandled element type in circle painterpath");
+ }
+ }
+
+ if (curPts.size() > 0) {
+ qDeleteAll(curPts.begin(), curPts.end());
+ curPts.clear();
+ }
+
+ if (borderPts.size() > 0) {
+ qDeleteAll(borderPts.begin(), borderPts.end());
+ borderPts.clear();
+ }
+#else // Using qTriangulate as this case is not frequent, and not many circles including both poles are usually used
+ QTriangleSet ts = qTriangulate(ppi);
+ qreal *vx = ts.vertices.data();
+
+ screenIndices_.reserve(ts.indices.size());
+ screenVertices_.reserve(ts.vertices.size());
+
+ if (ts.indices.type() == QVertexIndexVector::UnsignedInt) {
+ const quint32 *ix = reinterpret_cast<const quint32 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ } else {
+ const quint16 *ix = reinterpret_cast<const quint16 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ }
+ for (int i = 0; i < (ts.vertices.size()/2*2); i += 2)
+ screenVertices_ << QPointF(vx[i], vx[i + 1]);
+#endif
+
+ screenBounds_ = ppi.boundingRect();
+ sourceBounds_ = screenBounds_;
+}
+
+static bool crossEarthPole(const QGeoCoordinate &center, qreal distance)
+{
+ qreal poleLat = 90;
+ QGeoCoordinate northPole = QGeoCoordinate(poleLat, center.longitude());
+ QGeoCoordinate southPole = QGeoCoordinate(-poleLat, center.longitude());
+ // approximate using great circle distance
+ qreal distanceToNorthPole = center.distanceTo(northPole);
+ qreal distanceToSouthPole = center.distanceTo(southPole);
+ if (distanceToNorthPole < distance || distanceToSouthPole < distance)
+ return true;
+ return false;
+}
+
+static void calculatePeripheralPoints(QList<QGeoCoordinate> &path,
+ const QGeoCoordinate &center,
+ qreal distance,
+ int steps)
+{
+ // Calculate points based on great-circle distance
+ // Calculation is the same as GeoCoordinate's atDistanceAndAzimuth function
+ // but tweaked here for computing multiple points
+
+ // pre-calculations
+ steps = qMax(steps, 3);
+ qreal centerLon = center.longitude();
+ qreal latRad = QLocationUtils::radians(center.latitude());
+ qreal lonRad = QLocationUtils::radians(centerLon);
+ qreal cosLatRad = std::cos(latRad);
+ qreal sinLatRad = std::sin(latRad);
+ qreal ratio = (distance / (QLocationUtils::earthMeanRadius()));
+ qreal cosRatio = std::cos(ratio);
+ qreal sinRatio = std::sin(ratio);
+ qreal sinLatRad_x_cosRatio = sinLatRad * cosRatio;
+ qreal cosLatRad_x_sinRatio = cosLatRad * sinRatio;
+ for (int i = 0; i < steps; ++i) {
+ qreal azimuthRad = 2 * M_PI * i / steps;
+ qreal resultLatRad = std::asin(sinLatRad_x_cosRatio
+ + cosLatRad_x_sinRatio * std::cos(azimuthRad));
+ qreal resultLonRad = lonRad + std::atan2(std::sin(azimuthRad) * cosLatRad_x_sinRatio,
+ cosRatio - sinLatRad * std::sin(resultLatRad));
+ qreal lat2 = QLocationUtils::degrees(resultLatRad);
+ qreal lon2 = QLocationUtils::wrapLong(QLocationUtils::degrees(resultLonRad));
+
+ path << QGeoCoordinate(lat2, lon2, center.altitude());
+ }
+}
+
+QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), dirtyMaterial_(true),
+ updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(markSourceDirtyAndUpdate()));
+
+ // assume that circles are not self-intersecting
+ // to speed up processing
+ // FIXME: unfortunately they self-intersect at the poles due to current drawing method
+ // so the line is commented out until fixed
+ //geometry_.setAssumeSimple(true);
+
+}
+
+QDeclarativeCircleMapItem::~QDeclarativeCircleMapItem()
+{
+}
+
+/*!
+ \qmlpropertygroup Location::MapCircle::border
+ \qmlproperty int MapCircle::border.width
+ \qmlproperty color MapCircle::border.color
+
+ This property is part of the border group property.
+ The border property holds the width and color used to draw the border of the circle.
+ The width is in pixels and is independent of the zoom level of the map.
+
+ The default values correspond to a black border with a width of 1 pixel.
+ For no line, use a width of 0 or a transparent color.
+*/
+QDeclarativeMapLineProperties *QDeclarativeCircleMapItem::border()
+{
+ return &border_;
+}
+
+void QDeclarativeCircleMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+void QDeclarativeCircleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map)
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \qmlproperty coordinate MapCircle::center
+
+ This property holds the central point about which the circle is defined.
+
+ \sa radius
+*/
+void QDeclarativeCircleMapItem::setCenter(const QGeoCoordinate &center)
+{
+ if (circle_.center() == center)
+ return;
+
+ circle_.setCenter(center);
+ markSourceDirtyAndUpdate();
+ emit centerChanged(center);
+}
+
+QGeoCoordinate QDeclarativeCircleMapItem::center()
+{
+ return circle_.center();
+}
+
+/*!
+ \qmlproperty color MapCircle::color
+
+ This property holds the fill color of the circle when drawn. For no fill,
+ use a transparent color.
+*/
+void QDeclarativeCircleMapItem::setColor(const QColor &color)
+{
+ if (color_ == color)
+ return;
+ color_ = color;
+ dirtyMaterial_ = true;
+ update();
+ emit colorChanged(color_);
+}
+
+QColor QDeclarativeCircleMapItem::color() const
+{
+ return color_;
+}
+
+/*!
+ \qmlproperty real MapCircle::radius
+
+ This property holds the radius of the circle, in meters on the ground.
+
+ \sa center
+*/
+void QDeclarativeCircleMapItem::setRadius(qreal radius)
+{
+ if (circle_.radius() == radius)
+ return;
+
+ circle_.setRadius(radius);
+ markSourceDirtyAndUpdate();
+ emit radiusChanged(radius);
+}
+
+qreal QDeclarativeCircleMapItem::radius() const
+{
+ return circle_.radius();
+}
+
+/*!
+ \qmlproperty real MapCircle::opacity
+
+ This property holds the opacity of the item. Opacity is specified as a
+ number between 0 (fully transparent) and 1 (fully opaque). The default is 1.
+
+ An item with 0 opacity will still receive mouse events. To stop mouse events, set the
+ visible property of the item to false.
+*/
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativeCircleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+
+ MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
+
+ if (!node)
+ node = new MapPolygonNode();
+
+ //TODO: update only material
+ if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
+ node->update(color_, border_.color(), &geometry_, &borderGeometry_);
+ geometry_.setPreserveGeometry(false);
+ borderGeometry_.setPreserveGeometry(false);
+ geometry_.markClean();
+ borderGeometry_.markClean();
+ dirtyMaterial_ = false;
+ }
+ return node;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCircleMapItem::updatePolish()
+{
+ if (!map() || !circle_.isValid())
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ if (geometry_.isSourceDirty()) {
+ circlePath_.clear();
+ calculatePeripheralPoints(circlePath_, circle_.center(), circle_.radius(), CircleSamples);
+ }
+
+ QList<QGeoCoordinate> originalCirclePath = circlePath_;
+
+ int pathCount = circlePath_.size();
+ bool preserve = preserveCircleGeometry(circlePath_, circle_.center(), circle_.radius());
+ geometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_
+ geometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft());
+
+ bool invertedCircle = false;
+ if (crossEarthPole(circle_.center(), circle_.radius()) && circlePath_.size() == pathCount) {
+ geometry_.updateScreenPointsInvert(circlePath_, *map()); // invert fill area for really huge circles
+ invertedCircle = true;
+ } else {
+ geometry_.updateSourcePoints(*map(), circlePath_);
+ geometry_.updateScreenPoints(*map());
+ }
+
+ borderGeometry_.clear();
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QGeoCoordinate> closedPath = circlePath_;
+ closedPath << closedPath.first();
+
+ if (invertedCircle) {
+ closedPath = originalCirclePath;
+ closedPath << closedPath.first();
+ std::reverse(closedPath.begin(), closedPath.end());
+ }
+
+ borderGeometry_.setPreserveGeometry(true, circle_.boundingGeoRectangle().topLeft()); // to set the geoLeftBound_
+ borderGeometry_.setPreserveGeometry(preserve, circle_.boundingGeoRectangle().topLeft());
+
+ // Use srcOrigin_ from fill geometry after clipping to ensure that translateToCommonOrigin won't fail.
+ const QGeoCoordinate &geometryOrigin = geometry_.origin();
+
+ borderGeometry_.srcPoints_.clear();
+ borderGeometry_.srcPointTypes_.clear();
+
+ QDoubleVector2D borderLeftBoundWrapped;
+ QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
+ if (clippedPaths.size()) {
+ borderLeftBoundWrapped = map()->geoProjection().geoToWrappedMapProjection(geometryOrigin);
+ borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
+ borderGeometry_.updateScreenPoints(*map(), border_.width());
+ geoms << &borderGeometry_;
+ } else {
+ borderGeometry_.clear();
+ }
+ }
+
+ QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ setWidth(combined.width());
+ setHeight(combined.height());
+
+ setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCircleMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ return;
+
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeCircleMapItem::contains(const QPointF &point) const
+{
+ return (geometry_.contains(point) || borderGeometry_.contains(point));
+}
+
+const QGeoShape &QDeclarativeCircleMapItem::geoShape() const
+{
+ return circle_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCircleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (updatingGeometry_ || newGeometry == oldGeometry) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+
+ QDoubleVector2D newPoint = QDoubleVector2D(x(),y()) + QDoubleVector2D(width(), height()) / 2;
+ QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(newPoint, false);
+ if (newCoordinate.isValid())
+ setCenter(newCoordinate);
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+bool QDeclarativeCircleMapItem::preserveCircleGeometry (QList<QGeoCoordinate> &path,
+ const QGeoCoordinate &center, qreal distance)
+{
+ // if circle crosses north/south pole, then don't preserve circular shape,
+ if ( crossEarthPole(center, distance)) {
+ updateCirclePathForRendering(path, center, distance);
+ return false;
+ }
+ return true;
+
+}
+
+/*
+ * A workaround for circle path to be drawn correctly using a polygon geometry
+ * This method generates a polygon like
+ * _____________
+ * | |
+ * \ /
+ * | |
+ * / \
+ * | |
+ * -------------
+ *
+ * or a polygon like
+ *
+ * ______________
+ * | ____ |
+ * \__/ \__/
+ */
+void QDeclarativeCircleMapItem::updateCirclePathForRendering(QList<QGeoCoordinate> &path,
+ const QGeoCoordinate &center,
+ qreal distance)
+{
+ qreal poleLat = 90;
+ qreal distanceToNorthPole = center.distanceTo(QGeoCoordinate(poleLat, 0));
+ qreal distanceToSouthPole = center.distanceTo(QGeoCoordinate(-poleLat, 0));
+ bool crossNorthPole = distanceToNorthPole < distance;
+ bool crossSouthPole = distanceToSouthPole < distance;
+
+ QList<int> wrapPathIndex;
+ QDoubleVector2D prev = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(0)));
+
+ for (int i = 1; i <= path.count(); ++i) {
+ int index = i % path.count();
+ QDoubleVector2D point = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(index)));
+ double diff = qAbs(point.x() - prev.x());
+ if (diff > 0.5) {
+ continue;
+ }
+ }
+
+ // find the points in path where wrapping occurs
+ for (int i = 1; i <= path.count(); ++i) {
+ int index = i % path.count();
+ QDoubleVector2D point = map()->geoProjection().wrapMapProjection(map()->geoProjection().geoToMapProjection(path.at(index)));
+ if ( (qAbs(point.x() - prev.x())) >= 0.5 ) { // TODO: Add a projectionWidth to GeoProjection, perhaps?
+ wrapPathIndex << index;
+ if (wrapPathIndex.size() == 2 || !(crossNorthPole && crossSouthPole))
+ break;
+ }
+ prev = point;
+ }
+ // insert two additional coords at top/bottom map corners of the map for shape
+ // to be drawn correctly
+ if (wrapPathIndex.size() > 0) {
+ qreal newPoleLat = 90;
+ QGeoCoordinate wrapCoord = path.at(wrapPathIndex[0]);
+ if (wrapPathIndex.size() == 2) {
+ QGeoCoordinate wrapCoord2 = path.at(wrapPathIndex[1]);
+ if (wrapCoord2.latitude() > wrapCoord.latitude())
+ newPoleLat = -90;
+ } else if (center.latitude() < 0) {
+ newPoleLat = -90;
+ }
+ for (int i = 0; i < wrapPathIndex.size(); ++i) {
+ int index = wrapPathIndex[i] == 0 ? 0 : wrapPathIndex[i] + i*2;
+ int prevIndex = (index - 1) < 0 ? (path.count() - 1): index - 1;
+ QGeoCoordinate coord0 = path.at(prevIndex);
+ QGeoCoordinate coord1 = path.at(index);
+ coord0.setLatitude(newPoleLat);
+ coord1.setLatitude(newPoleLat);
+ path.insert(index ,coord1);
+ path.insert(index, coord0);
+ newPoleLat = -newPoleLat;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativecirclemapitem_p.h b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
new file mode 100644
index 00000000..62bef6d3
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativecirclemapitem_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVECIRCLEMAPITEM_H
+#define QDECLARATIVECIRCLEMAPITEM_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+#include <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+#include <QtPositioning/QGeoCircle>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoMapCircleGeometry : public QGeoMapPolygonGeometry
+{
+public:
+ QGeoMapCircleGeometry();
+
+ void updateScreenPointsInvert(const QList<QGeoCoordinate> &circlePath, const QGeoMap &map);
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCircleMapItem : public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+ Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QDeclarativeMapLineProperties *border READ border CONSTANT)
+
+public:
+ explicit QDeclarativeCircleMapItem(QQuickItem *parent = 0);
+ ~QDeclarativeCircleMapItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+
+ QGeoCoordinate center();
+ void setCenter(const QGeoCoordinate &center);
+
+ qreal radius() const;
+ void setRadius(qreal radius);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QDeclarativeMapLineProperties *border();
+
+ bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void centerChanged(const QGeoCoordinate &center);
+ void radiusChanged(qreal radius);
+ void colorChanged(const QColor &color);
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ bool preserveCircleGeometry(QList<QGeoCoordinate> &path, const QGeoCoordinate &center,
+ qreal distance);
+ void updateCirclePathForRendering(QList<QGeoCoordinate> &path, const QGeoCoordinate &center,
+ qreal distance);
+
+private:
+ QGeoCircle circle_;
+ QDeclarativeMapLineProperties border_;
+ QColor color_;
+ QList<QGeoCoordinate> circlePath_;
+ bool dirtyMaterial_;
+ QGeoMapCircleGeometry geometry_;
+ QGeoMapPolylineGeometry borderGeometry_;
+ bool updatingGeometry_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeCircleMapItem)
+
+#endif /* QDECLARATIVECIRCLEMAPITEM_H */
diff --git a/src/location/declarativemaps/qdeclarativegeocodemodel.cpp b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp
new file mode 100644
index 00000000..e92949ee
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeocodemodel.cpp
@@ -0,0 +1,727 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeocodemodel_p.h"
+#include "error_messages.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtQml/QQmlInfo>
+#include <QtPositioning/QGeoCircle>
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/QGeoCodingManager>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype GeocodeModel
+ \instantiates QDeclarativeGeocodeModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-geocoding
+ \since Qt Location 5.5
+
+ \brief The GeocodeModel type provides support for searching operations
+ related to geographic information.
+
+ The GeocodeModel type is used as part of a model/view grouping to
+ match addresses or search strings with geographic locations. How the
+ geographic locations generated are used or displayed is decided by any
+ Views attached to the GeocodeModel (for example a \l MapItemView or \l{ListView}).
+
+ Like \l Map and \l RouteModel, all the data for a GeocodeModel to work
+ comes from a services plugin. This is contained in the \l{plugin} property,
+ and this must be set before the GeocodeModel can do any useful work.
+
+ Once the plugin is set, the \l{query} property can be used to specify the
+ address or search string to match. If \l{autoUpdate} is enabled, the Model
+ will update its output automatically. Otherwise, the \l{update} method may
+ be used. By default, autoUpdate is disabled.
+
+ The data stored and returned in the GeocodeModel consists of \l{Location}
+ objects, as a list with the role name "locationData". See the documentation
+ for \l{Location} for further details on its structure and contents.
+
+ \section2 Example Usage
+
+ The following snippet is two-part, showing firstly the declaration of
+ objects, and secondly a short piece of procedural code using it. We set
+ the geocodeModel's \l{autoUpdate} property to false, and call \l{update} once
+ the query is set up. In this case, as we use a string value in \l{query},
+ only one update would occur, even with autoUpdate enabled. However, if we
+ provided an \l{Address} object we may inadvertently trigger multiple
+ requests whilst setting its properties.
+
+ \code
+ Plugin {
+ id: aPlugin
+ }
+
+ GeocodeModel {
+ id: geocodeModel
+ plugin: aPlugin
+ autoUpdate: false
+ }
+ \endcode
+
+ \code
+ {
+ geocodeModel.query = "53 Brandl St, Eight Mile Plains, Australia"
+ geocodeModel.update()
+ }
+ \endcode
+*/
+
+/*!
+ \qmlsignal QtLocation::GeocodeModel::locationsChanged()
+
+ This signal is emitted when locations in the model have changed.
+
+ \sa count
+*/
+
+
+QDeclarativeGeocodeModel::QDeclarativeGeocodeModel(QObject *parent)
+: QAbstractListModel(parent), autoUpdate_(false), complete_(false), reply_(0), plugin_(0),
+ status_(QDeclarativeGeocodeModel::Null), error_(QDeclarativeGeocodeModel::NoError),
+ address_(0), limit_(-1), offset_(0)
+{
+}
+
+QDeclarativeGeocodeModel::~QDeclarativeGeocodeModel()
+{
+ qDeleteAll(declarativeLocations_);
+ declarativeLocations_.clear();
+ delete reply_;
+}
+
+/*!
+ \internal
+ From QQmlParserStatus
+*/
+void QDeclarativeGeocodeModel::componentComplete()
+{
+ complete_ = true;
+ if (autoUpdate_)
+ update();
+}
+
+/*!
+ \qmlmethod void QtLocation::GeocodeModel::update()
+
+ Instructs the GeocodeModel to update its data. This is most useful
+ when \l autoUpdate is disabled, to force a refresh when the query
+ has been changed.
+*/
+void QDeclarativeGeocodeModel::update()
+{
+ if (!complete_)
+ return;
+
+ if (!plugin_) {
+ setError(EngineNotSetError, tr("Cannot geocode, plugin not set."));
+ return;
+ }
+
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return;
+
+ QGeoCodingManager *geocodingManager = serviceProvider->geocodingManager();
+ if (!geocodingManager) {
+ setError(EngineNotSetError, tr("Cannot geocode, geocode manager not set."));
+ return;
+ }
+ if (!coordinate_.isValid() && (!address_ || address_->address().isEmpty()) &&
+ (searchString_.isEmpty())) {
+ setError(ParseError, tr("Cannot geocode, valid query not set."));
+ return;
+ }
+ abortRequest(); // abort possible previous requests
+ setError(NoError, QString());
+
+ if (coordinate_.isValid()) {
+ setStatus(QDeclarativeGeocodeModel::Loading);
+ reply_ = geocodingManager->reverseGeocode(coordinate_, boundingArea_);
+ if (reply_->isFinished()) {
+ if (reply_->error() == QGeoCodeReply::NoError) {
+ geocodeFinished(reply_);
+ } else {
+ geocodeError(reply_, reply_->error(), reply_->errorString());
+ }
+ }
+ } else if (address_) {
+ setStatus(QDeclarativeGeocodeModel::Loading);
+ reply_ = geocodingManager->geocode(address_->address(), boundingArea_);
+ if (reply_->isFinished()) {
+ if (reply_->error() == QGeoCodeReply::NoError) {
+ geocodeFinished(reply_);
+ } else {
+ geocodeError(reply_, reply_->error(), reply_->errorString());
+ }
+ }
+ } else if (!searchString_.isEmpty()) {
+ setStatus(QDeclarativeGeocodeModel::Loading);
+ reply_ = geocodingManager->geocode(searchString_, limit_, offset_, boundingArea_);
+ if (reply_->isFinished()) {
+ if (reply_->error() == QGeoCodeReply::NoError) {
+ geocodeFinished(reply_);
+ } else {
+ geocodeError(reply_, reply_->error(), reply_->errorString());
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::abortRequest()
+{
+ if (reply_) {
+ reply_->abort();
+ reply_->deleteLater();
+ reply_ = 0;
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::queryContentChanged()
+{
+ if (autoUpdate_)
+ update();
+}
+
+/*!
+ \internal
+ From QAbstractListModel
+*/
+int QDeclarativeGeocodeModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return declarativeLocations_.count();
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeGeocodeModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+ if (index.row() >= declarativeLocations_.count())
+ return QVariant();
+ if (role == QDeclarativeGeocodeModel::LocationRole) {
+ QObject *locationObject = declarativeLocations_.at(index.row());
+ Q_ASSERT(locationObject);
+ return QVariant::fromValue(locationObject);
+ }
+ return QVariant();
+}
+
+QHash<int, QByteArray> QDeclarativeGeocodeModel::roleNames() const
+{
+ QHash<int, QByteArray> roleNames = QAbstractItemModel::roleNames();
+ roleNames.insert(LocationRole, "locationData");
+ return roleNames;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (plugin_ == plugin)
+ return;
+
+ reset(); // reset the model
+ plugin_ = plugin;
+ if (complete_)
+ emit pluginChanged();
+
+ if (!plugin)
+ return;
+
+ if (plugin_->isAttached()) {
+ pluginReady();
+ } else {
+ connect(plugin_, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::pluginReady()
+{
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ QGeoCodingManager *geocodingManager = serviceProvider->geocodingManager();
+
+ if (serviceProvider->error() != QGeoServiceProvider::NoError) {
+ QDeclarativeGeocodeModel::GeocodeError newError = UnknownError;
+ switch (serviceProvider->error()) {
+ case QGeoServiceProvider::NotSupportedError:
+ newError = EngineNotSetError; break;
+ case QGeoServiceProvider::UnknownParameterError:
+ newError = UnknownParameterError; break;
+ case QGeoServiceProvider::MissingRequiredParameterError:
+ newError = MissingRequiredParameterError; break;
+ case QGeoServiceProvider::ConnectionError:
+ newError = CommunicationError; break;
+ default:
+ break;
+ }
+
+ setError(newError, serviceProvider->errorString());
+ return;
+ }
+
+ if (!geocodingManager) {
+ setError(EngineNotSetError,tr("Plugin does not support (reverse) geocoding."));
+ return;
+ }
+
+ connect(geocodingManager, SIGNAL(finished(QGeoCodeReply*)),
+ this, SLOT(geocodeFinished(QGeoCodeReply*)));
+ connect(geocodingManager, SIGNAL(error(QGeoCodeReply*,QGeoCodeReply::Error,QString)),
+ this, SLOT(geocodeError(QGeoCodeReply*,QGeoCodeReply::Error,QString)));
+}
+
+/*!
+ \qmlproperty Plugin QtLocation::GeocodeModel::plugin
+
+ This property holds the plugin that provides the actual geocoding service.
+ Note that all plugins do not necessarily provide geocoding (could for example provide
+ only routing or maps).
+
+ \sa Plugin
+*/
+
+QDeclarativeGeoServiceProvider *QDeclarativeGeocodeModel::plugin() const
+{
+ return plugin_;
+}
+
+void QDeclarativeGeocodeModel::setBounds(const QVariant &boundingArea)
+{
+ QGeoShape s;
+
+ if (boundingArea.userType() == qMetaTypeId<QGeoRectangle>())
+ s = boundingArea.value<QGeoRectangle>();
+ else if (boundingArea.userType() == qMetaTypeId<QGeoCircle>())
+ s = boundingArea.value<QGeoCircle>();
+ else if (boundingArea.userType() == qMetaTypeId<QGeoShape>())
+ s = boundingArea.value<QGeoShape>();
+
+
+ if (boundingArea_ == s)
+ return;
+
+ boundingArea_ = s;
+ emit boundsChanged();
+}
+
+/*!
+ \qmlproperty geoshape QtLocation::GeocodeModel::bounds
+
+ This property holds the bounding area used to limit the results to those
+ within the area. This is particularly useful if query is only partially filled out,
+ as the service will attempt to (reverse) geocode all matches for the specified data.
+
+ Accepted types are \l {georectangle} and
+ \l {geocircle}.
+*/
+QVariant QDeclarativeGeocodeModel::bounds() const
+{
+ if (boundingArea_.type() == QGeoShape::RectangleType)
+ return QVariant::fromValue(QGeoRectangle(boundingArea_));
+ else if (boundingArea_.type() == QGeoShape::CircleType)
+ return QVariant::fromValue(QGeoCircle(boundingArea_));
+ else
+ return QVariant::fromValue(boundingArea_);
+}
+
+void QDeclarativeGeocodeModel::geocodeFinished(QGeoCodeReply *reply)
+{
+ if (reply != reply_ || reply->error() != QGeoCodeReply::NoError)
+ return;
+ int oldCount = declarativeLocations_.count();
+ setLocations(reply->locations());
+ setError(NoError, QString());
+ setStatus(QDeclarativeGeocodeModel::Ready);
+ reply->deleteLater();
+ reply_ = 0;
+ emit locationsChanged();
+ if (oldCount != declarativeLocations_.count())
+ emit countChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::geocodeError(QGeoCodeReply *reply,
+ QGeoCodeReply::Error error,
+ const QString &errorString)
+{
+ if (reply != reply_)
+ return;
+ Q_UNUSED(error);
+ int oldCount = declarativeLocations_.count();
+ if (oldCount > 0) {
+ // Reset the model
+ setLocations(reply->locations());
+ emit locationsChanged();
+ emit countChanged();
+ }
+ setError(static_cast<QDeclarativeGeocodeModel::GeocodeError>(error), errorString);
+ setStatus(QDeclarativeGeocodeModel::Error);
+ reply->deleteLater();
+ reply_ = 0;
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::GeocodeModel::status
+
+ This read-only property holds the current status of the model.
+
+ \list
+ \li GeocodeModel.Null - No geocode requests have been issued or \l reset has been called.
+ \li GeocodeModel.Ready - Geocode request(s) have finished successfully.
+ \li GeocodeModel.Loading - Geocode request has been issued but not yet finished
+ \li GeocodeModel.Error - Geocoding error has occurred, details are in \l error and \l errorString
+ \endlist
+*/
+
+QDeclarativeGeocodeModel::Status QDeclarativeGeocodeModel::status() const
+{
+ return status_;
+}
+
+void QDeclarativeGeocodeModel::setStatus(QDeclarativeGeocodeModel::Status status)
+{
+ if (status_ == status)
+ return;
+ status_ = status;
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::GeocodeModel::error
+
+ This read-only property holds the latest error value of the geocoding request.
+
+ \list
+ \li GeocodeModel.NoError - No error has occurred.
+ \li GeocodeModel.CombinationError - An error occurred while results where being combined from multiple sources.
+ \li GeocodeModel.CommunicationError - An error occurred while communicating with the service provider.
+ \li GeocodeModel.EngineNotSetError - The model's plugin property was not set or there is no geocoding manager associated with the plugin.
+ \li GeocodeModel.MissingRequiredParameterError - A required parameter was not specified.
+ \li GeocodeModel.ParseError - The response from the service provider was in an unrecognizable format.
+ \li GeocodeModel.UnknownError - An error occurred which does not fit into any of the other categories.
+ \li GeocodeModel.UnknownParameterError - The plugin did not recognize one of the parameters it was given.
+ \li GeocodeModel.UnsupportedOptionError - The requested operation is not supported by the geocoding provider.
+ This may happen when the loaded engine does not support a particular geocoding request
+ such as reverse geocoding.
+ \endlist
+*/
+
+QDeclarativeGeocodeModel::GeocodeError QDeclarativeGeocodeModel::error() const
+{
+ return error_;
+}
+
+void QDeclarativeGeocodeModel::setError(GeocodeError error, const QString &errorString)
+{
+ if (error_ == error && errorString_ == errorString)
+ return;
+ error_ = error;
+ errorString_ = errorString;
+ emit errorChanged();
+}
+
+/*!
+ \qmlproperty string QtLocation::GeocodeModel::errorString
+
+ This read-only property holds the textual presentation of the latest geocoding error.
+ If no error has occurred or the model has been reset, an empty string is returned.
+
+ An empty string may also be returned if an error occurred which has no associated
+ textual representation.
+*/
+
+QString QDeclarativeGeocodeModel::errorString() const
+{
+ return errorString_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeocodeModel::setLocations(const QList<QGeoLocation> &locations)
+{
+ beginResetModel();
+ qDeleteAll(declarativeLocations_);
+ declarativeLocations_.clear();
+ for (int i = 0; i < locations.count(); ++i) {
+ QDeclarativeGeoLocation *location = new QDeclarativeGeoLocation(locations.at(i), this);
+ declarativeLocations_.append(location);
+ }
+ endResetModel();
+}
+
+/*!
+ \qmlproperty int QtLocation::GeocodeModel::count
+
+ This property holds how many locations the model currently has.
+ Amongst other uses, you can use this value when accessing locations
+ via the GeocodeModel::get -method.
+*/
+
+int QDeclarativeGeocodeModel::count() const
+{
+ return declarativeLocations_.count();
+}
+
+/*!
+ \qmlmethod Location QtLocation::GeocodeModel::get(int)
+
+ Returns the Location at given index. Use \l count property to check the
+ amount of locations available. The locations are indexed from zero, so the accessible range
+ is 0...(count - 1).
+
+ If you access out of bounds, a zero (null object) is returned and a warning is issued.
+*/
+
+QDeclarativeGeoLocation *QDeclarativeGeocodeModel::get(int index)
+{
+ if (index < 0 || index >= declarativeLocations_.count()) {
+ qmlWarning(this) << QStringLiteral("Index '%1' out of range").arg(index);
+ return 0;
+ }
+ return declarativeLocations_.at(index);
+}
+
+/*!
+ \qmlproperty int QtLocation::GeocodeModel::limit
+
+ This property holds the maximum number of results. The limit and \l offset values are only
+ applicable with free string geocoding (that is they are not considered when using addresses
+ or coordinates in the search query).
+
+ If limit is -1 the entire result set will be returned, otherwise at most limit results will be
+ returned. The limit and \l offset results can be used together to implement paging.
+*/
+
+int QDeclarativeGeocodeModel::limit() const
+{
+ return limit_;
+}
+
+void QDeclarativeGeocodeModel::setLimit(int limit)
+{
+ if (limit == limit_)
+ return;
+ limit_ = limit;
+ if (autoUpdate_) {
+ update();
+ }
+ emit limitChanged();
+}
+
+/*!
+ \qmlproperty int QtLocation::GeocodeModel::offset
+
+ This property tells not to return the first 'offset' number of the results. The \l limit and
+ offset values are only applicable with free string geocoding (that is they are not considered
+ when using addresses or coordinates in the search query).
+
+ The \l limit and offset results can be used together to implement paging.
+*/
+
+int QDeclarativeGeocodeModel::offset() const
+{
+ return offset_;
+}
+
+void QDeclarativeGeocodeModel::setOffset(int offset)
+{
+ if (offset == offset_)
+ return;
+ offset_ = offset;
+ if (autoUpdate_) {
+ update();
+ }
+ emit offsetChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::GeocodeModel::reset()
+
+ Resets the model. All location data is cleared, any outstanding requests
+ are aborted and possible errors are cleared. Model status will be set
+ to GeocodeModel.Null
+*/
+
+void QDeclarativeGeocodeModel::reset()
+{
+ beginResetModel();
+ if (!declarativeLocations_.isEmpty()) {
+ setLocations(QList<QGeoLocation>());
+ emit countChanged();
+ }
+ endResetModel();
+
+ abortRequest();
+ setError(NoError, QString());
+ setStatus(QDeclarativeGeocodeModel::Null);
+}
+
+/*!
+ \qmlmethod void QtLocation::GeocodeModel::cancel()
+
+ Cancels any outstanding requests and clears errors. Model status will be set to either
+ GeocodeModel.Null or GeocodeModel.Ready.
+*/
+void QDeclarativeGeocodeModel::cancel()
+{
+ abortRequest();
+ setError(NoError, QString());
+ setStatus(declarativeLocations_.isEmpty() ? Null : Ready);
+}
+
+/*!
+ \qmlproperty QVariant QtLocation::GeocodeModel::query
+
+ This property holds the data of the geocoding request.
+ The property accepts three types of queries which determine both the data and
+ the type of action to be performed:
+
+ \list
+ \li Address - Geocoding (address to coordinate)
+ \li \l {coordinate} - Reverse geocoding (coordinate to address)
+ \li string - Geocoding (address to coordinate)
+ \endlist
+*/
+
+QVariant QDeclarativeGeocodeModel::query() const
+{
+ return queryVariant_;
+}
+
+void QDeclarativeGeocodeModel::setQuery(const QVariant &query)
+{
+ if (query == queryVariant_)
+ return;
+
+ if (query.userType() == qMetaTypeId<QGeoCoordinate>()) {
+ if (address_) {
+ address_->disconnect(this);
+ address_ = 0;
+ }
+ searchString_.clear();
+
+ coordinate_ = query.value<QGeoCoordinate>();
+ } else if (query.type() == QVariant::String) {
+ searchString_ = query.toString();
+ if (address_) {
+ address_->disconnect(this);
+ address_ = 0;
+ }
+ coordinate_ = QGeoCoordinate();
+ } else if (QObject *object = query.value<QObject *>()) {
+ if (QDeclarativeGeoAddress *address = qobject_cast<QDeclarativeGeoAddress *>(object)) {
+ if (address_)
+ address_->disconnect(this);
+ coordinate_ = QGeoCoordinate();
+ searchString_.clear();
+
+ address_ = address;
+ connect(address_, SIGNAL(countryChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(countryCodeChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(stateChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(countyChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(cityChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(districtChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(streetChanged()), this, SLOT(queryContentChanged()));
+ connect(address_, SIGNAL(postalCodeChanged()), this, SLOT(queryContentChanged()));
+ } else {
+ qmlWarning(this) << QStringLiteral("Unsupported query type for geocode model ")
+ << QStringLiteral("(coordinate, string and Address supported).");
+ return;
+ }
+ } else {
+ qmlWarning(this) << QStringLiteral("Unsupported query type for geocode model ")
+ << QStringLiteral("(coordinate, string and Address supported).");
+ return;
+ }
+
+ queryVariant_ = query;
+ emit queryChanged();
+ if (autoUpdate_)
+ update();
+}
+
+/*!
+ \qmlproperty bool QtLocation::GeocodeModel::autoUpdate
+
+ This property controls whether the Model automatically updates in response
+ to changes in its attached query. The default value of this property
+ is false.
+
+ If setting this value to 'true' and using an Address or
+ \l {coordinate} as the query, note that any change at all in the
+ object's properties will trigger a new request to be sent. If you are adjusting many
+ properties of the object whilst autoUpdate is enabled, this can generate large numbers of
+ useless (and later discarded) requests.
+*/
+
+bool QDeclarativeGeocodeModel::autoUpdate() const
+{
+ return autoUpdate_;
+}
+
+void QDeclarativeGeocodeModel::setAutoUpdate(bool update)
+{
+ if (autoUpdate_ == update)
+ return;
+ autoUpdate_ = update;
+ emit autoUpdateChanged();
+}
+
+#include "moc_qdeclarativegeocodemodel_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeocodemodel_p.h b/src/location/declarativemaps/qdeclarativegeocodemodel_p.h
new file mode 100644
index 00000000..6c8f533b
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeocodemodel_p.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOCODEMODEL_H
+#define QDECLARATIVEGEOCODEMODEL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
+
+#include <QtLocation/qgeocodereply.h>
+#include <QtPositioning/private/qdeclarativegeoaddress_p.h>
+#include <QtPositioning/private/qdeclarativegeolocation_p.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlParserStatus>
+#include <QAbstractListModel>
+#include <QPointer>
+
+
+QT_BEGIN_NAMESPACE
+
+class QGeoServiceProvider;
+class QGeoCodingManager;
+class QDeclarativeGeoLocation;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeocodeModel : public QAbstractListModel, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+ Q_ENUMS(GeocodeError)
+
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(bool autoUpdate READ autoUpdate WRITE setAutoUpdate NOTIFY autoUpdateChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged)
+ Q_PROPERTY(int offset READ offset WRITE setOffset NOTIFY offsetChanged)
+ Q_PROPERTY(QVariant query READ query WRITE setQuery NOTIFY queryChanged)
+ Q_PROPERTY(QVariant bounds READ bounds WRITE setBounds NOTIFY boundsChanged)
+ Q_PROPERTY(GeocodeError error READ error NOTIFY errorChanged)
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ enum Status {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ enum GeocodeError {
+ NoError = QGeoCodeReply::NoError,
+ EngineNotSetError = QGeoCodeReply::EngineNotSetError, //TODO Qt6 consider merge with NotSupportedError
+ CommunicationError = QGeoCodeReply::CommunicationError, //TODO Qt6 merge with Map's ConnectionError
+ ParseError = QGeoCodeReply::ParseError,
+ UnsupportedOptionError = QGeoCodeReply::UnsupportedOptionError, //TODO Qt6 consider rename UnsupportedOperationError
+ CombinationError = QGeoCodeReply::CombinationError,
+ UnknownError = QGeoCodeReply::UnknownError,
+ //we leave gap for future QGeoCodeReply errors
+
+ //QGeoServiceProvider related errors start here
+ UnknownParameterError = 100,
+ MissingRequiredParameterError
+ };
+
+ enum Roles {
+ LocationRole = Qt::UserRole + 1
+ };
+
+ explicit QDeclarativeGeocodeModel(QObject *parent = 0);
+ virtual ~QDeclarativeGeocodeModel();
+
+ // From QQmlParserStatus
+ virtual void classBegin() {}
+ virtual void componentComplete();
+
+ // From QAbstractListModel
+ virtual int rowCount(const QModelIndex &parent) const;
+ virtual QVariant data(const QModelIndex &index, int role) const;
+ virtual QHash<int,QByteArray> roleNames() const;
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ void setBounds(const QVariant &boundingArea);
+ QVariant bounds() const;
+
+ Status status() const;
+ QString errorString() const;
+ GeocodeError error() const;
+
+ bool autoUpdate() const;
+ void setAutoUpdate(bool update);
+
+ int count() const;
+ Q_INVOKABLE QDeclarativeGeoLocation *get(int index);
+
+ int limit() const;
+ void setLimit(int limit);
+ int offset() const;
+ void setOffset(int offset);
+
+ QVariant query() const;
+ void setQuery(const QVariant &query);
+ Q_INVOKABLE void reset();
+ Q_INVOKABLE void cancel();
+
+Q_SIGNALS:
+ void countChanged();
+ void pluginChanged();
+ void statusChanged();
+ void errorChanged(); //emitted also for errorString notification
+ void locationsChanged();
+ void autoUpdateChanged();
+ void boundsChanged();
+ void queryChanged();
+ void limitChanged();
+ void offsetChanged();
+
+public Q_SLOTS:
+ void update();
+
+protected Q_SLOTS:
+ void queryContentChanged();
+ void geocodeFinished(QGeoCodeReply *reply);
+ void geocodeError(QGeoCodeReply *reply,
+ QGeoCodeReply::Error error,
+ const QString &errorString);
+ void pluginReady();
+
+protected:
+ QGeoCodingManager *searchManager();
+ void setStatus(Status status);
+ void setError(GeocodeError error, const QString &errorString);
+ bool autoUpdate_;
+ bool complete_;
+
+private:
+ void setLocations(const QList<QGeoLocation> &locations);
+ void abortRequest();
+ QGeoCodeReply *reply_;
+
+ QDeclarativeGeoServiceProvider *plugin_;
+ QGeoShape boundingArea_;
+
+ QList<QDeclarativeGeoLocation *> declarativeLocations_;
+
+ Status status_;
+ QString errorString_;
+ GeocodeError error_;
+ QVariant queryVariant_;
+ QGeoCoordinate coordinate_;
+ QDeclarativeGeoAddress *address_;
+ QString searchString_;
+
+ int limit_;
+ int offset_;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomaneuver.cpp b/src/location/declarativemaps/qdeclarativegeomaneuver.cpp
new file mode 100644
index 00000000..72c38865
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaneuver.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomaneuver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RouteManeuver
+ \instantiates QDeclarativeGeoManeuver
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The RouteManeuver type represents the information relevant to the
+ point at which two RouteSegments meet.
+
+ RouteSegment instances can be thought of as edges on a routing
+ graph, with RouteManeuver instances as optional labels attached to the
+ vertices of the graph.
+
+ The most interesting information held in a RouteManeuver instance is
+ normally the textual navigation to provide and the position at which to
+ provide it, accessible by \l instructionText and \l position respectively.
+
+ \section1 Example
+
+ The following QML snippet demonstrates how to print information about a
+ route maneuver:
+
+ \snippet declarative/routing.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/routing.qml RouteManeuver
+*/
+
+QDeclarativeGeoManeuver::QDeclarativeGeoManeuver(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QDeclarativeGeoManeuver::QDeclarativeGeoManeuver(const QGeoManeuver &maneuver, QObject *parent)
+ : QObject(parent),
+ maneuver_(maneuver)
+{
+}
+
+QDeclarativeGeoManeuver::~QDeclarativeGeoManeuver() {}
+
+/*!
+ \qmlproperty bool RouteManeuver::valid
+
+ This read-only property holds whether this maneuver is valid or not.
+
+ Invalid maneuvers are used when there is no information
+ that needs to be attached to the endpoint of a QGeoRouteSegment instance.
+*/
+
+bool QDeclarativeGeoManeuver::valid() const
+{
+ return maneuver_.isValid();
+}
+
+/*!
+ \qmlproperty coordinate RouteManeuver::position
+
+ This read-only property holds where the \l instructionText should be displayed.
+
+*/
+
+QGeoCoordinate QDeclarativeGeoManeuver::position() const
+{
+ return maneuver_.position();
+}
+
+/*!
+ \qmlproperty string RouteManeuver::instructionText
+
+ This read-only property holds textual navigation instruction.
+*/
+
+QString QDeclarativeGeoManeuver::instructionText() const
+{
+ return maneuver_.instructionText();
+}
+
+/*!
+ \qmlproperty enumeration RouteManeuver::direction
+
+ Describes the change in direction associated with the instruction text
+ that is associated with a RouteManeuver.
+
+ \list
+ \li RouteManeuver.NoDirection - There is no direction associated with the instruction text
+ \li RouteManeuver.DirectionForward - The instruction indicates that the direction of travel does not need to change
+ \li RouteManeuver.DirectionBearRight - The instruction indicates that the direction of travel should bear to the right
+ \li RouteManeuver.DirectionLightRight - The instruction indicates that a light turn to the right is required
+ \li RouteManeuver.DirectionRight - The instruction indicates that a turn to the right is required
+ \li RouteManeuver.DirectionHardRight - The instruction indicates that a hard turn to the right is required
+ \li RouteManeuver.DirectionUTurnRight - The instruction indicates that a u-turn to the right is required
+ \li RouteManeuver.DirectionUTurnLeft - The instruction indicates that a u-turn to the left is required
+ \li RouteManeuver.DirectionHardLeft - The instruction indicates that a hard turn to the left is required
+ \li RouteManeuver.DirectionLeft - The instruction indicates that a turn to the left is required
+ \li RouteManeuver.DirectionLightLeft - The instruction indicates that a light turn to the left is required
+ \li RouteManeuver.DirectionBearLeft - The instruction indicates that the direction of travel should bear to the left
+ \endlist
+*/
+
+QDeclarativeGeoManeuver::Direction QDeclarativeGeoManeuver::direction() const
+{
+ return QDeclarativeGeoManeuver::Direction(maneuver_.direction());
+}
+
+/*!
+ \qmlproperty int RouteManeuver::timeToNextInstruction
+
+ This read-only property holds the estimated time it will take to travel
+ from the point at which the associated instruction was issued and the
+ point that the next instruction should be issued, in seconds.
+*/
+
+int QDeclarativeGeoManeuver::timeToNextInstruction() const
+{
+ return maneuver_.timeToNextInstruction();
+}
+
+/*!
+ \qmlproperty real RouteManeuver::distanceToNextInstruction
+
+ This read-only property holds the distance, in meters, between the point at which
+ the associated instruction was issued and the point that the next instruction should
+ be issued.
+*/
+
+qreal QDeclarativeGeoManeuver::distanceToNextInstruction() const
+{
+ return maneuver_.distanceToNextInstruction();
+}
+
+/*!
+ \qmlproperty coordinate RouteManeuver::waypoint
+
+ This property holds the waypoint associated with this maneuver.
+ All maneuvers do not have a waypoint associated with them, this
+ can be checked with \l waypointValid.
+
+*/
+
+QGeoCoordinate QDeclarativeGeoManeuver::waypoint() const
+{
+ return maneuver_.waypoint();
+}
+
+/*!
+ \qmlproperty bool RouteManeuver::waypointValid
+
+ This read-only property holds whether this \l waypoint, associated with this
+ maneuver, is valid or not.
+*/
+
+bool QDeclarativeGeoManeuver::waypointValid() const
+{
+ return maneuver_.waypoint().isValid();
+}
+
+#include "moc_qdeclarativegeomaneuver_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomaneuver_p.h b/src/location/declarativemaps/qdeclarativegeomaneuver_p.h
new file mode 100644
index 00000000..0e957a1f
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaneuver_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMANEUVER_H
+#define QDECLARATIVEGEOMANEUVER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/qgeomaneuver.h>
+
+#include <QtPositioning/QGeoCoordinate>
+
+#include <QObject>
+
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoManeuver : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(Direction)
+
+ Q_PROPERTY(bool valid READ valid CONSTANT)
+ Q_PROPERTY(QGeoCoordinate position READ position CONSTANT)
+ Q_PROPERTY(QString instructionText READ instructionText CONSTANT)
+ Q_PROPERTY(Direction direction READ direction CONSTANT)
+ Q_PROPERTY(int timeToNextInstruction READ timeToNextInstruction CONSTANT)
+ Q_PROPERTY(qreal distanceToNextInstruction READ distanceToNextInstruction CONSTANT)
+ Q_PROPERTY(QGeoCoordinate waypoint READ waypoint CONSTANT)
+ Q_PROPERTY(bool waypointValid READ waypointValid CONSTANT)
+
+public:
+ enum Direction {
+ NoDirection = QGeoManeuver::NoDirection,
+ DirectionForward = QGeoManeuver::DirectionForward,
+ DirectionBearRight = QGeoManeuver::DirectionBearRight,
+ DirectionLightRight = QGeoManeuver::DirectionLightRight,
+ DirectionRight = QGeoManeuver::DirectionRight,
+ DirectionHardRight = QGeoManeuver::DirectionHardRight,
+ DirectionUTurnRight = QGeoManeuver::DirectionUTurnRight,
+ DirectionUTurnLeft = QGeoManeuver::DirectionUTurnLeft,
+ DirectionHardLeft = QGeoManeuver::DirectionHardLeft,
+ DirectionLeft = QGeoManeuver::DirectionLeft,
+ DirectionLightLeft = QGeoManeuver::DirectionLightLeft,
+ DirectionBearLeft = QGeoManeuver::DirectionBearLeft
+ };
+
+ explicit QDeclarativeGeoManeuver(QObject *parent = 0);
+ QDeclarativeGeoManeuver(const QGeoManeuver &maneuver, QObject *parent = 0);
+ ~QDeclarativeGeoManeuver();
+
+ bool valid() const;
+ bool waypointValid() const;
+
+ QGeoCoordinate position() const;
+ QString instructionText() const;
+ Direction direction() const;
+ int timeToNextInstruction() const;
+ qreal distanceToNextInstruction() const;
+ QGeoCoordinate waypoint() const;
+
+private:
+ QGeoManeuver maneuver_;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp
new file mode 100644
index 00000000..15d802e6
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomap.cpp
@@ -0,0 +1,1822 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomap_p.h"
+#include "qdeclarativegeomapquickitem_p.h"
+#include "qdeclarativegeomapcopyrightsnotice_p.h"
+#include "qdeclarativegeoserviceprovider_p.h"
+#include "qdeclarativegeomaptype_p.h"
+#include "qgeomappingmanager_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qgeomap_p.h"
+#include "qdeclarativegeomapparameter_p.h"
+#include <QtPositioning/QGeoCircle>
+#include <QtPositioning/QGeoRectangle>
+#include <QtQuick/QQuickWindow>
+#include <QtQuick/QSGRectangleNode>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQml/qqmlinfo.h>
+#include <cmath>
+
+#ifndef M_PI
+#define M_PI 3.141592653589793238463
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Map
+ \instantiates QDeclarativeGeoMap
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+
+ \brief The Map type displays a map.
+
+ The Map type is used to display a map or image of the Earth, with
+ the capability to also display interactive objects tied to the map's
+ surface.
+
+ There are a variety of different ways to visualize the Earth's surface
+ in a 2-dimensional manner, but all of them involve some kind of projection:
+ a mathematical relationship between the 3D coordinates (latitude, longitude
+ and altitude) and 2D coordinates (X and Y in pixels) on the screen.
+
+ Different sources of map data can use different projections, and from the
+ point of view of the Map type, we treat these as one replaceable unit:
+ the Map plugin. A Map plugin consists of a data source, as well as all other
+ details needed to display its data on-screen.
+
+ The current Map plugin in use is contained in the \l plugin property of
+ the Map item. In order to display any image in a Map item, you will need
+ to set this property. See the \l Plugin type for a description of how
+ to retrieve an appropriate plugin for use.
+
+ The geographic region displayed in the Map item is referred to as its
+ viewport, and this is defined by the properties \l center, and
+ \l zoomLevel. The \l center property contains a \l {coordinate}
+ specifying the center of the viewport, while \l zoomLevel controls the scale of the
+ map. See each of these properties for further details about their values.
+
+ When the map is displayed, each possible geographic coordinate that is
+ visible will map to some pixel X and Y coordinate on the screen. To perform
+ conversions between these two, Map provides the \l toCoordinate and
+ \l fromCoordinate functions, which are of general utility.
+
+ \section2 Map Objects
+
+ Map related objects can be declared within the body of a Map object in Qt Quick and will
+ automatically appear on the Map. To add objects programmatically, first be
+ sure they are created with the Map as their parent (for example in an argument to
+ Component::createObject), and then call the \l addMapItem method on the Map.
+ A corresponding \l removeMapItem method also exists to do the opposite and
+ remove an object from the Map.
+
+ Moving Map objects around, resizing them or changing their shape normally
+ does not involve any special interaction with Map itself -- changing these
+ details about a map object will automatically update the display.
+
+ \section2 Interaction
+
+ The Map type includes support for pinch and flick gestures to control
+ zooming and panning. These are enabled by default, and available at any
+ time by using the \l gesture object. The actual GestureArea is constructed
+ specially at startup and cannot be replaced or destroyed. Its properties
+ can be altered, however, to control its behavior.
+
+ \section2 Performance
+
+ Maps are rendered using OpenGL (ES) and the Qt Scene Graph stack, and as
+ a result perform quite well where GL accelerated hardware is available.
+
+ For "online" Map plugins, network bandwidth and latency can be major
+ contributors to the user's perception of performance. Extensive caching is
+ performed to mitigate this, but such mitigation is not always perfect. For
+ "offline" plugins, the time spent retrieving the stored geographic data
+ and rendering the basic map features can often play a dominant role. Some
+ offline plugins may use hardware acceleration themselves to (partially)
+ avert this.
+
+ In general, large and complex Map items such as polygons and polylines with
+ large numbers of vertices can have an adverse effect on UI performance.
+ Further, more detailed notes on this are in the documentation for each
+ map item type.
+
+ \section2 Example Usage
+
+ The following snippet shows a simple Map and the necessary Plugin type
+ to use it. The map is centered over Oslo, Norway, with zoom level 10.
+
+ \quotefromfile minimal_map/main.qml
+ \skipto import
+ \printuntil }
+ \printline }
+ \skipto Map
+ \printuntil }
+ \printline }
+
+ \image minimal_map.png
+*/
+
+/*!
+ \qmlsignal QtLocation::Map::copyrightLinkActivated(string link)
+
+ This signal is emitted when the user clicks on a \a link in the copyright notice. The
+ application should open the link in a browser or display its contents to the user.
+*/
+
+static const qreal EARTH_MEAN_RADIUS = 6371007.2;
+
+QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent)
+ : QQuickItem(parent),
+ m_plugin(0),
+ m_mappingManager(0),
+ m_activeMapType(0),
+ m_gestureArea(new QQuickGeoMapGestureArea(this)),
+ m_map(0),
+ m_error(QGeoServiceProvider::NoError),
+ m_color(QColor::fromRgbF(0.9, 0.9, 0.9)),
+ m_componentCompleted(false),
+ m_pendingFitViewport(false),
+ m_copyrightsVisible(true),
+ m_maximumViewportLatitude(0.0),
+ m_initialized(false)
+{
+ setAcceptHoverEvents(false);
+ setAcceptedMouseButtons(Qt::LeftButton);
+ setFlags(QQuickItem::ItemHasContents | QQuickItem::ItemClipsChildrenToShape);
+ setFiltersChildMouseEvents(true);
+
+ connect(this, SIGNAL(childrenChanged()), this, SLOT(onMapChildrenChanged()), Qt::QueuedConnection);
+
+ m_activeMapType = new QDeclarativeGeoMapType(QGeoMapType(QGeoMapType::NoMap,
+ tr("No Map"),
+ tr("No Map"), false, false, 0), this);
+ m_cameraData.setCenter(QGeoCoordinate(51.5073,-0.1277)); //London city center
+ m_cameraData.setZoomLevel(8.0);
+}
+
+QDeclarativeGeoMap::~QDeclarativeGeoMap()
+{
+ if (!m_mapViews.isEmpty())
+ qDeleteAll(m_mapViews);
+ // remove any map items associations
+ for (int i = 0; i < m_mapItems.count(); ++i) {
+ if (m_mapItems.at(i))
+ m_mapItems.at(i).data()->setMap(0,0);
+ }
+ m_mapItems.clear();
+
+ delete m_copyrights.data();
+ m_copyrights.clear();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::onMapChildrenChanged()
+{
+ if (!m_componentCompleted || !m_map)
+ return;
+
+ int maxChildZ = 0;
+ QObjectList kids = children();
+ bool foundCopyrights = false;
+
+ for (int i = 0; i < kids.size(); ++i) {
+ QDeclarativeGeoMapCopyrightNotice *copyrights = qobject_cast<QDeclarativeGeoMapCopyrightNotice *>(kids.at(i));
+ if (copyrights) {
+ foundCopyrights = true;
+ } else {
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(kids.at(i));
+ if (mapItem) {
+ if (mapItem->z() > maxChildZ)
+ maxChildZ = mapItem->z();
+ }
+ }
+ }
+
+ QDeclarativeGeoMapCopyrightNotice *copyrights = m_copyrights.data();
+ // if copyrights object not found within the map's children
+ if (!foundCopyrights) {
+ // if copyrights object was deleted!
+ if (!copyrights) {
+ // create a new one and set its parent, re-assign it to the weak pointer, then connect the copyrights-change signal
+ m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this);
+ copyrights = m_copyrights.data();
+ connect(m_map, SIGNAL(copyrightsChanged(QImage)),
+ copyrights, SLOT(copyrightsChanged(QImage)));
+ connect(m_map, SIGNAL(copyrightsChanged(QString)),
+ copyrights, SLOT(copyrightsChanged(QString)));
+ connect(copyrights, SIGNAL(linkActivated(QString)),
+ this, SIGNAL(copyrightLinkActivated(QString)));
+
+ // set visibility of copyright notice
+ copyrights->setCopyrightsVisible(m_copyrightsVisible);
+
+ } else {
+ // just re-set its parent.
+ copyrights->setParent(this);
+ }
+ }
+
+ // put the copyrights notice object at the highest z order
+ copyrights->setCopyrightsZ(maxChildZ + 1);
+}
+
+static QDeclarativeGeoMapType *findMapType(const QList<QDeclarativeGeoMapType *> &types, const QGeoMapType &type)
+{
+ for (int i = 0; i < types.size(); ++i)
+ if (types[i]->mapType() == type)
+ return types[i];
+ return Q_NULLPTR;
+}
+
+void QDeclarativeGeoMap::onSupportedMapTypesChanged()
+{
+ QList<QDeclarativeGeoMapType *> supportedMapTypes;
+ QList<QGeoMapType> types = m_mappingManager->supportedMapTypes();
+ for (int i = 0; i < types.size(); ++i) {
+ // types that are present and get removed will be deleted at QObject destruction
+ QDeclarativeGeoMapType *type = findMapType(m_supportedMapTypes, types[i]);
+ if (!type)
+ type = new QDeclarativeGeoMapType(types[i], this);
+ supportedMapTypes.append(type);
+ }
+ m_supportedMapTypes.swap(supportedMapTypes);
+ if (m_supportedMapTypes.isEmpty()) {
+ m_map->setActiveMapType(QGeoMapType()); // no supported map types: setting an invalid one
+ } else {
+ bool hasMapType = false;
+ foreach (QDeclarativeGeoMapType *declarativeType, m_supportedMapTypes) {
+ if (declarativeType->mapType() == m_map->activeMapType())
+ hasMapType = true;
+ }
+ if (!hasMapType) {
+ QDeclarativeGeoMapType *type = m_supportedMapTypes.at(0);
+ m_activeMapType = type;
+ m_map->setActiveMapType(type->mapType());
+ }
+ }
+
+ emit supportedMapTypesChanged();
+}
+
+void QDeclarativeGeoMap::setError(QGeoServiceProvider::Error error, const QString &errorString)
+{
+ if (m_error == error && m_errorString == errorString)
+ return;
+ m_error = error;
+ m_errorString = errorString;
+ emit errorChanged();
+}
+
+void QDeclarativeGeoMap::initialize()
+{
+ // try to keep change signals in the end
+ bool centerHasChanged = false;
+ bool bearingHasChanged = false;
+ bool tiltHasChanged = false;
+ bool fovHasChanged = false;
+ bool minTiltHasChanged = false;
+ bool maxTiltHasChanged = false;
+ bool minFovHasChanged = false;
+ bool maxFovHasChanged = false;
+
+ QGeoCoordinate center = m_cameraData.center();
+
+ setMinimumZoomLevel(m_map->minimumZoom());
+
+ double bearing = m_cameraData.bearing();
+ double tilt = m_cameraData.tilt();
+ double fov = m_cameraData.fieldOfView(); // Must be 45.0
+ if (m_map->cameraCapabilities().minimumFieldOfView() != 1)
+ minFovHasChanged = true;
+ if (m_map->cameraCapabilities().maximumFieldOfView() != 179)
+ maxFovHasChanged = true;
+ if (m_map->cameraCapabilities().minimumTilt() != 0)
+ minTiltHasChanged = true;
+ if (m_map->cameraCapabilities().maximumTilt() != 89)
+ maxTiltHasChanged = true;
+ if (!m_map->cameraCapabilities().supportsBearing() && bearing != 0.0) {
+ m_cameraData.setBearing(0);
+ bearingHasChanged = true;
+ }
+ if (!m_map->cameraCapabilities().supportsTilting() && tilt != 0.0) {
+ m_cameraData.setTilt(0);
+ tiltHasChanged = true;
+ }
+
+ m_cameraData.setFieldOfView(qBound(m_map->cameraCapabilities().minimumFieldOfView(),
+ fov,
+ m_map->cameraCapabilities().maximumFieldOfView()));
+ if (fov != m_cameraData.fieldOfView())
+ fovHasChanged = true;
+
+ // set latitude boundary check
+ m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
+
+ center.setLatitude(qBound(-m_maximumViewportLatitude, center.latitude(), m_maximumViewportLatitude));
+
+ if (center != m_cameraData.center()) {
+ centerHasChanged = true;
+ m_cameraData.setCenter(center);
+ }
+
+ m_map->setCameraData(m_cameraData);
+
+ m_initialized = true;
+
+ if (centerHasChanged)
+ emit centerChanged(m_cameraData.center());
+
+ if (bearingHasChanged)
+ emit bearingChanged(m_cameraData.bearing());
+
+ if (tiltHasChanged)
+ emit tiltChanged(m_cameraData.tilt());
+
+ if (fovHasChanged)
+ emit fieldOfViewChanged(m_cameraData.fieldOfView());
+
+ if (minTiltHasChanged)
+ emit minimumTiltChanged(m_map->cameraCapabilities().minimumTilt());
+
+ if (maxTiltHasChanged)
+ emit maximumTiltChanged(m_map->cameraCapabilities().maximumTilt());
+
+ if (minFovHasChanged)
+ emit minimumFieldOfViewChanged(m_map->cameraCapabilities().minimumFieldOfView());
+
+ if (maxFovHasChanged)
+ emit maximumFieldOfViewChanged(m_map->cameraCapabilities().maximumFieldOfView());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::pluginReady()
+{
+ QGeoServiceProvider *provider = m_plugin->sharedGeoServiceProvider();
+ m_mappingManager = provider->mappingManager();
+
+ if (provider->error() != QGeoServiceProvider::NoError) {
+ setError(provider->error(), provider->errorString());
+ return;
+ }
+
+ if (!m_mappingManager) {
+ //TODO Should really be EngineNotSetError (see QML GeoCodeModel)
+ setError(QGeoServiceProvider::NotSupportedError, tr("Plugin does not support mapping."));
+ return;
+ }
+
+ if (!m_mappingManager->isInitialized())
+ connect(m_mappingManager, SIGNAL(initialized()), this, SLOT(mappingManagerInitialized()));
+ else
+ mappingManagerInitialized();
+
+ // make sure this is only called once
+ disconnect(this, SLOT(pluginReady()));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::componentComplete()
+{
+ m_componentCompleted = true;
+ populateParameters();
+ populateMap();
+ QQuickItem::componentComplete();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::mousePressEvent(QMouseEvent *event)
+{
+ if (isInteractive())
+ m_gestureArea->handleMousePressEvent(event);
+ else
+ QQuickItem::mousePressEvent(event);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::mouseMoveEvent(QMouseEvent *event)
+{
+ if (isInteractive())
+ m_gestureArea->handleMouseMoveEvent(event);
+ else
+ QQuickItem::mouseMoveEvent(event);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (isInteractive()) {
+ m_gestureArea->handleMouseReleaseEvent(event);
+ } else {
+ QQuickItem::mouseReleaseEvent(event);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::mouseUngrabEvent()
+{
+ if (isInteractive())
+ m_gestureArea->handleMouseUngrabEvent();
+ else
+ QQuickItem::mouseUngrabEvent();
+}
+
+void QDeclarativeGeoMap::touchUngrabEvent()
+{
+ if (isInteractive())
+ m_gestureArea->handleTouchUngrabEvent();
+ else
+ QQuickItem::touchUngrabEvent();
+}
+
+/*!
+ \qmlproperty MapGestureArea QtLocation::Map::gesture
+
+ Contains the MapGestureArea created with the Map. This covers pan, flick and pinch gestures.
+ Use \c{gesture.enabled: true} to enable basic gestures, or see \l{MapGestureArea} for
+ further details.
+*/
+
+QQuickGeoMapGestureArea *QDeclarativeGeoMap::gesture()
+{
+ return m_gestureArea;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::populateMap()
+{
+ QObjectList kids = children();
+ QList<QQuickItem *> quickKids = childItems();
+ for (int i=0; i < quickKids.count(); ++i)
+ kids.append(quickKids.at(i));
+
+ for (int i = 0; i < kids.size(); ++i) {
+ // dispatch items appropriately
+ QDeclarativeGeoMapItemView *mapView = qobject_cast<QDeclarativeGeoMapItemView *>(kids.at(i));
+ if (mapView) {
+ m_mapViews.append(mapView);
+ setupMapView(mapView);
+ continue;
+ }
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(kids.at(i));
+ if (mapItem) {
+ addMapItem(mapItem);
+ }
+ }
+}
+
+void QDeclarativeGeoMap::populateParameters()
+{
+ QObjectList kids = children();
+ QList<QQuickItem *> quickKids = childItems();
+ for (int i = 0; i < quickKids.count(); ++i)
+ kids.append(quickKids.at(i));
+ for (int i = 0; i < kids.size(); ++i) {
+ QDeclarativeGeoMapParameter *mapParameter = qobject_cast<QDeclarativeGeoMapParameter *>(kids.at(i));
+ if (mapParameter)
+ addMapParameter(mapParameter);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::setupMapView(QDeclarativeGeoMapItemView *view)
+{
+ Q_UNUSED(view)
+ view->setMap(this);
+ view->repopulate();
+}
+
+/*!
+ * \internal
+ */
+QSGNode *QDeclarativeGeoMap::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ if (!m_map) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGRectangleNode *root = static_cast<QSGRectangleNode *>(oldNode);
+ if (!root)
+ root = window()->createRectangleNode();
+
+ root->setRect(boundingRect());
+ root->setColor(m_color);
+
+ QSGNode *content = root->childCount() ? root->firstChild() : 0;
+ content = m_map->updateSceneGraph(content, window());
+ if (content && root->childCount() == 0)
+ root->appendChildNode(content);
+
+ return root;
+}
+
+/*!
+ \qmlproperty Plugin QtLocation::Map::plugin
+
+ This property holds the plugin which provides the mapping functionality.
+
+ This is a write-once property. Once the map has a plugin associated with
+ it, any attempted modifications of the plugin will be ignored.
+*/
+
+void QDeclarativeGeoMap::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (m_plugin) {
+ qmlWarning(this) << QStringLiteral("Plugin is a write-once property, and cannot be set again.");
+ return;
+ }
+ m_plugin = plugin;
+ emit pluginChanged(m_plugin);
+
+ if (m_plugin->isAttached()) {
+ pluginReady();
+ } else {
+ connect(m_plugin, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+/*!
+ \internal
+ this function will only be ever called once
+*/
+void QDeclarativeGeoMap::mappingManagerInitialized()
+{
+ m_map = m_mappingManager->createMap(this);
+
+ if (!m_map)
+ return;
+
+ m_gestureArea->setMap(m_map);
+
+ QList<QGeoMapType> types = m_mappingManager->supportedMapTypes();
+ for (int i = 0; i < types.size(); ++i) {
+ QDeclarativeGeoMapType *type = new QDeclarativeGeoMapType(types[i], this);
+ m_supportedMapTypes.append(type);
+ }
+
+ if (!m_supportedMapTypes.isEmpty()) {
+ QDeclarativeGeoMapType *type = m_supportedMapTypes.at(0);
+ m_activeMapType = type;
+ m_map->setActiveMapType(type->mapType());
+ } else {
+ m_map->setActiveMapType(m_activeMapType->mapType());
+ }
+
+ //The zoom level limits are only restricted by the plugins values, if the user has set a more
+ //strict zoom level limit before initialization nothing is done here.
+ //minimum zoom level might be changed to limit gray bundaries
+ //This code assumes that plugins' maximum zoom level will never exceed 30.0
+ if (m_mappingManager->cameraCapabilities().maximumZoomLevelAt256() < m_gestureArea->maximumZoomLevel())
+ setMaximumZoomLevel(m_mappingManager->cameraCapabilities().maximumZoomLevelAt256());
+
+ if (m_mappingManager->cameraCapabilities().minimumZoomLevelAt256() > m_gestureArea->minimumZoomLevel())
+ setMinimumZoomLevel(m_mappingManager->cameraCapabilities().minimumZoomLevelAt256());
+
+
+ // Map tiles are built in this call. m_map->minimumZoom() becomes operational
+ // after this has been called at least once, after creation.
+
+ if (!m_initialized && width() > 0 && height() > 0) {
+ m_map->setViewportSize(QSize(width(), height()));
+ initialize();
+ }
+
+ m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this);
+ connect(m_map, SIGNAL(copyrightsChanged(QImage)),
+ m_copyrights.data(), SLOT(copyrightsChanged(QImage)));
+ connect(m_map, SIGNAL(copyrightsChanged(QString)),
+ m_copyrights.data(), SLOT(copyrightsChanged(QString)));
+ connect(m_copyrights.data(), SIGNAL(linkActivated(QString)),
+ this, SIGNAL(copyrightLinkActivated(QString)));
+ connect(m_map, &QGeoMap::sgNodeChanged, this, &QQuickItem::update);
+
+ // set visibility of copyright notice
+ m_copyrights->setCopyrightsVisible(m_copyrightsVisible);
+
+ // This prefetches a buffer around the map
+ m_map->prefetchData();
+
+ connect(m_mappingManager, SIGNAL(supportedMapTypesChanged()), this, SLOT(onSupportedMapTypesChanged()));
+ emit minimumZoomLevelChanged();
+ emit maximumZoomLevelChanged();
+ emit supportedMapTypesChanged();
+ emit activeMapTypeChanged();
+
+ // Any map items that were added before the plugin was ready
+ // need to have setMap called again
+ foreach (const QPointer<QDeclarativeGeoMapItemBase> &item, m_mapItems) {
+ if (item)
+ item.data()->setMap(this, m_map);
+ }
+
+ // All map parameters that were added before the plugin was ready
+ // need to be added to m_map
+ for (QDeclarativeGeoMapParameter *p : m_mapParameters)
+ m_map->addParameter(p);
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider *QDeclarativeGeoMap::plugin() const
+{
+ return m_plugin;
+}
+
+/*!
+ \internal
+ Sets the gesture areas minimum zoom level. If the camera capabilities
+ has been set this method honors the boundaries set by it.
+ The minimum zoom level will also have a lower bound dependent on the size
+ of the canvas, effectively preventing to display out of bounds areas.
+*/
+void QDeclarativeGeoMap::setMinimumZoomLevel(qreal minimumZoomLevel)
+{
+
+ if (minimumZoomLevel >= 0) {
+ qreal oldMinimumZoomLevel = this->minimumZoomLevel();
+
+ if (m_map) {
+ minimumZoomLevel = qBound(qreal(m_map->cameraCapabilities().minimumZoomLevelAt256()), minimumZoomLevel, maximumZoomLevel());
+ double minimumViewportZoomLevel = m_map->minimumZoom();
+ if (minimumZoomLevel < minimumViewportZoomLevel)
+ minimumZoomLevel = minimumViewportZoomLevel;
+ }
+
+ m_gestureArea->setMinimumZoomLevel(minimumZoomLevel);
+
+ if (zoomLevel() < minimumZoomLevel)
+ setZoomLevel(minimumZoomLevel);
+
+ if (oldMinimumZoomLevel != minimumZoomLevel)
+ emit minimumZoomLevelChanged();
+ }
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::minimumZoomLevel
+
+ This property holds the minimum valid zoom level for the map.
+
+ The minimum zoom level defined by the \l plugin used is a lower bound for
+ this property. However, the returned value is also canvas-size-dependent, and
+ can be higher than the user-specified value, or than the minimum zoom level
+ defined by the plugin used, to prevent the map from being smaller than the
+ viewport in either dimension.
+
+ If a plugin supporting mapping is not set, 0.0 is returned.
+*/
+
+qreal QDeclarativeGeoMap::minimumZoomLevel() const
+{
+ return m_gestureArea->minimumZoomLevel();
+}
+
+/*!
+ \internal
+ Sets the gesture areas maximum zoom level. If the camera capabilities
+ has been set this method honors the boundaries set by it.
+*/
+void QDeclarativeGeoMap::setMaximumZoomLevel(qreal maximumZoomLevel)
+{
+ if (maximumZoomLevel >= 0) {
+ qreal oldMaximumZoomLevel = this->maximumZoomLevel();
+
+ if (m_map)
+ maximumZoomLevel = qBound(minimumZoomLevel(), maximumZoomLevel, qreal(m_map->cameraCapabilities().maximumZoomLevelAt256()));
+
+ m_gestureArea->setMaximumZoomLevel(maximumZoomLevel);
+
+ if (zoomLevel() > maximumZoomLevel)
+ setZoomLevel(maximumZoomLevel);
+
+ if (oldMaximumZoomLevel != maximumZoomLevel)
+ emit maximumZoomLevelChanged();
+ }
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::maximumZoomLevel
+
+ This property holds the maximum valid zoom level for the map.
+
+ The maximum zoom level is defined by the \l plugin used.
+ If a plugin supporting mapping is not set, 30.0 is returned.
+*/
+
+qreal QDeclarativeGeoMap::maximumZoomLevel() const
+{
+ return m_gestureArea->maximumZoomLevel();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::zoomLevel
+
+ This property holds the zoom level for the map.
+
+ Larger values for the zoom level provide more detail. Zoom levels
+ are always non-negative. The default value is 8.0.
+*/
+void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel)
+{
+ if (m_cameraData.zoomLevel() == zoomLevel || zoomLevel < 0)
+ return;
+
+ //small optimization to avoid double setCameraData
+ bool centerHasChanged = false;
+
+ if (m_initialized) {
+ m_cameraData.setZoomLevel(qBound(minimumZoomLevel(), zoomLevel, maximumZoomLevel()));
+ m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
+ QGeoCoordinate coord = m_cameraData.center();
+ coord.setLatitude(qBound(-m_maximumViewportLatitude, coord.latitude(), m_maximumViewportLatitude));
+ if (coord != m_cameraData.center()) {
+ centerHasChanged = true;
+ m_cameraData.setCenter(coord);
+ }
+ m_map->setCameraData(m_cameraData);
+ } else {
+ m_cameraData.setZoomLevel(zoomLevel);
+ }
+
+ if (centerHasChanged)
+ emit centerChanged(m_cameraData.center());
+ emit zoomLevelChanged(m_cameraData.zoomLevel());
+}
+
+qreal QDeclarativeGeoMap::zoomLevel() const
+{
+ return m_cameraData.zoomLevel();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::bearing
+
+ This property holds the bearing for the map.
+ The default value is 0.
+ If the Plugin used for the Map supports bearing, the valid range for this value is between 0 and 360.
+ If the Plugin used for the Map does not support bearing, changing this property will have no effect.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setBearing(qreal bearing)
+{
+ bearing = std::fmod(bearing, qreal(360.0));
+ if (m_map && !m_map->cameraCapabilities().supportsBearing())
+ bearing = 0.0;
+ if (m_cameraData.bearing() == bearing || bearing < 0.0)
+ return;
+
+ m_cameraData.setBearing(bearing);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit bearingChanged(bearing);
+}
+
+qreal QDeclarativeGeoMap::bearing() const
+{
+ return m_cameraData.bearing();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::tilt
+
+ This property holds the tilt for the map.
+ The default value is 0.
+ If the Plugin used for the Map supports tilt, the valid range for this value is
+ [ plugin.minimumTilt, plugin.maximumTilt ].
+ If the Plugin used for the Map does not support tilting, changing this property will have no effect.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setTilt(qreal tilt)
+{
+ tilt = qBound(minimumTilt(), tilt, maximumTilt());
+ if (m_cameraData.tilt() == tilt)
+ return;
+
+ m_cameraData.setTilt(tilt);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit tiltChanged(tilt);
+}
+
+qreal QDeclarativeGeoMap::tilt() const
+{
+ return m_cameraData.tilt();
+}
+
+/*!
+ \qmlproperty real QtLocation::Map::fieldOfView
+
+ This property holds the field of view of the camera used to look at the map, in degrees.
+ If the plugin property of the map is not set, or the plugin does not support mapping, the value is 45 degrees.
+
+ Note that changing this value implicitly changes also the distance between the camera and the map,
+ so that, at a tilting angle of 0 degrees, the resulting image is identical for any value used for this property.
+
+ For more information about this parameter, consult the Wikipedia articles about \l {https://en.wikipedia.org/wiki/Field_of_view} {Field of view} and
+ \l {https://en.wikipedia.org/wiki/Angle_of_view} {Angle of view}.
+
+ \since Qt Location 5.9
+*/
+void QDeclarativeGeoMap::setFieldOfView(qreal fieldOfView)
+{
+ fieldOfView = qBound(minimumFieldOfView(), fieldOfView, maximumFieldOfView());
+ if (m_cameraData.fieldOfView() == fieldOfView)
+ return;
+
+ m_cameraData.setFieldOfView(fieldOfView);
+ if (m_map)
+ m_map->setCameraData(m_cameraData);
+ emit fieldOfViewChanged(fieldOfView);
+}
+
+qreal QDeclarativeGeoMap::fieldOfView() const
+{
+ return m_cameraData.fieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::minimumFieldOfView
+ This property holds the minimum field of view that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 1.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::minimumFieldOfView() const
+{
+ if (!m_map)
+ return 1;
+ return m_map->cameraCapabilities().minimumFieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::maximumFieldOfView
+ This property holds the maximum field of view that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 179.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::maximumFieldOfView() const
+{
+ if (!m_map)
+ return 179;
+ return m_map->cameraCapabilities().maximumFieldOfView();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::bearingSupported
+
+ This property indicates if the Map supports bearing.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is false.
+
+ \since Qt Location 5.9
+*/
+bool QDeclarativeGeoMap::isBearingSupported() const
+{
+ if (!m_map)
+ return false;
+ return m_map->cameraCapabilities().supportsBearing();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::tiltingSupported
+
+ This property indicates if the Map supports tilting.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is false.
+
+ \since Qt Location 5.9
+*/
+bool QDeclarativeGeoMap::isTiltingSupported() const
+{
+ if (!m_map)
+ return false;
+ return m_map->cameraCapabilities().supportsTilting();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::minimumTilt
+
+ This property holds the minimum tilt that the map supports.
+ If the plugin property of the map is not set, or the plugin does not support mapping, this property is 0.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::minimumTilt() const
+{
+ if (!m_map || !m_map->cameraCapabilities().supportsTilting())
+ return 0.0;
+ return m_map->cameraCapabilities().minimumTilt();
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::maximumTilt
+
+ This property holds the maximum tilt that the map supports.
+ If the plugin property of the map is not set, this property is 89.
+ If the plugin is set and it does not support mapping, this property is 0.
+
+ \since Qt Location 5.9
+*/
+qreal QDeclarativeGeoMap::maximumTilt() const
+{
+ if (!m_map)
+ return 89.0;
+ else if (!m_map->cameraCapabilities().supportsTilting())
+ return 0.0;
+ return m_map->cameraCapabilities().maximumTilt();
+}
+
+/*!
+ \qmlproperty coordinate QtLocation::Map::center
+
+ This property holds the coordinate which occupies the center of the
+ mapping viewport. Invalid center coordinates are ignored.
+
+ The default value is an arbitrary valid coordinate.
+*/
+void QDeclarativeGeoMap::setCenter(const QGeoCoordinate &center)
+{
+ if (center == m_cameraData.center())
+ return;
+
+ if (!center.isValid())
+ return;
+
+ if (m_initialized) {
+ QGeoCoordinate coord(center);
+ coord.setLatitude(qBound(-m_maximumViewportLatitude, center.latitude(), m_maximumViewportLatitude));
+ m_cameraData.setCenter(coord);
+ m_map->setCameraData(m_cameraData);
+ } else {
+ m_cameraData.setCenter(center);
+ }
+
+ emit centerChanged(m_cameraData.center());
+}
+
+QGeoCoordinate QDeclarativeGeoMap::center() const
+{
+ return m_cameraData.center();
+}
+
+
+/*!
+ \qmlproperty geoshape QtLocation::Map::visibleRegion
+
+ This property holds the region which occupies the viewport of
+ the map. The camera is positioned in the center of the shape, and
+ at the largest integral zoom level possible which allows the
+ whole shape to be visible on the screen. This implies that
+ reading this property back shortly after having been set the
+ returned area is equal or larger than the set area.
+
+ Setting this property implicitly changes the \l center and
+ \l zoomLevel of the map. Any previously set value to those
+ properties will be overridden.
+
+ This property does not provide any change notifications.
+
+ \since 5.6
+*/
+void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape)
+{
+ if (shape.boundingGeoRectangle() == visibleRegion())
+ return;
+
+ m_visibleRegion = shape.boundingGeoRectangle();
+ if (!m_visibleRegion.isValid()
+ || (m_visibleRegion.bottomRight().latitude() >= 85.0) // rect entirely outside web mercator
+ || (m_visibleRegion.topLeft().latitude() <= -85.0)) {
+ // shape invalidated -> nothing to fit anymore
+ m_visibleRegion = QGeoRectangle();
+ m_pendingFitViewport = false;
+ return;
+ }
+
+ if (!m_map || !width() || !height()) {
+ m_pendingFitViewport = true;
+ return;
+ }
+
+ fitViewportToGeoShape();
+}
+
+QGeoShape QDeclarativeGeoMap::visibleRegion() const
+{
+ if (!m_map || !width() || !height())
+ return m_visibleRegion;
+
+ QGeoCoordinate tl = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(0, 0));
+ QGeoCoordinate br = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(width(), height()));
+
+ return QGeoRectangle(tl, br);
+}
+
+/*!
+ \qmlproperty bool QtLocation::Map::copyrightsVisible
+
+ This property holds the visibility of the copyrights notice. The notice is usually
+ displayed in the bottom left corner. By default, this property is set to \c true.
+
+ \note Many map providers require the notice to be visible as part of the terms and conditions.
+ Please consult the relevant provider documentation before turning this notice off.
+
+ \since 5.7
+*/
+void QDeclarativeGeoMap::setCopyrightsVisible(bool visible)
+{
+ if (m_copyrightsVisible == visible)
+ return;
+
+ if (!m_copyrights.isNull())
+ m_copyrights->setCopyrightsVisible(visible);
+
+ m_copyrightsVisible = visible;
+ emit copyrightsVisibleChanged(visible);
+}
+
+bool QDeclarativeGeoMap::copyrightsVisible() const
+{
+ return m_copyrightsVisible;
+}
+
+
+
+/*!
+ \qmlproperty color QtLocation::Map::color
+
+ This property holds the background color of the map element.
+
+ \since 5.6
+*/
+void QDeclarativeGeoMap::setColor(const QColor &color)
+{
+ if (color != m_color) {
+ m_color = color;
+ update();
+ emit colorChanged(m_color);
+ }
+}
+
+QColor QDeclarativeGeoMap::color() const
+{
+ return m_color;
+}
+
+// TODO: offer the possibility to specify the margins.
+void QDeclarativeGeoMap::fitViewportToGeoShape()
+{
+ const int margins = 10;
+ if (!m_map || !m_visibleRegion.isValid() || width() <= margins || height() <= margins)
+ return;
+
+ QDoubleVector2D topLeftPoint = m_map->geoProjection().geoToMapProjection(m_visibleRegion.topLeft());
+ QDoubleVector2D bottomRightPoint = m_map->geoProjection().geoToMapProjection(m_visibleRegion.bottomRight());
+ if (bottomRightPoint.x() < topLeftPoint.x()) // crossing the dateline
+ bottomRightPoint.setX(bottomRightPoint.x() + 1.0);
+
+ // find center of the bounding box
+ QDoubleVector2D center = (topLeftPoint + bottomRightPoint) * 0.5;
+ center.setX(center.x() > 1.0 ? center.x() - 1.0 : center.x());
+ QGeoCoordinate centerCoordinate = m_map->geoProjection().mapProjectionToGeo(center);
+
+ // position camera to the center of bounding box
+ setCenter(centerCoordinate);
+
+ // if the shape is empty we just change center position, not zoom
+ double bboxWidth = (bottomRightPoint.x() - topLeftPoint.x()) * m_map->mapWidth();
+ double bboxHeight = (bottomRightPoint.y() - topLeftPoint.y()) * m_map->mapHeight();
+
+ if (bboxHeight == 0.0 && bboxWidth == 0.0)
+ return;
+
+ double zoomRatio = qMax(bboxWidth / (width() - margins),
+ bboxHeight / (height() - margins));
+ zoomRatio = std::log(zoomRatio) / std::log(2.0);
+ double newZoom = qMax<double>(minimumZoomLevel(), zoomLevel() - zoomRatio);
+ setZoomLevel(newZoom);
+}
+
+
+/*!
+ \qmlproperty list<MapType> QtLocation::Map::supportedMapTypes
+
+ This read-only property holds the set of \l{MapType}{map types} supported by this map.
+
+ \sa activeMapType
+*/
+QQmlListProperty<QDeclarativeGeoMapType> QDeclarativeGeoMap::supportedMapTypes()
+{
+ return QQmlListProperty<QDeclarativeGeoMapType>(this, m_supportedMapTypes);
+}
+
+/*!
+ \qmlmethod coordinate QtLocation::Map::toCoordinate(QPointF position, bool clipToViewPort)
+
+ Returns the coordinate which corresponds to the \a position relative to the map item.
+
+ If \a cliptoViewPort is \c true, or not supplied then returns an invalid coordinate if
+ \a position is not within the current viewport.
+*/
+QGeoCoordinate QDeclarativeGeoMap::toCoordinate(const QPointF &position, bool clipToViewPort) const
+{
+ if (m_map)
+ return m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(position), clipToViewPort);
+ else
+ return QGeoCoordinate();
+}
+
+/*!
+ \qmlmethod point QtLocation::Map::fromCoordinate(coordinate coordinate, bool clipToViewPort)
+
+ Returns the position relative to the map item which corresponds to the \a coordinate.
+
+ If \a cliptoViewPort is \c true, or not supplied then returns an invalid QPointF if
+ \a coordinate is not within the current viewport.
+*/
+QPointF QDeclarativeGeoMap::fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort) const
+{
+ if (m_map)
+ return m_map->geoProjection().coordinateToItemPosition(coordinate, clipToViewPort).toPointF();
+ else
+ return QPointF(qQNaN(), qQNaN());
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::pan(int dx, int dy)
+
+ Starts panning the map by \a dx pixels along the x-axis and
+ by \a dy pixels along the y-axis.
+
+ Positive values for \a dx move the map right, negative values left.
+ Positive values for \a dy move the map down, negative values up.
+
+ During panning the \l center, and \l zoomLevel may change.
+*/
+void QDeclarativeGeoMap::pan(int dx, int dy)
+{
+ if (!m_map)
+ return;
+ if (dx == 0 && dy == 0)
+ return;
+
+ QGeoCoordinate coord = m_map->geoProjection().itemPositionToCoordinate(
+ QDoubleVector2D(m_map->viewportWidth() / 2 + dx,
+ m_map->viewportHeight() / 2 + dy));
+ setCenter(coord);
+}
+
+
+/*!
+ \qmlmethod void QtLocation::Map::prefetchData()
+
+ Optional hint that allows the map to prefetch during this idle period
+*/
+void QDeclarativeGeoMap::prefetchData()
+{
+ if (!m_map)
+ return;
+ m_map->prefetchData();
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::clearData()
+
+ Clears map data collected by the currently selected plugin.
+ \note This method will delete cached files.
+ \sa plugin
+*/
+void QDeclarativeGeoMap::clearData()
+{
+ m_map->clearData();
+}
+
+/*!
+ \qmlproperty string QtLocation::Map::errorString
+
+ This read-only property holds the textual presentation of the latest mapping provider error.
+ If no error has occurred, an empty string is returned.
+
+ An empty string may also be returned if an error occurred which has no associated
+ textual representation.
+
+ \sa QGeoServiceProvider::errorString()
+*/
+
+QString QDeclarativeGeoMap::errorString() const
+{
+ return m_errorString;
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::Map::error
+
+ This read-only property holds the last occurred mapping service provider error.
+
+ \list
+ \li Map.NoError - No error has occurred.
+ \li Map.NotSupportedError -The maps plugin property was not set or there is no mapping manager associated with the plugin.
+ \li Map.UnknownParameterError -The plugin did not recognize one of the parameters it was given.
+ \li Map.MissingRequiredParameterError - The plugin did not find one of the parameters it was expecting.
+ \li Map.ConnectionError - The plugin could not connect to its backend service or database.
+ \endlist
+
+ \sa QGeoServiceProvider::Error
+*/
+
+QGeoServiceProvider::Error QDeclarativeGeoMap::error() const
+{
+ return m_error;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::touchEvent(QTouchEvent *event)
+{
+ if (isInteractive()) {
+ m_gestureArea->handleTouchEvent(event);
+ } else {
+ //ignore event so sythesized event is generated;
+ QQuickItem::touchEvent(event);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::wheelEvent(QWheelEvent *event)
+{
+ if (isInteractive())
+ m_gestureArea->handleWheelEvent(event);
+ else
+ QQuickItem::wheelEvent(event);
+
+}
+
+bool QDeclarativeGeoMap::isInteractive()
+{
+ return (m_gestureArea->enabled() && m_gestureArea->acceptedGestures()) || m_gestureArea->isActive();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoMap::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ Q_UNUSED(item)
+ if (!isVisible() || !isEnabled() || !isInteractive())
+ return QQuickItem::childMouseEventFilter(item, event);
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ return sendMouseEvent(static_cast<QMouseEvent *>(event));
+ case QEvent::UngrabMouse: {
+ QQuickWindow *win = window();
+ if (!win) break;
+ if (!win->mouseGrabberItem() ||
+ (win->mouseGrabberItem() &&
+ win->mouseGrabberItem() != this)) {
+ // child lost grab, we could even lost
+ // some events if grab already belongs for example
+ // in item in diffrent window , clear up states
+ mouseUngrabEvent();
+ }
+ break;
+ }
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ case QEvent::TouchCancel:
+ if (static_cast<QTouchEvent *>(event)->touchPoints().count() >= 2) {
+ // 1 touch point = handle with MouseEvent (event is always synthesized)
+ // let the synthesized mouse event grab the mouse,
+ // note there is no mouse grabber at this point since
+ // touch event comes first (see Qt::AA_SynthesizeMouseForUnhandledTouchEvents)
+ return sendTouchEvent(static_cast<QTouchEvent *>(event));
+ }
+ default:
+ break;
+ }
+ return QQuickItem::childMouseEventFilter(item, event);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::addMapItem(MapItem item)
+
+ Adds the given \a item to the Map (for example MapQuickItem, MapCircle). If the object
+ already is on the Map, it will not be added again.
+
+ As an example, consider the case where you have a MapCircle representing your current position:
+
+ \snippet declarative/maps.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/maps.qml Map addMapItem MapCircle at current position
+
+ \note MapItemViews cannot be added with this method.
+
+ \sa mapItems, removeMapItem, clearMapItems
+*/
+
+void QDeclarativeGeoMap::addMapItem(QDeclarativeGeoMapItemBase *item)
+{
+ if (!item || item->quickMap())
+ return;
+ item->setParentItem(this);
+ if (m_map)
+ item->setMap(this, m_map);
+ m_mapItems.append(item);
+ emit mapItemsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::addMapParameter(MapParameter parameter)
+
+ Adds a MapParameter object to the map. The effect of this call is dependent
+ on the combination of the content of the MapParameter and the type of
+ underlying QGeoMap. If a MapParameter that is not supported by the underlying
+ QGeoMap gets added, the call has no effect.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, removeMapParameter, mapParameters, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::addMapParameter(QDeclarativeGeoMapParameter *parameter)
+{
+ if (!parameter->isComponentComplete()) {
+ connect(parameter, &QDeclarativeGeoMapParameter::completed, this, &QDeclarativeGeoMap::addMapParameter);
+ return;
+ }
+
+ disconnect(parameter);
+ if (m_mapParameters.contains(parameter))
+ return;
+ parameter->setParent(this);
+ m_mapParameters.insert(parameter); // parameter now owned by QDeclarativeGeoMap
+ if (m_map)
+ m_map->addParameter(parameter);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::removeMapParameter(MapParameter parameter)
+
+ Removes the given MapParameter object from the map.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, addMapParameter, mapParameters, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::removeMapParameter(QDeclarativeGeoMapParameter *parameter)
+{
+ if (!m_mapParameters.contains(parameter))
+ return;
+ if (m_map)
+ m_map->removeParameter(parameter);
+ m_mapParameters.remove(parameter);
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::clearMapParameters()
+
+ Removes all map parameters from the map.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, mapParameters, addMapParameter, removeMapParameter, clearMapParameters
+
+ \since 5.9
+*/
+void QDeclarativeGeoMap::clearMapParameters()
+{
+ if (m_map)
+ m_map->clearParameters();
+ m_mapParameters.clear();
+}
+
+/*!
+ \qmlproperty list<MapParameters> QtLocation::Map::mapParameters
+
+ Returns the list of all map parameters in no particular order.
+ These items include map parameters that were declared statically as part of
+ the type declaration, as well as dynamical map parameters (\l addMapParameter).
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+
+ \sa MapParameter, addMapParameter, removeMapParameter, clearMapParameters
+
+ \since 5.9
+*/
+QList<QObject *> QDeclarativeGeoMap::mapParameters()
+{
+ QList<QObject *> ret;
+ for (QDeclarativeGeoMapParameter *p : m_mapParameters)
+ ret << p;
+ return ret;
+}
+
+/*!
+ \qmlproperty list<MapItem> QtLocation::Map::mapItems
+
+ Returns the list of all map items in no particular order.
+ These items include items that were declared statically as part of
+ the type declaration, as well as dynamical items (\l addMapItem,
+ \l MapItemView).
+
+ \sa addMapItem, removeMapItem, clearMapItems
+*/
+
+QList<QObject *> QDeclarativeGeoMap::mapItems()
+{
+ QList<QObject *> ret;
+ foreach (const QPointer<QDeclarativeGeoMapItemBase> &ptr, m_mapItems) {
+ if (ptr)
+ ret << ptr.data();
+ }
+ return ret;
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::removeMapItem(MapItem item)
+
+ Removes the given \a item from the Map (for example MapQuickItem, MapCircle). If
+ the MapItem does not exist or was not previously added to the map, the
+ method does nothing.
+
+ \sa mapItems, addMapItem, clearMapItems
+*/
+void QDeclarativeGeoMap::removeMapItem(QDeclarativeGeoMapItemBase *ptr)
+{
+ if (!ptr || !m_map)
+ return;
+ QPointer<QDeclarativeGeoMapItemBase> item(ptr);
+ if (!m_mapItems.contains(item))
+ return;
+ item.data()->setParentItem(0);
+ item.data()->setMap(0, 0);
+ // these can be optimized for perf, as we already check the 'contains' above
+ m_mapItems.removeOne(item);
+ emit mapItemsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::clearMapItems()
+
+ Removes all items from the map.
+
+ \sa mapItems, addMapItem, removeMapItem
+*/
+void QDeclarativeGeoMap::clearMapItems()
+{
+ if (m_mapItems.isEmpty())
+ return;
+ for (int i = 0; i < m_mapItems.count(); ++i) {
+ if (m_mapItems.at(i)) {
+ m_mapItems.at(i).data()->setParentItem(0);
+ m_mapItems.at(i).data()->setMap(0, 0);
+ }
+ }
+ m_mapItems.clear();
+ emit mapItemsChanged();
+}
+
+/*!
+ \qmlproperty MapType QtLocation::Map::activeMapType
+
+ \brief Access to the currently active \l{MapType}{map type}.
+
+ This property can be set to change the active \l{MapType}{map type}.
+ See the \l{Map::supportedMapTypes}{supportedMapTypes} property for possible values.
+
+ \sa MapType
+*/
+void QDeclarativeGeoMap::setActiveMapType(QDeclarativeGeoMapType *mapType)
+{
+ if (m_activeMapType->mapType() != mapType->mapType()) {
+ m_activeMapType = mapType;
+ if (m_map)
+ m_map->setActiveMapType(mapType->mapType());
+ emit activeMapTypeChanged();
+ }
+}
+
+QDeclarativeGeoMapType * QDeclarativeGeoMap::activeMapType() const
+{
+ return m_activeMapType;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ m_gestureArea->setSize(newGeometry.size());
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+
+ if (!m_map || !newGeometry.size().isValid())
+ return;
+
+ m_map->setViewportSize(newGeometry.size().toSize());
+
+ if (!m_initialized) {
+ initialize();
+ } else {
+ setMinimumZoomLevel(m_map->minimumZoom());
+
+ // Update the center latitudinal threshold
+ double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(m_cameraData);
+ if (maximumCenterLatitudeAtZoom != m_maximumViewportLatitude) {
+ m_maximumViewportLatitude = maximumCenterLatitudeAtZoom;
+ QGeoCoordinate coord = m_cameraData.center();
+ coord.setLatitude(qBound(-m_maximumViewportLatitude, coord.latitude(), m_maximumViewportLatitude));
+
+ if (coord != m_cameraData.center()) {
+ m_cameraData.setCenter(coord);
+ m_map->setCameraData(m_cameraData);
+ emit centerChanged(m_cameraData.center());
+ }
+ }
+ }
+
+ /*!
+ The fitViewportTo*() functions depend on a valid map geometry.
+ If they were called prior to the first resize they cause
+ the zoomlevel to jump to 0 (showing the world). Therefore the
+ calls were queued up until now.
+
+ Multiple fitViewportTo*() calls replace each other.
+ */
+ if (m_pendingFitViewport && width() && height()) {
+ fitViewportToGeoShape();
+ m_pendingFitViewport = false;
+ }
+
+}
+
+/*!
+ \qmlmethod void QtLocation::Map::fitViewportToMapItems()
+
+ Fits the current viewport to the boundary of all map items. The camera is positioned
+ in the center of the map items, and at the largest integral zoom level possible which
+ allows all map items to be visible on screen
+
+*/
+void QDeclarativeGeoMap::fitViewportToMapItems()
+{
+ fitViewportToMapItemsRefine(true);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMap::fitViewportToMapItemsRefine(bool refine)
+{
+ if (!m_map)
+ return;
+
+ if (m_mapItems.size() == 0)
+ return;
+
+ double minX = 0;
+ double maxX = 0;
+ double minY = 0;
+ double maxY = 0;
+ double topLeftX = 0;
+ double topLeftY = 0;
+ double bottomRightX = 0;
+ double bottomRightY = 0;
+ bool haveQuickItem = false;
+
+ // find bounds of all map items
+ int itemCount = 0;
+ for (int i = 0; i < m_mapItems.count(); ++i) {
+ if (!m_mapItems.at(i))
+ continue;
+ QDeclarativeGeoMapItemBase *item = m_mapItems.at(i).data();
+ if (!item)
+ continue;
+
+ // skip quick items in the first pass and refine the fit later
+ if (refine) {
+ QDeclarativeGeoMapQuickItem *quickItem =
+ qobject_cast<QDeclarativeGeoMapQuickItem*>(item);
+ if (quickItem) {
+ haveQuickItem = true;
+ continue;
+ }
+ }
+ // Force map items to update immediately. Needed to ensure correct item size and positions
+ // when recursively calling this function.
+ if (item->isPolishScheduled())
+ item->updatePolish();
+
+ topLeftX = item->position().x();
+ topLeftY = item->position().y();
+ bottomRightX = topLeftX + item->width();
+ bottomRightY = topLeftY + item->height();
+
+ if (itemCount == 0) {
+ minX = topLeftX;
+ maxX = bottomRightX;
+ minY = topLeftY;
+ maxY = bottomRightY;
+ } else {
+ minX = qMin(minX, topLeftX);
+ maxX = qMax(maxX, bottomRightX);
+ minY = qMin(minY, topLeftY);
+ maxY = qMax(maxY, bottomRightY);
+ }
+ ++itemCount;
+ }
+
+ if (itemCount == 0) {
+ if (haveQuickItem)
+ fitViewportToMapItemsRefine(false);
+ return;
+ }
+ double bboxWidth = maxX - minX;
+ double bboxHeight = maxY - minY;
+ double bboxCenterX = minX + (bboxWidth / 2.0);
+ double bboxCenterY = minY + (bboxHeight / 2.0);
+
+ // position camera to the center of bounding box
+ QGeoCoordinate coordinate;
+ coordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(bboxCenterX, bboxCenterY), false);
+ setProperty("center", QVariant::fromValue(coordinate));
+
+ // adjust zoom
+ double bboxWidthRatio = bboxWidth / (bboxWidth + bboxHeight);
+ double mapWidthRatio = width() / (width() + height());
+ double zoomRatio;
+
+ if (bboxWidthRatio > mapWidthRatio)
+ zoomRatio = bboxWidth / width();
+ else
+ zoomRatio = bboxHeight / height();
+
+ qreal newZoom = std::log10(zoomRatio) / std::log10(0.5);
+ newZoom = std::floor(qMax(minimumZoomLevel(), (zoomLevel() + newZoom)));
+ setProperty("zoomLevel", QVariant::fromValue(newZoom));
+
+ // as map quick items retain the same screen size after the camera zooms in/out
+ // we refine the viewport again to achieve better results
+ if (refine)
+ fitViewportToMapItemsRefine(false);
+}
+
+bool QDeclarativeGeoMap::sendMouseEvent(QMouseEvent *event)
+{
+ QPointF localPos = mapFromScene(event->windowPos());
+ QQuickWindow *win = window();
+ QQuickItem *grabber = win ? win->mouseGrabberItem() : 0;
+ bool stealEvent = m_gestureArea->isActive();
+
+ if ((stealEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
+ QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos));
+ mouseEvent->setAccepted(false);
+
+ switch (mouseEvent->type()) {
+ case QEvent::MouseMove:
+ m_gestureArea->handleMouseMoveEvent(mouseEvent.data());
+ break;
+ case QEvent::MouseButtonPress:
+ m_gestureArea->handleMousePressEvent(mouseEvent.data());
+ break;
+ case QEvent::MouseButtonRelease:
+ m_gestureArea->handleMouseReleaseEvent(mouseEvent.data());
+ break;
+ default:
+ break;
+ }
+
+ stealEvent = m_gestureArea->isActive();
+ grabber = win ? win->mouseGrabberItem() : 0;
+
+ if (grabber && stealEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ if (stealEvent) {
+ //do not deliver
+ event->setAccepted(true);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeGeoMap::sendTouchEvent(QTouchEvent *event)
+{
+ const QQuickPointerDevice *touchDevice = QQuickPointerDevice::touchDevice(event->device());
+ const QTouchEvent::TouchPoint &point = event->touchPoints().first();
+
+ auto touchPointGrabberItem = [touchDevice](const QTouchEvent::TouchPoint &point) -> QQuickItem* {
+ if (QQuickEventPoint *eventPointer = touchDevice->pointerEvent()->pointById(point.id()))
+ return eventPointer->grabber();
+ return nullptr;
+ };
+
+ QQuickItem *grabber = touchPointGrabberItem(point);
+
+ bool stealEvent = m_gestureArea->isActive();
+ bool containsPoint = contains(mapFromScene(point.scenePos()));
+
+ if ((stealEvent || containsPoint) && (!grabber || !grabber->keepTouchGrab())) {
+ QScopedPointer<QTouchEvent> touchEvent(new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints()));
+ touchEvent->setTimestamp(event->timestamp());
+ touchEvent->setAccepted(false);
+
+ m_gestureArea->handleTouchEvent(touchEvent.data());
+ stealEvent = m_gestureArea->isActive();
+ grabber = touchPointGrabberItem(point);
+
+ if (grabber && stealEvent && !grabber->keepTouchGrab() && grabber != this) {
+ QVector<int> ids;
+ foreach (const QTouchEvent::TouchPoint &tp, event->touchPoints()) {
+ if (!(tp.state() & Qt::TouchPointReleased)) {
+ ids.append(tp.id());
+ }
+ }
+ grabTouchPoints(ids);
+ }
+
+ if (stealEvent) {
+ //do not deliver
+ event->setAccepted(true);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+#include "moc_qdeclarativegeomap_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h
new file mode 100644
index 00000000..ca2ec0a9
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomap_p.h
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAP_H
+#define QDECLARATIVEGEOMAP_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitemview_p.h>
+#include <QtLocation/private/qquickgeomapgesturearea_p.h>
+
+#include <QtLocation/qgeoserviceprovider.h>
+#include <QtLocation/private/qgeocameradata_p.h>
+#include <QtQuick/QQuickItem>
+#include <QtCore/QPointer>
+#include <QtCore/QSet>
+#include <QtGui/QColor>
+#include <QtPositioning/qgeoshape.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGeoServiceProvider;
+class QDeclarativeGeoMapType;
+class QDeclarativeGeoMapCopyrightNotice;
+class QDeclarativeGeoMapParameter;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMap : public QQuickItem
+{
+ Q_OBJECT
+ Q_ENUMS(QGeoServiceProvider::Error)
+ Q_PROPERTY(QQuickGeoMapGestureArea *gesture READ gesture CONSTANT)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(qreal minimumZoomLevel READ minimumZoomLevel WRITE setMinimumZoomLevel NOTIFY minimumZoomLevelChanged)
+ Q_PROPERTY(qreal maximumZoomLevel READ maximumZoomLevel WRITE setMaximumZoomLevel NOTIFY maximumZoomLevelChanged)
+ Q_PROPERTY(qreal zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged)
+
+ Q_PROPERTY(bool bearingSupported READ isBearingSupported NOTIFY bearingSupportChanged)
+ Q_PROPERTY(bool tiltingSupported READ isTiltingSupported NOTIFY tiltingSupportChanged)
+ Q_PROPERTY(qreal minimumTilt READ minimumTilt NOTIFY minimumTiltChanged)
+ Q_PROPERTY(qreal maximumTilt READ maximumTilt NOTIFY maximumTiltChanged)
+ Q_PROPERTY(qreal bearing READ bearing WRITE setBearing NOTIFY bearingChanged)
+ Q_PROPERTY(qreal tilt READ tilt WRITE setTilt NOTIFY tiltChanged)
+ Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged)
+ Q_PROPERTY(qreal minimumFieldOfView READ minimumFieldOfView NOTIFY minimumFieldOfViewChanged)
+ Q_PROPERTY(qreal maximumFieldOfView READ maximumFieldOfView NOTIFY minimumFieldOfViewChanged)
+
+ Q_PROPERTY(QDeclarativeGeoMapType *activeMapType READ activeMapType WRITE setActiveMapType NOTIFY activeMapTypeChanged)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeGeoMapType> supportedMapTypes READ supportedMapTypes NOTIFY supportedMapTypesChanged)
+ Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
+ Q_PROPERTY(QList<QObject *> mapItems READ mapItems NOTIFY mapItemsChanged)
+ Q_PROPERTY(QList<QObject *> mapParameters READ mapParameters)
+ Q_PROPERTY(QGeoServiceProvider::Error error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(QGeoShape visibleRegion READ visibleRegion WRITE setVisibleRegion)
+ Q_PROPERTY(bool copyrightsVisible READ copyrightsVisible WRITE setCopyrightsVisible NOTIFY copyrightsVisibleChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+
+ explicit QDeclarativeGeoMap(QQuickItem *parent = 0);
+ ~QDeclarativeGeoMap();
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ void setActiveMapType(QDeclarativeGeoMapType *mapType);
+ QDeclarativeGeoMapType *activeMapType() const;
+
+ void setMinimumZoomLevel(qreal minimumZoomLevel);
+ qreal minimumZoomLevel() const;
+
+ void setMaximumZoomLevel(qreal maximumZoomLevel);
+ qreal maximumZoomLevel() const;
+
+ void setZoomLevel(qreal zoomLevel);
+ qreal zoomLevel() const;
+
+ void setBearing(qreal bearing);
+ qreal bearing() const;
+
+ void setTilt(qreal tilt);
+ qreal tilt() const;
+
+ void setFieldOfView(qreal fieldOfView);
+ qreal fieldOfView() const;
+ qreal minimumFieldOfView() const;
+ qreal maximumFieldOfView() const;
+
+ bool isBearingSupported() const;
+ bool isTiltingSupported() const;
+ qreal minimumTilt() const;
+ qreal maximumTilt() const;
+
+ void setCenter(const QGeoCoordinate &center);
+ QGeoCoordinate center() const;
+
+ void setVisibleRegion(const QGeoShape &shape);
+ QGeoShape visibleRegion() const;
+
+ void setCopyrightsVisible(bool visible);
+ bool copyrightsVisible() const;
+
+ void setColor(const QColor &color);
+ QColor color() const;
+
+ QQmlListProperty<QDeclarativeGeoMapType> supportedMapTypes();
+
+ Q_INVOKABLE void removeMapItem(QDeclarativeGeoMapItemBase *item);
+ Q_INVOKABLE void addMapItem(QDeclarativeGeoMapItemBase *item);
+
+ Q_INVOKABLE void clearMapItems();
+ QList<QObject *> mapItems();
+
+ Q_INVOKABLE void addMapParameter(QDeclarativeGeoMapParameter *parameter);
+ Q_INVOKABLE void removeMapParameter(QDeclarativeGeoMapParameter *parameter);
+ Q_INVOKABLE void clearMapParameters();
+ QList<QObject *> mapParameters();
+
+ Q_INVOKABLE QGeoCoordinate toCoordinate(const QPointF &position, bool clipToViewPort = true) const;
+ Q_INVOKABLE QPointF fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort = true) const;
+
+ QQuickGeoMapGestureArea *gesture();
+
+ Q_INVOKABLE void fitViewportToMapItems();
+ Q_INVOKABLE void pan(int dx, int dy);
+ Q_INVOKABLE void prefetchData(); // optional hint for prefetch
+ Q_INVOKABLE void clearData();
+
+ QString errorString() const;
+ QGeoServiceProvider::Error error() const;
+
+Q_SIGNALS:
+ void pluginChanged(QDeclarativeGeoServiceProvider *plugin);
+ void zoomLevelChanged(qreal zoomLevel);
+ void centerChanged(const QGeoCoordinate &coordinate);
+ void activeMapTypeChanged();
+ void supportedMapTypesChanged();
+ void minimumZoomLevelChanged();
+ void maximumZoomLevelChanged();
+ void mapItemsChanged();
+ void errorChanged();
+ void copyrightLinkActivated(const QString &link);
+ void copyrightsVisibleChanged(bool visible);
+ void colorChanged(const QColor &color);
+ void bearingChanged(qreal bearing);
+ void tiltChanged(qreal tilt);
+ void fieldOfViewChanged(qreal fieldOfView);
+ void bearingSupportChanged(bool bearingSupport);
+ void tiltingSupportChanged(bool tiltingSupport);
+ void minimumTiltChanged(qreal minimumTilt);
+ void maximumTiltChanged(qreal maximumTilt);
+ void minimumFieldOfViewChanged(qreal minimumFieldOfView);
+ void maximumFieldOfViewChanged(qreal maximumFieldOfView);
+
+protected:
+ void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE ;
+ void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE ;
+ void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE ;
+ void mouseUngrabEvent() Q_DECL_OVERRIDE ;
+ void touchUngrabEvent() Q_DECL_OVERRIDE;
+ void touchEvent(QTouchEvent *event) Q_DECL_OVERRIDE ;
+ void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE ;
+
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event) Q_DECL_OVERRIDE;
+ bool sendMouseEvent(QMouseEvent *event);
+ bool sendTouchEvent(QTouchEvent *event);
+
+ void componentComplete() Q_DECL_OVERRIDE;
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+
+ void setError(QGeoServiceProvider::Error error, const QString &errorString);
+ void initialize();
+private Q_SLOTS:
+ void mappingManagerInitialized();
+ void pluginReady();
+ void onMapChildrenChanged();
+ void onSupportedMapTypesChanged();
+
+private:
+ void setupMapView(QDeclarativeGeoMapItemView *view);
+ void populateMap();
+ void populateParameters();
+ void fitViewportToMapItemsRefine(bool refine);
+ void fitViewportToGeoShape();
+ bool isInteractive();
+
+private:
+ QDeclarativeGeoServiceProvider *m_plugin;
+ QGeoMappingManager *m_mappingManager;
+ QDeclarativeGeoMapType *m_activeMapType;
+ QList<QDeclarativeGeoMapType *> m_supportedMapTypes;
+ QList<QDeclarativeGeoMapItemView *> m_mapViews;
+ QQuickGeoMapGestureArea *m_gestureArea;
+ QGeoMap *m_map;
+ QPointer<QDeclarativeGeoMapCopyrightNotice> m_copyrights;
+ QList<QPointer<QDeclarativeGeoMapItemBase> > m_mapItems;
+ QString m_errorString;
+ QGeoServiceProvider::Error m_error;
+ QGeoRectangle m_visibleRegion;
+ QColor m_color;
+ QGeoCameraData m_cameraData;
+ bool m_componentCompleted;
+ bool m_pendingFitViewport;
+ bool m_copyrightsVisible;
+ double m_maximumViewportLatitude;
+ bool m_initialized;
+ QSet<QDeclarativeGeoMapParameter *> m_mapParameters;
+
+ friend class QDeclarativeGeoMapItem;
+ friend class QDeclarativeGeoMapItemView;
+ friend class QQuickGeoMapGestureArea;
+ Q_DISABLE_COPY(QDeclarativeGeoMap)
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMap)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp
new file mode 100644
index 00000000..7b5a5765
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com>
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomapcopyrightsnotice_p.h"
+
+#include <QtGui/QTextDocument>
+#include <QtGui/QAbstractTextDocumentLayout>
+#include <QtGui/QPainter>
+#include <QtQuick/private/qquickanchors_p.h>
+#include <QtQuick/private/qquickanchors_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeGeoMapCopyrightNotice::QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent)
+: QQuickPaintedItem(parent), m_copyrightsHtml(0), m_copyrightsVisible(true)
+{
+ QQuickAnchors *anchors = property("anchors").value<QQuickAnchors *>();
+ if (anchors) {
+ anchors->setLeft(QQuickAnchorLine(parent, QQuickAnchors::LeftAnchor));
+ anchors->setBottom(QQuickAnchorLine(parent, QQuickAnchors::BottomAnchor));
+ }
+}
+
+QDeclarativeGeoMapCopyrightNotice::~QDeclarativeGeoMapCopyrightNotice()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::paint(QPainter *painter)
+{
+ painter->drawImage(0, 0, m_copyrightsImage);
+}
+
+void QDeclarativeGeoMapCopyrightNotice::mousePressEvent(QMouseEvent *event)
+{
+ if (m_copyrightsHtml) {
+ m_activeAnchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos());
+ if (!m_activeAnchor.isEmpty())
+ return;
+ }
+
+ QQuickPaintedItem::mousePressEvent(event);
+}
+
+void QDeclarativeGeoMapCopyrightNotice::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (m_copyrightsHtml) {
+ QString anchor = m_copyrightsHtml->documentLayout()->anchorAt(event->pos());
+ if (anchor == m_activeAnchor && !anchor.isEmpty()) {
+ emit linkActivated(anchor);
+ m_activeAnchor.clear();
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::setCopyrightsVisible(bool visible)
+{
+ m_copyrightsVisible = visible;
+
+ setVisible(!m_copyrightsImage.isNull() && visible);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::setCopyrightsZ(int copyrightsZ)
+{
+ setZ(copyrightsZ);
+ update();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QImage &copyrightsImage)
+{
+ delete m_copyrightsHtml;
+ m_copyrightsHtml = 0;
+
+ m_copyrightsImage = copyrightsImage;
+
+ setWidth(m_copyrightsImage.width());
+ setHeight(m_copyrightsImage.height());
+
+ setKeepMouseGrab(false);
+ setAcceptedMouseButtons(Qt::NoButton);
+ setVisible(m_copyrightsVisible);
+
+ update();
+}
+
+void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QString &copyrightsHtml)
+{
+ if (copyrightsHtml.isEmpty() || !m_copyrightsVisible) {
+ m_copyrightsImage = QImage();
+ setVisible(false);
+ return;
+ } else {
+ setVisible(true);
+ }
+
+ if (!m_copyrightsHtml)
+ m_copyrightsHtml = new QTextDocument(this);
+
+ m_copyrightsHtml->setHtml(copyrightsHtml);
+
+ m_copyrightsImage = QImage(m_copyrightsHtml->size().toSize(),
+ QImage::Format_ARGB32_Premultiplied);
+ m_copyrightsImage.fill(qPremultiply(qRgba(255, 255, 255, 128)));
+
+ QPainter painter(&m_copyrightsImage);
+ //m_copyrightsHtml->drawContents(&painter); // <- this uses the default application palette, that might have, f.ex., white text
+ QAbstractTextDocumentLayout::PaintContext ctx;
+ ctx.palette.setColor(QPalette::Text, QColor(QStringLiteral("black")));
+ ctx.palette.setColor(QPalette::Link, QColor(QStringLiteral("blue")));
+ m_copyrightsHtml->documentLayout()->draw(&painter, ctx);
+
+ setWidth(m_copyrightsImage.width());
+ setHeight(m_copyrightsImage.height());
+
+ setContentsSize(m_copyrightsImage.size());
+
+ setKeepMouseGrab(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+
+ update();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
new file mode 100644
index 00000000..1aeef7c1
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com>
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPCOPYRIGHTSNOTICE_H
+#define QDECLARATIVEGEOMAPCOPYRIGHTSNOTICE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtGui/QImage>
+#include <QtQuick/QQuickPaintedItem>
+
+QT_BEGIN_NAMESPACE
+
+class QTextDocument;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapCopyrightNotice : public QQuickPaintedItem
+{
+ Q_OBJECT
+
+public:
+ explicit QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent);
+ ~QDeclarativeGeoMapCopyrightNotice();
+
+ void setCopyrightsZ(int copyrightsZ);
+
+ void setCopyrightsVisible(bool visible);
+
+public Q_SLOTS:
+ void copyrightsChanged(const QImage &copyrightsImage);
+ void copyrightsChanged(const QString &copyrightsHtml);
+
+signals:
+ void linkActivated(const QString &link);
+
+protected:
+ void paint(QPainter *painter) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+ void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+
+private:
+ QTextDocument *m_copyrightsHtml;
+ QImage m_copyrightsImage;
+ QString m_activeAnchor;
+ bool m_copyrightsVisible;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
new file mode 100644
index 00000000..93d07386
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomapitembase_p.h"
+#include "qgeocameradata_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+#include <QtQml/QQmlInfo>
+#include <QtQuick/QSGOpacityNode>
+#include <QtQuick/private/qquickmousearea_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent()
+ : zoomLevelChanged(false),
+ centerChanged(false),
+ mapSizeChanged(false),
+ tiltChanged(false),
+ bearingChanged(false),
+ rollChanged(false)
+{
+}
+
+QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent(const QGeoMapViewportChangeEvent &other)
+{
+ this->operator=(other);
+}
+
+QGeoMapViewportChangeEvent &QGeoMapViewportChangeEvent::operator=(const QGeoMapViewportChangeEvent &other)
+{
+ if (this == &other)
+ return (*this);
+
+ cameraData = other.cameraData;
+ mapSize = other.mapSize;
+ zoomLevelChanged = other.zoomLevelChanged;
+ centerChanged = other.centerChanged;
+ mapSizeChanged = other.mapSizeChanged;
+ tiltChanged = other.tiltChanged;
+ bearingChanged = other.bearingChanged;
+ rollChanged = other.rollChanged;
+
+ return (*this);
+}
+
+QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent)
+: QQuickItem(parent), map_(0), quickMap_(0)
+{
+ setFiltersChildMouseEvents(true);
+ connect(this, SIGNAL(childrenChanged()),
+ this, SLOT(afterChildrenChanged()));
+}
+
+QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase()
+{
+ disconnect(this, SLOT(afterChildrenChanged()));
+ if (quickMap_)
+ quickMap_->removeMapItem(this);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemBase::afterChildrenChanged()
+{
+ QList<QQuickItem *> kids = childItems();
+ if (kids.size() > 0) {
+ bool printedWarning = false;
+ foreach (QQuickItem *i, kids) {
+ if (i->flags() & QQuickItem::ItemHasContents
+ && !qobject_cast<QQuickMouseArea *>(i)) {
+ if (!printedWarning) {
+ qmlWarning(this) << "Geographic map items do not support child items";
+ printedWarning = true;
+ }
+
+ qmlWarning(i) << "deleting this child";
+ i->deleteLater();
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ if (quickMap == quickMap_)
+ return;
+ if (quickMap && quickMap_)
+ return; // don't allow association to more than one map
+ if (quickMap_)
+ quickMap_->disconnect(this);
+ if (map_)
+ map_->disconnect(this);
+
+ quickMap_ = quickMap;
+ map_ = map;
+
+ if (map_ && quickMap_) {
+ connect(map_, SIGNAL(cameraDataChanged(QGeoCameraData)),
+ this, SLOT(baseCameraDataChanged(QGeoCameraData)));
+ connect(quickMap, SIGNAL(heightChanged()), this, SLOT(polishAndUpdate()));
+ connect(quickMap, SIGNAL(widthChanged()), this, SLOT(polishAndUpdate()));
+ lastSize_ = QSizeF(quickMap_->width(), quickMap_->height());
+ lastCameraData_ = map_->cameraData();
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemBase::baseCameraDataChanged(const QGeoCameraData &cameraData)
+{
+ QGeoMapViewportChangeEvent evt;
+ evt.cameraData = cameraData;
+ evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
+
+ if (evt.mapSize != lastSize_)
+ evt.mapSizeChanged = true;
+
+ if (cameraData.bearing() != lastCameraData_.bearing())
+ evt.bearingChanged = true;
+ if (cameraData.center() != lastCameraData_.center())
+ evt.centerChanged = true;
+ if (cameraData.roll() != lastCameraData_.roll())
+ evt.rollChanged = true;
+ if (cameraData.tilt() != lastCameraData_.tilt())
+ evt.tiltChanged = true;
+ if (cameraData.zoomLevel() != lastCameraData_.zoomLevel())
+ evt.zoomLevelChanged = true;
+
+ lastSize_ = evt.mapSize;
+ lastCameraData_ = cameraData;
+
+ afterViewportChanged(evt);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset)
+{
+ if (!map_ || !quickMap_)
+ return;
+
+ QDoubleVector2D wrappedProjection = map_->geoProjection().geoToWrappedMapProjection(coordinate);
+ if (! map_->geoProjection().isProjectable(wrappedProjection))
+ return;
+
+ QDoubleVector2D pos = map_->geoProjection().wrappedMapProjectionToItemPosition(wrappedProjection);
+ QPointF topLeft = pos.toPointF() - offset;
+
+ setPosition(topLeft);
+}
+
+static const double opacityRampMin = 1.5;
+static const double opacityRampMax = 2.5;
+/*!
+ \internal
+*/
+float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const
+{
+ if (quickMap_->zoomLevel() > opacityRampMax)
+ return 1.0;
+ else if (quickMap_->zoomLevel() > opacityRampMin)
+ return quickMap_->zoomLevel() - opacityRampMin;
+ else
+ return 0.0;
+}
+
+bool QDeclarativeGeoMapItemBase::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ Q_UNUSED(item)
+ if (event->type() == QEvent::MouseButtonPress && !contains(static_cast<QMouseEvent*>(event)->pos())) {
+ // This is an evil hack: in case of items that are not rectangles, we never accept the event.
+ // Instead the events are now delivered to QDeclarativeGeoMapItemBase which doesn't to anything with them.
+ // The map below it still works since it filters events and steals the events at some point.
+ event->setAccepted(false);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativeGeoMapItemBase::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *pd)
+{
+ if (!map_ || !quickMap_) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGOpacityNode *opn = static_cast<QSGOpacityNode *>(oldNode);
+ if (!opn)
+ opn = new QSGOpacityNode();
+
+ opn->setOpacity(zoomLevelOpacity());
+
+ QSGNode *oldN = opn->childCount() ? opn->firstChild() : 0;
+ opn->removeAllChildNodes();
+ if (opn->opacity() > 0.0) {
+ QSGNode *n = this->updateMapItemPaintNode(oldN, pd);
+ if (n)
+ opn->appendChildNode(n);
+ } else {
+ delete oldN;
+ }
+
+ return opn;
+}
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ delete oldNode;
+ return 0;
+}
+
+bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
+{
+ return QQuickItemPrivate::get(this)->polishScheduled;
+}
+
+void QDeclarativeGeoMapItemBase::polishAndUpdate()
+{
+ polish();
+ update();
+}
+
+
+#include "moc_qdeclarativegeomapitembase_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
new file mode 100644
index 00000000..82a24233
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPITEMBASE_H
+#define QDECLARATIVEGEOMAPITEMBASE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtQuick/QQuickItem>
+#include <QtPositioning/QGeoShape>
+
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qlocationglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QGeoMapViewportChangeEvent
+{
+public:
+ explicit QGeoMapViewportChangeEvent();
+ QGeoMapViewportChangeEvent(const QGeoMapViewportChangeEvent &other);
+ QGeoMapViewportChangeEvent &operator=(const QGeoMapViewportChangeEvent &other);
+
+ QGeoCameraData cameraData;
+ QSizeF mapSize;
+
+ bool zoomLevelChanged;
+ bool centerChanged;
+ bool mapSizeChanged;
+ bool tiltChanged;
+ bool bearingChanged;
+ bool rollChanged;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QGeoShape geoShape READ geoShape STORED false )
+public:
+ explicit QDeclarativeGeoMapItemBase(QQuickItem *parent = 0);
+ virtual ~QDeclarativeGeoMapItemBase();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map);
+ virtual void setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset);
+
+ QDeclarativeGeoMap *quickMap() { return quickMap_; }
+ QGeoMap *map() { return map_; }
+ virtual const QGeoShape &geoShape() const = 0;
+
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *);
+
+protected Q_SLOTS:
+ virtual void afterChildrenChanged();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) = 0;
+ void polishAndUpdate();
+
+protected:
+ float zoomLevelOpacity() const;
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event);
+ bool isPolishScheduled() const;
+
+private Q_SLOTS:
+ void baseCameraDataChanged(const QGeoCameraData &camera);
+
+private:
+ QGeoMap *map_;
+ QDeclarativeGeoMap *quickMap_;
+
+ QSizeF lastSize_;
+ QGeoCameraData lastCameraData_;
+
+ friend class QDeclarativeGeoMap;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp
new file mode 100644
index 00000000..cb1a4348
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp
@@ -0,0 +1,541 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Jolla Ltd.
+** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomapitemview_p.h"
+#include "qdeclarativegeomapitemview_p_p.h"
+#include "qdeclarativegeomap_p.h"
+#include "qdeclarativegeomapitembase_p.h"
+#include "mapitemviewdelegateincubator_p.h"
+
+#include <QtCore/QAbstractItemModel>
+#include <QtQml/QQmlContext>
+#include <QtQml/QQmlIncubator>
+#include <QtQml/private/qqmlopenmetaobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapItemView
+ \instantiates QDeclarativeGeoMapItemView
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+ \inherits QObject
+
+ \brief The MapItemView is used to populate Map from a model.
+
+ The MapItemView is used to populate Map with MapItems from a model.
+ The MapItemView type only makes sense when contained in a Map,
+ meaning that it has no standalone presentation.
+
+ \section2 Example Usage
+
+ This example demonstrates how to use the MapViewItem object to display
+ a \l{Route}{route} on a \l{Map}{map}:
+
+ \snippet declarative/maps.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/maps.qml MapRoute
+*/
+
+QDeclarativeGeoMapItemView::QDeclarativeGeoMapItemView(QQuickItem *parent)
+ : QObject(parent), componentCompleted_(false), delegate_(0),
+ itemModel_(0), map_(0), fitViewport_(false), m_metaObjectType(0),
+ m_readyIncubators(0), m_repopulating(false)
+{
+}
+
+QDeclarativeGeoMapItemView::~QDeclarativeGeoMapItemView()
+{
+ removeInstantiatedItems();
+ if (m_metaObjectType)
+ m_metaObjectType->release();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::componentComplete()
+{
+ componentCompleted_ = true;
+}
+
+void QDeclarativeGeoMapItemView::incubatorStatusChanged(MapItemViewDelegateIncubator *incubator,
+ QQmlIncubator::Status status,
+ bool batched)
+{
+ if (status == QQmlIncubator::Loading)
+ return;
+
+ QDeclarativeGeoMapItemViewItemData *itemData = incubator->m_itemData;
+ if (!itemData) {
+ // Should never get here
+ qWarning() << "MapItemViewDelegateIncubator incubating invalid itemData";
+ return;
+ }
+
+ switch (status) {
+ case QQmlIncubator::Ready:
+ {
+ QDeclarativeGeoMapItemBase *item = qobject_cast<QDeclarativeGeoMapItemBase *>(incubator->object());
+ if (!item)
+ break;
+ itemData->item = item;
+ if (!itemData->item) {
+ qWarning() << "QDeclarativeGeoMapItemView map item delegate is of unsupported type.";
+ delete incubator->object();
+ } else {
+ if (!batched) {
+ map_->addMapItem(itemData->item);
+ fitViewport();
+ } else {
+ ++m_readyIncubators; // QSemaphore not needed as multiple threads not involved
+
+ if (m_readyIncubators == m_itemDataBatched.size()) {
+
+ // Clearing stuff older than the reset
+ foreach (QDeclarativeGeoMapItemViewItemData *i, m_itemData)
+ removeItemData(i);
+ m_itemData.clear();
+
+ // Adding everthing created after reset was issued
+ foreach (QDeclarativeGeoMapItemViewItemData *i, m_itemDataBatched) {
+ map_->addMapItem(i->item);
+ }
+ m_itemData = m_itemDataBatched;
+ m_itemDataBatched.clear();
+
+ m_readyIncubators = 0;
+ m_repopulating = false;
+
+ fitViewport();
+ }
+ }
+ }
+ delete itemData->incubator;
+ itemData->incubator = 0;
+ break;
+ }
+ case QQmlIncubator::Null:
+ // Should never get here
+ delete itemData->incubator;
+ itemData->incubator = 0;
+ break;
+ case QQmlIncubator::Error:
+ qWarning() << "QDeclarativeGeoMapItemView map item creation failed.";
+ delete itemData->incubator;
+ itemData->incubator = 0;
+ break;
+ default:
+ ;
+ }
+}
+
+/*!
+ \qmlproperty model QtLocation::MapItemView::model
+
+ This property holds the model that provides data used for creating the map items defined by the
+ delegate. Only QAbstractItemModel based models are supported.
+*/
+QVariant QDeclarativeGeoMapItemView::model() const
+{
+ return QVariant::fromValue(itemModel_);
+}
+
+void QDeclarativeGeoMapItemView::setModel(const QVariant &model)
+{
+ QAbstractItemModel *itemModel = model.value<QAbstractItemModel *>();
+ if (itemModel == itemModel_)
+ return;
+
+ if (itemModel_) {
+ disconnect(itemModel_, SIGNAL(modelReset()), this, SLOT(itemModelReset()));
+ disconnect(itemModel_, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(itemModelRowsRemoved(QModelIndex,int,int)));
+ disconnect(itemModel_, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(itemModelRowsInserted(QModelIndex,int,int)));
+ disconnect(itemModel_, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(itemModelRowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ disconnect(itemModel_, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
+ this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>)));
+
+ removeInstantiatedItems(); // this also terminates ongong repopulations.
+ m_metaObjectType->release();
+ m_metaObjectType = 0;
+
+ itemModel_ = 0;
+ }
+
+ if (itemModel) {
+ itemModel_ = itemModel;
+ connect(itemModel_, SIGNAL(modelReset()), this, SLOT(itemModelReset()));
+ connect(itemModel_, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(itemModelRowsRemoved(QModelIndex,int,int)));
+ connect(itemModel_, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(itemModelRowsInserted(QModelIndex,int,int)));
+ connect(itemModel_, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
+ this, SLOT(itemModelRowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ connect(itemModel_, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
+ this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>)));
+
+ m_metaObjectType = new QQmlOpenMetaObjectType(&QObject::staticMetaObject, 0);
+ foreach (const QByteArray &name, itemModel_->roleNames())
+ m_metaObjectType->createProperty(name);
+
+ instantiateAllItems();
+ }
+
+ emit modelChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::itemModelReset()
+{
+ repopulate();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::itemModelRowsInserted(const QModelIndex &index, int start, int end)
+{
+ Q_UNUSED(index)
+
+ if (!componentCompleted_ || !map_ || !delegate_ || !itemModel_)
+ return;
+
+ for (int i = start; i <= end; ++i) {
+ const QModelIndex insertedIndex = itemModel_->index(i, 0, index);
+ // If ran inside a qquickwidget which forces incubators to be synchronous, this call won't happen
+ // with m_repopulating == true while incubators from a model reset are still incubating.
+ // Note that having the model in a different thread is not supported in general.
+ createItemForIndex(insertedIndex, m_repopulating);
+ }
+
+ fitViewport();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::itemModelRowsRemoved(const QModelIndex &index, int start, int end)
+{
+ Q_UNUSED(index)
+
+ if (!componentCompleted_ || !map_ || !delegate_ || !itemModel_)
+ return;
+
+ for (int i = end; i >= start; --i) {
+ if (m_repopulating) {
+ QDeclarativeGeoMapItemViewItemData *itemData = m_itemDataBatched.takeAt(i);
+ if (!itemData)
+ continue;
+ if (itemData->incubator) {
+ if (itemData->incubator->isReady()) {
+ --m_readyIncubators;
+ delete itemData->incubator->object();
+ }
+ itemData->incubator->clear();
+ }
+ delete itemData;
+ } else {
+ QDeclarativeGeoMapItemViewItemData *itemData = m_itemData.takeAt(i);
+ removeItemData(itemData);
+ }
+ }
+
+ fitViewport();
+}
+
+void QDeclarativeGeoMapItemView::itemModelRowsMoved(const QModelIndex &parent, int start, int end,
+ const QModelIndex &destination, int row)
+{
+ Q_UNUSED(parent)
+ Q_UNUSED(start)
+ Q_UNUSED(end)
+ Q_UNUSED(destination)
+ Q_UNUSED(row)
+
+ qWarning() << "QDeclarativeGeoMapItemView does not support models that move rows.";
+}
+
+void QDeclarativeGeoMapItemView::itemModelDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight,
+ const QVector<int> &roles)
+{
+ Q_UNUSED(roles)
+
+ if (!m_itemData.count() || (m_repopulating && !m_itemDataBatched.count()) )
+ return;
+
+ for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
+ const QModelIndex index = itemModel_->index(i, 0);
+ QDeclarativeGeoMapItemViewItemData *itemData;
+ if (m_repopulating)
+ itemData= m_itemDataBatched.at(i);
+ else
+ itemData= m_itemData.at(i);
+
+ QHashIterator<int, QByteArray> iterator(itemModel_->roleNames());
+ while (iterator.hasNext()) {
+ iterator.next();
+
+ QVariant modelData = itemModel_->data(index, iterator.key());
+ if (!modelData.isValid())
+ continue;
+
+ itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()),
+ modelData);
+ itemData->modelDataMeta->setValue(iterator.value(), modelData);
+ }
+ }
+}
+
+/*!
+ \qmlproperty Component QtLocation::MapItemView::delegate
+
+ This property holds the delegate which defines how each item in the
+ model should be displayed. The Component must contain exactly one
+ MapItem -derived object as the root object.
+*/
+QQmlComponent *QDeclarativeGeoMapItemView::delegate() const
+{
+ return delegate_;
+}
+
+void QDeclarativeGeoMapItemView::setDelegate(QQmlComponent *delegate)
+{
+ if (delegate_ == delegate)
+ return;
+
+ delegate_ = delegate;
+
+ repopulate();
+ emit delegateChanged();
+}
+
+/*!
+ \qmlproperty Component QtLocation::MapItemView::autoFitViewport
+
+ This property controls whether to automatically pan and zoom the viewport
+ to display all map items when items are added or removed.
+
+ Defaults to false.
+*/
+bool QDeclarativeGeoMapItemView::autoFitViewport() const
+{
+ return fitViewport_;
+}
+
+void QDeclarativeGeoMapItemView::setAutoFitViewport(const bool &fitViewport)
+{
+ if (fitViewport == fitViewport_)
+ return;
+ fitViewport_ = fitViewport;
+ emit autoFitViewportChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::fitViewport()
+{
+ if (!map_ || !fitViewport_ || m_repopulating)
+ return;
+
+ if (map_->mapItems().size() > 0)
+ map_->fitViewportToMapItems();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::setMap(QDeclarativeGeoMap *map)
+{
+ if (!map || map_) // changing map on the fly not supported
+ return;
+ map_ = map;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapItemView::removeInstantiatedItems()
+{
+ if (!map_)
+ return;
+
+ terminateOngoingRepopulation();
+ foreach (QDeclarativeGeoMapItemViewItemData *itemData, m_itemData)
+ removeItemData(itemData);
+ m_itemData.clear();
+}
+
+/*!
+ \internal
+
+ Instantiates all items.
+*/
+void QDeclarativeGeoMapItemView::instantiateAllItems()
+{
+ if (!componentCompleted_ || !map_ || !delegate_ || !itemModel_)
+ return;
+ Q_ASSERT(!m_itemDataBatched.size());
+ m_repopulating = true;
+
+ // QQuickWidget forces incubators to synchronous mode. Thus itemDataChanged gets called during the for loop below.
+ m_itemDataBatched.resize(itemModel_->rowCount());
+ for (int i = 0; i < itemModel_->rowCount(); ++i) {
+ const QModelIndex index = itemModel_->index(i, 0);
+ createItemForIndex(index, true);
+ }
+
+ fitViewport();
+}
+
+void QDeclarativeGeoMapItemView::removeItemData(QDeclarativeGeoMapItemViewItemData *itemData)
+{
+ if (!itemData)
+ return;
+ if (itemData->incubator) {
+ if (itemData->incubator->isReady()) {
+ if (itemData->incubator->object() == itemData->item) {
+ map_->removeMapItem(itemData->item); // removeMapItem checks whether the item is in the map, so it's safe to call.
+ itemData->item = 0;
+ }
+ delete itemData->incubator->object();
+ }
+ itemData->incubator->clear(); // stops ongoing incubation
+ }
+ if (itemData->item)
+ map_->removeMapItem(itemData->item);
+ delete itemData; // destroys the ->item too.
+}
+
+void QDeclarativeGeoMapItemView::terminateOngoingRepopulation()
+{
+ if (m_repopulating) {
+ // Terminate the previous resetting task. Not all incubators finished, but
+ // QQmlIncubatorController operates in the same thread, so it is safe
+ // to check, here, whether incubators are ready or not, without having
+ // to race with them.
+
+ foreach (QDeclarativeGeoMapItemViewItemData *itemData, m_itemDataBatched)
+ removeItemData(itemData);
+
+ m_itemDataBatched.clear();
+ m_readyIncubators = 0;
+ m_repopulating = false;
+ }
+}
+
+/*!
+ \internal
+ Removes and repopulates all items.
+*/
+void QDeclarativeGeoMapItemView::repopulate()
+{
+ if (!itemModel_ || !itemModel_->rowCount()) {
+ removeInstantiatedItems();
+ } else {
+ terminateOngoingRepopulation();
+ instantiateAllItems(); // removal of instantiated item done at incubation completion
+ }
+}
+
+/*!
+ \internal
+
+ Note: this call is async. that is returns to the event loop before returning to the caller.
+ May also trigger incubatorStatusChanged() before returning to the caller if the incubator is fast enough.
+*/
+void QDeclarativeGeoMapItemView::createItemForIndex(const QModelIndex &index, bool batched)
+{
+ // Expected to be already tested by caller.
+ Q_ASSERT(delegate_);
+ Q_ASSERT(itemModel_);
+
+ QDeclarativeGeoMapItemViewItemData *itemData = new QDeclarativeGeoMapItemViewItemData;
+
+ itemData->modelData = new QObject;
+ itemData->modelDataMeta = new QQmlOpenMetaObject(itemData->modelData, m_metaObjectType, false);
+ itemData->context = new QQmlContext(qmlContext(this));
+
+ QHashIterator<int, QByteArray> iterator(itemModel_->roleNames());
+ while (iterator.hasNext()) {
+ iterator.next();
+
+ QVariant modelData = itemModel_->data(index, iterator.key());
+ if (!modelData.isValid())
+ continue;
+
+ itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()),
+ modelData);
+
+ itemData->modelDataMeta->setValue(iterator.value(), modelData);
+ }
+
+ itemData->context->setContextProperty(QLatin1String("model"), itemData->modelData);
+ itemData->context->setContextProperty(QLatin1String("index"), index.row());
+
+ if (batched || m_repopulating) {
+ if (index.row() < m_itemDataBatched.size())
+ m_itemDataBatched.replace(index.row(), itemData);
+ else
+ m_itemDataBatched.insert(index.row(), itemData);
+ } else
+ m_itemData.insert(index.row(), itemData);
+ itemData->incubator = new MapItemViewDelegateIncubator(this, itemData, batched || m_repopulating);
+
+ delegate_->create(*itemData->incubator, itemData->context);
+}
+
+QDeclarativeGeoMapItemViewItemData::~QDeclarativeGeoMapItemViewItemData()
+{
+ delete incubator;
+ delete item;
+ delete context;
+ delete modelData;
+}
+
+#include "moc_qdeclarativegeomapitemview_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h
new file mode 100644
index 00000000..bd696d6e
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Jolla Ltd.
+** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPITEMVIEW_H
+#define QDECLARATIVEGEOMAPITEMVIEW_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtCore/QModelIndex>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlIncubator>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractItemModel;
+class QQmlComponent;
+class QQuickItem;
+class QDeclarativeGeoMap;
+class QDeclarativeGeoMapItemBase;
+class QQmlOpenMetaObject;
+class QQmlOpenMetaObjectType;
+class MapItemViewDelegateIncubator;
+class QDeclarativeGeoMapItemViewItemData;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemView : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+
+ Q_INTERFACES(QQmlParserStatus)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(bool autoFitViewport READ autoFitViewport WRITE setAutoFitViewport NOTIFY autoFitViewportChanged)
+
+public:
+ explicit QDeclarativeGeoMapItemView(QQuickItem *parent = 0);
+ ~QDeclarativeGeoMapItemView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *);
+
+ bool autoFitViewport() const;
+ void setAutoFitViewport(const bool &);
+
+ void setMap(QDeclarativeGeoMap *);
+ void repopulate();
+ void removeInstantiatedItems();
+ void instantiateAllItems();
+
+ qreal zValue();
+ void setZValue(qreal zValue);
+
+ // From QQmlParserStatus
+ virtual void componentComplete();
+ void classBegin() {}
+
+Q_SIGNALS:
+ void modelChanged();
+ void delegateChanged();
+ void autoFitViewportChanged();
+
+protected:
+ void incubatorStatusChanged(MapItemViewDelegateIncubator *incubator,
+ QQmlIncubator::Status status,
+ bool batched);
+
+private Q_SLOTS:
+ void itemModelReset();
+ void itemModelRowsInserted(const QModelIndex &index, int start, int end);
+ void itemModelRowsRemoved(const QModelIndex &index, int start, int end);
+ void itemModelRowsMoved(const QModelIndex &parent, int start, int end,
+ const QModelIndex &destination, int row);
+ void itemModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QVector<int> &roles);
+
+private:
+ void createItemForIndex(const QModelIndex &index, bool batched = false);
+ void fitViewport();
+ void terminateOngoingRepopulation();
+ void removeItemData(QDeclarativeGeoMapItemViewItemData *itemData);
+
+ bool componentCompleted_;
+ QQmlComponent *delegate_;
+ QAbstractItemModel *itemModel_;
+ QDeclarativeGeoMap *map_;
+ QVector<QDeclarativeGeoMapItemViewItemData *> m_itemData;
+ QVector<QDeclarativeGeoMapItemViewItemData *> m_itemDataBatched;
+ bool fitViewport_;
+
+ QQmlOpenMetaObjectType *m_metaObjectType;
+ int m_readyIncubators;
+ bool m_repopulating;
+
+ friend struct QDeclarativeGeoMapItemViewItemData;
+ friend class MapItemViewDelegateIncubator;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapItemView)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h
new file mode 100644
index 00000000..3ad3ceb4
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPITEMVIEW_P_P_H
+#define QDECLARATIVEGEOMAPITEMVIEW_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QModelIndex>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlIncubator>
+#include <QtQml/qqml.h>
+#include <QtQml/private/qqmlopenmetaobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class MapItemViewDelegateIncubator;
+class QDeclarativeGeoMapItemView;
+class QDeclarativeGeoMapItemBase;
+
+class QDeclarativeGeoMapItemViewItemData
+{
+public:
+ QDeclarativeGeoMapItemViewItemData()
+ : incubator(0), item(0), context(0), modelData(0), modelDataMeta(0)
+ {
+ }
+
+ ~QDeclarativeGeoMapItemViewItemData();
+
+ MapItemViewDelegateIncubator *incubator;
+ QDeclarativeGeoMapItemBase *item;
+ QQmlContext *context;
+ QObject *modelData;
+ QQmlOpenMetaObject *modelDataMeta;
+
+ friend class MapItemViewDelegateIncubator;
+ friend class QDeclarativeGeoMapItemView;
+};
+
+Q_DECLARE_TYPEINFO(QDeclarativeGeoMapItemViewItemData, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEGEOMAPITEMVIEW_P_P_H
diff --git a/src/location/declarativemaps/qdeclarativegeomapparameter.cpp b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp
new file mode 100644
index 00000000..88d609f4
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapparameter.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomapparameter_p.h"
+
+#include <QByteArray>
+#include <QMetaObject>
+#include <QMetaProperty>
+#include <QSignalMapper>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapParameter
+ \instantiates QDeclarativeGeoMapParameter
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.9
+
+ \brief The MapParameter type represents a parameter for a Map element.
+ This type provides a mean to specify plugin-dependent optional parameters
+ for a map.
+
+ MapParameters by default contain only the \l type property, and
+ are highly plugin-dependent.
+ For this reason, additional properties have to be defined inside a
+ MapParameter at declaration time, using the QML syntax "property var foo".
+
+ What properties have to be put inside a particular MapParameter type for
+ a particular plugin can be found in the documentation of the plugin.
+ Note that MapProperties are \b optional.
+ By not specifying any of them, the Map will have the default behavior.
+
+ The release of this API with Qt 5.9 is a Technology Preview.
+*/
+
+/*!
+ \qmlproperty georectangle QtLocation::MapParameter::type
+
+ Set-once property which holds a string defining the type of the MapParameter
+*/
+
+QDeclarativeGeoMapParameter::QDeclarativeGeoMapParameter(QObject *parent)
+: QGeoMapParameter(parent), m_initialPropertyCount(metaObject()->propertyCount()), m_complete(false)
+{
+
+}
+
+QDeclarativeGeoMapParameter::~QDeclarativeGeoMapParameter()
+{
+}
+
+bool QDeclarativeGeoMapParameter::isComponentComplete() const
+{
+ return m_complete;
+}
+
+int QDeclarativeGeoMapParameter::initialPropertyCount() const
+{
+ return m_initialPropertyCount;
+}
+
+void QDeclarativeGeoMapParameter::classBegin()
+{
+}
+
+void QDeclarativeGeoMapParameter::componentComplete()
+{
+ for (int i = m_initialPropertyCount; i < metaObject()->propertyCount(); ++i) {
+ QMetaProperty property = metaObject()->property(i);
+
+ if (!property.hasNotifySignal()) {
+ return;
+ }
+
+ QSignalMapper *mapper = new QSignalMapper(this);
+ mapper->setMapping(this, i);
+
+ const QByteArray signalName = '2' + property.notifySignal().methodSignature(); // TODO: explain why '2'
+ QObject::connect(this, signalName, mapper, SLOT(map()));
+ QObject::connect(mapper, SIGNAL(mapped(int)), this, SLOT(onPropertyUpdated(int)));
+ }
+ m_complete = true;
+ emit completed(this);
+}
+
+void QDeclarativeGeoMapParameter::onPropertyUpdated(int index)
+{
+ emit propertyUpdated(this, metaObject()->property(index).name());
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapparameter_p.h b/src/location/declarativemaps/qdeclarativegeomapparameter_p.h
new file mode 100644
index 00000000..0f54e1b7
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapparameter_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPPARAMETER_P_H
+#define QDECLARATIVEGEOMAPPARAMETER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qgeomapparameter_p.h>
+#include <QQmlParserStatus>
+#include <qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapParameter : public QGeoMapParameter, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativeGeoMapParameter(QObject *parent = 0);
+ virtual ~QDeclarativeGeoMapParameter();
+
+ bool isComponentComplete() const;
+
+Q_SIGNALS:
+ void completed(QDeclarativeGeoMapParameter *);
+
+protected:
+ int initialPropertyCount() const;
+ // QQmlParserStatus implementation
+ void classBegin() override;
+ void componentComplete() override;
+
+private slots:
+ void onPropertyUpdated(int index);
+
+private:
+ int m_initialPropertyCount;
+ bool m_complete;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapParameter)
+
+#endif // QDECLARATIVEGEOMAPPARAMETER_P_H
diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp
new file mode 100644
index 00000000..b3b8aa8a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapquickitem.cpp
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomapquickitem_p.h"
+
+#include <QtCore/QScopedValueRollback>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/QSGOpacityNode>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtQuick/private/qquickmousearea_p.h>
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <QDebug>
+#include <cmath>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapQuickItem
+ \instantiates QDeclarativeGeoMapQuickItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapQuickItem type displays an arbitrary Qt Quick object
+ on a Map.
+
+ The MapQuickItem type is used to place an arbitrary Qt Quick object
+ on a Map at a specified location and size. Compared to floating an item
+ above the Map, a MapQuickItem will follow the panning (and optionally, the
+ zooming) of the Map as if it is on the Map surface.
+
+ The \l{sourceItem} property contains the Qt Quick item to be drawn, which
+ can be any kind of visible type.
+
+ \section2 Positioning and Sizing
+
+ The positioning of the MapQuickItem on the Map is controlled by two
+ properties: \l coordinate and \l anchorPoint. If only \l coordinate is set,
+ it specifies a longitude/latitude coordinate for the item to be placed at.
+ The set coordinate will line up with the top-left corner of the contained
+ item when shown on the screen.
+
+ The \l anchorPoint property provides a way to line up the coordinate with
+ other parts of the item than just the top-left corner, by setting a number
+ of pixels the item will be offset by. A simple way to think about it is
+ to note that the point given by \l anchorPoint on the item itself is the
+ point that will line up with the given \l coordinate when displayed.
+
+ In addition to being anchored to the map, the MapQuickItem can optionally
+ follow the scale of the map, and change size when the Map is zoomed in or
+ zoomed out. This behaviour is controlled by the \l zoomLevel property. The
+ default behaviour if \l zoomLevel is not set is for the item to be drawn
+ "on the screen" rather than "on the map", so that its size remains the same
+ regardless of the zoom level of the Map.
+
+ \section2 Performance
+
+ Performance of a MapQuickItem is normally in the same ballpark as the
+ contained Qt Quick item alone. Overheads added amount to a translation
+ and (possibly) scaling of the original item, as well as a transformation
+ from longitude and latitude to screen position.
+
+ \section2 Limitations
+
+ \note Due to an implementation detail, items placed inside a
+ MapQuickItem will have a \c{parent} item which is not the MapQuickItem.
+ Refer to the MapQuickItem by its \c{id}, and avoid the use of \c{anchor}
+ in the \c{sourceItem}.
+
+ \section2 Example Usage
+
+ The following snippet shows a MapQuickItem containing an Image object,
+ to display a Marker on the Map. This strategy is used to show the map
+ markers in the MapViewer example.
+
+ \snippet mapviewer/map/Marker.qml mqi-top
+ \snippet mapviewer/map/Marker.qml mqi-anchor
+ \snippet mapviewer/map/Marker.qml mqi-closeimage
+ \snippet mapviewer/map/Marker.qml mqi-close
+
+ \image api-mapquickitem.png
+*/
+
+QDeclarativeGeoMapQuickItem::QDeclarativeGeoMapQuickItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), zoomLevel_(0.0),
+ mapAndSourceItemSet_(false), updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ opacityContainer_ = new QQuickItem(this);
+ opacityContainer_->setParentItem(this);
+ opacityContainer_->setFlag(ItemHasContents, true);
+}
+
+QDeclarativeGeoMapQuickItem::~QDeclarativeGeoMapQuickItem() {}
+
+/*!
+ \qmlproperty coordinate MapQuickItem::coordinate
+
+ This property holds the anchor coordinate of the MapQuickItem. The point
+ on the sourceItem that is specified by anchorPoint is kept aligned with
+ this coordinate when drawn on the map.
+
+ In the image below, there are 3 MapQuickItems that are identical except
+ for the value of their anchorPoint properties. The values of anchorPoint
+ for each are written on top of the item.
+
+ \image api-mapquickitem-anchor.png
+*/
+void QDeclarativeGeoMapQuickItem::setCoordinate(const QGeoCoordinate &coordinate)
+{
+ if (coordinate_ == coordinate)
+ return;
+
+ coordinate_ = coordinate;
+ geoshape_.setTopLeft(coordinate_);
+ geoshape_.setBottomRight(coordinate_);
+ // TODO: Handle zoomLevel != 0.0
+
+ polishAndUpdate();
+ emit coordinateChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map && quickMap) {
+ connect(map, SIGNAL(cameraDataChanged(QGeoCameraData)),
+ this, SLOT(polishAndUpdate()));
+ polishAndUpdate();
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (!mapAndSourceItemSet_ || updatingGeometry_ ||
+ newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+
+ QGeoCoordinate newCoordinate = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(x(), y()) + (scaleFactor() * QDoubleVector2D(anchorPoint_)), false);
+ if (newCoordinate.isValid())
+ setCoordinate(newCoordinate);
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+/*!
+ \internal
+*/
+QGeoCoordinate QDeclarativeGeoMapQuickItem::coordinate()
+{
+ return coordinate_;
+}
+
+/*!
+ \qmlproperty object MapQuickItem::sourceItem
+
+ This property holds the source item that will be drawn on the map.
+*/
+void QDeclarativeGeoMapQuickItem::setSourceItem(QQuickItem *sourceItem)
+{
+ if (sourceItem_.data() == sourceItem)
+ return;
+ sourceItem_ = sourceItem;
+
+ polishAndUpdate();
+ emit sourceItemChanged();
+}
+
+QQuickItem *QDeclarativeGeoMapQuickItem::sourceItem()
+{
+ return sourceItem_.data();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::afterChildrenChanged()
+{
+ QList<QQuickItem *> kids = childItems();
+ if (kids.size() > 0) {
+ bool printedWarning = false;
+ foreach (QQuickItem *i, kids) {
+ if (i->flags() & QQuickItem::ItemHasContents
+ && !qobject_cast<QQuickMouseArea *>(i)
+ && sourceItem_.data() != i
+ && opacityContainer_ != i) {
+ if (!printedWarning) {
+ qmlWarning(this) << "Use the sourceItem property for the contained item, direct children are not supported";
+ printedWarning = true;
+ }
+
+ qmlWarning(i) << "deleting this child";
+ i->deleteLater();
+ }
+ }
+ }
+}
+
+/*!
+ \qmlproperty QPointF MapQuickItem::anchorPoint
+
+ This property determines which point on the sourceItem that will be lined
+ up with the coordinate on the map.
+*/
+void QDeclarativeGeoMapQuickItem::setAnchorPoint(const QPointF &anchorPoint)
+{
+ if (anchorPoint == anchorPoint_)
+ return;
+ anchorPoint_ = anchorPoint;
+ polishAndUpdate();
+ emit anchorPointChanged();
+}
+
+QPointF QDeclarativeGeoMapQuickItem::anchorPoint() const
+{
+ return anchorPoint_;
+}
+
+/*!
+ \qmlproperty real MapQuickItem::zoomLevel
+
+ This property controls the scaling behaviour of the contents of the
+ MapQuickItem. In particular, by setting this property it is possible
+ to choose between objects that are drawn on the screen (and sized in
+ screen pixels), and those drawn on the map surface (which change size
+ with the zoom level of the map).
+
+ The default value for this property is 0.0, which corresponds to drawing
+ the object on the screen surface. If set to another value, the object will
+ be drawn on the map surface instead. The value (if not zero) specifies the
+ zoomLevel at which the object will be visible at a scale of 1:1 (ie, where
+ object pixels and screen pixels are the same). At zoom levels lower than
+ this, the object will appear smaller, and at higher zoom levels, appear
+ larger. This is in contrast to when this property is set to zero, where
+ the object remains the same size on the screen at all zoom levels.
+*/
+void QDeclarativeGeoMapQuickItem::setZoomLevel(qreal zoomLevel)
+{
+ if (zoomLevel == zoomLevel_)
+ return;
+ zoomLevel_ = zoomLevel;
+ // TODO: update geoshape_!
+ polishAndUpdate();
+ emit zoomLevelChanged();
+}
+
+qreal QDeclarativeGeoMapQuickItem::zoomLevel() const
+{
+ return zoomLevel_;
+}
+
+const QGeoShape &QDeclarativeGeoMapQuickItem::geoShape() const
+{
+ // TODO: return a QGeoRectangle representing the bounding geo rectangle of the quick item
+ // when zoomLevel_ is != 0.0
+ return geoshape_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::updatePolish()
+{
+ if (!quickMap() && sourceItem_) {
+ mapAndSourceItemSet_ = false;
+ sourceItem_.data()->setParentItem(0);
+ return;
+ }
+
+ if (!quickMap() || !map() || !sourceItem_) {
+ mapAndSourceItemSet_ = false;
+ return;
+ }
+
+ if (!mapAndSourceItemSet_ && quickMap() && map() && sourceItem_) {
+ mapAndSourceItemSet_ = true;
+ sourceItem_.data()->setParentItem(opacityContainer_);
+ sourceItem_.data()->setTransformOrigin(QQuickItem::TopLeft);
+ connect(sourceItem_.data(), SIGNAL(xChanged()),
+ this, SLOT(polishAndUpdate()));
+ connect(sourceItem_.data(), SIGNAL(yChanged()),
+ this, SLOT(polishAndUpdate()));
+ connect(sourceItem_.data(), SIGNAL(widthChanged()),
+ this, SLOT(polishAndUpdate()));
+ connect(sourceItem_.data(), SIGNAL(heightChanged()),
+ this, SLOT(polishAndUpdate()));
+ }
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ opacityContainer_->setOpacity(zoomLevelOpacity());
+
+ sourceItem_.data()->setScale(scaleFactor());
+ sourceItem_.data()->setPosition(QPointF(0,0));
+ setWidth(sourceItem_.data()->width());
+ setHeight(sourceItem_.data()->height());
+ setPositionOnMap(coordinate(), scaleFactor() * anchorPoint_);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoMapQuickItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeGeoMapQuickItem::scaleFactor()
+{
+ qreal scale = 1.0;
+ // use 1+x to avoid fuzzy compare against zero
+ if (!qFuzzyCompare(1.0 + zoomLevel_, 1.0))
+ scale = std::pow(0.5, zoomLevel_ - map()->cameraData().zoomLevel());
+ return scale;
+}
+
+#include "moc_qdeclarativegeomapquickitem_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h
new file mode 100644
index 00000000..2d910167
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomapquickitem_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPQUICKITEM_H
+#define QDECLARATIVEGEOMAPQUICKITEM_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtQuick/QQuickItem>
+#include <QtQuick/QSGNode>
+
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtPositioning/qgeoshape.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapQuickItem : public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+ Q_PROPERTY(QGeoCoordinate coordinate READ coordinate WRITE setCoordinate NOTIFY coordinateChanged)
+ Q_PROPERTY(QPointF anchorPoint READ anchorPoint WRITE setAnchorPoint NOTIFY anchorPointChanged)
+ Q_PROPERTY(qreal zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged)
+ Q_PROPERTY(QQuickItem *sourceItem READ sourceItem WRITE setSourceItem NOTIFY sourceItemChanged)
+
+public:
+ explicit QDeclarativeGeoMapQuickItem(QQuickItem *parent = 0);
+ ~QDeclarativeGeoMapQuickItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+
+ void setCoordinate(const QGeoCoordinate &coordinate);
+ QGeoCoordinate coordinate();
+
+ void setSourceItem(QQuickItem *sourceItem);
+ QQuickItem *sourceItem();
+
+ void setAnchorPoint(const QPointF &anchorPoint);
+ QPointF anchorPoint() const;
+
+ void setZoomLevel(qreal zoomLevel);
+ qreal zoomLevel() const;
+
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void coordinateChanged();
+ void sourceItemChanged();
+ void anchorPointChanged();
+ void zoomLevelChanged();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ virtual void afterChildrenChanged() Q_DECL_OVERRIDE;
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ qreal scaleFactor();
+ QGeoCoordinate coordinate_;
+ QGeoRectangle geoshape_;
+ QPointer<QQuickItem> sourceItem_;
+ QQuickItem *opacityContainer_;
+ QPointF anchorPoint_;
+ qreal zoomLevel_;
+ bool mapAndSourceItemSet_;
+ bool updatingGeometry_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapQuickItem)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeomaptype.cpp b/src/location/declarativemaps/qdeclarativegeomaptype.cpp
new file mode 100644
index 00000000..0b90ec3a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaptype.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeomaptype_p.h"
+#include <qnumeric.h>
+#include <QtQml/qqml.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapType
+ \instantiates QDeclarativeGeoMapType
+ \inherits QObject
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapType type holds information about a map type.
+
+ This includes the map type's \l name and \l description, the \l style and
+ a flag to indicate if the map type is optimized for mobile devices (\l mobile).
+*/
+
+QDeclarativeGeoMapType::QDeclarativeGeoMapType(const QGeoMapType mapType, QObject *parent)
+ : QObject(parent),
+ mapType_(mapType) {}
+
+QDeclarativeGeoMapType::~QDeclarativeGeoMapType() {}
+
+/*!
+ \qmlproperty enumeration MapType::style
+
+ This read-only property gives access to the style of the map type.
+
+ \list
+ \li MapType.NoMap - No map.
+ \li MapType.StreetMap - A street map.
+ \li MapType.SatelliteMapDay - A map with day-time satellite imagery.
+ \li MapType.SatelliteMapNight - A map with night-time satellite imagery.
+ \li MapType.TerrainMap - A terrain map.
+ \li MapType.HybridMap - A map with satellite imagery and street information.
+ \li MapType.GrayStreetMap - A gray-shaded street map.
+ \li MapType.PedestrianMap - A street map suitable for pedestriants.
+ \li MapType.CarNavigationMap - A street map suitable for car navigation.
+ \li MapType.CycleMap - A street map suitable for cyclists.
+ \li MapType.CustomMap - A custom map type.
+ \endlist
+*/
+QDeclarativeGeoMapType::MapStyle QDeclarativeGeoMapType::style() const
+{
+ return QDeclarativeGeoMapType::MapStyle(mapType_.style());
+}
+
+/*!
+ \qmlproperty string MapType::name
+
+ This read-only property holds the name of the map type as a single formatted string.
+*/
+QString QDeclarativeGeoMapType::name() const
+{
+ return mapType_.name();
+}
+
+/*!
+ \qmlproperty string MapType::description
+
+ This read-only property holds the description of the map type as a single formatted string.
+*/
+QString QDeclarativeGeoMapType::description() const
+{
+ return mapType_.description();
+}
+
+/*!
+ \qmlproperty bool MapType::mobile
+
+ \brief Whether the map type is optimized for the use on a mobile device.
+
+ Map types for mobile devices usually have higher constrast to counteract the
+ effects of sunlight and a reduced color for improved readability.
+*/
+bool QDeclarativeGeoMapType::mobile() const
+{
+ return mapType_.mobile();
+}
+
+/*!
+ \qmlproperty bool MapType::night
+ \since Qt Location 5.4
+
+ \brief Whether the map type is optimized for use at night.
+
+ Map types suitable for use at night usually have a dark background.
+*/
+bool QDeclarativeGeoMapType::night() const
+{
+ return mapType_.night();
+}
+
+#include "moc_qdeclarativegeomaptype_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeomaptype_p.h b/src/location/declarativemaps/qdeclarativegeomaptype_p.h
new file mode 100644
index 00000000..7b449aa0
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeomaptype_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOMAPTYPE_H
+#define QDECLARATIVEGEOMAPTYPE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtCore/QObject>
+#include <QtQml/qqml.h>
+#include <QtLocation/private/qgeomaptype_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapType : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(MapStyle)
+
+ Q_PROPERTY(MapStyle style READ style CONSTANT)
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString description READ description CONSTANT)
+ Q_PROPERTY(bool mobile READ mobile CONSTANT)
+ Q_PROPERTY(bool night READ night CONSTANT REVISION 1)
+
+public:
+ enum MapStyle {
+ NoMap = QGeoMapType::NoMap,
+ StreetMap = QGeoMapType::StreetMap,
+ SatelliteMapDay = QGeoMapType::SatelliteMapDay,
+ SatelliteMapNight = QGeoMapType::SatelliteMapNight,
+ TerrainMap = QGeoMapType::TerrainMap,
+ HybridMap = QGeoMapType::HybridMap,
+ TransitMap = QGeoMapType::TransitMap,
+ GrayStreetMap = QGeoMapType::GrayStreetMap,
+ PedestrianMap = QGeoMapType::PedestrianMap,
+ CarNavigationMap = QGeoMapType::CarNavigationMap,
+ CycleMap = QGeoMapType::CycleMap,
+ CustomMap = 100
+ };
+
+ QDeclarativeGeoMapType(const QGeoMapType mapType, QObject *parent = 0);
+ ~QDeclarativeGeoMapType();
+
+ MapStyle style() const;
+ QString name() const;
+ QString description() const;
+ bool mobile() const;
+ bool night() const;
+
+ const QGeoMapType mapType() { return mapType_; }
+
+private:
+ QGeoMapType mapType_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoMapType)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeoroute.cpp b/src/location/declarativemaps/qdeclarativegeoroute.cpp
new file mode 100644
index 00000000..fd6378da
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroute.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeoroute_p.h"
+#include "locationvaluetypehelper_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <QtQml/QQmlEngine>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtPositioning/QGeoRectangle>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Route
+ \instantiates QDeclarativeGeoRoute
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The Route type represents one geographical route.
+
+ A Route type contains high level information about a route, such
+ as the length the route, the estimated travel time for the route,
+ and enough information to render a basic image of the route on a map.
+
+ The QGeoRoute object also contains a list of \l RouteSegment objects which
+ describe subsections of the route in greater detail.
+
+ The primary means of acquiring Route objects is \l RouteModel.
+
+ \section1 Example
+
+ This example shows how to display a route's maneuvers in a ListView:
+
+ \snippet declarative/routing.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/routing.qml Route Maneuver List1
+ \snippet declarative/routing.qml Route Maneuver List2
+ \snippet declarative/routing.qml Route Maneuver List3
+
+*/
+
+QDeclarativeGeoRoute::QDeclarativeGeoRoute(QObject *parent)
+ : QObject(parent)
+{
+ this->init();
+}
+
+QDeclarativeGeoRoute::QDeclarativeGeoRoute(const QGeoRoute &route, QObject *parent)
+ : QObject(parent),
+ route_(route)
+{
+ this->init();
+}
+
+QDeclarativeGeoRoute::~QDeclarativeGeoRoute() {}
+
+void QDeclarativeGeoRoute::init()
+{
+ QGeoRouteSegment segment = route_.firstRouteSegment();
+ while (segment.isValid()) {
+ QDeclarativeGeoRouteSegment *routeSegment = new QDeclarativeGeoRouteSegment(segment, this);
+ QQmlEngine::setContextForObject(routeSegment, QQmlEngine::contextForObject(this));
+ segments_.append(routeSegment);
+ segment = segment.nextRouteSegment();
+ }
+}
+
+/*!
+ \internal
+*/
+QList<QGeoCoordinate> QDeclarativeGeoRoute::routePath()
+{
+ return route_.path();
+}
+
+/*!
+ \qmlproperty georectangle QtLocation::Route::bounds
+
+ Read-only property which holds a bounding box which encompasses the entire route.
+
+*/
+
+QGeoRectangle QDeclarativeGeoRoute::bounds() const
+{
+ return route_.bounds();
+}
+
+/*!
+ \qmlproperty int QtLocation::Route::travelTime
+
+ Read-only property which holds the estimated amount of time it will take to
+ traverse this route, in seconds.
+
+*/
+
+int QDeclarativeGeoRoute::travelTime() const
+{
+ return route_.travelTime();
+}
+
+/*!
+ \qmlproperty real QtLocation::Route::distance
+
+ Read-only property which holds distance covered by this route, in meters.
+*/
+
+qreal QDeclarativeGeoRoute::distance() const
+{
+ return route_.distance();
+}
+
+/*!
+ \qmlproperty QJSValue QtLocation::Route::path
+
+ Read-only property which holds the geographical coordinates of this route.
+ Coordinates are listed in the order in which they would be traversed by someone
+ traveling along this segment of the route.
+
+ To access individual segments you can use standard list accessors: 'path.length'
+ indicates the number of objects and 'path[index starting from zero]' gives
+ the actual object.
+
+ \sa QtPositioning::coordinate
+*/
+
+QJSValue QDeclarativeGeoRoute::path() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(parent());
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(route_.path().length()));
+ for (int i = 0; i < route_.path().length(); ++i) {
+ const QGeoCoordinate &c = route_.path().at(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ pathArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, pathArray.asReturnedValue());
+}
+
+void QDeclarativeGeoRoute::setPath(const QJSValue &value)
+{
+ if (!value.isArray())
+ return;
+
+ QList<QGeoCoordinate> pathList;
+ quint32 length = value.property(QStringLiteral("length")).toUInt();
+ for (quint32 i = 0; i < length; ++i) {
+ bool ok;
+ QGeoCoordinate c = parseCoordinate(value.property(i), &ok);
+
+ if (!ok || !c.isValid()) {
+ qmlWarning(this) << "Unsupported path type";
+ return;
+ }
+
+ pathList.append(c);
+ }
+
+ if (route_.path() == pathList)
+ return;
+
+ route_.setPath(pathList);
+
+ emit pathChanged();
+}
+
+/*!
+ \qmlproperty list<RouteSegment> QtLocation::Route::segments
+
+ Read-only property which holds the list of \l RouteSegment objects of this route.
+
+ To access individual segments you can use standard list accessors: 'segments.length'
+ indicates the number of objects and 'segments[index starting from zero]' gives
+ the actual objects.
+
+ \sa RouteSegment
+*/
+
+QQmlListProperty<QDeclarativeGeoRouteSegment> QDeclarativeGeoRoute::segments()
+{
+ return QQmlListProperty<QDeclarativeGeoRouteSegment>(this, 0, segments_append, segments_count,
+ segments_at, segments_clear);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRoute::segments_append(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop,
+ QDeclarativeGeoRouteSegment *segment)
+{
+ static_cast<QDeclarativeGeoRoute *>(prop->object)->appendSegment(segment);
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeGeoRoute::segments_count(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop)
+{
+ return static_cast<QDeclarativeGeoRoute *>(prop->object)->segments_.count();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoRouteSegment *QDeclarativeGeoRoute::segments_at(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, int index)
+{
+ return static_cast<QDeclarativeGeoRoute *>(prop->object)->segments_.at(index);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRoute::segments_clear(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop)
+{
+ static_cast<QDeclarativeGeoRoute *>(prop->object)->clearSegments();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRoute::appendSegment(QDeclarativeGeoRouteSegment *segment)
+{
+ segments_.append(segment);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRoute::clearSegments()
+{
+ segments_.clear();
+}
+
+#include "moc_qdeclarativegeoroute_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeoroute_p.h b/src/location/declarativemaps/qdeclarativegeoroute_p.h
new file mode 100644
index 00000000..e4501770
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroute_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOROUTE_H
+#define QDECLARATIVEGEOROUTE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoroutesegment_p.h>
+
+#include <QtCore/QObject>
+#include <QtQml/QQmlListProperty>
+#include <QtLocation/QGeoRoute>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRoute : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QGeoRectangle bounds READ bounds CONSTANT)
+ Q_PROPERTY(int travelTime READ travelTime CONSTANT)
+ Q_PROPERTY(qreal distance READ distance CONSTANT)
+ Q_PROPERTY(QJSValue path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeGeoRouteSegment> segments READ segments CONSTANT)
+
+public:
+ explicit QDeclarativeGeoRoute(QObject *parent = 0);
+ QDeclarativeGeoRoute(const QGeoRoute &route, QObject *parent = 0);
+ ~QDeclarativeGeoRoute();
+
+ QGeoRectangle bounds() const;
+ int travelTime() const;
+ qreal distance() const;
+
+ QJSValue path() const;
+ void setPath(const QJSValue &value);
+
+ QQmlListProperty<QDeclarativeGeoRouteSegment> segments();
+
+ void appendSegment(QDeclarativeGeoRouteSegment *segment);
+ void clearSegments();
+
+Q_SIGNALS:
+ void pathChanged();
+
+private:
+ static void segments_append(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, QDeclarativeGeoRouteSegment *segment);
+ static int segments_count(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop);
+ static QDeclarativeGeoRouteSegment *segments_at(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop, int index);
+ static void segments_clear(QQmlListProperty<QDeclarativeGeoRouteSegment> *prop);
+
+ void init();
+ QList<QGeoCoordinate> routePath();
+
+ QGeoRoute route_;
+ QList<QDeclarativeGeoRouteSegment *> segments_;
+ friend class QDeclarativeRouteMapItem;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
new file mode 100644
index 00000000..90796412
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel.cpp
@@ -0,0 +1,1308 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeoroutemodel_p.h"
+#include "qdeclarativegeoroute_p.h"
+#include "error_messages.h"
+#include "locationvaluetypehelper_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtQml/QQmlEngine>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtLocation/QGeoRoutingManager>
+#include <QtPositioning/QGeoRectangle>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RouteModel
+ \instantiates QDeclarativeGeoRouteModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The RouteModel type provides access to routes.
+
+ The RouteModel type is used as part of a model/view grouping to retrieve
+ geographic routes from a backend provider. Routes include data about driving
+ directions between two points, walking directions with multiple waypoints,
+ and various other similar concepts. It functions much like other Model
+ types in QML (see for example \l {Models and Views in Qt Quick#ListModel}{ListModel} and
+ \l XmlListModel), and interacts with views such as \l MapItemView, and \l{ListView}.
+
+ Like \l Map and \l GeocodeModel, all the data for a RouteModel to work comes
+ from a services plugin. This is contained in the \l{plugin} property, and
+ this must be set before the RouteModel can do any useful work.
+
+ Once the plugin is set, create a \l RouteQuery with the appropriate
+ waypoints and other settings, and set the RouteModel's \l{query}
+ property. If \l autoUpdate is enabled, the update will being automatically.
+ Otherwise, the \l{update} method may be used. By default, autoUpdate is
+ disabled.
+
+ The data stored and returned in the RouteModel consists of \l Route objects,
+ as a list with the role name "routeData". See the documentation for \l Route
+ for further details on its structure and contents.
+
+ \section2 Example Usage
+
+ The following snippet is two-part, showing firstly the declaration of
+ objects, and secondly a short piece of procedural code using it. We set
+ the routeModel's \l{autoUpdate} property to false, and call \l{update} once
+ the query is set up, to avoid useless extra requests halfway through the
+ set up of the query.
+
+ \code
+ Plugin {
+ id: aPlugin
+ name: "osm"
+ }
+
+ RouteQuery {
+ id: aQuery
+ }
+
+ RouteModel {
+ id: routeModel
+ plugin: aPlugin
+ query: aQuery
+ autoUpdate: false
+ }
+ \endcode
+
+ \code
+ {
+ aQuery.addWaypoint(...)
+ aQuery.addWaypoint(...)
+ aQuery.travelModes = ...
+ routeModel.update()
+ }
+ \endcode
+
+*/
+
+QDeclarativeGeoRouteModel::QDeclarativeGeoRouteModel(QObject *parent)
+ : QAbstractListModel(parent),
+ complete_(false),
+ plugin_(0),
+ routeQuery_(0),
+ autoUpdate_(false),
+ status_(QDeclarativeGeoRouteModel::Null),
+ error_(QDeclarativeGeoRouteModel::NoError)
+{
+}
+
+QDeclarativeGeoRouteModel::~QDeclarativeGeoRouteModel()
+{
+ if (!routes_.empty()) {
+ qDeleteAll(routes_);
+ routes_.clear();
+ }
+}
+
+/*!
+ \qmlproperty int QtLocation::RouteModel::count
+
+ This property holds how many routes the model currently has.
+ Amongst other uses, you can use this value when accessing routes
+ via the QtLocation::RouteModel::get -method.
+*/
+
+int QDeclarativeGeoRouteModel::count() const
+{
+ return routes_.count();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteModel::reset()
+
+ Resets the model. All route data is cleared, any outstanding requests
+ are aborted and possible errors are cleared. Model status will be set
+ to RouteModel.Null
+*/
+
+void QDeclarativeGeoRouteModel::reset()
+{
+ if (!routes_.isEmpty()) {
+ beginResetModel();
+ qDeleteAll(routes_);
+ routes_.clear();
+ emit countChanged();
+ emit routesChanged();
+ endResetModel();
+ }
+
+ emit abortRequested();
+ setError(NoError, QString());
+ setStatus(QDeclarativeGeoRouteModel::Null);
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteModel::cancel()
+
+ Cancels any outstanding requests and clears errors. Model status will be set to either
+ RouteModel.Null or RouteModel.Ready.
+*/
+void QDeclarativeGeoRouteModel::cancel()
+{
+ emit abortRequested();
+ setError(NoError, QString());
+ setStatus(routes_.isEmpty() ? Null : Ready);
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteModel::get(int)
+
+ Returns the Route at given index. Use \l count property to check the
+ amount of routes available. The routes are indexed from zero, so the accessible range
+ is 0...(count - 1).
+
+ If you access out of bounds, a zero (null object) is returned and a warning is issued.
+*/
+
+QDeclarativeGeoRoute *QDeclarativeGeoRouteModel::get(int index)
+{
+ if (index < 0 || index >= routes_.count()) {
+ qmlWarning(this) << QStringLiteral("Index '%1' out of range").arg(index);
+ return 0;
+ }
+ return routes_.at(index);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::componentComplete()
+{
+ complete_ = true;
+ if (autoUpdate_) {
+ update();
+ }
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeGeoRouteModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return routes_.count();
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeGeoRouteModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ qmlWarning(this) << QStringLiteral("Error in indexing route model's data (invalid index).");
+ return QVariant();
+ }
+
+ if (index.row() >= routes_.count()) {
+ qmlWarning(this) << QStringLiteral("Fatal error in indexing route model's data (index overflow).");
+ return QVariant();
+ }
+
+ if (role == RouteRole) {
+ QObject *route = routes_.at(index.row());
+ return QVariant::fromValue(route);
+ }
+ return QVariant();
+}
+
+QHash<int, QByteArray> QDeclarativeGeoRouteModel::roleNames() const
+{
+ QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
+ roleNames.insert(RouteRole, "routeData");
+ return roleNames;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (plugin_ == plugin)
+ return;
+
+ reset(); // reset the model
+
+ if (plugin_)
+ disconnect(plugin_, SIGNAL(localesChanged()), this, SIGNAL(measurementSystemChanged()));
+ if (plugin)
+ connect(plugin, SIGNAL(localesChanged()), this, SIGNAL(measurementSystemChanged()));
+
+ plugin_ = plugin;
+
+ if (complete_)
+ emit pluginChanged();
+
+ if (!plugin)
+ return;
+
+ if (plugin_->isAttached()) {
+ pluginReady();
+ } else {
+ connect(plugin_, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::pluginReady()
+{
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ QGeoRoutingManager *routingManager = serviceProvider->routingManager();
+
+ if (serviceProvider->error() != QGeoServiceProvider::NoError) {
+ QDeclarativeGeoRouteModel::RouteError newError = UnknownError;
+ switch (serviceProvider->error()) {
+ case QGeoServiceProvider::NotSupportedError:
+ newError = EngineNotSetError; break;
+ case QGeoServiceProvider::UnknownParameterError:
+ newError = UnknownParameterError; break;
+ case QGeoServiceProvider::MissingRequiredParameterError:
+ newError = MissingRequiredParameterError; break;
+ case QGeoServiceProvider::ConnectionError:
+ newError = CommunicationError; break;
+ default:
+ break;
+ }
+
+ setError(newError, serviceProvider->errorString());
+ return;
+ }
+
+ if (!routingManager) {
+ setError(EngineNotSetError, tr("Plugin does not support routing."));
+ return;
+ }
+
+ connect(routingManager, SIGNAL(finished(QGeoRouteReply*)),
+ this, SLOT(routingFinished(QGeoRouteReply*)));
+ connect(routingManager, SIGNAL(error(QGeoRouteReply*,QGeoRouteReply::Error,QString)),
+ this, SLOT(routingError(QGeoRouteReply*,QGeoRouteReply::Error,QString)));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::queryDetailsChanged()
+{
+ if (autoUpdate_ && complete_)
+ update();
+}
+
+/*!
+ \qmlproperty Plugin QtLocation::RouteModel::plugin
+
+ This property holds the plugin that providers the actual
+ routing service. Note that all plugins do not necessarily
+ provide routing (could for example provide only geocoding or maps).
+
+ A valid plugin must be set before the RouteModel can perform any useful
+ operations.
+
+ \sa Plugin
+*/
+
+QDeclarativeGeoServiceProvider *QDeclarativeGeoRouteModel::plugin() const
+{
+ return plugin_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::setQuery(QDeclarativeGeoRouteQuery *query)
+{
+ if (!query || query == routeQuery_)
+ return;
+ if (routeQuery_)
+ routeQuery_->disconnect(this);
+ routeQuery_ = query;
+ connect(query, SIGNAL(queryDetailsChanged()), this, SLOT(queryDetailsChanged()));
+ if (complete_) {
+ emit queryChanged();
+ if (autoUpdate_)
+ update();
+ }
+}
+
+/*!
+ \qmlproperty RouteQuery QtLocation::RouteModel::query
+
+ This property holds the data of the route request.
+ The primary data are the waypoint coordinates and possible further
+ preferences (means of traveling, things to avoid on route etc).
+*/
+
+QDeclarativeGeoRouteQuery *QDeclarativeGeoRouteModel::query() const
+{
+ return routeQuery_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::setAutoUpdate(bool autoUpdate)
+{
+ if (autoUpdate_ == autoUpdate)
+ return;
+ autoUpdate_ = autoUpdate;
+ if (complete_)
+ emit autoUpdateChanged();
+}
+
+/*!
+ \qmlproperty bool QtLocation::RouteModel::autoUpdate
+
+ This property controls whether the Model automatically updates in response
+ to changes in its attached RouteQuery. The default value of this property
+ is false.
+
+ If setting this value to 'true', note that any change at all in
+ the RouteQuery object set in the \l{query} property will trigger a new
+ request to be sent. If you are adjusting many properties of the RouteQuery
+ with autoUpdate enabled, this can generate large numbers of useless (and
+ later discarded) requests.
+*/
+
+bool QDeclarativeGeoRouteModel::autoUpdate() const
+{
+ return autoUpdate_;
+}
+
+/*!
+ \qmlproperty Locale::MeasurementSystem QtLocation::RouteModel::measurementSystem
+
+ This property holds the measurement system which will be used when calculating the route. This
+ property is changed when the \l {QtLocation::Plugin::locales}{Plugin::locales} property of
+ \l {QtLocation::RouteModel::plugin}{plugin} changes.
+
+ If setting this property it must be set after the \l {QtLocation::RouteModel::plugin}{plugin}
+ property is set.
+*/
+void QDeclarativeGeoRouteModel::setMeasurementSystem(QLocale::MeasurementSystem ms)
+{
+ if (!plugin_)
+ return;
+
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return;
+
+ QGeoRoutingManager *routingManager = serviceProvider->routingManager();
+ if (!routingManager)
+ return;
+
+ if (routingManager->measurementSystem() == ms)
+ return;
+
+ routingManager->setMeasurementSystem(ms);
+ emit measurementSystemChanged();
+}
+
+QLocale::MeasurementSystem QDeclarativeGeoRouteModel::measurementSystem() const
+{
+ if (!plugin_)
+ return QLocale().measurementSystem();
+
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ if (!serviceProvider) {
+ if (plugin_->locales().isEmpty())
+ return QLocale().measurementSystem();
+
+ return QLocale(plugin_->locales().first()).measurementSystem();
+ }
+
+ QGeoRoutingManager *routingManager = serviceProvider->routingManager();
+ if (!routingManager) {
+ if (plugin_->locales().isEmpty())
+ return QLocale().measurementSystem();
+
+ return QLocale(plugin_->locales().first()).measurementSystem();
+ }
+
+ return routingManager->measurementSystem();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::setStatus(QDeclarativeGeoRouteModel::Status status)
+{
+ if (status_ == status)
+ return;
+
+ status_ = status;
+
+ if (complete_)
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::RouteModel::status
+
+ This read-only property holds the current status of the model.
+
+ \list
+ \li RouteModel.Null - No route requests have been issued or \l reset has been called.
+ \li RouteModel.Ready - Route request(s) have finished successfully.
+ \li RouteModel.Loading - Route request has been issued but not yet finished
+ \li RouteModel.Error - Routing error has occurred, details are in \l error and \l errorString
+ \endlist
+*/
+
+QDeclarativeGeoRouteModel::Status QDeclarativeGeoRouteModel::status() const
+{
+ return status_;
+}
+
+/*!
+ \qmlproperty string QtLocation::RouteModel::errorString
+
+ This read-only property holds the textual presentation of the latest routing error.
+ If no error has occurred or the model has been reset, an empty string is returned.
+
+ An empty string may also be returned if an error occurred which has no associated
+ textual representation.
+*/
+
+QString QDeclarativeGeoRouteModel::errorString() const
+{
+ return errorString_;
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::RouteModel::error
+
+ This read-only property holds the latest error value of the routing request.
+
+ \list
+ \li RouteModel.NoError - No error has occurred.
+ \li RouteModel.CommunicationError - An error occurred while communicating with the service provider.
+ \li RouteModel.EngineNotSetError - The model's plugin property was not set or there is no routing manager associated with the plugin.
+ \li RouteModel.MissingRequiredParameterError - A required parameter was not specified.
+ \li RouteModel.ParseError - The response from the service provider was in an unrecognizable format.
+ \li RouteModel.UnknownError - An error occurred which does not fit into any of the other categories.
+ \li RouteModel.UnknownParameterError - The plugin did not recognize one of the parameters it was given.
+ \li RouteModel.UnsupportedOptionError - The requested operation is not supported by the routing provider.
+ This may happen when the loaded engine does not support a particular
+ type of routing request.
+ \endlist
+*/
+
+QDeclarativeGeoRouteModel::RouteError QDeclarativeGeoRouteModel::error() const
+{
+ return error_;
+}
+
+void QDeclarativeGeoRouteModel::setError(RouteError error, const QString& errorString)
+{
+ if (error_ == error && errorString_ == errorString)
+ return;
+ error_ = error;
+ errorString_ = errorString;
+ emit errorChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteModel::update()
+
+ Instructs the RouteModel to update its data. This is most useful
+ when \l autoUpdate is disabled, to force a refresh when the query
+ has been changed.
+*/
+void QDeclarativeGeoRouteModel::update()
+{
+ if (!complete_)
+ return;
+
+ if (!plugin_) {
+ setError(EngineNotSetError, tr("Cannot route, plugin not set."));
+ return;
+ }
+
+ QGeoServiceProvider *serviceProvider = plugin_->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return;
+
+ QGeoRoutingManager *routingManager = serviceProvider->routingManager();
+ if (!routingManager) {
+ setError(EngineNotSetError, tr("Cannot route, route manager not set."));
+ return;
+ }
+ if (!routeQuery_) {
+ setError(ParseError,"Cannot route, valid query not set.");
+ return;
+ }
+ emit abortRequested(); // Clear previous requests
+ QGeoRouteRequest request = routeQuery_->routeRequest();
+ if (request.waypoints().count() < 2) {
+ setError(ParseError,tr("Not enough waypoints for routing."));
+ return;
+ }
+
+ setError(NoError, QString());
+
+ QGeoRouteReply *reply = routingManager->calculateRoute(request);
+ setStatus(QDeclarativeGeoRouteModel::Loading);
+ if (!reply->isFinished()) {
+ connect(this, &QDeclarativeGeoRouteModel::abortRequested, reply, &QGeoRouteReply::abort);
+ } else {
+ if (reply->error() == QGeoRouteReply::NoError) {
+ routingFinished(reply);
+ } else {
+ routingError(reply, reply->error(), reply->errorString());
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::routingFinished(QGeoRouteReply *reply)
+{
+ if (!reply)
+ return;
+ reply->deleteLater();
+ if (reply->error() != QGeoRouteReply::NoError)
+ return;
+
+ beginResetModel();
+ int oldCount = routes_.count();
+ qDeleteAll(routes_);
+ // Convert routes to declarative
+ routes_.clear();
+ for (int i = 0; i < reply->routes().size(); ++i) {
+ QDeclarativeGeoRoute *route = new QDeclarativeGeoRoute(reply->routes().at(i), this);
+ QQmlEngine::setContextForObject(route, QQmlEngine::contextForObject(this));
+ routes_.append(route);
+ }
+ endResetModel();
+
+ setError(NoError, QString());
+ setStatus(QDeclarativeGeoRouteModel::Ready);
+
+ if (oldCount != 0 || routes_.count() != 0)
+ emit routesChanged();
+ if (oldCount != routes_.count())
+ emit countChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteModel::routingError(QGeoRouteReply *reply,
+ QGeoRouteReply::Error error,
+ const QString &errorString)
+{
+ if (!reply)
+ return;
+ reply->deleteLater();
+ setError(static_cast<QDeclarativeGeoRouteModel::RouteError>(error), errorString);
+ setStatus(QDeclarativeGeoRouteModel::Error);
+}
+
+
+/*!
+ \qmltype RouteQuery
+ \instantiates QDeclarativeGeoRouteQuery
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The RouteQuery type is used to provide query parameters to a
+ RouteModel.
+
+ A RouteQuery contains all the parameters necessary to make a request
+ to a routing service, which can then populate the contents of a RouteModel.
+
+ These parameters describe key details of the route, such as \l waypoints to
+ pass through, \l excludedAreas to avoid, the \l travelModes in use, as well
+ as detailed preferences on how to optimize the route and what features
+ to prefer or avoid along the path (such as toll roads, highways, etc).
+
+ RouteQuery objects are used exclusively to fill out the value of a
+ RouteModel's \l{RouteModel::query}{query} property, which can then begin
+ the retrieval process to populate the model.
+
+ \section2 Example Usage
+
+ The following snipped shows an incomplete example of creating a RouteQuery
+ object and setting it as the value of a RouteModel's \l{RouteModel::query}{query}
+ property.
+
+ \code
+ RouteQuery {
+ id: aQuery
+ }
+
+ RouteModel {
+ query: aQuery
+ autoUpdate: false
+ }
+ \endcode
+
+ For a more complete example, see the documentation for the \l{RouteModel}
+ type, and the Mapviewer example.
+
+ \sa RouteModel
+
+*/
+
+QDeclarativeGeoRouteQuery::QDeclarativeGeoRouteQuery(QObject *parent)
+: QObject(parent), complete_(false), m_excludedAreaCoordinateChanged(false)
+{
+}
+
+QDeclarativeGeoRouteQuery::~QDeclarativeGeoRouteQuery()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteQuery::componentComplete()
+{
+ complete_ = true;
+}
+
+/*!
+ \qmlproperty QList<FeatureType> RouteQuery::featureTypes
+
+ List of features that will be considered when planning the
+ route. Features with a weight of NeutralFeatureWeight will not be returned.
+
+ \list
+ \li RouteQuery.NoFeature - No features will be taken into account when planning the route
+ \li RouteQuery.TollFeature - Consider tollways when planning the route
+ \li RouteQuery.HighwayFeature - Consider highways when planning the route
+ \li RouteQuery.PublicTransitFeature - Consider public transit when planning the route
+ \li RouteQuery.FerryFeature - Consider ferries when planning the route
+ \li RouteQuery.TunnelFeature - Consider tunnels when planning the route
+ \li RouteQuery.DirtRoadFeature - Consider dirt roads when planning the route
+ \li RouteQuery.ParksFeature - Consider parks when planning the route
+ \li RouteQuery.MotorPoolLaneFeature - Consider motor pool lanes when planning the route
+ \endlist
+
+ \sa setFeatureWeight, featureWeight
+*/
+
+QList<int> QDeclarativeGeoRouteQuery::featureTypes()
+{
+ QList<int> list;
+
+ for (int i = 0; i < request_.featureTypes().count(); ++i) {
+ list.append(static_cast<int>(request_.featureTypes().at(i)));
+ }
+ return list;
+}
+
+/*!
+ \qmlproperty int RouteQuery::numberAlternativeRoutes
+
+ The number of alternative routes requested when requesting routes.
+ The default value is 0.
+*/
+
+
+int QDeclarativeGeoRouteQuery::numberAlternativeRoutes() const
+{
+ return request_.numberAlternativeRoutes();
+}
+
+void QDeclarativeGeoRouteQuery::setNumberAlternativeRoutes(int numberAlternativeRoutes)
+{
+ if (numberAlternativeRoutes == request_.numberAlternativeRoutes())
+ return;
+
+ request_.setNumberAlternativeRoutes(numberAlternativeRoutes);
+
+ if (complete_) {
+ emit numberAlternativeRoutesChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlproperty QJSValue RouteQuery::waypoints
+
+
+ The waypoint coordinates of the desired route.
+ The waypoints should be given in order from origin to destination.
+ Two or more coordinates are needed.
+
+ Waypoints can be set as part of the RouteQuery type declaration or
+ dynamically with the functions provided.
+
+ \sa addWaypoint, removeWaypoint, clearWaypoints
+*/
+
+QJSValue QDeclarativeGeoRouteQuery::waypoints()
+{
+ QQmlContext *context = QQmlEngine::contextForObject(parent());
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> waypointArray(scope, v4->newArrayObject(request_.waypoints().length()));
+ for (int i = 0; i < request_.waypoints().length(); ++i) {
+ const QGeoCoordinate &c = request_.waypoints().at(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ waypointArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, waypointArray.asReturnedValue());
+}
+
+void QDeclarativeGeoRouteQuery::setWaypoints(const QJSValue &value)
+{
+ if (!value.isArray())
+ return;
+
+ QList<QGeoCoordinate> waypointList;
+ quint32 length = value.property(QStringLiteral("length")).toUInt();
+ for (quint32 i = 0; i < length; ++i) {
+ bool ok;
+ QGeoCoordinate c = parseCoordinate(value.property(i), &ok);
+
+ if (!ok || !c.isValid()) {
+ qmlWarning(this) << "Unsupported waypoint type";
+ return;
+ }
+
+ waypointList.append(c);
+ }
+
+ if (request_.waypoints() == waypointList)
+ return;
+
+ request_.setWaypoints(waypointList);
+
+ emit waypointsChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlproperty list<georectangle> RouteQuery::excludedAreas
+
+ Areas that the route must not cross.
+
+ Excluded areas can be set as part of the \l RouteQuery type declaration or
+ dynamically with the functions provided.
+
+ \sa addExcludedArea, removeExcludedArea, clearExcludedAreas
+*/
+QJSValue QDeclarativeGeoRouteQuery::excludedAreas() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(parent());
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> excludedAreasArray(scope, v4->newArrayObject(request_.excludeAreas().length()));
+ for (int i = 0; i < request_.excludeAreas().length(); ++i) {
+ const QGeoRectangle &r = request_.excludeAreas().at(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(r)));
+ excludedAreasArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, excludedAreasArray.asReturnedValue());
+}
+
+void QDeclarativeGeoRouteQuery::setExcludedAreas(const QJSValue &value)
+{
+ if (!value.isArray())
+ return;
+
+ QList<QGeoRectangle> excludedAreasList;
+ quint32 length = value.property(QStringLiteral("length")).toUInt();
+ for (quint32 i = 0; i < length; ++i) {
+ bool ok;
+ QGeoRectangle r = parseRectangle(value.property(i), &ok);
+
+ if (!ok || !r.isValid()) {
+ qmlWarning(this) << "Unsupported area type";
+ return;
+ }
+
+ excludedAreasList.append(r);
+ }
+
+ if (request_.excludeAreas() == excludedAreasList)
+ return;
+
+ request_.setExcludeAreas(excludedAreasList);
+
+ emit excludedAreasChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::addExcludedArea(georectangle)
+
+ Adds the given area to excluded areas (areas that the route must not cross).
+ Same area can only be added once.
+
+ \sa removeExcludedArea, clearExcludedAreas
+*/
+
+
+void QDeclarativeGeoRouteQuery::addExcludedArea(const QGeoRectangle &area)
+{
+ if (!area.isValid())
+ return;
+
+ QList<QGeoRectangle> excludedAreas = request_.excludeAreas();
+
+ if (excludedAreas.contains(area))
+ return;
+
+ excludedAreas.append(area);
+
+ request_.setExcludeAreas(excludedAreas);
+
+ if (complete_) {
+ emit excludedAreasChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::removeExcludedArea(georectangle)
+
+ Removes the given area to excluded areas (areas that the route must not cross).
+
+ \sa addExcludedArea, clearExcludedAreas
+*/
+
+void QDeclarativeGeoRouteQuery::removeExcludedArea(const QGeoRectangle &area)
+{
+ if (!area.isValid())
+ return;
+
+ QList<QGeoRectangle> excludedAreas = request_.excludeAreas();
+
+ int index = excludedAreas.lastIndexOf(area);
+ if (index == -1) {
+ qmlWarning(this) << QStringLiteral("Cannot remove nonexistent area.");
+ return;
+ }
+ excludedAreas.removeAt(index);
+ request_.setExcludeAreas(excludedAreas);
+
+ emit excludedAreasChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::clearExcludedAreas()
+
+ Clears all excluded areas (areas that the route must not cross).
+
+ \sa addExcludedArea, removeExcludedArea
+*/
+
+void QDeclarativeGeoRouteQuery::clearExcludedAreas()
+{
+ if (request_.excludeAreas().isEmpty())
+ return;
+
+ request_.setExcludeAreas(QList<QGeoRectangle>());
+
+ emit excludedAreasChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::addWaypoint(coordinate)
+
+ Appends a coordinate to the list of waypoints. Same coordinate
+ can be set multiple times.
+
+ \sa removeWaypoint, clearWaypoints
+*/
+void QDeclarativeGeoRouteQuery::addWaypoint(const QGeoCoordinate &waypoint)
+{
+ if (!waypoint.isValid()) {
+ qmlWarning(this) << QStringLiteral("Not adding invalid waypoint.");
+ return;
+ }
+
+ QList<QGeoCoordinate> waypoints = request_.waypoints();
+ waypoints.append(waypoint);
+ request_.setWaypoints(waypoints);
+
+ if (complete_) {
+ emit waypointsChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::removeWaypoint(coordinate)
+
+ Removes the given from the list of waypoints. In case same coordinate
+ appears multiple times, the most recently added coordinate instance is
+ removed.
+
+ \sa addWaypoint, clearWaypoints
+*/
+void QDeclarativeGeoRouteQuery::removeWaypoint(const QGeoCoordinate &waypoint)
+{
+ QList<QGeoCoordinate> waypoints = request_.waypoints();
+
+ int index = waypoints.lastIndexOf(waypoint);
+ if (index == -1) {
+ qmlWarning(this) << QStringLiteral("Cannot remove nonexistent waypoint.");
+ return;
+ }
+
+ waypoints.removeAt(index);
+
+ request_.setWaypoints(waypoints);
+
+ emit waypointsChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::clearWaypoints()
+
+ Clears all waypoints.
+
+ \sa removeWaypoint, addWaypoint
+*/
+void QDeclarativeGeoRouteQuery::clearWaypoints()
+{
+ if (request_.waypoints().isEmpty())
+ return;
+
+ request_.setWaypoints(QList<QGeoCoordinate>());
+
+ emit waypointsChanged();
+ emit queryDetailsChanged();
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::setFeatureWeight(FeatureType, FeatureWeight)
+
+ Defines the weight to associate with a feature during the planning of a
+ route.
+
+ Following lists the possible feature weights:
+
+ \list
+ \li RouteQuery.NeutralFeatureWeight - The presence or absence of the feature will not affect the planning of the route
+ \li RouteQuery.PreferFeatureWeight - Routes which contain the feature will be preferred over those that do not
+ \li RouteQuery.RequireFeatureWeight - Only routes which contain the feature will be considered, otherwise no route will be returned
+ \li RouteQuery.AvoidFeatureWeight - Routes which do not contain the feature will be preferred over those that do
+ \li RouteQuery.DisallowFeatureWeight - Only routes which do not contain the feature will be considered, otherwise no route will be returned
+ \endlist
+
+ \sa featureTypes, resetFeatureWeights, featureWeight
+
+*/
+
+void QDeclarativeGeoRouteQuery::setFeatureWeight(FeatureType featureType, FeatureWeight featureWeight)
+{
+ if (featureType == NoFeature && !request_.featureTypes().isEmpty()) {
+ resetFeatureWeights();
+ return;
+ }
+
+ // Check if the weight changes, as we need to signal it
+ FeatureWeight originalWeight = static_cast<FeatureWeight>(request_.featureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType)));
+ if (featureWeight == originalWeight)
+ return;
+
+ request_.setFeatureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType),
+ static_cast<QGeoRouteRequest::FeatureWeight>(featureWeight));
+ if (complete_ && ((originalWeight == NeutralFeatureWeight) || (featureWeight == NeutralFeatureWeight))) {
+ // featureTypes should now give a different list, because the original and new weight
+ // were not same, and other one was neutral weight
+ emit featureTypesChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlmethod void QtLocation::RouteQuery::resetFeatureWeights()
+
+ Resets all feature weights to their default state (NeutralFeatureWeight).
+
+ \sa featureTypes, setFeatureWeight, featureWeight
+*/
+void QDeclarativeGeoRouteQuery::resetFeatureWeights()
+{
+ // reset all feature types.
+ QList<QGeoRouteRequest::FeatureType> featureTypes = request_.featureTypes();
+ for (int i = 0; i < featureTypes.count(); ++i) {
+ request_.setFeatureWeight(featureTypes.at(i), QGeoRouteRequest::NeutralFeatureWeight);
+ }
+ if (complete_) {
+ emit featureTypesChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \qmlmethod FeatureWeight QtLocation::RouteQuery::featureWeight(FeatureType featureType)
+
+ Gets the weight for the \a featureType.
+
+ \sa featureTypes, setFeatureWeight, resetFeatureWeights
+*/
+
+int QDeclarativeGeoRouteQuery::featureWeight(FeatureType featureType)
+{
+ return request_.featureWeight(static_cast<QGeoRouteRequest::FeatureType>(featureType));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoRouteQuery::setTravelModes(QDeclarativeGeoRouteQuery::TravelModes travelModes)
+{
+ QGeoRouteRequest::TravelModes reqTravelModes;
+
+ if (travelModes & QDeclarativeGeoRouteQuery::CarTravel)
+ reqTravelModes |= QGeoRouteRequest::CarTravel;
+ if (travelModes & QDeclarativeGeoRouteQuery::PedestrianTravel)
+ reqTravelModes |= QGeoRouteRequest::PedestrianTravel;
+ if (travelModes & QDeclarativeGeoRouteQuery::BicycleTravel)
+ reqTravelModes |= QGeoRouteRequest::BicycleTravel;
+ if (travelModes & QDeclarativeGeoRouteQuery::PublicTransitTravel)
+ reqTravelModes |= QGeoRouteRequest::PublicTransitTravel;
+ if (travelModes & QDeclarativeGeoRouteQuery::TruckTravel)
+ reqTravelModes |= QGeoRouteRequest::TruckTravel;
+
+ if (reqTravelModes == request_.travelModes())
+ return;
+
+ request_.setTravelModes(reqTravelModes);
+
+ if (complete_) {
+ emit travelModesChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+
+/*!
+ \qmlproperty enumeration RouteQuery::segmentDetail
+
+ The level of detail which will be used in the representation of routing segments.
+
+ \list
+ \li RouteQuery.NoSegmentData - No segment data should be included with the route
+ \li RouteQuery.BasicSegmentData - Basic segment data will be included with the route
+ \endlist
+
+ The default value is RouteQuery.BasicSegmentData
+*/
+
+void QDeclarativeGeoRouteQuery::setSegmentDetail(SegmentDetail segmentDetail)
+{
+ if (static_cast<QGeoRouteRequest::SegmentDetail>(segmentDetail) == request_.segmentDetail())
+ return;
+ request_.setSegmentDetail(static_cast<QGeoRouteRequest::SegmentDetail>(segmentDetail));
+ if (complete_) {
+ emit segmentDetailChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+QDeclarativeGeoRouteQuery::SegmentDetail QDeclarativeGeoRouteQuery::segmentDetail() const
+{
+ return static_cast<QDeclarativeGeoRouteQuery::SegmentDetail>(request_.segmentDetail());
+}
+
+/*!
+ \qmlproperty enumeration RouteQuery::maneuverDetail
+
+ The level of detail which will be used in the representation of routing maneuvers.
+
+ \list
+ \li RouteQuery.NoManeuvers - No maneuvers should be included with the route
+ \li RouteQuery.BasicManeuvers - Basic maneuvers will be included with the route
+ \endlist
+
+ The default value is RouteQuery.BasicManeuvers
+*/
+
+void QDeclarativeGeoRouteQuery::setManeuverDetail(ManeuverDetail maneuverDetail)
+{
+ if (static_cast<QGeoRouteRequest::ManeuverDetail>(maneuverDetail) == request_.maneuverDetail())
+ return;
+ request_.setManeuverDetail(static_cast<QGeoRouteRequest::ManeuverDetail>(maneuverDetail));
+ if (complete_) {
+ emit maneuverDetailChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+QDeclarativeGeoRouteQuery::ManeuverDetail QDeclarativeGeoRouteQuery::maneuverDetail() const
+{
+ return static_cast<QDeclarativeGeoRouteQuery::ManeuverDetail>(request_.maneuverDetail());
+}
+
+/*!
+ \qmlproperty enumeration RouteQuery::travelModes
+
+ The travel modes which should be considered during the planning of the route.
+ Values can be combined with OR ('|') -operator.
+
+ \list
+ \li RouteQuery.CarTravel - The route will be optimized for someone who is driving a car
+ \li RouteQuery.PedestrianTravel - The route will be optimized for someone who is walking
+ \li RouteQuery.BicycleTravel - The route will be optimized for someone who is riding a bicycle
+ \li RouteQuery.PublicTransitTravel - The route will be optimized for someone who is making use of public transit
+ \li RouteQuery.TruckTravel - The route will be optimized for someone who is driving a truck
+ \endlist
+
+ The default value is RouteQuery.CarTravel
+*/
+
+QDeclarativeGeoRouteQuery::TravelModes QDeclarativeGeoRouteQuery::travelModes() const
+{
+ QGeoRouteRequest::TravelModes reqTravelModes = request_.travelModes();
+ QDeclarativeGeoRouteQuery::TravelModes travelModes;
+
+ if (reqTravelModes & QGeoRouteRequest::CarTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::CarTravel;
+ if (reqTravelModes & QGeoRouteRequest::PedestrianTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::PedestrianTravel;
+ if (reqTravelModes & QGeoRouteRequest::BicycleTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::BicycleTravel;
+ if (reqTravelModes & QGeoRouteRequest::PublicTransitTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::PublicTransitTravel;
+ if (reqTravelModes & QGeoRouteRequest::TruckTravel)
+ travelModes |= QDeclarativeGeoRouteQuery::TruckTravel;
+
+ return travelModes;
+}
+
+/*!
+ \qmlproperty enumeration RouteQuery::routeOptimizations
+
+ The route optimizations which should be considered during the planning of the route.
+ Values can be combined with OR ('|') -operator.
+
+ \list
+ \li RouteQuery.ShortestRoute - Minimize the length of the journey
+ \li RouteQuery.FastestRoute - Minimize the traveling time for the journey
+ \li RouteQuery.MostEconomicRoute - Minimize the cost of the journey
+ \li RouteQuery.MostScenicRoute - Maximize the scenic potential of the journey
+ \endlist
+
+ The default value is RouteQuery.FastestRoute
+*/
+
+QDeclarativeGeoRouteQuery::RouteOptimizations QDeclarativeGeoRouteQuery::routeOptimizations() const
+{
+ QGeoRouteRequest::RouteOptimizations reqOptimizations = request_.routeOptimization();
+ QDeclarativeGeoRouteQuery::RouteOptimizations optimization;
+
+ if (reqOptimizations & QGeoRouteRequest::ShortestRoute)
+ optimization |= QDeclarativeGeoRouteQuery::ShortestRoute;
+ if (reqOptimizations & QGeoRouteRequest::FastestRoute)
+ optimization |= QDeclarativeGeoRouteQuery::FastestRoute;
+ if (reqOptimizations & QGeoRouteRequest::MostEconomicRoute)
+ optimization |= QDeclarativeGeoRouteQuery::MostEconomicRoute;
+ if (reqOptimizations & QGeoRouteRequest::MostScenicRoute)
+ optimization |= QDeclarativeGeoRouteQuery::MostScenicRoute;
+
+ return optimization;
+}
+
+void QDeclarativeGeoRouteQuery::setRouteOptimizations(QDeclarativeGeoRouteQuery::RouteOptimizations optimization)
+{
+ QGeoRouteRequest::RouteOptimizations reqOptimizations;
+
+ if (optimization & QDeclarativeGeoRouteQuery::ShortestRoute)
+ reqOptimizations |= QGeoRouteRequest::ShortestRoute;
+ if (optimization & QDeclarativeGeoRouteQuery::FastestRoute)
+ reqOptimizations |= QGeoRouteRequest::FastestRoute;
+ if (optimization & QDeclarativeGeoRouteQuery::MostEconomicRoute)
+ reqOptimizations |= QGeoRouteRequest::MostEconomicRoute;
+ if (optimization & QDeclarativeGeoRouteQuery::MostScenicRoute)
+ reqOptimizations |= QGeoRouteRequest::MostScenicRoute;
+
+ if (reqOptimizations == request_.routeOptimization())
+ return;
+
+ request_.setRouteOptimization(reqOptimizations);
+
+ if (complete_) {
+ emit routeOptimizationsChanged();
+ emit queryDetailsChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+QGeoRouteRequest QDeclarativeGeoRouteQuery::routeRequest() const
+{
+ return request_;
+}
+
+void QDeclarativeGeoRouteQuery::excludedAreaCoordinateChanged()
+{
+ if (!m_excludedAreaCoordinateChanged) {
+ m_excludedAreaCoordinateChanged = true;
+ QMetaObject::invokeMethod(this, "doCoordinateChanged", Qt::QueuedConnection);
+ }
+}
+
+void QDeclarativeGeoRouteQuery::doCoordinateChanged()
+{
+ m_excludedAreaCoordinateChanged = false;
+ emit queryDetailsChanged();
+}
+
+#include "moc_qdeclarativegeoroutemodel_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h b/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h
new file mode 100644
index 00000000..3dfd2ce6
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutemodel_p.h
@@ -0,0 +1,344 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOROUTEMODEL_H
+#define QDECLARATIVEGEOROUTEMODEL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
+
+#include <QtPositioning/QGeoCoordinate>
+#include <QtPositioning/QGeoRectangle>
+
+#include <qgeorouterequest.h>
+#include <qgeoroutereply.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/private/qv4engine_p.h>
+#include <QAbstractListModel>
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoServiceProvider;
+class QGeoRoutingManager;
+class QDeclarativeGeoRoute;
+class QDeclarativeGeoRouteQuery;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteModel : public QAbstractListModel, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+ Q_ENUMS(RouteError)
+
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(QDeclarativeGeoRouteQuery *query READ query WRITE setQuery NOTIFY queryChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(bool autoUpdate READ autoUpdate WRITE setAutoUpdate NOTIFY autoUpdateChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged)
+ Q_PROPERTY(RouteError error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QLocale::MeasurementSystem measurementSystem READ measurementSystem WRITE setMeasurementSystem NOTIFY measurementSystemChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ enum Roles {
+ RouteRole = Qt::UserRole + 500
+ };
+
+ enum Status {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ enum RouteError {
+ NoError = QGeoRouteReply::NoError,
+ EngineNotSetError = QGeoRouteReply::EngineNotSetError,
+ CommunicationError = QGeoRouteReply::CommunicationError,
+ ParseError = QGeoRouteReply::ParseError,
+ UnsupportedOptionError = QGeoRouteReply::UnsupportedOptionError,
+ UnknownError = QGeoRouteReply::UnknownError,
+ //we leave gap for future QGeoRouteReply errors
+
+ //QGeoServiceProvider related errors start here
+ UnknownParameterError = 100,
+ MissingRequiredParameterError
+ };
+
+ explicit QDeclarativeGeoRouteModel(QObject *parent = 0);
+ ~QDeclarativeGeoRouteModel();
+
+ // From QQmlParserStatus
+ void classBegin() {}
+ void componentComplete();
+
+ // From QAbstractListModel
+ int rowCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ virtual QHash<int,QByteArray> roleNames() const;
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ void setQuery(QDeclarativeGeoRouteQuery *query);
+ QDeclarativeGeoRouteQuery *query() const;
+
+ void setAutoUpdate(bool autoUpdate);
+ bool autoUpdate() const;
+
+ void setMeasurementSystem(QLocale::MeasurementSystem ms);
+ QLocale::MeasurementSystem measurementSystem() const;
+
+ Status status() const;
+ QString errorString() const;
+ RouteError error() const;
+
+ int count() const;
+ Q_INVOKABLE QDeclarativeGeoRoute *get(int index);
+ Q_INVOKABLE void reset();
+ Q_INVOKABLE void cancel();
+
+Q_SIGNALS:
+ void countChanged();
+ void pluginChanged();
+ void queryChanged();
+ void autoUpdateChanged();
+ void statusChanged();
+ void errorChanged(); //emitted also for errorString notification
+ void routesChanged();
+ void measurementSystemChanged();
+ void abortRequested();
+
+public Q_SLOTS:
+ void update();
+
+private Q_SLOTS:
+ void routingFinished(QGeoRouteReply *reply);
+ void routingError(QGeoRouteReply *reply,
+ QGeoRouteReply::Error error,
+ const QString &errorString);
+ void queryDetailsChanged();
+ void pluginReady();
+
+private:
+ void setStatus(Status status);
+ void setError(RouteError error, const QString &errorString);
+
+ bool complete_;
+
+ QDeclarativeGeoServiceProvider *plugin_;
+ QDeclarativeGeoRouteQuery *routeQuery_;
+
+ QList<QDeclarativeGeoRoute *> routes_;
+ bool autoUpdate_;
+ Status status_;
+ QString errorString_;
+ RouteError error_;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteQuery : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_ENUMS(TravelMode)
+ Q_ENUMS(FeatureType)
+ Q_ENUMS(FeatureWeight)
+ Q_ENUMS(SegmentDetail)
+ Q_ENUMS(ManeuverDetail)
+ Q_ENUMS(RouteOptimization)
+ Q_FLAGS(RouteOptimizations)
+ Q_FLAGS(ManeuverDetails)
+ Q_FLAGS(SegmentDetails)
+ Q_FLAGS(TravelModes)
+
+ Q_PROPERTY(int numberAlternativeRoutes READ numberAlternativeRoutes WRITE setNumberAlternativeRoutes NOTIFY numberAlternativeRoutesChanged)
+ Q_PROPERTY(TravelModes travelModes READ travelModes WRITE setTravelModes NOTIFY travelModesChanged)
+ Q_PROPERTY(RouteOptimizations routeOptimizations READ routeOptimizations WRITE setRouteOptimizations NOTIFY routeOptimizationsChanged)
+ Q_PROPERTY(SegmentDetail segmentDetail READ segmentDetail WRITE setSegmentDetail NOTIFY segmentDetailChanged)
+ Q_PROPERTY(ManeuverDetail maneuverDetail READ maneuverDetail WRITE setManeuverDetail NOTIFY maneuverDetailChanged)
+ Q_PROPERTY(QJSValue waypoints READ waypoints WRITE setWaypoints NOTIFY waypointsChanged)
+ Q_PROPERTY(QJSValue excludedAreas READ excludedAreas WRITE setExcludedAreas NOTIFY excludedAreasChanged)
+ Q_PROPERTY(QList<int> featureTypes READ featureTypes NOTIFY featureTypesChanged)
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+
+ explicit QDeclarativeGeoRouteQuery(QObject *parent = 0);
+ ~QDeclarativeGeoRouteQuery();
+
+ // From QQmlParserStatus
+ void classBegin() {}
+ void componentComplete();
+
+ QGeoRouteRequest routeRequest() const;
+
+ enum TravelMode {
+ CarTravel = QGeoRouteRequest::CarTravel,
+ PedestrianTravel = QGeoRouteRequest::PedestrianTravel,
+ BicycleTravel = QGeoRouteRequest::BicycleTravel,
+ PublicTransitTravel = QGeoRouteRequest::PublicTransitTravel,
+ TruckTravel = QGeoRouteRequest::TruckTravel
+ };
+ Q_DECLARE_FLAGS(TravelModes, TravelMode)
+
+ enum FeatureType {
+ NoFeature = QGeoRouteRequest::NoFeature,
+ TollFeature = QGeoRouteRequest::TollFeature,
+ HighwayFeature = QGeoRouteRequest::HighwayFeature,
+ PublicTransitFeature = QGeoRouteRequest::PublicTransitFeature,
+ FerryFeature = QGeoRouteRequest::FerryFeature,
+ TunnelFeature = QGeoRouteRequest::TunnelFeature,
+ DirtRoadFeature = QGeoRouteRequest::DirtRoadFeature,
+ ParksFeature = QGeoRouteRequest::ParksFeature,
+ MotorPoolLaneFeature = QGeoRouteRequest::MotorPoolLaneFeature
+ };
+ Q_DECLARE_FLAGS(FeatureTypes, FeatureType)
+
+ enum FeatureWeight {
+ NeutralFeatureWeight = QGeoRouteRequest::NeutralFeatureWeight,
+ PreferFeatureWeight = QGeoRouteRequest::PreferFeatureWeight,
+ RequireFeatureWeight = QGeoRouteRequest::RequireFeatureWeight,
+ AvoidFeatureWeight = QGeoRouteRequest::AvoidFeatureWeight,
+ DisallowFeatureWeight = QGeoRouteRequest::DisallowFeatureWeight
+ };
+ Q_DECLARE_FLAGS(FeatureWeights, FeatureWeight)
+
+ enum RouteOptimization {
+ ShortestRoute = QGeoRouteRequest::ShortestRoute,
+ FastestRoute = QGeoRouteRequest::FastestRoute,
+ MostEconomicRoute = QGeoRouteRequest::MostEconomicRoute,
+ MostScenicRoute = QGeoRouteRequest::MostScenicRoute
+ };
+ Q_DECLARE_FLAGS(RouteOptimizations, RouteOptimization)
+
+ enum SegmentDetail {
+ NoSegmentData = 0x0000,
+ BasicSegmentData = 0x0001
+ };
+ Q_DECLARE_FLAGS(SegmentDetails, SegmentDetail)
+
+ enum ManeuverDetail {
+ NoManeuvers = 0x0000,
+ BasicManeuvers = 0x0001
+ };
+ Q_DECLARE_FLAGS(ManeuverDetails, ManeuverDetail)
+
+ void setNumberAlternativeRoutes(int numberAlternativeRoutes);
+ int numberAlternativeRoutes() const;
+
+ //QList<FeatureType> featureTypes();
+ QList<int> featureTypes();
+
+
+ QJSValue waypoints();
+ void setWaypoints(const QJSValue &value);
+
+ // READ functions for list properties
+ QJSValue excludedAreas() const;
+ void setExcludedAreas(const QJSValue &value);
+
+ Q_INVOKABLE void addWaypoint(const QGeoCoordinate &waypoint);
+ Q_INVOKABLE void removeWaypoint(const QGeoCoordinate &waypoint);
+ Q_INVOKABLE void clearWaypoints();
+
+ Q_INVOKABLE void addExcludedArea(const QGeoRectangle &area);
+ Q_INVOKABLE void removeExcludedArea(const QGeoRectangle &area);
+ Q_INVOKABLE void clearExcludedAreas();
+
+ Q_INVOKABLE void setFeatureWeight(FeatureType featureType, FeatureWeight featureWeight);
+ Q_INVOKABLE int featureWeight(FeatureType featureType);
+ Q_INVOKABLE void resetFeatureWeights();
+
+ /*
+ feature weights
+ */
+
+ void setTravelModes(TravelModes travelModes);
+ TravelModes travelModes() const;
+
+ void setSegmentDetail(SegmentDetail segmentDetail);
+ SegmentDetail segmentDetail() const;
+
+ void setManeuverDetail(ManeuverDetail maneuverDetail);
+ ManeuverDetail maneuverDetail() const;
+
+ void setRouteOptimizations(RouteOptimizations optimization);
+ RouteOptimizations routeOptimizations() const;
+
+Q_SIGNALS:
+ void numberAlternativeRoutesChanged();
+ void travelModesChanged();
+ void routeOptimizationsChanged();
+
+ void waypointsChanged();
+ void excludedAreasChanged();
+
+ void featureTypesChanged();
+ void maneuverDetailChanged();
+ void segmentDetailChanged();
+
+ void queryDetailsChanged();
+
+private Q_SLOTS:
+ void excludedAreaCoordinateChanged();
+
+private:
+ Q_INVOKABLE void doCoordinateChanged();
+
+ QGeoRouteRequest request_;
+ bool complete_;
+ bool m_excludedAreaCoordinateChanged;
+
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
new file mode 100644
index 00000000..acfe2441
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutesegment.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeoroutesegment_p.h"
+
+#include <QtQml/QQmlEngine>
+#include <QtQml/private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RouteSegment
+ \instantiates QDeclarativeGeoRouteSegment
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-routing
+ \since Qt Location 5.5
+
+ \brief The RouteSegment type represents a segment of a Route.
+
+ A RouteSegment instance has information about the physical layout
+ of the route segment, the length of the route and estimated time required
+ to traverse the route segment and optional RouteManeuvers associated with
+ the end of the route segment.
+
+ RouteSegment instances can be thought of as edges on a routing
+ graph, with RouteManeuver instances as optional labels attached to the
+ vertices of the graph.
+
+ The primary means of acquiring Route objects is via Routes via \l RouteModel.
+
+ \section1 Example
+
+ The following QML snippet demonstrates how to print information about a
+ route segment:
+
+ \snippet declarative/routing.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/routing.qml RouteSegment
+*/
+
+QDeclarativeGeoRouteSegment::QDeclarativeGeoRouteSegment(QObject *parent)
+ : QObject(parent)
+{
+ maneuver_ = new QDeclarativeGeoManeuver(this);
+}
+
+QDeclarativeGeoRouteSegment::QDeclarativeGeoRouteSegment(const QGeoRouteSegment &segment,
+ QObject *parent)
+ : QObject(parent),
+ segment_(segment)
+{
+ maneuver_ = new QDeclarativeGeoManeuver(segment_.maneuver(), this);
+}
+
+QDeclarativeGeoRouteSegment::~QDeclarativeGeoRouteSegment() {}
+
+/*!
+ \qmlproperty int QtLocation::RouteSegment::travelTime
+
+ Read-only property which holds the estimated amount of time it will take to
+ traverse this segment, in seconds.
+
+*/
+
+int QDeclarativeGeoRouteSegment::travelTime() const
+{
+ return segment_.travelTime();
+}
+
+/*!
+ \qmlproperty real QtLocation::RouteSegment::distance
+
+ Read-only property which holds the distance covered by this segment of the route, in meters.
+
+*/
+
+qreal QDeclarativeGeoRouteSegment::distance() const
+{
+ return segment_.distance();
+}
+
+/*!
+ \qmlproperty RouteManeuver QtLocation::RouteSegment::maneuver
+
+ Read-only property which holds the maneuver for this route segment.
+
+ Will return invalid maneuver if no information has been attached to the endpoint
+ of this route segment.
+*/
+
+QDeclarativeGeoManeuver *QDeclarativeGeoRouteSegment::maneuver() const
+{
+ return maneuver_;
+}
+
+/*!
+ \qmlproperty QJSValue QtLocation::RouteSegment::path
+
+ Read-only property which holds the geographical coordinates of this segment.
+ Coordinates are listed in the order in which they would be traversed by someone
+ traveling along this segment of the route.
+
+ To access individual segments you can use standard list accessors: 'path.length'
+ indicates the number of objects and 'path[index starting from zero]' gives
+ the actual object.
+
+ \sa QtPositioning::coordinate
+*/
+
+QJSValue QDeclarativeGeoRouteSegment::path() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(parent());
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(segment_.path().length()));
+ for (int i = 0; i < segment_.path().length(); ++i) {
+ const QGeoCoordinate &c = segment_.path().at(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ pathArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, pathArray.asReturnedValue());
+}
+
+#include "moc_qdeclarativegeoroutesegment_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativegeoroutesegment_p.h b/src/location/declarativemaps/qdeclarativegeoroutesegment_p.h
new file mode 100644
index 00000000..c3203ef0
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoroutesegment_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEGEOROUTESEGMENT_H
+#define QDECLARATIVEGEOROUTESEGMENT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomaneuver_p.h>
+
+#include <QtCore/QObject>
+#include <QtQml/qjsvalue.h>
+#include <QtLocation/QGeoRouteSegment>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoRouteSegment : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int travelTime READ travelTime CONSTANT)
+ Q_PROPERTY(qreal distance READ distance CONSTANT)
+ Q_PROPERTY(QJSValue path READ path CONSTANT)
+ Q_PROPERTY(QDeclarativeGeoManeuver *maneuver READ maneuver CONSTANT)
+
+public:
+ explicit QDeclarativeGeoRouteSegment(QObject *parent = 0);
+ QDeclarativeGeoRouteSegment(const QGeoRouteSegment &segment, QObject *parent = 0);
+ ~QDeclarativeGeoRouteSegment();
+
+ int travelTime() const;
+ qreal distance() const;
+ QJSValue path() const;
+ QDeclarativeGeoManeuver *maneuver() const;
+
+private:
+ QGeoRouteSegment segment_;
+ QDeclarativeGeoManeuver *maneuver_;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp
new file mode 100644
index 00000000..994b4913
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider.cpp
@@ -0,0 +1,821 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativegeoserviceprovider_p.h"
+#include <QtQml/QQmlInfo>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Plugin
+ \instantiates QDeclarativeGeoServiceProvider
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-common
+ \since Qt Location 5.5
+
+ \brief The Plugin type describes a Location based services plugin.
+
+ The Plugin type is used to declaratively specify which available
+ GeoServices plugin should be used for various tasks in the Location API.
+ Plugins are used by \l Map, \l RouteModel, and \l GeocodeModel
+ types, as well as a variety of others.
+
+ Plugins recognized by the system have a \l name property, a simple string
+ normally indicating the name of the service that the Plugin retrieves
+ data from. They also have a variety of features, which can be test for using the
+ \l {supportsRouting()}, \l {supportsGeocoding()}, \l {supportsMapping()} and
+ \l {supportsPlaces()} methods.
+
+ When a Plugin object is created, it is "detached" and not associated with
+ any actual service plugin. Once it has received information via setting
+ its \l name, \l preferred, or \l required properties, it will choose an
+ appropriate service plugin to attach to. Plugin objects can only be
+ attached once; to use multiple plugins, create multiple Plugin objects.
+
+ \section2 Example Usage
+
+ The following snippet shows a Plugin object being created with the
+ \l required and \l preferred properties set. This Plugin will attach to the
+ first found plugin that supports both mapping and geocoding, and will
+ prefer plugins named "here" or "osm" to any others.
+
+ \code
+ Plugin {
+ id: plugin
+ preferred: ["here", "osm"]
+ required: Plugin.AnyMappingFeatures | Plugin.AnyGeocodingFeatures
+ }
+ \endcode
+*/
+
+QDeclarativeGeoServiceProvider::QDeclarativeGeoServiceProvider(QObject *parent)
+: QObject(parent),
+ sharedProvider_(0),
+ required_(new QDeclarativeGeoServiceProviderRequirements),
+ complete_(false),
+ experimental_(false)
+{
+ locales_.append(QLocale().name());
+}
+
+QDeclarativeGeoServiceProvider::~QDeclarativeGeoServiceProvider()
+{
+ delete required_;
+ delete sharedProvider_;
+}
+
+
+
+/*!
+ \qmlproperty string Plugin::name
+
+ This property holds the name of the plugin. Setting this property
+ will cause the Plugin to only attach to a plugin with exactly this
+ name. The value of \l required will be ignored.
+*/
+void QDeclarativeGeoServiceProvider::setName(const QString &name)
+{
+ if (name_ == name)
+ return;
+
+ name_ = name;
+ delete sharedProvider_;
+ sharedProvider_ = new QGeoServiceProvider(name_, parameterMap());
+ sharedProvider_->setLocale(locales_.at(0));
+ sharedProvider_->setAllowExperimental(experimental_);
+
+ emit nameChanged(name_);
+ emit attached();
+}
+
+QString QDeclarativeGeoServiceProvider::name() const
+{
+ return name_;
+}
+
+
+/*!
+ \qmlproperty stringlist Plugin::availableServiceProviders
+
+ This property holds a list of all available service plugins' names. This
+ can be used to manually enumerate the available plugins if the
+ control provided by \l name and \l required is not sufficient for your
+ needs.
+*/
+QStringList QDeclarativeGeoServiceProvider::availableServiceProviders()
+{
+ return QGeoServiceProvider::availableServiceProviders();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProvider::componentComplete()
+{
+ complete_ = true;
+ if (!name_.isEmpty()) {
+ return;
+ }
+
+ if (!prefer_.isEmpty()
+ || required_->mappingRequirements() != NoMappingFeatures
+ || required_->routingRequirements() != NoRoutingFeatures
+ || required_->geocodingRequirements() != NoGeocodingFeatures
+ || required_->placesRequirements() != NoPlacesFeatures) {
+
+ QStringList providers = QGeoServiceProvider::availableServiceProviders();
+
+ /* first check any preferred plugins */
+ foreach (const QString &name, prefer_) {
+ if (providers.contains(name)) {
+ // so we don't try it again later
+ providers.removeAll(name);
+
+ QGeoServiceProvider sp(name, parameterMap(), experimental_);
+ if (required_->matches(&sp)) {
+ setName(name);
+ return;
+ }
+ }
+ }
+
+ /* then try the rest */
+ foreach (const QString &name, providers) {
+ QGeoServiceProvider sp(name, parameterMap(), experimental_);
+ if (required_->matches(&sp)) {
+ setName(name);
+ return;
+ }
+ }
+
+ qmlWarning(this) << "Could not find a plugin with the required features to attach to";
+ }
+}
+
+/*!
+ \qmlmethod bool Plugin::supportsGeocoding(GeocodingFeatures features)
+
+ This method returns a boolean indicating whether the specified set of \a features are supported
+ by the geo service provider plugin. True is returned if all specified \a features are
+ supported; otherwise false is returned.
+
+ The \a features parameter can be any flag combination of:
+ \table
+ \header
+ \li Feature
+ \li Description
+ \row
+ \li Plugin.NoGeocodingFeatures
+ \li No geocoding features are supported.
+ \row
+ \li Plugin.OnlineGeocodingFeature
+ \li Online geocoding is supported.
+ \row
+ \li Plugin.OfflineGeocodingFeature
+ \li Offline geocoding is supported.
+ \row
+ \li Plugin.ReverseGeocodingFeature
+ \li Reverse geocoding is supported.
+ \row
+ \li Plugin.LocalizedGeocodingFeature
+ \li Supports returning geocoding results with localized addresses.
+ \row
+ \li Plugin.AnyGeocodingFeatures
+ \li Matches a geo service provider that provides any geocoding features.
+ \endtable
+*/
+bool QDeclarativeGeoServiceProvider::supportsGeocoding(const GeocodingFeatures &feature) const
+{
+ QGeoServiceProvider *sp = sharedGeoServiceProvider();
+ QGeoServiceProvider::GeocodingFeatures f =
+ static_cast<QGeoServiceProvider::GeocodingFeature>(int(feature));
+ if (f == QGeoServiceProvider::AnyGeocodingFeatures)
+ return (sp && (sp->geocodingFeatures() != QGeoServiceProvider::NoGeocodingFeatures));
+ else
+ return (sp && (sp->geocodingFeatures() & f) == f);
+}
+
+/*!
+ \qmlmethod bool Plugin::supportsMapping(MappingFeatures features)
+
+ This method returns a boolean indicating whether the specified set of \a features are supported
+ by the geo service provider plugin. True is returned if all specified \a features are
+ supported; otherwise false is returned.
+
+ The \a features parameter can be any flag combination of:
+ \table
+ \header
+ \li Feature
+ \li Description
+ \row
+ \li Plugin.NoMappingFeatures
+ \li No mapping features are supported.
+ \row
+ \li Plugin.OnlineMappingFeature
+ \li Online mapping is supported.
+ \row
+ \li Plugin.OfflineMappingFeature
+ \li Offline mapping is supported.
+ \row
+ \li Plugin.LocalizedMappingFeature
+ \li Supports returning localized map data.
+ \row
+ \li Plugin.AnyMappingFeatures
+ \li Matches a geo service provider that provides any mapping features.
+ \endtable
+*/
+bool QDeclarativeGeoServiceProvider::supportsMapping(const MappingFeatures &feature) const
+{
+ QGeoServiceProvider *sp = sharedGeoServiceProvider();
+ QGeoServiceProvider::MappingFeatures f =
+ static_cast<QGeoServiceProvider::MappingFeature>(int(feature));
+ if (f == QGeoServiceProvider::AnyMappingFeatures)
+ return (sp && (sp->mappingFeatures() != QGeoServiceProvider::NoMappingFeatures));
+ else
+ return (sp && (sp->mappingFeatures() & f) == f);
+}
+
+/*!
+ \qmlmethod bool Plugin::supportsRouting(RoutingFeatures features)
+
+ This method returns a boolean indicating whether the specified set of \a features are supported
+ by the geo service provider plugin. True is returned if all specified \a features are
+ supported; otherwise false is returned.
+
+ The \a features parameter can be any flag combination of:
+ \table
+ \header
+ \li Feature
+ \li Description
+ \row
+ \li Plugin.NoRoutingFeatures
+ \li No routing features are supported.
+ \row
+ \li Plugin.OnlineRoutingFeature
+ \li Online routing is supported.
+ \row
+ \li Plugin.OfflineRoutingFeature
+ \li Offline routing is supported.
+ \row
+ \li Plugin.LocalizedRoutingFeature
+ \li Supports returning routes with localized addresses and instructions.
+ \row
+ \li Plugin.RouteUpdatesFeature
+ \li Updating an existing route based on the current position is supported.
+ \row
+ \li Plugin.AlternativeRoutesFeature
+ \li Supports returning alternative routes.
+ \row
+ \li Plugin.ExcludeAreasRoutingFeature
+ \li Supports specifying a areas which the returned route must not cross.
+ \row
+ \li Plugin.AnyRoutingFeatures
+ \li Matches a geo service provider that provides any routing features.
+ \endtable
+*/
+bool QDeclarativeGeoServiceProvider::supportsRouting(const RoutingFeatures &feature) const
+{
+ QGeoServiceProvider *sp = sharedGeoServiceProvider();
+ QGeoServiceProvider::RoutingFeatures f =
+ static_cast<QGeoServiceProvider::RoutingFeature>(int(feature));
+ if (f == QGeoServiceProvider::AnyRoutingFeatures)
+ return (sp && (sp->routingFeatures() != QGeoServiceProvider::NoRoutingFeatures));
+ else
+ return (sp && (sp->routingFeatures() & f) == f);
+}
+
+/*!
+ \qmlmethod bool Plugin::supportsPlaces(PlacesFeatures features)
+
+ This method returns a boolean indicating whether the specified set of \a features are supported
+ by the geo service provider plugin. True is returned if all specified \a features are
+ supported; otherwise false is returned.
+
+ The \a features parameter can be any flag combination of:
+ \table
+ \header
+ \li Feature
+ \li Description
+ \row
+ \li Plugin.NoPlacesFeatures
+ \li No places features are supported.
+ \row
+ \li Plugin.OnlinePlacesFeature
+ \li Online places is supported.
+ \row
+ \li Plugin.OfflinePlacesFeature
+ \li Offline places is supported.
+ \row
+ \li Plugin.SavePlaceFeature
+ \li Saving categories is supported.
+ \row
+ \li Plugin.RemovePlaceFeature
+ \li Removing or deleting places is supported.
+ \row
+ \li Plugin.PlaceRecommendationsFeature
+ \li Searching for recommended places similar to another place is supported.
+ \row
+ \li Plugin.SearchSuggestionsFeature
+ \li Search suggestions is supported.
+ \row
+ \li Plugin.LocalizedPlacesFeature
+ \li Supports returning localized place data.
+ \row
+ \li Plugin.NotificationsFeature
+ \li Notifications of place and category changes is supported.
+ \row
+ \li Plugin.PlaceMatchingFeature
+ \li Supports matching places from two different geo service providers.
+ \row
+ \li Plugin.AnyPlacesFeatures
+ \li Matches a geo service provider that provides any places features.
+ \endtable
+*/
+bool QDeclarativeGeoServiceProvider::supportsPlaces(const PlacesFeatures &features) const
+{
+ QGeoServiceProvider *sp = sharedGeoServiceProvider();
+ QGeoServiceProvider::PlacesFeatures f =
+ static_cast<QGeoServiceProvider::PlacesFeature>(int(features));
+ if (f == QGeoServiceProvider::AnyPlacesFeatures)
+ return (sp && (sp->placesFeatures() != QGeoServiceProvider::NoPlacesFeatures));
+ else
+ return (sp && (sp->placesFeatures() & f) == f);
+}
+
+/*!
+ \qmlproperty enumeration Plugin::required
+
+ This property contains the set of features that will be required by the
+ Plugin object when choosing which service plugin to attach to. If the
+ \l name property is set, this has no effect.
+
+ Any of the following values or a bitwise combination of multiple values
+ may be set:
+
+ \list
+ \li Plugin.NoFeatures
+ \li Plugin.GeocodingFeature
+ \li Plugin.ReverseGeocodingFeature
+ \li Plugin.RoutingFeature
+ \li Plugin.MappingFeature
+ \li Plugin.AnyPlacesFeature
+ \endlist
+*/
+QDeclarativeGeoServiceProviderRequirements *QDeclarativeGeoServiceProvider::requirements() const
+{
+ return required_;
+}
+
+/*!
+ \qmlproperty stringlist Plugin::preferred
+
+ This property contains an ordered list of preferred plugin names, which
+ will be checked for the required features set in \l{Plugin::required}{required}
+ before any other available plugins are checked.
+*/
+QStringList QDeclarativeGeoServiceProvider::preferred() const
+{
+ return prefer_;
+}
+
+void QDeclarativeGeoServiceProvider::setPreferred(const QStringList &val)
+{
+ prefer_ = val;
+ emit preferredChanged(prefer_);
+}
+
+/*!
+ \qmlproperty bool Plugin::isAttached
+
+ This property indicates if the Plugin item is attached to a geoservice provider plugin.
+*/
+bool QDeclarativeGeoServiceProvider::isAttached() const
+{
+ return (sharedProvider_ != 0);
+}
+
+/*!
+ \qmlproperty bool Plugin::allowExperimental
+
+ This property indicates if experimental plugins can be used.
+*/
+bool QDeclarativeGeoServiceProvider::allowExperimental() const
+{
+ return experimental_;
+}
+
+void QDeclarativeGeoServiceProvider::setAllowExperimental(bool allow)
+{
+ if (experimental_ == allow)
+ return;
+
+ experimental_ = allow;
+ if (sharedProvider_)
+ sharedProvider_->setAllowExperimental(allow);
+
+ emit allowExperimentalChanged(allow);
+}
+
+/*!
+ \internal
+*/
+QGeoServiceProvider *QDeclarativeGeoServiceProvider::sharedGeoServiceProvider() const
+{
+ return sharedProvider_;
+}
+
+/*!
+ \qmlproperty stringlist Plugin::locales
+
+ This property contains an ordered list of preferred plugin locales. If the first locale cannot be accommodated, then
+ the backend falls back to using the second, and so on. By default the locales property contains the system locale.
+
+ The locales are specified as strings which have the format
+ "language[_script][_country]" or "C", where:
+
+ \list
+ \li language is a lowercase, two-letter, ISO 639 language code,
+ \li script is a titlecase, four-letter, ISO 15924 script code,
+ \li country is an uppercase, two- or three-letter, ISO 3166 country code (also "419" as defined by United Nations),
+ \li the "C" locale is identical in behavior to English/UnitedStates as per QLocale
+ \endlist
+
+ If the first specified locale cannot be accommodated, the \l {Plugin} falls back to the next and so forth.
+ Some \l {Plugin} backends may not support a set of locales which are rigidly defined. An arbitrary
+ example is that some \l {Place}'s in France could have French and English localizations, while
+ certain areas in America may only have the English localization available. In the above scenario,
+ the set of supported locales is context dependent on the search location.
+
+ If the \l {Plugin} cannot accommodate any of the preferred locales, the manager falls
+ back to using a supported language that is backend specific.
+
+ For \l {Plugin}'s that do not support locales, the locales list is always empty.
+
+ The following code demonstrates how to set a single and multiple locales:
+ \snippet declarative/plugin.qml Plugin locale
+*/
+QStringList QDeclarativeGeoServiceProvider::locales() const
+{
+ return locales_;
+}
+
+void QDeclarativeGeoServiceProvider::setLocales(const QStringList &locales)
+{
+ if (locales_ == locales)
+ return;
+
+ locales_ = locales;
+
+ if (locales_.isEmpty())
+ locales_.append(QLocale().name());
+
+ if (sharedProvider_)
+ sharedProvider_->setLocale(locales_.at(0));
+
+ emit localesChanged();
+}
+
+/*!
+ \qmlproperty list<PluginParameter> Plugin::parameters
+ \default
+
+ This property holds the list of plugin parameters.
+*/
+QQmlListProperty<QDeclarativeGeoServiceProviderParameter> QDeclarativeGeoServiceProvider::parameters()
+{
+ return QQmlListProperty<QDeclarativeGeoServiceProviderParameter>(this,
+ 0,
+ parameter_append,
+ parameter_count,
+ parameter_at,
+ parameter_clear);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProvider::parameter_append(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, QDeclarativeGeoServiceProviderParameter *parameter)
+{
+ QDeclarativeGeoServiceProvider *p = static_cast<QDeclarativeGeoServiceProvider *>(prop->object);
+ p->parameters_.append(parameter);
+ if (p->sharedProvider_)
+ p->sharedProvider_->setParameters(p->parameterMap());
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeGeoServiceProvider::parameter_count(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop)
+{
+ return static_cast<QDeclarativeGeoServiceProvider *>(prop->object)->parameters_.count();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProviderParameter *QDeclarativeGeoServiceProvider::parameter_at(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, int index)
+{
+ return static_cast<QDeclarativeGeoServiceProvider *>(prop->object)->parameters_[index];
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProvider::parameter_clear(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop)
+{
+ QDeclarativeGeoServiceProvider *p = static_cast<QDeclarativeGeoServiceProvider *>(prop->object);
+ p->parameters_.clear();
+ if (p->sharedProvider_)
+ p->sharedProvider_->setParameters(p->parameterMap());
+}
+
+/*!
+ \internal
+*/
+QVariantMap QDeclarativeGeoServiceProvider::parameterMap() const
+{
+ QVariantMap map;
+
+ for (int i = 0; i < parameters_.size(); ++i) {
+ QDeclarativeGeoServiceProviderParameter *parameter = parameters_.at(i);
+ map.insert(parameter->name(), parameter->value());
+ }
+
+ return map;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+
+QDeclarativeGeoServiceProviderRequirements::QDeclarativeGeoServiceProviderRequirements(QObject *parent)
+ : QObject(parent),
+ mapping_(QDeclarativeGeoServiceProvider::NoMappingFeatures),
+ routing_(QDeclarativeGeoServiceProvider::NoRoutingFeatures),
+ geocoding_(QDeclarativeGeoServiceProvider::NoGeocodingFeatures),
+ places_(QDeclarativeGeoServiceProvider::NoPlacesFeatures)
+{
+}
+
+QDeclarativeGeoServiceProviderRequirements::~QDeclarativeGeoServiceProviderRequirements()
+{
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider::MappingFeatures QDeclarativeGeoServiceProviderRequirements::mappingRequirements() const
+{
+ return mapping_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProviderRequirements::setMappingRequirements(const QDeclarativeGeoServiceProvider::MappingFeatures &features)
+{
+ if (mapping_ == features)
+ return;
+
+ mapping_ = features;
+ emit mappingRequirementsChanged(mapping_);
+ emit requirementsChanged();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider::RoutingFeatures QDeclarativeGeoServiceProviderRequirements::routingRequirements() const
+{
+ return routing_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProviderRequirements::setRoutingRequirements(const QDeclarativeGeoServiceProvider::RoutingFeatures &features)
+{
+ if (routing_ == features)
+ return;
+
+ routing_ = features;
+ emit routingRequirementsChanged(routing_);
+ emit requirementsChanged();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider::GeocodingFeatures QDeclarativeGeoServiceProviderRequirements::geocodingRequirements() const
+{
+ return geocoding_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProviderRequirements::setGeocodingRequirements(const QDeclarativeGeoServiceProvider::GeocodingFeatures &features)
+{
+ if (geocoding_ == features)
+ return;
+
+ geocoding_ = features;
+ emit geocodingRequirementsChanged(geocoding_);
+ emit requirementsChanged();
+}
+
+/*!
+ \internal
+
+ */
+QDeclarativeGeoServiceProvider::PlacesFeatures QDeclarativeGeoServiceProviderRequirements::placesRequirements() const
+{
+ return places_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeGeoServiceProviderRequirements::setPlacesRequirements(const QDeclarativeGeoServiceProvider::PlacesFeatures &features)
+{
+ if (places_ == features)
+ return;
+
+ places_ = features;
+ emit placesRequirementsChanged(places_);
+ emit requirementsChanged();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeGeoServiceProviderRequirements::matches(const QGeoServiceProvider *provider) const
+{
+ QGeoServiceProvider::MappingFeatures mapping =
+ static_cast<QGeoServiceProvider::MappingFeatures>(int(mapping_));
+
+ // extra curlies here to avoid "dangling" else, which could belong to either if
+ // same goes for all the rest of these blocks
+ if (mapping == QGeoServiceProvider::AnyMappingFeatures) {
+ if (provider->mappingFeatures() == QGeoServiceProvider::NoMappingFeatures)
+ return false;
+ } else {
+ if ((provider->mappingFeatures() & mapping) != mapping)
+ return false;
+ }
+
+ QGeoServiceProvider::RoutingFeatures routing =
+ static_cast<QGeoServiceProvider::RoutingFeatures>(int(routing_));
+
+ if (routing == QGeoServiceProvider::AnyRoutingFeatures) {
+ if (provider->routingFeatures() == QGeoServiceProvider::NoRoutingFeatures)
+ return false;
+ } else {
+ if ((provider->routingFeatures() & routing) != routing)
+ return false;
+ }
+
+ QGeoServiceProvider::GeocodingFeatures geocoding =
+ static_cast<QGeoServiceProvider::GeocodingFeatures>(int(geocoding_));
+
+ if (geocoding == QGeoServiceProvider::AnyGeocodingFeatures) {
+ if (provider->geocodingFeatures() == QGeoServiceProvider::NoGeocodingFeatures)
+ return false;
+ } else {
+ if ((provider->geocodingFeatures() & geocoding) != geocoding)
+ return false;
+ }
+
+ QGeoServiceProvider::PlacesFeatures places =
+ static_cast<QGeoServiceProvider::PlacesFeatures>(int(places_));
+
+ if (places == QGeoServiceProvider::AnyPlacesFeatures) {
+ if (provider->placesFeatures() == QGeoServiceProvider::NoPlacesFeatures)
+ return false;
+ } else {
+ if ((provider->placesFeatures() & places) != places)
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+
+/*!
+ \qmltype PluginParameter
+ \instantiates QDeclarativeGeoServiceProviderParameter
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-common
+ \since Qt Location 5.5
+
+ \brief The PluginParameter type describes a parameter to a \l Plugin.
+
+ The PluginParameter object is used to provide a parameter of some kind
+ to a Plugin. Typically these parameters contain details like an application
+ token for access to a service, or a proxy server to use for network access.
+
+ To set such a parameter, declare a PluginParameter inside a \l Plugin
+ object, and give it \l{name} and \l{value} properties. A list of valid
+ parameter names for each plugin is available from the
+ \l {Qt Location#Plugin References and Parameters}{plugin reference pages}.
+
+ \section2 Example Usage
+
+ The following example shows an instantiation of the \l {Qt Location HERE Plugin}{HERE} plugin
+ with a mapping API \e app_id and \e token pair specific to the application.
+
+ \code
+ Plugin {
+ name: "here"
+ PluginParameter { name: "here.app_id"; value: "EXAMPLE_API_ID" }
+ PluginParameter { name: "here.token"; value: "EXAMPLE_TOKEN_123" }
+ }
+ \endcode
+*/
+
+QDeclarativeGeoServiceProviderParameter::QDeclarativeGeoServiceProviderParameter(QObject *parent)
+ : QObject(parent) {}
+
+QDeclarativeGeoServiceProviderParameter::~QDeclarativeGeoServiceProviderParameter() {}
+
+/*!
+ \qmlproperty string PluginParameter::name
+
+ This property holds the name of the plugin parameter as a single formatted string.
+*/
+void QDeclarativeGeoServiceProviderParameter::setName(const QString &name)
+{
+ if (name_ == name)
+ return;
+
+ name_ = name;
+
+ emit nameChanged(name_);
+}
+
+QString QDeclarativeGeoServiceProviderParameter::name() const
+{
+ return name_;
+}
+
+/*!
+ \qmlproperty QVariant PluginParameter::value
+
+ This property holds the value of the plugin parameter which support different types of values (variant).
+*/
+void QDeclarativeGeoServiceProviderParameter::setValue(const QVariant &value)
+{
+ if (value_ == value)
+ return;
+
+ value_ = value;
+
+ emit valueChanged(value_);
+}
+
+QVariant QDeclarativeGeoServiceProviderParameter::value() const
+{
+ return value_;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+
+#include "moc_qdeclarativegeoserviceprovider_p.cpp"
+
+QT_END_NAMESPACE
+
diff --git a/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h b/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h
new file mode 100644
index 00000000..bcf67124
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativegeoserviceprovider_p.h
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEQGEOSERVICEPROVIDER_H
+#define QDECLARATIVEQGEOSERVICEPROVIDER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlListProperty>
+#include <QtLocation/QGeoServiceProvider>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProviderParameter : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ explicit QDeclarativeGeoServiceProviderParameter(QObject *parent = 0);
+ ~QDeclarativeGeoServiceProviderParameter();
+
+ void setName(const QString &name);
+ QString name() const;
+
+ void setValue(const QVariant &value);
+ QVariant value() const;
+
+Q_SIGNALS:
+ void nameChanged(const QString &name);
+ void valueChanged(const QVariant &value);
+
+private:
+ QString name_;
+ QVariant value_;
+};
+
+class QDeclarativeGeoServiceProviderRequirements;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProvider : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_ENUMS(RoutingFeature)
+ Q_ENUMS(GeocodingFeature)
+ Q_ENUMS(MappingFeature)
+ Q_ENUMS(PlacesFeature)
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QStringList availableServiceProviders READ availableServiceProviders CONSTANT)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> parameters READ parameters)
+ Q_PROPERTY(QDeclarativeGeoServiceProviderRequirements *required READ requirements)
+ Q_PROPERTY(QStringList locales READ locales WRITE setLocales NOTIFY localesChanged)
+ Q_PROPERTY(QStringList preferred READ preferred WRITE setPreferred NOTIFY preferredChanged)
+ Q_PROPERTY(bool allowExperimental READ allowExperimental WRITE setAllowExperimental NOTIFY allowExperimentalChanged)
+ Q_PROPERTY(bool isAttached READ isAttached NOTIFY attached)
+
+ Q_CLASSINFO("DefaultProperty", "parameters")
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativeGeoServiceProvider(QObject *parent = Q_NULLPTR);
+ ~QDeclarativeGeoServiceProvider();
+
+ enum RoutingFeature {
+ NoRoutingFeatures = QGeoServiceProvider::NoRoutingFeatures,
+ OnlineRoutingFeature = QGeoServiceProvider::OnlineRoutingFeature,
+ OfflineRoutingFeature = QGeoServiceProvider::OfflineRoutingFeature,
+ LocalizedRoutingFeature = QGeoServiceProvider::LocalizedRoutingFeature,
+ RouteUpdatesFeature = QGeoServiceProvider::RouteUpdatesFeature,
+ AlternativeRoutesFeature = QGeoServiceProvider::AlternativeRoutesFeature,
+ ExcludeAreasRoutingFeature = QGeoServiceProvider::ExcludeAreasRoutingFeature,
+ AnyRoutingFeatures = QGeoServiceProvider::AnyRoutingFeatures
+ };
+
+ enum GeocodingFeature {
+ NoGeocodingFeatures = QGeoServiceProvider::NoGeocodingFeatures,
+ OnlineGeocodingFeature = QGeoServiceProvider::OnlineGeocodingFeature,
+ OfflineGeocodingFeature = QGeoServiceProvider::OfflineGeocodingFeature,
+ ReverseGeocodingFeature = QGeoServiceProvider::ReverseGeocodingFeature,
+ LocalizedGeocodingFeature = QGeoServiceProvider::LocalizedGeocodingFeature,
+ AnyGeocodingFeatures = QGeoServiceProvider::AnyGeocodingFeatures
+ };
+
+ enum MappingFeature {
+ NoMappingFeatures = QGeoServiceProvider::NoMappingFeatures,
+ OnlineMappingFeature = QGeoServiceProvider::OnlineMappingFeature,
+ OfflineMappingFeature = QGeoServiceProvider::OfflineMappingFeature,
+ LocalizedMappingFeature = QGeoServiceProvider::LocalizedMappingFeature,
+ AnyMappingFeatures = QGeoServiceProvider::AnyMappingFeatures
+ };
+
+ enum PlacesFeature {
+ NoPlacesFeatures = QGeoServiceProvider::NoPlacesFeatures,
+ OnlinePlacesFeature = QGeoServiceProvider::OnlinePlacesFeature,
+ OfflinePlacesFeature = QGeoServiceProvider::OfflinePlacesFeature,
+ SavePlaceFeature = QGeoServiceProvider::SavePlaceFeature,
+ RemovePlaceFeature = QGeoServiceProvider::RemovePlaceFeature,
+ SaveCategoryFeature = QGeoServiceProvider::SaveCategoryFeature,
+ RemoveCategoryFeature = QGeoServiceProvider::RemoveCategoryFeature,
+ PlaceRecommendationsFeature = QGeoServiceProvider::PlaceRecommendationsFeature,
+ SearchSuggestionsFeature = QGeoServiceProvider::SearchSuggestionsFeature,
+ LocalizedPlacesFeature = QGeoServiceProvider::LocalizedPlacesFeature,
+ NotificationsFeature = QGeoServiceProvider::NotificationsFeature,
+ PlaceMatchingFeature = QGeoServiceProvider::PlaceMatchingFeature,
+ AnyPlacesFeatures = QGeoServiceProvider::AnyPlacesFeatures
+ };
+
+ Q_DECLARE_FLAGS(RoutingFeatures, RoutingFeature)
+ Q_FLAGS(RoutingFeatures)
+
+ Q_DECLARE_FLAGS(GeocodingFeatures, GeocodingFeature)
+ Q_FLAGS(GeocodingFeatures)
+
+ Q_DECLARE_FLAGS(MappingFeatures, MappingFeature)
+ Q_FLAGS(MappingFeatures)
+
+ Q_DECLARE_FLAGS(PlacesFeatures, PlacesFeature)
+ Q_FLAGS(PlacesFeatures)
+
+ // From QQmlParserStatus
+ virtual void classBegin() {}
+ virtual void componentComplete();
+
+ void setName(const QString &name);
+ QString name() const;
+
+ QQmlListProperty<QDeclarativeGeoServiceProviderParameter> parameters();
+ QVariantMap parameterMap() const;
+
+ QStringList availableServiceProviders();
+
+ QDeclarativeGeoServiceProviderRequirements *requirements() const;
+
+ QStringList preferred() const;
+ void setPreferred(const QStringList &val);
+
+ QGeoServiceProvider *sharedGeoServiceProvider() const;
+
+ Q_INVOKABLE bool supportsRouting(const RoutingFeatures &feature = AnyRoutingFeatures) const;
+ Q_INVOKABLE bool supportsGeocoding(const GeocodingFeatures &feature = AnyGeocodingFeatures) const;
+ Q_INVOKABLE bool supportsMapping(const MappingFeatures &feature = AnyMappingFeatures) const;
+ Q_INVOKABLE bool supportsPlaces(const PlacesFeatures &feature = AnyPlacesFeatures) const;
+
+ QStringList locales() const;
+ void setLocales(const QStringList &locales);
+
+ bool isAttached() const;
+
+ void setAllowExperimental(bool allow);
+ bool allowExperimental() const;
+
+Q_SIGNALS:
+ void nameChanged(const QString &name);
+ void localesChanged();
+ void attached();
+ void preferredChanged(const QStringList &preferences);
+ void allowExperimentalChanged(bool allow);
+
+private:
+ static void parameter_append(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, QDeclarativeGeoServiceProviderParameter *mapObject);
+ static int parameter_count(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop);
+ static QDeclarativeGeoServiceProviderParameter *parameter_at(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop, int index);
+ static void parameter_clear(QQmlListProperty<QDeclarativeGeoServiceProviderParameter> *prop);
+
+ QGeoServiceProvider *sharedProvider_;
+ QString name_;
+ QList<QDeclarativeGeoServiceProviderParameter *> parameters_;
+ QDeclarativeGeoServiceProviderRequirements *required_;
+ bool complete_;
+ bool experimental_;
+ QStringList locales_;
+ QStringList prefer_;
+ Q_DISABLE_COPY(QDeclarativeGeoServiceProvider)
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoServiceProviderRequirements : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QDeclarativeGeoServiceProvider::MappingFeatures mapping
+ READ mappingRequirements WRITE setMappingRequirements
+ NOTIFY mappingRequirementsChanged)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider::RoutingFeatures routing
+ READ routingRequirements WRITE setRoutingRequirements
+ NOTIFY routingRequirementsChanged)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider::GeocodingFeatures geocoding
+ READ geocodingRequirements WRITE setGeocodingRequirements
+ NOTIFY geocodingRequirementsChanged)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider::PlacesFeatures places
+ READ placesRequirements WRITE setPlacesRequirements
+ NOTIFY placesRequirementsChanged)
+
+public:
+ explicit QDeclarativeGeoServiceProviderRequirements(QObject *parent = 0);
+ ~QDeclarativeGeoServiceProviderRequirements();
+
+ QDeclarativeGeoServiceProvider::MappingFeatures mappingRequirements() const;
+ void setMappingRequirements(const QDeclarativeGeoServiceProvider::MappingFeatures &features);
+
+ QDeclarativeGeoServiceProvider::RoutingFeatures routingRequirements() const;
+ void setRoutingRequirements(const QDeclarativeGeoServiceProvider::RoutingFeatures &features);
+
+ QDeclarativeGeoServiceProvider::GeocodingFeatures geocodingRequirements() const;
+ void setGeocodingRequirements(const QDeclarativeGeoServiceProvider::GeocodingFeatures &features);
+
+ QDeclarativeGeoServiceProvider::PlacesFeatures placesRequirements() const;
+ void setPlacesRequirements(const QDeclarativeGeoServiceProvider::PlacesFeatures &features);
+
+ Q_INVOKABLE bool matches(const QGeoServiceProvider *provider) const;
+
+Q_SIGNALS:
+ void mappingRequirementsChanged(const QDeclarativeGeoServiceProvider::MappingFeatures &features);
+ void routingRequirementsChanged(const QDeclarativeGeoServiceProvider::RoutingFeatures &features);
+ void geocodingRequirementsChanged(const QDeclarativeGeoServiceProvider::GeocodingFeatures &features);
+ void placesRequirementsChanged(const QDeclarativeGeoServiceProvider::PlacesFeatures &features);
+
+ void requirementsChanged();
+
+private:
+ QDeclarativeGeoServiceProvider::MappingFeatures mapping_;
+ QDeclarativeGeoServiceProvider::RoutingFeatures routing_;
+ QDeclarativeGeoServiceProvider::GeocodingFeatures geocoding_;
+ QDeclarativeGeoServiceProvider::PlacesFeatures places_;
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGeoServiceProviderParameter)
+QML_DECLARE_TYPE(QDeclarativeGeoServiceProviderRequirements)
+QML_DECLARE_TYPE(QDeclarativeGeoServiceProvider)
+
+#endif
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
new file mode 100644
index 00000000..3f05957a
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
@@ -0,0 +1,743 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2015 The Qt Company Ltd.
+ ** Contact: http://www.qt.io/licensing/
+ **
+ ** This file is part of the QtLocation module of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:LGPL3$
+ ** Commercial License Usage
+ ** Licensees holding valid commercial Qt licenses may use this file in
+ ** accordance with the commercial license agreement provided with the
+ ** Software or, alternatively, in accordance with the terms contained in
+ ** a written agreement between you and The Qt Company. For licensing terms
+ ** and conditions see http://www.qt.io/terms-conditions. For further
+ ** information use the contact form at http://www.qt.io/contact-us.
+ **
+ ** GNU Lesser General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU Lesser
+ ** General Public License version 3 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU Lesser General Public License version 3 requirements
+ ** will be met: https://www.gnu.org/licenses/lgpl.html.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 2.0 or later as published by the Free
+ ** Software Foundation and appearing in the file LICENSE.GPL included in
+ ** the packaging of this file. Please review the following information to
+ ** ensure the GNU General Public License version 2.0 requirements will be
+ ** met: http://www.gnu.org/licenses/gpl-2.0.html.
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#include "qdeclarativepolygonmapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qlocationutils_p.h"
+#include "error_messages.h"
+#include "locationvaluetypehelper_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <QtCore/QScopedValueRollback>
+#include <QtGui/private/qtriangulator_p.h>
+#include <QtQml/QQmlInfo>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QPainter>
+#include <QPainterPath>
+#include <qnumeric.h>
+
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtPositioning/private/qclipperutils_p.h>
+
+/* poly2tri triangulator includes */
+#include <clip2tri.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapPolygon
+ \instantiates QDeclarativePolygonMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapPolygon type displays a polygon on a Map
+
+ The MapPolygon type displays a polygon on a Map, specified in terms of an ordered list of
+ \l {QtPositioning::coordinate}{coordinates}. For best appearance and results, polygons should be
+ simple (not self-intersecting).
+
+ The \l {QtPositioning::coordinate}{coordinates} on the path cannot be directly changed after
+ being added to the Polygon. Instead, copy the \l path into a var, modify the copy and reassign
+ the copy back to the \l path.
+
+ \code
+ var path = mapPolygon.path;
+ path[0].latitude = 5;
+ mapPolygon.path = path;
+ \endcode
+
+ Coordinates can also be added and removed at any time using the \l addCoordinate and
+ \l removeCoordinate methods.
+
+ For drawing rectangles with "straight" edges (same latitude across one
+ edge, same latitude across the other), the \l MapRectangle type provides
+ a simpler, two-point API.
+
+ By default, the polygon is displayed as a 1 pixel black border with no
+ fill. To change its appearance, use the \l color, \l border.color and
+ \l border.width properties.
+
+ \note Since MapPolygons are geographic items, dragging a MapPolygon
+ (through the use of \l MouseArea) causes its vertices to be
+ recalculated in the geographic coordinate space. The edges retain the
+ same geographic lengths (latitude and longitude differences between the
+ vertices), but they remain straight. Apparent stretching of the item occurs
+ when dragged to a different latitude.
+
+ \section2 Performance
+
+ MapPolygons have a rendering cost that is O(n) with respect to the number
+ of vertices. This means that the per frame cost of having a Polygon on the
+ Map grows in direct proportion to the number of points on the Polygon. There
+ is an additional triangulation cost (approximately O(n log n)) which is
+ currently paid with each frame, but in future may be paid only upon adding
+ or removing points.
+
+ Like the other map objects, MapPolygon is normally drawn without a smooth
+ appearance. Setting the \l {Item::opacity}{opacity} property will force the object to
+ be blended, which decreases performance considerably depending on the hardware in use.
+
+ \section2 Example Usage
+
+ The following snippet shows a MapPolygon being used to display a triangle,
+ with three vertices near Brisbane, Australia. The triangle is filled in
+ green, with a 1 pixel black border.
+
+ \code
+ Map {
+ MapPolygon {
+ color: 'green'
+ path: [
+ { latitude: -27, longitude: 153.0 },
+ { latitude: -27, longitude: 154.1 },
+ { latitude: -28, longitude: 153.5 }
+ ]
+ }
+ }
+ \endcode
+
+ \image api-mappolygon.png
+*/
+
+QGeoMapPolygonGeometry::QGeoMapPolygonGeometry()
+: assumeSimple_(false)
+{
+}
+
+/*!
+ \internal
+*/
+void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path)
+{
+ if (!sourceDirty_)
+ return;
+
+ srcPath_ = QPainterPath();
+
+ // build the actual path
+ // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints
+ srcOrigin_ = geoLeftBound_;
+ double unwrapBelowX = 0;
+ QDoubleVector2D leftBoundWrapped = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(geoLeftBound_));
+ if (preserveGeometry_)
+ unwrapBelowX = leftBoundWrapped.x();
+
+ QList<QDoubleVector2D> wrappedPath;
+ wrappedPath.reserve(path.size());
+ QDoubleVector2D wrappedLeftBound(qInf(), qInf());
+ // 1)
+ for (int i = 0; i < path.size(); ++i) {
+ const QGeoCoordinate &coord = path.at(i);
+ if (!coord.isValid())
+ continue;
+
+ QDoubleVector2D wrappedProjection = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(coord));
+
+ // We can get NaN if the map isn't set up correctly, or the projection
+ // is faulty -- probably best thing to do is abort
+ if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y()))
+ return;
+
+ const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x());
+ // unwrap x to preserve geometry if moved to border of map
+ if (preserveGeometry_ && isPointLessThanUnwrapBelowX) {
+ double distance = wrappedProjection.x() - unwrapBelowX;
+ if (distance < 0.0)
+ distance += 1.0;
+ wrappedProjection.setX(unwrapBelowX + distance);
+ }
+ if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) {
+ wrappedLeftBound = wrappedProjection;
+ }
+ wrappedPath.append(wrappedProjection);
+ }
+
+ // 2)
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), true);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X
+ QDoubleVector2D lb(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths)
+ for (const QDoubleVector2D &p: path)
+ if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y()))
+ // y-minimization needed to find the same point on polygon and border
+ lb = p;
+
+ if (qIsInf(lb.x())) // e.g., when the polygon is clipped entirely
+ return;
+
+ // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(wrappedLeftBound.x(), lb.x()));
+ leftBoundWrapped = lb;
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(lb));
+ } else {
+ clippedPaths.append(wrappedPath);
+ }
+
+ // 3)
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(leftBoundWrapped);
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+ point = point - origin; // (0,0) if point == geoLeftBound_
+
+ if (i == 0) {
+ srcPath_.moveTo(point.toPointF());
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ srcPath_.lineTo(point.toPointF());
+ lastAddedPoint = point;
+ }
+ }
+ }
+ srcPath_.closeSubpath();
+ }
+
+ if (!assumeSimple_)
+ srcPath_ = srcPath_.simplified();
+
+ sourceBounds_ = srcPath_.boundingRect();
+}
+
+/*!
+ \internal
+*/
+void QGeoMapPolygonGeometry::updateScreenPoints(const QGeoMap &map)
+{
+ if (!screenDirty_)
+ return;
+
+ if (map.viewportWidth() == 0 || map.viewportHeight() == 0) {
+ clear();
+ return;
+ }
+
+ QDoubleVector2D origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false);
+
+ // Create the viewport rect in the same coordinate system
+ // as the actual points
+ QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight());
+ viewport.translate(-1 * origin.toPointF());
+
+ QPainterPath vpPath;
+ vpPath.addRect(viewport);
+
+ // The geometry has already been clipped against the visible region projection in wrapped mercator space.
+ QPainterPath ppi = srcPath_;
+ clear();
+
+ // a polygon requires at least 3 points;
+ if (ppi.elementCount() < 3)
+ return;
+
+ // TODO: move this to clip2tri, and remove the code below.
+ // For clip2tri use the intersection between the the viewport AND the map as clipping region.
+
+ // Intersection between the viewport and a concave polygon can create multiple polygons
+ // joined by a line at the viewport border, and poly2tri does not triangulate this very well
+ // so use the full src path if the resulting polygon is concave.
+ if (clipToViewport_) {
+ int changeInX = 0;
+ int changeInY = 0;
+ QPainterPath::Element e1 = ppi.elementAt(1);
+ QPainterPath::Element e = ppi.elementAt(0);
+ QVector2D edgeA(e1.x - e.x ,e1.y - e.y);
+ for (int i = 2; i <= ppi.elementCount(); ++i) {
+ e = ppi.elementAt(i % ppi.elementCount());
+ if (e.x == e1.x && e.y == e1.y)
+ continue;
+ QVector2D edgeB(e.x - e1.x, e.y - e1.y);
+ if ((edgeA.x() < 0) == (edgeB.x() >= 0))
+ changeInX++;
+ if ((edgeA.y() < 0) == (edgeB.y() >= 0))
+ changeInY++;
+ edgeA = edgeB;
+ e1 = e;
+ }
+ if (changeInX > 2 || changeInY > 2) // polygon is concave
+ ppi = srcPath_;
+ }
+
+ // translate the path into top-left-centric coordinates
+ QRectF bb = ppi.boundingRect();
+ ppi.translate(-bb.left(), -bb.top());
+ firstPointOffset_ = -1 * bb.topLeft();
+
+ ppi.closeSubpath();
+
+ screenOutline_ = ppi;
+
+#if 0 // TODO: This code appears to crash seldomly in presence of tilt. Requires further investigation
+ std::vector<std::vector<c2t::Point>> clipperPoints;
+ clipperPoints.push_back(std::vector<c2t::Point>());
+ std::vector<c2t::Point> &curPts = clipperPoints.front();
+ curPts.reserve(ppi.elementCount());
+ for (int i = 0; i < ppi.elementCount(); ++i) {
+ const QPainterPath::Element e = ppi.elementAt(i);
+ if (e.isMoveTo() || i == ppi.elementCount() - 1
+ || (qAbs(e.x - curPts.front().x) < 0.1
+ && qAbs(e.y - curPts.front().y) < 0.1)) {
+ if (curPts.size() > 2) {
+ c2t::clip2tri *cdt = new c2t::clip2tri();
+ std::vector<c2t::Point> outputTriangles;
+ cdt->triangulate(clipperPoints, outputTriangles, std::vector<c2t::Point>());
+ for (size_t i = 0; i < outputTriangles.size(); ++i) {
+ screenVertices_ << QPointF(outputTriangles[i].x, outputTriangles[i].y);
+ }
+ delete cdt;
+ }
+ curPts.clear();
+ curPts.reserve(ppi.elementCount() - i);
+ curPts.push_back( c2t::Point(e.x, e.y));
+ } else if (e.isLineTo()) {
+ curPts.push_back( c2t::Point(e.x, e.y));
+ } else {
+ qWarning("Unhandled element type in polygon painterpath");
+ }
+ }
+#else // Old qTriangulate()-based code.
+ QTriangleSet ts = qTriangulate(ppi);
+ qreal *vx = ts.vertices.data();
+
+ screenIndices_.reserve(ts.indices.size());
+ screenVertices_.reserve(ts.vertices.size());
+
+ if (ts.indices.type() == QVertexIndexVector::UnsignedInt) {
+ const quint32 *ix = reinterpret_cast<const quint32 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ } else {
+ const quint16 *ix = reinterpret_cast<const quint16 *>(ts.indices.data());
+ for (int i = 0; i < (ts.indices.size()/3*3); ++i)
+ screenIndices_ << ix[i];
+ }
+ for (int i = 0; i < (ts.vertices.size()/2*2); i += 2)
+ screenVertices_ << QPointF(vx[i], vx[i + 1]);
+#endif
+
+ screenBounds_ = ppi.boundingRect();
+}
+
+QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), dirtyMaterial_(true),
+ updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(handleBorderUpdated()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(handleBorderUpdated()));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::handleBorderUpdated()
+{
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+QDeclarativePolygonMapItem::~QDeclarativePolygonMapItem()
+{
+}
+
+/*!
+ \qmlpropertygroup Location::MapPolygon::border
+ \qmlproperty int MapPolygon::border.width
+ \qmlproperty color MapPolygon::border.color
+
+ This property is part of the border property group. The border property
+ group holds the width and color used to draw the border of the polygon.
+
+ The width is in pixels and is independent of the zoom level of the map.
+
+ The default values correspond to a black border with a width of 1 pixel.
+ For no line, use a width of 0 or a transparent color.
+*/
+
+QDeclarativeMapLineProperties *QDeclarativePolygonMapItem::border()
+{
+ return &border_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map) {
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+ }
+}
+
+/*!
+ \qmlproperty list<coordinate> MapPolygon::path
+
+ This property holds the ordered list of coordinates which
+ define the polygon.
+
+ \sa addCoordinate, removeCoordinate
+*/
+QJSValue QDeclarativePolygonMapItem::path() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(this);
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(geopath_.path().length()));
+ for (int i = 0; i < geopath_.path().length(); ++i) {
+ const QGeoCoordinate &c = geopath_.coordinateAt(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ pathArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, pathArray.asReturnedValue());
+}
+
+void QDeclarativePolygonMapItem::setPath(const QJSValue &value)
+{
+ if (!value.isArray())
+ return;
+
+ QList<QGeoCoordinate> pathList;
+ quint32 length = value.property(QStringLiteral("length")).toUInt();
+ for (quint32 i = 0; i < length; ++i) {
+ bool ok;
+ QGeoCoordinate c = parseCoordinate(value.property(i), &ok);
+
+ if (!ok || !c.isValid()) {
+ qmlWarning(this) << "Unsupported path type";
+ return;
+ }
+
+ pathList.append(c);
+ }
+
+ // Equivalent to QDeclarativePolylineMapItem::setPathFromGeoList
+ if (geopath_.path() == pathList)
+ return;
+
+ geopath_.setPath(pathList);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolygon::addCoordinate(coordinate)
+
+ Adds a coordinate to the path.
+
+ \sa removeCoordinate, path
+*/
+
+void QDeclarativePolygonMapItem::addCoordinate(const QGeoCoordinate &coordinate)
+{
+ geopath_.addCoordinate(coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolygon::removeCoordinate(coordinate)
+
+ Removes \a coordinate from the path. If there are multiple instances of the
+ same coordinate, the one added last is removed.
+
+ If \a coordinate is not in the path this method does nothing.
+
+ \sa addCoordinate, path
+*/
+void QDeclarativePolygonMapItem::removeCoordinate(const QGeoCoordinate &coordinate)
+{
+ int length = geopath_.path().length();
+ geopath_.removeCoordinate(coordinate);
+ if (geopath_.path().length() == length)
+ return;
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlproperty color MapPolygon::color
+
+ This property holds the color used to fill the polygon.
+
+ The default value is transparent.
+*/
+
+QColor QDeclarativePolygonMapItem::color() const
+{
+ return color_;
+}
+
+void QDeclarativePolygonMapItem::setColor(const QColor &color)
+{
+ if (color_ == color)
+ return;
+
+ color_ = color;
+ dirtyMaterial_ = true;
+ update();
+ emit colorChanged(color_);
+}
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativePolygonMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
+
+ if (!node)
+ node = new MapPolygonNode();
+
+ //TODO: update only material
+ if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
+ node->update(color_, border_.color(), &geometry_, &borderGeometry_);
+ geometry_.setPreserveGeometry(false);
+ borderGeometry_.setPreserveGeometry(false);
+ geometry_.markClean();
+ borderGeometry_.markClean();
+ dirtyMaterial_ = false;
+ }
+ return node;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::updatePolish()
+{
+ if (!map() || geopath_.path().length() == 0)
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ geometry_.updateSourcePoints(*map(), geopath_.path());
+ geometry_.updateScreenPoints(*map());
+
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+ borderGeometry_.clear();
+
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QGeoCoordinate> closedPath = geopath_.path();
+ closedPath << closedPath.first();
+
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+
+ const QGeoCoordinate &geometryOrigin = geometry_.origin();
+
+ borderGeometry_.srcPoints_.clear();
+ borderGeometry_.srcPointTypes_.clear();
+
+ QDoubleVector2D borderLeftBoundWrapped;
+ QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
+ if (clippedPaths.size()) {
+ borderLeftBoundWrapped = map()->geoProjection().geoToWrappedMapProjection(geometryOrigin);
+ borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
+ borderGeometry_.updateScreenPoints(*map(), border_.width());
+
+ geoms << &borderGeometry_;
+ } else {
+ borderGeometry_.clear();
+ }
+ }
+
+ QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ setWidth(combined.width());
+ setHeight(combined.height());
+
+ setPositionOnMap(geometry_.origin(), -1 * geometry_.sourceBoundingBox().topLeft());
+}
+
+void QDeclarativePolygonMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ return;
+
+ geometry_.setPreserveGeometry(true, geometry_.geoLeftBound());
+ borderGeometry_.setPreserveGeometry(true, borderGeometry_.geoLeftBound());
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativePolygonMapItem::contains(const QPointF &point) const
+{
+ return (geometry_.contains(point) || borderGeometry_.contains(point));
+}
+
+const QGeoShape &QDeclarativePolygonMapItem::geoShape() const
+{
+ return geopath_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolygonMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+ // TODO: change the algorithm to preserve the distances and size!
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
+
+ geopath_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+//////////////////////////////////////////////////////////////////////
+
+MapPolygonNode::MapPolygonNode() :
+ border_(new MapPolylineNode()),
+ geometry_(QSGGeometry::defaultAttributes_Point2D(), 0),
+ blocked_(true)
+{
+ geometry_.setDrawingMode(QSGGeometry::DrawTriangles);
+ QSGGeometryNode::setMaterial(&fill_material_);
+ QSGGeometryNode::setGeometry(&geometry_);
+
+ appendChildNode(border_);
+}
+
+MapPolygonNode::~MapPolygonNode()
+{
+}
+
+/*!
+ \internal
+*/
+bool MapPolygonNode::isSubtreeBlocked() const
+{
+ return blocked_;
+}
+
+/*!
+ \internal
+*/
+void MapPolygonNode::update(const QColor &fillColor, const QColor &borderColor,
+ const QGeoMapItemGeometry *fillShape,
+ const QGeoMapItemGeometry *borderShape)
+{
+ /* Do the border update first */
+ border_->update(borderColor, borderShape);
+
+ /* If we have neither fill nor border with valid points, block the whole
+ * tree. We can't just block the fill without blocking the border too, so
+ * we're a little conservative here (maybe at the expense of rendering
+ * accuracy) */
+ if (fillShape->size() == 0) {
+ if (borderShape->size() == 0) {
+ blocked_ = true;
+ return;
+ } else {
+ blocked_ = false;
+ }
+ } else {
+ blocked_ = false;
+ }
+
+ QSGGeometry *fill = QSGGeometryNode::geometry();
+ fillShape->allocateAndFill(fill);
+ markDirty(DirtyGeometry);
+
+ if (fillColor != fill_material_.color()) {
+ fill_material_.setColor(fillColor);
+ setMaterial(&fill_material_);
+ markDirty(DirtyMaterial);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
new file mode 100644
index 00000000..cb4de6b9
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPOLYGONMAPITEM
+#define QDECLARATIVEPOLYGONMAPITEM
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qgeomapitemgeometry_p.h>
+
+#include <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+
+QT_BEGIN_NAMESPACE
+
+class MapPolygonNode;
+
+class QGeoMapPolygonGeometry : public QGeoMapItemGeometry
+{
+public:
+ QGeoMapPolygonGeometry();
+
+ inline void setAssumeSimple(bool value) { assumeSimple_ = value; }
+
+ void updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path);
+
+ void updateScreenPoints(const QGeoMap &map);
+
+protected:
+ QPainterPath srcPath_;
+ bool assumeSimple_;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolygonMapItem : public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QJSValue path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QDeclarativeMapLineProperties *border READ border CONSTANT)
+
+public:
+ explicit QDeclarativePolygonMapItem(QQuickItem *parent = 0);
+ ~QDeclarativePolygonMapItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+ //from QuickItem
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+
+ Q_INVOKABLE void addCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void removeCoordinate(const QGeoCoordinate &coordinate);
+
+ QJSValue path() const;
+ void setPath(const QJSValue &value);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QDeclarativeMapLineProperties *border();
+
+ bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void pathChanged();
+ void colorChanged(const QColor &color);
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
+ void handleBorderUpdated();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ void pathPropertyChanged();
+
+ QGeoPath geopath_;
+ QDeclarativeMapLineProperties border_;
+ QColor color_;
+ bool dirtyMaterial_;
+ QGeoMapPolygonGeometry geometry_;
+ QGeoMapPolylineGeometry borderGeometry_;
+ bool updatingGeometry_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class MapPolygonNode : public QSGGeometryNode
+{
+
+public:
+ MapPolygonNode();
+ ~MapPolygonNode();
+
+ void update(const QColor &fillColor, const QColor &borderColor,
+ const QGeoMapItemGeometry *fillShape,
+ const QGeoMapItemGeometry *borderShape);
+
+ bool isSubtreeBlocked() const;
+
+private:
+ QSGFlatColorMaterial fill_material_;
+ MapPolylineNode *border_;
+ QSGGeometry geometry_;
+ bool blocked_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePolygonMapItem)
+
+#endif /* QDECLARATIVEPOLYGONMAPITEM_H_ */
diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
new file mode 100644
index 00000000..601af6ee
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
@@ -0,0 +1,956 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2015 The Qt Company Ltd.
+ ** Contact: http://www.qt.io/licensing/
+ **
+ ** This file is part of the QtLocation module of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:LGPL3$
+ ** Commercial License Usage
+ ** Licensees holding valid commercial Qt licenses may use this file in
+ ** accordance with the commercial license agreement provided with the
+ ** Software or, alternatively, in accordance with the terms contained in
+ ** a written agreement between you and The Qt Company. For licensing terms
+ ** and conditions see http://www.qt.io/terms-conditions. For further
+ ** information use the contact form at http://www.qt.io/contact-us.
+ **
+ ** GNU Lesser General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU Lesser
+ ** General Public License version 3 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU Lesser General Public License version 3 requirements
+ ** will be met: https://www.gnu.org/licenses/lgpl.html.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 2.0 or later as published by the Free
+ ** Software Foundation and appearing in the file LICENSE.GPL included in
+ ** the packaging of this file. Please review the following information to
+ ** ensure the GNU General Public License version 2.0 requirements will be
+ ** met: http://www.gnu.org/licenses/gpl-2.0.html.
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#include "qdeclarativepolylinemapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qlocationutils_p.h"
+#include "error_messages.h"
+#include "locationvaluetypehelper_p.h"
+#include "qdoublevector2d_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+#include <QtCore/QScopedValueRollback>
+#include <QtQml/QQmlInfo>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPainterPathStroker>
+#include <qnumeric.h>
+
+#include <QtGui/private/qvectorpath_p.h>
+#include <QtGui/private/qtriangulatingstroker_p.h>
+#include <QtGui/private/qtriangulator_p.h>
+
+#include <QtPositioning/private/qclipperutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapPolyline
+ \instantiates QDeclarativePolylineMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+
+ \brief The MapPolyline type displays a polyline on a map.
+
+ The MapPolyline type displays a polyline on a map, specified in terms of an ordered list of
+ \l {coordinate}{coordinates}. The \l {coordinate}{coordinates} on
+ the path cannot be directly changed after being added to the Polyline. Instead, copy the
+ \l path into a var, modify the copy and reassign the copy back to the \l path.
+
+ \code
+ var path = mapPolyline.path;
+ path[0].latitude = 5;
+ mapPolyline.path = path;
+ \endcode
+
+ Coordinates can also be added and removed at any time using the \l addCoordinate and
+ \l removeCoordinate methods.
+
+ By default, the polyline is displayed as a 1-pixel thick black line. This
+ can be changed using the \l line.width and \l line.color properties.
+
+ \section2 Performance
+
+ MapPolylines have a rendering cost that is O(n) with respect to the number
+ of vertices. This means that the per frame cost of having a polyline on
+ the Map grows in direct proportion to the number of points in the polyline.
+
+ Like the other map objects, MapPolyline is normally drawn without a smooth
+ appearance. Setting the \l {Item::opacity}{opacity} property will force the object to
+ be blended, which decreases performance considerably depending on the hardware in use.
+
+ \note MapPolylines are implemented using the OpenGL GL_LINES
+ primitive. There have been occasional reports of issues and rendering
+ inconsistencies on some (particularly quite old) platforms. No workaround
+ is yet available for these issues.
+
+ \section2 Example Usage
+
+ The following snippet shows a MapPolyline with 4 points, making a shape
+ like the top part of a "question mark" (?), near Brisbane, Australia.
+ The line drawn is 3 pixels in width and green in color.
+
+ \code
+ Map {
+ MapPolyline {
+ line.width: 3
+ line.color: 'green'
+ path: [
+ { latitude: -27, longitude: 153.0 },
+ { latitude: -27, longitude: 154.1 },
+ { latitude: -28, longitude: 153.5 },
+ { latitude: -29, longitude: 153.5 }
+ ]
+ }
+ }
+ \endcode
+
+ \image api-mappolyline.png
+*/
+
+QDeclarativeMapLineProperties::QDeclarativeMapLineProperties(QObject *parent) :
+ QObject(parent),
+ width_(1.0),
+ color_(Qt::black)
+{
+}
+
+/*!
+ \internal
+*/
+QColor QDeclarativeMapLineProperties::color() const
+{
+ return color_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeMapLineProperties::setColor(const QColor &color)
+{
+ if (color_ == color)
+ return;
+
+ color_ = color;
+ emit colorChanged(color_);
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeMapLineProperties::width() const
+{
+ return width_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeMapLineProperties::setWidth(qreal width)
+{
+ if (width_ == width)
+ return;
+
+ width_ = width;
+ emit widthChanged(width_);
+}
+
+struct Vertex
+{
+ QVector2D position;
+};
+
+QGeoMapPolylineGeometry::QGeoMapPolylineGeometry()
+{
+}
+
+QList<QList<QDoubleVector2D> > QGeoMapPolylineGeometry::clipPath(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ QDoubleVector2D &leftBoundWrapped)
+{
+ /*
+ * Approach:
+ * 1) project coordinates to wrapped web mercator, and do unwrapBelowX
+ * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons)
+ * 2.1) recalculate the origin and geoLeftBound to prevent these parameters from ending in unprojectable areas
+ * 2.2) ensure the left bound does not wrap around due to QGeoCoordinate <-> clipper conversions
+ */
+
+ srcOrigin_ = geoLeftBound_;
+
+ double unwrapBelowX = 0;
+ leftBoundWrapped = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(geoLeftBound_));
+ if (preserveGeometry_)
+ unwrapBelowX = leftBoundWrapped.x();
+
+ QList<QDoubleVector2D> wrappedPath;
+ wrappedPath.reserve(path.size());
+ QDoubleVector2D wrappedLeftBound(qInf(), qInf());
+ // 1)
+ for (int i = 0; i < path.size(); ++i) {
+ const QGeoCoordinate &coord = path.at(i);
+ if (!coord.isValid())
+ continue;
+
+ QDoubleVector2D wrappedProjection = map.geoProjection().wrapMapProjection(map.geoProjection().geoToMapProjection(coord));
+
+ // We can get NaN if the map isn't set up correctly, or the projection
+ // is faulty -- probably best thing to do is abort
+ if (!qIsFinite(wrappedProjection.x()) || !qIsFinite(wrappedProjection.y()))
+ return QList<QList<QDoubleVector2D> >();
+
+ const bool isPointLessThanUnwrapBelowX = (wrappedProjection.x() < leftBoundWrapped.x());
+ // unwrap x to preserve geometry if moved to border of map
+ if (preserveGeometry_ && isPointLessThanUnwrapBelowX) {
+ double distance = wrappedProjection.x() - unwrapBelowX;
+ if (distance < 0.0)
+ distance += 1.0;
+ wrappedProjection.setX(unwrapBelowX + distance);
+ }
+ if (wrappedProjection.x() < wrappedLeftBound.x() || (wrappedProjection.x() == wrappedLeftBound.x() && wrappedProjection.y() < wrappedLeftBound.y())) {
+ wrappedLeftBound = wrappedProjection;
+ }
+ wrappedPath.append(wrappedProjection);
+ }
+
+ // 2)
+ QList<QList<QDoubleVector2D> > clippedPaths;
+ const QList<QDoubleVector2D> &visibleRegion = map.geoProjection().visibleRegion();
+ if (visibleRegion.size()) {
+ c2t::clip2tri clipper;
+ clipper.addSubjectPath(QClipperUtils::qListToPath(wrappedPath), false);
+ clipper.addClipPolygon(QClipperUtils::qListToPath(visibleRegion));
+ Paths res = clipper.execute(c2t::clip2tri::Intersection);
+ clippedPaths = QClipperUtils::pathsToQList(res);
+
+ // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X
+ QDoubleVector2D lb(qInf(), qInf());
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ for (const QDoubleVector2D &p: path) {
+ if (p == leftBoundWrapped) {
+ lb = p;
+ break;
+ } else if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y())) {
+ // y-minimization needed to find the same point on polygon and border
+ lb = p;
+ }
+ }
+ }
+ if (qIsInf(lb.x()))
+ return QList<QList<QDoubleVector2D> >();
+
+ // 2.2) Prevent the conversion to and from clipper from introducing negative offsets which
+ // in turn will make the geometry wrap around.
+ lb.setX(qMax(wrappedLeftBound.x(), lb.x()));
+ leftBoundWrapped = lb;
+ } else {
+ clippedPaths.append(wrappedPath);
+ }
+
+ return clippedPaths;
+}
+
+void QGeoMapPolylineGeometry::pathToScreen(const QGeoMap &map,
+ const QList<QList<QDoubleVector2D> > &clippedPaths,
+ const QDoubleVector2D &leftBoundWrapped)
+{
+ // 3) project the resulting geometry to screen position and calculate screen bounds
+ double minX = qInf();
+ double minY = qInf();
+ double maxX = -qInf();
+ double maxY = -qInf();
+
+ srcOrigin_ = map.geoProjection().mapProjectionToGeo(map.geoProjection().unwrapMapProjection(leftBoundWrapped));
+ QDoubleVector2D origin = map.geoProjection().wrappedMapProjectionToItemPosition(leftBoundWrapped);
+ for (const QList<QDoubleVector2D> &path: clippedPaths) {
+ QDoubleVector2D lastAddedPoint;
+ for (int i = 0; i < path.size(); ++i) {
+ QDoubleVector2D point = map.geoProjection().wrappedMapProjectionToItemPosition(path.at(i));
+
+ point = point - origin; // (0,0) if point == geoLeftBound_
+
+ minX = qMin(point.x(), minX);
+ minY = qMin(point.y(), minY);
+ maxX = qMax(point.x(), maxX);
+ maxY = qMax(point.y(), maxY);
+
+ if (i == 0) {
+ srcPoints_ << point.x() << point.y();
+ srcPointTypes_ << QPainterPath::MoveToElement;
+ lastAddedPoint = point;
+ } else {
+ if ((point - lastAddedPoint).manhattanLength() > 3 ||
+ i == path.size() - 1) {
+ srcPoints_ << point.x() << point.y();
+ srcPointTypes_ << QPainterPath::LineToElement;
+ lastAddedPoint = point;
+ }
+ }
+ }
+ }
+
+ sourceBounds_ = QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
+}
+
+/*!
+ \internal
+*/
+void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ const QGeoCoordinate geoLeftBound)
+{
+ if (!sourceDirty_)
+ return;
+
+ geoLeftBound_ = geoLeftBound;
+
+ // clear the old data and reserve enough memory
+ srcPoints_.clear();
+ srcPoints_.reserve(path.size() * 2);
+ srcPointTypes_.clear();
+ srcPointTypes_.reserve(path.size());
+
+ /*
+ * Approach:
+ * 1) project coordinates to wrapped web mercator, and do unwrapBelowX
+ * 2) if the scene is tilted, clip the geometry against the visible region (this may generate multiple polygons)
+ * 3) project the resulting geometry to screen position and calculate screen bounds
+ */
+
+ QDoubleVector2D leftBoundWrapped;
+ // 1, 2)
+ const QList<QList<QDoubleVector2D> > &clippedPaths = clipPath(map, path, leftBoundWrapped);
+
+ // 3)
+ pathToScreen(map, clippedPaths, leftBoundWrapped);
+}
+
+////////////////////////////////////////////////////////////////////////////
+#if 0 // Old polyline to viewport clipping code. Retaining it for now.
+/* Polyline clip */
+
+enum ClipPointType {
+ InsidePoint = 0x00,
+ LeftPoint = 0x01,
+ RightPoint = 0x02,
+ BottomPoint = 0x04,
+ TopPoint = 0x08
+};
+
+static inline int clipPointType(qreal x, qreal y, const QRectF &rect)
+{
+ int type = InsidePoint;
+ if (x < rect.left())
+ type |= LeftPoint;
+ else if (x > rect.right())
+ type |= RightPoint;
+ if (y < rect.top())
+ type |= TopPoint;
+ else if (y > rect.bottom())
+ type |= BottomPoint;
+ return type;
+}
+
+static void clipSegmentToRect(qreal x0, qreal y0, qreal x1, qreal y1,
+ const QRectF &clipRect,
+ QVector<qreal> &outPoints,
+ QVector<QPainterPath::ElementType> &outTypes)
+{
+ int type0 = clipPointType(x0, y0, clipRect);
+ int type1 = clipPointType(x1, y1, clipRect);
+ bool accept = false;
+
+ while (true) {
+ if (!(type0 | type1)) {
+ accept = true;
+ break;
+ } else if (type0 & type1) {
+ break;
+ } else {
+ qreal x = 0.0;
+ qreal y = 0.0;
+ int outsideType = type0 ? type0 : type1;
+
+ if (outsideType & BottomPoint) {
+ x = x0 + (x1 - x0) * (clipRect.bottom() - y0) / (y1 - y0);
+ y = clipRect.bottom() - 0.1;
+ } else if (outsideType & TopPoint) {
+ x = x0 + (x1 - x0) * (clipRect.top() - y0) / (y1 - y0);
+ y = clipRect.top() + 0.1;
+ } else if (outsideType & RightPoint) {
+ y = y0 + (y1 - y0) * (clipRect.right() - x0) / (x1 - x0);
+ x = clipRect.right() - 0.1;
+ } else if (outsideType & LeftPoint) {
+ y = y0 + (y1 - y0) * (clipRect.left() - x0) / (x1 - x0);
+ x = clipRect.left() + 0.1;
+ }
+
+ if (outsideType == type0) {
+ x0 = x;
+ y0 = y;
+ type0 = clipPointType(x0, y0, clipRect);
+ } else {
+ x1 = x;
+ y1 = y;
+ type1 = clipPointType(x1, y1, clipRect);
+ }
+ }
+ }
+
+ if (accept) {
+ if (outPoints.size() >= 2) {
+ qreal lastX, lastY;
+ lastY = outPoints.at(outPoints.size() - 1);
+ lastX = outPoints.at(outPoints.size() - 2);
+
+ if (!qFuzzyCompare(lastY, y0) || !qFuzzyCompare(lastX, x0)) {
+ outTypes << QPainterPath::MoveToElement;
+ outPoints << x0 << y0;
+ }
+ } else {
+ outTypes << QPainterPath::MoveToElement;
+ outPoints << x0 << y0;
+ }
+
+ outTypes << QPainterPath::LineToElement;
+ outPoints << x1 << y1;
+ }
+}
+
+static void clipPathToRect(const QVector<qreal> &points,
+ const QVector<QPainterPath::ElementType> &types,
+ const QRectF &clipRect,
+ QVector<qreal> &outPoints,
+ QVector<QPainterPath::ElementType> &outTypes)
+{
+ outPoints.clear();
+ outPoints.reserve(points.size());
+ outTypes.clear();
+ outTypes.reserve(types.size());
+
+ qreal lastX, lastY;
+ for (int i = 0; i < types.size(); ++i) {
+ if (i > 0 && types[i] != QPainterPath::MoveToElement) {
+ qreal x = points[i * 2], y = points[i * 2 + 1];
+ clipSegmentToRect(lastX, lastY, x, y, clipRect, outPoints, outTypes);
+ }
+
+ lastX = points[i * 2];
+ lastY = points[i * 2 + 1];
+ }
+}
+#endif
+/*!
+ \internal
+*/
+void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
+ qreal strokeWidth)
+{
+ if (!screenDirty_)
+ return;
+
+ QPointF origin = map.geoProjection().coordinateToItemPosition(srcOrigin_, false).toPointF();
+
+ if (!qIsFinite(origin.x()) || !qIsFinite(origin.y()) || srcPointTypes_.size() < 2) { // the line might have been clipped away.
+ clear();
+ return;
+ }
+
+ // Create the viewport rect in the same coordinate system
+ // as the actual points
+ QRectF viewport(0, 0, map.viewportWidth(), map.viewportHeight());
+ viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth, strokeWidth);
+ viewport.translate(-1 * origin);
+
+ // The geometry has already been clipped against the visible region projection in wrapped mercator space.
+ QVector<qreal> points = srcPoints_;
+ QVector<QPainterPath::ElementType> types = srcPointTypes_;
+
+ QVectorPath vp(points.data(), types.size(), types.data());
+ QTriangulatingStroker ts;
+ // viewport is not used in the call below.
+ ts.process(vp, QPen(QBrush(Qt::black), strokeWidth), viewport, QPainter::Qt4CompatiblePainting);
+
+ clear();
+
+ // Nothing is on the screen
+ if (ts.vertexCount() == 0)
+ return;
+
+ // QTriangulatingStroker#vertexCount is actually the length of the array,
+ // not the number of vertices
+ screenVertices_.reserve(ts.vertexCount());
+
+ QRectF bb;
+
+ QPointF pt;
+ const float *vs = ts.vertices();
+ for (int i = 0; i < (ts.vertexCount()/2*2); i += 2) {
+ pt = QPointF(vs[i], vs[i + 1]);
+ screenVertices_ << pt;
+
+ if (!qIsFinite(pt.x()) || !qIsFinite(pt.y()))
+ break;
+
+ if (!bb.contains(pt)) {
+ if (pt.x() < bb.left())
+ bb.setLeft(pt.x());
+
+ if (pt.x() > bb.right())
+ bb.setRight(pt.x());
+
+ if (pt.y() < bb.top())
+ bb.setTop(pt.y());
+
+ if (pt.y() > bb.bottom())
+ bb.setBottom(pt.y());
+ }
+ }
+
+ screenBounds_ = bb;
+ this->translate( -1 * sourceBounds_.topLeft());
+}
+
+QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), dirtyMaterial_(true), updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ QObject::connect(&line_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(updateAfterLinePropertiesChanged()));
+ QObject::connect(&line_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(updateAfterLinePropertiesChanged()));
+}
+
+QDeclarativePolylineMapItem::~QDeclarativePolylineMapItem()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged()
+{
+ // mark dirty just in case we're a width change
+ geometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map) {
+ geometry_.markSourceDirty();
+ polishAndUpdate();
+ }
+}
+
+/*!
+ \qmlproperty list<coordinate> MapPolyline::path
+
+ This property holds the ordered list of coordinates which
+ define the polyline.
+*/
+
+QJSValue QDeclarativePolylineMapItem::path() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(this);
+ QQmlEngine *engine = context->engine();
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::ArrayObject> pathArray(scope, v4->newArrayObject(geopath_.path().length()));
+ for (int i = 0; i < geopath_.path().length(); ++i) {
+ const QGeoCoordinate &c = geopath_.coordinateAt(i);
+
+ QV4::ScopedValue cv(scope, v4->fromVariant(QVariant::fromValue(c)));
+ pathArray->putIndexed(i, cv);
+ }
+
+ return QJSValue(v4, pathArray.asReturnedValue());
+}
+
+void QDeclarativePolylineMapItem::setPath(const QJSValue &value)
+{
+ if (!value.isArray())
+ return;
+
+ QList<QGeoCoordinate> pathList;
+ quint32 length = value.property(QStringLiteral("length")).toUInt();
+ for (quint32 i = 0; i < length; ++i) {
+ bool ok;
+ QGeoCoordinate c = parseCoordinate(value.property(i), &ok);
+
+ if (!ok || !c.isValid()) {
+ qmlWarning(this) << "Unsupported path type";
+ return;
+ }
+
+ pathList.append(c);
+ }
+
+ setPathFromGeoList(pathList);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::setPathFromGeoList(const QList<QGeoCoordinate> &path)
+{
+ if (geopath_.path() == path)
+ return;
+
+ geopath_.setPath(path);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod int MapPolyline::pathLength()
+
+ Returns the number of coordinates of the polyline.
+
+ \since Qt Location 5.6
+
+ \sa path
+*/
+int QDeclarativePolylineMapItem::pathLength() const
+{
+ return geopath_.path().length();
+}
+
+/*!
+ \qmlmethod void MapPolyline::addCoordinate(coordinate)
+
+ Adds a coordinate to the end of the path.
+
+ \sa insertCoordinate, removeCoordinate, path
+*/
+void QDeclarativePolylineMapItem::addCoordinate(const QGeoCoordinate &coordinate)
+{
+ geopath_.addCoordinate(coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolyline::insertCoordinate(index, coordinate)
+
+ Inserts a \a coordinate to the path at the given \a index.
+
+ \since Qt Location 5.6
+
+ \sa addCoordinate, removeCoordinate, path
+*/
+void QDeclarativePolylineMapItem::insertCoordinate(int index, const QGeoCoordinate &coordinate)
+{
+ if (index < 0 || index > geopath_.path().length())
+ return;
+
+ geopath_.insertCoordinate(index, coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolyline::replaceCoordinate(index, coordinate)
+
+ Replaces the coordinate in the current path at the given \a index
+ with the new \a coordinate.
+
+ \since Qt Location 5.6
+
+ \sa addCoordinate, insertCoordinate, removeCoordinate, path
+*/
+void QDeclarativePolylineMapItem::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
+{
+ if (index < 0 || index >= geopath_.path().length())
+ return;
+
+ geopath_.replaceCoordinate(index, coordinate);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod coordinate MapPolyline::coordinateAt(index)
+
+ Gets the coordinate of the polyline at the given \a index.
+ If the index is outside the path's bounds then an invalid
+ coordinate is returned.
+
+ \since Qt Location 5.6
+*/
+QGeoCoordinate QDeclarativePolylineMapItem::coordinateAt(int index) const
+{
+ if (index < 0 || index >= geopath_.path().length())
+ return QGeoCoordinate();
+
+ return geopath_.coordinateAt(index);
+}
+
+/*!
+ \qmlmethod coordinate MapPolyline::containsCoordinate(coordinate)
+
+ Returns true if the given \a coordinate is part of the path.
+
+ \since Qt Location 5.6
+*/
+bool QDeclarativePolylineMapItem::containsCoordinate(const QGeoCoordinate &coordinate)
+{
+ return geopath_.containsCoordinate(coordinate);
+}
+
+/*!
+ \qmlmethod void MapPolyline::removeCoordinate(coordinate)
+
+ Removes \a coordinate from the path. If there are multiple instances of the
+ same coordinate, the one added last is removed.
+
+ If \a coordinate is not in the path this method does nothing.
+
+ \sa addCoordinate, insertCoordinate, path
+*/
+void QDeclarativePolylineMapItem::removeCoordinate(const QGeoCoordinate &coordinate)
+{
+ int length = geopath_.path().length();
+ geopath_.removeCoordinate(coordinate);
+ if (geopath_.path().length() == length)
+ return;
+ geometry_.markSourceDirty();
+ polishAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlmethod void MapPolyline::removeCoordinate(index)
+
+ Removes a coordinate from the path at the given \a index.
+
+ If \a index is invalid then this method does nothing.
+
+ \since Qt Location 5.6
+
+ \sa addCoordinate, insertCoordinate, path
+*/
+void QDeclarativePolylineMapItem::removeCoordinate(int index)
+{
+ if (index < 0 || index >= geopath_.path().length())
+ return;
+
+ geopath_.removeCoordinate(index);
+
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+}
+
+/*!
+ \qmlpropertygroup Location::MapPolyline::line
+ \qmlproperty int MapPolyline::line.width
+ \qmlproperty color MapPolyline::line.color
+
+ This property is part of the line property group. The line
+ property group holds the width and color used to draw the line.
+
+ The width is in pixels and is independent of the zoom level of the map.
+ The default values correspond to a black border with a width of 1 pixel.
+
+ For no line, use a width of 0 or a transparent color.
+*/
+
+QDeclarativeMapLineProperties *QDeclarativePolylineMapItem::line()
+{
+ return &line_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+ // TODO: change the algorithm to preserve the distances and size!
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
+
+ geopath_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
+ markSourceDirtyAndUpdate();
+ emit pathChanged();
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ return;
+
+ geometry_.setPreserveGeometry(true, geometry_.geoLeftBound());
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePolylineMapItem::updatePolish()
+{
+ if (!map() || geopath_.path().length() == 0)
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ geometry_.updateSourcePoints(*map(), geopath_.path(), geopath_.boundingGeoRectangle().topLeft());
+ geometry_.updateScreenPoints(*map(), line_.width());
+
+ setWidth(geometry_.sourceBoundingBox().width());
+ setHeight(geometry_.sourceBoundingBox().height());
+
+ setPositionOnMap(geometry_.origin(), -1 * geometry_.sourceBoundingBox().topLeft());
+}
+
+void QDeclarativePolylineMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativePolylineMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+
+ MapPolylineNode *node = static_cast<MapPolylineNode *>(oldNode);
+
+ if (!node) {
+ node = new MapPolylineNode();
+ }
+
+ //TODO: update only material
+ if (geometry_.isScreenDirty() || dirtyMaterial_ || !oldNode) {
+ node->update(line_.color(), &geometry_);
+ geometry_.setPreserveGeometry(false);
+ geometry_.markClean();
+ dirtyMaterial_ = false;
+ }
+ return node;
+}
+
+bool QDeclarativePolylineMapItem::contains(const QPointF &point) const
+{
+ QVector<QPointF> vertices = geometry_.vertices();
+ QPolygonF tri;
+ for (int i = 0; i < vertices.size(); ++i) {
+ tri << vertices[i];
+ if (tri.size() == 3) {
+ if (tri.containsPoint(point,Qt::OddEvenFill))
+ return true;
+ tri.remove(0);
+ }
+ }
+
+ return false;
+}
+
+const QGeoShape &QDeclarativePolylineMapItem::geoShape() const
+{
+ return geopath_;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+/*!
+ \internal
+*/
+MapPolylineNode::MapPolylineNode() :
+ geometry_(QSGGeometry::defaultAttributes_Point2D(),0),
+ blocked_(true)
+{
+ geometry_.setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ QSGGeometryNode::setMaterial(&fill_material_);
+ QSGGeometryNode::setGeometry(&geometry_);
+}
+
+
+/*!
+ \internal
+*/
+MapPolylineNode::~MapPolylineNode()
+{
+}
+
+/*!
+ \internal
+*/
+bool MapPolylineNode::isSubtreeBlocked() const
+{
+ return blocked_;
+}
+
+/*!
+ \internal
+*/
+void MapPolylineNode::update(const QColor &fillColor,
+ const QGeoMapItemGeometry *shape)
+{
+ if (shape->size() == 0) {
+ blocked_ = true;
+ return;
+ } else {
+ blocked_ = false;
+ }
+
+ QSGGeometry *fill = QSGGeometryNode::geometry();
+ shape->allocateAndFill(fill);
+ markDirty(DirtyGeometry);
+
+ if (fillColor != fill_material_.color()) {
+ fill_material_.setColor(fillColor);
+ setMaterial(&fill_material_);
+ markDirty(DirtyMaterial);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
new file mode 100644
index 00000000..abc1df2f
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem_p.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPOLYLINEMAPITEM
+#define QDECLARATIVEPOLYLINEMAPITEM
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qgeomapitemgeometry_p.h>
+
+#include <QtPositioning/QGeoPath>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+
+QT_BEGIN_NAMESPACE
+
+class MapPolylineNode;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeMapLineProperties : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+
+public:
+ explicit QDeclarativeMapLineProperties(QObject *parent = 0);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ qreal width() const;
+ void setWidth(qreal width);
+
+Q_SIGNALS:
+ void widthChanged(qreal width);
+ void colorChanged(const QColor &color);
+
+private:
+ qreal width_;
+ QColor color_;
+};
+
+class QGeoMapPolylineGeometry : public QGeoMapItemGeometry
+{
+public:
+ QGeoMapPolylineGeometry();
+
+ void updateSourcePoints(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ const QGeoCoordinate geoLeftBound);
+
+ void updateScreenPoints(const QGeoMap &map,
+ qreal strokeWidth);
+
+protected:
+ QList<QList<QDoubleVector2D> > clipPath(const QGeoMap &map,
+ const QList<QGeoCoordinate> &path,
+ QDoubleVector2D &leftBoundWrapped);
+
+ void pathToScreen(const QGeoMap &map,
+ const QList<QList<QDoubleVector2D> > &clippedPaths,
+ const QDoubleVector2D &leftBoundWrapped);
+
+private:
+ QVector<qreal> srcPoints_;
+ QVector<QPainterPath::ElementType> srcPointTypes_;
+
+ friend class QDeclarativeCircleMapItem;
+ friend class QDeclarativePolygonMapItem;
+ friend class QDeclarativeRectangleMapItem;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePolylineMapItem : public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QJSValue path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QDeclarativeMapLineProperties *line READ line CONSTANT)
+
+public:
+ explicit QDeclarativePolylineMapItem(QQuickItem *parent = 0);
+ ~QDeclarativePolylineMapItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+ //from QuickItem
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+
+ Q_INVOKABLE int pathLength() const;
+ Q_INVOKABLE void addCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void insertCoordinate(int index, const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void replaceCoordinate(int index, const QGeoCoordinate &coordinate);
+ Q_INVOKABLE QGeoCoordinate coordinateAt(int index) const;
+ Q_INVOKABLE bool containsCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void removeCoordinate(const QGeoCoordinate &coordinate);
+ Q_INVOKABLE void removeCoordinate(int index);
+
+ QJSValue path() const;
+ virtual void setPath(const QJSValue &value);
+
+ bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+ QDeclarativeMapLineProperties *line();
+
+Q_SIGNALS:
+ void pathChanged();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void setPathFromGeoList(const QList<QGeoCoordinate> &path);
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
+ void updateAfterLinePropertiesChanged();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ void pathPropertyChanged();
+
+ QGeoPath geopath_;
+ QDeclarativeMapLineProperties line_;
+ QColor color_;
+ bool dirtyMaterial_;
+ QGeoMapPolylineGeometry geometry_;
+ bool updatingGeometry_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class MapPolylineNode : public QSGGeometryNode
+{
+
+public:
+ MapPolylineNode();
+ ~MapPolylineNode();
+
+ void update(const QColor &fillColor, const QGeoMapItemGeometry *shape);
+ bool isSubtreeBlocked() const;
+
+private:
+ QSGFlatColorMaterial fill_material_;
+ QSGGeometry geometry_;
+ bool blocked_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeMapLineProperties)
+QML_DECLARE_TYPE(QDeclarativePolylineMapItem)
+
+#endif /* QDECLARATIVEPOLYLINEMAPITEM_H_ */
diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
new file mode 100644
index 00000000..8abd58dd
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativerectanglemapitem_p.h"
+#include "qdeclarativepolygonmapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qlocationutils_p.h"
+#include <QPainterPath>
+#include <qnumeric.h>
+#include <QRectF>
+#include <QPointF>
+#include <QtLocation/private/qgeomap_p.h>
+#include <QtPositioning/private/qdoublevector2d_p.h>
+#include <QtCore/QScopedValueRollback>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapRectangle
+ \instantiates QDeclarativeRectangleMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.5
+
+ \brief The MapRectangle type displays a rectangle on a Map.
+
+ The MapRectangle type displays a rectangle on a Map. Rectangles are a
+ special case of Polygon with exactly 4 vertices and 4 "straight" edges. In
+ this case, "straight" means that the top-left point has the same latitude
+ as the top-right point (the top edge), and the bottom-left point has the
+ same latitude as the bottom-right point (the bottom edge). Similarly, the
+ points on the left side have the same longitude, and the points on the
+ right side have the same longitude.
+
+ To specify the rectangle, it requires a \l topLeft and \l bottomRight point,
+ both given by a \l {coordinate}.
+
+ By default, the rectangle is displayed with transparent fill and a 1-pixel
+ thick black border. This can be changed using the \l color, \l border.color
+ and \l border.width properties.
+
+ \note Similar to the \l MapPolygon type, MapRectangles are geographic
+ items, thus dragging a MapRectangle causes its vertices to be recalculated
+ in the geographic coordinate space. Apparent stretching of the item
+ occurs when dragged to the a different latitude, however, its edges
+ remain straight.
+
+ \section2 Performance
+
+ MapRectangles have a rendering cost identical to a MapPolygon with 4
+ vertices.
+
+ Like the other map objects, MapRectangle is normally drawn without a smooth
+ appearance. Setting the \l opacity property will force the object to be
+ blended, which decreases performance considerably depending on the hardware
+ in use.
+
+ \section2 Example Usage
+
+ The following snippet shows a map containing a MapRectangle, spanning
+ from (-27, 153) to (-28, 153.5), near Brisbane, Australia. The rectangle
+ is filled in green, with a 2 pixel black border.
+
+ \code
+ Map {
+ MapRectangle {
+ color: 'green'
+ border.width: 2
+ topLeft {
+ latitude: -27
+ longitude: 153
+ }
+ bottomRight {
+ latitude: -28
+ longitude: 153.5
+ }
+ }
+ }
+ \endcode
+
+ \image api-maprectangle.png
+*/
+
+QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent)
+: QDeclarativeGeoMapItemBase(parent), color_(Qt::transparent), dirtyMaterial_(true),
+ updatingGeometry_(false)
+{
+ setFlag(ItemHasContents, true);
+ QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
+ this, SLOT(markSourceDirtyAndUpdate()));
+ QObject::connect(&border_, SIGNAL(widthChanged(qreal)),
+ this, SLOT(markSourceDirtyAndUpdate()));
+}
+
+QDeclarativeRectangleMapItem::~QDeclarativeRectangleMapItem()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
+{
+ QDeclarativeGeoMapItemBase::setMap(quickMap,map);
+ if (map)
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \qmlpropertygroup Location::MapRectangle::border
+ \qmlproperty int MapRectangle::border.width
+ \qmlproperty color MapRectangle::border.color
+
+ This property is part of the border property group. The border property group
+ holds the width and color used to draw the border of the rectangle.
+ The width is in pixels and is independent of the zoom level of the map.
+
+ The default values correspond to a black border with a width of 1 pixel.
+ For no line, use a width of 0 or a transparent color.
+*/
+QDeclarativeMapLineProperties *QDeclarativeRectangleMapItem::border()
+{
+ return &border_;
+}
+
+/*!
+ \qmlproperty coordinate MapRectangle::topLeft
+
+ This property holds the top-left coordinate of the MapRectangle which
+ can be used to retrieve its longitude, latitude and altitude.
+*/
+void QDeclarativeRectangleMapItem::setTopLeft(const QGeoCoordinate &topLeft)
+{
+ if (rectangle_.topLeft() == topLeft)
+ return;
+
+ rectangle_.setTopLeft(topLeft);
+
+ markSourceDirtyAndUpdate();
+ emit topLeftChanged(topLeft);
+}
+
+QGeoCoordinate QDeclarativeRectangleMapItem::topLeft()
+{
+ return rectangle_.topLeft();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::markSourceDirtyAndUpdate()
+{
+ geometry_.markSourceDirty();
+ borderGeometry_.markSourceDirty();
+ polishAndUpdate();
+}
+
+/*!
+ \qmlproperty coordinate MapRectangle::bottomRight
+
+ This property holds the bottom-right coordinate of the MapRectangle which
+ can be used to retrieve its longitude, latitude and altitude.
+*/
+void QDeclarativeRectangleMapItem::setBottomRight(const QGeoCoordinate &bottomRight)
+{
+ if (rectangle_.bottomRight() == bottomRight)
+ return;
+
+ rectangle_.setBottomRight(bottomRight);
+
+ markSourceDirtyAndUpdate();
+ emit bottomRightChanged(bottomRight);
+}
+
+QGeoCoordinate QDeclarativeRectangleMapItem::bottomRight()
+{
+ return rectangle_.bottomRight();
+}
+
+/*!
+ \qmlproperty color MapRectangle::color
+
+ This property holds the fill color of the rectangle. For no fill, use
+ a transparent color.
+*/
+QColor QDeclarativeRectangleMapItem::color() const
+{
+ return color_;
+}
+
+void QDeclarativeRectangleMapItem::setColor(const QColor &color)
+{
+ if (color_ == color)
+ return;
+ color_ = color;
+ dirtyMaterial_ = true;
+ polishAndUpdate();
+ emit colorChanged(color_);
+}
+
+/*!
+ \qmlproperty real MapRectangle::opacity
+
+ This property holds the opacity of the item. Opacity is specified as a
+ number between 0 (fully transparent) and 1 (fully opaque). The default is 1.
+
+ An item with 0 opacity will still receive mouse events. To stop mouse events, set the
+ visible property of the item to false.
+*/
+
+/*!
+ \internal
+*/
+QSGNode *QDeclarativeRectangleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+
+ MapPolygonNode *node = static_cast<MapPolygonNode *>(oldNode);
+
+ if (!node) {
+ node = new MapPolygonNode();
+ }
+
+ //TODO: update only material
+ if (geometry_.isScreenDirty() || borderGeometry_.isScreenDirty() || dirtyMaterial_) {
+ node->update(color_, border_.color(), &geometry_, &borderGeometry_);
+ geometry_.setPreserveGeometry(false);
+ borderGeometry_.setPreserveGeometry(false);
+ geometry_.markClean();
+ borderGeometry_.markClean();
+ dirtyMaterial_ = false;
+ }
+ return node;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::updatePolish()
+{
+ if (!map() || !topLeft().isValid() || !bottomRight().isValid())
+ return;
+
+ QScopedValueRollback<bool> rollback(updatingGeometry_);
+ updatingGeometry_ = true;
+
+ QList<QGeoCoordinate> path;
+ path << rectangle_.topLeft();
+ path << QGeoCoordinate(rectangle_.topLeft().latitude(), rectangle_.bottomRight().longitude());
+ path << rectangle_.bottomRight();
+ path << QGeoCoordinate(rectangle_.bottomRight().latitude(), rectangle_.topLeft().longitude());
+
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ geometry_.updateSourcePoints(*map(), path);
+ geometry_.updateScreenPoints(*map());
+
+ QList<QGeoMapItemGeometry *> geoms;
+ geoms << &geometry_;
+ borderGeometry_.clear();
+
+ if (border_.color() != Qt::transparent && border_.width() > 0) {
+ QList<QGeoCoordinate> closedPath = path;
+ closedPath << closedPath.first();
+
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ const QGeoCoordinate &geometryOrigin = geometry_.origin();
+
+ borderGeometry_.srcPoints_.clear();
+ borderGeometry_.srcPointTypes_.clear();
+
+ QDoubleVector2D borderLeftBoundWrapped;
+ QList<QList<QDoubleVector2D > > clippedPaths = borderGeometry_.clipPath(*map(), closedPath, borderLeftBoundWrapped);
+ if (clippedPaths.size()) {
+ borderLeftBoundWrapped = map()->geoProjection().geoToWrappedMapProjection(geometryOrigin);
+ borderGeometry_.pathToScreen(*map(), clippedPaths, borderLeftBoundWrapped);
+ borderGeometry_.updateScreenPoints(*map(), border_.width());
+
+ geoms << &borderGeometry_;
+ } else {
+ borderGeometry_.clear();
+ }
+ }
+
+ QRectF combined = QGeoMapItemGeometry::translateToCommonOrigin(geoms);
+ setWidth(combined.width());
+ setHeight(combined.height());
+
+ setPositionOnMap(geometry_.origin(), geometry_.firstPointOffset());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
+{
+ if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
+ return;
+
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ markSourceDirtyAndUpdate();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeRectangleMapItem::contains(const QPointF &point) const
+{
+ return (geometry_.contains(point) || borderGeometry_.contains(point));
+}
+
+const QGeoShape &QDeclarativeRectangleMapItem::geoShape() const
+{
+ return rectangle_;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (updatingGeometry_ || newGeometry.topLeft() == oldGeometry.topLeft()) {
+ QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+ // TODO: change the algorithm to preserve the distances and size
+ QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()), false);
+ QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()), false);
+ if (!newCenter.isValid() || !oldCenter.isValid())
+ return;
+ double offsetLongi = newCenter.longitude() - oldCenter.longitude();
+ double offsetLati = newCenter.latitude() - oldCenter.latitude();
+ if (offsetLati == 0.0 && offsetLongi == 0.0)
+ return;
+
+ rectangle_.translate(offsetLati, offsetLongi);
+ geometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ borderGeometry_.setPreserveGeometry(true, rectangle_.topLeft());
+ markSourceDirtyAndUpdate();
+ emit topLeftChanged(rectangle_.topLeft());
+ emit bottomRightChanged(rectangle_.bottomRight());
+
+ // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
+ // call to this function.
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
new file mode 100644
index 00000000..6e6ea5b1
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativerectanglemapitem_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVERECTANGLEMAPITEM_H_
+#define QDECLARATIVERECTANGLEMAPITEM_H_
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qgeomapitemgeometry_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QtLocation/private/qdeclarativepolygonmapitem_p.h>
+
+#include <QSGGeometryNode>
+#include <QSGFlatColorMaterial>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRectangleMapItem: public QDeclarativeGeoMapItemBase
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QGeoCoordinate topLeft READ topLeft WRITE setTopLeft NOTIFY topLeftChanged)
+ Q_PROPERTY(QGeoCoordinate bottomRight READ bottomRight WRITE setBottomRight NOTIFY bottomRightChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QDeclarativeMapLineProperties *border READ border)
+
+public:
+ explicit QDeclarativeRectangleMapItem(QQuickItem *parent = 0);
+ ~QDeclarativeRectangleMapItem();
+
+ virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map) Q_DECL_OVERRIDE;
+ //from QuickItem
+ virtual QSGNode *updateMapItemPaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
+
+ QGeoCoordinate topLeft();
+ void setTopLeft(const QGeoCoordinate &center);
+
+ QGeoCoordinate bottomRight();
+ void setBottomRight(const QGeoCoordinate &center);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QDeclarativeMapLineProperties *border();
+
+ bool contains(const QPointF &point) const Q_DECL_OVERRIDE;
+ const QGeoShape &geoShape() const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void topLeftChanged(const QGeoCoordinate &topLeft);
+ void bottomRightChanged(const QGeoCoordinate &bottomRight);
+ void colorChanged(const QColor &color);
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void updatePolish() Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void markSourceDirtyAndUpdate();
+ virtual void afterViewportChanged(const QGeoMapViewportChangeEvent &event) Q_DECL_OVERRIDE;
+
+private:
+ QGeoRectangle rectangle_;
+ QDeclarativeMapLineProperties border_;
+ QColor color_;
+ bool dirtyMaterial_;
+ QGeoMapPolygonGeometry geometry_;
+ QGeoMapPolylineGeometry borderGeometry_;
+ bool updatingGeometry_;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeRectangleMapItem)
+
+#endif /* QDECLARATIVERECTANGLEMAPITEM_H_ */
diff --git a/src/location/declarativemaps/qdeclarativeroutemapitem.cpp b/src/location/declarativemaps/qdeclarativeroutemapitem.cpp
new file mode 100644
index 00000000..1fbeeeb7
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativeroutemapitem.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qdeclarativeroutemapitem_p.h"
+#include "qdeclarativepolylinemapitem_p.h"
+#include "qgeocameracapabilities_p.h"
+#include "qdeclarativegeoroute_p.h"
+
+#include <QtQml/QQmlInfo>
+#include <QtGui/QPainter>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MapRoute
+ \instantiates QDeclarativeRouteMapItem
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+
+ \brief The MapRoute type displays a Route on a Map.
+
+ The MapRoute type displays a Route obtained through a RouteModel or
+ other means, on the Map as a Polyline following the path of the Route.
+
+ MapRoute is really a \l MapPolyline, but with the path specified using the
+ \l route property instead of directly in \l {coordinate}{coordinates}.
+
+ By default, the route is displayed as a 1-pixel thick black line. This can
+ be changed using the \l line.width and \l line.color properties.
+
+ \section2 Performance
+
+ For notes about the performance on MapRoute, refer to the documentation for
+ \l MapPolyline.
+
+ \section2 Example Usage
+
+ Here is how to draw a \l{Route}{route} on a \l{Map}{map}:
+
+ \snippet declarative/maps.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/maps.qml MapRoute
+*/
+
+/*!
+ \qmlpropertygroup Location::MapRoute::line
+ \qmlproperty int MapRoute::line.width
+ \qmlproperty color MapRoute::line.color
+
+ This property is part of the line property group. The line
+ property group holds the width and color used to draw the line.
+
+ The width is in pixels and is independent of the zoom level of the map.
+ The default values correspond to a black border with a width of 1 pixel.
+
+ For no line, use a width of 0 or a transparent color.
+*/
+
+
+QDeclarativeRouteMapItem::QDeclarativeRouteMapItem(QQuickItem *parent)
+: QDeclarativePolylineMapItem(parent), route_(0)
+{
+ setFlag(ItemHasContents, true);
+}
+
+QDeclarativeRouteMapItem::~QDeclarativeRouteMapItem()
+{
+}
+
+/*!
+ \qmlproperty Route MapRoute::route
+
+ This property holds the route to be drawn which can be used
+ to represent one geographical route.
+*/
+QDeclarativeGeoRoute *QDeclarativeRouteMapItem::route() const
+{
+ return route_;
+}
+
+void QDeclarativeRouteMapItem::setRoute(QDeclarativeGeoRoute *route)
+{
+ if (route_ == route)
+ return;
+
+ route_ = route;
+
+ connect(route_, SIGNAL(pathChanged()), this, SLOT(updateRoutePath()));
+
+ if (route_)
+ setPathFromGeoList(route_->routePath());
+
+ emit routeChanged(route_);
+}
+
+void QDeclarativeRouteMapItem::updateRoutePath()
+{
+ setPathFromGeoList(route_->routePath());
+}
+
+/*!
+ \internal void QDeclarativeRouteMapItem::setPath(const QJSValue &value)
+
+ Used to disable path property on the RouteMapItem
+ */
+void QDeclarativeRouteMapItem::setPath(const QJSValue &value)
+{
+ Q_UNUSED(value);
+ qWarning() << "Can not set the path on QDeclarativeRouteMapItem."
+ << "Please use the route property instead.";
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qdeclarativeroutemapitem_p.h b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
new file mode 100644
index 00000000..ad959837
--- /dev/null
+++ b/src/location/declarativemaps/qdeclarativeroutemapitem_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEROUTEMAPITEM_H_
+#define QDECLARATIVEROUTEMAPITEM_H_
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeomapitembase_p.h>
+#include <QtLocation/private/qdeclarativegeomap_p.h>
+#include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
+#include <QPen>
+#include <QBrush>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGeoRoute;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRouteMapItem : public QDeclarativePolylineMapItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeGeoRoute *route READ route WRITE setRoute NOTIFY routeChanged)
+
+public:
+ explicit QDeclarativeRouteMapItem(QQuickItem *parent = 0);
+ ~QDeclarativeRouteMapItem();
+
+ QDeclarativeGeoRoute *route() const;
+ void setRoute(QDeclarativeGeoRoute *route);
+
+Q_SIGNALS:
+ void routeChanged(const QDeclarativeGeoRoute *route);
+
+private slots:
+ void updateRoutePath();
+
+protected:
+ void setPath(const QJSValue &value) Q_DECL_OVERRIDE;
+
+private:
+ QDeclarativeGeoRoute *route_;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeRouteMapItem)
+
+#endif /* QDECLARATIVEROUTEMAPITEM_H_ */
diff --git a/src/location/declarativemaps/qgeomapitemgeometry.cpp b/src/location/declarativemaps/qgeomapitemgeometry.cpp
new file mode 100644
index 00000000..80f3e218
--- /dev/null
+++ b/src/location/declarativemaps/qgeomapitemgeometry.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeomapitemgeometry_p.h"
+#include "qdeclarativegeomap_p.h"
+#include "qlocationutils_p.h"
+#include <QtQuick/QSGGeometry>
+#include "qdoublevector2d_p.h"
+#include <QtLocation/private/qgeomap_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QGeoMapItemGeometry::QGeoMapItemGeometry()
+: sourceDirty_(true), screenDirty_(true), clipToViewport_(true), preserveGeometry_(false)
+{
+}
+
+/*!
+ \internal
+*/
+void QGeoMapItemGeometry::translate(const QPointF &offset)
+{
+ for (int i = 0; i < screenVertices_.size(); ++i)
+ screenVertices_[i] += offset;
+
+ firstPointOffset_ += offset;
+ screenOutline_.translate(offset);
+ screenBounds_.translate(offset);
+}
+
+/*!
+ \internal
+*/
+void QGeoMapItemGeometry::allocateAndFill(QSGGeometry *geom) const
+{
+ const QVector<QPointF> &vx = screenVertices_;
+ const QVector<quint32> &ix = screenIndices_;
+
+ if (isIndexed()) {
+ geom->allocate(vx.size(), ix.size());
+ if (geom->indexType() == QSGGeometry::UnsignedShortType) {
+ quint16 *its = geom->indexDataAsUShort();
+ for (int i = 0; i < ix.size(); ++i)
+ its[i] = ix[i];
+ } else if (geom->indexType() == QSGGeometry::UnsignedIntType) {
+ quint32 *its = geom->indexDataAsUInt();
+ for (int i = 0; i < ix.size(); ++i)
+ its[i] = ix[i];
+ }
+ } else {
+ geom->allocate(vx.size());
+ }
+
+ QSGGeometry::Point2D *pts = geom->vertexDataAsPoint2D();
+ for (int i = 0; i < vx.size(); ++i)
+ pts[i].set(vx[i].x(), vx[i].y());
+}
+
+/*!
+ \internal
+*/
+QRectF QGeoMapItemGeometry::translateToCommonOrigin(const QList<QGeoMapItemGeometry *> &geoms)
+{
+ QGeoCoordinate origin = geoms.at(0)->origin();
+
+ QPainterPath brects;
+
+ // first get max offset
+ QPointF maxOffset = geoms.at(0)->firstPointOffset();
+ foreach (QGeoMapItemGeometry *g, geoms) {
+#ifndef QT_NO_DEBUG
+ //Q_ASSERT(g->origin() == origin); // this might fail on clipper clipping inaccuracies, so better to remove it in production
+ if (!qFuzzyCompare(origin.latitude(), g->origin().latitude())) {
+ qWarning("translateToCommonOrigin: Origins differ!");
+ }
+ if (!qFuzzyCompare(origin.longitude(), g->origin().longitude())) {
+ qWarning("translateToCommonOrigin: Origins differ!");
+ }
+#endif
+ QPointF o = g->firstPointOffset();
+ maxOffset.setX(qMax(o.x(), maxOffset.x()));
+ maxOffset.setY(qMax(o.y(), maxOffset.y()));
+ }
+
+ // then translate everything
+ foreach (QGeoMapItemGeometry *g, geoms) {
+ g->translate(maxOffset - g->firstPointOffset());
+ brects.addRect(g->sourceBoundingBox());
+ }
+
+ return brects.boundingRect();
+}
+
+/*!
+ \internal
+*/
+double QGeoMapItemGeometry::geoDistanceToScreenWidth(const QGeoMap &map,
+ const QGeoCoordinate &fromCoord,
+ const QGeoCoordinate &toCoord)
+{
+ // Do not wrap around half the globe
+ Q_ASSERT(!qFuzzyCompare(fromCoord.longitude(), toCoord.longitude()));
+
+ QGeoCoordinate mapMid = map.geoProjection().itemPositionToCoordinate(QDoubleVector2D(map.viewportWidth()/2.0, 0));
+ double halfGeoDist = toCoord.longitude() - fromCoord.longitude();
+ if (toCoord.longitude() < fromCoord.longitude())
+ halfGeoDist += 360;
+ halfGeoDist /= 2.0;
+ QGeoCoordinate geoDelta = QGeoCoordinate(0,
+ QLocationUtils::wrapLong(mapMid.longitude() + halfGeoDist));
+ QDoubleVector2D halfScreenDist = map.geoProjection().coordinateToItemPosition(geoDelta, false)
+ - QDoubleVector2D(map.viewportWidth()/2.0, 0);
+ return halfScreenDist.x() * 2.0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qgeomapitemgeometry_p.h b/src/location/declarativemaps/qgeomapitemgeometry_p.h
new file mode 100644
index 00000000..595107ae
--- /dev/null
+++ b/src/location/declarativemaps/qgeomapitemgeometry_p.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2015 The Qt Company Ltd.
+ ** Contact: http://www.qt.io/licensing/
+ **
+ ** This file is part of the QtLocation module of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:LGPL3$
+ ** Commercial License Usage
+ ** Licensees holding valid commercial Qt licenses may use this file in
+ ** accordance with the commercial license agreement provided with the
+ ** Software or, alternatively, in accordance with the terms contained in
+ ** a written agreement between you and The Qt Company. For licensing terms
+ ** and conditions see http://www.qt.io/terms-conditions. For further
+ ** information use the contact form at http://www.qt.io/contact-us.
+ **
+ ** GNU Lesser General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU Lesser
+ ** General Public License version 3 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU Lesser General Public License version 3 requirements
+ ** will be met: https://www.gnu.org/licenses/lgpl.html.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 2.0 or later as published by the Free
+ ** Software Foundation and appearing in the file LICENSE.GPL included in
+ ** the packaging of this file. Please review the following information to
+ ** ensure the GNU General Public License version 2.0 requirements will be
+ ** met: http://www.gnu.org/licenses/gpl-2.0.html.
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#ifndef QGEOMAPITEMGEOMETRY_H
+#define QGEOMAPITEMGEOMETRY_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QPainterPath>
+#include <QPointF>
+#include <QRectF>
+#include <QVector>
+#include <QGeoCoordinate>
+#include <QVector2D>
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+
+class QSGGeometry;
+class QGeoMap;
+
+class QGeoMapItemGeometry
+{
+public:
+ QGeoMapItemGeometry();
+
+ inline bool isSourceDirty() const { return sourceDirty_; }
+ inline bool isScreenDirty() const { return screenDirty_; }
+ inline void markSourceDirty() { sourceDirty_ = true; screenDirty_ = true; }
+ inline void markScreenDirty() { screenDirty_ = true; clipToViewport_ = true; }
+ inline void markFullScreenDirty() { screenDirty_ = true; clipToViewport_ = false;}
+ inline void markClean() { screenDirty_ = (sourceDirty_ = false); clipToViewport_ = true;}
+
+ inline void setPreserveGeometry(bool value, const QGeoCoordinate &geoLeftBound = QGeoCoordinate())
+ {
+ preserveGeometry_ = value;
+ if (preserveGeometry_)
+ geoLeftBound_ = geoLeftBound;
+ }
+ inline QGeoCoordinate geoLeftBound() { return geoLeftBound_; }
+
+ inline QRectF sourceBoundingBox() const { return sourceBounds_; }
+ inline QRectF screenBoundingBox() const { return screenBounds_; }
+
+ inline QPointF firstPointOffset() const { return firstPointOffset_; }
+ void translate(const QPointF &offset);
+
+ inline const QGeoCoordinate &origin() const { return srcOrigin_; }
+
+ inline bool contains(const QPointF &screenPoint) const {
+ return screenOutline_.contains(screenPoint);
+ }
+
+ inline QVector2D vertex(quint32 index) const {
+ return QVector2D(screenVertices_[index]);
+ }
+
+ inline QVector<QPointF> vertices() const { return screenVertices_; }
+ inline QVector<quint32> indices() const { return screenIndices_; }
+
+ inline bool isIndexed() const { return (!screenIndices_.isEmpty()); }
+
+ /* Size is # of triangles */
+ inline quint32 size() const
+ {
+ if (isIndexed())
+ return screenIndices_.size() / 3;
+ else
+ return screenVertices_.size() / 3;
+ }
+
+ inline void clear() { firstPointOffset_ = QPointF(0,0);
+ screenVertices_.clear(); screenIndices_.clear(); }
+
+ void allocateAndFill(QSGGeometry *geom) const;
+
+ double geoDistanceToScreenWidth(const QGeoMap &map,
+ const QGeoCoordinate &fromCoord,
+ const QGeoCoordinate &toCoord);
+
+ static QRectF translateToCommonOrigin(const QList<QGeoMapItemGeometry *> &geoms);
+
+
+protected:
+ bool sourceDirty_;
+ bool screenDirty_;
+ bool clipToViewport_;
+ bool preserveGeometry_;
+ QGeoCoordinate geoLeftBound_;
+
+ QPointF firstPointOffset_;
+
+ QPainterPath screenOutline_;
+
+ QRectF sourceBounds_;
+ QRectF screenBounds_;
+
+ QGeoCoordinate srcOrigin_;
+
+ QVector<QPointF> screenVertices_;
+ QVector<quint32> screenIndices_;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOMAPITEMGEOMETRY_H
diff --git a/src/location/declarativemaps/qquickgeomapgesturearea.cpp b/src/location/declarativemaps/qquickgeomapgesturearea.cpp
new file mode 100644
index 00000000..7b9a48f1
--- /dev/null
+++ b/src/location/declarativemaps/qquickgeomapgesturearea.cpp
@@ -0,0 +1,1288 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickgeomapgesturearea_p.h"
+#include "qquickgeocoordinateanimation_p.h"
+#include "qdeclarativegeomap_p.h"
+#include "error_messages.h"
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/qevent.h>
+#include <QtGui/QWheelEvent>
+#include <QtGui/QStyleHints>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/QQuickWindow>
+#include <QPropertyAnimation>
+#include <QDebug>
+#include "math.h"
+#include "qgeomap_p.h"
+#include "qdoublevector2d_p.h"
+
+#define QML_MAP_FLICK_DEFAULTMAXVELOCITY 2500
+#define QML_MAP_FLICK_MINIMUMDECELERATION 500
+#define QML_MAP_FLICK_DEFAULTDECELERATION 2500
+#define QML_MAP_FLICK_MAXIMUMDECELERATION 10000
+
+#define QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD 50
+// FlickThreshold determines how far the "mouse" must have moved
+// before we perform a flick.
+static const int FlickThreshold = 20;
+// Really slow flicks can be annoying.
+const qreal MinimumFlickVelocity = 75.0;
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \qmltype MapPinchEvent
+ \instantiates QGeoMapPinchEvent
+ \inqmlmodule QtLocation
+
+ \brief MapPinchEvent type provides basic information about pinch event.
+
+ MapPinchEvent type provides basic information about pinch event. They are
+ present in handlers of MapPinch (for example pinchStarted/pinchUpdated). Events are only
+ guaranteed to be valid for the duration of the handler.
+
+ Except for the \l accepted property, all properties are read-only.
+
+ \section2 Example Usage
+
+ The following example enables the pinch gesture on a map and reacts to the
+ finished event.
+
+ \code
+ Map {
+ id: map
+ gesture.enabled: true
+ gesture.onPinchFinished:{
+ var coordinate1 = map.toCoordinate(gesture.point1)
+ var coordinate2 = map.toCoordinate(gesture.point2)
+ console.log("Pinch started at:")
+ console.log(" Points (" + gesture.point1.x + ", " + gesture.point1.y + ") - (" + gesture.point2.x + ", " + gesture.point2.y + ")")
+ console.log(" Coordinates (" + coordinate1.latitude + ", " + coordinate1.longitude + ") - (" + coordinate2.latitude + ", " + coordinate2.longitude + ")")
+ }
+ }
+ \endcode
+
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+*/
+
+/*!
+ \qmlproperty QPoint QtLocation::MapPinchEvent::center
+
+ This read-only property holds the current center point.
+*/
+
+/*!
+ \qmlproperty real QtLocation::MapPinchEvent::angle
+
+ This read-only property holds the current angle between the two points in
+ the range -180 to 180. Positive values for the angles mean counter-clockwise
+ while negative values mean the clockwise direction. Zero degrees is at the
+ 3 o'clock position.
+*/
+
+/*!
+ \qmlproperty QPoint QtLocation::MapPinchEvent::point1
+ \qmlproperty QPoint QtLocation::MapPinchEvent::point2
+
+ These read-only properties hold the actual touch points generating the pinch.
+ The points are not in any particular order.
+*/
+
+/*!
+ \qmlproperty int QtLocation::MapPinchEvent::pointCount
+
+ This read-only property holds the number of points currently touched.
+ The MapPinch will not react until two touch points have initiated a gesture,
+ but will remain active until all touch points have been released.
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapPinchEvent::accepted
+
+ Setting this property to false in the \c MapPinch::onPinchStarted handler
+ will result in no further pinch events being generated, and the gesture
+ ignored.
+*/
+
+/*!
+ \qmltype MapGestureArea
+ \instantiates QQuickGeoMapGestureArea
+
+ \inqmlmodule QtLocation
+
+ \brief The MapGestureArea type provides Map gesture interaction.
+
+ MapGestureArea objects are used as part of a Map, to provide for panning,
+ flicking and pinch-to-zoom gesture used on touch displays.
+
+ A MapGestureArea is automatically created with a new Map and available with
+ the \l{Map::gesture}{gesture} property. This is the only way
+ to create a MapGestureArea, and once created this way cannot be destroyed
+ without its parent Map.
+
+ The two most commonly used properties of the MapGestureArea are the \l enabled
+ and \l acceptedGestures properties. Both of these must be set before a
+ MapGestureArea will have any effect upon interaction with the Map.
+ The \l flickDeceleration property controls how quickly the map pan slows after contact
+ is released while panning the map.
+
+ \section2 Performance
+
+ The MapGestureArea, when enabled, must process all incoming touch events in
+ order to track the shape and size of the "pinch". The overhead added on
+ touch events can be considered constant time.
+
+ \section2 Example Usage
+
+ The following example enables the pinch and pan gestures on the map, but not flicking. So the
+ map scrolling will halt immediately on releasing the mouse button / touch.
+
+ \code
+ Map {
+ gesture.enabled: true
+ gesture.acceptedGestures: MapGestureArea.PinchGesture | MapGestureArea.PanGesture
+ }
+ \endcode
+
+ \ingroup qml-QtLocation5-maps
+ \since Qt Location 5.0
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::enabled
+
+ This property holds whether the gestures are enabled.
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::pinchActive
+
+ This read-only property holds whether pinch gesture is active.
+*/
+
+/*!
+ \qmlproperty bool QtLocation::MapGestureArea::panActive
+
+ This read-only property holds whether pan gesture is active.
+
+ \note Change notifications for this property were introduced in Qt 5.5.
+*/
+
+/*!
+ \qmlproperty real QtLocation::MapGestureArea::maximumZoomLevelChange
+
+ This property holds the maximum zoom level change per pinch, essentially
+ meant to be used for setting the zoom sensitivity.
+
+ It is an indicative measure calculated from the dimensions of the
+ map area, roughly corresponding how much zoom level could change with
+ maximum pinch zoom. Default value is 4.0, maximum value is 10.0
+*/
+
+/*!
+ \qmlproperty real MapGestureArea::flickDeceleration
+
+ This property holds the rate at which a flick will decelerate.
+
+ The default value is 2500.
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::pinchStarted(PinchEvent event)
+
+ This signal is emitted when a pinch gesture is started.
+
+ The corresponding handler is \c onPinchStarted.
+
+ \sa pinchUpdated, pinchFinished
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::pinchUpdated(PinchEvent event)
+
+ This signal is emitted as the user's fingers move across the map,
+ after the \l pinchStarted signal is emitted.
+
+ The corresponding handler is \c onPinchUpdated.
+
+ \sa pinchStarted, pinchFinished
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::pinchFinished(PinchEvent event)
+
+ This signal is emitted at the end of a pinch gesture.
+
+ The corresponding handler is \c onPinchFinished.
+
+ \sa pinchStarted, pinchUpdated
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::panStarted()
+
+ This signal is emitted when the map begins to move due to user
+ interaction. Typically this means that the user is dragging a finger -
+ or a mouse with one of more mouse buttons pressed - on the map.
+
+ The corresponding handler is \c onPanStarted.
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::panFinished()
+
+ This signal is emitted when the map stops moving due to user
+ interaction. If a flick was generated, this signal is
+ emitted before flick starts. If a flick was not
+ generated, this signal is emitted when the
+ user stops dragging - that is a mouse or touch release.
+
+ The corresponding handler is \c onPanFinished.
+
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::flickStarted()
+
+ This signal is emitted when the map is flicked. A flick
+ starts from the point where the mouse or touch was released,
+ while still in motion.
+
+ The corresponding handler is \c onFlichStarted.
+*/
+
+/*!
+ \qmlsignal QtLocation::MapGestureArea::flickFinished()
+
+ This signal is emitted when the map stops moving due to a flick.
+
+ The corresponding handler is \c onFlickFinished.
+*/
+
+QQuickGeoMapGestureArea::QQuickGeoMapGestureArea(QDeclarativeGeoMap *map)
+ : QQuickItem(map),
+ m_map(0),
+ m_declarativeMap(map),
+ m_enabled(true),
+ m_acceptedGestures(PinchGesture | PanGesture | FlickGesture),
+ m_preventStealing(false),
+ m_panEnabled(true)
+{
+ m_flick.m_enabled = true,
+ m_flick.m_maxVelocity = QML_MAP_FLICK_DEFAULTMAXVELOCITY;
+ m_flick.m_deceleration = QML_MAP_FLICK_DEFAULTDECELERATION;
+ m_flick.m_animation = 0;
+ m_touchPointState = touchPoints0;
+ m_pinchState = pinchInactive;
+ m_flickState = flickInactive;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setMap(QGeoMap *map)
+{
+ if (m_map || !map)
+ return;
+
+ m_map = map;
+ m_flick.m_animation = new QQuickGeoCoordinateAnimation(this);
+ m_flick.m_animation->setTargetObject(m_declarativeMap);
+ m_flick.m_animation->setProperty(QStringLiteral("center"));
+ m_flick.m_animation->setEasing(QEasingCurve(QEasingCurve::OutQuad));
+ connect(m_flick.m_animation, &QQuickAbstractAnimation::stopped, this, &QQuickGeoMapGestureArea::handleFlickAnimationStopped);
+}
+
+/*!
+ \qmlproperty bool QtQuick::MapGestureArea::preventStealing
+ This property holds whether the mouse events may be stolen from this
+ MapGestureArea.
+
+ If a Map is placed within an item that filters child mouse
+ and touch events, such as Flickable, the mouse and touch events
+ may be stolen from the MapGestureArea if a gesture is recognized
+ by the parent item, e.g. a flick gesture. If preventStealing is
+ set to true, no item will steal the mouse and touch events.
+
+ Note that setting preventStealing to true once an item has started
+ stealing events will have no effect until the next press event.
+
+ By default this property is false.
+*/
+
+bool QQuickGeoMapGestureArea::preventStealing() const
+{
+ return m_preventStealing;
+}
+
+void QQuickGeoMapGestureArea::setPreventStealing(bool prevent)
+{
+ if (prevent != m_preventStealing) {
+ m_preventStealing = prevent;
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing && m_enabled);
+ m_declarativeMap->setKeepTouchGrab(m_preventStealing && m_enabled);
+ emit preventStealingChanged();
+ }
+}
+
+QQuickGeoMapGestureArea::~QQuickGeoMapGestureArea()
+{
+}
+
+/*!
+ \qmlproperty enumeration QtLocation::MapGestureArea::acceptedGestures
+
+ This property holds the gestures that will be active. By default
+ the zoom, pan and flick gestures are enabled.
+
+ \list
+ \li MapGestureArea.NoGesture - Don't support any additional gestures (value: 0x0000).
+ \li MapGestureArea.PinchGesture - Support the map pinch gesture (value: 0x0001).
+ \li MapGestureArea.PanGesture - Support the map pan gesture (value: 0x0002).
+ \li MapGestureArea.FlickGesture - Support the map flick gesture (value: 0x0004).
+ \endlist
+*/
+
+QQuickGeoMapGestureArea::AcceptedGestures QQuickGeoMapGestureArea::acceptedGestures() const
+{
+ return m_acceptedGestures;
+}
+
+
+void QQuickGeoMapGestureArea::setAcceptedGestures(AcceptedGestures acceptedGestures)
+{
+ if (acceptedGestures == m_acceptedGestures)
+ return;
+ m_acceptedGestures = acceptedGestures;
+
+ setPanEnabled(acceptedGestures & PanGesture);
+ setFlickEnabled(acceptedGestures & FlickGesture);
+ setPinchEnabled(acceptedGestures & PinchGesture);
+
+ emit acceptedGesturesChanged();
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::isPinchActive() const
+{
+ return m_pinchState == pinchActive;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::isPanActive() const
+{
+ return m_flickState == panActive || m_flickState == flickActive;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::enabled() const
+{
+ return m_enabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setEnabled(bool enabled)
+{
+ if (enabled == m_enabled)
+ return;
+ m_enabled = enabled;
+
+ if (enabled) {
+ setPanEnabled(m_acceptedGestures & PanGesture);
+ setFlickEnabled(m_acceptedGestures & FlickGesture);
+ setPinchEnabled(m_acceptedGestures & PinchGesture);
+ } else {
+ setPanEnabled(false);
+ setFlickEnabled(false);
+ setPinchEnabled(false);
+ }
+
+ emit enabledChanged();
+}
+
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::pinchEnabled() const
+{
+ return m_pinch.m_enabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setPinchEnabled(bool enabled)
+{
+ if (enabled == m_pinch.m_enabled)
+ return;
+ m_pinch.m_enabled = enabled;
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::panEnabled() const
+{
+ return m_panEnabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setPanEnabled(bool enabled)
+{
+ if (enabled == m_flick.m_enabled)
+ return;
+ m_panEnabled = enabled;
+
+ // unlike the pinch, the pan existing functionality is to stop immediately
+ if (!enabled)
+ stopPan();
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::flickEnabled() const
+{
+ return m_flick.m_enabled;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setFlickEnabled(bool enabled)
+{
+ if (enabled == m_flick.m_enabled)
+ return;
+ m_flick.m_enabled = enabled;
+ // unlike the pinch, the flick existing functionality is to stop immediately
+ if (!enabled) {
+ stopFlick();
+ }
+}
+
+/*!
+ \internal
+ Used internally to set the minimum zoom level of the gesture area.
+ The caller is responsible to only send values that are valid
+ for the map plugin. Negative values are ignored.
+ */
+void QQuickGeoMapGestureArea::setMinimumZoomLevel(qreal min)
+{
+ if (min >= 0)
+ m_pinch.m_zoom.m_minimum = min;
+}
+
+/*!
+ \internal
+ */
+qreal QQuickGeoMapGestureArea::minimumZoomLevel() const
+{
+ return m_pinch.m_zoom.m_minimum;
+}
+
+/*!
+ \internal
+ Used internally to set the maximum zoom level of the gesture area.
+ The caller is responsible to only send values that are valid
+ for the map plugin. Negative values are ignored.
+ */
+void QQuickGeoMapGestureArea::setMaximumZoomLevel(qreal max)
+{
+ if (max >= 0)
+ m_pinch.m_zoom.m_maximum = max;
+}
+
+/*!
+ \internal
+ */
+qreal QQuickGeoMapGestureArea::maximumZoomLevel() const
+{
+ return m_pinch.m_zoom.m_maximum;
+}
+
+/*!
+ \internal
+*/
+qreal QQuickGeoMapGestureArea::maximumZoomLevelChange() const
+{
+ return m_pinch.m_zoom.maximumChange;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setMaximumZoomLevelChange(qreal maxChange)
+{
+ if (maxChange == m_pinch.m_zoom.maximumChange || maxChange < 0.1 || maxChange > 10.0)
+ return;
+ m_pinch.m_zoom.maximumChange = maxChange;
+ emit maximumZoomLevelChangeChanged();
+}
+
+/*!
+ \internal
+*/
+qreal QQuickGeoMapGestureArea::flickDeceleration() const
+{
+ return m_flick.m_deceleration;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::setFlickDeceleration(qreal deceleration)
+{
+ if (deceleration < QML_MAP_FLICK_MINIMUMDECELERATION)
+ deceleration = QML_MAP_FLICK_MINIMUMDECELERATION;
+ else if (deceleration > QML_MAP_FLICK_MAXIMUMDECELERATION)
+ deceleration = QML_MAP_FLICK_MAXIMUMDECELERATION;
+ if (deceleration == m_flick.m_deceleration)
+ return;
+ m_flick.m_deceleration = deceleration;
+ emit flickDecelerationChanged();
+}
+
+/*!
+ \internal
+*/
+QTouchEvent::TouchPoint* createTouchPointFromMouseEvent(QMouseEvent *event, Qt::TouchPointState state)
+{
+ // this is only partially filled. But since it is only partially used it works
+ // more robust would be to store a list of QPointFs rather than TouchPoints
+ QTouchEvent::TouchPoint* newPoint = new QTouchEvent::TouchPoint();
+ newPoint->setPos(event->localPos());
+ newPoint->setScenePos(event->windowPos());
+ newPoint->setScreenPos(event->screenPos());
+ newPoint->setState(state);
+ newPoint->setId(0);
+ return newPoint;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleMousePressEvent(QMouseEvent *event)
+{
+ m_mousePoint.reset(createTouchPointFromMouseEvent(event, Qt::TouchPointPressed));
+ if (m_touchPoints.isEmpty()) update();
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleMouseMoveEvent(QMouseEvent *event)
+{
+ m_mousePoint.reset(createTouchPointFromMouseEvent(event, Qt::TouchPointMoved));
+ if (m_touchPoints.isEmpty()) update();
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleMouseReleaseEvent(QMouseEvent *event)
+{
+ if (!m_mousePoint.isNull()) {
+ //this looks super ugly , however is required in case we do not get synthesized MouseReleaseEvent
+ //and we reset the point already in handleTouchUngrabEvent
+ m_mousePoint.reset(createTouchPointFromMouseEvent(event, Qt::TouchPointReleased));
+ if (m_touchPoints.isEmpty()) update();
+ }
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleMouseUngrabEvent()
+{
+
+ if (m_touchPoints.isEmpty() && !m_mousePoint.isNull()) {
+ m_mousePoint.reset();
+ update();
+ } else {
+ m_mousePoint.reset();
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleTouchUngrabEvent()
+{
+ m_touchPoints.clear();
+ //this is needed since in some cases mouse release is not delivered
+ //(second touch point breaks mouse synthesized events)
+ m_mousePoint.reset();
+ update();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::handleTouchEvent(QTouchEvent *event)
+{
+ m_touchPoints.clear();
+ m_mousePoint.reset();
+
+ for (int i = 0; i < event->touchPoints().count(); ++i) {
+ auto point = event->touchPoints().at(i);
+ if (point.state() != Qt::TouchPointReleased)
+ m_touchPoints << point;
+ }
+ if (event->touchPoints().count() >= 2)
+ event->accept();
+ else
+ event->ignore();
+ update();
+}
+
+void QQuickGeoMapGestureArea::handleWheelEvent(QWheelEvent *event)
+{
+ if (!m_map)
+ return;
+
+ QGeoCoordinate wheelGeoPos = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(event->posF()), false);
+ QPointF preZoomPoint = m_map->geoProjection().coordinateToItemPosition(wheelGeoPos, false).toPointF();
+
+ double zoomLevelDelta = event->angleDelta().y() * qreal(0.001);
+ m_declarativeMap->setZoomLevel(m_declarativeMap->zoomLevel() + zoomLevelDelta);
+ QPointF postZoomPoint = m_map->geoProjection().coordinateToItemPosition(wheelGeoPos, false).toPointF();
+
+ if (preZoomPoint != postZoomPoint)
+ {
+ qreal dx = postZoomPoint.x() - preZoomPoint.x();
+ qreal dy = postZoomPoint.y() - preZoomPoint.y();
+ QPointF mapCenterPoint(m_map->viewportWidth() / 2.0 + dx, m_map->viewportHeight() / 2.0 + dy);
+
+ QGeoCoordinate mapCenterCoordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(mapCenterPoint), false);
+ m_declarativeMap->setCenter(mapCenterCoordinate);
+ }
+ event->accept();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::clearTouchData()
+{
+ m_velocityX = 0;
+ m_velocityY = 0;
+ m_sceneCenter.setX(0);
+ m_sceneCenter.setY(0);
+ m_touchCenterCoord.setLongitude(0);
+ m_touchCenterCoord.setLatitude(0);
+ m_startCoord.setLongitude(0);
+ m_startCoord.setLatitude(0);
+}
+
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateVelocityList(const QPointF &pos)
+{
+ // Take velocity samples every sufficient period of time, used later to determine the flick
+ // duration and speed (when mouse is released).
+ qreal elapsed = qreal(m_lastPosTime.elapsed());
+
+ if (elapsed >= QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD) {
+ elapsed /= 1000.;
+ int dyFromLastPos = pos.y() - m_lastPos.y();
+ int dxFromLastPos = pos.x() - m_lastPos.x();
+ m_lastPos = pos;
+ m_lastPosTime.restart();
+ qreal velX = qreal(dxFromLastPos) / elapsed;
+ qreal velY = qreal(dyFromLastPos) / elapsed;
+ m_velocityX = qBound<qreal>(-m_flick.m_maxVelocity, velX, m_flick.m_maxVelocity);
+ m_velocityY = qBound<qreal>(-m_flick.m_maxVelocity, velY, m_flick.m_maxVelocity);
+ }
+}
+
+/*!
+ \internal
+*/
+
+bool QQuickGeoMapGestureArea::isActive() const
+{
+ return isPanActive() || isPinchActive();
+}
+
+/*!
+ \internal
+*/
+// simplify the gestures by using a state-machine format (easy to move to a future state machine)
+void QQuickGeoMapGestureArea::update()
+{
+ if (!m_map)
+ return;
+
+ // First state machine is for the number of touch points
+
+ //combine touch with mouse event
+ m_allPoints.clear();
+ m_allPoints << m_touchPoints;
+ if (m_allPoints.isEmpty() && !m_mousePoint.isNull())
+ m_allPoints << *m_mousePoint.data();
+
+ touchPointStateMachine();
+
+ // Parallel state machine for pinch
+ if (isPinchActive() || (m_enabled && m_pinch.m_enabled && (m_acceptedGestures & (PinchGesture))))
+ pinchStateMachine();
+
+ // Parallel state machine for pan (since you can pan at the same time as pinching)
+ // The stopPan function ensures that pan stops immediately when disabled,
+ // but the line below allows pan continue its current gesture if you disable
+ // the whole gesture (enabled_ flag), this keeps the enabled_ consistent with the pinch
+ if (isPanActive() || (m_enabled && m_flick.m_enabled && (m_acceptedGestures & (PanGesture | FlickGesture))))
+ panStateMachine();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::touchPointStateMachine()
+{
+ // Transitions:
+ switch (m_touchPointState) {
+ case touchPoints0:
+ if (m_allPoints.count() == 1) {
+ clearTouchData();
+ startOneTouchPoint();
+ m_touchPointState = touchPoints1;
+ } else if (m_allPoints.count() >= 2) {
+ clearTouchData();
+ startTwoTouchPoints();
+ m_touchPointState = touchPoints2;
+ }
+ break;
+ case touchPoints1:
+ if (m_allPoints.count() == 0) {
+ m_touchPointState = touchPoints0;
+ } else if (m_allPoints.count() == 2) {
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ startTwoTouchPoints();
+ m_touchPointState = touchPoints2;
+ }
+ break;
+ case touchPoints2:
+ if (m_allPoints.count() == 0) {
+ m_touchPointState = touchPoints0;
+ } else if (m_allPoints.count() == 1) {
+ m_touchCenterCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ startOneTouchPoint();
+ m_touchPointState = touchPoints1;
+ }
+ break;
+ };
+
+ // Update
+ switch (m_touchPointState) {
+ case touchPoints0:
+ break; // do nothing if no touch points down
+ case touchPoints1:
+ updateOneTouchPoint();
+ break;
+ case touchPoints2:
+ updateTwoTouchPoints();
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startOneTouchPoint()
+{
+ m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_lastPos = m_sceneStartPoint1;
+ m_lastPosTime.start();
+ QGeoCoordinate startCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneStartPoint1), false);
+ // ensures a smooth transition for panning
+ m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() -
+ m_touchCenterCoord.longitude());
+ m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() -
+ m_touchCenterCoord.latitude());
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateOneTouchPoint()
+{
+ m_sceneCenter = mapFromScene(m_allPoints.at(0).scenePos());
+ updateVelocityList(m_sceneCenter);
+}
+
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startTwoTouchPoints()
+{
+ m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_sceneStartPoint2 = mapFromScene(m_allPoints.at(1).scenePos());
+ QPointF startPos = (m_sceneStartPoint1 + m_sceneStartPoint2) * 0.5;
+ m_lastPos = startPos;
+ m_lastPosTime.start();
+ QGeoCoordinate startCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(startPos), false);
+ m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() -
+ m_touchCenterCoord.longitude());
+ m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() -
+ m_touchCenterCoord.latitude());
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updateTwoTouchPoints()
+{
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ qreal dx = p1.x() - p2.x();
+ qreal dy = p1.y() - p2.y();
+ m_distanceBetweenTouchPoints = sqrt(dx * dx + dy * dy);
+ m_sceneCenter = (p1 + p2) / 2;
+ updateVelocityList(m_sceneCenter);
+
+ m_twoTouchAngle = QLineF(p1, p2).angle();
+ if (m_twoTouchAngle > 180)
+ m_twoTouchAngle -= 360;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::pinchStateMachine()
+{
+ PinchState lastState = m_pinchState;
+ // Transitions:
+ switch (m_pinchState) {
+ case pinchInactive:
+ if (m_allPoints.count() >= 2) {
+ if (canStartPinch()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startPinch();
+ m_pinchState = pinchActive;
+ } else {
+ m_pinchState = pinchInactiveTwoPoints;
+ }
+ }
+ break;
+ case pinchInactiveTwoPoints:
+ if (m_allPoints.count() <= 1) {
+ m_pinchState = pinchInactive;
+ } else {
+ if (canStartPinch()) {
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_declarativeMap->setKeepTouchGrab(true);
+ startPinch();
+ m_pinchState = pinchActive;
+ }
+ }
+ break;
+ case pinchActive:
+ if (m_allPoints.count() <= 1) {
+ m_pinchState = pinchInactive;
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_declarativeMap->setKeepTouchGrab(m_preventStealing);
+ endPinch();
+ }
+ break;
+ }
+ // This line implements an exclusive state machine, where the transitions and updates don't
+ // happen on the same frame
+ if (m_pinchState != lastState) {
+ emit pinchActiveChanged();
+ return;
+ }
+
+ // Update
+ switch (m_pinchState) {
+ case pinchInactive:
+ case pinchInactiveTwoPoints:
+ break; // do nothing
+ case pinchActive:
+ updatePinch();
+ break;
+ }
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::canStartPinch()
+{
+ const int startDragDistance = qApp->styleHints()->startDragDistance();
+
+ if (m_allPoints.count() >= 2) {
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ QPointF p2 = mapFromScene(m_allPoints.at(1).scenePos());
+ if (qAbs(p1.x()-m_sceneStartPoint1.x()) > startDragDistance
+ || qAbs(p1.y()-m_sceneStartPoint1.y()) > startDragDistance
+ || qAbs(p2.x()-m_sceneStartPoint2.x()) > startDragDistance
+ || qAbs(p2.y()-m_sceneStartPoint2.y()) > startDragDistance) {
+ m_pinch.m_event.setCenter(mapFromScene(m_sceneCenter));
+ m_pinch.m_event.setAngle(m_twoTouchAngle);
+ m_pinch.m_event.setPoint1(p1);
+ m_pinch.m_event.setPoint2(p2);
+ m_pinch.m_event.setPointCount(m_allPoints.count());
+ m_pinch.m_event.setAccepted(true);
+ emit pinchStarted(&m_pinch.m_event);
+ return m_pinch.m_event.accepted();
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startPinch()
+{
+ m_pinch.m_startDist = m_distanceBetweenTouchPoints;
+ m_pinch.m_zoom.m_previous = m_declarativeMap->zoomLevel();
+ m_pinch.m_lastAngle = m_twoTouchAngle;
+
+ m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePos());
+
+ m_pinch.m_zoom.m_start = m_declarativeMap->zoomLevel();
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updatePinch()
+{
+ // Calculate the new zoom level if we have distance ( >= 2 touchpoints), otherwise stick with old.
+ qreal newZoomLevel = m_pinch.m_zoom.m_previous;
+ if (m_distanceBetweenTouchPoints) {
+ newZoomLevel =
+ // How much further/closer the current touchpoints are (in pixels) compared to pinch start
+ ((m_distanceBetweenTouchPoints - m_pinch.m_startDist) *
+ // How much one pixel corresponds in units of zoomlevel (and multiply by above delta)
+ (m_pinch.m_zoom.maximumChange / ((width() + height()) / 2))) +
+ // Add to starting zoom level. Sign of (dist-pinchstartdist) takes care of zoom in / out
+ m_pinch.m_zoom.m_start;
+ }
+
+ m_pinch.m_event.setCenter(mapFromScene(m_sceneCenter));
+ m_pinch.m_event.setAngle(m_twoTouchAngle);
+
+ m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePos());
+ m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePos());
+ m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1);
+ m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2);
+ m_pinch.m_event.setPointCount(m_allPoints.count());
+ m_pinch.m_event.setAccepted(true);
+
+ m_pinch.m_lastAngle = m_twoTouchAngle;
+ emit pinchUpdated(&m_pinch.m_event);
+
+ if (m_acceptedGestures & PinchGesture) {
+ // Take maximum and minimumzoomlevel into account
+ qreal perPinchMinimumZoomLevel = qMax(m_pinch.m_zoom.m_start - m_pinch.m_zoom.maximumChange, m_pinch.m_zoom.m_minimum);
+ qreal perPinchMaximumZoomLevel = qMin(m_pinch.m_zoom.m_start + m_pinch.m_zoom.maximumChange, m_pinch.m_zoom.m_maximum);
+ newZoomLevel = qMin(qMax(perPinchMinimumZoomLevel, newZoomLevel), perPinchMaximumZoomLevel);
+ m_declarativeMap->setZoomLevel(newZoomLevel);
+ m_pinch.m_zoom.m_previous = newZoomLevel;
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::endPinch()
+{
+ QPointF p1 = mapFromScene(m_pinch.m_lastPoint1);
+ QPointF p2 = mapFromScene(m_pinch.m_lastPoint2);
+ m_pinch.m_event.setCenter((p1 + p2) / 2);
+ m_pinch.m_event.setAngle(m_pinch.m_lastAngle);
+ m_pinch.m_event.setPoint1(p1);
+ m_pinch.m_event.setPoint2(p2);
+ m_pinch.m_event.setAccepted(true);
+ m_pinch.m_event.setPointCount(0);
+ emit pinchFinished(&m_pinch.m_event);
+ m_pinch.m_startDist = 0;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::panStateMachine()
+{
+ FlickState lastState = m_flickState;
+
+ // Transitions
+ switch (m_flickState) {
+ case flickInactive:
+ if (canStartPan()) {
+ // Update startCoord_ to ensure smooth start for panning when going over startDragDistance
+ QGeoCoordinate newStartCoord = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(m_sceneCenter), false);
+ m_startCoord.setLongitude(newStartCoord.longitude());
+ m_startCoord.setLatitude(newStartCoord.latitude());
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_flickState = panActive;
+ }
+ break;
+ case panActive:
+ if (m_allPoints.count() == 0) {
+ if (!tryStartFlick())
+ {
+ m_flickState = flickInactive;
+ // mark as inactive for use by camera
+ if (m_pinchState == pinchInactive) {
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ m_map->prefetchData();
+ }
+ emit panFinished();
+ } else {
+ m_flickState = flickActive;
+ emit panFinished();
+ emit flickStarted();
+ }
+ }
+ break;
+ case flickActive:
+ if (m_allPoints.count() > 0) { // re touched before movement ended
+ stopFlick();
+ m_declarativeMap->setKeepMouseGrab(true);
+ m_flickState = panActive;
+ }
+ break;
+ }
+
+ if (m_flickState != lastState)
+ emit panActiveChanged();
+
+ // Update
+ switch (m_flickState) {
+ case flickInactive: // do nothing
+ break;
+ case panActive:
+ updatePan();
+ // this ensures 'panStarted' occurs after the pan has actually started
+ if (lastState != panActive)
+ emit panStarted();
+ break;
+ case flickActive:
+ break;
+ }
+}
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::canStartPan()
+{
+ if (m_allPoints.count() == 0 || (m_acceptedGestures & PanGesture) == 0)
+ return false;
+
+ // Check if thresholds for normal panning are met.
+ // (normal panning vs flicking: flicking will start from mouse release event).
+ const int startDragDistance = qApp->styleHints()->startDragDistance() * 2;
+ QPointF p1 = mapFromScene(m_allPoints.at(0).scenePos());
+ int dyFromPress = int(p1.y() - m_sceneStartPoint1.y());
+ int dxFromPress = int(p1.x() - m_sceneStartPoint1.x());
+ if ((qAbs(dyFromPress) >= startDragDistance || qAbs(dxFromPress) >= startDragDistance))
+ return true;
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::updatePan()
+{
+ QPointF startPoint = m_map->geoProjection().coordinateToItemPosition(m_startCoord, false).toPointF();
+ int dx = static_cast<int>(m_sceneCenter.x() - startPoint.x());
+ int dy = static_cast<int>(m_sceneCenter.y() - startPoint.y());
+ QPointF mapCenterPoint;
+ mapCenterPoint.setY(m_map->viewportHeight() / 2.0 - dy);
+ mapCenterPoint.setX(m_map->viewportWidth() / 2.0 - dx);
+ QGeoCoordinate animationStartCoordinate = m_map->geoProjection().itemPositionToCoordinate(QDoubleVector2D(mapCenterPoint), false);
+ m_declarativeMap->setCenter(animationStartCoordinate);
+}
+
+/*!
+ \internal
+*/
+bool QQuickGeoMapGestureArea::tryStartFlick()
+{
+ if ((m_acceptedGestures & FlickGesture) == 0)
+ return false;
+ // if we drag then pause before release we should not cause a flick.
+ qreal velocityX = 0.0;
+ qreal velocityY = 0.0;
+ if (m_lastPosTime.elapsed() < QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD) {
+ velocityY = m_velocityY;
+ velocityX = m_velocityX;
+ }
+ int flickTimeY = 0;
+ int flickTimeX = 0;
+ int flickPixelsX = 0;
+ int flickPixelsY = 0;
+ if (qAbs(velocityY) > MinimumFlickVelocity && qAbs(m_sceneCenter.y() - m_sceneStartPoint1.y()) > FlickThreshold) {
+ // calculate Y flick animation values
+ qreal acceleration = m_flick.m_deceleration;
+ if ((velocityY > 0.0f) == (m_flick.m_deceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+ flickTimeY = static_cast<int>(-1000 * velocityY / acceleration);
+ flickPixelsY = (flickTimeY * velocityY) / (1000.0 * 2);
+ }
+ if (qAbs(velocityX) > MinimumFlickVelocity && qAbs(m_sceneCenter.x() - m_sceneStartPoint1.x()) > FlickThreshold) {
+ // calculate X flick animation values
+ qreal acceleration = m_flick.m_deceleration;
+ if ((velocityX > 0.0f) == (m_flick.m_deceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+ flickTimeX = static_cast<int>(-1000 * velocityX / acceleration);
+ flickPixelsX = (flickTimeX * velocityX) / (1000.0 * 2);
+ }
+ int flickTime = qMax(flickTimeY, flickTimeX);
+ if (flickTime > 0) {
+ startFlick(flickPixelsX, flickPixelsY, flickTime);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::startFlick(int dx, int dy, int timeMs)
+{
+ if (!m_flick.m_animation)
+ return;
+ if (timeMs < 0)
+ return;
+
+ QGeoCoordinate animationStartCoordinate = m_declarativeMap->center();
+
+ if (m_flick.m_animation->isRunning())
+ m_flick.m_animation->stop();
+ QGeoCoordinate animationEndCoordinate = m_declarativeMap->center();
+ m_flick.m_animation->setDuration(timeMs);
+
+ double zoom = pow(2.0, m_declarativeMap->zoomLevel());
+ double longitude = animationStartCoordinate.longitude() - (dx / zoom);
+ double latitude = animationStartCoordinate.latitude() + (dy / zoom);
+
+ if (dx > 0)
+ m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::East);
+ else
+ m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::West);
+
+ //keep animation in correct bounds
+ if (latitude > 85.05113)
+ latitude = 85.05113;
+ else if (latitude < -85.05113)
+ latitude = -85.05113;
+
+ if (longitude > 180)
+ longitude = longitude - 360;
+ else if (longitude < -180)
+ longitude = longitude + 360;
+
+ animationEndCoordinate.setLongitude(longitude);
+ animationEndCoordinate.setLatitude(latitude);
+
+ m_flick.m_animation->setFrom(animationStartCoordinate);
+ m_flick.m_animation->setTo(animationEndCoordinate);
+ m_flick.m_animation->start();
+}
+
+void QQuickGeoMapGestureArea::stopPan()
+{
+ if (m_flickState == flickActive) {
+ stopFlick();
+ } else if (m_flickState == panActive) {
+ m_velocityX = 0;
+ m_velocityY = 0;
+ m_flickState = flickInactive;
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ emit panFinished();
+ emit panActiveChanged();
+ m_map->prefetchData();
+ }
+}
+
+/*!
+ \internal
+*/
+void QQuickGeoMapGestureArea::stopFlick()
+{
+ if (!m_flick.m_animation)
+ return;
+ m_velocityX = 0;
+ m_velocityY = 0;
+ if (m_flick.m_animation->isRunning())
+ m_flick.m_animation->stop();
+ else
+ handleFlickAnimationStopped();
+}
+
+void QQuickGeoMapGestureArea::handleFlickAnimationStopped()
+{
+ m_declarativeMap->setKeepMouseGrab(m_preventStealing);
+ if (m_flickState == flickActive) {
+ m_flickState = flickInactive;
+ emit flickFinished();
+ emit panActiveChanged();
+ m_map->prefetchData();
+ }
+}
+
+#include "moc_qquickgeomapgesturearea_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativemaps/qquickgeomapgesturearea_p.h b/src/location/declarativemaps/qquickgeomapgesturearea_p.h
new file mode 100644
index 00000000..5d3efc8d
--- /dev/null
+++ b/src/location/declarativemaps/qquickgeomapgesturearea_p.h
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKGEOMAPGESTUREAREA_P_H
+#define QQUICKGEOMAPGESTUREAREA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/private/qlocationglobal_p.h>
+
+#include <QtQuick/QQuickItem>
+#include <QTouchEvent>
+#include <QDebug>
+#include <QElapsedTimer>
+#include <QtPositioning/qgeocoordinate.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsSceneMouseEvent;
+class QQuickGeoCoordinateAnimation;
+class QDeclarativeGeoMap;
+class QTouchEvent;
+class QWheelEvent;
+class QGeoMap;
+
+class Q_LOCATION_PRIVATE_EXPORT QGeoMapPinchEvent : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPointF center READ center)
+ Q_PROPERTY(qreal angle READ angle)
+ Q_PROPERTY(QPointF point1 READ point1)
+ Q_PROPERTY(QPointF point2 READ point2)
+ Q_PROPERTY(int pointCount READ pointCount)
+ Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+
+public:
+ QGeoMapPinchEvent(const QPointF &center, qreal angle,
+ const QPointF &point1, const QPointF &point2,
+ int pointCount = 0, bool accepted = true)
+ : QObject(), m_center(center), m_angle(angle),
+ m_point1(point1), m_point2(point2),
+ m_pointCount(pointCount), m_accepted(accepted) {}
+ QGeoMapPinchEvent()
+ : QObject(),
+ m_angle(0.0),
+ m_pointCount(0),
+ m_accepted(true) {}
+
+ QPointF center() const { return m_center; }
+ void setCenter(const QPointF &center) { m_center = center; }
+ qreal angle() const { return m_angle; }
+ void setAngle(qreal angle) { m_angle = angle; }
+ QPointF point1() const { return m_point1; }
+ void setPoint1(const QPointF &p) { m_point1 = p; }
+ QPointF point2() const { return m_point2; }
+ void setPoint2(const QPointF &p) { m_point2 = p; }
+ int pointCount() const { return m_pointCount; }
+ void setPointCount(int count) { m_pointCount = count; }
+ bool accepted() const { return m_accepted; }
+ void setAccepted(bool a) { m_accepted = a; }
+
+private:
+ QPointF m_center;
+ qreal m_angle;
+ QPointF m_point1;
+ QPointF m_point2;
+ int m_pointCount;
+ bool m_accepted;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QQuickGeoMapGestureArea: public QQuickItem
+{
+ Q_OBJECT
+ Q_ENUMS(GeoMapGesture)
+ Q_FLAGS(AcceptedGestures)
+
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool pinchActive READ isPinchActive NOTIFY pinchActiveChanged)
+ Q_PROPERTY(bool panActive READ isPanActive NOTIFY panActiveChanged)
+ Q_PROPERTY(AcceptedGestures acceptedGestures READ acceptedGestures WRITE setAcceptedGestures NOTIFY acceptedGesturesChanged)
+ Q_PROPERTY(qreal maximumZoomLevelChange READ maximumZoomLevelChange WRITE setMaximumZoomLevelChange NOTIFY maximumZoomLevelChangeChanged)
+ Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
+ Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged REVISION 1)
+
+public:
+ QQuickGeoMapGestureArea(QDeclarativeGeoMap *map);
+ ~QQuickGeoMapGestureArea();
+
+ enum GeoMapGesture {
+ NoGesture = 0x0000,
+ PinchGesture = 0x0001,
+ PanGesture = 0x0002,
+ FlickGesture = 0x004
+ };
+
+ Q_DECLARE_FLAGS(AcceptedGestures, GeoMapGesture)
+
+ AcceptedGestures acceptedGestures() const;
+ void setAcceptedGestures(AcceptedGestures acceptedGestures);
+
+ bool isPinchActive() const;
+ bool isPanActive() const;
+ bool isActive() const;
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+ qreal maximumZoomLevelChange() const;
+ void setMaximumZoomLevelChange(qreal maxChange);
+
+ qreal flickDeceleration() const;
+ void setFlickDeceleration(qreal deceleration);
+
+ void handleTouchEvent(QTouchEvent *event);
+ void handleWheelEvent(QWheelEvent *event);
+ void handleMousePressEvent(QMouseEvent *event);
+ void handleMouseMoveEvent(QMouseEvent *event);
+ void handleMouseReleaseEvent(QMouseEvent *event);
+ void handleMouseUngrabEvent();
+ void handleTouchUngrabEvent();
+
+ void setMinimumZoomLevel(qreal min);
+ qreal minimumZoomLevel() const;
+
+ void setMaximumZoomLevel(qreal max);
+ qreal maximumZoomLevel() const;
+
+ void setMap(QGeoMap *map);
+
+ bool preventStealing() const;
+ void setPreventStealing(bool prevent);
+
+Q_SIGNALS:
+ void panActiveChanged();
+ void pinchActiveChanged();
+ void enabledChanged();
+ void maximumZoomLevelChangeChanged();
+ void acceptedGesturesChanged();
+ void flickDecelerationChanged();
+ void pinchStarted(QGeoMapPinchEvent *pinch);
+ void pinchUpdated(QGeoMapPinchEvent *pinch);
+ void pinchFinished(QGeoMapPinchEvent *pinch);
+ void panStarted();
+ void panFinished();
+ void flickStarted();
+ void flickFinished();
+ void preventStealingChanged();
+private:
+ void update();
+
+ // Create general data relating to the touch points
+ void touchPointStateMachine();
+ void startOneTouchPoint();
+ void updateOneTouchPoint();
+ void startTwoTouchPoints();
+ void updateTwoTouchPoints();
+
+ // All pinch related code, which encompasses zoom
+ void pinchStateMachine();
+ bool canStartPinch();
+ void startPinch();
+ void updatePinch();
+ void endPinch();
+
+ // Pan related code (regardles of number of touch points),
+ // includes the flick based panning after letting go
+ void panStateMachine();
+ bool canStartPan();
+ void updatePan();
+ bool tryStartFlick();
+ void startFlick(int dx, int dy, int timeMs = 0);
+ void stopFlick();
+
+ bool pinchEnabled() const;
+ void setPinchEnabled(bool enabled);
+ bool panEnabled() const;
+ void setPanEnabled(bool enabled);
+ bool flickEnabled() const;
+ void setFlickEnabled(bool enabled);
+
+private Q_SLOTS:
+ void handleFlickAnimationStopped();
+
+
+private:
+ void stopPan();
+ void clearTouchData();
+ void updateVelocityList(const QPointF &pos);
+
+private:
+ QGeoMap *m_map;
+ QDeclarativeGeoMap *m_declarativeMap;
+ bool m_enabled;
+
+ struct Pinch
+ {
+ Pinch() : m_enabled(true), m_startDist(0), m_lastAngle(0.0) {}
+
+ QGeoMapPinchEvent m_event;
+ bool m_enabled;
+ struct Zoom
+ {
+ Zoom() : m_minimum(0.0), m_maximum(30.0), m_start(0.0), m_previous(0.0),
+ maximumChange(4.0) {}
+ qreal m_minimum;
+ qreal m_maximum;
+ qreal m_start;
+ qreal m_previous;
+ qreal maximumChange;
+ } m_zoom;
+
+ QPointF m_lastPoint1;
+ QPointF m_lastPoint2;
+ qreal m_startDist;
+ qreal m_lastAngle;
+ } m_pinch;
+
+ AcceptedGestures m_acceptedGestures;
+
+ struct Pan
+ {
+ qreal m_maxVelocity;
+ qreal m_deceleration;
+ QQuickGeoCoordinateAnimation *m_animation;
+ bool m_enabled;
+ } m_flick;
+
+
+ // these are calculated regardless of gesture or number of touch points
+ qreal m_velocityX;
+ qreal m_velocityY;
+ QElapsedTimer m_lastPosTime;
+ QPointF m_lastPos;
+ QList<QTouchEvent::TouchPoint> m_allPoints;
+ QList<QTouchEvent::TouchPoint> m_touchPoints;
+ QScopedPointer<QTouchEvent::TouchPoint> m_mousePoint;
+ QPointF m_sceneStartPoint1;
+
+ // only set when two points in contact
+ QPointF m_sceneStartPoint2;
+ QGeoCoordinate m_startCoord;
+ QGeoCoordinate m_touchCenterCoord;
+ qreal m_twoTouchAngle;
+ qreal m_distanceBetweenTouchPoints;
+ QPointF m_sceneCenter;
+ bool m_preventStealing;
+ bool m_panEnabled;
+
+ // prototype state machine...
+ enum TouchPointState
+ {
+ touchPoints0,
+ touchPoints1,
+ touchPoints2
+ } m_touchPointState;
+
+ enum PinchState
+ {
+ pinchInactive,
+ pinchInactiveTwoPoints,
+ pinchActive
+ } m_pinchState;
+
+ enum FlickState
+ {
+ flickInactive,
+ panActive,
+ flickActive
+ } m_flickState;
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QQuickGeoMapGestureArea)
+
+#endif // QQUICKGEOMAPGESTUREAREA_P_H
diff --git a/src/location/declarativeplaces/declarativeplaces.pri b/src/location/declarativeplaces/declarativeplaces.pri
new file mode 100644
index 00000000..82f60c23
--- /dev/null
+++ b/src/location/declarativeplaces/declarativeplaces.pri
@@ -0,0 +1,51 @@
+INCLUDEPATH += declarativeplaces
+
+SOURCES += \
+#models
+ declarativeplaces/qdeclarativeplacecontentmodel.cpp \
+ declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp \
+ declarativeplaces/qdeclarativesearchsuggestionmodel.cpp \
+ declarativeplaces/qdeclarativesearchresultmodel.cpp \
+ declarativeplaces/qdeclarativereviewmodel.cpp \
+ declarativeplaces/qdeclarativeplaceimagemodel.cpp \
+ declarativeplaces/qdeclarativeplaceeditorialmodel.cpp \
+#data
+ declarativeplaces/qdeclarativecontactdetail.cpp \
+ declarativeplaces/qdeclarativecategory.cpp \
+ declarativeplaces/qdeclarativeplace.cpp \
+ declarativeplaces/qdeclarativeplaceattribute.cpp \
+ declarativeplaces/qdeclarativeplaceicon.cpp \
+ declarativeplaces/qdeclarativeplaceuser.cpp \
+ declarativeplaces/qdeclarativeratings.cpp \
+ declarativeplaces/qdeclarativesupplier.cpp \
+ declarativeplaces/qdeclarativesearchmodelbase.cpp
+
+PRIVATE_HEADERS += \
+#models
+ declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h \
+ declarativeplaces/qdeclarativesearchsuggestionmodel_p.h \
+ declarativeplaces/qdeclarativesearchresultmodel_p.h \
+ declarativeplaces/qdeclarativereviewmodel_p.h \
+ declarativeplaces/qdeclarativeplaceimagemodel_p.h \
+#data
+ declarativeplaces/qdeclarativecontactdetail_p.h \
+ declarativeplaces/qdeclarativecategory_p.h \
+ declarativeplaces/qdeclarativeplace_p.h \
+ declarativeplaces/qdeclarativeplaceattribute_p.h \
+ declarativeplaces/qdeclarativeplaceicon_p.h \
+ declarativeplaces/qdeclarativeplaceuser_p.h \
+ declarativeplaces/qdeclarativeratings_p.h \
+ declarativeplaces/qdeclarativesupplier_p.h \
+ declarativeplaces/qdeclarativesearchmodelbase_p.h \
+ declarativeplaces/qdeclarativeplacecontentmodel_p.h \
+ declarativeplaces/qdeclarativeplaceeditorialmodel_p.h
+
+
+
+
+
+
+
+
+
+
diff --git a/src/location/declarativeplaces/qdeclarativecategory.cpp b/src/location/declarativeplaces/qdeclarativecategory.cpp
new file mode 100644
index 00000000..c58ec3a2
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativecategory.cpp
@@ -0,0 +1,458 @@
+/****************************************************************************
+**
+** 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 "qdeclarativecategory_p.h"
+#include "qdeclarativeplaceicon_p.h"
+#include "qdeclarativegeoserviceprovider_p.h"
+#include "error_messages.h"
+
+#include <QtQml/QQmlInfo>
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/QPlaceManager>
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Category
+ \instantiates QDeclarativeCategory
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+
+ \since Qt Location 5.5
+
+ \brief The Category type represents a category that a \l Place can be associated with.
+
+ Categories are used to search for places based on the categories they are associated with. The
+ list of available categories can be obtained from the \l CategoryModel. The
+ \l PlaceSearchModel has a \l {PlaceSearchModel::categories}{categories} property that is used
+ to limit the search results to places with the specified categories.
+
+ If the \l Plugin supports it, categories can be created or removed. To create a new category
+ construct a new Category object and set its properties, then invoke the \l save() method.
+
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml Category
+ \dots 0
+ \snippet declarative/places.qml Category save
+
+ To remove a category ensure that the \l plugin and categoryId properties are set and call the
+ \l remove() method.
+
+ \sa CategoryModel
+*/
+
+QDeclarativeCategory::QDeclarativeCategory(QObject *parent)
+: QObject(parent), m_icon(0), m_plugin(0), m_reply(0), m_complete(false), m_status(Ready)
+{
+}
+
+QDeclarativeCategory::QDeclarativeCategory(const QPlaceCategory &category,
+ QDeclarativeGeoServiceProvider *plugin,
+ QObject *parent)
+: QObject(parent), m_category(category), m_icon(0), m_plugin(plugin), m_reply(0),
+ m_complete(false), m_status(Ready)
+{
+ setCategory(category);
+}
+
+QDeclarativeCategory::~QDeclarativeCategory() {}
+
+// From QQmlParserStatus
+void QDeclarativeCategory::componentComplete()
+{
+ // delayed instantiation of QObject based properties.
+ if (!m_icon) {
+ m_icon = new QDeclarativePlaceIcon(this);
+ m_icon->setPlugin(m_plugin);
+ }
+
+ m_complete = true;
+}
+
+/*!
+ \qmlproperty Plugin Category::plugin
+
+ This property holds the location based service to which the category belongs.
+*/
+void QDeclarativeCategory::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (m_plugin == plugin)
+ return;
+
+ m_plugin = plugin;
+ if (m_complete)
+ emit pluginChanged();
+
+ if (m_icon && m_icon->parent() == this && !m_icon->plugin())
+ m_icon->setPlugin(m_plugin);
+
+ if (!m_plugin)
+ return;
+
+ if (m_plugin->isAttached()) {
+ pluginReady();
+ } else {
+ connect(m_plugin, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+QDeclarativeGeoServiceProvider *QDeclarativeCategory::plugin() const
+{
+ return m_plugin;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCategory::pluginReady()
+{
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) {
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
+ .arg(m_plugin->name()).arg(serviceProvider->errorString()));
+ return;
+ }
+}
+
+
+/*!
+ \qmlproperty QPlaceCategory Category::category
+ \keyword Category::category
+
+ For details on how to use this property to interface between C++ and QML see
+ "\l {Category - QPlaceCategory} {Interfaces between C++ and QML Code}".
+*/
+void QDeclarativeCategory::setCategory(const QPlaceCategory &category)
+{
+ QPlaceCategory previous = m_category;
+ m_category = category;
+
+ if (category.name() != previous.name())
+ emit nameChanged();
+
+ if (category.categoryId() != previous.categoryId())
+ emit categoryIdChanged();
+
+ if (m_icon && m_icon->parent() == this) {
+ m_icon->setPlugin(m_plugin);
+ m_icon->setIcon(m_category.icon());
+ } else if (!m_icon || m_icon->parent() != this) {
+ m_icon = new QDeclarativePlaceIcon(m_category.icon(), m_plugin, this);
+ emit iconChanged();
+ }
+}
+
+QPlaceCategory QDeclarativeCategory::category()
+{
+ m_category.setIcon(m_icon ? m_icon->icon() : QPlaceIcon());
+ return m_category;
+}
+
+/*!
+ \qmlproperty string Category::categoryId
+
+ This property holds the identifier of the category. The categoryId is a string which uniquely
+ identifies this category within the categories \l plugin.
+*/
+void QDeclarativeCategory::setCategoryId(const QString &id)
+{
+ if (m_category.categoryId() != id) {
+ m_category.setCategoryId(id);
+ emit categoryIdChanged();
+ }
+}
+
+QString QDeclarativeCategory::categoryId() const
+{
+ return m_category.categoryId();
+}
+
+/*!
+ \qmlproperty string Category::name
+
+ This property holds string based name of the category.
+*/
+void QDeclarativeCategory::setName(const QString &name)
+{
+ if (m_category.name() != name) {
+ m_category.setName(name);
+ emit nameChanged();
+ }
+}
+
+QString QDeclarativeCategory::name() const
+{
+ return m_category.name();
+}
+
+/*!
+ \qmlproperty enumeration Category::visibility
+
+ This property holds the visibility of the category. It can be one of:
+
+ \table
+ \row
+ \li Category.UnspecifiedVisibility
+ \li The visibility of the category is unspecified. If saving a category, the
+ plugin will automatically set a default visibility to the category saved in the backend.
+ This default is dependent on the plugin implementation.
+ \row
+ \li Category.DeviceVisibility
+ \li The category is limited to the current device. The category will not be transferred
+ off of the device.
+ \row
+ \li Category.PrivateVisibility
+ \li The category is private to the current user. The category may be transferred to an
+ online service but is only ever visible to the current user.
+ \row
+ \li Category.PublicVisibility
+ \li The category is public.
+ \endtable
+
+ Note that visibility does not affect how \l{Place}s associated with
+ the category are displayed in the user-interface of an application
+ on the device. Instead, it defines the sharing semantics of the
+ category.
+*/
+QDeclarativeCategory::Visibility QDeclarativeCategory::visibility() const
+{
+ return static_cast<QDeclarativeCategory::Visibility>(m_category.visibility());
+}
+
+void QDeclarativeCategory::setVisibility(Visibility visibility)
+{
+ if (static_cast<QDeclarativeCategory::Visibility>(m_category.visibility()) == visibility)
+ return;
+
+ m_category.setVisibility(static_cast<QLocation::Visibility>(visibility));
+ emit visibilityChanged();
+}
+
+/*!
+ \qmlproperty PlaceIcon Category::icon
+
+ This property holds the image source associated with the category. To display the icon you can use
+ the \l Image type.
+*/
+QDeclarativePlaceIcon *QDeclarativeCategory::icon() const
+{
+ return m_icon;
+}
+
+void QDeclarativeCategory::setIcon(QDeclarativePlaceIcon *icon)
+{
+ if (m_icon == icon)
+ return;
+
+ if (m_icon && m_icon->parent() == this)
+ delete m_icon;
+
+ m_icon = icon;
+ emit iconChanged();
+}
+
+/*!
+ \qmlmethod string Category::errorString()
+
+ Returns a string description of the error of the last operation.
+ If the last operation completed successfully then the string is empty.
+*/
+QString QDeclarativeCategory::errorString() const
+{
+ return m_errorString;
+}
+
+void QDeclarativeCategory::setStatus(Status status, const QString &errorString)
+{
+ Status originalStatus = m_status;
+ m_status = status;
+ m_errorString = errorString;
+
+ if (originalStatus != m_status)
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty enumeration Category::status
+
+ This property holds the status of the category. It can be one of:
+
+ \table
+ \row
+ \li Category.Ready
+ \li No error occurred during the last operation, further operations may be performed on
+ the category.
+ \row
+ \li Category.Saving
+ \li The category is currently being saved, no other operations may be performed until the
+ current operation completes.
+ \row
+ \li Category.Removing
+ \li The category is currently being removed, no other operations can be performed until
+ the current operation completes.
+ \row
+ \li Category.Error
+ \li An error occurred during the last operation, further operations can still be
+ performed on the category.
+ \endtable
+*/
+QDeclarativeCategory::Status QDeclarativeCategory::status() const
+{
+ return m_status;
+}
+
+/*!
+ \qmlmethod void Category::save()
+
+ This method saves the category to the backend service.
+*/
+void QDeclarativeCategory::save(const QString &parentId)
+{
+ QPlaceManager *placeManager = manager();
+ if (!placeManager)
+ return;
+
+ m_reply = placeManager->saveCategory(category(), parentId);
+ connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ setStatus(QDeclarativeCategory::Saving);
+}
+
+/*!
+ \qmlmethod void Category::remove()
+
+ This method permanently removes the category from the backend service.
+*/
+void QDeclarativeCategory::remove()
+{
+ QPlaceManager *placeManager = manager();
+ if (!placeManager)
+ return;
+
+ m_reply = placeManager->removeCategory(m_category.categoryId());
+ connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ setStatus(QDeclarativeCategory::Removing);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeCategory::replyFinished()
+{
+ if (!m_reply)
+ return;
+
+ if (m_reply->error() == QPlaceReply::NoError) {
+ switch (m_reply->type()) {
+ case (QPlaceReply::IdReply) : {
+ QPlaceIdReply *idReply = qobject_cast<QPlaceIdReply *>(m_reply);
+
+ switch (idReply->operationType()) {
+ case QPlaceIdReply::SaveCategory:
+ setCategoryId(idReply->id());
+ break;
+ case QPlaceIdReply::RemoveCategory:
+ setCategoryId(QString());
+ break;
+ default:
+ //Other operation types shouldn't ever be received.
+ break;
+ }
+ break;
+ }
+ default:
+ //other types of replies shouldn't ever be received.
+ break;
+ }
+
+ m_errorString.clear();
+
+ m_reply->deleteLater();
+ m_reply = 0;
+
+ setStatus(QDeclarativeCategory::Ready);
+ } else {
+ QString errorString = m_reply->errorString();
+
+ m_reply->deleteLater();
+ m_reply = 0;
+
+ setStatus(QDeclarativeCategory::Error, errorString);
+ }
+}
+
+/*!
+ \internal
+ Helper function to return the manager, this manager is intended to be used to perform the next
+ operation. Sets status to Error and an appropriate m_errorString if the manager cannot be
+ obtained.
+*/
+QPlaceManager *QDeclarativeCategory::manager()
+{
+ if (m_status != QDeclarativeCategory::Ready && m_status != QDeclarativeCategory::Error)
+ return 0;
+
+ if (m_reply) {
+ m_reply->abort();
+ m_reply->deleteLater();
+ m_reply = 0;
+ }
+
+ if (!m_plugin) {
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROPERTY_NOT_SET));
+ return 0;
+ }
+
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (!serviceProvider) {
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_NOT_VALID));
+ return 0;
+ }
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (!placeManager) {
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
+ .arg(m_plugin->name()).arg(serviceProvider->errorString()));
+ return 0;
+ }
+
+ return placeManager;
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativecategory_p.h b/src/location/declarativeplaces/qdeclarativecategory_p.h
new file mode 100644
index 00000000..c32072f4
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativecategory_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVECATEGORY_P_H
+#define QDECLARATIVECATEGORY_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 <QtQml/qqml.h>
+#include <QtQml/QQmlParserStatus>
+#include <QObject>
+
+#include <QtLocation/qplacecategory.h>
+
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePlaceIcon;
+class QPlaceReply;
+class QPlaceManager;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCategory : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+
+ Q_ENUMS(Status Visibility)
+
+
+ Q_PROPERTY(QPlaceCategory category READ category WRITE setCategory)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(QString categoryId READ categoryId WRITE setCategoryId NOTIFY categoryIdChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
+ Q_PROPERTY(QDeclarativePlaceIcon *icon READ icon WRITE setIcon NOTIFY iconChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativeCategory(QObject *parent = 0);
+ QDeclarativeCategory(const QPlaceCategory &category, QDeclarativeGeoServiceProvider *plugin, QObject *parent = 0);
+ ~QDeclarativeCategory();
+
+ enum Visibility {
+ UnspecifiedVisibility = QLocation::UnspecifiedVisibility,
+ DeviceVisibility = QLocation::DeviceVisibility,
+ PrivateVisibility = QLocation::PrivateVisibility,
+ PublicVisibility = QLocation::PublicVisibility
+ };
+ enum Status {Ready, Saving, Removing, Error};
+
+ //From QQmlParserStatus
+ virtual void classBegin() {}
+ virtual void componentComplete();
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ QPlaceCategory category();
+ void setCategory(const QPlaceCategory &category);
+
+ QString categoryId() const;
+ void setCategoryId(const QString &catID);
+ QString name() const;
+ void setName(const QString &name);
+
+ Visibility visibility() const;
+ void setVisibility(Visibility visibility);
+
+ QDeclarativePlaceIcon *icon() const;
+ void setIcon(QDeclarativePlaceIcon *icon);
+
+ Q_INVOKABLE QString errorString() const;
+
+ Status status() const;
+ void setStatus(Status status, const QString &errorString = QString());
+
+ Q_INVOKABLE void save(const QString &parentId = QString());
+ Q_INVOKABLE void remove();
+
+Q_SIGNALS:
+ void pluginChanged();
+ void categoryIdChanged();
+ void nameChanged();
+ void visibilityChanged();
+ void iconChanged();
+ void statusChanged();
+
+private Q_SLOTS:
+ void replyFinished();
+ void pluginReady();
+
+private:
+ QPlaceManager *manager();
+
+ QPlaceCategory m_category;
+ QDeclarativePlaceIcon *m_icon;
+ QDeclarativeGeoServiceProvider *m_plugin;
+ QPlaceReply *m_reply;
+ bool m_complete;
+ Status m_status;
+ QString m_errorString;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeCategory)
+
+#endif // QDECLARATIVECATEGORY_P_H
diff --git a/src/location/declarativeplaces/qdeclarativecontactdetail.cpp b/src/location/declarativeplaces/qdeclarativecontactdetail.cpp
new file mode 100644
index 00000000..7a7a4c33
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativecontactdetail.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** 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 "qdeclarativecontactdetail_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ContactDetails
+ \instantiates QDeclarativeContactDetails
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief The ContactDetails type holds contact details for a \l Place.
+
+ The ContactDetails type is a map of \l {QtLocation::ContactDetail}{ContactDetail} objects.
+ To access contact details in the map use the \l keys() method to get the list of keys stored in
+ the map and then use the \c {[]} operator to access the
+ \l {QtLocation::ContactDetail}{ContactDetail} items.
+
+ The following keys are defined in the API. \l Plugin implementations are free to define
+ additional keys.
+
+ \list
+ \li phone
+ \li fax
+ \li email
+ \li website
+ \endlist
+
+ ContactDetails instances are only ever used in the context of \l {Place}{Places}. It is not possible
+ to create a ContactDetails instance directly or re-assign ContactDetails instances to \l {Place}{Places}.
+ Modification of ContactDetails can only be accomplished via Javascript.
+
+ \section1 Examples
+
+ The following example shows how to access all \l {QtLocation::ContactDetail}{ContactDetails}
+ and print them to the console:
+
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml ContactDetails read
+
+ The returned list of contact details is an \l {QObjectList-based model}{object list} and so can be used directly as a data model. For example, the
+ following demonstrates how to display a list of contact phone numbers in a list view:
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml ContactDetails phoneList
+
+ The following example demonstrates how to assign a single phone number to a place in JavaScript:
+ \snippet declarative/places.qml ContactDetails write single
+
+ The following demonstrates how to assign multiple phone numbers to a place in JavaScript:
+ \snippet declarative/places.qml ContactDetails write multiple
+*/
+
+/*!
+ \qmlmethod variant ContactDetails::keys()
+
+ Returns an array of contact detail keys currently stored in the map.
+*/
+QDeclarativeContactDetails::QDeclarativeContactDetails(QObject *parent)
+ : QQmlPropertyMap(parent)
+{
+}
+
+QVariant QDeclarativeContactDetails::updateValue(const QString &, const QVariant &input)
+{
+ if (input.userType() == QMetaType::QObjectStar) {
+ QDeclarativeContactDetail *detail =
+ qobject_cast<QDeclarativeContactDetail *>(input.value<QObject *>());
+ if (detail) {
+ QVariantList varList;
+ varList.append(input);
+ return varList;
+ }
+ }
+
+ return input;
+}
+
+/*!
+ \qmltype ContactDetail
+ \instantiates QDeclarativeContactDetail
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief The ContactDetail type holds a contact detail such as a phone number or a website
+ address.
+
+ The ContactDetail provides a single detail on how one could contact a \l Place. The
+ ContactDetail consists of a \l label, which is a localized string describing the contact
+ method, and a \l value representing the actual contact detail.
+
+ \section1 Examples
+
+ The following example demonstrates how to assign a single phone number to a place in JavaScript:
+ \snippet declarative/places.qml ContactDetails write single
+
+ The following demonstrates how to assign multiple phone numbers to a place in JavaScript:
+ \snippet declarative/places.qml ContactDetails write multiple
+
+ Note, due to limitations of the QQmlPropertyMap, it is not possible
+ to declaratively specify the contact details in QML, it can only be accomplished
+ via JavaScript.
+*/
+QDeclarativeContactDetail::QDeclarativeContactDetail(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QDeclarativeContactDetail::QDeclarativeContactDetail(const QPlaceContactDetail &src, QObject *parent)
+ : QObject(parent), m_contactDetail(src)
+{
+}
+
+QDeclarativeContactDetail::~QDeclarativeContactDetail()
+{
+}
+
+/*!
+ \qmlproperty QPlaceContactDetail QtLocation::ContactDetail::contactDetail
+
+ For details on how to use this property to interface between C++ and QML see
+ "\l {ContactDetail - QDeclarativeContactDetail} {Interfaces between C++ and QML Code}".
+*/
+void QDeclarativeContactDetail::setContactDetail(const QPlaceContactDetail &src)
+{
+ QPlaceContactDetail prevContactDetail = m_contactDetail;
+ m_contactDetail = src;
+
+ if (m_contactDetail.label() != prevContactDetail.label())
+ emit labelChanged();
+ if (m_contactDetail.value() != prevContactDetail.value())
+ emit valueChanged();
+}
+
+QPlaceContactDetail QDeclarativeContactDetail::contactDetail() const
+{
+ return m_contactDetail;
+}
+
+/*!
+ \qmlproperty string QtLocation::ContactDetail::label
+
+ This property holds a label describing the contact detail.
+
+ The label can potentially be localized. The language is dependent on the entity that sets it,
+ typically this is the \l {Plugin}. The \l {Plugin::locales} property defines
+ what language is used.
+*/
+QString QDeclarativeContactDetail::label() const
+{
+ return m_contactDetail.label();
+}
+
+void QDeclarativeContactDetail::setLabel(const QString &label)
+{
+ if (m_contactDetail.label() != label) {
+ m_contactDetail.setLabel(label);
+ emit labelChanged();
+ }
+}
+
+/*!
+ \qmlproperty string QtLocation::ContactDetail::value
+
+ This property holds the value of the contact detail which may be a phone number, an email
+ address, a website url and so on.
+*/
+QString QDeclarativeContactDetail::value() const
+{
+ return m_contactDetail.value();
+}
+
+void QDeclarativeContactDetail::setValue(const QString &value)
+{
+ if (m_contactDetail.value() != value) {
+ m_contactDetail.setValue(value);
+ emit valueChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativecontactdetail_p.h b/src/location/declarativeplaces/qdeclarativecontactdetail_p.h
new file mode 100644
index 00000000..ad60c3b5
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativecontactdetail_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVECONTACTDETAIL_P_H
+#define QDECLARATIVECONTACTDETAIL_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/QObject>
+#include <QtLocation/QPlaceContactDetail>
+#include <QtQml/QQmlPropertyMap>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeContactDetails : public QQmlPropertyMap
+{
+ Q_OBJECT
+
+public:
+ explicit QDeclarativeContactDetails(QObject *parent = 0);
+ virtual QVariant updateValue(const QString &key, const QVariant &input);
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeContactDetail : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPlaceContactDetail contactDetail READ contactDetail WRITE setContactDetail)
+ Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged)
+ Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ explicit QDeclarativeContactDetail(QObject *parent = 0);
+ explicit QDeclarativeContactDetail(const QPlaceContactDetail &src, QObject *parent = 0);
+ ~QDeclarativeContactDetail();
+
+ QPlaceContactDetail contactDetail() const;
+ void setContactDetail(const QPlaceContactDetail &contactDetail);
+
+ QString label() const;
+ void setLabel(const QString &label);
+
+ QString value() const;
+ void setValue(const QString &value);
+
+Q_SIGNALS:
+ void labelChanged();
+ void valueChanged();
+
+private:
+ QPlaceContactDetail m_contactDetail;
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeContactDetail)
+QML_DECLARE_TYPE(QDeclarativeContactDetails)
+
+#endif
diff --git a/src/location/declarativeplaces/qdeclarativeperiod_p.h b/src/location/declarativeplaces/qdeclarativeperiod_p.h
new file mode 100644
index 00000000..3ded0109
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeperiod_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVEPERIOD_P_H
+#define QDECLARATIVEPERIOD_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 <qplaceperiod.h>
+#include <QtQml/qqml.h>
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePeriod : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDate startDate READ startDate WRITE setStartDate NOTIFY startDateChanged)
+ Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
+ Q_PROPERTY(QDate endDate READ endDate WRITE setEndDate NOTIFY endDateChanged)
+ Q_PROPERTY(QTime endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged)
+
+public:
+ explicit QDeclarativePeriod(QObject *parent = 0);
+ explicit QDeclarativePeriod(const QPlacePeriod &period, QObject *parent = 0);
+ ~QDeclarativePeriod();
+
+ QPlacePeriod period() const;
+ void setPeriod(const QPlacePeriod &period);
+
+ QDate startDate() const;
+ void setStartDate(const QDate &data);
+ QTime startTime() const;
+ void setStartTime(const QTime &data);
+ QDate endDate() const;
+ void setEndDate(const QDate &data);
+ QTime endTime() const;
+ void setEndTime(const QTime &data);
+
+Q_SIGNALS:
+ void startDateChanged();
+ void startTimeChanged();
+ void endDateChanged();
+ void endTimeChanged();
+
+private:
+ QPlacePeriod m_period;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativePeriod));
+
+#endif // QDECLARATIVEPERIOD_P_H
diff --git a/src/location/declarativeplaces/qdeclarativeplace.cpp b/src/location/declarativeplaces/qdeclarativeplace.cpp
new file mode 100644
index 00000000..91ef2026
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplace.cpp
@@ -0,0 +1,1229 @@
+/****************************************************************************
+**
+** 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 "qdeclarativeplace_p.h"
+#include "qdeclarativecontactdetail_p.h"
+#include "qdeclarativegeoserviceprovider_p.h"
+#include "qdeclarativeplaceattribute_p.h"
+#include "qdeclarativeplaceicon_p.h"
+#include "error_messages.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QMetaObject>
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlInfo>
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/QPlaceManager>
+#include <QtLocation/QPlaceDetailsReply>
+#include <QtLocation/QPlaceReply>
+#include <QtLocation/QPlaceIdReply>
+#include <QtLocation/QPlaceContactDetail>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Place
+ \instantiates QDeclarativePlace
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief The Place type represents a location that is a position of interest.
+
+ The Place type represents a physical location with additional metadata describing that
+ location. Contrasted with \l Location, \l Address, and
+ \l {coordinate} type which are used to describe where a location is.
+ The basic properties of a Place are its \l name and \l location.
+
+ Place objects are typically obtained from a search model and will generally only have their
+ basic properties set. The \l detailsFetched property can be used to test if further property
+ values need to be fetched from the \l Plugin. This can be done by invoking the \l getDetails()
+ method. Progress of the fetching operation can be monitored with the \l status property, which
+ will be set to Place.Fetching when the details are being fetched.
+
+ The Place type has many properties holding information about the location. Details on how to
+ contact the place are available from the \l contactDetails property. Convenience properties
+ for obtaining the primary \l {primaryPhone}{phone}, \l {primaryFax}{fax},
+ \l {primaryEmail}{email} and \l {primaryWebsite}{website} are also available.
+
+ Each place is assigned zero or more \l categories. Categories are typically used when
+ searching for a particular kind of place, such as a restaurant or hotel. Some places have a
+ \l ratings object, which gives an indication of the quality of the place.
+
+ Place metadata is provided by a \l supplier who may require that an \l attribution message be
+ displayed to the user when the place details are viewed.
+
+ Places have an associated \l icon which can be used to represent a place on a map or to
+ decorate a delegate in a view.
+
+ Places may have additional rich content associated with them. The currently supported rich
+ content include editorial descriptions, reviews and images. These are exposed as a set of
+ models for retrieving the content. Editorial descriptions of the place are available from the
+ \l editorialModel property. Reviews of the place are available from the \l reviewModel
+ property. A gallery of pictures of the place can be accessed using the \l imageModel property.
+
+ Places may have additional attributes which are not covered in the formal API. The
+ \l extendedAttributes property provides access to these. The type of extended attributes
+ available is specific to each \l Plugin.
+
+ A Place is almost always tied to a \l plugin. The \l plugin property must be set before it is
+ possible to call \l save(), \l remove() or \l getDetails(). The \l reviewModel, \l imageModel
+ and \l editorialModel are only valid then the \l plugin property is set.
+
+ \section2 Saving a Place
+
+ If the \l Plugin supports it, the Place type can be used to save a place. First create a new
+ Place and set its properties:
+
+ \snippet declarative/places.qml Place savePlace def
+
+ Then invoke the \l save() method:
+
+ \snippet declarative/places.qml Place savePlace
+
+ The \l status property will change to Place.Saving and then to Place.Ready if the save was
+ successful or to Place.Error if an error occurs.
+
+ If the \l placeId property is set, the backend will update an existing place otherwise it will
+ create a new place. On success the \l placeId property will be updated with the identifier of the newly
+ saved place.
+
+ \section3 Caveats
+ \input place-caveats.qdocinc
+
+ \section3 Saving Between Plugins
+ When saving places between plugins, there are a few things to be aware of.
+ Some fields of a place such as the id, categories and icons are plugin specific entities. For example
+ the categories in one manager may not be recognised in another.
+ Therefore trying to save a place directly from one plugin to another is not possible.
+
+ It is generally recommended that saving across plugins be handled as saving \l {Favorites}{favorites}
+ as explained in the Favorites section. However there is another approach which is to create a new place,
+ set its (destination) plugin and then use the \l copyFrom() method to copy the details of the original place.
+ Using \l copyFrom() only copies data that is supported by the destination plugin,
+ plugin specific data such as the place identifier is not copied over. Once the copy is done,
+ the place is in a suitable state to be saved.
+
+ The following snippet provides an example of saving a place to a different plugin
+ using the \l copyFrom method:
+
+ \snippet declarative/places.qml Place save to different plugin
+
+ \section2 Removing a Place
+
+ To remove a place, ensure that a Place object with a valid \l placeId property exists and call
+ its \l remove() method. The \l status property will change to Place.Removing and then to
+ Place.Ready if the save was successful or to Place.Error if an error occurs.
+
+ \section2 Favorites
+ The Places API supports the concept of favorites. Favorites are generally implemented
+ by using two plugins, the first plugin is typically a read-only source of places (origin plugin) and a second
+ read/write plugin (destination plugin) is used to store places from the origin as favorites.
+
+ Each Place has a favorite property which is intended to contain the corresponding place
+ from the destination plugin (the place itself is sourced from the origin plugin). Because both the original
+ place and favorite instances are available, the developer can choose which
+ properties to show to the user. For example the favorite may have a modified name which should
+ be displayed rather than the original name.
+
+ \snippet declarative/places.qml Place favorite
+
+ The following demonstrates how to save a new favorite instance. A call is made
+ to create/initialize the favorite instance and then the instance is saved.
+
+ \snippet declarative/places.qml Place saveFavorite
+
+ The following demonstrates favorite removal:
+
+ \snippet declarative/places.qml Place removeFavorite 1
+ \dots
+ \snippet declarative/places.qml Place removeFavorite 2
+
+ The PlaceSearchModel has a favoritesPlugin property. If the property is set, any places found
+ during a search are checked against the favoritesPlugin to see if there is a corresponding
+ favorite place. If so, the favorite property of the Place is set, otherwise the favorite
+ property is remains null.
+
+ \sa PlaceSearchModel
+*/
+
+QDeclarativePlace::QDeclarativePlace(QObject *parent)
+: QObject(parent), m_location(0), m_ratings(0), m_supplier(0), m_icon(0),
+ m_reviewModel(0), m_imageModel(0), m_editorialModel(0),
+ m_extendedAttributes(new QQmlPropertyMap(this)),
+ m_contactDetails(new QDeclarativeContactDetails(this)), m_reply(0), m_plugin(0),
+ m_complete(false), m_favorite(0), m_status(QDeclarativePlace::Ready)
+{
+ connect(m_contactDetails, SIGNAL(valueChanged(QString,QVariant)),
+ this, SLOT(contactsModified(QString,QVariant)));
+
+ setPlace(QPlace());
+}
+
+QDeclarativePlace::QDeclarativePlace(const QPlace &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent)
+: QObject(parent), m_location(0), m_ratings(0), m_supplier(0), m_icon(0),
+ m_reviewModel(0), m_imageModel(0), m_editorialModel(0),
+ m_extendedAttributes(new QQmlPropertyMap(this)),
+ m_contactDetails(new QDeclarativeContactDetails(this)), m_reply(0), m_plugin(plugin),
+ m_complete(false), m_favorite(0), m_status(QDeclarativePlace::Ready)
+{
+ Q_ASSERT(plugin);
+
+ connect(m_contactDetails, SIGNAL(valueChanged(QString,QVariant)),
+ this, SLOT(contactsModified(QString,QVariant)));
+
+ setPlace(src);
+}
+
+QDeclarativePlace::~QDeclarativePlace()
+{
+}
+
+// From QQmlParserStatus
+void QDeclarativePlace::componentComplete()
+{
+ m_complete = true;
+}
+
+/*!
+ \qmlproperty Plugin Place::plugin
+
+ This property holds the \l Plugin that provided this place which can be used to retrieve more information about the service.
+*/
+void QDeclarativePlace::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (m_plugin == plugin)
+ return;
+
+ m_plugin = plugin;
+ if (m_complete)
+ emit pluginChanged();
+
+ if (m_plugin->isAttached()) {
+ pluginReady();
+ } else {
+ connect(m_plugin, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+void QDeclarativePlace::pluginReady()
+{
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) {
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
+ .arg(m_plugin->name()).arg(serviceProvider->errorString()));
+ return;
+ }
+}
+
+QDeclarativeGeoServiceProvider *QDeclarativePlace::plugin() const
+{
+ return m_plugin;
+}
+
+/*!
+ \qmlproperty ReviewModel Place::reviewModel
+
+ This property holds a model which can be used to retrieve reviews about the place.
+*/
+QDeclarativeReviewModel *QDeclarativePlace::reviewModel()
+{
+ if (!m_reviewModel) {
+ m_reviewModel = new QDeclarativeReviewModel(this);
+ m_reviewModel->setPlace(this);
+ }
+
+ return m_reviewModel;
+}
+
+/*!
+ \qmlproperty ImageModel Place::imageModel
+
+ This property holds a model which can be used to retrieve images of the place.
+*/
+QDeclarativePlaceImageModel *QDeclarativePlace::imageModel()
+{
+ if (!m_imageModel) {
+ m_imageModel = new QDeclarativePlaceImageModel(this);
+ m_imageModel->setPlace(this);
+ }
+
+ return m_imageModel;
+}
+
+/*!
+ \qmlproperty EditorialModel Place::editorialModel
+
+ This property holds a model which can be used to retrieve editorial descriptions of the place.
+*/
+QDeclarativePlaceEditorialModel *QDeclarativePlace::editorialModel()
+{
+ if (!m_editorialModel) {
+ m_editorialModel = new QDeclarativePlaceEditorialModel(this);
+ m_editorialModel->setPlace(this);
+ }
+
+ return m_editorialModel;
+}
+
+/*!
+ \qmlproperty QPlace Place::place
+
+ For details on how to use this property to interface between C++ and QML see
+ "\l {Place - QPlace} {Interfaces between C++ and QML Code}".
+*/
+void QDeclarativePlace::setPlace(const QPlace &src)
+{
+ QPlace previous = m_src;
+ m_src = src;
+
+ if (previous.categories() != m_src.categories()) {
+ synchronizeCategories();
+ emit categoriesChanged();
+ }
+
+ if (m_location && m_location->parent() == this) {
+ m_location->setLocation(m_src.location());
+ } else if (!m_location || m_location->parent() != this) {
+ m_location = new QDeclarativeGeoLocation(m_src.location(), this);
+ emit locationChanged();
+ }
+
+ if (m_ratings && m_ratings->parent() == this) {
+ m_ratings->setRatings(m_src.ratings());
+ } else if (!m_ratings || m_ratings->parent() != this) {
+ m_ratings = new QDeclarativeRatings(m_src.ratings(), this);
+ emit ratingsChanged();
+ }
+
+ if (m_supplier && m_supplier->parent() == this) {
+ m_supplier->setSupplier(m_src.supplier(), m_plugin);
+ } else if (!m_supplier || m_supplier->parent() != this) {
+ m_supplier = new QDeclarativeSupplier(m_src.supplier(), m_plugin, this);
+ emit supplierChanged();
+ }
+
+ if (m_icon && m_icon->parent() == this) {
+ m_icon->setPlugin(m_plugin);
+ m_icon->setIcon(m_src.icon());
+ } else if (!m_icon || m_icon->parent() != this) {
+ m_icon = new QDeclarativePlaceIcon(m_src.icon(), m_plugin, this);
+ emit iconChanged();
+ }
+
+ if (previous.name() != m_src.name()) {
+ emit nameChanged();
+ }
+ if (previous.placeId() != m_src.placeId()) {
+ emit placeIdChanged();
+ }
+ if (previous.attribution() != m_src.attribution()) {
+ emit attributionChanged();
+ }
+ if (previous.detailsFetched() != m_src.detailsFetched()) {
+ emit detailsFetchedChanged();
+ }
+ if (previous.primaryPhone() != m_src.primaryPhone()) {
+ emit primaryPhoneChanged();
+ }
+ if (previous.primaryFax() != m_src.primaryFax()) {
+ emit primaryFaxChanged();
+ }
+ if (previous.primaryEmail() != m_src.primaryEmail()) {
+ emit primaryEmailChanged();
+ }
+ if (previous.primaryWebsite() != m_src.primaryWebsite()) {
+ emit primaryWebsiteChanged();
+ }
+
+ if (m_reviewModel && m_src.totalContentCount(QPlaceContent::ReviewType) >= 0) {
+ m_reviewModel->initializeCollection(m_src.totalContentCount(QPlaceContent::ReviewType),
+ m_src.content(QPlaceContent::ReviewType));
+ }
+ if (m_imageModel && m_src.totalContentCount(QPlaceContent::ImageType) >= 0) {
+ m_imageModel->initializeCollection(m_src.totalContentCount(QPlaceContent::ImageType),
+ m_src.content(QPlaceContent::ImageType));
+ }
+ if (m_editorialModel && m_src.totalContentCount(QPlaceContent::EditorialType) >= 0) {
+ m_editorialModel->initializeCollection(m_src.totalContentCount(QPlaceContent::EditorialType),
+ m_src.content(QPlaceContent::EditorialType));
+ }
+
+ synchronizeExtendedAttributes();
+ synchronizeContacts();
+}
+
+QPlace QDeclarativePlace::place()
+{
+ // The following properties are not stored in m_src but instead stored in QDeclarative* objects
+
+ QPlace result = m_src;
+
+ // Categories
+ QList<QPlaceCategory> categories;
+ foreach (QDeclarativeCategory *value, m_categories)
+ categories.append(value->category());
+
+ result.setCategories(categories);
+
+ // Location
+ result.setLocation(m_location ? m_location->location() : QGeoLocation());
+
+ // Rating
+ result.setRatings(m_ratings ? m_ratings->ratings() : QPlaceRatings());
+
+ // Supplier
+ result.setSupplier(m_supplier ? m_supplier->supplier() : QPlaceSupplier());
+
+ // Icon
+ result.setIcon(m_icon ? m_icon->icon() : QPlaceIcon());
+
+ //contact details
+ QList<QPlaceContactDetail> cppDetails;
+ foreach (const QString &key, m_contactDetails->keys()) {
+ cppDetails.clear();
+ if (m_contactDetails->value(key).type() == QVariant::List) {
+ QVariantList detailsVarList = m_contactDetails->value(key).toList();
+ foreach (const QVariant &detailVar, detailsVarList) {
+ QDeclarativeContactDetail *detail = qobject_cast<QDeclarativeContactDetail *>(detailVar.value<QObject *>());
+ if (detail)
+ cppDetails.append(detail->contactDetail());
+ }
+ } else {
+ QDeclarativeContactDetail *detail = qobject_cast<QDeclarativeContactDetail *>(m_contactDetails->value(key).value<QObject *>());
+ if (detail)
+ cppDetails.append(detail->contactDetail());
+ }
+ result.setContactDetails(key, cppDetails);
+ }
+
+ return result;
+}
+
+/*!
+ \qmlproperty QtPositioning::Location Place::location
+
+ This property holds the location of the place which can be used to retrieve the coordinate,
+ address and the bounding box.
+*/
+void QDeclarativePlace::setLocation(QDeclarativeGeoLocation *location)
+{
+ if (m_location == location)
+ return;
+
+ if (m_location && m_location->parent() == this)
+ delete m_location;
+
+ m_location = location;
+ emit locationChanged();
+}
+
+QDeclarativeGeoLocation *QDeclarativePlace::location()
+{
+ return m_location;
+}
+
+/*!
+ \qmlproperty Ratings Place::ratings
+
+ This property holds ratings of the place. The ratings provide an indication of the quality of a
+ place.
+*/
+void QDeclarativePlace::setRatings(QDeclarativeRatings *rating)
+{
+ if (m_ratings == rating)
+ return;
+
+ if (m_ratings && m_ratings->parent() == this)
+ delete m_ratings;
+
+ m_ratings = rating;
+ emit ratingsChanged();
+}
+
+QDeclarativeRatings *QDeclarativePlace::ratings()
+{
+
+ return m_ratings;
+}
+
+/*!
+ \qmlproperty Supplier Place::supplier
+
+ This property holds the supplier of the place data.
+ The supplier is typically a business or organization that collected the data about the place.
+*/
+void QDeclarativePlace::setSupplier(QDeclarativeSupplier *supplier)
+{
+ if (m_supplier == supplier)
+ return;
+
+ if (m_supplier && m_supplier->parent() == this)
+ delete m_supplier;
+
+ m_supplier = supplier;
+ emit supplierChanged();
+}
+
+QDeclarativeSupplier *QDeclarativePlace::supplier() const
+{
+ return m_supplier;
+}
+
+/*!
+ \qmlproperty Icon Place::icon
+
+ This property holds a graphical icon which can be used to represent the place.
+*/
+QDeclarativePlaceIcon *QDeclarativePlace::icon() const
+{
+ return m_icon;
+}
+
+void QDeclarativePlace::setIcon(QDeclarativePlaceIcon *icon)
+{
+ if (m_icon == icon)
+ return;
+
+ if (m_icon && m_icon->parent() == this)
+ delete m_icon;
+
+ m_icon = icon;
+ emit iconChanged();
+}
+
+/*!
+ \qmlproperty string Place::name
+
+ This property holds the name of the place which can be used to represent the place.
+*/
+void QDeclarativePlace::setName(const QString &name)
+{
+ if (m_src.name() != name) {
+ m_src.setName(name);
+ emit nameChanged();
+ }
+}
+
+QString QDeclarativePlace::name() const
+{
+ return m_src.name();
+}
+
+/*!
+ \qmlproperty string Place::placeId
+
+ This property holds the unique identifier of the place. The place identifier is only meaningful to the
+ \l Plugin that generated it and is not transferable between \l {Plugin}{Plugins}. The place id
+ is not guaranteed to be universally unique, but unique within the \l Plugin that generated it.
+
+ If only the place identifier is known, all other place data can fetched from the \l Plugin.
+
+ \snippet declarative/places.qml Place placeId
+*/
+void QDeclarativePlace::setPlaceId(const QString &placeId)
+{
+ if (m_src.placeId() != placeId) {
+ m_src.setPlaceId(placeId);
+ emit placeIdChanged();
+ }
+}
+
+QString QDeclarativePlace::placeId() const
+{
+ return m_src.placeId();
+}
+
+/*!
+ \qmlproperty string Place::attribution
+
+ This property holds a rich text attribution string for the place.
+ Some providers may require that the attribution be shown to the user
+ whenever a place is displayed. The contents of this property should
+ be shown to the user if it is not empty.
+*/
+void QDeclarativePlace::setAttribution(const QString &attribution)
+{
+ if (m_src.attribution() != attribution) {
+ m_src.setAttribution(attribution);
+ emit attributionChanged();
+ }
+}
+
+QString QDeclarativePlace::attribution() const
+{
+ return m_src.attribution();
+}
+
+/*!
+ \qmlproperty bool Place::detailsFetched
+
+ This property indicates whether the details of the place have been fetched. If this property
+ is false, the place details have not yet been fetched. Fetching can be done by invoking the
+ \l getDetails() method.
+
+ \sa getDetails()
+*/
+bool QDeclarativePlace::detailsFetched() const
+{
+ return m_src.detailsFetched();
+}
+
+/*!
+ \qmlproperty enumeration Place::status
+
+ This property holds the status of the place. It can be one of:
+
+ \table
+ \row
+ \li Place.Ready
+ \li No error occurred during the last operation, further operations may be performed on
+ the place.
+ \row
+ \li Place.Saving
+ \li The place is currently being saved, no other operation may be performed until
+ complete.
+ \row
+ \li Place.Fetching
+ \li The place details are currently being fetched, no other operations may be performed
+ until complete.
+ \row
+ \li Place.Removing
+ \li The place is currently being removed, no other operations can be performed until
+ complete.
+ \row
+ \li Place.Error
+ \li An error occurred during the last operation, further operations can still be
+ performed on the place.
+ \endtable
+
+ The status of a place can be checked by connecting the status property
+ to a handler function, and then have the handler function process the change
+ in status.
+
+ \snippet declarative/places.qml Place checkStatus
+ \dots
+ \snippet declarative/places.qml Place checkStatus handler
+
+*/
+void QDeclarativePlace::setStatus(Status status, const QString &errorString)
+{
+ Status originalStatus = m_status;
+ m_status = status;
+ m_errorString = errorString;
+
+ if (originalStatus != m_status)
+ emit statusChanged();
+}
+
+QDeclarativePlace::Status QDeclarativePlace::status() const
+{
+ return m_status;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlace::finished()
+{
+ if (!m_reply)
+ return;
+
+ if (m_reply->error() == QPlaceReply::NoError) {
+ switch (m_reply->type()) {
+ case (QPlaceReply::IdReply) : {
+ QPlaceIdReply *idReply = qobject_cast<QPlaceIdReply *>(m_reply);
+
+ switch (idReply->operationType()) {
+ case QPlaceIdReply::SavePlace:
+ setPlaceId(idReply->id());
+ break;
+ case QPlaceIdReply::RemovePlace:
+ break;
+ default:
+ //Other operation types shouldn't ever be received.
+ break;
+ }
+ break;
+ }
+ case (QPlaceReply::DetailsReply): {
+ QPlaceDetailsReply *detailsReply = qobject_cast<QPlaceDetailsReply *>(m_reply);
+ setPlace(detailsReply->place());
+ break;
+ }
+ default:
+ //other types of replies shouldn't ever be received.
+ break;
+ }
+
+ m_errorString.clear();
+
+ m_reply->deleteLater();
+ m_reply = 0;
+
+ setStatus(QDeclarativePlace::Ready);
+ } else {
+ QString errorString = m_reply->errorString();
+
+ m_reply->deleteLater();
+ m_reply = 0;
+
+ setStatus(QDeclarativePlace::Error, errorString);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlace::contactsModified(const QString &key, const QVariant &)
+{
+ primarySignalsEmission(key);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlace::cleanupDeletedCategories()
+{
+ foreach (QDeclarativeCategory * category, m_categoriesToBeDeleted) {
+ if (category->parent() == this)
+ delete category;
+ }
+ m_categoriesToBeDeleted.clear();
+}
+
+/*!
+ \qmlmethod void Place::getDetails()
+
+ This method starts fetching place details.
+
+ The \l status property will change to Place.Fetching while the fetch is in progress. On
+ success the object's properties will be updated, \l status will be set to Place.Ready and
+ \l detailsFetched will be set to true. On error \l status will be set to Place.Error. The
+ \l errorString() method can be used to get the details of the error.
+*/
+void QDeclarativePlace::getDetails()
+{
+ QPlaceManager *placeManager = manager();
+ if (!placeManager)
+ return;
+
+ m_reply = placeManager->getPlaceDetails(placeId());
+ connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ setStatus(QDeclarativePlace::Fetching);
+}
+
+/*!
+ \qmlmethod void Place::save()
+
+ This method performs a save operation on the place.
+
+ The \l status property will change to Place.Saving while the save operation is in progress. On
+ success the \l status will be set to Place.Ready. On error \l status will be set to Place.Error.
+ The \l errorString() method can be used to get the details of the error.
+
+ If the \l placeId property was previously empty, it will be assigned a valid value automatically
+ during a successful save operation.
+
+ Note that a \l PlaceSearchModel will call Place::getDetails on any place that it detects an update
+ on. A consequence of this is that whenever a Place from a \l PlaceSearchModel is successfully saved,
+ it will be followed by a fetch of place details, leading to a sequence of state changes
+ of \c Saving, \c Ready, \c Fetching, \c Ready.
+
+*/
+void QDeclarativePlace::save()
+{
+ QPlaceManager *placeManager = manager();
+ if (!placeManager)
+ return;
+
+ m_reply = placeManager->savePlace(place());
+ connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ setStatus(QDeclarativePlace::Saving);
+}
+
+/*!
+ \qmlmethod void Place::remove()
+
+ This method performs a remove operation on the place.
+
+ The \l status property will change to Place.Removing while the save operation is in progress.
+ On success \l status will be set to Place.Ready. On error \l status will be set to
+ Place.Error. The \l errorString() method can be used to get the details of the error.
+*/
+void QDeclarativePlace::remove()
+{
+ QPlaceManager *placeManager = manager();
+ if (!placeManager)
+ return;
+
+ m_reply = placeManager->removePlace(place().placeId());
+ connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ setStatus(QDeclarativePlace::Removing);
+}
+
+/*!
+ \qmlmethod string Place::errorString()
+
+ Returns a string description of the error of the last operation. If the last operation
+ completed successfully then the string is empty.
+*/
+QString QDeclarativePlace::errorString() const
+{
+ return m_errorString;
+}
+
+/*!
+ \qmlproperty string Place::primaryPhone
+
+ This property holds the primary phone number of the place. If no "phone" contact detail is
+ defined for this place, this property will be an empty string. It is equivalent to:
+
+
+ \snippet declarative/places.qml Place primaryPhone
+*/
+QString QDeclarativePlace::primaryPhone() const
+{
+ return primaryValue(QPlaceContactDetail::Phone);
+}
+
+/*!
+ \qmlproperty string Place::primaryFax
+
+ This property holds the primary fax number of the place. If no "fax" contact detail is
+ defined for this place this property will be an empty string. It is equivalent to
+
+ \snippet declarative/places.qml Place primaryFax
+*/
+QString QDeclarativePlace::primaryFax() const
+{
+ return primaryValue(QPlaceContactDetail::Fax);
+}
+
+/*!
+ \qmlproperty string Place::primaryEmail
+
+ This property holds the primary email address of the place. If no "email" contact detail is
+ defined for this place this property will be an empty string. It is equivalent to
+
+ \snippet declarative/places.qml Place primaryEmail
+*/
+QString QDeclarativePlace::primaryEmail() const
+{
+ return primaryValue(QPlaceContactDetail::Email);
+}
+
+/*!
+ \qmlproperty string Place::primaryWebsite
+
+ This property holds the primary website url of the place. If no "website" contact detail is
+ defined for this place this property will be an empty string. It is equivalent to
+
+ \snippet declarative/places.qml Place primaryWebsite
+*/
+
+QUrl QDeclarativePlace::primaryWebsite() const
+{
+ return QUrl(primaryValue(QPlaceContactDetail::Website));
+}
+
+/*!
+ \qmlproperty ExtendedAttributes Place::extendedAttributes
+
+ This property holds the extended attributes of a place. Extended attributes are additional
+ information about a place not covered by the place's properties.
+*/
+QQmlPropertyMap *QDeclarativePlace::extendedAttributes() const
+{
+ return m_extendedAttributes;
+}
+
+/*!
+ \qmlproperty ContactDetails Place::contactDetails
+
+ This property holds the contact information for this place, for example a phone number or
+ a website URL. This property is a map of \l ContactDetail objects.
+*/
+QDeclarativeContactDetails *QDeclarativePlace::contactDetails() const
+{
+ return m_contactDetails;
+}
+
+/*!
+ \qmlproperty list<Category> Place::categories
+
+ This property holds the list of categories this place is a member of. The categories that can
+ be assigned to a place are specific to each \l plugin.
+*/
+QQmlListProperty<QDeclarativeCategory> QDeclarativePlace::categories()
+{
+ return QQmlListProperty<QDeclarativeCategory>(this,
+ 0, // opaque data parameter
+ category_append,
+ category_count,
+ category_at,
+ category_clear);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlace::category_append(QQmlListProperty<QDeclarativeCategory> *prop,
+ QDeclarativeCategory *value)
+{
+ QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object);
+
+ if (object->m_categoriesToBeDeleted.contains(value))
+ object->m_categoriesToBeDeleted.removeAll(value);
+
+ if (!object->m_categories.contains(value)) {
+ object->m_categories.append(value);
+ QList<QPlaceCategory> list = object->m_src.categories();
+ list.append(value->category());
+ object->m_src.setCategories(list);
+
+ emit object->categoriesChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+int QDeclarativePlace::category_count(QQmlListProperty<QDeclarativeCategory> *prop)
+{
+ return static_cast<QDeclarativePlace *>(prop->object)->m_categories.count();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeCategory *QDeclarativePlace::category_at(QQmlListProperty<QDeclarativeCategory> *prop,
+ int index)
+{
+ QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object);
+ QDeclarativeCategory *res = NULL;
+ if (object->m_categories.count() > index && index > -1) {
+ res = object->m_categories[index];
+ }
+ return res;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlace::category_clear(QQmlListProperty<QDeclarativeCategory> *prop)
+{
+ QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object);
+ if (object->m_categories.isEmpty())
+ return;
+
+ for (int i = 0; i < object->m_categories.count(); ++i) {
+ if (object->m_categories.at(i)->parent() == object)
+ object->m_categoriesToBeDeleted.append(object->m_categories.at(i));
+ }
+
+ object->m_categories.clear();
+ object->m_src.setCategories(QList<QPlaceCategory>());
+ emit object->categoriesChanged();
+ QMetaObject::invokeMethod(object, "cleanupDeletedCategories", Qt::QueuedConnection);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlace::synchronizeCategories()
+{
+ qDeleteAll(m_categories);
+ m_categories.clear();
+ foreach (const QPlaceCategory &value, m_src.categories()) {
+ QDeclarativeCategory *declarativeValue = new QDeclarativeCategory(value, m_plugin, this);
+ m_categories.append(declarativeValue);
+ }
+}
+
+/*!
+ \qmlproperty enumeration Place::visibility
+
+ This property holds the visibility of the place. It can be one of:
+
+ \table
+ \row
+ \li Place.UnspecifiedVisibility
+ \li The visibility of the place is unspecified, the default visibility of the \l Plugin
+ will be used.
+ \row
+ \li Place.DeviceVisibility
+ \li The place is limited to the current device. The place will not be transferred off
+ of the device.
+ \row
+ \li Place.PrivateVisibility
+ \li The place is private to the current user. The place may be transferred to an online
+ service but is only ever visible to the current user.
+ \row
+ \li Place.PublicVisibility
+ \li The place is public.
+ \endtable
+
+ Note that visibility does not affect how the place is displayed
+ in the user-interface of an application on the device. Instead,
+ it defines the sharing semantics of the place.
+*/
+QDeclarativePlace::Visibility QDeclarativePlace::visibility() const
+{
+ return static_cast<QDeclarativePlace::Visibility>(m_src.visibility());
+}
+
+void QDeclarativePlace::setVisibility(Visibility visibility)
+{
+ if (static_cast<QDeclarativePlace::Visibility>(m_src.visibility()) == visibility)
+ return;
+
+ m_src.setVisibility(static_cast<QLocation::Visibility>(visibility));
+ emit visibilityChanged();
+}
+
+/*!
+ \qmlproperty Place Place::favorite
+
+ This property holds the favorite instance of a place.
+*/
+QDeclarativePlace *QDeclarativePlace::favorite() const
+{
+ return m_favorite;
+}
+
+void QDeclarativePlace::setFavorite(QDeclarativePlace *favorite)
+{
+
+ if (m_favorite == favorite)
+ return;
+
+ if (m_favorite && m_favorite->parent() == this)
+ delete m_favorite;
+
+ m_favorite = favorite;
+ emit favoriteChanged();
+}
+
+/*!
+ \qmlmethod void Place::copyFrom(Place original)
+
+ Copies data from an \a original place into this place. Only data that is supported by this
+ place's plugin is copied over and plugin specific data such as place identifier is not copied over.
+*/
+void QDeclarativePlace::copyFrom(QDeclarativePlace *original)
+{
+ QPlaceManager *placeManager = manager();
+ if (!placeManager)
+ return;
+
+ setPlace(placeManager->compatiblePlace(original->place()));
+}
+
+/*!
+ \qmlmethod void Place::initializeFavorite(Plugin destinationPlugin)
+
+ Creates a favorite instance for the place which is to be saved into the
+ \a destination plugin. This method does nothing if the favorite property is
+ not null.
+*/
+void QDeclarativePlace::initializeFavorite(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (m_favorite == 0) {
+ QDeclarativePlace *place = new QDeclarativePlace(this);
+ place->setPlugin(plugin);
+ place->copyFrom(this);
+ setFavorite(place);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlace::synchronizeExtendedAttributes()
+{
+ QStringList keys = m_extendedAttributes->keys();
+ foreach (const QString &key, keys)
+ m_extendedAttributes->clear(key);
+
+ QStringList attributeTypes = m_src.extendedAttributeTypes();
+ foreach (const QString &attributeType, attributeTypes) {
+ m_extendedAttributes->insert(attributeType,
+ qVariantFromValue(new QDeclarativePlaceAttribute(m_src.extendedAttribute(attributeType))));
+ }
+
+ emit extendedAttributesChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlace::synchronizeContacts()
+{
+ //clear out contact data
+ foreach (const QString &contactType, m_contactDetails->keys()) {
+ QList<QVariant> contacts = m_contactDetails->value(contactType).toList();
+ foreach (const QVariant &var, contacts) {
+ QObject *obj = var.value<QObject *>();
+ if (obj->parent() == this)
+ delete obj;
+ }
+ m_contactDetails->insert(contactType, QVariantList());
+ }
+
+ //insert new contact data from source place
+ foreach (const QString &contactType, m_src.contactTypes()) {
+ QList<QPlaceContactDetail> sourceContacts = m_src.contactDetails(contactType);
+ QVariantList declContacts;
+ foreach (const QPlaceContactDetail &sourceContact, sourceContacts) {
+ QDeclarativeContactDetail *declContact = new QDeclarativeContactDetail(this);
+ declContact->setContactDetail(sourceContact);
+ declContacts.append(QVariant::fromValue(qobject_cast<QObject *>(declContact)));
+ }
+ m_contactDetails->insert(contactType, declContacts);
+ }
+ primarySignalsEmission();
+}
+
+/*!
+ \internal
+ Helper function to emit the signals for the primary___()
+ fields. It is expected that the values of the primary___()
+ functions have already been modified to new values.
+*/
+void QDeclarativePlace::primarySignalsEmission(const QString &type)
+{
+ if (type.isEmpty() || type == QPlaceContactDetail::Phone) {
+ if (m_prevPrimaryPhone != primaryPhone()) {
+ m_prevPrimaryPhone = primaryPhone();
+ emit primaryPhoneChanged();
+ }
+ if (!type.isEmpty())
+ return;
+ }
+
+ if (type.isEmpty() || type == QPlaceContactDetail::Email) {
+ if (m_prevPrimaryEmail != primaryEmail()) {
+ m_prevPrimaryEmail = primaryEmail();
+ emit primaryEmailChanged();
+ }
+ if (!type.isEmpty())
+ return;
+ }
+
+ if (type.isEmpty() || type == QPlaceContactDetail::Website) {
+ if (m_prevPrimaryWebsite != primaryWebsite()) {
+ m_prevPrimaryWebsite = primaryWebsite();
+ emit primaryWebsiteChanged();
+ }
+ if (!type.isEmpty())
+ return;
+ }
+
+ if (type.isEmpty() || type == QPlaceContactDetail::Fax) {
+ if (m_prevPrimaryFax != primaryFax()) {
+ m_prevPrimaryFax = primaryFax();
+ emit primaryFaxChanged();
+ }
+ }
+}
+
+/*!
+ \internal
+ Helper function to return the manager, this manager is intended to be used
+ to perform the next operation. If a an operation is currently underway
+ then return a null pointer.
+*/
+QPlaceManager *QDeclarativePlace::manager()
+{
+ if (m_status != QDeclarativePlace::Ready && m_status != QDeclarativePlace::Error)
+ return 0;
+
+ if (m_reply) {
+ m_reply->abort();
+ m_reply->deleteLater();
+ m_reply = 0;
+ }
+
+ if (!m_plugin) {
+ qmlWarning(this) << QStringLiteral("Plugin is not assigned to place.");
+ return 0;
+ }
+
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return 0;
+
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+
+ if (!placeManager) {
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
+ .arg(m_plugin->name()).arg(serviceProvider->errorString()));
+ return 0;
+ }
+
+ return placeManager;
+}
+
+/*!
+ \internal
+*/
+QString QDeclarativePlace::primaryValue(const QString &contactType) const
+{
+ QVariant value = m_contactDetails->value(contactType);
+ if (value.userType() == qMetaTypeId<QJSValue>())
+ value = value.value<QJSValue>().toVariant();
+
+ if (value.userType() == QVariant::List) {
+ QVariantList detailList = m_contactDetails->value(contactType).toList();
+ if (!detailList.isEmpty()) {
+ QDeclarativeContactDetail *primaryDetail = qobject_cast<QDeclarativeContactDetail *>(detailList.at(0).value<QObject *>());
+ if (primaryDetail)
+ return primaryDetail->value();
+ }
+ } else if (value.userType() == QMetaType::QObjectStar) {
+ QDeclarativeContactDetail *primaryDetail = qobject_cast<QDeclarativeContactDetail *>(m_contactDetails->value(contactType).value<QObject *>());
+ if (primaryDetail)
+ return primaryDetail->value();
+ }
+
+ return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativeplace_p.h b/src/location/declarativeplaces/qdeclarativeplace_p.h
new file mode 100644
index 00000000..5a1470fe
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplace_p.h
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVEPLACE_P_H
+#define QDECLARATIVEPLACE_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/QObject>
+#include <QtQml/QQmlListProperty>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlPropertyMap>
+#include <QtLocation/QPlace>
+
+#include <QtPositioning/private/qdeclarativegeolocation_p.h>
+#include <QtLocation/private/qdeclarativecategory_p.h>
+#include <QtLocation/private/qdeclarativecontactdetail_p.h>
+#include <QtLocation/private/qdeclarativesupplier_p.h>
+#include <QtLocation/private/qdeclarativeratings_p.h>
+#include <QtLocation/private/qdeclarativereviewmodel_p.h>
+#include <QtLocation/private/qdeclarativeplaceimagemodel_p.h>
+#include <QtLocation/private/qdeclarativeplaceeditorialmodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlaceReply;
+
+class QPlaceManager;
+class QDeclarativePlaceIcon;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlace : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+
+ Q_ENUMS(Status Visibility)
+
+ Q_PROPERTY(QPlace place READ place WRITE setPlace)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeCategory> categories READ categories NOTIFY categoriesChanged)
+ Q_PROPERTY(QDeclarativeGeoLocation *location READ location WRITE setLocation NOTIFY locationChanged)
+ Q_PROPERTY(QDeclarativeRatings *ratings READ ratings WRITE setRatings NOTIFY ratingsChanged)
+ Q_PROPERTY(QDeclarativeSupplier *supplier READ supplier WRITE setSupplier NOTIFY supplierChanged)
+ Q_PROPERTY(QDeclarativePlaceIcon *icon READ icon WRITE setIcon NOTIFY iconChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QString placeId READ placeId WRITE setPlaceId NOTIFY placeIdChanged)
+ Q_PROPERTY(QString attribution READ attribution WRITE setAttribution NOTIFY attributionChanged)
+
+ Q_PROPERTY(QDeclarativeReviewModel *reviewModel READ reviewModel NOTIFY reviewModelChanged)
+ Q_PROPERTY(QDeclarativePlaceImageModel *imageModel READ imageModel NOTIFY imageModelChanged)
+ Q_PROPERTY(QDeclarativePlaceEditorialModel *editorialModel READ editorialModel NOTIFY editorialModelChanged)
+
+ Q_PROPERTY(QObject *extendedAttributes READ extendedAttributes NOTIFY extendedAttributesChanged)
+ Q_PROPERTY(QObject *contactDetails READ contactDetails NOTIFY contactDetailsChanged)
+ Q_PROPERTY(bool detailsFetched READ detailsFetched NOTIFY detailsFetchedChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+
+ Q_PROPERTY(QString primaryPhone READ primaryPhone NOTIFY primaryPhoneChanged)
+ Q_PROPERTY(QString primaryFax READ primaryFax NOTIFY primaryFaxChanged)
+ Q_PROPERTY(QString primaryEmail READ primaryEmail NOTIFY primaryEmailChanged)
+ Q_PROPERTY(QUrl primaryWebsite READ primaryWebsite NOTIFY primaryWebsiteChanged)
+
+ Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
+ Q_PROPERTY(QDeclarativePlace *favorite READ favorite WRITE setFavorite NOTIFY favoriteChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativePlace(QObject *parent = 0);
+ QDeclarativePlace(const QPlace &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent = 0);
+ ~QDeclarativePlace();
+
+ enum Status {Ready, Saving, Fetching, Removing, Error};
+ enum Visibility {
+ UnspecifiedVisibility = QLocation::UnspecifiedVisibility,
+ DeviceVisibility = QLocation::DeviceVisibility,
+ PrivateVisibility = QLocation::PrivateVisibility,
+ PublicVisibility = QLocation::PublicVisibility
+ };
+
+ //From QQmlParserStatus
+ virtual void classBegin() {}
+ virtual void componentComplete();
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ QDeclarativeReviewModel *reviewModel();
+ QDeclarativePlaceImageModel *imageModel();
+ QDeclarativePlaceEditorialModel *editorialModel();
+
+ QPlace place();
+ void setPlace(const QPlace &src);
+
+ QQmlListProperty<QDeclarativeCategory> categories();
+ static void category_append(QQmlListProperty<QDeclarativeCategory> *prop,
+ QDeclarativeCategory *value);
+ static int category_count(QQmlListProperty<QDeclarativeCategory> *prop);
+ static QDeclarativeCategory *category_at(QQmlListProperty<QDeclarativeCategory> *prop, int index);
+ static void category_clear(QQmlListProperty<QDeclarativeCategory> *prop);
+
+ QDeclarativeGeoLocation *location();
+ void setLocation(QDeclarativeGeoLocation *location);
+ QDeclarativeRatings *ratings();
+ void setRatings(QDeclarativeRatings *ratings);
+ QDeclarativeSupplier *supplier() const;
+ void setSupplier(QDeclarativeSupplier *supplier);
+ QDeclarativePlaceIcon *icon() const;
+ void setIcon(QDeclarativePlaceIcon *icon);
+ QString name() const;
+ void setName(const QString &name);
+ QString placeId() const;
+ void setPlaceId(const QString &placeId);
+ QString attribution() const;
+ void setAttribution(const QString &attribution);
+ bool detailsFetched() const;
+
+ Status status() const;
+ void setStatus(Status status, const QString &errorString = QString());
+
+ Q_INVOKABLE void getDetails();
+ Q_INVOKABLE void save();
+ Q_INVOKABLE void remove();
+ Q_INVOKABLE QString errorString() const;
+
+ QString primaryPhone() const;
+ QString primaryFax() const;
+ QString primaryEmail() const;
+ QUrl primaryWebsite() const;
+
+ QQmlPropertyMap *extendedAttributes() const;
+
+ QDeclarativeContactDetails *contactDetails() const;
+
+ Visibility visibility() const;
+ void setVisibility(Visibility visibility);
+
+ QDeclarativePlace *favorite() const;
+ void setFavorite(QDeclarativePlace *favorite);
+
+ Q_INVOKABLE void copyFrom(QDeclarativePlace *original);
+ Q_INVOKABLE void initializeFavorite(QDeclarativeGeoServiceProvider *plugin);
+
+Q_SIGNALS:
+ void pluginChanged();
+ void categoriesChanged();
+ void locationChanged();
+ void ratingsChanged();
+ void supplierChanged();
+ void iconChanged();
+ void nameChanged();
+ void placeIdChanged();
+ void attributionChanged();
+ void detailsFetchedChanged();
+ void reviewModelChanged();
+ void imageModelChanged();
+ void editorialModelChanged();
+
+ void primaryPhoneChanged();
+ void primaryFaxChanged();
+ void primaryEmailChanged();
+ void primaryWebsiteChanged();
+
+ void extendedAttributesChanged();
+ void contactDetailsChanged();
+ void statusChanged();
+ void visibilityChanged();
+ void favoriteChanged();
+
+private Q_SLOTS:
+ void finished();
+ void contactsModified(const QString &, const QVariant &);
+ void pluginReady();
+ void cleanupDeletedCategories();
+private:
+ void synchronizeCategories();
+ void synchronizeExtendedAttributes();
+ void synchronizeContacts();
+ void primarySignalsEmission(const QString &type = QString());
+ QString primaryValue(const QString &contactType) const;
+
+private:
+ QPlaceManager *manager();
+
+ QList<QDeclarativeCategory *> m_categories;
+ QDeclarativeGeoLocation *m_location;
+ QDeclarativeRatings *m_ratings;
+ QDeclarativeSupplier *m_supplier;
+ QDeclarativePlaceIcon *m_icon;
+ QDeclarativeReviewModel *m_reviewModel;
+ QDeclarativePlaceImageModel *m_imageModel;
+ QDeclarativePlaceEditorialModel *m_editorialModel;
+ QQmlPropertyMap *m_extendedAttributes;
+ QDeclarativeContactDetails *m_contactDetails;
+
+ QPlace m_src;
+
+ QPlaceReply *m_reply;
+
+ QDeclarativeGeoServiceProvider *m_plugin;
+ bool m_complete;
+
+ QString m_prevPrimaryPhone;
+ QString m_prevPrimaryEmail;
+ QString m_prevPrimaryFax;
+ QUrl m_prevPrimaryWebsite;
+
+ QDeclarativePlace *m_favorite;
+
+ Status m_status;
+ QString m_errorString;
+
+ QList<QDeclarativeCategory *>m_categoriesToBeDeleted;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePlace)
+
+#endif // QDECLARATIVEPLACE_P_H
diff --git a/src/location/declarativeplaces/qdeclarativeplaceattribute.cpp b/src/location/declarativeplaces/qdeclarativeplaceattribute.cpp
new file mode 100644
index 00000000..20adbafb
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceattribute.cpp
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** 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 "qdeclarativeplaceattribute_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ExtendedAttributes
+ \instantiates QQmlPropertyMap
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief The ExtendedAttributes type holds additional data about a \l Place.
+
+ The ExtendedAttributes type is a map of \l {PlaceAttribute}{PlaceAttributes}. To access
+ attributes in the map use the \l keys() method to get the list of keys stored in the map and
+ use the \c {[]} operator to access the \l PlaceAttribute items.
+
+ The following are standard keys that are defined by the API. \l Plugin
+ implementations are free to define additional keys. Custom keys should
+ be qualified by a unique prefix to avoid clashes.
+ \table
+ \header
+ \li key
+ \li description
+ \row
+ \li openingHours
+ \li The trading hours of the place
+ \row
+ \li payment
+ \li The types of payment the place accepts, for example visa, mastercard.
+ \row
+ \li x_provider
+ \li The name of the provider that a place is sourced from
+ \row
+ \li x_id_<provider> (for example x_id_here)
+ \li An alternative identifier which identifies the place from the
+ perspective of the specified provider.
+ \endtable
+
+ Some plugins may not support attributes at all, others may only support a
+ certain set, others still may support a dynamically changing set of attributes
+ over time or even allow attributes to be arbitrarily defined by the client
+ application. The attributes could also vary on a place by place basis,
+ for example one place may have opening hours while another does not.
+ Consult the \l {Plugin References and Parameters}{plugin
+ references} for details.
+
+ Some attributes may not be intended to be readable by end users, the label field
+ of such attributes is empty to indicate this fact.
+
+ \note ExtendedAttributes instances are only ever used in the context of \l {Place}s. It is not
+ possible to create an ExtendedAttributes instance directly or re-assign a \l {Place}'s
+ ExtendedAttributes property. Modification of ExtendedAttributes can only be accomplished
+ via Javascript.
+
+ The following example shows how to access all \l {PlaceAttribute}{PlaceAttributes} and print
+ them to the console:
+
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml ExtendedAttributes read
+
+ The following example shows how to assign and modify an attribute:
+ \snippet declarative/places.qml ExtendedAttributes write
+
+ \sa PlaceAttribute, QQmlPropertyMap
+*/
+
+/*!
+ \qmlmethod variant ExtendedAttributes::keys()
+
+ Returns an array of place attribute keys currently stored in the map.
+*/
+
+/*!
+ \qmlsignal void ExtendedAttributes::valueChanged(string key, variant value)
+
+ This signal is emitted when the set of attributes changes. \a key is the key
+ corresponding to the \a value that was changed.
+
+ The corresponding handler is \c onValueChanged.
+*/
+
+/*!
+ \qmltype PlaceAttribute
+ \instantiates QDeclarativePlaceAttribute
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief The PlaceAttribute type holds generic place attribute information.
+
+ A place attribute stores an additional piece of information about a \l Place that is not
+ otherwise exposed through the \l Place type. A PlaceAttribute is a textual piece of data,
+ accessible through the \l text property, and a \l label. Both the \l text and \l label
+ properties are intended to be displayed to the user. PlaceAttributes are stored in an
+ \l ExtendedAttributes map with a unique key.
+
+ The following example shows how to display all attributes in a list:
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml ExtendedAttributes
+
+ The following example shows how to assign and modify an attribute:
+ \snippet declarative/places.qml ExtendedAttributes write
+*/
+
+QDeclarativePlaceAttribute::QDeclarativePlaceAttribute(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QDeclarativePlaceAttribute::QDeclarativePlaceAttribute(const QPlaceAttribute &src, QObject *parent)
+ : QObject(parent),m_attribute(src)
+{
+}
+
+QDeclarativePlaceAttribute::~QDeclarativePlaceAttribute()
+{
+}
+
+/*!
+ \qmlproperty QPlaceAttribute PlaceAttribute::attribute
+
+ For details on how to use this property to interface between C++ and QML see
+ "\l {PlaceAttribute - QPlaceAttribute} {Interfaces between C++ and QML Code}".
+*/
+void QDeclarativePlaceAttribute::setAttribute(const QPlaceAttribute &src)
+{
+ QPlaceAttribute prevAttribute = m_attribute;
+ m_attribute = src;
+
+ if (m_attribute.label() != prevAttribute.label())
+ emit labelChanged();
+ if (m_attribute.text() != prevAttribute.text())
+ emit textChanged();
+}
+
+QPlaceAttribute QDeclarativePlaceAttribute::attribute() const
+{
+ return m_attribute;
+}
+
+/*!
+ \qmlproperty string PlaceAttribute::label
+
+ This property holds the attribute label which is a user visible string
+ describing the attribute.
+*/
+void QDeclarativePlaceAttribute::setLabel(const QString &label)
+{
+ if (m_attribute.label() != label) {
+ m_attribute.setLabel(label);
+ emit labelChanged();
+ }
+}
+
+QString QDeclarativePlaceAttribute::label() const
+{
+ return m_attribute.label();
+}
+
+/*!
+ \qmlproperty string PlaceAttribute::text
+
+ This property holds the attribute text which can be used to show additional information about the place.
+*/
+void QDeclarativePlaceAttribute::setText(const QString &text)
+{
+ if (m_attribute.text() != text) {
+ m_attribute.setText(text);
+ emit textChanged();
+ }
+}
+
+QString QDeclarativePlaceAttribute::text() const
+{
+ return m_attribute.text();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativeplaceattribute_p.h b/src/location/declarativeplaces/qdeclarativeplaceattribute_p.h
new file mode 100644
index 00000000..8079df9c
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceattribute_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVEPLACEATTRIBUTE_P_H
+#define QDECLARATIVEPLACEATTRIBUTE_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 <QObject>
+#include <QtQml/qqml.h>
+#include <QString>
+
+#include <QtLocation/qplaceattribute.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceAttribute : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPlaceAttribute attribute READ attribute WRITE setAttribute)
+ Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+
+public:
+ explicit QDeclarativePlaceAttribute(QObject *parent = 0);
+ explicit QDeclarativePlaceAttribute(const QPlaceAttribute &src, QObject *parent = 0);
+ ~QDeclarativePlaceAttribute();
+
+ QPlaceAttribute attribute() const;
+ void setAttribute(const QPlaceAttribute &place);
+
+ QString text() const;
+ void setText(const QString &text);
+
+
+ QString label() const;
+ void setLabel(const QString &label);
+
+Q_SIGNALS:
+ void labelChanged();
+ void textChanged();
+
+private:
+ QPlaceAttribute m_attribute;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePlaceAttribute)
+
+#endif
diff --git a/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp b/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp
new file mode 100644
index 00000000..faf7e418
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplacecontentmodel.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 "qdeclarativeplacecontentmodel_p.h"
+#include "qdeclarativeplace_p.h"
+#include "qdeclarativegeoserviceprovider_p.h"
+#include "qdeclarativeplaceuser_p.h"
+#include "error_messages.h"
+
+#include <QtQml/QQmlInfo>
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/QPlaceManager>
+#include <QtLocation/QPlaceContentRequest>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativePlaceContentModel::QDeclarativePlaceContentModel(QPlaceContent::Type type,
+ QObject *parent)
+: QAbstractListModel(parent), m_place(0), m_type(type), m_batchSize(1), m_contentCount(-1),
+ m_reply(0), m_complete(false)
+{
+}
+
+QDeclarativePlaceContentModel::~QDeclarativePlaceContentModel()
+{
+}
+
+/*!
+ \internal
+*/
+QDeclarativePlace *QDeclarativePlaceContentModel::place() const
+{
+ return m_place;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceContentModel::setPlace(QDeclarativePlace *place)
+{
+ if (m_place != place) {
+ beginResetModel();
+
+ int initialCount = m_contentCount;
+ clearData();
+ m_place = place;
+ endResetModel();
+
+ emit placeChanged();
+ if (initialCount != -1)
+ emit totalCountChanged();
+
+ fetchMore(QModelIndex());
+ }
+}
+
+/*!
+ \internal
+*/
+int QDeclarativePlaceContentModel::batchSize() const
+{
+ return m_batchSize;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceContentModel::setBatchSize(int batchSize)
+{
+ if (m_batchSize != batchSize) {
+ m_batchSize = batchSize;
+ emit batchSizeChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+int QDeclarativePlaceContentModel::totalCount() const
+{
+ return m_contentCount;
+}
+
+/*!
+ \internal
+ Clears the model data but does not reset it.
+*/
+void QDeclarativePlaceContentModel::clearData()
+{
+ qDeleteAll(m_users);
+ m_users.clear();
+
+ qDeleteAll(m_suppliers);
+ m_suppliers.clear();
+
+ m_content.clear();
+
+ m_contentCount = -1;
+
+ if (m_reply) {
+ m_reply->abort();
+ m_reply->deleteLater();
+ m_reply = 0;
+ }
+
+ m_nextRequest.clear();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceContentModel::initializeCollection(int totalCount, const QPlaceContent::Collection &collection)
+{
+ beginResetModel();
+
+ int initialCount = m_contentCount;
+ clearData();
+
+ QMapIterator<int, QPlaceContent> i(collection);
+ while (i.hasNext()) {
+ i.next();
+
+ const QPlaceContent &content = i.value();
+ if (content.type() != m_type)
+ continue;
+
+ m_content.insert(i.key(), content);
+ if (!m_suppliers.contains(content.supplier().supplierId())) {
+ m_suppliers.insert(content.supplier().supplierId(),
+ new QDeclarativeSupplier(content.supplier(), m_place->plugin(), this));
+ }
+ if (!m_users.contains(content.user().userId())) {
+ m_users.insert(content.user().userId(),
+ new QDeclarativePlaceUser(content.user(), this));
+ }
+ }
+
+ m_contentCount = totalCount;
+
+ if (initialCount != totalCount)
+ emit totalCountChanged();
+
+ endResetModel();
+}
+
+/*!
+ \internal
+*/
+int QDeclarativePlaceContentModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_content.count();
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativePlaceContentModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.row() >= rowCount(index.parent()) || index.row() < 0)
+ return QVariant();
+
+ const QPlaceContent &content = m_content.value(index.row());
+
+ switch (role) {
+ case SupplierRole:
+ return QVariant::fromValue(static_cast<QObject *>(m_suppliers.value(content.supplier().supplierId())));
+ case PlaceUserRole:
+ return QVariant::fromValue(static_cast<QObject *>(m_users.value(content.user().userId())));
+ case AttributionRole:
+ return content.attribution();
+ default:
+ return QVariant();
+ }
+}
+
+QHash<int, QByteArray> QDeclarativePlaceContentModel::roleNames() const
+{
+ QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
+ roles.insert(SupplierRole, "supplier");
+ roles.insert(PlaceUserRole, "user");
+ roles.insert(AttributionRole, "attribution");
+ return roles;
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativePlaceContentModel::canFetchMore(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return false;
+
+ if (!m_place)
+ return false;
+
+ if (m_contentCount == -1)
+ return true;
+
+ return m_content.count() != m_contentCount;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceContentModel::fetchMore(const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return;
+
+ if (!m_place)
+ return;
+
+ if (m_reply)
+ return;
+
+ if (!m_place->plugin())
+ return;
+
+ QDeclarativeGeoServiceProvider *plugin = m_place->plugin();
+
+ QGeoServiceProvider *serviceProvider = plugin->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return;
+
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (!placeManager)
+ return;
+
+ if (m_nextRequest == QPlaceContentRequest()) {
+ QPlaceContentRequest request;
+ request.setContentType(m_type);
+ request.setPlaceId(m_place->place().placeId());
+ request.setLimit(m_batchSize);
+
+ m_reply = placeManager->getPlaceContent(request);
+ } else {
+ m_reply = placeManager->getPlaceContent(m_nextRequest);
+ }
+
+ connect(m_reply, SIGNAL(finished()), this, SLOT(fetchFinished()), Qt::QueuedConnection);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceContentModel::classBegin()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceContentModel::componentComplete()
+{
+ m_complete = true;
+ fetchMore(QModelIndex());
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceContentModel::fetchFinished()
+{
+ if (!m_reply)
+ return;
+
+ QPlaceContentReply *reply = m_reply;
+ m_reply = 0;
+
+ m_nextRequest = reply->nextPageRequest();
+
+ if (m_contentCount != reply->totalCount()) {
+ m_contentCount = reply->totalCount();
+ emit totalCountChanged();
+ }
+
+ if (!reply->content().isEmpty()) {
+ QPlaceContent::Collection contents = reply->content();
+
+ //find out which indexes are new and which ones have changed.
+ QMapIterator<int, QPlaceContent> it(contents);
+ QList<int> changedIndexes;
+ QList<int> newIndexes;
+ while (it.hasNext()) {
+ it.next();
+ if (!m_content.contains(it.key()))
+ newIndexes.append(it.key());
+ else if (it.value() != m_content.value(it.key()))
+ changedIndexes.append(it.key());
+ }
+
+ //insert new indexes in blocks where within each
+ //block, the indexes are consecutive.
+ QListIterator<int> newIndexesIter(newIndexes);
+ int startIndex = -1;
+ while (newIndexesIter.hasNext()) {
+ int currentIndex = newIndexesIter.next();
+ if (startIndex == -1)
+ startIndex = currentIndex;
+
+ if (!newIndexesIter.hasNext() || (newIndexesIter.hasNext() && (newIndexesIter.peekNext() > (currentIndex + 1)))) {
+ beginInsertRows(QModelIndex(),startIndex,currentIndex);
+ for (int i = startIndex; i <= currentIndex; ++i) {
+ const QPlaceContent &content = contents.value(i);
+
+ m_content.insert(i, content);
+ if (!m_suppliers.contains(content.supplier().supplierId())) {
+ m_suppliers.insert(content.supplier().supplierId(),
+ new QDeclarativeSupplier(content.supplier(), m_place->plugin(), this));
+ }
+ if (!m_users.contains(content.user().userId())) {
+ m_users.insert(content.user().userId(),
+ new QDeclarativePlaceUser(content.user(), this));
+ }
+ }
+ endInsertRows();
+ startIndex = -1;
+ }
+ }
+
+ //modify changed indexes in blocks where within each
+ //block, the indexes are consecutive.
+ startIndex = -1;
+ QListIterator<int> changedIndexesIter(changedIndexes);
+ while (changedIndexesIter.hasNext()) {
+ int currentIndex = changedIndexesIter.next();
+ if (startIndex == -1)
+ startIndex = currentIndex;
+
+ if (!changedIndexesIter.hasNext() || (changedIndexesIter.hasNext() && changedIndexesIter.peekNext() > (currentIndex + 1))) {
+ for (int i = startIndex; i <= currentIndex; ++i) {
+ const QPlaceContent &content = contents.value(i);
+ m_content.insert(i, content);
+ if (!m_suppliers.contains(content.supplier().supplierId())) {
+ m_suppliers.insert(content.supplier().supplierId(),
+ new QDeclarativeSupplier(content.supplier(), m_place->plugin(), this));
+ }
+ if (!m_users.contains(content.user().userId())) {
+ m_users.insert(content.user().userId(),
+ new QDeclarativePlaceUser(content.user(), this));
+ }
+ }
+ emit dataChanged(index(startIndex),index(currentIndex));
+ startIndex = -1;
+ }
+ }
+
+ // The fetch didn't add any new content and we haven't fetched all content yet. This is
+ // likely due to the model being prepopulated by Place::getDetails(). Keep fetching more
+ // data until new content is available.
+ if (newIndexes.isEmpty() && m_content.count() != m_contentCount)
+ fetchMore(QModelIndex());
+ }
+
+ reply->deleteLater();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h b/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h
new file mode 100644
index 00000000..a8ed2fdb
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplacecontentmodel_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 QDECLARATIVEPLACECONTENTMODEL_H
+#define QDECLARATIVEPLACECONTENTMODEL_H
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtCore/QAbstractListModel>
+#include <QtQml/QQmlParserStatus>
+#include <QtLocation/QPlaceContent>
+#include <QtLocation/QPlaceContentReply>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePlace;
+class QDeclarativeGeoServiceProvider;
+class QGeoServiceProvider;
+class QDeclarativeSupplier;
+class QDeclarativePlaceUser;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceContentModel : public QAbstractListModel, public QQmlParserStatus
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativePlace *place READ place WRITE setPlace NOTIFY placeChanged)
+ Q_PROPERTY(int batchSize READ batchSize WRITE setBatchSize NOTIFY batchSizeChanged)
+ Q_PROPERTY(int totalCount READ totalCount NOTIFY totalCountChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativePlaceContentModel(QPlaceContent::Type type, QObject *parent = 0);
+ ~QDeclarativePlaceContentModel();
+
+ QDeclarativePlace *place() const;
+ void setPlace(QDeclarativePlace *place);
+
+ int batchSize() const;
+ void setBatchSize(int batchSize);
+
+ int totalCount() const;
+
+ void clearData();
+
+ void initializeCollection(int totalCount, const QPlaceContent::Collection &collection);
+
+ // from QAbstractListModel
+ int rowCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QHash<int, QByteArray> roleNames() const;
+
+ enum Roles {
+ SupplierRole = Qt::UserRole,
+ PlaceUserRole,
+ AttributionRole,
+ UserRole //indicator for next conten type specific role
+ };
+
+ bool canFetchMore(const QModelIndex &parent) const;
+ void fetchMore(const QModelIndex &parent);
+
+ // from QQmlParserStatus
+ void classBegin();
+ void componentComplete();
+
+Q_SIGNALS:
+ void placeChanged();
+ void batchSizeChanged();
+ void totalCountChanged();
+
+private Q_SLOTS:
+ void fetchFinished();
+
+protected:
+ QPlaceContent::Collection m_content;
+ QMap<QString, QDeclarativeSupplier *> m_suppliers;
+ QMap<QString, QDeclarativePlaceUser *>m_users;
+
+private:
+ QDeclarativePlace *m_place;
+ QPlaceContent::Type m_type;
+ int m_batchSize;
+ int m_contentCount;
+
+ QPlaceContentReply *m_reply;
+ QPlaceContentRequest m_nextRequest;
+
+ bool m_complete;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEPLACECONTENTMODEL_H
diff --git a/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp
new file mode 100644
index 00000000..dbc23737
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** 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 "qdeclarativeplaceeditorialmodel_p.h"
+
+#include <QtCore/QUrl>
+#include <QtLocation/QPlaceEditorial>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype EditorialModel
+ \instantiates QDeclarativePlaceEditorialModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-models
+ \since Qt Location 5.5
+
+ \brief The EditorialModel type provides a model of place editorials.
+
+ The EditorialModel is a read-only model used to fetch editorials related to a \l Place.
+ Binding a \l Place via \l EditorialModel::place initiates an initial fetch of editorials.
+ The model performs fetches incrementally and is intended to be used in conjunction
+ with a View such as a \l ListView. When the View reaches the last of the editorials
+ currently in the model, a fetch is performed to retrieve more if they are available.
+ The View is automatically updated as the editorials are received. The number of
+ editorials which are fetched at a time is specified by the \l batchSize property.
+ The total number of editorials available can be accessed via the \l totalCount property.
+
+ The model returns data for the following roles:
+
+ \table
+ \header
+ \li Role
+ \li Type
+ \li Description
+ \row
+ \li text
+ \li string
+ \li The editorial's textual description of the place. It can be either rich (HTML based) text or plain text
+ depending upon the provider.
+ \row
+ \li title
+ \li string
+ \li The title of the editorial.
+ \row
+ \li language
+ \li string
+ \li The language that the editorial is written in.
+ \row
+ \li supplier
+ \li \l Supplier
+ \li The supplier of the editorial.
+ \row
+ \li user
+ \li \l {QtLocation::User}{User}
+ \li The user who contributed the editorial.
+ \row
+ \li attribution
+ \li string
+ \li Attribution text which must be displayed when displaying the editorial.
+ \endtable
+
+ \section1 Example
+
+ The following example shows how to display editorials for a place:
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml EditorialModel
+
+*/
+
+/*!
+ \qmlproperty Place EditorialModel::place
+
+ This property holds the Place that the editorials are for.
+*/
+
+/*!
+ \qmlproperty int EditorialModel::batchSize
+
+ This property holds the batch size to use when fetching more editorials items.
+*/
+
+/*!
+ \qmlproperty int EditorialModel::totalCount
+
+ This property holds the total number of editorial items for the place.
+*/
+
+QDeclarativePlaceEditorialModel::QDeclarativePlaceEditorialModel(QObject *parent)
+: QDeclarativePlaceContentModel(QPlaceContent::EditorialType, parent)
+{
+}
+
+QDeclarativePlaceEditorialModel::~QDeclarativePlaceEditorialModel()
+{
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativePlaceEditorialModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.row() >= rowCount(index.parent()) || index.row() < 0)
+ return QVariant();
+
+ const QPlaceEditorial &description = m_content.value(index.row());
+
+ switch (role) {
+ case TextRole:
+ return description.text();
+ case TitleRole:
+ return description.title();
+ case LanguageRole:
+ return description.language();
+ }
+
+ return QDeclarativePlaceContentModel::data(index, role);
+}
+
+QHash<int, QByteArray> QDeclarativePlaceEditorialModel::roleNames() const
+{
+ QHash<int, QByteArray> roleNames = QDeclarativePlaceContentModel::roleNames();
+ roleNames.insert(TextRole, "text");
+ roleNames.insert(TitleRole, "title");
+ roleNames.insert(LanguageRole, "language");
+ return roleNames;
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h
new file mode 100644
index 00000000..f574677a
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVEPLACEEDITORIALMODEL_H
+#define QDECLARATIVEPLACEEDITORIALMODEL_H
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativeplacecontentmodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceEditorialModel : public QDeclarativePlaceContentModel
+{
+ Q_OBJECT
+
+public:
+ explicit QDeclarativePlaceEditorialModel(QObject *parent = 0);
+ ~QDeclarativePlaceEditorialModel();
+
+ QVariant data(const QModelIndex &index, int role) const;
+ QHash<int, QByteArray> roleNames() const;
+
+ enum Roles {
+ TextRole = UserRole,
+ TitleRole,
+ LanguageRole
+ };
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEPLACEEDITORIALMODEL_H
diff --git a/src/location/declarativeplaces/qdeclarativeplaceicon.cpp b/src/location/declarativeplaces/qdeclarativeplaceicon.cpp
new file mode 100644
index 00000000..24891138
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceicon.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** 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 "qdeclarativeplaceicon_p.h"
+#include "error_messages.h"
+
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/QPlaceManager>
+#include <QtQml/QQmlInfo>
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Icon
+ \instantiates QDeclarativePlaceIcon
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief The Icon type represents an icon image source which can have multiple sizes.
+
+ The Icon type can be used in conjunction with an \l Image type to display an icon.
+ The \l url() function is used to construct an icon URL of a requested size,
+ the icon which most closely matches the requested size is returned.
+
+ The Icon type also has a parameters map which is a set of key value pairs. The precise
+ keys to use depend on the
+ \l {Qt Location#Plugin References and Parameters}{plugin} being used.
+ The parameters map is used by the \l Plugin to determine which URL to return.
+
+ In the case where an icon can only possibly have one image URL, the
+ parameter key of \c "singleUrl" can be used with a QUrl value. Any Icon with this
+ parameter will always return the specified URL regardless of the requested icon
+ size and not defer to any Plugin.
+
+ The following code shows how to display a 64x64 pixel icon:
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml Icon
+
+ Alternatively, a default sized icon can be specified like so:
+ \snippet declarative/places.qml Icon default
+*/
+
+QDeclarativePlaceIcon::QDeclarativePlaceIcon(QObject *parent)
+: QObject(parent), m_plugin(0), m_parameters(new QQmlPropertyMap(this))
+{
+}
+
+QDeclarativePlaceIcon::QDeclarativePlaceIcon(const QPlaceIcon &icon, QDeclarativeGeoServiceProvider *plugin, QObject *parent)
+: QObject(parent), m_parameters(new QQmlPropertyMap(this))
+{
+ if (icon.isEmpty())
+ m_plugin = 0;
+ else
+ m_plugin = plugin;
+
+ initParameters(icon.parameters());
+}
+
+QDeclarativePlaceIcon::~QDeclarativePlaceIcon()
+{
+}
+
+/*!
+ \qmlproperty QPlaceIcon Icon::icon
+
+ For details on how to use this property to interface between C++ and QML see
+ "\l {Icon - QPlaceIcon} {Interfaces between C++ and QML Code}".
+*/
+QPlaceIcon QDeclarativePlaceIcon::icon() const
+{
+ QPlaceIcon result;
+
+ if (m_plugin)
+ result.setManager(manager());
+ else
+ result.setManager(0);
+
+ QVariantMap params;
+ foreach (const QString &key, m_parameters->keys()) {
+ const QVariant value = m_parameters->value(key);
+ if (value.isValid()) {
+ params.insert(key, value);
+ }
+ }
+
+ result.setParameters(params);
+
+ return result;
+}
+
+void QDeclarativePlaceIcon::setIcon(const QPlaceIcon &src)
+{
+ initParameters(src.parameters());
+}
+
+/*!
+ \qmlmethod url Icon::url(size size)
+
+ Returns a URL for the icon image that most closely matches the given \a size.
+
+ If no plugin has been assigned to the icon, and the parameters do not contain the 'singleUrl' key, a default constructed URL
+ is returned.
+
+*/
+QUrl QDeclarativePlaceIcon::url(const QSize &size) const
+{
+ return icon().url(size);
+}
+
+/*!
+ \qmlproperty Object Icon::parameters
+
+ This property holds the parameters of the icon and is a map. These parameters
+ are used by the plugin to return the appropriate URL when url() is called and to
+ specify locations to save to when saving icons.
+
+ Consult the \l {Qt Location#Plugin References and Parameters}{plugin documentation}
+ for what parameters are supported and how they should be used.
+
+ Note, due to limitations of the QQmlPropertyMap, it is not possible
+ to declaratively specify the parameters in QML, assignment of parameters keys
+ and values can only be accomplished by JavaScript.
+
+*/
+QQmlPropertyMap *QDeclarativePlaceIcon::parameters() const
+{
+ return m_parameters;
+}
+
+/*!
+ \qmlproperty Plugin Icon::plugin
+
+ The property holds the plugin that is responsible for managing this icon.
+*/
+QDeclarativeGeoServiceProvider *QDeclarativePlaceIcon::plugin() const
+{
+ return m_plugin;
+}
+
+void QDeclarativePlaceIcon::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (m_plugin == plugin)
+ return;
+
+ m_plugin = plugin;
+ emit pluginChanged();
+
+ if (!m_plugin)
+ return;
+
+ if (m_plugin->isAttached()) {
+ pluginReady();
+ } else {
+ connect(m_plugin, SIGNAL(attached()),
+ this, SLOT(pluginReady()));
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceIcon::pluginReady()
+{
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) {
+ qmlWarning(this) << QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
+ .arg(m_plugin->name()).arg(serviceProvider->errorString());
+ return;
+ }
+}
+
+/*!
+ \internal
+ Helper function to return the manager from the plugin
+*/
+QPlaceManager *QDeclarativePlaceIcon::manager() const
+{
+ if (!m_plugin) {
+ qmlWarning(this) << QStringLiteral("Plugin is not assigned to place.");
+ return 0;
+ }
+
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (!serviceProvider)
+ return 0;
+
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+
+ if (!placeManager)
+ return 0;
+
+ return placeManager;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePlaceIcon::initParameters(const QVariantMap &parameterMap)
+{
+ //clear out old parameters
+ foreach (const QString &key, m_parameters->keys())
+ m_parameters->clear(key);
+
+ foreach (const QString &key, parameterMap.keys()) {
+ QVariant value = parameterMap.value(key);
+ m_parameters->insert(key, value);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativeplaceicon_p.h b/src/location/declarativeplaces/qdeclarativeplaceicon_p.h
new file mode 100644
index 00000000..535d98eb
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceicon_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVEPLACEICON_P_H
+#define QDECLARATIVEPLACEICON_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/qdeclarativegeoserviceprovider_p.h>
+
+#include <QtLocation/qplaceicon.h>
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlPropertyMap>
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlPropertyMap;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceIcon : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPlaceIcon icon READ icon WRITE setIcon)
+ Q_PROPERTY(QObject *parameters READ parameters NOTIFY parametersChanged)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+
+public:
+ explicit QDeclarativePlaceIcon(QObject *parent = 0);
+ QDeclarativePlaceIcon(const QPlaceIcon &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent = 0);
+ ~QDeclarativePlaceIcon();
+
+ QPlaceIcon icon() const;
+ void setIcon(const QPlaceIcon &src);
+
+ Q_INVOKABLE QUrl url(const QSize &size = QSize()) const;
+
+ QQmlPropertyMap *parameters() const;
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+Q_SIGNALS:
+ void pluginChanged();
+ void parametersChanged(); //in practice is never emitted since parameters cannot be re-assigned
+ //the declaration is needed to avoid warnings about non-notifyable properties
+
+private Q_SLOTS:
+ void pluginReady();
+
+private:
+ QPlaceManager *manager() const;
+ void initParameters(const QVariantMap &parameterMap);
+ QDeclarativeGeoServiceProvider *m_plugin;
+ QQmlPropertyMap *m_parameters;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp b/src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp
new file mode 100644
index 00000000..4da37081
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** 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 "qdeclarativeplaceimagemodel_p.h"
+#include "qdeclarativesupplier_p.h"
+
+#include <QtCore/QUrl>
+#include <QtLocation/QPlaceImage>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ImageModel
+ \instantiates QDeclarativePlaceImageModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-models
+ \since Qt Location 5.5
+
+ \brief The ImageModel type provides a model of place images.
+
+ The ImageModel is a read-only model used to fetch images related to a \l Place.
+ Binding a \l Place via \l ImageModel::place initiates an initial fetch of images.
+ The model performs fetches incrementally and is intended to be used in conjunction
+ with a View such as a \l ListView. When the View reaches the last of the images
+ currently in the model, a fetch is performed to retrieve more if they are available.
+ The View is automatically updated as the images are received. The number of images
+ which are fetched at a time is specified by the \l batchSize property. The total number
+ of images available can be accessed via the \l totalCount property.
+
+ The model returns data for the following roles:
+
+ \table
+ \header
+ \li Role
+ \li Type
+ \li Description
+ \row
+ \li url
+ \li url
+ \li The URL of the image.
+ \row
+ \li imageId
+ \li string
+ \li The identifier of the image.
+ \row
+ \li mimeType
+ \li string
+ \li The MIME type of the image.
+ \row
+ \li supplier
+ \li \l Supplier
+ \li The supplier of the image.
+ \row
+ \li user
+ \li \l {QtLocation::User}{User}
+ \li The user who contributed the image.
+ \row
+ \li attribution
+ \li string
+ \li Attribution text which must be displayed when displaying the image.
+ \endtable
+
+
+ \section1 Example
+
+ The following example shows how to display images for a place:
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml ImageModel
+*/
+
+/*!
+ \qmlproperty Place ImageModel::place
+
+ This property holds the Place that the images are for.
+*/
+
+/*!
+ \qmlproperty int ImageModel::batchSize
+
+ This property holds the batch size to use when fetching more image items.
+*/
+
+/*!
+ \qmlproperty int ImageModel::totalCount
+
+ This property holds the total number of image items for the place.
+*/
+
+QDeclarativePlaceImageModel::QDeclarativePlaceImageModel(QObject *parent)
+: QDeclarativePlaceContentModel(QPlaceContent::ImageType, parent)
+{
+}
+
+QDeclarativePlaceImageModel::~QDeclarativePlaceImageModel()
+{
+ qDeleteAll(m_suppliers);
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativePlaceImageModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.row() >= rowCount(index.parent()) || index.row() < 0)
+ return QVariant();
+
+ const QPlaceImage &image = m_content.value(index.row());
+
+ switch (role) {
+ case UrlRole:
+ return image.url();
+ case ImageIdRole:
+ return image.imageId();
+ case MimeTypeRole:
+ return image.mimeType();
+ }
+
+ return QDeclarativePlaceContentModel::data(index, role);
+}
+
+QHash<int, QByteArray> QDeclarativePlaceImageModel::roleNames() const
+{
+ QHash<int, QByteArray> roles = QDeclarativePlaceContentModel::roleNames();
+ roles.insert(UrlRole, "url");
+ roles.insert(ImageIdRole, "imageId");
+ roles.insert(MimeTypeRole, "mimeType");
+ return roles;
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h b/src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h
new file mode 100644
index 00000000..2c244219
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVEPLACEIMAGEMODEL_P_H
+#define QDECLARATIVEPLACEIMAGEMODEL_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/qdeclarativeplacecontentmodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeSupplier;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceImageModel : public QDeclarativePlaceContentModel
+{
+ Q_OBJECT
+
+public:
+ explicit QDeclarativePlaceImageModel(QObject *parent = 0);
+ ~QDeclarativePlaceImageModel();
+
+ QVariant data(const QModelIndex &index, int role) const;
+ QHash<int, QByteArray> roleNames() const;
+
+ enum Roles {
+ UrlRole = UserRole,
+ ImageIdRole,
+ MimeTypeRole
+ };
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativeplaces/qdeclarativeplaceuser.cpp b/src/location/declarativeplaces/qdeclarativeplaceuser.cpp
new file mode 100644
index 00000000..86901a98
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceuser.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** 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 "qdeclarativeplaceuser_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype User
+ \instantiates QDeclarativePlaceUser
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief The User type identifies a user who contributed a particular \l Place content item.
+
+ Each \l Place content item has an associated user who contributed the content. This type
+ provides information about that user.
+
+ \sa ImageModel, ReviewModel, EditorialModel
+
+ \section1 Example
+
+ The following example shows how to display information about the user who
+ submitted an editorial:
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml EditorialModel
+*/
+
+QDeclarativePlaceUser::QDeclarativePlaceUser(QObject *parent)
+ : QObject(parent) {}
+
+QDeclarativePlaceUser::QDeclarativePlaceUser(const QPlaceUser &user,
+ QObject *parent)
+ : QObject(parent),
+ m_user(user) {}
+
+QDeclarativePlaceUser::~QDeclarativePlaceUser() {}
+
+/*!
+ \qmlproperty QPlaceUser QtLocation::User::user
+
+ For details on how to use this property to interface between C++ and QML see
+ "\l {User - QPlaceUser} {Interfaces between C++ and QML Code}".
+*/
+void QDeclarativePlaceUser::setUser(const QPlaceUser &user)
+{
+ QPlaceUser previousUser = m_user;
+ m_user = user;
+
+ if (m_user.userId() != previousUser.userId())
+ emit userIdChanged();
+
+ if (m_user.name() != previousUser.name())
+ emit nameChanged();
+}
+
+QPlaceUser QDeclarativePlaceUser::user() const
+{
+ return m_user;
+}
+
+/*!
+ \qmlproperty string QtLocation::User::userId
+
+ This property holds the unique identifier of the user.
+*/
+
+void QDeclarativePlaceUser::setUserId(const QString &id)
+{
+ if (m_user.userId() == id)
+ return;
+
+ m_user.setUserId(id);
+ emit userIdChanged();
+}
+
+QString QDeclarativePlaceUser::userId() const
+{
+ return m_user.userId();
+}
+
+/*!
+ \qmlproperty string QtLocation::User::name
+
+ This property holds the name of a user.
+*/
+void QDeclarativePlaceUser::setName(const QString &name)
+{
+ if (m_user.name() == name)
+ return;
+
+ m_user.setName(name);
+ emit nameChanged();
+}
+
+QString QDeclarativePlaceUser::name() const
+{
+ return m_user.name();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativeplaceuser_p.h b/src/location/declarativeplaces/qdeclarativeplaceuser_p.h
new file mode 100644
index 00000000..8cd64493
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeplaceuser_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 QDECLARATIVEPLACEUSER_P_H
+#define QDECLARATIVEPLACEUSER_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/QObject>
+#include <QtQml/qqml.h>
+#include <QtLocation/QPlaceUser>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceUser : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPlaceUser user READ user WRITE setUser)
+ Q_PROPERTY(QString userId READ userId WRITE setUserId NOTIFY userIdChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+
+public:
+ explicit QDeclarativePlaceUser(QObject *parent = 0);
+ explicit QDeclarativePlaceUser(const QPlaceUser &src, QObject *parent = 0);
+ ~QDeclarativePlaceUser();
+
+ QPlaceUser user() const;
+ void setUser(const QPlaceUser &src);
+
+ QString userId() const;
+ void setUserId(const QString &id);
+
+ QString name() const;
+ void setName(const QString &name);
+
+Q_SIGNALS:
+ void userIdChanged();
+ void nameChanged();
+
+private:
+ QPlaceUser m_user;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePlaceUser)
+
+#endif
diff --git a/src/location/declarativeplaces/qdeclarativeratings.cpp b/src/location/declarativeplaces/qdeclarativeratings.cpp
new file mode 100644
index 00000000..150e5966
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeratings.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** 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 "qdeclarativeratings_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Ratings
+ \instantiates QDeclarativeRatings
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief The Ratings type holds place rating information.
+
+ Rating information is used to describe how \e good a place is conceived to be. Typically this
+ information is visualized as a number of stars. The \l average property gives an aggregated
+ ratings value out of a possible maximum as given by the \l maximum property.
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml Ratings
+*/
+
+QDeclarativeRatings::QDeclarativeRatings(QObject *parent)
+ : QObject(parent) {}
+
+QDeclarativeRatings::QDeclarativeRatings(const QPlaceRatings &rating,
+ QObject *parent)
+ : QObject(parent),
+ m_ratings(rating) {}
+
+QDeclarativeRatings::~QDeclarativeRatings() {}
+
+/*!
+ \qmlproperty QPlaceRatings Ratings::ratings
+
+ For details on how to use this property to interface between C++ and QML see
+ "\l {Ratings - QPlaceRatings} {Interfaces between C++ and QML Code}".
+*/
+void QDeclarativeRatings::setRatings(const QPlaceRatings &ratings)
+{
+ QPlaceRatings previous = m_ratings;
+ m_ratings = ratings;
+
+ if (ratings.average() != previous.average()) {
+ emit averageChanged();
+ }
+ if (ratings.count() != previous.count()) {
+ emit countChanged();
+ }
+}
+
+QPlaceRatings QDeclarativeRatings::ratings() const
+{
+ return m_ratings;
+}
+
+/*!
+ \qmlproperty real Ratings::average
+
+ This property holds the average of the individual ratings.
+
+ \sa maximum
+*/
+void QDeclarativeRatings::setAverage(qreal average)
+{
+ if (m_ratings.average() != average) {
+ m_ratings.setAverage(average);
+ emit averageChanged();
+ }
+}
+
+qreal QDeclarativeRatings::average() const
+{
+ return m_ratings.average();
+}
+
+/*!
+ \qmlproperty real Ratings::maximum
+
+ This property holds the maximum rating value.
+*/
+void QDeclarativeRatings::setMaximum(qreal max)
+{
+ if (m_ratings.maximum() == max)
+ return;
+
+ m_ratings.setMaximum(max);
+ emit maximumChanged();
+}
+
+qreal QDeclarativeRatings::maximum() const
+{
+ return m_ratings.maximum();
+}
+
+/*!
+ \qmlproperty int Ratings::count
+
+ This property holds the total number of individual user ratings
+ used in determining the overall ratings \l average.
+*/
+void QDeclarativeRatings::setCount(int count)
+{
+ if (m_ratings.count() != count) {
+ m_ratings.setCount(count);
+ emit countChanged();
+ }
+}
+
+int QDeclarativeRatings::count() const
+{
+ return m_ratings.count();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativeratings_p.h b/src/location/declarativeplaces/qdeclarativeratings_p.h
new file mode 100644
index 00000000..5ee530dc
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativeratings_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVERATINGS_P_H
+#define QDECLARATIVERATINGS_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/qplaceratings.h>
+#include <QtQml/qqml.h>
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRatings : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPlaceRatings ratings READ ratings WRITE setRatings)
+ Q_PROPERTY(qreal average READ average WRITE setAverage NOTIFY averageChanged)
+ Q_PROPERTY(qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged)
+ Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged)
+
+public:
+ explicit QDeclarativeRatings(QObject *parent = 0);
+ explicit QDeclarativeRatings(const QPlaceRatings &src, QObject *parent = 0);
+ ~QDeclarativeRatings();
+
+ QPlaceRatings ratings() const;
+ void setRatings(const QPlaceRatings &src);
+
+ qreal average() const;
+ void setAverage(qreal average);
+
+ qreal maximum() const;
+ void setMaximum(qreal max);
+
+ int count() const;
+ void setCount(int count);
+
+Q_SIGNALS:
+ void averageChanged();
+ void maximumChanged();
+ void countChanged();
+
+private:
+ QPlaceRatings m_ratings;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeRatings)
+
+#endif // QDECLARATIVERATING_P_H
diff --git a/src/location/declarativeplaces/qdeclarativereviewmodel.cpp b/src/location/declarativeplaces/qdeclarativereviewmodel.cpp
new file mode 100644
index 00000000..b7237bc9
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativereviewmodel.cpp
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** 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 "qdeclarativereviewmodel_p.h"
+#include "qdeclarativesupplier_p.h"
+
+#include <QtCore/QDateTime>
+#include <QtLocation/QPlaceReview>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ReviewModel
+ \instantiates QDeclarativeReviewModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-models
+ \since Qt Location 5.5
+
+ \brief Provides access to reviews of a \l Place.
+
+ The ReviewModel is a read-only model used to fetch reviews about a \l Place. The model
+ incrementally fetches. The number of reviews which are fetched at a time is specified
+ by the \l batchSize property. The total number of reviews available can be accessed via the
+ \l totalCount property.
+
+ To use the ReviewModel we need a view and a delegate. In this snippet we
+ see the setting up of a ListView with a ReviewModel model and a delegate.
+
+ \snippet places/views/ReviewView.qml ReviewModel delegate
+
+ The model returns data for the following roles:
+
+ \table
+ \header
+ \li Role
+ \li Type
+ \li Description
+ \row
+ \li dateTime
+ \li datetime
+ \li The date and time that the review was posted.
+ \row
+ \li text
+ \li string
+ \li The review's textual description of the place. It can be either rich (HTML based) text or plain text
+ depending on the provider.
+ \row
+ \li language
+ \li string
+ \li The language that the review is written in.
+ \row
+ \li rating
+ \li real
+ \li The rating that the reviewer gave to the place.
+ \row
+ \li reviewId
+ \li string
+ \li The identifier of the review.
+ \row
+ \li title
+ \li string
+ \li The title of the review.
+ \row
+ \li supplier
+ \li \l Supplier
+ \li The supplier of the review.
+ \row
+ \li user
+ \li \l {QtLocation::User}{User}
+ \li The user who contributed the review.
+ \row
+ \li attribution
+ \li string
+ \li Attribution text which must be displayed when displaying the review.
+ \endtable
+*/
+
+/*!
+ \qmlproperty Place QtLocation::ReviewModel::place
+
+ This property holds the Place that the reviews are for.
+*/
+
+/*!
+ \qmlproperty int QtLocation::ReviewModel::batchSize
+
+ This property holds the batch size to use when fetching more reviews.
+*/
+
+/*!
+ \qmlproperty int QtLocation::ReviewModel::totalCount
+
+ This property holds the total number of reviews for the place.
+*/
+
+QDeclarativeReviewModel::QDeclarativeReviewModel(QObject *parent)
+: QDeclarativePlaceContentModel(QPlaceContent::ReviewType, parent)
+{
+}
+
+QDeclarativeReviewModel::~QDeclarativeReviewModel()
+{
+ qDeleteAll(m_suppliers);
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeReviewModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.row() >= rowCount(index.parent()) || index.row() < 0)
+ return QVariant();
+
+ const QPlaceReview &review = m_content.value(index.row());
+
+ switch (role) {
+ case DateTimeRole:
+ return review.dateTime();
+ case TextRole:
+ return review.text();
+ case LanguageRole:
+ return review.language();
+ case RatingRole:
+ return review.rating();
+ case ReviewIdRole:
+ return review.reviewId();
+ case TitleRole:
+ return review.title();
+ }
+
+ return QDeclarativePlaceContentModel::data(index, role);
+}
+
+QHash<int, QByteArray> QDeclarativeReviewModel::roleNames() const
+{
+ QHash<int, QByteArray> roles = QDeclarativePlaceContentModel::roleNames();
+ roles.insert(DateTimeRole, "dateTime");
+ roles.insert(TextRole, "text");
+ roles.insert(LanguageRole, "language");
+ roles.insert(RatingRole, "rating");
+ roles.insert(ReviewIdRole, "reviewId");
+ roles.insert(TitleRole, "title");
+ return roles;
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativereviewmodel_p.h b/src/location/declarativeplaces/qdeclarativereviewmodel_p.h
new file mode 100644
index 00000000..e6d2bd95
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativereviewmodel_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVEREVIEWMODEL_P_H
+#define QDECLARATIVEREVIEWMODEL_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/qdeclarativeplacecontentmodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeReviewModel : public QDeclarativePlaceContentModel
+{
+ Q_OBJECT
+
+public:
+ explicit QDeclarativeReviewModel(QObject *parent = 0);
+ ~QDeclarativeReviewModel();
+
+ QVariant data(const QModelIndex &index, int role) const;
+ QHash<int, QByteArray> roleNames() const;
+ enum Roles {
+ DateTimeRole = UserRole,
+ TextRole,
+ LanguageRole,
+ RatingRole,
+ ReviewIdRole,
+ TitleRole
+ };
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEREVIEWMODEL_P_H
diff --git a/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp b/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp
new file mode 100644
index 00000000..3a3faa56
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp
@@ -0,0 +1,362 @@
+/****************************************************************************
+**
+** 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 "qdeclarativesearchmodelbase_p.h"
+#include "qdeclarativeplace_p.h"
+#include "error_messages.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtQml/QQmlInfo>
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/QPlaceManager>
+#include <QtLocation/QPlaceSearchRequest>
+#include <QtLocation/QPlaceSearchReply>
+#include <QtPositioning/QGeoCircle>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeSearchModelBase::QDeclarativeSearchModelBase(QObject *parent)
+: QAbstractListModel(parent), m_plugin(0), m_reply(0), m_complete(false), m_status(Null)
+{
+}
+
+QDeclarativeSearchModelBase::~QDeclarativeSearchModelBase()
+{
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider *QDeclarativeSearchModelBase::plugin() const
+{
+ return m_plugin;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (m_plugin == plugin)
+ return;
+
+ initializePlugin(plugin);
+
+ if (m_complete)
+ emit pluginChanged();
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeSearchModelBase::searchArea() const
+{
+ QGeoShape s = m_request.searchArea();
+ if (s.type() == QGeoShape::RectangleType)
+ return QVariant::fromValue(QGeoRectangle(s));
+ else if (s.type() == QGeoShape::CircleType)
+ return QVariant::fromValue(QGeoCircle(s));
+ else
+ return QVariant::fromValue(s);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::setSearchArea(const QVariant &searchArea)
+{
+ QGeoShape s;
+
+ if (searchArea.userType() == qMetaTypeId<QGeoRectangle>())
+ s = searchArea.value<QGeoRectangle>();
+ else if (searchArea.userType() == qMetaTypeId<QGeoCircle>())
+ s = searchArea.value<QGeoCircle>();
+ else if (searchArea.userType() == qMetaTypeId<QGeoShape>())
+ s = searchArea.value<QGeoShape>();
+
+ if (m_request.searchArea() == s)
+ return;
+
+ m_request.setSearchArea(s);
+ emit searchAreaChanged();
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeSearchModelBase::limit() const
+{
+ return m_request.limit();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::setLimit(int limit)
+{
+ if (m_request.limit() == limit)
+ return;
+
+ m_request.setLimit(limit);
+ emit limitChanged();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeSearchModelBase::previousPagesAvailable() const
+{
+ return m_previousPageRequest != QPlaceSearchRequest();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeSearchModelBase::nextPagesAvailable() const
+{
+ return m_nextPageRequest != QPlaceSearchRequest();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeSearchModelBase::Status QDeclarativeSearchModelBase::status() const
+{
+ return m_status;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::setStatus(Status status, const QString &errorString)
+{
+ Status prevStatus = m_status;
+
+ m_status = status;
+ m_errorString = errorString;
+
+ if (prevStatus != m_status)
+ emit statusChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::update()
+{
+ if (m_reply)
+ return;
+
+ setStatus(Loading);
+
+ if (!m_plugin) {
+ clearData();
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROPERTY_NOT_SET));
+ return;
+ }
+
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (!serviceProvider) {
+ clearData();
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROVIDER_ERROR)
+ .arg(m_plugin->name()));
+ return;
+ }
+
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (!placeManager) {
+ clearData();
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
+ .arg(m_plugin->name()).arg(serviceProvider->errorString()));
+ return;
+ }
+
+ m_reply = sendQuery(placeManager, m_request);
+ if (!m_reply) {
+ clearData();
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, UNABLE_TO_MAKE_REQUEST));
+ return;
+ }
+
+ m_reply->setParent(this);
+ connect(m_reply, SIGNAL(finished()), this, SLOT(queryFinished()));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::cancel()
+{
+ if (!m_reply)
+ return;
+
+ if (!m_reply->isFinished())
+ m_reply->abort();
+
+ if (m_reply) {
+ m_reply->deleteLater();
+ m_reply = 0;
+ }
+
+ setStatus(Ready);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::reset()
+{
+ beginResetModel();
+ clearData();
+ setStatus(Null);
+ endResetModel();
+}
+
+/*!
+ \internal
+*/
+QString QDeclarativeSearchModelBase::errorString() const
+{
+ return m_errorString;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::previousPage()
+{
+ if (m_previousPageRequest == QPlaceSearchRequest())
+ return;
+
+ m_request = m_previousPageRequest;
+ update();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::nextPage()
+{
+ if (m_nextPageRequest == QPlaceSearchRequest())
+ return;
+
+ m_request = m_nextPageRequest;
+ update();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::clearData(bool suppressSignal)
+{
+ Q_UNUSED(suppressSignal)
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::classBegin()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::componentComplete()
+{
+ m_complete = true;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::initializePlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ beginResetModel();
+ if (plugin != m_plugin) {
+ if (m_plugin)
+ disconnect(m_plugin, SIGNAL(nameChanged(QString)), this, SLOT(pluginNameChanged()));
+ if (plugin)
+ connect(plugin, SIGNAL(nameChanged(QString)), this, SLOT(pluginNameChanged()));
+ m_plugin = plugin;
+ }
+
+ if (m_plugin) {
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (serviceProvider) {
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (placeManager) {
+ if (placeManager->childCategoryIds().isEmpty()) {
+ QPlaceReply *reply = placeManager->initializeCategories();
+ connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
+ }
+ }
+ }
+ }
+
+ endResetModel();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::pluginNameChanged()
+{
+ initializePlugin(m_plugin);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchModelBase::setPreviousPageRequest(const QPlaceSearchRequest &previous)
+{
+ if (m_previousPageRequest == previous)
+ return;
+
+ m_previousPageRequest = previous;
+ emit previousPagesAvailableChanged();
+}
+
+void QDeclarativeSearchModelBase::setNextPageRequest(const QPlaceSearchRequest &next)
+{
+ if (m_nextPageRequest == next)
+ return;
+
+ m_nextPageRequest = next;
+ emit nextPagesAvailableChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h b/src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h
new file mode 100644
index 00000000..cb8e4032
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESEARCHMODELBASE_H
+#define QDECLARATIVESEARCHMODELBASE_H
+
+#include <QtLocation/private/qlocationglobal_p.h>
+#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h>
+#include <QtCore/QAbstractListModel>
+#include <QtQml/QQmlParserStatus>
+#include <QtLocation/QPlaceSearchRequest>
+#include <QtLocation/QPlaceSearchResult>
+#include <QtLocation/QPlaceReply>
+
+QT_BEGIN_NAMESPACE
+
+class QPlaceManager;
+class QPlaceSearchRequest;
+class QPlaceSearchReply;
+class QDeclarativePlace;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchModelBase : public QAbstractListModel, public QQmlParserStatus
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(QVariant searchArea READ searchArea WRITE setSearchArea NOTIFY searchAreaChanged)
+ Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged)
+ Q_PROPERTY(bool previousPagesAvailable READ previousPagesAvailable NOTIFY previousPagesAvailableChanged)
+ Q_PROPERTY(bool nextPagesAvailable READ nextPagesAvailable NOTIFY nextPagesAvailableChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+
+ Q_ENUMS(Status)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ enum Status {
+ Null,
+ Ready,
+ Loading,
+ Error
+ };
+
+ explicit QDeclarativeSearchModelBase(QObject *parent = 0);
+ ~QDeclarativeSearchModelBase();
+
+ QDeclarativeGeoServiceProvider *plugin() const;
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+
+ QVariant searchArea() const;
+ void setSearchArea(const QVariant &searchArea);
+
+ int limit() const;
+ void setLimit(int limit);
+
+ bool previousPagesAvailable() const;
+ bool nextPagesAvailable() const;
+
+ Status status() const;
+ void setStatus(Status status, const QString &errorString = QString());
+
+ Q_INVOKABLE void update();
+
+ Q_INVOKABLE void cancel();
+ Q_INVOKABLE void reset();
+
+ Q_INVOKABLE QString errorString() const;
+
+ Q_INVOKABLE void previousPage();
+ Q_INVOKABLE void nextPage();
+
+ virtual void clearData(bool suppressSignal = false);
+
+ // From QQmlParserStatus
+ virtual void classBegin();
+ virtual void componentComplete();
+
+Q_SIGNALS:
+ void pluginChanged();
+ void searchAreaChanged();
+ void limitChanged();
+ void previousPagesAvailableChanged();
+ void nextPagesAvailableChanged();
+ void statusChanged();
+
+protected:
+ virtual void initializePlugin(QDeclarativeGeoServiceProvider *plugin);
+
+protected Q_SLOTS:
+ virtual void queryFinished() = 0;
+
+private Q_SLOTS:
+ void pluginNameChanged();
+
+protected:
+ virtual QPlaceReply *sendQuery(QPlaceManager *manager, const QPlaceSearchRequest &request) = 0;
+ void setPreviousPageRequest(const QPlaceSearchRequest &previous);
+ void setNextPageRequest(const QPlaceSearchRequest &next);
+
+ QPlaceSearchRequest m_request;
+ QDeclarativeGeoServiceProvider *m_plugin;
+ QPlaceReply *m_reply;
+
+private:
+ bool m_complete;
+ Status m_status;
+ QString m_errorString;
+ QPlaceSearchRequest m_previousPageRequest;
+ QPlaceSearchRequest m_nextPageRequest;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESEARCHMODELBASE_H
diff --git a/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp
new file mode 100644
index 00000000..31d152db
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp
@@ -0,0 +1,917 @@
+/****************************************************************************
+**
+** 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 "qdeclarativesearchresultmodel_p.h"
+#include "qdeclarativeplace_p.h"
+#include "qdeclarativeplaceicon_p.h"
+
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlInfo>
+#include <QtLocation/QGeoServiceProvider>
+#include <QtLocation/QPlaceSearchReply>
+#include <QtLocation/QPlaceManager>
+#include <QtLocation/QPlaceMatchRequest>
+#include <QtLocation/QPlaceMatchReply>
+#include <QtLocation/QPlaceResult>
+#include <QtLocation/QPlaceProposedSearchResult>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype PlaceSearchModel
+ \instantiates QDeclarativeSearchResultModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-models
+ \since Qt Location 5.5
+
+ \brief Provides access to place search results.
+
+ PlaceSearchModel provides a model of place search results within the \l searchArea. The
+ \l searchTerm and \l categories properties can be set to restrict the search results to
+ places matching those criteria.
+
+ The PlaceSearchModel returns both sponsored and
+ \l {http://en.wikipedia.org/wiki/Organic_search}{organic search results}. Sponsored search
+ results will have the \c sponsored role set to true.
+
+ \target PlaceSearchModel Roles
+ The model returns data for the following roles:
+
+ \table
+ \header
+ \li Role
+ \li Type
+ \li Description
+ \row
+ \li type
+ \li enum
+ \li The type of search result.
+ \row
+ \li title
+ \li string
+ \li A string describing the search result.
+ \row
+ \li icon
+ \li PlaceIcon
+ \li Icon representing the search result.
+ \row
+ \li distance
+ \li real
+ \li Valid only when the \c type role is \c PlaceResult, the distance to the place
+ from the center of the \l searchArea. If no \l searchArea
+ has been specified, the distance is NaN.
+ \row
+ \li place
+ \li \l Place
+ \li Valid only when the \c type role is \c PlaceResult, an object representing the
+ place.
+ \row
+ \li sponsored
+ \li bool
+ \li Valid only when the \c type role is \c PlaceResult, true if the search result is a
+ sponsored result.
+ \endtable
+
+ \section2 Search Result Types
+
+ The \c type role can take on the following values:
+
+ \table
+ \row
+ \li PlaceSearchModel.UnknownSearchResult
+ \li The contents of the search result are unknown.
+ \row
+ \li PlaceSearchModel.PlaceResult
+ \li The search result contains a place.
+ \row
+ \li PlaceSearchModel.ProposedSearchResult
+ \li The search result contains a proposed search which may be relevant.
+ \endtable
+
+
+ It can often be helpful to use a \l Loader to create a delegate
+ that will choose different \l {Component}s based on the search result type.
+
+ \snippet declarative/places_loader.qml Handle Result Types
+
+ \section1 Detection of Updated and Removed Places
+
+ The PlaceSearchModel listens for places that have been updated or removed from its plugin's backend.
+ If it detects that a place has been updated and that place is currently present in the model, then
+ it will call \l Place::getDetails to refresh the details. If it detects that a place has been
+ removed, then correspondingly the place will be removed from the model if it is currently
+ present.
+
+ \section1 Example
+
+ The following example shows how to use the PlaceSearchModel to search for Pizza restaurants in
+ close proximity of a given position. A \l searchTerm and \l searchArea are provided to the model
+ and \l update() is used to perform a lookup query. Note that the model does not incrementally
+ fetch search results, but rather performs a single fetch when \l update() is run. The \l count
+ is set to the number of search results returned during the fetch.
+
+ \snippet places_list/places_list.qml Imports
+ \codeline
+ \snippet places_list/places_list.qml PlaceSearchModel
+
+ \sa CategoryModel, {QPlaceManager}
+
+ \section1 Paging
+ The PlaceSearchModel API has some limited support
+ for paging. The \l nextPage() and \l previousPage() functions as well as
+ the \l limit property can be used to access
+ paged search results. When the \l limit property is set
+ the search result page contains at most \l limit entries (of type place result).
+ For example, if the backend has 5 search results in total
+ [a,b,c,d,e], and assuming the first page is shown and limit of 3 has been set
+ then a,b,c is returned. The \l nextPage() would return d,e. The
+ \l nextPagesAvailable and \l previousPagesAvailable properties
+ can be used to check for further pages. At the moment the API does not
+ support the means to retrieve the total number of items available from the
+ backed. Note that support for \l nextPage(), previousPage() and \l limit can vary
+ according to the \l plugin.
+*/
+
+/*!
+ \qmlproperty Plugin PlaceSearchModel::plugin
+
+ This property holds the \l Plugin which will be used to perform the search.
+*/
+
+/*!
+ \qmlproperty Plugin PlaceSearchModel::favoritesPlugin
+
+ This property holds the \l Plugin which will be used to search for favorites.
+ Any places from the search which can be cross-referenced or matched
+ in the favoritesPlugin will have their \l {Place::favorite}{favorite} property
+ set to the corresponding \l Place from the favoritesPlugin.
+
+ If the favoritesPlugin is not set, the \l {Place::favorite}{favorite} property
+ of the places in the results will always be null.
+
+ \sa Favorites
+*/
+
+/*!
+ \qmlproperty VariantMap PlaceSearchModel::favoritesMatchParameters
+
+ This property holds a set of parameters used to specify how search result places
+ are matched to favorites in the favoritesPlugin.
+
+ By default the parameter map is empty and implies that the favorites plugin
+ matches by \l {Alternative Identifier Cross-Referencing}{alternative identifiers}. Generally,
+ an application developer will not need to set this property.
+
+ In cases where the favorites plugin does not support matching by alternative identifiers,
+ then the \l {Qt Location#Plugin References and Parameters}{plugin documentation} should
+ be consulted to see precisely what key-value parameters to set.
+*/
+
+/*!
+ \qmlproperty variant PlaceSearchModel::searchArea
+
+ This property holds the search area. The search result returned by the model will be within
+ the search area.
+
+ If this property is set to a \l {geocircle} its
+ \l {geocircle}{radius} property may be left unset, in which case the \l Plugin
+ will choose an appropriate radius for the search.
+
+ Support for specifying a search area can vary according to the \l plugin backend
+ implementation. For example, some may support a search center only while others may only
+ support geo rectangles.
+*/
+
+/*!
+ \qmlproperty int PlaceSearchModel::limit
+
+ This property holds the limit of the number of items that will be returned.
+*/
+
+/*!
+ \qmlproperty bool PlaceSearchModel::previousPagesAvailable
+
+ This property holds whether there is one or more previous pages of search results available.
+
+ \sa previousPage()
+*/
+
+/*!
+ \qmlproperty bool PlaceSearchModel::nextPagesAvailable
+
+ This property holds whether there is one or more additional pages of search results available.
+
+ \sa nextPage()
+*/
+
+/*!
+ \qmlproperty enum PlaceSearchModel::status
+
+ This property holds the status of the model. It can be one of:
+
+ \table
+ \row
+ \li PlaceSearchModel.Null
+ \li No search query has been executed. The model is empty.
+ \row
+ \li PlaceSearchModel.Ready
+ \li The search query has completed, and the results are available.
+ \row
+ \li PlaceSearchModel.Loading
+ \li A search query is currently being executed.
+ \row
+ \li PlaceSearchModel.Error
+ \li An error occurred when executing the previous search query.
+ \endtable
+*/
+
+/*!
+ \qmlmethod void PlaceSearchModel::update()
+
+ Updates the model based on the provided query parameters. The model will be populated with a
+ list of places matching the search parameters specified by the type's properties. Search
+ criteria is specified by setting properties such as the \l searchTerm, \l categories, \l searchArea and \l limit.
+ Support for these properties may vary according to \l plugin. \c update() then
+ submits the set of criteria to the \l plugin to process.
+
+ While the model is updating the \l status of the model is set to
+ \c PlaceSearchModel.Loading. If the model is successfully updated the \l status is set to
+ \c PlaceSearchModel.Ready, while if it unsuccessfully completes, the \l status is set to
+ \c PlaceSearchModel.Error and the model cleared.
+
+ \code
+ PlaceSearchModel {
+ id: model
+ plugin: backendPlugin
+ searchArea: QtPositioning.circle(QtPositioning.coordinate(10, 10))
+ ...
+ }
+
+ MouseArea {
+ ...
+ onClicked: {
+ model.searchTerm = "pizza";
+ model.categories = null; //not searching by any category
+ model.searchArea.center.latitude = -27.5;
+ model.searchArea.center.longitude = 153;
+ model.update();
+ }
+ }
+ \endcode
+
+ \sa cancel(), status
+*/
+
+/*!
+ \qmlmethod void PlaceSearchModel::cancel()
+
+ Cancels an ongoing search operation immediately and sets the model
+ status to PlaceSearchModel.Ready. The model retains any search
+ results it had before the operation was started.
+
+ If an operation is not ongoing, invoking cancel() has no effect.
+
+ \sa update(), status
+*/
+
+/*!
+ \qmlmethod void PlaceSearchModel::reset()
+
+ Resets the model. All search results are cleared, any outstanding requests are aborted and
+ possible errors are cleared. Model status will be set to PlaceSearchModel.Null.
+*/
+
+/*!
+ \qmlmethod string PlaceSearchModel::errorString() const
+
+ This read-only property holds the textual presentation of the latest place search model error.
+ If no error has occurred or if the model was cleared, an empty string is returned.
+
+ An empty string may also be returned if an error occurred which has no associated
+ textual representation.
+*/
+
+/*!
+ \qmlmethod void PlaceSearchModel::previousPage()
+
+ Updates the model to display the previous page of search results. If there is no previous page
+ then this method does nothing.
+*/
+
+/*!
+ \qmlmethod void PlaceSearchModel::nextPage()
+
+ Updates the model to display the next page of search results. If there is no next page then
+ this method does nothing.
+*/
+
+QDeclarativeSearchResultModel::QDeclarativeSearchResultModel(QObject *parent)
+ : QDeclarativeSearchModelBase(parent), m_favoritesPlugin(0)
+{
+}
+
+QDeclarativeSearchResultModel::~QDeclarativeSearchResultModel()
+{
+}
+
+/*!
+ \qmlproperty string PlaceSearchModel::searchTerm
+
+ This property holds search term used in query. The search term is a free-form text string.
+*/
+QString QDeclarativeSearchResultModel::searchTerm() const
+{
+ return m_request.searchTerm();
+}
+
+void QDeclarativeSearchResultModel::setSearchTerm(const QString &searchTerm)
+{
+ m_request.setSearchContext(QVariant());
+
+ if (m_request.searchTerm() == searchTerm)
+ return;
+
+ m_request.setSearchTerm(searchTerm);
+ emit searchTermChanged();
+}
+
+/*!
+ \qmlproperty list<Category> PlaceSearchModel::categories
+
+ This property holds a list of categories to be used when searching. Returned search results
+ will be for places that match at least one of the categories.
+*/
+QQmlListProperty<QDeclarativeCategory> QDeclarativeSearchResultModel::categories()
+{
+ return QQmlListProperty<QDeclarativeCategory>(this,
+ 0, // opaque data parameter
+ categories_append,
+ categories_count,
+ category_at,
+ categories_clear);
+}
+
+void QDeclarativeSearchResultModel::categories_append(QQmlListProperty<QDeclarativeCategory> *list,
+ QDeclarativeCategory *declCategory)
+{
+ QDeclarativeSearchResultModel *searchModel = qobject_cast<QDeclarativeSearchResultModel *>(list->object);
+ if (searchModel && declCategory) {
+ searchModel->m_request.setSearchContext(QVariant());
+ searchModel->m_categories.append(declCategory);
+ QList<QPlaceCategory> categories = searchModel->m_request.categories();
+ categories.append(declCategory->category());
+ searchModel->m_request.setCategories(categories);
+ emit searchModel->categoriesChanged();
+ }
+}
+
+int QDeclarativeSearchResultModel::categories_count(QQmlListProperty<QDeclarativeCategory> *list)
+{
+ QDeclarativeSearchResultModel *searchModel = qobject_cast<QDeclarativeSearchResultModel *>(list->object);
+ if (searchModel)
+ return searchModel->m_categories.count();
+ else
+ return -1;
+}
+
+QDeclarativeCategory *QDeclarativeSearchResultModel::category_at(QQmlListProperty<QDeclarativeCategory> *list,
+ int index)
+{
+ QDeclarativeSearchResultModel *searchModel = qobject_cast<QDeclarativeSearchResultModel *>(list->object);
+ if (searchModel && (searchModel->m_categories.count() > index) && (index > -1))
+ return searchModel->m_categories.at(index);
+ else
+ return 0;
+}
+
+void QDeclarativeSearchResultModel::categories_clear(QQmlListProperty<QDeclarativeCategory> *list)
+{
+ QDeclarativeSearchResultModel *searchModel = qobject_cast<QDeclarativeSearchResultModel *>(list->object);
+ if (searchModel) {
+ //note: we do not need to delete each of the objects in m_categories since the search model
+ //should never be the parent of the categories anyway.
+ searchModel->m_request.setSearchContext(QVariant());
+ searchModel->m_categories.clear();
+ searchModel->m_request.setCategories(QList<QPlaceCategory>());
+ emit searchModel->categoriesChanged();
+ }
+}
+
+/*!
+ \qmlproperty string PlaceSearchModel::recommendationId
+
+ This property holds the placeId to be used in order to find recommendations
+ for similar places.
+*/
+QString QDeclarativeSearchResultModel::recommendationId() const
+{
+ return m_request.recommendationId();
+}
+
+void QDeclarativeSearchResultModel::setRecommendationId(const QString &placeId)
+{
+ if (m_request.recommendationId() == placeId)
+ return;
+
+ m_request.setRecommendationId(placeId);
+ emit recommendationIdChanged();
+}
+
+/*!
+ \qmlproperty enumeration PlaceSearchModel::relevanceHint
+
+ This property holds a relevance hint used in the search query. The hint is given to the
+ provider to help but not dictate the ranking of results. For example, the distance hint may
+ give closer places a higher ranking but it does not necessarily mean the results will be
+ strictly ordered according to distance. A provider may ignore the hint altogether.
+
+ \table
+ \row
+ \li SearchResultModel.UnspecifiedHint
+ \li No relevance hint is given to the provider.
+ \row
+ \li SearchResultModel.DistanceHint
+ \li The distance of the place from the user's current location is important to the user.
+ This hint is only meaningful when a circular search area is used.
+ \row
+ \li SearchResultModel.LexicalPlaceNameHint
+ \li The lexical ordering of place names (in ascending alphabetical order) is relevant to
+ the user. This hint is useful for providers based on a local data store.
+ \endtable
+*/
+QDeclarativeSearchResultModel::RelevanceHint QDeclarativeSearchResultModel::relevanceHint() const
+{
+ return static_cast<QDeclarativeSearchResultModel::RelevanceHint>(m_request.relevanceHint());
+}
+
+void QDeclarativeSearchResultModel::setRelevanceHint(QDeclarativeSearchResultModel::RelevanceHint hint)
+{
+ if (m_request.relevanceHint() != static_cast<QPlaceSearchRequest::RelevanceHint>(hint)) {
+ m_request.setRelevanceHint(static_cast<QPlaceSearchRequest::RelevanceHint>(hint));
+ emit relevanceHintChanged();
+ }
+}
+
+/*!
+ \qmlproperty enum PlaceSearchModel::visibilityScope
+
+ This property holds the visibility scope of the places to search. Only places with the
+ specified visibility will be returned in the search results.
+
+ The visibility scope can be one of:
+
+ \table
+ \row
+ \li Place.UnspecifiedVisibility
+ \li No explicit visibility scope specified, places with any visibility may be part of
+ search results.
+ \row
+ \li Place.DeviceVisibility
+ \li Only places stored on the local device will be part of the search results.
+ \row
+ \li Place.PrivateVisibility
+ \li Only places that are private to the current user will be part of the search results.
+ \row
+ \li Place.PublicVisibility
+ \li Only places that are public will be part of the search results.
+ \endtable
+*/
+QDeclarativePlace::Visibility QDeclarativeSearchResultModel::visibilityScope() const
+{
+ return QDeclarativePlace::Visibility(int(m_visibilityScope));
+}
+
+void QDeclarativeSearchResultModel::setVisibilityScope(QDeclarativePlace::Visibility visibilityScope)
+{
+ QLocation::VisibilityScope scope = QLocation::VisibilityScope(visibilityScope);
+
+ if (m_visibilityScope == scope)
+ return;
+
+ m_visibilityScope = scope;
+ emit visibilityScopeChanged();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider *QDeclarativeSearchResultModel::favoritesPlugin() const
+{
+ return m_favoritesPlugin;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchResultModel::setFavoritesPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+
+ if (m_favoritesPlugin == plugin)
+ return;
+
+ m_favoritesPlugin = plugin;
+
+ if (m_favoritesPlugin) {
+ QGeoServiceProvider *serviceProvider = m_favoritesPlugin->sharedGeoServiceProvider();
+ if (serviceProvider) {
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (placeManager) {
+ if (placeManager->childCategoryIds().isEmpty()) {
+ QPlaceReply *reply = placeManager->initializeCategories();
+ connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
+ }
+ }
+ }
+ }
+
+ emit favoritesPluginChanged();
+}
+
+/*!
+ \internal
+*/
+QVariantMap QDeclarativeSearchResultModel::favoritesMatchParameters() const
+{
+ return m_matchParameters;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchResultModel::setFavoritesMatchParameters(const QVariantMap &parameters)
+{
+ if (m_matchParameters == parameters)
+ return;
+
+ m_matchParameters = parameters;
+ emit favoritesMatchParametersChanged();
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeSearchResultModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return m_results.count();
+}
+
+void QDeclarativeSearchResultModel::clearData(bool suppressSignal)
+{
+ QDeclarativeSearchModelBase::clearData(suppressSignal);
+
+ qDeleteAll(m_places);
+ m_places.clear();
+ qDeleteAll(m_icons);
+ m_icons.clear();
+ if (!m_results.isEmpty()) {
+ m_results.clear();
+
+ if (!suppressSignal)
+ emit rowCountChanged();
+ }
+}
+
+QVariant QDeclarativeSearchResultModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() > m_results.count())
+ return QVariant();
+
+ const QPlaceSearchResult &result = m_results.at(index.row());
+
+ switch (role) {
+ case SearchResultTypeRole:
+ return result.type();
+ case Qt::DisplayRole:
+ case TitleRole:
+ return result.title();
+ case IconRole:
+ return QVariant::fromValue(static_cast<QObject *>(m_icons.at(index.row())));
+ case DistanceRole:
+ if (result.type() == QPlaceSearchResult::PlaceResult) {
+ QPlaceResult placeResult = result;
+ return placeResult.distance();
+ }
+ break;
+ case PlaceRole:
+ if (result.type() == QPlaceSearchResult::PlaceResult)
+ return QVariant::fromValue(static_cast<QObject *>(m_places.at(index.row())));
+ case SponsoredRole:
+ if (result.type() == QPlaceSearchResult::PlaceResult) {
+ QPlaceResult placeResult = result;
+ return placeResult.isSponsored();
+ }
+ break;
+ }
+ return QVariant();
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeSearchResultModel::data(int index, const QString &role) const
+{
+ QModelIndex modelIndex = createIndex(index, 0);
+ return data(modelIndex, roleNames().key(role.toLatin1()));
+}
+
+QHash<int, QByteArray> QDeclarativeSearchResultModel::roleNames() const
+{
+ QHash<int, QByteArray> roles = QDeclarativeSearchModelBase::roleNames();
+ roles.insert(SearchResultTypeRole, "type");
+ roles.insert(TitleRole, "title");
+ roles.insert(IconRole, "icon");
+ roles.insert(DistanceRole, "distance");
+ roles.insert(PlaceRole, "place");
+ roles.insert(SponsoredRole, "sponsored");
+
+ return roles;
+}
+
+/*!
+ \qmlmethod void PlaceSearchModel::updateWith(int proposedSearchIndex)
+
+ Updates the model based on the ProposedSearchResult at index \a proposedSearchIndex. The model
+ will be populated with a list of places matching the proposed search. Model status will be set
+ to PlaceSearchModel.Loading. If the model is updated successfully status will be set to
+ PlaceSearchModel.Ready. If an error occurs status will be set to PlaceSearchModel.Error and the
+ model cleared.
+
+ If \a proposedSearchIndex does not reference a ProposedSearchResult this method does nothing.
+*/
+void QDeclarativeSearchResultModel::updateWith(int proposedSearchIndex)
+{
+ if (m_results.at(proposedSearchIndex).type() != QPlaceSearchResult::ProposedSearchResult)
+ return;
+
+ m_request = QPlaceProposedSearchResult(m_results.at(proposedSearchIndex)).searchRequest();
+ update();
+}
+
+QPlaceReply *QDeclarativeSearchResultModel::sendQuery(QPlaceManager *manager,
+ const QPlaceSearchRequest &request)
+{
+ Q_ASSERT(manager);
+ return manager->search(request);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchResultModel::initializePlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ //disconnect the manager of the old plugin if we have one
+ if (m_plugin) {
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (serviceProvider) {
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (placeManager) {
+ disconnect(placeManager, SIGNAL(placeUpdated(QString)), this, SLOT(placeUpdated(QString)));
+ disconnect(placeManager, SIGNAL(placeRemoved(QString)), this, SLOT(placeRemoved(QString)));
+ connect(placeManager, SIGNAL(dataChanged()), this, SIGNAL(dataChanged()));
+ }
+ }
+ }
+
+ //connect to the manager of the new plugin.
+ if (plugin) {
+ QGeoServiceProvider *serviceProvider = plugin->sharedGeoServiceProvider();
+ if (serviceProvider) {
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (placeManager) {
+ connect(placeManager, SIGNAL(placeUpdated(QString)), this, SLOT(placeUpdated(QString)));
+ connect(placeManager, SIGNAL(placeRemoved(QString)), this, SLOT(placeRemoved(QString)));
+ disconnect(placeManager, SIGNAL(dataChanged()), this, SIGNAL(dataChanged()));
+ }
+ }
+ }
+ QDeclarativeSearchModelBase::initializePlugin(plugin);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchResultModel::queryFinished()
+{
+ if (!m_reply)
+ return;
+ QPlaceReply *reply = m_reply;
+ m_reply = 0;
+ if (reply->error() != QPlaceReply::NoError) {
+ m_resultsBuffer.clear();
+ updateLayout();
+ setStatus(Error, reply->errorString());
+ reply->deleteLater();
+ return;
+ }
+
+ if (reply->type() == QPlaceReply::SearchReply) {
+ QPlaceSearchReply *searchReply = qobject_cast<QPlaceSearchReply *>(reply);
+ Q_ASSERT(searchReply);
+
+ m_resultsBuffer = searchReply->results();
+ setPreviousPageRequest(searchReply->previousPageRequest());
+ setNextPageRequest(searchReply->nextPageRequest());
+
+ reply->deleteLater();
+
+ if (!m_favoritesPlugin) {
+ updateLayout();
+ setStatus(Ready);
+ } else {
+ QGeoServiceProvider *serviceProvider = m_favoritesPlugin->sharedGeoServiceProvider();
+ if (!serviceProvider) {
+ updateLayout();
+ setStatus(Error, QStringLiteral("Favorites plugin returns a null QGeoServiceProvider instance"));
+ return;
+ }
+
+ QPlaceManager *favoritesManager = serviceProvider->placeManager();
+ if (!favoritesManager) {
+ updateLayout();
+ setStatus(Error, QStringLiteral("Favorites plugin returns a null QPlaceManager"));
+ return;
+ }
+
+ QPlaceMatchRequest request;
+ if (m_matchParameters.isEmpty()) {
+ if (!m_plugin) {
+ reply->deleteLater();
+ setStatus(Error, QStringLiteral("Plugin not assigned"));
+ return;
+ }
+
+ QVariantMap params;
+ params.insert(QPlaceMatchRequest::AlternativeId, QVariant(QString::fromLatin1("x_id_") + m_plugin->name()));
+ request.setParameters(params);
+ } else {
+ request.setParameters(m_matchParameters);
+ }
+
+ request.setResults(m_resultsBuffer);
+ m_reply = favoritesManager->matchingPlaces(request);
+ connect(m_reply, SIGNAL(finished()), this, SLOT(queryFinished()));
+ }
+ } else if (reply->type() == QPlaceReply::MatchReply) {
+ QPlaceMatchReply *matchReply = qobject_cast<QPlaceMatchReply *>(reply);
+ Q_ASSERT(matchReply);
+ updateLayout(matchReply->places());
+ setStatus(Ready);
+ reply->deleteLater();
+ } else {
+ setStatus(Error, QStringLiteral("Unknown reply type"));
+ reply->deleteLater();
+ }
+}
+
+/*!
+ \qmlmethod void PlaceSearchModel::data(int index, string role)
+
+ Returns the data for a given \a role at the specified row \a index.
+*/
+
+/*!
+ \qmlproperty int PlaceSearchModel::count
+
+ This property holds the number of results the model has.
+
+ Note that it does not refer to the total number of search results
+ available in the backend. The total number of search results
+ is not currently supported by the API.
+*/
+
+/*!
+ \internal
+ Note: m_results buffer should be correctly populated before
+ calling this function
+*/
+void QDeclarativeSearchResultModel::updateLayout(const QList<QPlace> &favoritePlaces)
+{
+ int oldRowCount = rowCount();
+
+ beginResetModel();
+ clearData(true);
+ m_results = m_resultsBuffer;
+ m_resultsBuffer.clear();
+
+ for (int i = 0; i < m_results.count(); ++i) {
+ const QPlaceSearchResult &result = m_results.at(i);
+
+ if (result.type() == QPlaceSearchResult::PlaceResult) {
+ QPlaceResult placeResult = result;
+ QDeclarativePlace *place = new QDeclarativePlace(placeResult.place(), plugin(), this);
+ m_places.append(place);
+
+ if ((favoritePlaces.count() == m_results.count()) && favoritePlaces.at(i) != QPlace())
+ m_places[i]->setFavorite(new QDeclarativePlace(favoritePlaces.at(i),
+ m_favoritesPlugin, m_places[i]));
+ } else if (result.type() == QPlaceSearchResult::ProposedSearchResult) {
+ m_places.append(0);
+ }
+
+ QDeclarativePlaceIcon *icon = 0;
+ if (!result.icon().isEmpty())
+ icon = new QDeclarativePlaceIcon(result.icon(), plugin(), this);
+ m_icons.append(icon);
+ }
+
+ endResetModel();
+ if (m_results.count() != oldRowCount)
+ emit rowCountChanged();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchResultModel::placeUpdated(const QString &placeId)
+{
+ int row = getRow(placeId);
+ if (row < 0 || row > m_places.count())
+ return;
+
+ if (m_places.at(row))
+ m_places.at(row)->getDetails();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchResultModel::placeRemoved(const QString &placeId)
+{
+ int row = getRow(placeId);
+ if (row < 0 || row > m_places.count())
+ return;
+
+ beginRemoveRows(QModelIndex(), row, row);
+ delete m_places.at(row);
+ m_places.removeAt(row);
+ m_results.removeAt(row);
+ endRemoveRows();
+
+ emit rowCountChanged();
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeSearchResultModel::getRow(const QString &placeId) const
+{
+ for (int i = 0; i < m_places.count(); ++i) {
+ if (!m_places.at(i))
+ continue;
+ else if (m_places.at(i)->placeId() == placeId)
+ return i;
+ }
+
+ return -1;
+}
+
+/*!
+ \qmlsignal PlaceSearchResultModel::dataChanged()
+
+ This signal is emitted when significant changes have been made to the underlying datastore.
+
+ Applications should act on this signal at their own discretion. The data
+ provided by the model could be out of date and so the model should be reupdated
+ sometime, however an immediate reupdate may be disconcerting to users if the results
+ change without any action on their part.
+
+ The corresponding handler is \c onDataChanged.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h b/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h
new file mode 100644
index 00000000..77526fd0
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVESEARCHRESULTMODEL_P_H
+#define QDECLARATIVESEARCHRESULTMODEL_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/qdeclarativesearchmodelbase_p.h>
+#include <QtLocation/private/qdeclarativecategory_p.h>
+#include <QtLocation/private/qdeclarativeplace_p.h>
+#include <QtLocation/private/qdeclarativeplaceicon_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGeoServiceProvider;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchResultModel : public QDeclarativeSearchModelBase
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString searchTerm READ searchTerm WRITE setSearchTerm NOTIFY searchTermChanged)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeCategory> categories READ categories NOTIFY categoriesChanged)
+ Q_PROPERTY(QString recommendationId READ recommendationId WRITE setRecommendationId NOTIFY recommendationIdChanged)
+ Q_PROPERTY(RelevanceHint relevanceHint READ relevanceHint WRITE setRelevanceHint NOTIFY relevanceHintChanged)
+ Q_PROPERTY(QDeclarativePlace::Visibility visibilityScope READ visibilityScope WRITE setVisibilityScope NOTIFY visibilityScopeChanged)
+
+ Q_PROPERTY(int count READ rowCount NOTIFY rowCountChanged)
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *favoritesPlugin READ favoritesPlugin WRITE setFavoritesPlugin NOTIFY favoritesPluginChanged)
+ Q_PROPERTY(QVariantMap favoritesMatchParameters READ favoritesMatchParameters WRITE setFavoritesMatchParameters NOTIFY favoritesMatchParametersChanged)
+
+ Q_ENUMS(SearchResultType RelevanceHint)
+
+public:
+ enum SearchResultType {
+ UnknownSearchResult = QPlaceSearchResult::UnknownSearchResult,
+ PlaceResult = QPlaceSearchResult::PlaceResult,
+ ProposedSearchResult = QPlaceSearchResult::ProposedSearchResult
+ };
+
+ enum RelevanceHint {
+ UnspecifiedHint = QPlaceSearchRequest::UnspecifiedHint,
+ DistanceHint = QPlaceSearchRequest::DistanceHint,
+ LexicalPlaceNameHint = QPlaceSearchRequest::LexicalPlaceNameHint
+ };
+
+ explicit QDeclarativeSearchResultModel(QObject *parent = 0);
+ ~QDeclarativeSearchResultModel();
+
+ QString searchTerm() const;
+ void setSearchTerm(const QString &searchTerm);
+
+ QQmlListProperty<QDeclarativeCategory> categories();
+ static void categories_append(QQmlListProperty<QDeclarativeCategory> *list,
+ QDeclarativeCategory *category);
+ static int categories_count(QQmlListProperty<QDeclarativeCategory> *list);
+ static QDeclarativeCategory *category_at(QQmlListProperty<QDeclarativeCategory> *list, int index);
+ static void categories_clear(QQmlListProperty<QDeclarativeCategory> *list);
+
+ QString recommendationId() const;
+ void setRecommendationId(const QString &recommendationId);
+
+ QDeclarativeSearchResultModel::RelevanceHint relevanceHint() const;
+ void setRelevanceHint(QDeclarativeSearchResultModel::RelevanceHint hint);
+
+ QDeclarativePlace::Visibility visibilityScope() const;
+ void setVisibilityScope(QDeclarativePlace::Visibility visibilityScope);
+
+ QDeclarativeGeoServiceProvider *favoritesPlugin() const;
+ void setFavoritesPlugin(QDeclarativeGeoServiceProvider *plugin);
+
+ QVariantMap favoritesMatchParameters() const;
+ void setFavoritesMatchParameters(const QVariantMap &parameters);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+
+ virtual void clearData(bool suppressSignal = false);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ Q_INVOKABLE QVariant data(int index, const QString &roleName) const;
+ QHash<int, QByteArray> roleNames() const;
+
+ Q_INVOKABLE void updateWith(int proposedSearchIndex);
+
+ void updateSearchRequest();
+
+Q_SIGNALS:
+ void searchTermChanged();
+ void categoriesChanged();
+ void recommendationIdChanged();
+ void relevanceHintChanged();
+ void visibilityScopeChanged();
+
+ void rowCountChanged();
+ void favoritesPluginChanged();
+ void favoritesMatchParametersChanged();
+ void dataChanged();
+
+protected:
+ QPlaceReply *sendQuery(QPlaceManager *manager, const QPlaceSearchRequest &request);
+ virtual void initializePlugin(QDeclarativeGeoServiceProvider *plugin);
+
+protected Q_SLOTS:
+ virtual void queryFinished();
+
+private Q_SLOTS:
+ void updateLayout(const QList<QPlace> &favoritePlaces = QList<QPlace>());
+
+ void placeUpdated(const QString &placeId);
+ void placeRemoved(const QString &placeId);
+
+private:
+ enum Roles {
+ SearchResultTypeRole = Qt::UserRole,
+ TitleRole,
+ IconRole,
+ DistanceRole,
+ PlaceRole,
+ SponsoredRole
+ };
+
+ int getRow(const QString &placeId) const;
+ QList<QDeclarativeCategory *> m_categories;
+ QLocation::VisibilityScope m_visibilityScope;
+
+ QList<QPlaceSearchResult> m_results;
+ QList<QPlaceSearchResult> m_resultsBuffer;
+ QList<QDeclarativePlace *> m_places;
+ QList<QDeclarativePlaceIcon *> m_icons;
+
+ QDeclarativeGeoServiceProvider *m_favoritesPlugin;
+ QVariantMap m_matchParameters;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESEARCHRESULTMODEL_P_H
diff --git a/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp
new file mode 100644
index 00000000..95cd3277
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp
@@ -0,0 +1,353 @@
+/****************************************************************************
+**
+** 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 "qdeclarativesearchsuggestionmodel_p.h"
+#include "qdeclarativegeoserviceprovider_p.h"
+
+#include <QtQml/QQmlInfo>
+#include <QtLocation/QGeoServiceProvider>
+
+#include <qplacemanager.h>
+#include <qplacesearchrequest.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype PlaceSearchSuggestionModel
+ \instantiates QDeclarativeSearchSuggestionModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-models
+ \since Qt Location 5.5
+
+ \brief Provides access to search term suggestions.
+
+ The PlaceSearchSuggestionModel can be used to provide search term suggestions as the user enters their
+ search term. The properties of this model should match that of the \l PlaceSearchModel, which
+ will be used to perform the actual search query, to ensure that the search suggestion results are
+ relevant.
+
+ There are two ways of accessing the data provided by this model, either through the
+ \l suggestions property or through views and delegates. The latter is the preferred
+ method.
+
+ The \l offset and \l limit properties can be used to access paged suggestions. When the
+ \l offset and \l limit properties are set the suggestions between \l offset and
+ (\l offset + \l limit - 1) will be returned. Support for paging may vary
+ from plugin to plugin.
+
+ The model returns data for the following roles:
+
+ \table
+ \header
+ \li Role
+ \li Type
+ \li Description
+ \row
+ \li suggestion
+ \li string
+ \li Suggested search term.
+ \endtable
+
+ The following example shows how to use the PlaceSearchSuggestionModel to get suggested search terms
+ from a partial search term. The \l searchArea is set to match what would be used to perform the
+ actual place search with \l PlaceSearchModel.
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml SearchSuggestionModel
+
+ \sa PlaceSearchModel, {QPlaceManager}
+*/
+
+/*!
+ \qmlproperty Plugin PlaceSearchSuggestionModel::plugin
+
+ This property holds the provider \l Plugin which will be used to perform the search.
+*/
+
+/*!
+ \qmlproperty geoshape PlaceSearchSuggestionModel::searchArea
+
+ This property holds the search area. Search suggestion results returned by the model will be
+ relevant to the given search area.
+
+ If this property is set to a \l {geocircle} its
+ \l {geocircle}{radius} property may be left unset, in which case the \l Plugin
+ will choose an appropriate radius for the search.
+*/
+
+/*!
+ \qmlproperty int PlaceSearchSuggestionModel::offset
+
+ This property holds the index of the first item in the model.
+
+ \sa limit
+*/
+
+/*!
+ \qmlproperty int PlaceSearchSuggestionModel::limit
+
+ This property holds the limit of the number of items that will be returned.
+
+ \sa offset
+*/
+
+/*!
+ \qmlproperty enum PlaceSearchSuggestionModel::status
+
+ This property holds the status of the model. It can be one of:
+
+ \table
+ \row
+ \li PlaceSearchSuggestionModel.Null
+ \li No search query has been executed. The model is empty.
+ \row
+ \li PlaceSearchSuggestionModel.Ready
+ \li The search query has completed, and the results are available.
+ \row
+ \li PlaceSearchSuggestionModel.Loading
+ \li A search query is currently being executed.
+ \row
+ \li PlaceSearchSuggestionModel.Error
+ \li An error occurred when executing the previous search query.
+ \endtable
+*/
+
+/*!
+ \qmlmethod void PlaceSearchSuggestionModel::update()
+
+ Updates the model based on the provided query parameters. The model will be populated with a
+ list of search suggestions for the partial \l searchTerm and \l searchArea. If the \l plugin
+ supports it, other parameters such as \l limit and \l offset may be specified. \c update()
+ submits the set of parameters to the \l plugin to process.
+
+
+ While the model is updating the \l status of the model is set to
+ \c PlaceSearchSuggestionModel.Loading. If the model is successfully updated, the \l status is
+ set to \c PlaceSearchSuggestionModel.Ready, while if it unsuccessfully completes, the \l status
+ is set to \c PlaceSearchSuggestionModel.Error and the model cleared.
+
+ This example shows use of the model
+ \code
+ PlaceSeachSuggestionModel {
+ id: model
+ plugin: backendPlugin
+ searchArea: QtPositioning.circle(QtPositioning.coordinate(10, 10))
+ ...
+ }
+
+ MouseArea {
+ ...
+ onClicked: {
+ model.searchTerm = "piz"
+ model.searchArea.center.latitude = -27.5;
+ model.searchArea.cetner.longitude = 153;
+ model.update();
+ }
+ }
+ \endcode
+
+ A more detailed example can be found in the in
+ \l {Places (QML)#Presenting-Search-Suggestions}{Places (QML)} example.
+
+ \sa cancel(), status
+*/
+
+/*!
+ \qmlmethod void PlaceSearchSuggestionModel::cancel()
+
+ Cancels an ongoing search suggestion operation immediately and sets the model
+ status to PlaceSearchSuggestionModel.Ready. The model retains any search
+ suggestions it had before the operation was started.
+
+ If an operation is not ongoing, invoking cancel() has no effect.
+
+ \sa update(), status
+*/
+
+/*!
+ \qmlmethod void PlaceSearchSuggestionModel::reset()
+
+ Resets the model. All search suggestions are cleared, any outstanding requests are aborted and
+ possible errors are cleared. Model status will be set to PlaceSearchSuggestionModel.Null.
+*/
+
+
+/*!
+ \qmlmethod string QtLocation::PlaceSearchSuggestionModel::errorString() const
+
+ This read-only property holds the textual presentation of the latest search suggestion model error.
+ If no error has occurred, or if the model was cleared, an empty string is returned.
+
+ An empty string may also be returned if an error occurred which has no associated
+ textual representation.
+*/
+
+QDeclarativeSearchSuggestionModel::QDeclarativeSearchSuggestionModel(QObject *parent)
+: QDeclarativeSearchModelBase(parent)
+{
+}
+
+QDeclarativeSearchSuggestionModel::~QDeclarativeSearchSuggestionModel()
+{
+}
+
+/*!
+ \qmlproperty string PlaceSearchSuggestionModel::searchTerm
+
+ This property holds the partial search term used in query.
+*/
+QString QDeclarativeSearchSuggestionModel::searchTerm() const
+{
+ return m_request.searchTerm();
+}
+
+void QDeclarativeSearchSuggestionModel::setSearchTerm(const QString &searchTerm)
+{
+ if (m_request.searchTerm() == searchTerm)
+ return;
+
+ m_request.setSearchTerm(searchTerm);
+ emit searchTermChanged();
+}
+
+/*!
+ \qmlproperty stringlist PlaceSearchSuggestionModel::suggestions
+
+ This property holds the list of predicted search terms that the model currently has.
+*/
+QStringList QDeclarativeSearchSuggestionModel::suggestions() const
+{
+ return m_suggestions;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchSuggestionModel::clearData(bool suppressSignal)
+{
+ QDeclarativeSearchModelBase::clearData(suppressSignal);
+
+ if (!m_suggestions.isEmpty()) {
+ m_suggestions.clear();
+
+ if (!suppressSignal)
+ emit suggestionsChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeSearchSuggestionModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+
+ return m_suggestions.count();
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeSearchSuggestionModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.row() >= rowCount(index.parent()) || index.row() < 0)
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case SearchSuggestionRole:
+ return m_suggestions.at(index.row());
+ }
+
+ return QVariant();
+}
+
+QHash<int, QByteArray> QDeclarativeSearchSuggestionModel::roleNames() const
+{
+ QHash<int, QByteArray> roleNames = QDeclarativeSearchModelBase::roleNames();
+ roleNames.insert(SearchSuggestionRole, "suggestion");
+ return roleNames;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSearchSuggestionModel::queryFinished()
+{
+ if (!m_reply)
+ return;
+
+ QPlaceReply *reply = m_reply;
+ m_reply = 0;
+
+ int initialCount = m_suggestions.count();
+ beginResetModel();
+
+ clearData(true);
+
+ QPlaceSearchSuggestionReply *suggestionReply = qobject_cast<QPlaceSearchSuggestionReply *>(reply);
+ m_suggestions = suggestionReply->suggestions();
+
+ if (initialCount != m_suggestions.count())
+ emit suggestionsChanged();
+
+ endResetModel();
+
+ if (suggestionReply->error() != QPlaceReply::NoError)
+ setStatus(Error, suggestionReply->errorString());
+ else
+ setStatus(Ready);
+
+
+ reply->deleteLater();
+}
+
+/*!
+ \internal
+*/
+QPlaceReply *QDeclarativeSearchSuggestionModel::sendQuery(QPlaceManager *manager,
+ const QPlaceSearchRequest &request)
+{
+ return manager->searchSuggestions(request);
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h
new file mode 100644
index 00000000..5d75ee4b
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVESEARCHSUGGESTIONMODEL_P_H
+#define QDECLARATIVESEARCHSUGGESTIONMODEL_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/qdeclarativesearchmodelbase_p.h>
+
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGeoServiceProvider;
+class QGeoServiceProvider;
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchSuggestionModel : public QDeclarativeSearchModelBase
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString searchTerm READ searchTerm WRITE setSearchTerm NOTIFY searchTermChanged)
+ Q_PROPERTY(QStringList suggestions READ suggestions NOTIFY suggestionsChanged)
+
+public:
+ explicit QDeclarativeSearchSuggestionModel(QObject *parent = 0);
+ ~QDeclarativeSearchSuggestionModel();
+
+ QString searchTerm() const;
+ void setSearchTerm(const QString &searchTerm);
+
+ QStringList suggestions() const;
+
+ void clearData(bool suppressSignal = false);
+
+ // From QAbstractListModel
+ int rowCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QHash<int, QByteArray> roleNames() const;
+
+ enum Roles {
+ SearchSuggestionRole = Qt::UserRole
+ };
+
+protected Q_SLOTS:
+ virtual void queryFinished();
+
+Q_SIGNALS:
+ void searchTermChanged();
+ void suggestionsChanged();
+
+protected:
+ QPlaceReply *sendQuery(QPlaceManager *manager, const QPlaceSearchRequest &request);
+
+private:
+ QStringList m_suggestions;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/location/declarativeplaces/qdeclarativesupplier.cpp b/src/location/declarativeplaces/qdeclarativesupplier.cpp
new file mode 100644
index 00000000..92e9a8fd
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesupplier.cpp
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** 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 "qdeclarativesupplier_p.h"
+
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Supplier
+ \instantiates QDeclarativeSupplier
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-data
+ \since Qt Location 5.5
+
+ \brief Holds data regarding the supplier of a place, a place's image, review, or editorial.
+
+ Each instance represents a set of data about a supplier, which can include
+ supplier's name, url and icon. The supplier is typically a business or organization.
+
+ Note: The Places API only supports suppliers as 'retrieve-only' objects. Submitting
+ suppliers to a provider is not a supported use case.
+
+ \sa ImageModel, ReviewModel, EditorialModel
+
+ \section1 Example
+
+ The following example shows how to create and display a supplier in QML:
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml Supplier
+*/
+
+QDeclarativeSupplier::QDeclarativeSupplier(QObject *parent)
+ : QObject(parent), m_icon(0)
+{
+}
+
+QDeclarativeSupplier::QDeclarativeSupplier(const QPlaceSupplier &src,
+ QDeclarativeGeoServiceProvider *plugin,
+ QObject *parent)
+ : QObject(parent),
+ m_src(src),
+ m_icon(0)
+{
+ setSupplier(src, plugin);
+}
+
+QDeclarativeSupplier::~QDeclarativeSupplier()
+{
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupplier::componentComplete()
+{
+ // delayed instantiation of QObject based properties.
+ if (!m_icon)
+ m_icon = new QDeclarativePlaceIcon(this);
+}
+
+/*!
+ \qmlproperty QPlaceSupplier Supplier::supplier
+
+ For details on how to use this property to interface between C++ and QML see
+ "\l {Supplier - QPlaceSupplier} {Interfaces between C++ and QML Code}".
+*/
+void QDeclarativeSupplier::setSupplier(const QPlaceSupplier &src, QDeclarativeGeoServiceProvider *plugin)
+{
+ QPlaceSupplier previous = m_src;
+ m_src = src;
+
+ if (previous.name() != m_src.name())
+ emit nameChanged();
+
+ if (previous.supplierId() != m_src.supplierId())
+ emit supplierIdChanged();
+
+ if (previous.url() != m_src.url())
+ emit urlChanged();
+
+ if (m_icon && m_icon->parent() == this) {
+ m_icon->setPlugin(plugin);
+ m_icon->setIcon(m_src.icon());
+ } else if (!m_icon || m_icon->parent() != this) {
+ m_icon = new QDeclarativePlaceIcon(m_src.icon(), plugin, this);
+ emit iconChanged();
+ }
+}
+
+QPlaceSupplier QDeclarativeSupplier::supplier()
+{
+ m_src.setIcon(m_icon ? m_icon->icon() : QPlaceIcon());
+ return m_src;
+}
+
+/*!
+ \qmlproperty string Supplier::supplierId
+
+ This property holds the identifier of the supplier. The identifier is unique
+ to the Plugin backend which provided the supplier and is generally
+ not suitable for displaying to the user.
+*/
+
+void QDeclarativeSupplier::setSupplierId(const QString &supplierId)
+{
+ if (m_src.supplierId() != supplierId) {
+ m_src.setSupplierId(supplierId);
+ emit supplierIdChanged();
+ }
+}
+
+QString QDeclarativeSupplier::supplierId() const
+{
+ return m_src.supplierId();
+}
+
+/*!
+ \qmlproperty string Supplier::name
+
+ This property holds the name of the supplier which can be displayed
+ to the user.
+
+ The name can potentially be localized. The language is dependent on the
+ entity that sets it, typically this is the \l Plugin. The \l {Plugin::locales}
+ property defines what language is used.
+*/
+
+void QDeclarativeSupplier::setName(const QString &name)
+{
+ if (m_src.name() != name) {
+ m_src.setName(name);
+ emit nameChanged();
+ }
+}
+
+QString QDeclarativeSupplier::name() const
+{
+ return m_src.name();
+}
+
+/*!
+ \qmlproperty url Supplier::url
+
+ This property holds the URL of the supplier's website.
+*/
+
+void QDeclarativeSupplier::setUrl(const QUrl &url)
+{
+ if (m_src.url() != url) {
+ m_src.setUrl(url);
+ emit urlChanged();
+ }
+}
+
+QUrl QDeclarativeSupplier::url() const
+{
+ return m_src.url();
+}
+
+/*!
+ \qmlproperty PlaceIcon Supplier::icon
+
+ This property holds the icon of the supplier.
+*/
+QDeclarativePlaceIcon *QDeclarativeSupplier::icon() const
+{
+ return m_icon;
+}
+
+void QDeclarativeSupplier::setIcon(QDeclarativePlaceIcon *icon)
+{
+ if (m_icon == icon)
+ return;
+
+ if (m_icon && m_icon->parent() == this)
+ delete m_icon;
+
+ m_icon = icon;
+ emit iconChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativesupplier_p.h b/src/location/declarativeplaces/qdeclarativesupplier_p.h
new file mode 100644
index 00000000..b344d674
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesupplier_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 QDECLARATIVESUPPLIER_P_H
+#define QDECLARATIVESUPPLIER_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 <QObject>
+#include <QtCore/QUrl>
+#include <QtQml/qqml.h>
+#include <QtQml/QQmlParserStatus>
+#include <QtLocation/qplacesupplier.h>
+
+#include <QtLocation/private/qdeclarativeplaceicon_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSupplier : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPlaceSupplier supplier READ supplier WRITE setSupplier)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QString supplierId READ supplierId WRITE setSupplierId NOTIFY supplierIdChanged)
+ Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
+ Q_PROPERTY(QDeclarativePlaceIcon *icon READ icon WRITE setIcon NOTIFY iconChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ explicit QDeclarativeSupplier(QObject *parent = 0);
+ explicit QDeclarativeSupplier(const QPlaceSupplier &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent = 0);
+ ~QDeclarativeSupplier();
+
+ // From QQmlParserStatus
+ void classBegin() { }
+ void componentComplete();
+
+ QPlaceSupplier supplier();
+ void setSupplier(const QPlaceSupplier &src, QDeclarativeGeoServiceProvider *plugin = 0);
+
+ QString name() const;
+ void setName(const QString &data);
+ QString supplierId() const;
+ void setSupplierId(const QString &data);
+ QUrl url() const;
+ void setUrl(const QUrl &data);
+
+ QDeclarativePlaceIcon *icon() const;
+ void setIcon(QDeclarativePlaceIcon *icon);
+
+Q_SIGNALS:
+ void nameChanged();
+ void supplierIdChanged();
+ void urlChanged();
+ void iconChanged();
+
+private:
+ QPlaceSupplier m_src;
+ QDeclarativePlaceIcon *m_icon;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeSupplier)
+
+#endif // QDECLARATIVESUPPLIER_P_H
diff --git a/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp
new file mode 100644
index 00000000..d832ff40
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp
@@ -0,0 +1,689 @@
+/****************************************************************************
+**
+** 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 "qdeclarativesupportedcategoriesmodel_p.h"
+#include "qdeclarativeplaceicon_p.h"
+#include "qgeoserviceprovider.h"
+#include "error_messages.h"
+
+#include <QCoreApplication>
+#include <QtQml/QQmlInfo>
+#include <QtLocation/QPlaceManager>
+#include <QtLocation/QPlaceIcon>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype CategoryModel
+ \instantiates QDeclarativeSupportedCategoriesModel
+ \inqmlmodule QtLocation
+ \ingroup qml-QtLocation5-places
+ \ingroup qml-QtLocation5-places-models
+ \since Qt Location 5.5
+
+ \brief The CategoryModel type provides a model of the categories supported by a \l Plugin.
+
+ The CategoryModel type provides a model of the categories that are available from the
+ current \l Plugin. The model supports both a flat list of categories and a hierarchical tree
+ representing category groupings. This can be controlled by the \l hierarchical property.
+
+ The model supports the following roles:
+
+ \table
+ \header
+ \li Role
+ \li Type
+ \li Description
+ \row
+ \li category
+ \li \l Category
+ \li Category object for the current item.
+ \row
+ \li parentCategory
+ \li \l Category
+ \li Parent category object for the current item.
+ If there is no parent, null is returned.
+ \endtable
+
+ The following example displays a flat list of all available categories:
+
+ \snippet declarative/places.qml QtQuick import
+ \snippet declarative/maps.qml QtLocation import
+ \codeline
+ \snippet declarative/places.qml CategoryView
+
+ To access the hierarchical category model it is necessary to use a \l DelegateModel to access
+ the child items.
+*/
+
+/*!
+ \qmlproperty Plugin CategoryModel::plugin
+
+ This property holds the provider \l Plugin used by this model.
+*/
+
+/*!
+ \qmlproperty bool CategoryModel::hierarchical
+
+ This property holds whether the model provides a hierarchical tree of categories or a flat
+ list. The default is true.
+*/
+
+/*!
+ \qmlmethod string QtLocation::CategoryModel::data(ModelIndex index, int role)
+ \internal
+
+ This method retrieves the model's data per \a index and \a role.
+*/
+
+/*!
+ \qmlmethod string QtLocation::CategoryModel::errorString() const
+
+ This read-only property holds the textual presentation of the latest category model 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.
+*/
+
+/*!
+ \internal
+ \enum QDeclarativeSupportedCategoriesModel::Roles
+*/
+
+QDeclarativeSupportedCategoriesModel::QDeclarativeSupportedCategoriesModel(QObject *parent)
+: QAbstractItemModel(parent), m_response(0), m_plugin(0), m_hierarchical(true),
+ m_complete(false), m_status(Null)
+{
+}
+
+QDeclarativeSupportedCategoriesModel::~QDeclarativeSupportedCategoriesModel()
+{
+ qDeleteAll(m_categoriesTree);
+}
+
+/*!
+ \internal
+*/
+// From QQmlParserStatus
+void QDeclarativeSupportedCategoriesModel::componentComplete()
+{
+ m_complete = true;
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeSupportedCategoriesModel::rowCount(const QModelIndex &parent) const
+{
+ if (m_categoriesTree.keys().isEmpty())
+ return 0;
+
+ PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(parent.internalPointer());
+ if (!node)
+ node = m_categoriesTree.value(QString());
+ else if (m_categoriesTree.keys(node).isEmpty())
+ return 0;
+
+ return node->childIds.count();
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeSupportedCategoriesModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+
+ return 1;
+}
+
+/*!
+ \internal
+*/
+QModelIndex QDeclarativeSupportedCategoriesModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (column != 0 || row < 0)
+ return QModelIndex();
+
+ PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(parent.internalPointer());
+
+ if (!node)
+ node = m_categoriesTree.value(QString());
+ else if (m_categoriesTree.keys(node).isEmpty()) //return root index if parent is non-existent
+ return QModelIndex();
+
+ if (row > node->childIds.count())
+ return QModelIndex();
+
+ QString id = node->childIds.at(row);
+ Q_ASSERT(m_categoriesTree.contains(id));
+
+ return createIndex(row, 0, m_categoriesTree.value(id));
+}
+
+/*!
+ \internal
+*/
+QModelIndex QDeclarativeSupportedCategoriesModel::parent(const QModelIndex &child) const
+{
+ PlaceCategoryNode *childNode = static_cast<PlaceCategoryNode *>(child.internalPointer());
+ if (m_categoriesTree.keys(childNode).isEmpty())
+ return QModelIndex();
+
+ return index(childNode->parentId);
+}
+
+/*!
+ \internal
+*/
+QVariant QDeclarativeSupportedCategoriesModel::data(const QModelIndex &index, int role) const
+{
+ PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(index.internalPointer());
+ if (!node)
+ node = m_categoriesTree.value(QString());
+ else if (m_categoriesTree.keys(node).isEmpty())
+ return QVariant();
+
+ QDeclarativeCategory *category = node->declCategory.data();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ return category->name();
+ case CategoryRole:
+ return QVariant::fromValue(category);
+ case ParentCategoryRole: {
+ if (!m_categoriesTree.keys().contains(node->parentId))
+ return QVariant();
+ else
+ return QVariant::fromValue(m_categoriesTree.value(node->parentId)->declCategory.data());
+ }
+ default:
+ return QVariant();
+ }
+}
+
+QHash<int, QByteArray> QDeclarativeSupportedCategoriesModel::roleNames() const
+{
+ QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
+ roles.insert(CategoryRole, "category");
+ roles.insert(ParentCategoryRole, "parentCategory");
+ return roles;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::setPlugin(QDeclarativeGeoServiceProvider *plugin)
+{
+ if (m_plugin == plugin)
+ return;
+
+ //disconnect the manager of the old plugin if we have one
+ if (m_plugin) {
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (serviceProvider) {
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (placeManager) {
+ disconnect(placeManager, SIGNAL(categoryAdded(QPlaceCategory,QString)),
+ this, SLOT(addedCategory(QPlaceCategory,QString)));
+ disconnect(placeManager, SIGNAL(categoryUpdated(QPlaceCategory,QString)),
+ this, SLOT(updatedCategory(QPlaceCategory,QString)));
+ disconnect(placeManager, SIGNAL(categoryRemoved(QString,QString)),
+ this, SLOT(removedCategory(QString,QString)));
+ disconnect(placeManager, SIGNAL(dataChanged()),
+ this, SIGNAL(dataChanged()));
+ }
+ }
+ }
+
+ m_plugin = plugin;
+
+ // handle plugin name changes -> update categories
+ if (m_plugin) {
+ connect(m_plugin, SIGNAL(nameChanged(QString)), this, SLOT(connectNotificationSignals()));
+ connect(m_plugin, SIGNAL(nameChanged(QString)), this, SLOT(update()));
+ }
+
+ connectNotificationSignals();
+
+ if (m_complete)
+ emit pluginChanged();
+}
+
+/*!
+ \internal
+*/
+QDeclarativeGeoServiceProvider *QDeclarativeSupportedCategoriesModel::plugin() const
+{
+ return m_plugin;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::setHierarchical(bool hierarchical)
+{
+ if (m_hierarchical == hierarchical)
+ return;
+
+ m_hierarchical = hierarchical;
+ emit hierarchicalChanged();
+
+ updateLayout();
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeSupportedCategoriesModel::hierarchical() const
+{
+ return m_hierarchical;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::replyFinished()
+{
+ if (!m_response)
+ return;
+
+ m_response->deleteLater();
+
+ if (m_response->error() == QPlaceReply::NoError) {
+ m_errorString.clear();
+
+ m_response = 0;
+
+ updateLayout();
+ setStatus(QDeclarativeSupportedCategoriesModel::Ready);
+ } else {
+ const QString errorString = m_response->errorString();
+
+ m_response = 0;
+
+ setStatus(Error, errorString);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::addedCategory(const QPlaceCategory &category,
+ const QString &parentId)
+{
+ if (m_response)
+ return;
+
+ if (!m_categoriesTree.contains(parentId))
+ return;
+
+ if (category.categoryId().isEmpty())
+ return;
+
+ PlaceCategoryNode *parentNode = m_categoriesTree.value(parentId);
+ if (!parentNode)
+ return;
+
+ int rowToBeAdded = rowToAddChild(parentNode, category);
+ QModelIndex parentIndex = index(parentId);
+ beginInsertRows(parentIndex, rowToBeAdded, rowToBeAdded);
+ PlaceCategoryNode *categoryNode = new PlaceCategoryNode;
+ categoryNode->parentId = parentId;
+ categoryNode->declCategory = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(category, m_plugin, this));
+
+ m_categoriesTree.insert(category.categoryId(), categoryNode);
+ parentNode->childIds.insert(rowToBeAdded,category.categoryId());
+ endInsertRows();
+
+ //this is a workaround to deal with the fact that the hasModelChildren field of DelegateModel
+ //does not get updated when a child is added to a model
+ beginResetModel();
+ endResetModel();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::updatedCategory(const QPlaceCategory &category,
+ const QString &parentId)
+{
+ if (m_response)
+ return;
+
+ QString categoryId = category.categoryId();
+
+ if (!m_categoriesTree.contains(parentId))
+ return;
+
+ if (category.categoryId().isEmpty() || !m_categoriesTree.contains(categoryId))
+ return;
+
+ PlaceCategoryNode *newParentNode = m_categoriesTree.value(parentId);
+ if (!newParentNode)
+ return;
+
+ PlaceCategoryNode *categoryNode = m_categoriesTree.value(categoryId);
+ if (!categoryNode)
+ return;
+
+ categoryNode->declCategory->setCategory(category);
+
+ if (categoryNode->parentId == parentId) { //reparenting to same parent
+ QModelIndex parentIndex = index(parentId);
+ int rowToBeAdded = rowToAddChild(newParentNode, category);
+ int oldRow = newParentNode->childIds.indexOf(categoryId);
+
+ //check if we are changing the position of the category
+ if (qAbs(rowToBeAdded - newParentNode->childIds.indexOf(categoryId)) > 1) {
+ //if the position has changed we are moving rows
+ beginMoveRows(parentIndex, oldRow, oldRow,
+ parentIndex, rowToBeAdded);
+
+ newParentNode->childIds.removeAll(categoryId);
+ newParentNode->childIds.insert(rowToBeAdded, categoryId);
+ endMoveRows();
+ } else {// if the position has not changed we modifying an existing row
+ QModelIndex categoryIndex = index(categoryId);
+ emit dataChanged(categoryIndex, categoryIndex);
+ }
+ } else { //reparenting to different parents
+ QPlaceCategory oldCategory = categoryNode->declCategory->category();
+ PlaceCategoryNode *oldParentNode = m_categoriesTree.value(categoryNode->parentId);
+ if (!oldParentNode)
+ return;
+ QModelIndex oldParentIndex = index(categoryNode->parentId);
+ QModelIndex newParentIndex = index(parentId);
+
+ int rowToBeAdded = rowToAddChild(newParentNode, category);
+ beginMoveRows(oldParentIndex, oldParentNode->childIds.indexOf(categoryId),
+ oldParentNode->childIds.indexOf(categoryId), newParentIndex, rowToBeAdded);
+ oldParentNode->childIds.removeAll(oldCategory.categoryId());
+ newParentNode->childIds.insert(rowToBeAdded, categoryId);
+ categoryNode->parentId = parentId;
+ endMoveRows();
+
+ //this is a workaround to deal with the fact that the hasModelChildren field of DelegateModel
+ //does not get updated when an index is updated to contain children
+ beginResetModel();
+ endResetModel();
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::removedCategory(const QString &categoryId, const QString &parentId)
+{
+ if (m_response)
+ return;
+
+ if (!m_categoriesTree.contains(categoryId) || !m_categoriesTree.contains(parentId))
+ return;
+
+ QModelIndex parentIndex = index(parentId);
+ QModelIndex categoryIndex = index(categoryId);
+
+ beginRemoveRows(parentIndex, categoryIndex.row(), categoryIndex.row());
+ PlaceCategoryNode *parentNode = m_categoriesTree.value(parentId);
+ parentNode->childIds.removeAll(categoryId);
+ delete m_categoriesTree.take(categoryId);
+ endRemoveRows();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::connectNotificationSignals()
+{
+ if (!m_plugin)
+ return;
+
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (!serviceProvider || serviceProvider->error() != QGeoServiceProvider::NoError)
+ return;
+
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (!placeManager)
+ return;
+
+ // listen for any category notifications so that we can reupdate the categories
+ // model.
+ connect(placeManager, SIGNAL(categoryAdded(QPlaceCategory,QString)),
+ this, SLOT(addedCategory(QPlaceCategory,QString)));
+ connect(placeManager, SIGNAL(categoryUpdated(QPlaceCategory,QString)),
+ this, SLOT(updatedCategory(QPlaceCategory,QString)));
+ connect(placeManager, SIGNAL(categoryRemoved(QString,QString)),
+ this, SLOT(removedCategory(QString,QString)));
+ connect(placeManager, SIGNAL(dataChanged()),
+ this, SIGNAL(dataChanged()));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::update()
+{
+ if (m_response)
+ return;
+
+ setStatus(Loading);
+
+ if (!m_plugin) {
+ updateLayout();
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROPERTY_NOT_SET));
+ return;
+ }
+
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (!serviceProvider || serviceProvider->error() != QGeoServiceProvider::NoError) {
+ updateLayout();
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROVIDER_ERROR)
+ .arg(m_plugin->name()));
+ return;
+ }
+
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (!placeManager) {
+ updateLayout();
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
+ .arg(m_plugin->name()).arg(serviceProvider->errorString()));
+ return;
+ }
+
+ m_response = placeManager->initializeCategories();
+ if (m_response) {
+ connect(m_response, SIGNAL(finished()), this, SLOT(replyFinished()));
+ } else {
+ updateLayout();
+ setStatus(Error, QCoreApplication::translate(CONTEXT_NAME,
+ CATEGORIES_NOT_INITIALIZED));
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeSupportedCategoriesModel::updateLayout()
+{
+ beginResetModel();
+ qDeleteAll(m_categoriesTree);
+ m_categoriesTree.clear();
+
+ if (m_plugin) {
+ QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
+ if (serviceProvider && serviceProvider->error() == QGeoServiceProvider::NoError) {
+ QPlaceManager *placeManager = serviceProvider->placeManager();
+ if (placeManager) {
+ PlaceCategoryNode *node = new PlaceCategoryNode;
+ node->childIds = populateCategories(placeManager, QPlaceCategory());
+ m_categoriesTree.insert(QString(), node);
+ node->declCategory = QSharedPointer<QDeclarativeCategory>
+ (new QDeclarativeCategory(QPlaceCategory(), m_plugin, this));
+ }
+ }
+ }
+
+ endResetModel();
+}
+
+QString QDeclarativeSupportedCategoriesModel::errorString() const
+{
+ return m_errorString;
+}
+
+/*!
+ \qmlproperty enumeration CategoryModel::status
+
+ This property holds the status of the model. It can be one of:
+
+ \table
+ \row
+ \li CategoryModel.Null
+ \li No category fetch query has been executed. The model is empty.
+ \row
+ \li CategoryModel.Ready
+ \li No error occurred during the last operation, further operations may be performed on
+ the model.
+ \row
+ \li CategoryModel.Loading
+ \li The model is being updated, no other operations may be performed until complete.
+ \row
+ \li CategoryModel.Error
+ \li An error occurred during the last operation, further operations can still be
+ performed on the model.
+ \endtable
+*/
+void QDeclarativeSupportedCategoriesModel::setStatus(Status status, const QString &errorString)
+{
+ Status originalStatus = m_status;
+ m_status = status;
+ m_errorString = errorString;
+
+ if (originalStatus != m_status)
+ emit statusChanged();
+}
+
+QDeclarativeSupportedCategoriesModel::Status QDeclarativeSupportedCategoriesModel::status() const
+{
+ return m_status;
+}
+
+/*!
+ \internal
+*/
+QStringList QDeclarativeSupportedCategoriesModel::populateCategories(QPlaceManager *manager, const QPlaceCategory &parent)
+{
+ Q_ASSERT(manager);
+
+ QStringList childIds;
+ PlaceCategoryNode *node;
+
+ QMap<QString, QPlaceCategory> sortedCategories;
+ foreach ( const QPlaceCategory &category, manager->childCategories(parent.categoryId()))
+ sortedCategories.insert(category.name(), category);
+
+ QMapIterator<QString, QPlaceCategory> iter(sortedCategories);
+ while (iter.hasNext()) {
+ iter.next();
+ node = new PlaceCategoryNode;
+ node->parentId = parent.categoryId();
+ node->declCategory = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(iter.value(), m_plugin ,this));
+
+ if (m_hierarchical)
+ node->childIds = populateCategories(manager, iter.value());
+
+ m_categoriesTree.insert(node->declCategory->categoryId(), node);
+ childIds.append(iter.value().categoryId());
+
+ if (!m_hierarchical) {
+ childIds.append(populateCategories(manager,node->declCategory->category()));
+ }
+ }
+ return childIds;
+}
+
+/*!
+ \internal
+*/
+QModelIndex QDeclarativeSupportedCategoriesModel::index(const QString &categoryId) const
+{
+ if (categoryId.isEmpty())
+ return QModelIndex();
+
+ if (!m_categoriesTree.contains(categoryId))
+ return QModelIndex();
+
+ PlaceCategoryNode *categoryNode = m_categoriesTree.value(categoryId);
+ if (!categoryNode)
+ return QModelIndex();
+
+ QString parentCategoryId = categoryNode->parentId;
+
+ PlaceCategoryNode *parentNode = m_categoriesTree.value(parentCategoryId);
+
+ return createIndex(parentNode->childIds.indexOf(categoryId), 0, categoryNode);
+}
+
+/*!
+ \internal
+*/
+int QDeclarativeSupportedCategoriesModel::rowToAddChild(PlaceCategoryNode *node, const QPlaceCategory &category)
+{
+ Q_ASSERT(node);
+ for (int i = 0; i < node->childIds.count(); ++i) {
+ if (category.name() < m_categoriesTree.value(node->childIds.at(i))->declCategory->name())
+ return i;
+ }
+ return node->childIds.count();
+}
+
+/*!
+ \qmlsignal CategoryModel::dataChanged()
+
+ This signal is emitted when significant changes have been made to the underlying datastore.
+
+ Applications should act on this signal at their own discretion. The data
+ provided by the model could be out of date and so the model should be reupdated
+ sometime, however an immediate reupdate may be disconcerting to users if the categories
+ change without any action on their part.
+
+ The corresponding handler is \c onDataChanged.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h
new file mode 100644
index 00000000..9f17ab4d
--- /dev/null
+++ b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVESUPPORTEDCATEGORIESMODEL_H
+#define QDECLARATIVESUPPORTEDCATEGORIESMODEL_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 <QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QSharedPointer>
+#include <QAbstractListModel>
+#include <QQmlListProperty>
+#include <QtQml/QQmlParserStatus>
+
+#include <QtLocation/QPlaceCategory>
+
+#include <QtLocation/private/qdeclarativecategory_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoServiceProvider;
+class QPlaceManager;
+class QPlaceReply;
+
+class PlaceCategoryNode
+{
+public:
+ QString parentId;
+ QStringList childIds;
+ QSharedPointer<QDeclarativeCategory> declCategory;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSupportedCategoriesModel : public QAbstractItemModel, public QQmlParserStatus
+{
+ Q_OBJECT
+
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
+ Q_PROPERTY(bool hierarchical READ hierarchical WRITE setHierarchical NOTIFY hierarchicalChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+ Q_ENUMS(Roles) //The Roles enum is for internal usage only.
+
+public:
+ explicit QDeclarativeSupportedCategoriesModel(QObject *parent = 0);
+ virtual ~QDeclarativeSupportedCategoriesModel();
+
+ // From QQmlParserStatus
+ virtual void classBegin() {}
+ virtual void componentComplete();
+
+ // From QAbstractItemModel
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ QModelIndex parent(const QModelIndex &child) const;
+
+ Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const;
+ QHash<int, QByteArray> roleNames() const;
+
+ enum Roles {
+ CategoryRole = Qt::UserRole,
+ ParentCategoryRole
+ }; //for internal usage only
+
+ enum Status {Null, Ready, Loading, Error};
+
+ void setPlugin(QDeclarativeGeoServiceProvider *plugin);
+ QDeclarativeGeoServiceProvider *plugin() const;
+
+ void setHierarchical(bool hierarchical);
+ bool hierarchical() const;
+
+ Q_INVOKABLE QString errorString() const;
+
+ Status status() const;
+ void setStatus(Status status, const QString &errorString = QString());
+
+ using QAbstractItemModel::dataChanged;
+Q_SIGNALS:
+ void pluginChanged();
+ void hierarchicalChanged();
+ void statusChanged();
+ void dataChanged();
+
+public Q_SLOTS:
+ void update();
+
+private Q_SLOTS:
+ void replyFinished();
+ void addedCategory(const QPlaceCategory &category, const QString &parentId);
+ void updatedCategory(const QPlaceCategory &category, const QString &parentId);
+ void removedCategory(const QString &categoryId, const QString &parentId);
+ void connectNotificationSignals();
+
+private:
+ QStringList populateCategories(QPlaceManager *, const QPlaceCategory &parent);
+ QModelIndex index(const QString &categoryId) const;
+ int rowToAddChild(PlaceCategoryNode *, const QPlaceCategory &category);
+ void updateLayout();
+
+ QPlaceReply *m_response;
+
+ QDeclarativeGeoServiceProvider *m_plugin;
+ bool m_hierarchical;
+ bool m_complete;
+ Status m_status;
+ QString m_errorString;
+
+ QHash<QString, PlaceCategoryNode *> m_categoriesTree;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeSupportedCategoriesModel)
+
+#endif // QDECLARATIVESUPPORTEDCATEGORIESMODEL_H
diff --git a/src/location/location.pro b/src/location/location.pro
index 3669188c..b43d626a 100644
--- a/src/location/location.pro
+++ b/src/location/location.pro
@@ -1,15 +1,19 @@
TARGET = QtLocation
QT = core-private positioning-private
-
-#INCLUDEPATH += ../3rdparty/poly2tri
-INCLUDEPATH += ../3rdparty/clipper
-INCLUDEPATH += ../3rdparty/clip2tri
-
android {
# adding qtconcurrent dependency here for the osm plugin
QT += concurrent
}
+CONFIG += simd optimize_full
+
+INCLUDEPATH += ../3rdparty/poly2tri
+INCLUDEPATH += ../3rdparty/clipper
+INCLUDEPATH += ../3rdparty/clip2tri
+INCLUDEPATH += ../positioning
+INCLUDEPATH += ../imports/positioning
+INCLUDEPATH *= $$PWD
+
MODULE_PLUGIN_TYPES = \
geoservices
@@ -18,6 +22,7 @@ OTHER_FILES += doc/src/*.qdoc # show .qdoc files in Qt Creator
PUBLIC_HEADERS += \
qlocation.h \
+ qlocationglobal_p.h \
qlocationglobal.h
PRIVATE_HEADERS += \
@@ -28,6 +33,8 @@ SOURCES += \
include(maps/maps.pri)
include(places/places.pri)
+include(declarativemaps/declarativemaps.pri)
+include(declarativeplaces/declarativeplaces.pri)
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS