summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Klocek <michal.klocek@theqtcompany.com>2016-07-28 19:21:35 +0200
committerMichal Klocek <michal.klocek@theqtcompany.com>2016-07-28 19:21:47 +0200
commit1a1d2e3fff5856dc9d1283b510a9f325c6fb8a93 (patch)
tree2c16537e3321cde9ca9730f871f47ed32668e120
parent4e1008b4ac1eea776585ca41a6a3db127cf500ff (diff)
parent75dd424e11964d8755abdb1b12b27a8479353b37 (diff)
downloadqtlocation-1a1d2e3fff5856dc9d1283b510a9f325c6fb8a93.tar.gz
Merge remote-tracking branch 'origin/5.6' into 5.7
Change-Id: I37542960aa091ab2074914a2cebb8c5114237a26
-rw-r--r--LICENSE.GPLv22
-rw-r--r--LICENSE.GPLv32
-rw-r--r--LICENSE.LGPLv212
-rw-r--r--LICENSE.LGPLv32
-rw-r--r--examples/location/location.pro1
-rw-r--r--examples/location/mapviewer/mapviewer.qml1
-rw-r--r--examples/location/minimal_map/doc/images/minimal_map.pngbin0 -> 156053 bytes
-rw-r--r--examples/location/minimal_map/doc/src/minimal_map.qdoc89
-rw-r--r--examples/location/minimal_map/main.cpp53
-rw-r--r--examples/location/minimal_map/main.qml67
-rw-r--r--examples/location/minimal_map/minimal_map.pro10
-rw-r--r--examples/location/minimal_map/qml.qrc6
-rw-r--r--src/imports/location/location.pro3
-rw-r--r--src/imports/location/mapitemviewdelegateincubator.cpp7
-rw-r--r--src/imports/location/mapitemviewdelegateincubator.h7
-rw-r--r--src/imports/location/qdeclarativecirclemapitem.cpp2
-rw-r--r--src/imports/location/qdeclarativegeomap.cpp147
-rw-r--r--src/imports/location/qdeclarativegeomap_p.h1
-rw-r--r--src/imports/location/qdeclarativegeomapitemview.cpp204
-rw-r--r--src/imports/location/qdeclarativegeomapitemview_p.h32
-rw-r--r--src/imports/location/qdeclarativegeomapitemview_p_p.h85
-rw-r--r--src/location/doc/images/api-map.pngbin62031 -> 0 bytes
-rw-r--r--src/location/doc/src/plugins/osm.qdoc25
-rw-r--r--src/location/maps/qgeomap_p.h5
-rw-r--r--src/location/maps/qgeotiledmap.cpp14
-rw-r--r--src/location/maps/qgeotiledmap_p.h5
-rw-r--r--src/location/maps/qgeotiledmappingmanagerengine.cpp12
-rw-r--r--src/location/maps/qgeotilefetcher.cpp9
-rw-r--r--src/location/maps/qgeotilefetcher_p.h1
-rw-r--r--src/plugins/geoservices/osm/osm.pro6
-rw-r--r--src/plugins/geoservices/osm/qgeomapreplyosm.cpp17
-rw-r--r--src/plugins/geoservices/osm/qgeomapreplyosm.h5
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmaposm.cpp65
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmaposm.h7
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp150
-rw-r--r--src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h8
-rw-r--r--src/plugins/geoservices/osm/qgeotilefetcherosm.cpp110
-rw-r--r--src/plugins/geoservices/osm/qgeotilefetcherosm.h27
-rw-r--r--src/plugins/geoservices/osm/qgeotileproviderosm.cpp318
-rw-r--r--src/plugins/geoservices/osm/qgeotileproviderosm.h256
-rw-r--r--src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java4
-rw-r--r--src/plugins/position/android/src/jnipositioning.cpp5
-rw-r--r--src/plugins/position/android/src/qgeopositioninfosource_android.cpp2
-rw-r--r--src/plugins/position/android/src/qgeosatelliteinfosource_android.cpp2
-rw-r--r--tests/auto/declarative_ui/tst_map_item_fit_viewport.qml215
-rw-r--r--tests/auto/declarative_ui/tst_map_itemview.qml2
46 files changed, 1667 insertions, 326 deletions
diff --git a/LICENSE.GPLv2 b/LICENSE.GPLv2
index 6dbb032f..a4244777 100644
--- a/LICENSE.GPLv2
+++ b/LICENSE.GPLv2
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU General Public License version 2, which is displayed below.
-------------------------------------------------------------------------
diff --git a/LICENSE.GPLv3 b/LICENSE.GPLv3
index 4e49b122..71c4ad49 100644
--- a/LICENSE.GPLv3
+++ b/LICENSE.GPLv3
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 3. That license references
the General Public License version 3, that is displayed below. Other
portions of the Qt Toolkit may be licensed directly under this license.
diff --git a/LICENSE.LGPLv21 b/LICENSE.LGPLv21
index 6e184611..dfcab5e2 100644
--- a/LICENSE.LGPLv21
+++ b/LICENSE.LGPLv21
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 2.1, which is displayed below.
-------------------------------------------------------------------------
diff --git a/LICENSE.LGPLv3 b/LICENSE.LGPLv3
index 4d67bac0..6bf924cd 100644
--- a/LICENSE.LGPLv3
+++ b/LICENSE.LGPLv3
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 3, which is displayed below.
This license makes reference to the version 3 of the GNU General
Public License, which you can find in the LICENSE.GPLv3 file.
diff --git a/examples/location/location.pro b/examples/location/location.pro
index 851e37ac..0b4b2338 100644
--- a/examples/location/location.pro
+++ b/examples/location/location.pro
@@ -5,5 +5,6 @@ qtHaveModule(quick) {
places_list \
places_map \
mapviewer \
+ minimal_map \
planespotter
}
diff --git a/examples/location/mapviewer/mapviewer.qml b/examples/location/mapviewer/mapviewer.qml
index 929ea4ba..08ef2663 100644
--- a/examples/location/mapviewer/mapviewer.qml
+++ b/examples/location/mapviewer/mapviewer.qml
@@ -82,6 +82,7 @@ ApplicationWindow {
map = mapComponent.createObject(page);
map.plugin = plugin;
+
if (zoomLevel != null) {
map.zoomLevel = zoomLevel
map.center = center
diff --git a/examples/location/minimal_map/doc/images/minimal_map.png b/examples/location/minimal_map/doc/images/minimal_map.png
new file mode 100644
index 00000000..31ad0f8b
--- /dev/null
+++ b/examples/location/minimal_map/doc/images/minimal_map.png
Binary files differ
diff --git a/examples/location/minimal_map/doc/src/minimal_map.qdoc b/examples/location/minimal_map/doc/src/minimal_map.qdoc
new file mode 100644
index 00000000..06b310aa
--- /dev/null
+++ b/examples/location/minimal_map/doc/src/minimal_map.qdoc
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\example minimal_map
+\title Minimal Map (QML)
+\ingroup qtlocation-examples
+\brief The minimum code to display a map using Qt Quick.
+
+\image minimal_map.png
+
+\e {Minimal Map} demonstrates how to use the \l{Map} item to render a map.
+It shows the minimum amount of code needed to display the map, and can be used
+as a basis for further experimentation.
+
+\include examples-run.qdocinc
+
+\section1 C++ Code
+
+In \c main.cpp we use only the QGuiApplication and QQmlApplicationEngine
+classes.
+
+\quotefromfile minimal_map/main.cpp
+\skipto #include
+\printto main
+
+In the main function, we first instantiate a QGuiApplication object.
+Then we create a QQmlApplicationEngine and tell it to load \c main.qml
+from the \l{The Qt Resource System}{Qt Resource System}.
+
+Finally, QGuiApplication::exec() launches the main event loop.
+
+\printuntil }
+
+\section1 QML Code
+
+In \c main.qml, we import the \l {Qt Location QML Types}{QtLocation} QML module
+and its depending \l {Qt Positioning QML Types}{QtPositioning} QML module.
+Next, we create the top level window, set a sensible default size, and make
+it visible. The window will be filled by a \l [QML]{Map} item showing the map.
+
+\quotefromfile minimal_map/main.qml
+\skipto import
+\printuntil }
+\printline }
+\skipto Map
+\printuntil }
+\printline }
+
+The \l [QML]{Plugin} item is necessary to define the map provider we are
+going to use. The example can work with any of the available geo services
+plugins. However, some plugins may require additional plugin parameters
+in order to function correctly and we can use \l [QML]{PluginParameter}
+to specify them. In this example, we use the \c osm plugin, which is a
+\l {Qt Location Open Street Map Plugin} and does not require any parameters.
+
+In the \l [QML]{Map} item, we refer to the \c plugin we use and we set the \c
+center and the \c zoomLevel of the map.
+
+\section1 Requirements
+
+The example requires a working internet connection to download
+\c OpenStreetMap map tiles. An optional system proxy should be picked
+up automatically.
+*/
diff --git a/examples/location/minimal_map/main.cpp b/examples/location/minimal_map/main.cpp
new file mode 100644
index 00000000..e0b58e38
--- /dev/null
+++ b/examples/location/minimal_map/main.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
+
diff --git a/examples/location/minimal_map/main.qml b/examples/location/minimal_map/main.qml
new file mode 100644
index 00000000..26f24986
--- /dev/null
+++ b/examples/location/minimal_map/main.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Window 2.0
+import QtLocation 5.6
+import QtPositioning 5.6
+
+Window {
+ width: 512
+ height: 512
+ visible: true
+
+ Plugin {
+ id: osmPlugin
+ name: "osm"
+ // specify plugin parameters if necessary
+ // PluginParameter {
+ // name:
+ // value:
+ // }
+ }
+
+ Map {
+ anchors.fill: parent
+ plugin: osmPlugin
+ center: QtPositioning.coordinate(59.91, 10.75) // Oslo
+ zoomLevel: 10
+ }
+}
diff --git a/examples/location/minimal_map/minimal_map.pro b/examples/location/minimal_map/minimal_map.pro
new file mode 100644
index 00000000..5c165252
--- /dev/null
+++ b/examples/location/minimal_map/minimal_map.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+
+QT += location
+
+SOURCES += main.cpp
+
+RESOURCES += qml.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/location/minimal_map
+INSTALLS += target
diff --git a/examples/location/minimal_map/qml.qrc b/examples/location/minimal_map/qml.qrc
new file mode 100644
index 00000000..0ff3892d
--- /dev/null
+++ b/examples/location/minimal_map/qml.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
+
diff --git a/src/imports/location/location.pro b/src/imports/location/location.pro
index 3a574bd1..57172ad8 100644
--- a/src/imports/location/location.pro
+++ b/src/imports/location/location.pro
@@ -29,7 +29,8 @@ HEADERS += \
locationvaluetypehelper_p.h\
qquickgeomapgesturearea_p.h\
../positioning/qquickgeocoordinateanimation_p.h \
- mapitemviewdelegateincubator.h
+ mapitemviewdelegateincubator.h \
+ qdeclarativegeomapitemview_p_p.h
SOURCES += \
location.cpp \
diff --git a/src/imports/location/mapitemviewdelegateincubator.cpp b/src/imports/location/mapitemviewdelegateincubator.cpp
index 98f0d460..06dee7ba 100644
--- a/src/imports/location/mapitemviewdelegateincubator.cpp
+++ b/src/imports/location/mapitemviewdelegateincubator.cpp
@@ -37,17 +37,18 @@
#include "mapitemviewdelegateincubator.h"
#include "qdeclarativegeomapitemview_p.h"
+#include "qdeclarativegeomapitemview_p_p.h"
QT_BEGIN_NAMESPACE
-MapItemViewDelegateIncubator::MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view)
-: m_view(view)
+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_view->incubatorStatusChanged(this, status, m_batched);
}
QT_END_NAMESPACE
diff --git a/src/imports/location/mapitemviewdelegateincubator.h b/src/imports/location/mapitemviewdelegateincubator.h
index aa82a6bf..94c73252 100644
--- a/src/imports/location/mapitemviewdelegateincubator.h
+++ b/src/imports/location/mapitemviewdelegateincubator.h
@@ -38,6 +38,7 @@
#define MAPITEMVIEWDELEGATEINCUBATOR_H
#include <QtQml/QQmlIncubator>
+#include "qdeclarativegeomapitemview_p_p.h"
QT_BEGIN_NAMESPACE
@@ -46,13 +47,17 @@ class QDeclarativeGeoMapItemView;
class MapItemViewDelegateIncubator : public QQmlIncubator
{
public:
- MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view);
+ 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
diff --git a/src/imports/location/qdeclarativecirclemapitem.cpp b/src/imports/location/qdeclarativecirclemapitem.cpp
index b44183bb..f6b3c14f 100644
--- a/src/imports/location/qdeclarativecirclemapitem.cpp
+++ b/src/imports/location/qdeclarativecirclemapitem.cpp
@@ -471,7 +471,7 @@ QSGNode *QDeclarativeCircleMapItem::updateMapItemPaintNode(QSGNode *oldNode, Upd
*/
void QDeclarativeCircleMapItem::updatePolish()
{
- if (!map() || !center().isValid())
+ if (!map() || !center().isValid() || qIsNaN(radius_) || radius_ <= 0.0)
return;
QScopedValueRollback<bool> rollback(updatingGeometry_);
diff --git a/src/imports/location/qdeclarativegeomap.cpp b/src/imports/location/qdeclarativegeomap.cpp
index 7e000c06..75f81e1c 100644
--- a/src/imports/location/qdeclarativegeomap.cpp
+++ b/src/imports/location/qdeclarativegeomap.cpp
@@ -133,31 +133,17 @@ QT_BEGIN_NAMESPACE
\section2 Example Usage
The following snippet shows a simple Map and the necessary Plugin type
- to use it. The map is centered near Brisbane, Australia, zoomed out to the
- minimum zoom level, with gesture interaction enabled.
+ to use it. The map is centered over Oslo, Norway, with zoom level 10.
- \code
- Plugin {
- id: somePlugin
- // code here to choose the plugin as necessary
- }
-
- Map {
- id: map
-
- plugin: somePlugin
-
- center {
- latitude: -27
- longitude: 153
- }
- zoomLevel: map.minimumZoomLevel
-
- gesture.enabled: true
- }
- \endcode
+ \quotefromfile minimal_map/main.qml
+ \skipto import
+ \printuntil }
+ \printline }
+ \skipto Map
+ \printuntil }
+ \printline }
- \image api-map.png
+ \image minimal_map.png
*/
/*!
@@ -167,6 +153,8 @@ QT_BEGIN_NAMESPACE
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),
@@ -181,7 +169,8 @@ QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent)
m_pendingFitViewport(false),
m_copyrightsVisible(true),
m_maximumViewportLatitude(0.0),
- m_initialized(false)
+ m_initialized(false),
+ m_validRegion(false)
{
setAcceptHoverEvents(false);
setAcceptedMouseButtons(Qt::LeftButton);
@@ -545,7 +534,6 @@ void QDeclarativeGeoMap::mappingManagerInitialized()
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
@@ -701,6 +689,8 @@ void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel)
m_cameraData.setZoomLevel(zoomLevel);
}
+ m_validRegion = false;
+
if (centerHasChanged)
emit centerChanged(m_cameraData.center());
emit zoomLevelChanged(m_cameraData.zoomLevel());
@@ -736,6 +726,7 @@ void QDeclarativeGeoMap::setCenter(const QGeoCoordinate &center)
m_cameraData.setCenter(center);
}
+ m_validRegion = false;
emit centerChanged(m_cameraData.center());
}
@@ -765,7 +756,7 @@ QGeoCoordinate QDeclarativeGeoMap::center() const
*/
void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape)
{
- if (shape == m_region)
+ if (shape == m_region && m_validRegion)
return;
m_region = shape;
@@ -847,32 +838,63 @@ QColor QDeclarativeGeoMap::color() const
void QDeclarativeGeoMap::fitViewportToGeoShape()
{
- if (!m_map) return;
+ int margins = 10;
+ if (!m_map || width() <= margins || height() <= margins)
+ return;
- double bboxWidth;
- double bboxHeight;
- QGeoCoordinate centerCoordinate;
+ QGeoCoordinate topLeft;
+ QGeoCoordinate bottomRight;
switch (m_region.type()) {
case QGeoShape::RectangleType:
{
QGeoRectangle rect = m_region;
- QDoubleVector2D topLeftPoint = m_map->coordinateToItemPosition(rect.topLeft(), false);
- QDoubleVector2D botRightPoint = m_map->coordinateToItemPosition(rect.bottomRight(), false);
- bboxWidth = qAbs(topLeftPoint.x() - botRightPoint.x());
- bboxHeight = qAbs(topLeftPoint.y() - botRightPoint.y());
- centerCoordinate = rect.center();
+ topLeft = rect.topLeft();
+ bottomRight = rect.bottomRight();
break;
}
case QGeoShape::CircleType:
{
+ const double pi = M_PI;
QGeoCircle circle = m_region;
- centerCoordinate = circle.center();
- QGeoCoordinate edge = centerCoordinate.atDistanceAndAzimuth(circle.radius(), 90);
- QDoubleVector2D centerPoint = m_map->coordinateToItemPosition(centerCoordinate, false);
- QDoubleVector2D edgePoint = m_map->coordinateToItemPosition(edge, false);
- bboxWidth = qAbs(centerPoint.x() - edgePoint.x()) * 2;
- bboxHeight = bboxWidth;
+ QGeoCoordinate centerCoordinate = circle.center();
+
+ // calculate geo bounding box of the circle
+ // circle tangential points with meridians and the north pole create
+ // spherical triangle, we use spherical law of sines
+ // sin(lon_delta_in_rad)/sin(r_in_rad) =
+ // sin(alpha_in_rad)/sin(pi/2 - lat_in_rad), where:
+ // * lon_delta_in_rad - delta of longitudes of circle center
+ // and tangential points
+ // * r_in_rad - angular radius of the circle
+ // * lat_in_rad - latitude of circle center
+ // * alpha_in_rad - angle between meridian and radius to the circle =>
+ // this is tangential point => sin(alpha) = 1
+ // * lat_delta_in_rad - delta of latitudes of circle center and
+ // latitude of points where great circle (going through circle
+ // center) crosses circle and the pole
+
+ double r_in_rad = circle.radius() / EARTH_MEAN_RADIUS; // angular r
+ double lat_delta_in_deg = r_in_rad * 180 / pi;
+ double lon_delta_in_deg = std::asin(std::sin(r_in_rad) /
+ std::cos(centerCoordinate.latitude() * pi / 180)) * 180 / pi;
+
+ topLeft.setLatitude(centerCoordinate.latitude() + lat_delta_in_deg);
+ topLeft.setLongitude(centerCoordinate.longitude() - lon_delta_in_deg);
+ bottomRight.setLatitude(centerCoordinate.latitude()
+ - lat_delta_in_deg);
+ bottomRight.setLongitude(centerCoordinate.longitude()
+ + lon_delta_in_deg);
+
+ // adjust if circle reaches poles => cross all meridians and
+ // fit into Mercator projection bounds
+ if (topLeft.latitude() > 90 || bottomRight.latitude() < -90) {
+ topLeft.setLatitude(qMin(topLeft.latitude(), 85.05113));
+ topLeft.setLongitude(-180.0);
+ bottomRight.setLatitude(qMax(bottomRight.latitude(),
+ -85.05113));
+ bottomRight.setLongitude(180.0);
+ }
break;
}
case QGeoShape::UnknownType:
@@ -881,29 +903,40 @@ void QDeclarativeGeoMap::fitViewportToGeoShape()
return;
}
- // position camera to the center of bounding box
- setProperty("center", QVariant::fromValue(centerCoordinate));
+ // adjust zoom, use reference world to keep things simple
+ // otherwise we would need to do the error prone longitudes
+ // wrapping
+ QDoubleVector2D topLeftPoint =
+ m_map->referenceCoordinateToItemPosition(topLeft);
+ QDoubleVector2D bottomRightPoint =
+ m_map->referenceCoordinateToItemPosition(bottomRight);
- //If the shape is empty we just change centerposition, not zoom
- if (bboxHeight == 0 && bboxWidth == 0)
- return;
+ double bboxWidth = bottomRightPoint.x() - topLeftPoint.x();
+ double bboxHeight = bottomRightPoint.y() - topLeftPoint.y();
- // adjust zoom
- double bboxWidthRatio = bboxWidth / (bboxWidth + bboxHeight);
- double mapWidthRatio = width() / (width() + height());
- double zoomRatio;
+ // find center of the bounding box
+ QGeoCoordinate centerCoordinate =
+ m_map->referenceItemPositionToCoordinate(
+ (topLeftPoint + bottomRightPoint)/2);
- if (bboxWidthRatio > mapWidthRatio)
- zoomRatio = bboxWidth / width();
- else
- zoomRatio = bboxHeight / height();
+ // position camera to the center of bounding box
+ setCenter(centerCoordinate);
- qreal newZoom = std::log10(zoomRatio) / std::log10(0.5);
+ // if the shape is empty we just change center position, not zoom
+ if (bboxHeight == 0 && bboxWidth == 0)
+ return;
- newZoom = std::floor(qMax(minimumZoomLevel(), (zoomLevel() + newZoom)));
- setProperty("zoomLevel", QVariant::fromValue(newZoom));
+ double zoomRatio = qMax(bboxWidth / (width() - margins),
+ bboxHeight / (height() - margins));
+ // fixme: use log2 with c++11
+ zoomRatio = std::log(zoomRatio) / std::log(2.0);
+ double newZoom = qMax(minimumZoomLevel(), zoomLevel()
+ - zoomRatio);
+ setZoomLevel(newZoom);
+ m_validRegion = true;
}
+
/*!
\qmlproperty list<MapType> QtLocation::Map::supportedMapTypes
diff --git a/src/imports/location/qdeclarativegeomap_p.h b/src/imports/location/qdeclarativegeomap_p.h
index 807ed59c..31723490 100644
--- a/src/imports/location/qdeclarativegeomap_p.h
+++ b/src/imports/location/qdeclarativegeomap_p.h
@@ -203,6 +203,7 @@ private:
bool m_copyrightsVisible;
double m_maximumViewportLatitude;
bool m_initialized;
+ bool m_validRegion;
friend class QDeclarativeGeoMapItem;
friend class QDeclarativeGeoMapItemView;
diff --git a/src/imports/location/qdeclarativegeomapitemview.cpp b/src/imports/location/qdeclarativegeomapitemview.cpp
index 3e17e13a..0a9128f3 100644
--- a/src/imports/location/qdeclarativegeomapitemview.cpp
+++ b/src/imports/location/qdeclarativegeomapitemview.cpp
@@ -75,7 +75,8 @@ QT_BEGIN_NAMESPACE
QDeclarativeGeoMapItemView::QDeclarativeGeoMapItemView(QQuickItem *parent)
: QObject(parent), componentCompleted_(false), delegate_(0),
- itemModel_(0), map_(0), fitViewport_(false), m_metaObjectType(0)
+ itemModel_(0), map_(0), fitViewport_(false), m_metaObjectType(0),
+ m_readyIncubators(0), m_repopulating(false)
{
}
@@ -95,45 +96,73 @@ void QDeclarativeGeoMapItemView::componentComplete()
}
void QDeclarativeGeoMapItemView::incubatorStatusChanged(MapItemViewDelegateIncubator *incubator,
- QQmlIncubator::Status status)
+ QQmlIncubator::Status status,
+ bool batched)
{
if (status == QQmlIncubator::Loading)
return;
- for (int i = 0; i < m_itemData.length(); ++i) {
- ItemData *itemData = m_itemData.at(i);
- if (itemData->incubator != incubator)
- continue;
+ QDeclarativeGeoMapItemViewItemData *itemData = incubator->m_itemData;
+ if (!itemData) {
+ // Should never get here
+ qWarning() << "MapItemViewDelegateIncubator incubating invalid itemData";
+ return;
+ }
- switch (status) {
- case QQmlIncubator::Ready:
- itemData->item = qobject_cast<QDeclarativeGeoMapItemBase *>(incubator->object());
+ 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 {
- map_->addMapItem(itemData->item);
- if (fitViewport_)
+ 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:
- ;
}
-
+ 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:
+ ;
}
}
@@ -165,7 +194,7 @@ void QDeclarativeGeoMapItemView::setModel(const QVariant &model)
disconnect(itemModel_, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>)));
- removeInstantiatedItems();
+ removeInstantiatedItems(); // this also terminates ongong repopulations.
m_metaObjectType->release();
m_metaObjectType = 0;
@@ -214,11 +243,13 @@ void QDeclarativeGeoMapItemView::itemModelRowsInserted(const QModelIndex &index,
for (int i = start; i <= end; ++i) {
const QModelIndex insertedIndex = itemModel_->index(i, 0, index);
- createItemForIndex(insertedIndex);
+ // 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);
}
- if (fitViewport_)
- fitViewport();
+ fitViewport();
}
/*!
@@ -232,16 +263,25 @@ void QDeclarativeGeoMapItemView::itemModelRowsRemoved(const QModelIndex &index,
return;
for (int i = end; i >= start; --i) {
- ItemData *itemData = m_itemData.takeAt(i);
- if (!itemData)
- break;
-
- map_->removeMapItem(itemData->item);
- delete itemData;
+ 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);
+ }
}
- if (fitViewport_)
- fitViewport();
+ fitViewport();
}
void QDeclarativeGeoMapItemView::itemModelRowsMoved(const QModelIndex &parent, int start, int end,
@@ -262,12 +302,16 @@ void QDeclarativeGeoMapItemView::itemModelDataChanged(const QModelIndex &topLeft
{
Q_UNUSED(roles)
- if (!m_itemData.count())
+ 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);
- ItemData *itemData = m_itemData.at(i);
+ 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()) {
@@ -279,7 +323,6 @@ void QDeclarativeGeoMapItemView::itemModelDataChanged(const QModelIndex &topLeft
itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()),
modelData);
-
itemData->modelDataMeta->setValue(iterator.value(), modelData);
}
}
@@ -334,7 +377,7 @@ void QDeclarativeGeoMapItemView::setAutoFitViewport(const bool &fitViewport)
*/
void QDeclarativeGeoMapItemView::fitViewport()
{
- if (!map_ || !fitViewport_)
+ if (!map_ || !fitViewport_ || m_repopulating)
return;
if (map_->mapItems().size() > 0)
@@ -359,10 +402,9 @@ void QDeclarativeGeoMapItemView::removeInstantiatedItems()
if (!map_)
return;
- foreach (ItemData *itemData, m_itemData) {
- map_->removeMapItem(itemData->item);
- delete itemData;
- }
+ terminateOngoingRepopulation();
+ foreach (QDeclarativeGeoMapItemViewItemData *itemData, m_itemData)
+ removeItemData(itemData);
m_itemData.clear();
}
@@ -375,14 +417,53 @@ 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);
+ 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.
+}
- if (fitViewport_)
- fitViewport();
+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;
+ }
}
/*!
@@ -391,20 +472,27 @@ void QDeclarativeGeoMapItemView::instantiateAllItems()
*/
void QDeclarativeGeoMapItemView::repopulate()
{
- removeInstantiatedItems();
- instantiateAllItems();
+ 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)
+void QDeclarativeGeoMapItemView::createItemForIndex(const QModelIndex &index, bool batched)
{
// Expected to be already tested by caller.
Q_ASSERT(delegate_);
Q_ASSERT(itemModel_);
- ItemData *itemData = new ItemData;
+ QDeclarativeGeoMapItemViewItemData *itemData = new QDeclarativeGeoMapItemViewItemData;
itemData->modelData = new QObject;
itemData->modelDataMeta = new QQmlOpenMetaObject(itemData->modelData, m_metaObjectType, false);
@@ -427,13 +515,19 @@ void QDeclarativeGeoMapItemView::createItemForIndex(const QModelIndex &index)
itemData->context->setContextProperty(QLatin1String("model"), itemData->modelData);
itemData->context->setContextProperty(QLatin1String("index"), index.row());
- itemData->incubator = new MapItemViewDelegateIncubator(this);
- delegate_->create(*itemData->incubator, itemData->context);
+ 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);
- m_itemData.insert(index.row(), itemData);
+ delegate_->create(*itemData->incubator, itemData->context);
}
-QDeclarativeGeoMapItemView::ItemData::~ItemData()
+QDeclarativeGeoMapItemViewItemData::~QDeclarativeGeoMapItemViewItemData()
{
delete incubator;
delete item;
diff --git a/src/imports/location/qdeclarativegeomapitemview_p.h b/src/imports/location/qdeclarativegeomapitemview_p.h
index 004e3fb9..6a4a2921 100644
--- a/src/imports/location/qdeclarativegeomapitemview_p.h
+++ b/src/imports/location/qdeclarativegeomapitemview_p.h
@@ -54,6 +54,7 @@
#include <QtQml/QQmlParserStatus>
#include <QtQml/QQmlIncubator>
#include <QtQml/qqml.h>
+#include "qdeclarativegeomapitemview_p_p.h"
QT_BEGIN_NAMESPACE
@@ -108,7 +109,8 @@ Q_SIGNALS:
protected:
void incubatorStatusChanged(MapItemViewDelegateIncubator *incubator,
- QQmlIncubator::Status status);
+ QQmlIncubator::Status status,
+ bool batched);
private Q_SLOTS:
void itemModelReset();
@@ -120,39 +122,27 @@ private Q_SLOTS:
const QVector<int> &roles);
private:
- struct ItemData {
- ItemData()
- : incubator(0), item(0), context(0), modelData(0), modelDataMeta(0)
- {
- }
-
- ~ItemData();
-
- MapItemViewDelegateIncubator *incubator;
- QDeclarativeGeoMapItemBase *item;
- QQmlContext *context;
- QObject *modelData;
- QQmlOpenMetaObject *modelDataMeta;
- };
-
- void createItemForIndex(const QModelIndex &index);
+ 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<ItemData *> m_itemData;
+ QVector<QDeclarativeGeoMapItemViewItemData *> m_itemData;
+ QVector<QDeclarativeGeoMapItemViewItemData *> m_itemDataBatched;
bool fitViewport_;
QQmlOpenMetaObjectType *m_metaObjectType;
+ int m_readyIncubators;
+ bool m_repopulating;
- friend class QTypeInfo<ItemData>;
+ friend class QDeclarativeGeoMapItemViewItemData;
friend class MapItemViewDelegateIncubator;
};
-Q_DECLARE_TYPEINFO(QDeclarativeGeoMapItemView::ItemData, Q_MOVABLE_TYPE);
-
QT_END_NAMESPACE
QML_DECLARE_TYPE(QDeclarativeGeoMapItemView)
diff --git a/src/imports/location/qdeclarativegeomapitemview_p_p.h b/src/imports/location/qdeclarativegeomapitemview_p_p.h
new file mode 100644
index 00000000..5a4e3b25
--- /dev/null
+++ b/src/imports/location/qdeclarativegeomapitemview_p_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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;
+
+struct QDeclarativeGeoMapItemViewItemData {
+ 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/doc/images/api-map.png b/src/location/doc/images/api-map.png
deleted file mode 100644
index 6e7255d4..00000000
--- a/src/location/doc/images/api-map.png
+++ /dev/null
Binary files differ
diff --git a/src/location/doc/src/plugins/osm.qdoc b/src/location/doc/src/plugins/osm.qdoc
index 1c924fd3..2fd9e7c4 100644
--- a/src/location/doc/src/plugins/osm.qdoc
+++ b/src/location/doc/src/plugins/osm.qdoc
@@ -60,15 +60,30 @@ a prefix.
\li User agent string set when making network requests. This parameter should be set to a
value that uniquely identifies the application.
\row
- \li osm.mapping.host
+ \li osm.mapping.custom.host
\li Url string set when making network requests to the tile server. This parameter should be set to a
valid server url with the correct osm api and the \l{Map::activeMapType} to the corresponding \l{MapType}.CustomMap.
The CustomMap will only be available if this parameter is set.
- \note Setting the mapping.host parameter to a new server renders the map tile cache useless for the old custommap style.
+ \note Setting the mapping.custom.host parameter to a new server renders the map tile cache useless for the old custommap style.
\row
- \li osm.mapping.copyright
- \li Custom copryright string is used when setting the \l{Map::activeMapType} to \l{MapType}.CustomMap via urlprefix parameter.
- This copyright will only be used when using the CustomMap from above. If empty no copyright will be displayed for the custom map.
+ \li osm.mapping.custom.mapcopyright
+ \li Custom map copryright string is used when setting the \l{Map::activeMapType} to \l{MapType}.CustomMap via urlprefix parameter.
+ This copyright will only be used when using the CustomMap from above. If empty no map copyright will be displayed for the custom map.
+\row
+ \li osm.mapping.custom.datacopyright
+ \li Custom data copryright string is used when setting the \l{Map::activeMapType} to \l{MapType}.CustomMap via urlprefix parameter.
+ This copyright will only be used when using the CustomMap from above. If empty no data copyright will be displayed for the custom map.
+\row
+ \li osm.mapping.providersrepository.address
+ \li The OpenStreetMap plugin retrieves the provider's information from a remote repository. This is done to prevent using hardcoded
+ servers by default, which may become unavailable. By default this information is fetched from \l {http://maps-redirect.qt.io} {maps-redirect.qt.io}.
+ Setting this parameter changes the provider repository address to a user-specified one, which must contain the files
+ \tt{street}, \tt{satellite}, \tt{cycle}, \tt{transit}, \tt{night-transit}, \tt{terrain} and \tt{hiking}.
+\row
+ \li osm.mapping.providersrepository.disabled
+ \li By default, the OpenStreetMap plugin retrieves the provider's information from a remote repository to avoid a loss of service due to unavailability of hardcoded services.
+ The plugin, however, still contains fallback hardcoded provider data, in case the provider repository becomes unreachable.
+ Setting this parameter to \b true makes the plugin use the hardcoded urls only and therefore prevents the plugin from fetching provider data from the remote repository.
\row
\li osm.routing.host
\li Url string set when making network requests to the routing server. This parameter should be set to a
diff --git a/src/location/maps/qgeomap_p.h b/src/location/maps/qgeomap_p.h
index 8f7642d4..021c440b 100644
--- a/src/location/maps/qgeomap_p.h
+++ b/src/location/maps/qgeomap_p.h
@@ -84,8 +84,13 @@ public:
virtual QGeoCoordinate itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport = true) const = 0;
virtual QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const = 0;
+
virtual double minimumZoomForMapSize(int width, int height) const = 0;
virtual double maximumLatitudeForZoom(double zoomLevel) const = 0;
+
+ virtual QDoubleVector2D referenceCoordinateToItemPosition(const QGeoCoordinate &coordinate) const = 0;
+ virtual QGeoCoordinate referenceItemPositionToCoordinate(const QDoubleVector2D &pos) const = 0;
+
virtual void prefetchData();
virtual void clearData();
diff --git a/src/location/maps/qgeotiledmap.cpp b/src/location/maps/qgeotiledmap.cpp
index 99af8ab5..a6cbb294 100644
--- a/src/location/maps/qgeotiledmap.cpp
+++ b/src/location/maps/qgeotiledmap.cpp
@@ -194,6 +194,20 @@ double QGeoTiledMap::maximumLatitudeForZoom(double zoomLevel) const
return topMost.latitude();
}
+QDoubleVector2D QGeoTiledMap::referenceCoordinateToItemPosition(const QGeoCoordinate &coordinate) const
+{
+ Q_D(const QGeoTiledMap);
+ QDoubleVector2D point = QGeoProjection::coordToMercator(coordinate);
+ return point * std::pow(2.0, d->m_cameraData.zoomLevel()) * d->m_visibleTiles->tileSize();
+}
+
+QGeoCoordinate QGeoTiledMap::referenceItemPositionToCoordinate(const QDoubleVector2D &pos) const
+{
+ Q_D(const QGeoTiledMap);
+ QDoubleVector2D point = pos / (std::pow(2.0, d->m_cameraData.zoomLevel()) * d->m_visibleTiles->tileSize());
+ return QGeoProjection::mercatorToCoord(point);
+}
+
QGeoTiledMapPrivate::QGeoTiledMapPrivate(QGeoTiledMappingManagerEngine *engine)
: QGeoMapPrivate(engine),
m_cache(engine->tileCache()),
diff --git a/src/location/maps/qgeotiledmap_p.h b/src/location/maps/qgeotiledmap_p.h
index 6c735e86..813e342d 100644
--- a/src/location/maps/qgeotiledmap_p.h
+++ b/src/location/maps/qgeotiledmap_p.h
@@ -86,8 +86,13 @@ public:
QGeoCoordinate itemPositionToCoordinate(const QDoubleVector2D &pos, bool clipToViewport = true) const Q_DECL_OVERRIDE;
QDoubleVector2D coordinateToItemPosition(const QGeoCoordinate &coordinate, bool clipToViewport = true) const Q_DECL_OVERRIDE;
+
double minimumZoomForMapSize(int width, int height) const Q_DECL_OVERRIDE;
double maximumLatitudeForZoom(double zoomLevel) const Q_DECL_OVERRIDE;
+
+ QDoubleVector2D referenceCoordinateToItemPosition(const QGeoCoordinate &coordinate) const Q_DECL_OVERRIDE;
+ QGeoCoordinate referenceItemPositionToCoordinate(const QDoubleVector2D &pos) const Q_DECL_OVERRIDE;
+
void prefetchData() Q_DECL_OVERRIDE;
void clearData() Q_DECL_OVERRIDE;
diff --git a/src/location/maps/qgeotiledmappingmanagerengine.cpp b/src/location/maps/qgeotiledmappingmanagerengine.cpp
index 4e777ab2..dc5f1889 100644
--- a/src/location/maps/qgeotiledmappingmanagerengine.cpp
+++ b/src/location/maps/qgeotiledmappingmanagerengine.cpp
@@ -65,11 +65,16 @@ QGeoTiledMappingManagerEngine::~QGeoTiledMappingManagerEngine()
delete d_ptr;
}
-
+/*!
+ Sets the tile fetcher. Takes ownership of the QObject.
+*/
void QGeoTiledMappingManagerEngine::setTileFetcher(QGeoTileFetcher *fetcher)
{
Q_D(QGeoTiledMappingManagerEngine);
+ if (d->fetcher_)
+ d->fetcher_->deleteLater();
+ fetcher->setParent(this);
d->fetcher_ = fetcher;
qRegisterMetaType<QGeoTileSpec>();
@@ -275,10 +280,14 @@ void QGeoTiledMappingManagerEngine::setCacheHint(QGeoTiledMappingManagerEngine::
d->cacheHint_ = cacheHint;
}
+/*!
+ Sets the tile cache. Takes ownership of the QObject.
+*/
void QGeoTiledMappingManagerEngine::setTileCache(QAbstractGeoTileCache *cache)
{
Q_D(QGeoTiledMappingManagerEngine);
Q_ASSERT_X(!d->tileCache_, Q_FUNC_INFO, "This should be called only once");
+ cache->setParent(this);
d->tileCache_ = cache;
}
@@ -312,7 +321,6 @@ QGeoTiledMappingManagerEnginePrivate::QGeoTiledMappingManagerEnginePrivate()
QGeoTiledMappingManagerEnginePrivate::~QGeoTiledMappingManagerEnginePrivate()
{
- delete tileCache_;
}
#include "moc_qgeotiledmappingmanagerengine_p.cpp"
diff --git a/src/location/maps/qgeotilefetcher.cpp b/src/location/maps/qgeotilefetcher.cpp
index 40a1a721..0e0e81ca 100644
--- a/src/location/maps/qgeotilefetcher.cpp
+++ b/src/location/maps/qgeotilefetcher.cpp
@@ -73,7 +73,7 @@ void QGeoTileFetcher::updateTileRequests(const QSet<QGeoTileSpec> &tilesAdded,
d->queue_ += tilesAdded.toList();
- if (d->enabled_ && !d->queue_.isEmpty() && !d->timer_.isActive())
+ if (d->enabled_ && initialized() && !d->queue_.isEmpty() && !d->timer_.isActive())
d->timer_.start(0, this);
}
@@ -158,7 +158,7 @@ void QGeoTileFetcher::timerEvent(QTimerEvent *event)
return;
}
- if (d->queue_.isEmpty()) {
+ if (d->queue_.isEmpty() || !initialized()) {
d->timer_.stop();
return;
}
@@ -166,6 +166,11 @@ void QGeoTileFetcher::timerEvent(QTimerEvent *event)
requestNextTile();
}
+bool QGeoTileFetcher::initialized() const
+{
+ return true;
+}
+
void QGeoTileFetcher::handleReply(QGeoTiledMapReply *reply, const QGeoTileSpec &spec)
{
Q_D(QGeoTileFetcher);
diff --git a/src/location/maps/qgeotilefetcher_p.h b/src/location/maps/qgeotilefetcher_p.h
index cabab050..cbd8b995 100644
--- a/src/location/maps/qgeotilefetcher_p.h
+++ b/src/location/maps/qgeotilefetcher_p.h
@@ -85,6 +85,7 @@ Q_SIGNALS:
protected:
void timerEvent(QTimerEvent *event);
QGeoTiledMappingManagerEngine::CacheAreas cacheHint() const;
+ virtual bool initialized() const;
private:
QGeoTileFetcherPrivate *d_ptr;
diff --git a/src/plugins/geoservices/osm/osm.pro b/src/plugins/geoservices/osm/osm.pro
index e73c16d7..56f4cb33 100644
--- a/src/plugins/geoservices/osm/osm.pro
+++ b/src/plugins/geoservices/osm/osm.pro
@@ -14,7 +14,8 @@ HEADERS += \
qplacemanagerengineosm.h \
qplacesearchreplyosm.h \
qplacecategoriesreplyosm.h \
- qgeotiledmaposm.h
+ qgeotiledmaposm.h \
+ qgeotileproviderosm.h
SOURCES += \
qgeoserviceproviderpluginosm.cpp \
@@ -28,7 +29,8 @@ SOURCES += \
qplacemanagerengineosm.cpp \
qplacesearchreplyosm.cpp \
qplacecategoriesreplyosm.cpp \
- qgeotiledmaposm.cpp
+ qgeotiledmaposm.cpp \
+ qgeotileproviderosm.cpp
OTHER_FILES += \
diff --git a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
index a4a62e7f..052ed351 100644
--- a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp
@@ -41,12 +41,16 @@
#include <QtLocation/private/qgeotilespec_p.h>
-QGeoMapReplyOsm::QGeoMapReplyOsm(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent)
+QGeoMapReplyOsm::QGeoMapReplyOsm(QNetworkReply *reply,
+ const QGeoTileSpec &spec,
+ const QString &imageFormat,
+ QObject *parent)
: QGeoTiledMapReply(spec, parent), m_reply(reply)
{
connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ setMapImageFormat(imageFormat);
}
QGeoMapReplyOsm::~QGeoMapReplyOsm()
@@ -75,18 +79,15 @@ void QGeoMapReplyOsm::networkReplyFinished()
if (!m_reply)
return;
- if (m_reply->error() != QNetworkReply::NoError)
+ if (m_reply->error() != QNetworkReply::NoError) {
+ m_reply->deleteLater();
+ m_reply = 0;
return;
+ }
QByteArray a = m_reply->readAll();
setMapImageData(a);
- int mapId = tileSpec().mapId();
- if (mapId == 1 || mapId == 2)
- setMapImageFormat(QStringLiteral("jpg"));
- else
- setMapImageFormat(QStringLiteral("png"));
-
setFinished(true);
m_reply->deleteLater();
diff --git a/src/plugins/geoservices/osm/qgeomapreplyosm.h b/src/plugins/geoservices/osm/qgeomapreplyosm.h
index 994e568a..804a0a24 100644
--- a/src/plugins/geoservices/osm/qgeomapreplyosm.h
+++ b/src/plugins/geoservices/osm/qgeomapreplyosm.h
@@ -40,6 +40,9 @@
#ifndef QGEOMAPREPLYOSM_H
#define QGEOMAPREPLYOSM_H
+#include "qgeotilefetcherosm.h"
+#include "qgeotileproviderosm.h"
+
#include <QtNetwork/QNetworkReply>
#include <QtLocation/private/qgeotiledmapreply_p.h>
#include <QtCore/qpointer.h>
@@ -51,7 +54,7 @@ class QGeoMapReplyOsm : public QGeoTiledMapReply
Q_OBJECT
public:
- explicit QGeoMapReplyOsm(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent = 0);
+ QGeoMapReplyOsm(QNetworkReply *reply, const QGeoTileSpec &spec, const QString &imageFormat, QObject *parent = 0);
~QGeoMapReplyOsm();
void abort();
diff --git a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
index e0ec919e..f16e602a 100644
--- a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
+++ b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp
@@ -39,14 +39,22 @@
#include "qgeotiledmaposm.h"
#include "qgeotiledmappingmanagerengineosm.h"
+#include "qgeotilefetcherosm.h"
#include <QtLocation/private/qgeotilespec_p.h>
QT_BEGIN_NAMESPACE
QGeoTiledMapOsm::QGeoTiledMapOsm(QGeoTiledMappingManagerEngineOsm *engine, QObject *parent)
-: QGeoTiledMap(engine, parent), m_mapId(-1), m_customCopyright(engine->customCopyright())
+: QGeoTiledMap(engine, parent), m_mapId(-1), m_engine(engine)
{
+ // Needed because evaluateCopyrights() is only triggered if visible tiles change in the map.
+ // It fails the first time it gets called if providers aren't resolved, and subsequent calls
+ // to it will be skipped until visible tiles change.
+ // This connection makes sure the copyrights are evaluated when copyright data are ready regardless
+ // of what tiles are visible.
+ connect(qobject_cast<QGeoTileFetcherOsm *>(engine->tileFetcher()), &QGeoTileFetcherOsm::providerDataUpdated,
+ this, &QGeoTiledMapOsm::onProviderDataUpdated);
}
QGeoTiledMapOsm::~QGeoTiledMapOsm()
@@ -62,32 +70,43 @@ void QGeoTiledMapOsm::evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles)
if (tile.mapId() == m_mapId)
return;
+ int providerId = tile.mapId() - 1;
+ if (providerId < 0 || providerId >= m_engine->providers().size() || !m_engine->providers().at(providerId)->isValid())
+ return;
+
m_mapId = tile.mapId();
+ onProviderDataUpdated(m_engine->providers().at(providerId));
+}
- QString copyrights;
- switch (m_mapId) {
- case 1:
- case 2:
- // set attribution to Map Quest
- copyrights = tr("Tiles Courtesy of <a href='http://www.mapquest.com/'>MapQuest</a><br/>Data &copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors");
- break;
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- // set attribution to Thunder Forest
- copyrights = tr("Maps &copy; <a href='http://www.thunderforest.com/'>Thunderforest</a><br/>Data &copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors");
- break;
- case 8:
- copyrights = m_customCopyright;
- break;
- default:
- // set attribution to OSM
- copyrights = tr("&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors");
+void QGeoTiledMapOsm::onProviderDataUpdated(const QGeoTileProviderOsm *provider)
+{
+ if (!provider->isResolved() || provider->mapType().mapId() != m_mapId)
+ return;
+ QString copyRights;
+ const QString mapCopy = provider->mapCopyRight();
+ const QString dataCopy = provider->dataCopyRight();
+ const QString styleCopy = provider->styleCopyRight();
+ if (!mapCopy.isEmpty()) {
+ copyRights += QStringLiteral("Map &copy; ");
+ copyRights += mapCopy;
+ }
+ if (!dataCopy.isEmpty()) {
+ if (!copyRights.isEmpty())
+ copyRights += QStringLiteral("<br/>");
+ copyRights += QStringLiteral("Data &copy; ");
+ copyRights += dataCopy;
}
+ if (!styleCopy.isEmpty()) {
+ if (!copyRights.isEmpty())
+ copyRights += QStringLiteral("<br/>");
+ copyRights += QStringLiteral("Style &copy; ");
+ copyRights += styleCopy;
+ }
+
+ if (copyRights.isEmpty() && provider->mapType().style() == QGeoMapType::CustomMap)
+ copyRights = m_engine->customCopyright();
- emit copyrightsChanged(copyrights);
+ emit copyrightsChanged(copyRights);
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotiledmaposm.h b/src/plugins/geoservices/osm/qgeotiledmaposm.h
index 40d4e79b..cfc72948 100644
--- a/src/plugins/geoservices/osm/qgeotiledmaposm.h
+++ b/src/plugins/geoservices/osm/qgeotiledmaposm.h
@@ -40,6 +40,8 @@
#ifndef QGEOTILEDMAPOSM_H
#define QGEOTILEDMAPOSM_H
+#include "qgeotileproviderosm.h"
+
#include <QtLocation/private/qgeotiledmap_p.h>
QT_BEGIN_NAMESPACE
@@ -56,9 +58,12 @@ public:
protected:
void evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles) Q_DECL_OVERRIDE;
+protected Q_SLOTS:
+ void onProviderDataUpdated(const QGeoTileProviderOsm *provider);
+
private:
int m_mapId;
- const QString m_customCopyright;
+ QGeoTiledMappingManagerEngineOsm *m_engine;
};
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
index d5490559..920b0148 100644
--- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
+++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
@@ -40,10 +40,14 @@
#include "qgeotiledmappingmanagerengineosm.h"
#include "qgeotilefetcherosm.h"
#include "qgeotiledmaposm.h"
+#include "qgeotileproviderosm.h"
#include <QtLocation/private/qgeocameracapabilities_p.h>
#include <QtLocation/private/qgeomaptype_p.h>
#include <QtLocation/private/qgeotiledmap_p.h>
+#include <QtLocation/private/qgeofiletilecache_p.h>
+
+#include <QtNetwork/QNetworkAccessManager>
QT_BEGIN_NAMESPACE
@@ -57,33 +61,142 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian
setTileSize(QSize(256, 256));
+ QNetworkAccessManager *nm = new QNetworkAccessManager();
+ QString domain = QStringLiteral("http://maps-redirect.qt.io/osm/5.6/");
+ if (parameters.contains(QStringLiteral("osm.mapping.providersrepository.address"))) {
+ QString customAddress = parameters.value(QStringLiteral("osm.mapping.providersrepository.address")).toString();
+ // Allowing some malformed addresses ( containing the suffix "/osm/5.6/"
+ if (customAddress.indexOf(QStringLiteral(":")) < 0) // defaulting to http:// if no prefix is found
+ customAddress = QStringLiteral("http://") + customAddress;
+ if (customAddress[customAddress.length()-1] != QLatin1Char('/'))
+ customAddress += QLatin1Char('/');
+ domain = customAddress;
+ }
+
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "street",
+ nm,
+ QGeoMapType(QGeoMapType::StreetMap, tr("Street Map"), tr("Street map view in daylight mode"), false, false, 1),
+ QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile.openstreetmap.org/%z/%x/%y.png"),
+ QStringLiteral("png"),
+ QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap.org</a>"),
+ QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors")
+ )));
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "satellite",
+ nm,
+ QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite Map"), tr("Satellite map view in daylight mode"), false, false, 2),
+ QGeoTileProviderOsm::TileProvider(QStringLiteral("http://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/%z/%y/%x"),
+ QStringLiteral("jpg"),
+ QStringLiteral("<a href='http://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer'>USGS The National Map: Orthoimagery</a>"),
+ QStringLiteral("<a href='http://landsat.gsfc.nasa.gov/?page_id=2339'>USGS/NASA Landsat</a>")
+ )));
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "cycle",
+ nm,
+ QGeoMapType(QGeoMapType::CycleMap, tr("Cycle Map"), tr("Cycle map view in daylight mode"), false, false, 3),
+ QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile.opencyclemap.org/cycle/%z/%x/%y.png"),
+ QStringLiteral("png"),
+ QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"),
+ QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors")
+ )));
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "transit",
+ nm,
+ QGeoMapType(QGeoMapType::TransitMap, tr("Transit Map"), tr("Public transit map view in daylight mode"), false, false, 4),
+ QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile2.opencyclemap.org/transport/%z/%x/%y.png"),
+ QStringLiteral("png"),
+ QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"),
+ QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors")
+ )));
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "night-transit",
+ nm,
+ QGeoMapType(QGeoMapType::TransitMap, tr("Night Transit Map"), tr("Public transit map view in night mode"), false, true, 5),
+ QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/transport-dark/%z/%x/%y.png"),
+ QStringLiteral("png"),
+ QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"),
+ QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors")
+ )));
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "terrain",
+ nm,
+ QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain Map"), tr("Terrain map view"), false, false, 6),
+ QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/landscape/%z/%x/%y.png"),
+ QStringLiteral("png"),
+ QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"),
+ QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors")
+ )));
+ m_providers.push_back(
+ new QGeoTileProviderOsm(domain + "hiking",
+ nm,
+ QGeoMapType(QGeoMapType::PedestrianMap, tr("Hiking Map"), tr("Hiking map view"), false, false, 7),
+ QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/outdoors/%z/%x/%y.png"),
+ QStringLiteral("png"),
+ QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"),
+ QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors")
+ )));
+
+ if (parameters.contains(QStringLiteral("osm.mapping.custom.host"))
+ || parameters.contains(QStringLiteral("osm.mapping.host"))) {
+ // Adding a custom provider
+ QString tmsServer;
+ if (parameters.contains(QStringLiteral("osm.mapping.host")))
+ tmsServer = parameters.value(QStringLiteral("osm.mapping.host")).toString();
+ if (parameters.contains(QStringLiteral("osm.mapping.custom.host"))) // priority to the new one
+ tmsServer = parameters.value(QStringLiteral("osm.mapping.custom.host")).toString();
+
+ QString mapCopyright;
+ QString dataCopyright;
+ if (parameters.contains(QStringLiteral("osm.mapping.custom.mapcopyright")))
+ mapCopyright = parameters.value(QStringLiteral("osm.mapping.custom.mapcopyright")).toString();
+ if (parameters.contains(QStringLiteral("osm.mapping.custom.datacopyright")))
+ dataCopyright = parameters.value(QStringLiteral("osm.mapping.custom.datacopyright")).toString();
+
+ if (parameters.contains(QStringLiteral("osm.mapping.copyright")))
+ m_customCopyright = parameters.value(QStringLiteral("osm.mapping.copyright")).toString();
+
+ m_providers.push_back(
+ new QGeoTileProviderOsm("",
+ nm,
+ QGeoMapType(QGeoMapType::CustomMap, tr("Custom URL Map"), tr("Custom url map view set via urlprefix parameter"), false, false, 8),
+ QGeoTileProviderOsm::TileProvider(tmsServer + QStringLiteral("%z/%x/%y.png"),
+ QStringLiteral("png"),
+ mapCopyright,
+ dataCopyright
+ )));
+
+ m_providers.last()->disableRedirection();
+ }
+
+ bool disableRedirection = false;
+ if (parameters.contains(QStringLiteral("osm.mapping.providersrepository.disabled")))
+ disableRedirection = parameters.value(QStringLiteral("osm.mapping.providersrepository.disabled")).toBool();
+
QList<QGeoMapType> mapTypes;
+ foreach (QGeoTileProviderOsm * provider, m_providers) {
+ provider->setParent(this);
+ if (disableRedirection)
+ provider->disableRedirection();
+ mapTypes << provider->mapType();
+ }
// See map type implementations in QGeoTiledMapOsm and QGeoTileFetcherOsm.
- mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Street Map"), tr("Street map view in daylight mode"), false, false, 1);
- mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite Map"), tr("Satellite map view in daylight mode"), false, false, 2);
- mapTypes << QGeoMapType(QGeoMapType::CycleMap, tr("Cycle Map"), tr("Cycle map view in daylight mode"), false, false, 3);
- mapTypes << QGeoMapType(QGeoMapType::TransitMap, tr("Transit Map"), tr("Public transit map view in daylight mode"), false, false, 4);
- mapTypes << QGeoMapType(QGeoMapType::TransitMap, tr("Night Transit Map"), tr("Public transit map view in night mode"), false, true, 5);
- mapTypes << QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain Map"), tr("Terrain map view"), false, false, 6);
- mapTypes << QGeoMapType(QGeoMapType::PedestrianMap, tr("Hiking Map"), tr("Hiking map view"), false, false, 7);
- if (parameters.contains(QStringLiteral("osm.mapping.host")))
- mapTypes << QGeoMapType(QGeoMapType::CustomMap, tr("Custom URL Map"), tr("Custom url map view set via urlprefix parameter"), false, false, 8);
setSupportedMapTypes(mapTypes);
- QGeoTileFetcherOsm *tileFetcher = new QGeoTileFetcherOsm(this);
+ QGeoTileFetcherOsm *tileFetcher = new QGeoTileFetcherOsm(m_providers, nm, this);
if (parameters.contains(QStringLiteral("osm.useragent"))) {
const QByteArray ua = parameters.value(QStringLiteral("osm.useragent")).toString().toLatin1();
tileFetcher->setUserAgent(ua);
}
- if (parameters.contains(QStringLiteral("osm.mapping.host"))) {
- const QString up = parameters.value(QStringLiteral("osm.mapping.host")).toString().toLatin1();
- tileFetcher->setUrlPrefix(up);
- }
- if (parameters.contains(QStringLiteral("osm.mapping.copyright")))
- m_customCopyright = parameters.value(QStringLiteral("osm.mapping.copyright")).toString().toLatin1();
+
setTileFetcher(tileFetcher);
+ QAbstractGeoTileCache *tileCache = new QGeoFileTileCache(QAbstractGeoTileCache::baseCacheDirectory() + QStringLiteral("osm"));
+ // 50mb of disk cache by default to minimize n. of accesses to public OSM servers
+ tileCache->setMaxDiskUsage(50 * 1024 * 1024);
+ setTileCache(tileCache);
+
*error = QGeoServiceProvider::NoError;
errorString->clear();
}
@@ -97,6 +210,11 @@ QGeoMap *QGeoTiledMappingManagerEngineOsm::createMap()
return new QGeoTiledMapOsm(this);
}
+const QVector<QGeoTileProviderOsm *> &QGeoTiledMappingManagerEngineOsm::providers()
+{
+ return m_providers;
+}
+
QString QGeoTiledMappingManagerEngineOsm::customCopyright() const
{
return m_customCopyright;
diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h
index e0f7d873..2ceebc74 100644
--- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h
+++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h
@@ -40,25 +40,31 @@
#ifndef QGEOTILEDMAPPINGMANAGERENGINEOSM_H
#define QGEOTILEDMAPPINGMANAGERENGINEOSM_H
-#include <QtLocation/QGeoServiceProvider>
+#include "qgeotileproviderosm.h"
+#include <QtLocation/QGeoServiceProvider>
#include <QtLocation/private/qgeotiledmappingmanagerengine_p.h>
+#include <QVector>
+
QT_BEGIN_NAMESPACE
class QGeoTiledMappingManagerEngineOsm : public QGeoTiledMappingManagerEngine
{
Q_OBJECT
+ friend class QGeoTiledMapOsm;
public:
QGeoTiledMappingManagerEngineOsm(const QVariantMap &parameters,
QGeoServiceProvider::Error *error, QString *errorString);
~QGeoTiledMappingManagerEngineOsm();
QGeoMap *createMap();
+ const QVector<QGeoTileProviderOsm *> &providers();
QString customCopyright() const;
private:
+ QVector<QGeoTileProviderOsm *> m_providers;
QString m_customCopyright;
};
diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp
index 021c2882..730b5379 100644
--- a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp
+++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp
@@ -44,12 +44,36 @@
#include <QtNetwork/QNetworkRequest>
#include <QtLocation/private/qgeotilespec_p.h>
+
QT_BEGIN_NAMESPACE
-QGeoTileFetcherOsm::QGeoTileFetcherOsm(QObject *parent)
-: QGeoTileFetcher(parent), m_networkManager(new QNetworkAccessManager(this)),
- m_userAgent("Qt Location based application")
+static bool providersResolved(const QVector<QGeoTileProviderOsm *> &providers)
{
+ foreach (const QGeoTileProviderOsm *provider, providers)
+ if (!provider->isResolved())
+ return false;
+ return true;
+}
+
+QGeoTileFetcherOsm::QGeoTileFetcherOsm(const QVector<QGeoTileProviderOsm *> &providers,
+ QNetworkAccessManager *nm,
+ QObject *parent)
+: QGeoTileFetcher(parent), m_userAgent("Qt Location based application"),
+ m_providers(providers), m_nm(nm), m_ready(true)
+{
+ m_nm->setParent(this);
+ foreach (QGeoTileProviderOsm *provider, m_providers) {
+ if (!provider->isResolved()) {
+ m_ready = false;
+ connect(provider, &QGeoTileProviderOsm::resolutionFinished,
+ this, &QGeoTileFetcherOsm::onProviderResolutionFinished);
+ connect(provider, &QGeoTileProviderOsm::resolutionError,
+ this, &QGeoTileFetcherOsm::onProviderResolutionError);
+ provider->resolveProvider();
+ }
+ }
+ if (m_ready)
+ readyUpdated();
}
void QGeoTileFetcherOsm::setUserAgent(const QByteArray &userAgent)
@@ -57,57 +81,55 @@ void QGeoTileFetcherOsm::setUserAgent(const QByteArray &userAgent)
m_userAgent = userAgent;
}
-void QGeoTileFetcherOsm::setUrlPrefix(const QString &urlPrefix)
+bool QGeoTileFetcherOsm::initialized() const
{
- m_urlPrefix = urlPrefix;
+ if (!m_ready) {
+ foreach (QGeoTileProviderOsm *provider, m_providers)
+ if (!provider->isResolved())
+ provider->resolveProvider();
+ }
+ return m_ready;
}
-QGeoTiledMapReply *QGeoTileFetcherOsm::getTileImage(const QGeoTileSpec &spec)
+void QGeoTileFetcherOsm::onProviderResolutionFinished(const QGeoTileProviderOsm *provider)
{
- QNetworkRequest request;
- request.setRawHeader("User-Agent", m_userAgent);
+ if ((m_ready = providersResolved(m_providers))) {
+ qWarning("QGeoTileFetcherOsm: all providers resolved");
+ readyUpdated();
+ }
+ emit providerDataUpdated(provider);
+}
- QString urlPrefix;
- QString suffix = QStringLiteral(".png");
+void QGeoTileFetcherOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error)
+{
+ Q_UNUSED(error)
+ if ((m_ready = providersResolved(m_providers))) {
+ qWarning("QGeoTileFetcherOsm: all providers resolved");
+ readyUpdated();
+ }
+ emit providerDataUpdated(provider);
+}
- switch (spec.mapId()) {
- case 1:
- urlPrefix = QStringLiteral("http://otile1.mqcdn.com/tiles/1.0.0/map/");
- suffix = QStringLiteral(".jpg");
- break;
- case 2:
- urlPrefix = QStringLiteral("http://otile1.mqcdn.com/tiles/1.0.0/sat/");
- suffix = QStringLiteral(".jpg");
- break;
- case 3:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/cycle/");
- break;
- case 4:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/transport/");
- break;
- case 5:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/transport-dark/");
- break;
- case 6:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/landscape/");
- break;
- case 7:
- urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/outdoors/");
- break;
- case 8:
- urlPrefix = m_urlPrefix;
- break;
- default:
+QGeoTiledMapReply *QGeoTileFetcherOsm::getTileImage(const QGeoTileSpec &spec)
+{
+ int id = spec.mapId();
+ if (id < 1 || id > m_providers.size()) {
qWarning("Unknown map id %d\n", spec.mapId());
+ id = 0;
}
+ id -= 1; // TODO: make OSM map ids start from 0.
- request.setUrl(QUrl(urlPrefix + QString::number(spec.zoom()) + QLatin1Char('/') +
- QString::number(spec.x()) + QLatin1Char('/') +
- QString::number(spec.y()) + suffix));
-
- QNetworkReply *reply = m_networkManager->get(request);
+ const QUrl url = m_providers[id]->tileAddress(spec.x(), spec.y(), spec.zoom());
+ QNetworkRequest request;
+ request.setHeader(QNetworkRequest::UserAgentHeader, m_userAgent);
+ request.setUrl(url);
+ QNetworkReply *reply = m_nm->get(request);
+ return new QGeoMapReplyOsm(reply, spec, m_providers[id]->format());
+}
- return new QGeoMapReplyOsm(reply, spec);
+void QGeoTileFetcherOsm::readyUpdated()
+{
+ updateTileRequests(QSet<QGeoTileSpec>(), QSet<QGeoTileSpec>());
}
QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.h b/src/plugins/geoservices/osm/qgeotilefetcherosm.h
index 184f20a6..8d69cc56 100644
--- a/src/plugins/geoservices/osm/qgeotilefetcherosm.h
+++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.h
@@ -40,31 +40,48 @@
#ifndef QGEOTILEFETCHEROSM_H
#define QGEOTILEFETCHEROSM_H
+#include "qgeotileproviderosm.h"
#include <QtLocation/private/qgeotilefetcher_p.h>
+#include <QVector>
QT_BEGIN_NAMESPACE
-class QGeoTiledMappingManagerEngine;
class QNetworkAccessManager;
class QGeoTileFetcherOsm : public QGeoTileFetcher
{
Q_OBJECT
+ friend class QGeoMapReplyOsm;
+ friend class QGeoTiledMappingManagerEngineOsm;
public:
- QGeoTileFetcherOsm(QObject *parent = 0);
+ QGeoTileFetcherOsm(const QVector<QGeoTileProviderOsm *> &providers,
+ QNetworkAccessManager *nm,
+ QObject *parent = 0);
void setUserAgent(const QByteArray &userAgent);
- void setUrlPrefix(const QString &urlPrefix);
+
+Q_SIGNALS:
+ void providerDataUpdated(const QGeoTileProviderOsm *provider);
+
+protected:
+ bool initialized() const Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+ void onProviderResolutionFinished(const QGeoTileProviderOsm *provider);
+ void onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error);
private:
QGeoTiledMapReply *getTileImage(const QGeoTileSpec &spec);
+ void readyUpdated();
- QNetworkAccessManager *m_networkManager;
QByteArray m_userAgent;
- QString m_urlPrefix;
+ QVector<QGeoTileProviderOsm *> m_providers;
+ QNetworkAccessManager *m_nm;
+ bool m_ready;
};
QT_END_NAMESPACE
#endif // QGEOTILEFETCHEROSM_H
+
diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp
new file mode 100644
index 00000000..3d46a425
--- /dev/null
+++ b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** 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 "qgeotileproviderosm.h"
+
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+static const int maxValidZoom = 30;
+
+QGeoTileProviderOsm::QGeoTileProviderOsm(const QString &urlRedir,
+ QNetworkAccessManager *nm,
+ const QGeoMapType &mapType,
+ const QGeoTileProviderOsm::TileProvider &providerFallback)
+ : m_nm(nm), m_urlRedirector(urlRedir),
+ m_providerFallback(providerFallback),
+ m_mapType(mapType), m_status(Idle)
+{
+ if (!m_urlRedirector.isValid())
+ disableRedirection();
+}
+
+QGeoTileProviderOsm::~QGeoTileProviderOsm()
+{
+
+}
+
+void QGeoTileProviderOsm::resolveProvider()
+{
+ switch (m_status) {
+ case Resolving:
+ case Invalid:
+ case Valid:
+ return;
+ case Idle:
+ m_status = Resolving;
+ break;
+ }
+
+ QNetworkRequest request;
+ request.setHeader(QNetworkRequest::UserAgentHeader, QByteArrayLiteral("QGeoTileFetcherOsm"));
+ request.setUrl(m_urlRedirector);
+ QNetworkReply *reply = m_nm->get(request);
+ connect(reply, SIGNAL(finished()), this, SLOT(onNetworkReplyFinished()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(onNetworkReplyError(QNetworkReply::NetworkError)));
+}
+
+void QGeoTileProviderOsm::disableRedirection()
+{
+ m_status = Invalid;
+ m_provider.m_valid = false;
+}
+
+void QGeoTileProviderOsm::handleError(QNetworkReply::NetworkError error)
+{
+ switch (error) {
+ case QNetworkReply::ConnectionRefusedError:
+ case QNetworkReply::TooManyRedirectsError:
+ case QNetworkReply::InsecureRedirectError:
+ case QNetworkReply::ContentAccessDenied:
+ case QNetworkReply::ContentOperationNotPermittedError:
+ case QNetworkReply::ContentNotFoundError:
+ case QNetworkReply::AuthenticationRequiredError:
+ case QNetworkReply::ContentGoneError:
+ case QNetworkReply::OperationNotImplementedError:
+ case QNetworkReply::ServiceUnavailableError:
+ // Errors we don't expect to recover from in the near future, which
+ // prevent accessing the redirection info but not the actual providers.
+ m_status = Invalid;
+ default:
+ break;
+ }
+}
+
+QUrl QGeoTileProviderOsm::tileAddress(int x, int y, int z) const
+{
+ if (m_provider.isValid())
+ return m_provider.tileAddress(x,y,z);
+ if (m_providerFallback.isValid())
+ return m_providerFallback.tileAddress(x,y,z);
+ return QUrl();
+}
+
+QString QGeoTileProviderOsm::mapCopyRight() const
+{
+ if (m_provider.isValid())
+ return m_provider.mapCopyRight();
+ if (m_providerFallback.isValid())
+ return m_providerFallback.mapCopyRight();
+ return QString();
+}
+
+QString QGeoTileProviderOsm::dataCopyRight() const
+{
+ if (m_provider.isValid())
+ return m_provider.dataCopyRight();
+ if (m_providerFallback.isValid())
+ return m_providerFallback.dataCopyRight();
+ return QString();
+}
+
+QString QGeoTileProviderOsm::styleCopyRight() const
+{
+ if (m_provider.isValid())
+ return m_provider.styleCopyRight();
+ if (m_providerFallback.isValid())
+ return m_providerFallback.styleCopyRight();
+ return QString();
+}
+
+QString QGeoTileProviderOsm::format() const
+{
+ if (m_provider.isValid())
+ return m_provider.format();
+ if (m_providerFallback.isValid())
+ return m_providerFallback.format();
+ return QString();
+}
+
+const QGeoMapType &QGeoTileProviderOsm::mapType() const
+{
+ return m_mapType;
+}
+
+bool QGeoTileProviderOsm::isValid() const
+{
+ return (m_provider.isValid() || m_providerFallback.isValid());
+}
+
+bool QGeoTileProviderOsm::isResolved() const
+{
+ return (m_status == Valid || m_status == Invalid);
+}
+
+void QGeoTileProviderOsm::onNetworkReplyFinished()
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+
+ switch (m_status) {
+ case Resolving:
+ m_status = Idle;
+ case Idle: // should not happen
+ case Invalid: // should not happen
+ break;
+ case Valid: // should not happen
+ return;
+ }
+
+ if (reply->error() != QNetworkReply::NoError) {
+ handleError(reply->error());
+ if (m_status == Invalid)
+ emit resolutionError(this, reply->error());
+ return;
+ }
+ m_status = Invalid;
+
+ /*
+ * The content of a provider information file must be in JSON format, containing
+ * (as of Qt 5.6.2) the following fields:
+ *
+ * {
+ * "Enabled" : bool, (optional)
+ * "UrlTemplate" : "<url template>", (mandatory)
+ * "ImageFormat" : "<image format>", (mandatory)
+ * "MapCopyRight" : "<copyright>", (mandatory)
+ * "DataCopyRight" : "<copyright>", (mandatory)
+ * "StyleCopyRight" : "<copyright>", (optional)
+ * "MinimumZoomLevel" : <minimumZoomLevel>, (optional)
+ * "MaximumZoomLevel" : <maximumZoomLevel>, (optional)
+ * }
+ *
+ * Enabled is optional, and allows to temporarily disable a tile provider if it becomes
+ * unavailable, without making the osm plugin fire requests to it. Default is true.
+ *
+ * MinimumZoomLevel and MaximumZoomLevel are also optional, and allow to prevent invalid tile
+ * requests to the providers, if they do not support the specific ZL. Default is 0 and 19,
+ * respectively.
+ *
+ * <server address template> is required, and is the tile url template, with %x, %y and %z as
+ * placeholders for the actual parameters.
+ * Example:
+ * http://localhost:8080/maps/%z/%x/%y.png
+ *
+ * <image format> is required, and is the format of the tile.
+ * Examples:
+ * "png", "jpg"
+ *
+ * <MapCopyRight> is required and is the string that will be displayed in the "Map (c)" part
+ * of the on-screen copyright notice. Can be an empty string.
+ * Example:
+ * "<a href='http://www.mapquest.com/'>MapQuest</a>"
+ *
+ * <DataCopyRight> is required and is the string that will be displayed in the "Data (c)" part
+ * of the on-screen copyright notice. Can be an empty string.
+ * Example:
+ * "<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
+ *
+ * <StyleCopyRight> is optional and is the string that will be displayed in the optional "Style (c)" part
+ * of the on-screen copyright notice.
+ */
+
+ QJsonParseError error;
+ QJsonDocument d = QJsonDocument::fromJson(reply->readAll(), &error);
+ if (error.error != QJsonParseError::NoError) {
+ qWarning() << "QGeoTileProviderOsm: Error parsing redirection data: "<<error.errorString() << "at "<<m_urlRedirector;
+ emit resolutionFinished(this);
+ return;
+ }
+ if (!d.isObject()) {
+ qWarning() << "QGeoTileProviderOsm: Invalid redirection data" << "at "<<m_urlRedirector;
+ emit resolutionFinished(this);
+ return;
+ }
+ const QJsonObject json = d.object();
+ const QJsonValue urlTemplate = json.value(QLatin1String("UrlTemplate"));
+ const QJsonValue imageFormat = json.value(QLatin1String("ImageFormat"));
+ const QJsonValue copyRightMap = json.value(QLatin1String("MapCopyRight"));
+ const QJsonValue copyRightData = json.value(QLatin1String("DataCopyRight"));
+ if ( urlTemplate == QJsonValue::Undefined
+ || imageFormat == QJsonValue::Undefined
+ || copyRightMap == QJsonValue::Undefined
+ || copyRightData == QJsonValue::Undefined
+ || !urlTemplate.isString()
+ || !imageFormat.isString()
+ || !copyRightMap.isString()
+ || !copyRightData.isString()) {
+ qWarning() << "QGeoTileProviderOsm: Incomplete redirection data" << "at "<<m_urlRedirector;
+ emit resolutionFinished(this);
+ return;
+ }
+
+ const QJsonValue enabled = json.value(QLatin1String("Enabled"));
+ if (enabled.isBool() && ! enabled.toBool()) {
+ qWarning() << "QGeoTileProviderOsm: Tileserver disabled" << "at "<<m_urlRedirector;
+ emit resolutionFinished(this);
+ return;
+ }
+
+ QString styleCopyRight;
+ const QJsonValue copyRightStyle = json.value(QLatin1String("StyleCopyRight"));
+ if (copyRightStyle != QJsonValue::Undefined && copyRightStyle.isString())
+ styleCopyRight = copyRightStyle.toString();
+
+ int minZL = 0;
+ int maxZL = 19;
+ const QJsonValue minZoom = json.value(QLatin1String("MinimumZoomLevel"));
+ if (minZoom.isDouble())
+ minZL = qBound(0, int(minZoom.toDouble()), maxValidZoom);
+ const QJsonValue maxZoom = json.value(QLatin1String("MaximumZoomLevel"));
+ if (maxZoom.isDouble())
+ maxZL = qBound(0, int(maxZoom.toDouble()), maxValidZoom);
+
+ m_provider = TileProvider(urlTemplate.toString(),
+ imageFormat.toString(),
+ copyRightMap.toString(),
+ copyRightData.toString(),
+ minZL,
+ maxZL);
+ m_provider.setStyleCopyRight(styleCopyRight);
+
+ if (m_provider.isValid())
+ m_status = Valid;
+
+ emit resolutionFinished(this);
+}
+
+void QGeoTileProviderOsm::onNetworkReplyError(QNetworkReply::NetworkError error)
+{
+ if (m_status == Resolving)
+ m_status = Idle;
+
+ qWarning() << "QGeoTileProviderOsm::onNetworkReplyError " << error;
+ handleError(error);
+
+ static_cast<QNetworkReply *>(sender())->deleteLater();
+ if (m_status == Invalid)
+ emit resolutionError(this, error);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.h b/src/plugins/geoservices/osm/qgeotileproviderosm.h
new file mode 100644
index 00000000..cdff7997
--- /dev/null
+++ b/src/plugins/geoservices/osm/qgeotileproviderosm.h
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** 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 QTILEPROVIDEROSM_H
+#define QTILEPROVIDEROSM_H
+
+#include <QtLocation/private/qgeomaptype_p.h>
+
+#include <QtCore/QUrl>
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkReply>
+#include <QtCore/QPointer>
+#include <QTimer>
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoTileProviderOsm: public QObject
+{
+ Q_OBJECT
+
+ friend class QGeoTileFetcherOsm;
+ friend class QGeoMapReplyOsm;
+ friend class QGeoTiledMappingManagerEngineOsm;
+public:
+ struct TileProvider {
+
+ static inline void sort2(int &a, int &b)
+ {
+ if (a > b) {
+ int temp=a;
+ a=b;
+ b=temp;
+ }
+ }
+
+ TileProvider() : m_valid(false)
+ {
+
+ }
+
+ TileProvider(const QString &urlTemplate,
+ const QString &format,
+ const QString &copyRightMap,
+ const QString &copyRightData,
+ int minimumZoomLevel = 0,
+ int maximumZoomLevel = 19) : m_valid(false)
+ {
+ if (urlTemplate.isEmpty())
+ return;
+ m_urlTemplate = urlTemplate;
+
+ if (format.isEmpty())
+ return;
+ m_format = format;
+
+ m_copyRightMap = copyRightMap;
+ m_copyRightData = copyRightData;
+
+ if (minimumZoomLevel < 0 || minimumZoomLevel > 30)
+ return;
+ m_minimumZoomLevel = minimumZoomLevel;
+
+ if (maximumZoomLevel < 0 || maximumZoomLevel > 30 || maximumZoomLevel < minimumZoomLevel)
+ return;
+ m_maximumZoomLevel = maximumZoomLevel;
+
+ // Currently supporting only %x, %y and &z
+ int offset[3];
+ offset[0] = m_urlTemplate.indexOf(QLatin1String("%x"));
+ if (offset[0] < 0)
+ return;
+
+ offset[1] = m_urlTemplate.indexOf(QLatin1String("%y"));
+ if (offset[1] < 0)
+ return;
+
+ offset[2] = m_urlTemplate.indexOf(QLatin1String("%z"));
+ if (offset[2] < 0)
+ return;
+
+ int sortedOffsets[3];
+ std::copy(offset, offset + 4, sortedOffsets);
+ sort2(sortedOffsets[0] ,sortedOffsets[1]);
+ sort2(sortedOffsets[1] ,sortedOffsets[2]);
+ sort2(sortedOffsets[0] ,sortedOffsets[1]);
+
+ int min = sortedOffsets[0];
+ int max = sortedOffsets[2];
+ int mid = sortedOffsets[1];
+
+ // Initing LUT
+ for (int i=0; i<3; i++) {
+ if (offset[0] == sortedOffsets[i])
+ paramsLUT[i] = 0;
+ else if (offset[1] == sortedOffsets[i])
+ paramsLUT[i] = 1;
+ else
+ paramsLUT[i] = 2;
+ }
+
+ m_urlPrefix = m_urlTemplate.mid(0 , min);
+ m_urlSuffix = m_urlTemplate.mid(max + 2, m_urlTemplate.size() - max - 2);
+
+ paramsSep[0] = m_urlTemplate.mid(min + 2, mid - min - 2);
+ paramsSep[1] = m_urlTemplate.mid(mid + 2, max - mid - 2);
+ m_valid = true;
+ }
+
+ ~TileProvider()
+ {
+ }
+
+ inline bool isValid() const
+ {
+ return m_valid;
+ }
+
+ inline QString mapCopyRight() const
+ {
+ return m_copyRightMap;
+ }
+
+ inline QString dataCopyRight() const
+ {
+ return m_copyRightData;
+ }
+
+ inline QString styleCopyRight() const
+ {
+ return m_copyRightStyle;
+ }
+
+ inline QString format() const
+ {
+ return m_format;
+ }
+
+ // Optional properties, not needed to construct a provider
+ void setStyleCopyRight(const QString &copyright)
+ {
+ m_copyRightStyle = copyright;
+ }
+
+ QUrl tileAddress(int x, int y, int z) const
+ {
+ if (z < m_minimumZoomLevel || z > m_maximumZoomLevel)
+ return QUrl();
+ int params[3] = { x, y, z};
+ QString url;
+ url += m_urlPrefix;
+ url += QString::number(params[paramsLUT[0]]);
+ url += paramsSep[0];
+ url += QString::number(params[paramsLUT[1]]);
+ url += paramsSep[1];
+ url += QString::number(params[paramsLUT[2]]);
+ url += m_urlSuffix;
+ return QUrl(url);
+ }
+
+ bool m_valid;
+ QString m_urlTemplate;
+ QString m_format;
+ QString m_copyRightMap;
+ QString m_copyRightData;
+ QString m_copyRightStyle;
+ QString m_urlPrefix;
+ QString m_urlSuffix;
+ int m_minimumZoomLevel;
+ int m_maximumZoomLevel;
+
+ int paramsLUT[3]; //Lookup table to handle possibly shuffled x,y,z
+ QString paramsSep[2]; // what goes in between %x, %y and %z
+ };
+
+ enum Status {Idle,
+ Resolving,
+ Valid,
+ Invalid };
+
+ QGeoTileProviderOsm(const QString &urlRedir,
+ QNetworkAccessManager *nm,
+ const QGeoMapType &mapType,
+ const TileProvider &providerFallback);
+
+ ~QGeoTileProviderOsm();
+
+
+
+ QUrl tileAddress(int x, int y, int z) const;
+ QString mapCopyRight() const;
+ QString dataCopyRight() const;
+ QString styleCopyRight() const;
+ QString format() const;
+ const QGeoMapType &mapType() const;
+ bool isValid() const;
+ bool isResolved() const;
+
+Q_SIGNALS:
+ void resolutionFinished(const QGeoTileProviderOsm *provider);
+ void resolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error);
+
+public Q_SLOTS:
+ void onNetworkReplyFinished();
+ void onNetworkReplyError(QNetworkReply::NetworkError error);
+ void resolveProvider();
+
+protected:
+ void disableRedirection();
+ void handleError(QNetworkReply::NetworkError error);
+
+ QNetworkAccessManager *m_nm;
+ QUrl m_urlRedirector; // The URL from where to fetch the URL template
+ TileProvider m_provider;
+ TileProvider m_providerFallback;
+ QGeoMapType m_mapType;
+ Status m_status;
+ QTimer m_retryTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTILEPROVIDEROSM_H
diff --git a/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java b/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java
index ac718199..b55a90d4 100644
--- a/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java
+++ b/src/plugins/position/android/jar/src/org/qtproject/qt5/android/positioning/QtPositioning.java
@@ -241,7 +241,7 @@ public class QtPositioning implements LocationListener
positioningListener.isSatelliteUpdate = false;
if (updateInterval == 0)
- updateInterval = 1000; //don't update more often than once per second
+ updateInterval = 50; //don't update more often than once per 50ms
positioningListener.updateIntervalTime = updateInterval;
if ((locationProvider & QT_GPS_PROVIDER) > 0) {
@@ -361,7 +361,7 @@ public class QtPositioning implements LocationListener
positioningListener.isSingleUpdate = isSingleRequest;
if (updateInterval == 0)
- updateInterval = 1000; //don't update more often than once per second
+ updateInterval = 50; //don't update more often than once per 50ms
if (isSingleRequest)
Log.d(TAG, "Single update for Satellites " + updateInterval);
diff --git a/src/plugins/position/android/src/jnipositioning.cpp b/src/plugins/position/android/src/jnipositioning.cpp
index 3ec772cd..e0124eb6 100644
--- a/src/plugins/position/android/src/jnipositioning.cpp
+++ b/src/plugins/position/android/src/jnipositioning.cpp
@@ -546,6 +546,11 @@ static bool registerNatives(JNIEnv *env)
Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
{
+ static bool initialized = false;
+ if (initialized)
+ return JNI_VERSION_1_6;
+ initialized = true;
+
typedef union {
JNIEnv *nativeEnvironment;
void *venv;
diff --git a/src/plugins/position/android/src/qgeopositioninfosource_android.cpp b/src/plugins/position/android/src/qgeopositioninfosource_android.cpp
index b24a6c96..488c1a70 100644
--- a/src/plugins/position/android/src/qgeopositioninfosource_android.cpp
+++ b/src/plugins/position/android/src/qgeopositioninfosource_android.cpp
@@ -111,7 +111,7 @@ void QGeoPositionInfoSourceAndroid::setPreferredPositioningMethods(QGeoPositionI
int QGeoPositionInfoSourceAndroid::minimumUpdateInterval() const
{
- return 1000;
+ return 50;
}
QGeoPositionInfoSource::Error QGeoPositionInfoSourceAndroid::error() const
diff --git a/src/plugins/position/android/src/qgeosatelliteinfosource_android.cpp b/src/plugins/position/android/src/qgeosatelliteinfosource_android.cpp
index e7cd2e7d..f89f6663 100644
--- a/src/plugins/position/android/src/qgeosatelliteinfosource_android.cpp
+++ b/src/plugins/position/android/src/qgeosatelliteinfosource_android.cpp
@@ -90,7 +90,7 @@ void QGeoSatelliteInfoSourceAndroid::setUpdateInterval(int msec)
int QGeoSatelliteInfoSourceAndroid::minimumUpdateInterval() const
{
- return 1000;
+ return 50;
}
QGeoSatelliteInfoSource::Error QGeoSatelliteInfoSourceAndroid::error() const
diff --git a/tests/auto/declarative_ui/tst_map_item_fit_viewport.qml b/tests/auto/declarative_ui/tst_map_item_fit_viewport.qml
index e296fd8d..fe4d9e49 100644
--- a/tests/auto/declarative_ui/tst_map_item_fit_viewport.qml
+++ b/tests/auto/declarative_ui/tst_map_item_fit_viewport.qml
@@ -34,10 +34,10 @@ import QtLocation.Test 5.5
/*
- (0,0) ---------------------------------------------------- (240,0)
+ (0,0) ---------------------------------------------------- (296,0)
| no map |
| (20,20) |
- (0,20) | ------------------------------------------ | (240,20)
+ (0,20) | ------------------------------------------ | (296,20)
| | | |
| | map | |
| | | |
@@ -52,15 +52,15 @@ import QtLocation.Test 5.5
| | | |
| ------------------------------------------ |
| |
- (0,240) ---------------------------------------------------- (240,240)
+ (0,296) ---------------------------------------------------- (296,296)
*/
Item {
id: page
x: 0; y: 0;
- width: 240
- height: 240
+ width: 296
+ height: 296
Plugin { id: testPlugin; name : "qmlgeo.test.plugin"; allowExperimental: true }
property variant mapDefaultCenter: QtPositioning.coordinate(20, 20)
@@ -97,11 +97,8 @@ Item {
property variant mapPolylineBottomRight: QtPositioning.coordinate(0, 0)
property variant mapRouteTopLeft: QtPositioning.coordinate(0, 0)
property variant mapRouteBottomRight: QtPositioning.coordinate(0, 0)
-
- property variant boundingBox: QtPositioning.rectangle(QtPositioning.coordinate(0, 0),
- QtPositioning.coordinate(0, 0))
-
- property variant fitRect: QtPositioning.rectangle(QtPositioning.coordinate(80, 80), QtPositioning.coordinate(78, 82))
+ property variant fitRect: QtPositioning.rectangle(QtPositioning.coordinate(80, 80),
+ QtPositioning.coordinate(78, 82))
property variant fitEmptyRect: QtPositioning.rectangle(QtPositioning.coordinate(79, 79),-1, -1)
property variant fitCircle: QtPositioning.circle(QtPositioning.coordinate(-50, -100), 1500)
property variant fitInvalidShape: QtPositioning.shape()
@@ -111,7 +108,7 @@ Item {
Map {
id: map;
- x: 20; y: 20; width: 200; height: 200
+ x: 20; y: 20; width: 256; height: 256
zoomLevel: 3
center: mapDefaultCenter
plugin: testPlugin;
@@ -222,16 +219,58 @@ Item {
name: "MapItemsFitViewport"
when: windowShown
- function test_aa_visible_basic() { // aa et al. for execution order
- wait(10)
- // sanity check that the coordinate conversion works, as
- // rest of the case relies on it. for robustness cut
- // a little slack with fuzzy compare
+ function initTestCase()
+ {
+ // sanity check that the coordinate conversion works
var mapcenter = map.fromCoordinate(map.center)
- verify (fuzzy_compare(mapcenter.x, 100, 2))
- verify (fuzzy_compare(mapcenter.y, 100, 2))
+ verify (fuzzy_compare(mapcenter.x, 128, 2))
+ verify (fuzzy_compare(mapcenter.y, 128, 2))
+ }
+
+ function init()
+ {
+ preMapRect.topLeft.latitude = 20
+ preMapRect.topLeft.longitude = 20
+ preMapRect.bottomRight.latitude = 10
+ preMapRect.bottomRight.longitude = 30
+ preMapCircle.center.latitude = 10
+ preMapCircle.center.longitude = 30
+ preMapQuickItem.coordinate.latitude = 35
+ preMapQuickItem.coordinate.longitude = 3
+ var i
+ for (i = 0; i < preMapPolygon.path.length; ++i) {
+ preMapPolygon.path[i].latitude = preMapPolygonDefaultPath[i].latitude
+ preMapPolygon.path[i].longitude = preMapPolygonDefaultPath[i].longitude
+ }
+ for (i = 0; i < preMapPolyline.path.length; ++i) {
+ preMapPolyline.path[i].latitude = preMapPolylineDefaultPath[i].latitude
+ preMapPolyline.path[i].longitude = preMapPolylineDefaultPath[i].longitude
+ }
+ for (i = 0; i < preMapRoute.route.path.length; ++i) {
+ preMapRoute.route.path[i].latitude = preMapRouteDefaultPath[i].latitude
+ preMapRoute.route.path[i].longitude = preMapRouteDefaultPath[i].longitude
+ }
+ // remove items
+ map.clearMapItems()
+ //clear_data()
+ compare (map.mapItems.length, 0)
+ // reset map
+ map.center.latitude = 20
+ map.center.longitude = 20
+ map.zoomLevel = 3
+ // re-add items and verify they are back (without needing to pan map etc.)
+ map.addMapItem(preMapRect)
+ map.addMapItem(preMapCircle)
+ map.addMapItem(preMapQuickItem)
+ map.addMapItem(preMapPolygon)
+ map.addMapItem(preMapPolyline)
+ map.addMapItem(preMapRoute)
+ compare (map.mapItems.length, 6)
+ calculate_bounds()
+ }
- reset()
+ function test_visible_itmes()
+ {
// normal case - fit viewport to items which are all already visible
verify_visibility_all_items()
map.fitViewportToMapItems()
@@ -239,21 +278,23 @@ Item {
verify_visibility_all_items()
}
- function test_ab_visible_zoom() {
- var i
+ function test_visible_zoom_in()
+ {
// zoom in (clipping also occurs)
var z = map.zoomLevel
- for (i = (z + 1); i < map.maximumZoomLevel; ++i ) {
- reset()
+ for (var i = (z + 1); i < map.maximumZoomLevel; ++i ) {
map.zoomLevel = i
visualInspectionPoint()
map.fitViewportToMapItems()
visualInspectionPoint()
verify_visibility_all_items()
}
+ }
+
+ function test_visible_zoom_out()
+ {
// zoom out
- for (i = (z - 1); i >= 0; --i ) {
- reset()
+ for (var i = (z - 1); i >= 0; --i ) {
map.zoomLevel = i
visualInspectionPoint()
verify_visibility_all_items()
@@ -263,7 +304,7 @@ Item {
}
}
- function test_ac_visible_map_move() {
+ function test_visible_map_move() {
// move map so all items are out of screen
// then fit viewport
var xDir = 1
@@ -272,7 +313,6 @@ Item {
var yDirChange = 1
var dir = 0
for (dir = 0; dir < 4; dir++) {
- reset()
verify_visibility_all_items()
var i = 0
var panX = map.width * xDir * 0.5
@@ -307,8 +347,7 @@ Item {
}
}
- function test_ad_fit_to_geoshape() {
- reset()
+ function test_fit_to_geoshape() {
visualInspectionPoint()
calculate_fit_circle_bounds()
//None should be visible
@@ -352,6 +391,84 @@ Item {
verify(!is_coord_on_screen(fitCircleBottomRight))
verify(is_coord_on_screen(fitEmptyRect.topLeft))
verify(is_coord_on_screen(fitEmptyRect.bottomRight))
+
+ // Test if this can be reset
+ map.visibleRegion = fitRect
+ verify(is_coord_on_screen(fitRect.topLeft))
+ verify(is_coord_on_screen(fitRect.bottomRight))
+ // move map
+ map.center = QtPositioning.coordinate(0,0)
+ verify(!is_coord_on_screen(fitRect.topLeft))
+ verify(!is_coord_on_screen(fitRect.bottomRight))
+ // recheck
+ map.visibleRegion = fitRect
+ verify(is_coord_on_screen(fitRect.topLeft))
+ verify(is_coord_on_screen(fitRect.bottomRight))
+ //zoom map
+ map.zoomLevel++
+ verify(!is_coord_on_screen(fitRect.topLeft))
+ verify(!is_coord_on_screen(fitRect.bottomRight))
+ // recheck
+ map.visibleRegion = fitRect
+ verify(is_coord_on_screen(fitRect.topLeft))
+ verify(is_coord_on_screen(fitRect.bottomRight))
+ }
+
+ // checks that circles belongs to the view port
+ function circle_in_viewport(center, radius, visible)
+ {
+ for (var i = 0; i < 128; ++i) {
+ var azimuth = 360.0 * i / 128.0;
+ var coord = center.atDistanceAndAzimuth(radius,azimuth)
+ if (coord.isValid)
+ verify(is_coord_on_screen(coord) === visible, visible ?
+ "circle not visible" : "circle visible")
+ }
+ }
+
+ function test_fit_circle_to_viewport(data)
+ {
+ verify(!is_coord_on_screen(data.center))
+ circle_in_viewport(data.center, data.radius, false)
+ map.visibleRegion = QtPositioning.circle(data.center, data.radius)
+ circle_in_viewport(data.center, data.radius, true)
+ }
+
+ function test_fit_circle_to_viewport_data()
+ {
+ return [
+ { tag: "circle 1", center:
+ QtPositioning.coordinate(70,70), radius: 10 },
+ { tag: "circle 2", center:
+ QtPositioning.coordinate(80,30), radius: 2000000 },
+ { tag: "circle 3", center:
+ QtPositioning.coordinate(-82,30), radius: 2000000 },
+ { tag: "circle 4", center:
+ QtPositioning.coordinate(60,179), radius: 20000 },
+ { tag: "circle 5", center:
+ QtPositioning.coordinate(60,-179), radius: 20000 },
+ ]
+ }
+
+ function test_fit_rectangle_to_viewport(data)
+ {
+ verify(!is_coord_on_screen(data.topLeft),"rectangle visible")
+ verify(!is_coord_on_screen(data.bottomRight),"rectangle visible")
+ map.visibleRegion = QtPositioning.rectangle(data.topLeft,data.bottomRight)
+ verify(is_coord_on_screen(data.topLeft),"rectangle not visible")
+ verify(is_coord_on_screen(data.bottomRight),"rectangle not visible")
+ }
+
+ function test_fit_rectangle_to_viewport_data()
+ {
+ return [
+ { tag: "rectangle 1",
+ topLeft: QtPositioning.coordinate(80, 80),
+ bottomRight: QtPositioning.coordinate(78, 82) },
+ { tag: "rectangle 2",
+ topLeft: QtPositioning.coordinate(30,-130),
+ bottomRight: QtPositioning.coordinate(0,-100)}
+ ]
}
/*function test_ad_visible_items_move() {
@@ -535,46 +652,6 @@ Item {
verify(is_coord_on_screen(mapRouteBottomRight))
}
- function reset(){
- preMapRect.topLeft.latitude = 20
- preMapRect.topLeft.longitude = 20
- preMapRect.bottomRight.latitude = 10
- preMapRect.bottomRight.longitude = 30
- preMapCircle.center.latitude = 10
- preMapCircle.center.longitude = 30
- preMapQuickItem.coordinate.latitude = 35
- preMapQuickItem.coordinate.longitude = 3
- var i
- for (i=0; i< preMapPolygon.path.length; ++i) {
- preMapPolygon.path[i].latitude = preMapPolygonDefaultPath[i].latitude
- preMapPolygon.path[i].longitude = preMapPolygonDefaultPath[i].longitude
- }
- for (i=0; i< preMapPolyline.path.length; ++i) {
- preMapPolyline.path[i].latitude = preMapPolylineDefaultPath[i].latitude
- preMapPolyline.path[i].longitude = preMapPolylineDefaultPath[i].longitude
- }
- for (i=0; i< preMapRoute.route.path.length; ++i) {
- preMapRoute.route.path[i].latitude = preMapRouteDefaultPath[i].latitude
- preMapRoute.route.path[i].longitude = preMapRouteDefaultPath[i].longitude
- }
- // remove items
- map.clearMapItems()
- //clear_data()
- compare (map.mapItems.length, 0)
- // reset map
- map.center.latitude = 20
- map.center.longitude = 20
- map.zoomLevel = 3
- // re-add items and verify they are back (without needing to pan map etc.)
- map.addMapItem(preMapRect)
- map.addMapItem(preMapCircle)
- map.addMapItem(preMapQuickItem)
- map.addMapItem(preMapPolygon)
- map.addMapItem(preMapPolyline)
- map.addMapItem(preMapRoute)
- compare (map.mapItems.length, 6)
- calculate_bounds()
- }
function is_coord_on_screen(coord) {
return is_point_on_screen(map.fromCoordinate(coord))
diff --git a/tests/auto/declarative_ui/tst_map_itemview.qml b/tests/auto/declarative_ui/tst_map_itemview.qml
index d3e64b6c..db788ace 100644
--- a/tests/auto/declarative_ui/tst_map_itemview.qml
+++ b/tests/auto/declarative_ui/tst_map_itemview.qml
@@ -393,6 +393,8 @@ Item {
tryCompare(mapForView, "mapItemsLength", 7)
testModel.datacount += 2
testModel2.datacount += 1
+ // delegate spawning is async. wait a bit.
+ wait(1)
tryCompare(mapForView, "mapItemsLength", 9)
theItemView.model = testModel