| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2015 The Qt Company Ltd. | 
| 4 | ** Contact: http://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the QtLocation module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL3$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see http://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at http://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU Lesser General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the | 
| 21 | ** packaging of this file. Please review the following information to | 
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. | 
| 24 | ** | 
| 25 | ** GNU General Public License Usage | 
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
| 27 | ** General Public License version 2.0 or later as published by the Free | 
| 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in | 
| 29 | ** the packaging of this file. Please review the following information to | 
| 30 | ** ensure the GNU General Public License version 2.0 requirements will be | 
| 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. | 
| 32 | ** | 
| 33 | ** $QT_END_LICENSE$ | 
| 34 | ** | 
| 35 | ****************************************************************************/ | 
| 36 |  | 
| 37 | #include "qdeclarativegeomap_p.h" | 
| 38 | #include "qdeclarativegeomapquickitem_p.h" | 
| 39 | #include "qdeclarativegeomapcopyrightsnotice_p.h" | 
| 40 | #include "qdeclarativegeoserviceprovider_p.h" | 
| 41 | #include "qdeclarativegeomaptype_p.h" | 
| 42 | #include "qgeomappingmanager_p.h" | 
| 43 | #include "qgeocameracapabilities_p.h" | 
| 44 | #include "qgeomap_p.h" | 
| 45 | #include "qdeclarativegeomapparameter_p.h" | 
| 46 | #include "qgeomapobject_p.h" | 
| 47 | #include <QtPositioning/QGeoCircle> | 
| 48 | #include <QtPositioning/QGeoRectangle> | 
| 49 | #include <QtPositioning/QGeoPath> | 
| 50 | #include <QtPositioning/QGeoPolygon> | 
| 51 | #include <QtQuick/QQuickWindow> | 
| 52 | #include <QtQuick/QSGRectangleNode> | 
| 53 | #include <QtQuick/private/qquickwindow_p.h> | 
| 54 | #include <QtQml/qqmlinfo.h> | 
| 55 | #include <QtQuick/private/qquickitem_p.h> | 
| 56 | #include <cmath> | 
| 57 |  | 
| 58 | #ifndef M_PI | 
| 59 | #define M_PI 3.141592653589793238463 | 
| 60 | #endif | 
| 61 |  | 
| 62 |  | 
| 63 | QT_BEGIN_NAMESPACE | 
| 64 |  | 
| 65 | static qreal sanitizeBearing(qreal bearing) | 
| 66 | { | 
| 67 |     bearing = std::fmod(x: bearing, y: qreal(360.0)); | 
| 68 |     if (bearing < 0.0) | 
| 69 |         bearing += 360.0; | 
| 70 |  | 
| 71 |     return bearing; | 
| 72 | } | 
| 73 |  | 
| 74 | /*! | 
| 75 |     \qmltype Map | 
| 76 |     \instantiates QDeclarativeGeoMap | 
| 77 |     \inqmlmodule QtLocation | 
| 78 |     \ingroup qml-QtLocation5-maps | 
| 79 |     \since QtLocation 5.0 | 
| 80 |  | 
| 81 |     \brief The Map type displays a map. | 
| 82 |  | 
| 83 |     The Map type is used to display a map or image of the Earth, with | 
| 84 |     the capability to also display interactive objects tied to the map's | 
| 85 |     surface. | 
| 86 |  | 
| 87 |     There are a variety of different ways to visualize the Earth's surface | 
| 88 |     in a 2-dimensional manner, but all of them involve some kind of projection: | 
| 89 |     a mathematical relationship between the 3D coordinates (latitude, longitude | 
| 90 |     and altitude) and 2D coordinates (X and Y in pixels) on the screen. | 
| 91 |  | 
| 92 |     Different sources of map data can use different projections, and from the | 
| 93 |     point of view of the Map type, we treat these as one replaceable unit: | 
| 94 |     the Map plugin. A Map plugin consists of a data source, as well as all other | 
| 95 |     details needed to display its data on-screen. | 
| 96 |  | 
| 97 |     The current Map plugin in use is contained in the \l plugin property of | 
| 98 |     the Map item. In order to display any image in a Map item, you will need | 
| 99 |     to set this property. See the \l Plugin type for a description of how | 
| 100 |     to retrieve an appropriate plugin for use. | 
| 101 |  | 
| 102 |     The geographic region displayed in the Map item is referred to as its | 
| 103 |     viewport, and this is defined by the properties \l center, and | 
| 104 |     \l zoomLevel. The \l center property contains a \l {coordinate} | 
| 105 |     specifying the center of the viewport, while \l zoomLevel controls the scale of the | 
| 106 |     map. See each of these properties for further details about their values. | 
| 107 |  | 
| 108 |     When the map is displayed, each possible geographic coordinate that is | 
| 109 |     visible will map to some pixel X and Y coordinate on the screen. To perform | 
| 110 |     conversions between these two, Map provides the \l toCoordinate and | 
| 111 |     \l fromCoordinate functions, which are of general utility. | 
| 112 |  | 
| 113 |     \section2 Map Objects | 
| 114 |  | 
| 115 |     Map related objects can be declared within the body of a Map object in Qt Quick and will | 
| 116 |     automatically appear on the Map. To add an object programmatically, first be | 
| 117 |     sure it is created with the Map as its parent (for example in an argument to | 
| 118 |     Component::createObject). | 
| 119 |     Then call the \l addMapItem method on the Map, if the type of this object is one of | 
| 120 |     \l MapCircle, \l MapRectangle, \l MapPolyline, \l MapPolygon, \l MapRoute or \l MapQuickItem. | 
| 121 |     A corresponding \l removeMapItem method also exists to do the opposite and | 
| 122 |     remove any of the above types of map objects from the Map. | 
| 123 |  | 
| 124 |     Moving Map objects around, resizing them or changing their shape normally | 
| 125 |     does not involve any special interaction with Map itself -- changing these | 
| 126 |     properties in a map object will automatically update the display. | 
| 127 |  | 
| 128 |     \section2 Interaction | 
| 129 |  | 
| 130 |     The Map type includes support for pinch and flick gestures to control | 
| 131 |     zooming and panning. These are enabled by default, and available at any | 
| 132 |     time by using the \l gesture object. The actual GestureArea is constructed | 
| 133 |     specially at startup and cannot be replaced or destroyed. Its properties | 
| 134 |     can be altered, however, to control its behavior. | 
| 135 |  | 
| 136 |     \section2 Performance | 
| 137 |  | 
| 138 |     Maps are rendered using OpenGL (ES) and the Qt Scene Graph stack, and as | 
| 139 |     a result perform quite well where GL accelerated hardware is available. | 
| 140 |  | 
| 141 |     For "online" Map plugins, network bandwidth and latency can be major | 
| 142 |     contributors to the user's perception of performance. Extensive caching is | 
| 143 |     performed to mitigate this, but such mitigation is not always perfect. For | 
| 144 |     "offline" plugins, the time spent retrieving the stored geographic data | 
| 145 |     and rendering the basic map features can often play a dominant role. Some | 
| 146 |     offline plugins may use hardware acceleration themselves to (partially) | 
| 147 |     avert this. | 
| 148 |  | 
| 149 |     In general, large and complex Map items such as polygons and polylines with | 
| 150 |     large numbers of vertices can have an adverse effect on UI performance. | 
| 151 |     Further, more detailed notes on this are in the documentation for each | 
| 152 |     map item type. | 
| 153 |  | 
| 154 |     \section2 Example Usage | 
| 155 |  | 
| 156 |     The following snippet shows a simple Map and the necessary Plugin type | 
| 157 |     to use it. The map is centered over Oslo, Norway, with zoom level 14. | 
| 158 |  | 
| 159 |     \quotefromfile minimal_map/main.qml | 
| 160 |     \skipto import | 
| 161 |     \printuntil } | 
| 162 |     \printline } | 
| 163 |     \skipto Map | 
| 164 |     \printuntil } | 
| 165 |     \printline } | 
| 166 |  | 
| 167 |     \image minimal_map.png | 
| 168 | */ | 
| 169 |  | 
| 170 | /*! | 
| 171 |     \qmlsignal QtLocation::Map::copyrightLinkActivated(string link) | 
| 172 |  | 
| 173 |     This signal is emitted when the user clicks on a \a link in the copyright notice. The | 
| 174 |     application should open the link in a browser or display its contents to the user. | 
| 175 | */ | 
| 176 |  | 
| 177 | QDeclarativeGeoMap::QDeclarativeGeoMap(QQuickItem *parent) | 
| 178 |         : QQuickItem(parent), | 
| 179 |         m_plugin(0), | 
| 180 |         m_mappingManager(0), | 
| 181 |         m_activeMapType(0), | 
| 182 |         m_gestureArea(new QQuickGeoMapGestureArea(this)), | 
| 183 |         m_map(0), | 
| 184 |         m_error(QGeoServiceProvider::NoError), | 
| 185 |         m_color(QColor::fromRgbF(r: 0.9, g: 0.9, b: 0.9)), | 
| 186 |         m_componentCompleted(false), | 
| 187 |         m_pendingFitViewport(false), | 
| 188 |         m_copyrightsVisible(true), | 
| 189 |         m_maximumViewportLatitude(0.0), | 
| 190 |         m_initialized(false), | 
| 191 |         m_userMinimumZoomLevel(qQNaN()), | 
| 192 |         m_userMaximumZoomLevel(qQNaN()), | 
| 193 |         m_userMinimumTilt(qQNaN()), | 
| 194 |         m_userMaximumTilt(qQNaN()), | 
| 195 |         m_userMinimumFieldOfView(qQNaN()), | 
| 196 |         m_userMaximumFieldOfView(qQNaN()) | 
| 197 | { | 
| 198 |     setAcceptHoverEvents(false); | 
| 199 |     setAcceptedMouseButtons(Qt::LeftButton); | 
| 200 |     setFlags(QQuickItem::ItemHasContents | QQuickItem::ItemClipsChildrenToShape); | 
| 201 |     setFiltersChildMouseEvents(true); // needed for childMouseEventFilter to work. | 
| 202 |  | 
| 203 |     m_activeMapType = new QDeclarativeGeoMapType(QGeoMapType(QGeoMapType::NoMap, | 
| 204 |                                                              tr(s: "No Map" ), | 
| 205 |                                                              tr(s: "No Map" ), | 
| 206 |                                                              false, false, | 
| 207 |                                                              0, | 
| 208 |                                                              QByteArrayLiteral("" ), | 
| 209 |                                                              QGeoCameraCapabilities()), this); | 
| 210 |     m_cameraData.setCenter(QGeoCoordinate(51.5073,-0.1277)); //London city center | 
| 211 |     m_cameraData.setZoomLevel(8.0); | 
| 212 |  | 
| 213 |     m_cameraCapabilities.setTileSize(256); | 
| 214 |     m_cameraCapabilities.setSupportsBearing(true); | 
| 215 |     m_cameraCapabilities.setSupportsTilting(true); | 
| 216 |     m_cameraCapabilities.setMinimumZoomLevel(0); | 
| 217 |     m_cameraCapabilities.setMaximumZoomLevel(30); | 
| 218 |     m_cameraCapabilities.setMinimumTilt(0); | 
| 219 |     m_cameraCapabilities.setMaximumTilt(89.5); | 
| 220 |     m_cameraCapabilities.setMinimumFieldOfView(1); | 
| 221 |     m_cameraCapabilities.setMaximumFieldOfView(179); | 
| 222 |  | 
| 223 |     m_minimumTilt = m_cameraCapabilities.minimumTilt(); | 
| 224 |     m_maximumTilt = m_cameraCapabilities.maximumTilt(); | 
| 225 |     m_minimumFieldOfView = m_cameraCapabilities.minimumFieldOfView(); | 
| 226 |     m_maximumFieldOfView = m_cameraCapabilities.maximumFieldOfView(); | 
| 227 | } | 
| 228 |  | 
| 229 | QDeclarativeGeoMap::~QDeclarativeGeoMap() | 
| 230 | { | 
| 231 |     // Removing map parameters and map items from m_map | 
| 232 |     if (m_map) { | 
| 233 |         m_map->clearParameters(); | 
| 234 |         m_map->clearMapItems(); | 
| 235 |     } | 
| 236 |  | 
| 237 |     // Remove the items from the map, making them deletable. | 
| 238 |     // Go in the same order as in removeMapChild: views, groups, then items | 
| 239 |     if (!m_mapViews.isEmpty()) { | 
| 240 |         const auto mapViews = m_mapViews; | 
| 241 |         for (QDeclarativeGeoMapItemView *v : mapViews) { // so that removeMapItemView_real can safely modify m_mapViews; | 
| 242 |             if (!v) | 
| 243 |                 continue; | 
| 244 |  | 
| 245 |             QQuickItem *parent = v->parentItem(); | 
| 246 |             QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(object: parent); | 
| 247 |             if (group) | 
| 248 |                 continue; // Ignore non-top-level MIVs. They will be recursively processed. | 
| 249 |                           // Identify them as being parented by a MapItemGroup. | 
| 250 |  | 
| 251 |             removeMapItemView_real(itemView: v); | 
| 252 |         } | 
| 253 |     } | 
| 254 |  | 
| 255 |     if (!m_mapItemGroups.isEmpty()) { | 
| 256 |         const auto mapGroups = m_mapItemGroups; | 
| 257 |         for (QDeclarativeGeoMapItemGroup *g : mapGroups) { | 
| 258 |             if (!g) | 
| 259 |                 continue; | 
| 260 |  | 
| 261 |             QQuickItem *parent =g->parentItem(); | 
| 262 |             QDeclarativeGeoMapItemGroup *group = qobject_cast<QDeclarativeGeoMapItemGroup *>(object: parent); | 
| 263 |             if (group) | 
| 264 |                 continue; // Ignore non-top-level Groups. They will be recursively processed. | 
| 265 |                           // Identify them as being parented by a MapItemGroup. | 
| 266 |  | 
| 267 |             removeMapItemGroup_real(itemGroup: g); | 
| 268 |         } | 
| 269 |     } | 
| 270 |  | 
| 271 |     // remove any remaining map items associations | 
| 272 |     const auto mapItems = m_mapItems; | 
| 273 |     for (auto mi: mapItems) | 
| 274 |         removeMapItem_real(item: mi.data()); | 
| 275 |  | 
| 276 |     if (m_copyrights.data()) | 
| 277 |         delete m_copyrights.data(); | 
| 278 |     m_copyrights.clear(); | 
| 279 |  | 
| 280 |     for (auto obj: qAsConst(t&: m_pendingMapObjects)) | 
| 281 |         obj->setMap(nullptr); // worst case: going to be setMap(nullptr)'d twice | 
| 282 |  | 
| 283 |     delete m_map; // map objects get reset here | 
| 284 | } | 
| 285 |  | 
| 286 | static QDeclarativeGeoMapType *findMapType(const QList<QDeclarativeGeoMapType *> &types, const QGeoMapType &type) | 
| 287 | { | 
| 288 |     for (int i = 0; i < types.size(); ++i) | 
| 289 |         if (types[i]->mapType() == type) | 
| 290 |             return types[i]; | 
| 291 |     return nullptr; | 
| 292 | } | 
| 293 |  | 
| 294 | void QDeclarativeGeoMap::onSupportedMapTypesChanged() | 
| 295 | { | 
| 296 |     QList<QDeclarativeGeoMapType *> supportedMapTypes; | 
| 297 |     QList<QGeoMapType> types = m_mappingManager->supportedMapTypes(); | 
| 298 |     for (int i = 0; i < types.size(); ++i) { | 
| 299 |         // types that are present and get removed will be deleted at QObject destruction | 
| 300 |         QDeclarativeGeoMapType *type = findMapType(types: m_supportedMapTypes, type: types[i]); | 
| 301 |         if (!type) | 
| 302 |             type = new QDeclarativeGeoMapType(types[i], this); | 
| 303 |         supportedMapTypes.append(t: type); | 
| 304 |     } | 
| 305 |     m_supportedMapTypes.swap(other&: supportedMapTypes); | 
| 306 |     if (m_supportedMapTypes.isEmpty()) { | 
| 307 |         m_map->setActiveMapType(QGeoMapType()); // no supported map types: setting an invalid one | 
| 308 |     } else { | 
| 309 |         bool hasMapType = false; | 
| 310 |         foreach (QDeclarativeGeoMapType *declarativeType, m_supportedMapTypes) { | 
| 311 |             if (declarativeType->mapType() == m_map->activeMapType()) | 
| 312 |                 hasMapType = true; | 
| 313 |         } | 
| 314 |         if (!hasMapType) { | 
| 315 |             QDeclarativeGeoMapType *type = m_supportedMapTypes.at(i: 0); | 
| 316 |             m_activeMapType = type; | 
| 317 |             m_map->setActiveMapType(type->mapType()); | 
| 318 |         } | 
| 319 |     } | 
| 320 |  | 
| 321 |     emit supportedMapTypesChanged(); | 
| 322 | } | 
| 323 |  | 
| 324 | void QDeclarativeGeoMap::setError(QGeoServiceProvider::Error error, const QString &errorString) | 
| 325 | { | 
| 326 |     if (m_error == error && m_errorString == errorString) | 
| 327 |         return; | 
| 328 |     m_error = error; | 
| 329 |     m_errorString = errorString; | 
| 330 |     emit errorChanged(); | 
| 331 | } | 
| 332 |  | 
| 333 | /*! | 
| 334 |     \internal | 
| 335 |     Called when the mapping manager is initialized AND the declarative element has a valid size > 0 | 
| 336 | */ | 
| 337 | void QDeclarativeGeoMap::initialize() | 
| 338 | { | 
| 339 |     // try to keep change signals in the end | 
| 340 |     bool visibleAreaHasChanged = false; | 
| 341 |  | 
| 342 |     QGeoCoordinate center = m_cameraData.center(); | 
| 343 |  | 
| 344 |     if (!qIsFinite(d: m_userMinimumZoomLevel)) | 
| 345 |         setMinimumZoomLevel(minimumZoomLevel: m_map->minimumZoom(), userSet: false); | 
| 346 |     else | 
| 347 |         setMinimumZoomLevel(minimumZoomLevel: qMax<qreal>(a: m_map->minimumZoom(), b: m_userMinimumZoomLevel), userSet: false); | 
| 348 |  | 
| 349 |     double bearing = m_cameraData.bearing(); | 
| 350 |     double tilt = m_cameraData.tilt(); | 
| 351 |     double fov = m_cameraData.fieldOfView(); // Must be 45.0 | 
| 352 |     QGeoCameraData cameraData = m_cameraData; | 
| 353 |  | 
| 354 |     if (!m_cameraCapabilities.supportsBearing() && bearing != 0.0) | 
| 355 |         cameraData.setBearing(0); | 
| 356 |  | 
| 357 |     if (!m_cameraCapabilities.supportsTilting() && tilt != 0.0) | 
| 358 |         cameraData.setTilt(0); | 
| 359 |  | 
| 360 |     m_map->setVisibleArea(m_visibleArea); | 
| 361 |     if (m_map->visibleArea() != m_visibleArea) | 
| 362 |         visibleAreaHasChanged = true; | 
| 363 |  | 
| 364 |     cameraData.setFieldOfView(qBound(min: m_cameraCapabilities.minimumFieldOfView(), | 
| 365 |                                        val: fov, | 
| 366 |                                        max: m_cameraCapabilities.maximumFieldOfView())); | 
| 367 |  | 
| 368 |     // set latitude boundary check | 
| 369 |     m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(cameraData); | 
| 370 |     m_minimumViewportLatitude = m_map->minimumCenterLatitudeAtZoom(cameraData); | 
| 371 |  | 
| 372 |     center.setLatitude(qBound(min: m_minimumViewportLatitude, val: center.latitude(), max: m_maximumViewportLatitude)); | 
| 373 |     cameraData.setCenter(center); | 
| 374 |  | 
| 375 |     connect(sender: m_map.data(), signal: &QGeoMap::cameraDataChanged, | 
| 376 |             receiver: this,  slot: &QDeclarativeGeoMap::onCameraDataChanged); | 
| 377 |     m_map->setCameraData(cameraData); // This normally triggers property changed signals. | 
| 378 |                                       // BUT not in this case, since m_cameraData is already == cameraData. | 
| 379 |                                       // So, emit visibleRegionChanged() separately, as | 
| 380 |                                       // the effective visible region becomes available only now. | 
| 381 |  | 
| 382 |     for (auto obj : qAsConst(t&: m_pendingMapObjects)) | 
| 383 |         obj->setMap(m_map); | 
| 384 |  | 
| 385 |     m_initialized = true; | 
| 386 |  | 
| 387 |     if (visibleAreaHasChanged) | 
| 388 |         emit visibleAreaChanged(); | 
| 389 |     connect(sender: m_map.data(), signal: &QGeoMap::visibleAreaChanged, receiver: this, slot: &QDeclarativeGeoMap::visibleAreaChanged); | 
| 390 |  | 
| 391 |     emit mapReadyChanged(ready: true); | 
| 392 |     emit visibleRegionChanged(); | 
| 393 |  | 
| 394 |     if (m_copyrights) // To not update during initialize() | 
| 395 |          update(); | 
| 396 | } | 
| 397 |  | 
| 398 | /*! | 
| 399 |     \internal | 
| 400 | */ | 
| 401 | void QDeclarativeGeoMap::pluginReady() | 
| 402 | { | 
| 403 |     QGeoServiceProvider *provider = m_plugin->sharedGeoServiceProvider(); | 
| 404 |     m_mappingManager = provider->mappingManager(); | 
| 405 |  | 
| 406 |     if (provider->mappingError() != QGeoServiceProvider::NoError) { | 
| 407 |         setError(error: provider->mappingError(), errorString: provider->mappingErrorString()); | 
| 408 |         return; | 
| 409 |     } | 
| 410 |  | 
| 411 |     if (!m_mappingManager) { | 
| 412 |         //TODO Should really be EngineNotSetError (see QML GeoCodeModel) | 
| 413 |         setError(error: QGeoServiceProvider::NotSupportedError, errorString: tr(s: "Plugin does not support mapping." )); | 
| 414 |         return; | 
| 415 |     } | 
| 416 |  | 
| 417 |     if (!m_mappingManager->isInitialized()) | 
| 418 |         connect(sender: m_mappingManager, SIGNAL(initialized()), receiver: this, SLOT(mappingManagerInitialized())); | 
| 419 |     else | 
| 420 |         mappingManagerInitialized(); | 
| 421 |  | 
| 422 |     // make sure this is only called once | 
| 423 |     disconnect(receiver: this, SLOT(pluginReady())); | 
| 424 | } | 
| 425 |  | 
| 426 | /*! | 
| 427 |     \internal | 
| 428 | */ | 
| 429 | void QDeclarativeGeoMap::componentComplete() | 
| 430 | { | 
| 431 |     m_componentCompleted = true; | 
| 432 |     populateParameters(); | 
| 433 |     populateMap(); | 
| 434 |     QQuickItem::componentComplete(); | 
| 435 | } | 
| 436 |  | 
| 437 | /*! | 
| 438 |     \qmlproperty MapGestureArea QtLocation::Map::gesture | 
| 439 |  | 
| 440 |     Contains the MapGestureArea created with the Map. This covers pan, flick and pinch gestures. | 
| 441 |     Use \c{gesture.enabled: true} to enable basic gestures, or see \l{MapGestureArea} for | 
| 442 |     further details. | 
| 443 | */ | 
| 444 |  | 
| 445 | QQuickGeoMapGestureArea *QDeclarativeGeoMap::gesture() | 
| 446 | { | 
| 447 |     return m_gestureArea; | 
| 448 | } | 
| 449 |  | 
| 450 | /*! | 
| 451 |     \internal | 
| 452 |  | 
| 453 |     This may happen before mappingManagerInitialized() | 
| 454 | */ | 
| 455 | void QDeclarativeGeoMap::populateMap() | 
| 456 | { | 
| 457 |     QSet<QObject *> kids(children().cbegin(), children().cend()); | 
| 458 |     const QList<QQuickItem *> quickKids = childItems(); | 
| 459 |     for (QQuickItem *ite: quickKids) | 
| 460 |         kids.insert(value: ite); | 
| 461 |  | 
| 462 |     for (QObject *k : qAsConst(t&: kids)) { | 
| 463 |         addMapChild(child: k); | 
| 464 |     } | 
| 465 | } | 
| 466 |  | 
| 467 | void QDeclarativeGeoMap::populateParameters() | 
| 468 | { | 
| 469 |     QObjectList kids = children(); | 
| 470 |     QList<QQuickItem *> quickKids = childItems(); | 
| 471 |     for (int i = 0; i < quickKids.count(); ++i) | 
| 472 |         kids.append(t: quickKids.at(i)); | 
| 473 |     for (int i = 0; i < kids.size(); ++i) { | 
| 474 |         QDeclarativeGeoMapParameter *mapParameter = qobject_cast<QDeclarativeGeoMapParameter *>(object: kids.at(i)); | 
| 475 |         if (mapParameter) | 
| 476 |             addMapParameter(parameter: mapParameter); | 
| 477 |     } | 
| 478 | } | 
| 479 |  | 
| 480 | /*! | 
| 481 |     \internal | 
| 482 | */ | 
| 483 | void QDeclarativeGeoMap::setupMapView(QDeclarativeGeoMapItemView *view) | 
| 484 | { | 
| 485 |     view->setMap(this); | 
| 486 | } | 
| 487 |  | 
| 488 | /*! | 
| 489 |  * \internal | 
| 490 |  */ | 
| 491 | QSGNode *QDeclarativeGeoMap::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) | 
| 492 | { | 
| 493 |     if (!m_map) { | 
| 494 |         delete oldNode; | 
| 495 |         return 0; | 
| 496 |     } | 
| 497 |  | 
| 498 |     QSGRectangleNode *root = static_cast<QSGRectangleNode *>(oldNode); | 
| 499 |     if (!root) | 
| 500 |         root = window()->createRectangleNode(); | 
| 501 |  | 
| 502 |     root->setRect(boundingRect()); | 
| 503 |     root->setColor(m_color); | 
| 504 |  | 
| 505 |     QSGNode *content = root->childCount() ? root->firstChild() : 0; | 
| 506 |     content = m_map->updateSceneGraph(node: content, window: window()); | 
| 507 |     if (content && root->childCount() == 0) | 
| 508 |         root->appendChildNode(node: content); | 
| 509 |  | 
| 510 |     return root; | 
| 511 | } | 
| 512 |  | 
| 513 | /*! | 
| 514 |     \qmlproperty Plugin QtLocation::Map::plugin | 
| 515 |  | 
| 516 |     This property holds the plugin which provides the mapping functionality. | 
| 517 |  | 
| 518 |     This is a write-once property. Once the map has a plugin associated with | 
| 519 |     it, any attempted modifications of the plugin will be ignored. | 
| 520 | */ | 
| 521 |  | 
| 522 | void QDeclarativeGeoMap::setPlugin(QDeclarativeGeoServiceProvider *plugin) | 
| 523 | { | 
| 524 |     if (m_plugin) { | 
| 525 |         qmlWarning(me: this) << QStringLiteral("Plugin is a write-once property, and cannot be set again." ); | 
| 526 |         return; | 
| 527 |     } | 
| 528 |     m_plugin = plugin; | 
| 529 |     emit pluginChanged(plugin: m_plugin); | 
| 530 |  | 
| 531 |     if (m_plugin->isAttached()) { | 
| 532 |         pluginReady(); | 
| 533 |     } else { | 
| 534 |         connect(sender: m_plugin, SIGNAL(attached()), | 
| 535 |                 receiver: this, SLOT(pluginReady())); | 
| 536 |     } | 
| 537 | } | 
| 538 |  | 
| 539 | /*! | 
| 540 |     \internal | 
| 541 | */ | 
| 542 | void QDeclarativeGeoMap::onCameraCapabilitiesChanged(const QGeoCameraCapabilities &oldCameraCapabilities) | 
| 543 | { | 
| 544 |     if (m_map->cameraCapabilities() == oldCameraCapabilities) | 
| 545 |         return; | 
| 546 |     m_cameraCapabilities = m_map->cameraCapabilities(); | 
| 547 |  | 
| 548 |     //The zoom level limits are only restricted by the plugins values, if the user has set a more | 
| 549 |     //strict zoom level limit before initialization nothing is done here. | 
| 550 |     //minimum zoom level might be changed to limit gray bundaries | 
| 551 |     //This code assumes that plugins' maximum zoom level will never exceed 30.0 | 
| 552 |     if (m_cameraCapabilities.maximumZoomLevelAt256() < m_gestureArea->maximumZoomLevel()) { | 
| 553 |         setMaximumZoomLevel(maximumZoomLevel: m_cameraCapabilities.maximumZoomLevelAt256(), userSet: false); | 
| 554 |     } else if (m_cameraCapabilities.maximumZoomLevelAt256() > m_gestureArea->maximumZoomLevel()) { | 
| 555 |         if (!qIsFinite(d: m_userMaximumZoomLevel)) { | 
| 556 |             // If the user didn't set anything | 
| 557 |             setMaximumZoomLevel(maximumZoomLevel: m_cameraCapabilities.maximumZoomLevelAt256(), userSet: false); | 
| 558 |         } else {  // Try to set what the user requested | 
| 559 |             // Else if the user set something larger, but that got clamped by the previous camera caps | 
| 560 |             setMaximumZoomLevel(maximumZoomLevel: qMin<qreal>(a: m_cameraCapabilities.maximumZoomLevelAt256(), | 
| 561 |                                             b: m_userMaximumZoomLevel), userSet: false); | 
| 562 |         } | 
| 563 |     } | 
| 564 |  | 
| 565 |     if (m_cameraCapabilities.minimumZoomLevelAt256() > m_gestureArea->minimumZoomLevel()) { | 
| 566 |         setMinimumZoomLevel(minimumZoomLevel: m_cameraCapabilities.minimumZoomLevelAt256(), userSet: false); | 
| 567 |     } else if (m_cameraCapabilities.minimumZoomLevelAt256() < m_gestureArea->minimumZoomLevel()) { | 
| 568 |         if (!qIsFinite(d: m_userMinimumZoomLevel)) { | 
| 569 |             // If the user didn't set anything, trying to set the new caps. | 
| 570 |             setMinimumZoomLevel(minimumZoomLevel: m_cameraCapabilities.minimumZoomLevelAt256(), userSet: false); | 
| 571 |         } else {  // Try to set what the user requested | 
| 572 |             // Else if the user set a minimum, m_gestureArea->minimumZoomLevel() might be larger | 
| 573 |             // because of different reasons. Resetting it, as if it ends to be the same, | 
| 574 |             // no signal will be emitted. | 
| 575 |             setMinimumZoomLevel(minimumZoomLevel: qMax<qreal>(a: m_cameraCapabilities.minimumZoomLevelAt256(), | 
| 576 |                                             b: m_userMinimumZoomLevel), userSet: false); | 
| 577 |         } | 
| 578 |     } | 
| 579 |  | 
| 580 |     // Tilt | 
| 581 |     if (m_cameraCapabilities.maximumTilt() < m_maximumTilt) { | 
| 582 |         setMaximumTilt(maximumTilt: m_cameraCapabilities.maximumTilt(), userSet: false); | 
| 583 |     } else if (m_cameraCapabilities.maximumTilt() > m_maximumTilt) { | 
| 584 |         if (!qIsFinite(d: m_userMaximumTilt)) | 
| 585 |             setMaximumTilt(maximumTilt: m_cameraCapabilities.maximumTilt(), userSet: false); | 
| 586 |         else // Try to set what the user requested | 
| 587 |             setMaximumTilt(maximumTilt: qMin<qreal>(a: m_cameraCapabilities.maximumTilt(), b: m_userMaximumTilt), userSet: false); | 
| 588 |     } | 
| 589 |  | 
| 590 |     if (m_cameraCapabilities.minimumTilt() > m_minimumTilt) { | 
| 591 |         setMinimumTilt(minimumTilt: m_cameraCapabilities.minimumTilt(), userSet: false); | 
| 592 |     } else if (m_cameraCapabilities.minimumTilt() < m_minimumTilt) { | 
| 593 |         if (!qIsFinite(d: m_userMinimumTilt)) | 
| 594 |             setMinimumTilt(minimumTilt: m_cameraCapabilities.minimumTilt(), userSet: false); | 
| 595 |         else // Try to set what the user requested | 
| 596 |             setMinimumTilt(minimumTilt: qMax<qreal>(a: m_cameraCapabilities.minimumTilt(), b: m_userMinimumTilt), userSet: false); | 
| 597 |     } | 
| 598 |  | 
| 599 |     // FoV | 
| 600 |     if (m_cameraCapabilities.maximumFieldOfView() < m_maximumFieldOfView) { | 
| 601 |         setMaximumFieldOfView(maximumFieldOfView: m_cameraCapabilities.maximumFieldOfView(), userSet: false); | 
| 602 |     } else if (m_cameraCapabilities.maximumFieldOfView() > m_maximumFieldOfView) { | 
| 603 |         if (!qIsFinite(d: m_userMaximumFieldOfView)) | 
| 604 |             setMaximumFieldOfView(maximumFieldOfView: m_cameraCapabilities.maximumFieldOfView(), userSet: false); | 
| 605 |         else // Try to set what the user requested | 
| 606 |             setMaximumFieldOfView(maximumFieldOfView: qMin<qreal>(a: m_cameraCapabilities.maximumFieldOfView(), b: m_userMaximumFieldOfView), userSet: false); | 
| 607 |     } | 
| 608 |  | 
| 609 |     if (m_cameraCapabilities.minimumFieldOfView() > m_minimumFieldOfView) { | 
| 610 |         setMinimumFieldOfView(minimumFieldOfView: m_cameraCapabilities.minimumFieldOfView(), userSet: false); | 
| 611 |     } else if (m_cameraCapabilities.minimumFieldOfView() < m_minimumFieldOfView) { | 
| 612 |         if (!qIsFinite(d: m_userMinimumFieldOfView)) | 
| 613 |             setMinimumFieldOfView(minimumFieldOfView: m_cameraCapabilities.minimumFieldOfView(), userSet: false); | 
| 614 |         else // Try to set what the user requested | 
| 615 |             setMinimumFieldOfView(minimumFieldOfView: qMax<qreal>(a: m_cameraCapabilities.minimumFieldOfView(), b: m_userMinimumFieldOfView), userSet: false); | 
| 616 |     } | 
| 617 | } | 
| 618 |  | 
| 619 | /*! | 
| 620 |     \internal | 
| 621 |     this function will only be ever called once | 
| 622 | */ | 
| 623 | void QDeclarativeGeoMap::mappingManagerInitialized() | 
| 624 | { | 
| 625 |     m_map = m_mappingManager->createMap(parent: this); | 
| 626 |  | 
| 627 |     if (!m_map) | 
| 628 |         return; | 
| 629 |  | 
| 630 |     // Any map items that were added before the plugin was ready | 
| 631 |     // need to have setMap called again | 
| 632 |     for (const QPointer<QDeclarativeGeoMapItemBase> &item : qAsConst(t&: m_mapItems)) { | 
| 633 |         if (item) { | 
| 634 |             item->setMap(quickMap: this, map: m_map); | 
| 635 |             m_map->addMapItem(item: item.data()); // m_map filters out what is not supported. | 
| 636 |         } | 
| 637 |     } | 
| 638 |  | 
| 639 |     /* COPY NOTICE SETUP */ | 
| 640 |     m_copyrights = new QDeclarativeGeoMapCopyrightNotice(this); | 
| 641 |     m_copyrights->setCopyrightsZ(m_maxChildZ + 1); | 
| 642 |     m_copyrights->setCopyrightsVisible(m_copyrightsVisible); | 
| 643 |     m_copyrights->setMapSource(this); | 
| 644 |  | 
| 645 |     m_gestureArea->setMap(m_map); | 
| 646 |  | 
| 647 |     QList<QGeoMapType> types = m_mappingManager->supportedMapTypes(); | 
| 648 |     for (int i = 0; i < types.size(); ++i) { | 
| 649 |         QDeclarativeGeoMapType *type = new QDeclarativeGeoMapType(types[i], this); | 
| 650 |         m_supportedMapTypes.append(t: type); | 
| 651 |     } | 
| 652 |  | 
| 653 |     if (m_activeMapType && m_plugin->name().toLatin1() == m_activeMapType->mapType().pluginName()) { | 
| 654 |         m_map->setActiveMapType(m_activeMapType->mapType()); | 
| 655 |     } else { | 
| 656 |         if (m_activeMapType) | 
| 657 |             m_activeMapType->deleteLater(); | 
| 658 |  | 
| 659 |         if (!m_supportedMapTypes.isEmpty()) { | 
| 660 |                 m_activeMapType = m_supportedMapTypes.at(i: 0); | 
| 661 |                 m_map->setActiveMapType(m_activeMapType->mapType()); | 
| 662 |         } else { | 
| 663 |             m_activeMapType = new QDeclarativeGeoMapType(QGeoMapType(QGeoMapType::NoMap, | 
| 664 |                                                                      tr(s: "No Map" ), | 
| 665 |                                                                      tr(s: "No Map" ), | 
| 666 |                                                                      false, | 
| 667 |                                                                      false, | 
| 668 |                                                                      0, | 
| 669 |                                                                      QByteArrayLiteral("" ), | 
| 670 |                                                                      QGeoCameraCapabilities()), this); | 
| 671 |         } | 
| 672 |     } | 
| 673 |  | 
| 674 |     // Update camera capabilities | 
| 675 |     onCameraCapabilitiesChanged(oldCameraCapabilities: m_cameraCapabilities); | 
| 676 |  | 
| 677 |     // Map tiles are built in this call. m_map->minimumZoom() becomes operational | 
| 678 |     // after this has been called at least once, after creation. | 
| 679 |     // However, getting into the following block may fire a copyrightsChanged that would get lost, | 
| 680 |     // as the connections are set up after. | 
| 681 |     QString copyrightString; | 
| 682 |     QImage copyrightImage; | 
| 683 |     if (!m_initialized && width() > 0 && height() > 0) { | 
| 684 |         QMetaObject::Connection copyrightStringCatcherConnection = | 
| 685 |                 connect(sender: m_map.data(), | 
| 686 |                         signal: QOverload<const QString &>::of(ptr: &QGeoMap::copyrightsChanged), | 
| 687 |                         slot: [©rightString](const QString ©){ copyrightString = copy; }); | 
| 688 |         QMetaObject::Connection copyrightImageCatcherConnection = | 
| 689 |                 connect(sender: m_map.data(), | 
| 690 |                         signal: QOverload<const QImage &>::of(ptr: &QGeoMap::copyrightsChanged), | 
| 691 |                         slot: [©rightImage](const QImage ©){ copyrightImage = copy; }); | 
| 692 |         m_map->setViewportSize(QSize(width(), height())); | 
| 693 |         initialize(); // This emits the caught signals above | 
| 694 |         QObject::disconnect(copyrightStringCatcherConnection); | 
| 695 |         QObject::disconnect(copyrightImageCatcherConnection); | 
| 696 |     } | 
| 697 |  | 
| 698 |  | 
| 699 |     /* COPYRIGHT SIGNALS REWIRING */ | 
| 700 |     connect(sender: m_map.data(), SIGNAL(copyrightsChanged(QImage)), | 
| 701 |             receiver: this,  SIGNAL(copyrightsChanged(QImage))); | 
| 702 |     connect(sender: m_map.data(), SIGNAL(copyrightsChanged(QString)), | 
| 703 |             receiver: this,  SIGNAL(copyrightsChanged(QString))); | 
| 704 |     if (!copyrightString.isEmpty()) | 
| 705 |         emit m_map->copyrightsChanged(copyrightsHtml: copyrightString); | 
| 706 |     else if (!copyrightImage.isNull()) | 
| 707 |         emit m_map->copyrightsChanged(copyrightsImage: copyrightImage); | 
| 708 |  | 
| 709 |  | 
| 710 |     connect(sender: window(), signal: &QQuickWindow::beforeSynchronizing, receiver: this, slot: &QDeclarativeGeoMap::updateItemToWindowTransform, type: Qt::DirectConnection); | 
| 711 |     connect(sender: m_map.data(), signal: &QGeoMap::sgNodeChanged, receiver: this, slot: &QDeclarativeGeoMap::onSGNodeChanged); | 
| 712 |     connect(sender: m_map.data(), signal: &QGeoMap::cameraCapabilitiesChanged, receiver: this, slot: &QDeclarativeGeoMap::onCameraCapabilitiesChanged); | 
| 713 |  | 
| 714 |     // This prefetches a buffer around the map | 
| 715 |     m_map->prefetchData(); | 
| 716 |  | 
| 717 |     connect(sender: m_mappingManager, SIGNAL(supportedMapTypesChanged()), receiver: this, SLOT(onSupportedMapTypesChanged())); | 
| 718 |     emit minimumZoomLevelChanged(); | 
| 719 |     emit maximumZoomLevelChanged(); | 
| 720 |     emit supportedMapTypesChanged(); | 
| 721 |     emit activeMapTypeChanged(); | 
| 722 |  | 
| 723 |     // Any map item groups that were added before the plugin was ready | 
| 724 |     // DO NOT need to have setMap called again on their children map items | 
| 725 |     // because they have been added to m_mapItems, which is processed right above. | 
| 726 |  | 
| 727 |  | 
| 728 |     // All map parameters that were added before the plugin was ready | 
| 729 |     // need to be added to m_map | 
| 730 |     for (QDeclarativeGeoMapParameter *p : qAsConst(t&: m_mapParameters)) | 
| 731 |         m_map->addParameter(param: p); | 
| 732 |  | 
| 733 |     if (m_initialized) | 
| 734 |         update(); | 
| 735 | } | 
| 736 |  | 
| 737 | /*! | 
| 738 |     \internal | 
| 739 | */ | 
| 740 | QDeclarativeGeoServiceProvider *QDeclarativeGeoMap::plugin() const | 
| 741 | { | 
| 742 |     return m_plugin; | 
| 743 | } | 
| 744 |  | 
| 745 | /*! | 
| 746 |     \internal | 
| 747 |     Sets the gesture areas minimum zoom level. If the camera capabilities | 
| 748 |     has been set this method honors the boundaries set by it. | 
| 749 |     The minimum zoom level will also have a lower bound dependent on the size | 
| 750 |     of the canvas, effectively preventing to display out of bounds areas. | 
| 751 | */ | 
| 752 | void QDeclarativeGeoMap::setMinimumZoomLevel(qreal minimumZoomLevel, bool userSet) | 
| 753 | { | 
| 754 |     if (minimumZoomLevel >= 0) { | 
| 755 |         qreal oldUserMinimumZoomLevel = m_userMinimumZoomLevel; | 
| 756 |         if (userSet) | 
| 757 |             m_userMinimumZoomLevel = minimumZoomLevel; | 
| 758 |         qreal oldMinimumZoomLevel = this->minimumZoomLevel(); | 
| 759 |  | 
| 760 |         minimumZoomLevel = qBound(min: qreal(m_cameraCapabilities.minimumZoomLevelAt256()), val: minimumZoomLevel, max: maximumZoomLevel()); | 
| 761 |         if (m_map) | 
| 762 |              minimumZoomLevel = qMax<qreal>(a: minimumZoomLevel, b: m_map->minimumZoom()); | 
| 763 |  | 
| 764 |         // minimumZoomLevel is, at this point, the implicit minimum zoom level | 
| 765 |         m_gestureArea->setMinimumZoomLevel(minimumZoomLevel); | 
| 766 |  | 
| 767 |         if (zoomLevel() < minimumZoomLevel && (m_gestureArea->enabled() || !m_cameraCapabilities.overzoomEnabled())) | 
| 768 |             setZoomLevel(minimumZoomLevel); | 
| 769 |  | 
| 770 |         if (qIsNaN(d: m_userMinimumZoomLevel) && oldMinimumZoomLevel != minimumZoomLevel) | 
| 771 |             emit minimumZoomLevelChanged(); | 
| 772 |         else if (userSet && oldUserMinimumZoomLevel != m_userMinimumZoomLevel) | 
| 773 |             emit minimumZoomLevelChanged(); | 
| 774 |     } | 
| 775 | } | 
| 776 |  | 
| 777 | /*! | 
| 778 |     \qmlproperty real QtLocation::Map::minimumZoomLevel | 
| 779 |  | 
| 780 |     This property holds the minimum valid zoom level for the map. | 
| 781 |  | 
| 782 |     The minimum zoom level defined by the \l plugin used is a lower bound for | 
| 783 |     this property. However, the returned value is also canvas-size-dependent, and | 
| 784 |     can be higher than the user-specified value, or than the minimum zoom level | 
| 785 |     defined by the plugin used, to prevent the map from being smaller than the | 
| 786 |     viewport in either dimension. | 
| 787 |  | 
| 788 |     If the \l plugin property is not set or the plugin does not support mapping, this property is \c 0. | 
| 789 | */ | 
| 790 |  | 
| 791 | qreal QDeclarativeGeoMap::minimumZoomLevel() const | 
| 792 | { | 
| 793 |     if (!qIsNaN(d: m_userMinimumZoomLevel)) | 
| 794 |         return m_userMinimumZoomLevel; | 
| 795 |     else | 
| 796 |         return m_gestureArea->minimumZoomLevel(); | 
| 797 | } | 
| 798 |  | 
| 799 | /*! | 
| 800 |     \internal | 
| 801 | */ | 
| 802 | qreal QDeclarativeGeoMap::implicitMinimumZoomLevel() const | 
| 803 | { | 
| 804 |     return m_gestureArea->minimumZoomLevel(); | 
| 805 | } | 
| 806 |  | 
| 807 | /*! | 
| 808 |     \internal | 
| 809 | */ | 
| 810 | qreal QDeclarativeGeoMap::effectiveMinimumZoomLevel() const | 
| 811 | { | 
| 812 |     return qMax<qreal>(a: minimumZoomLevel(), b: implicitMinimumZoomLevel()); | 
| 813 | } | 
| 814 |  | 
| 815 | /*! | 
| 816 |     \internal | 
| 817 |     Sets the gesture areas maximum zoom level. If the camera capabilities | 
| 818 |     has been set this method honors the boundaries set by it. | 
| 819 | */ | 
| 820 | void QDeclarativeGeoMap::setMaximumZoomLevel(qreal maximumZoomLevel, bool userSet) | 
| 821 | { | 
| 822 |     if (maximumZoomLevel >= 0) { | 
| 823 |         if (userSet) | 
| 824 |             m_userMaximumZoomLevel = maximumZoomLevel; | 
| 825 |         qreal oldMaximumZoomLevel = this->maximumZoomLevel(); | 
| 826 |  | 
| 827 |         maximumZoomLevel = qBound(min: minimumZoomLevel(), val: maximumZoomLevel, max: qreal(m_cameraCapabilities.maximumZoomLevelAt256())); | 
| 828 |  | 
| 829 |         m_gestureArea->setMaximumZoomLevel(maximumZoomLevel); | 
| 830 |  | 
| 831 |         if (zoomLevel() > maximumZoomLevel && (m_gestureArea->enabled() || !m_cameraCapabilities.overzoomEnabled())) | 
| 832 |             setZoomLevel(maximumZoomLevel); | 
| 833 |  | 
| 834 |         if (oldMaximumZoomLevel != maximumZoomLevel) | 
| 835 |             emit maximumZoomLevelChanged(); | 
| 836 |     } | 
| 837 | } | 
| 838 |  | 
| 839 | /*! | 
| 840 |     \qmlproperty real QtLocation::Map::maximumZoomLevel | 
| 841 |  | 
| 842 |     This property holds the maximum valid zoom level for the map. | 
| 843 |  | 
| 844 |     The maximum zoom level is defined by the \l plugin used. | 
| 845 |     If the \l plugin property is not set or the plugin does not support mapping, this property is \c 30. | 
| 846 | */ | 
| 847 |  | 
| 848 | qreal QDeclarativeGeoMap::maximumZoomLevel() const | 
| 849 | { | 
| 850 |     return m_gestureArea->maximumZoomLevel(); | 
| 851 | } | 
| 852 |  | 
| 853 | /*! | 
| 854 |     \qmlproperty real QtLocation::Map::zoomLevel | 
| 855 |  | 
| 856 |     This property holds the zoom level for the map. | 
| 857 |  | 
| 858 |     Larger values for the zoom level provide more detail. Zoom levels | 
| 859 |     are always non-negative. The default value is 8.0. Depending on the plugin in use, | 
| 860 |     values outside the [minimumZoomLevel, maximumZoomLevel] range, which represent the range for which | 
| 861 |     tiles are available, may be accepted, or clamped. | 
| 862 | */ | 
| 863 | void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel) | 
| 864 | { | 
| 865 |     return setZoomLevel(zoomLevel, overzoom: m_cameraCapabilities.overzoomEnabled()); | 
| 866 | } | 
| 867 |  | 
| 868 | /*! | 
| 869 |     \internal | 
| 870 |  | 
| 871 |     Sets the zoom level. | 
| 872 |     Larger values for the zoom level provide more detail. Zoom levels | 
| 873 |     are always non-negative. The default value is 8.0. Values outside the | 
| 874 |     [minimumZoomLevel, maximumZoomLevel] range, which represent the range for which | 
| 875 |     tiles are available, can be accepted or clamped by setting the overzoom argument | 
| 876 |     to true or false respectively. | 
| 877 | */ | 
| 878 | void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel, bool overzoom) | 
| 879 | { | 
| 880 |     if (zoomLevel < 0) | 
| 881 |         return; | 
| 882 |  | 
| 883 |     if (m_initialized) { | 
| 884 |         QGeoCameraData cameraData = m_map->cameraData(); | 
| 885 |         if (cameraData.zoomLevel() == zoomLevel) | 
| 886 |             return; | 
| 887 |  | 
| 888 |         cameraData.setZoomLevel(qBound<qreal>(min: overzoom ? m_map->minimumZoom() : effectiveMinimumZoomLevel(), | 
| 889 |                                                 val: zoomLevel, | 
| 890 |                                                 max: overzoom ? 30 : maximumZoomLevel())); | 
| 891 |         m_maximumViewportLatitude = m_map->maximumCenterLatitudeAtZoom(cameraData); | 
| 892 |         m_minimumViewportLatitude = m_map->minimumCenterLatitudeAtZoom(cameraData); | 
| 893 |         QGeoCoordinate coord = cameraData.center(); | 
| 894 |         coord.setLatitude(qBound(min: m_minimumViewportLatitude, val: coord.latitude(), max: m_maximumViewportLatitude)); | 
| 895 |         cameraData.setCenter(coord); | 
| 896 |         m_map->setCameraData(cameraData); | 
| 897 |     } else { | 
| 898 |         const bool zlHasChanged = zoomLevel != m_cameraData.zoomLevel(); | 
| 899 |         m_cameraData.setZoomLevel(zoomLevel); | 
| 900 |         if (zlHasChanged) { | 
| 901 |             emit zoomLevelChanged(zoomLevel); | 
| 902 |             // do not emit visibleRegionChanged() here, because, if the map isn't initialized, | 
| 903 |             // the getter won't return anything updated | 
| 904 |         } | 
| 905 |     } | 
| 906 | } | 
| 907 |  | 
| 908 | bool QDeclarativeGeoMap::addMapChild(QObject *child) | 
| 909 | { | 
| 910 |     // dispatch items appropriately | 
| 911 |     QDeclarativeGeoMapItemView *mapView = qobject_cast<QDeclarativeGeoMapItemView *>(object: child); | 
| 912 |     if (mapView) | 
| 913 |         return addMapItemView_real(itemView: mapView); | 
| 914 |  | 
| 915 |     QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast<QDeclarativeGeoMapItemGroup *>(object: child); | 
| 916 |     if (itemGroup) // addMapItemView calls addMapItemGroup | 
| 917 |         return addMapItemGroup_real(itemGroup); | 
| 918 |  | 
| 919 |     QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(object: child); | 
| 920 |     if (mapItem) | 
| 921 |         return addMapItem_real(item: mapItem); | 
| 922 |  | 
| 923 |     QGeoMapObject *mapObject = qobject_cast<QGeoMapObject *>(object: child); | 
| 924 |     if (mapObject) | 
| 925 |         addMapObject(object: mapObject); // this emits mapObjectsChanged, != mapItemsChanged | 
| 926 |     return false; | 
| 927 | } | 
| 928 |  | 
| 929 | bool QDeclarativeGeoMap::removeMapChild(QObject *child) | 
| 930 | { | 
| 931 |     // dispatch items appropriately | 
| 932 |     QDeclarativeGeoMapItemView *mapView = qobject_cast<QDeclarativeGeoMapItemView *>(object: child); | 
| 933 |     if (mapView) | 
| 934 |         return removeMapItemView_real(itemView: mapView); | 
| 935 |  | 
| 936 |     QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast<QDeclarativeGeoMapItemGroup *>(object: child); | 
| 937 |     if (itemGroup) // removeMapItemView calls removeMapItemGroup for itself. | 
| 938 |         return removeMapItemGroup_real(itemGroup); | 
| 939 |  | 
| 940 |     QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(object: child); | 
| 941 |     if (mapItem) | 
| 942 |         return removeMapItem_real(item: mapItem); | 
| 943 |  | 
| 944 |     QGeoMapObject *mapObject = qobject_cast<QGeoMapObject *>(object: child); | 
| 945 |     if (mapObject) | 
| 946 |         removeMapObject(object: mapObject); // this emits mapObjectsChanged, != mapItemsChanged | 
| 947 |     return false; | 
| 948 | } | 
| 949 |  | 
| 950 | bool QDeclarativeGeoMap::isGroupNested(QDeclarativeGeoMapItemGroup *group) | 
| 951 | { | 
| 952 |     QObject *parent = group->parent(); | 
| 953 |     // Nested groups have parent set in parent's componentComplete() | 
| 954 |     // Those instantiated by MapItemView's delegateModel, however, do not, | 
| 955 |     // but have setParentItem set. | 
| 956 |     return qobject_cast<QDeclarativeGeoMapItemGroup *>(object: parent) | 
| 957 |             || qobject_cast<QDeclarativeGeoMapItemGroup *>(object: group->parentItem()); | 
| 958 | } | 
| 959 |  | 
| 960 | qreal QDeclarativeGeoMap::zoomLevel() const | 
| 961 | { | 
| 962 |     if (m_initialized) | 
| 963 |         return m_map->cameraData().zoomLevel(); | 
| 964 |     return m_cameraData.zoomLevel(); | 
| 965 | } | 
| 966 |  | 
| 967 | /*! | 
| 968 |     \qmlproperty real QtLocation::Map::bearing | 
| 969 |  | 
| 970 |     This property holds the bearing for the map. | 
| 971 |     The default value is 0. | 
| 972 |     If the Plugin used for the Map supports bearing, the valid range for this value is between 0 and 360. | 
| 973 |     If the Plugin used for the Map does not support bearing, changing this property will have no effect. | 
| 974 |  | 
| 975 |     \since QtLocation 5.9 | 
| 976 | */ | 
| 977 | void QDeclarativeGeoMap::setBearing(qreal bearing) | 
| 978 | { | 
| 979 |     bearing = sanitizeBearing(bearing); | 
| 980 |     if (m_initialized) { | 
| 981 |         QGeoCameraData cameraData = m_map->cameraData(); | 
| 982 |         cameraData.setBearing(bearing); | 
| 983 |         m_map->setCameraData(cameraData); | 
| 984 |     } else { | 
| 985 |         const bool bearingHasChanged = bearing != m_cameraData.bearing(); | 
| 986 |         m_cameraData.setBearing(bearing); | 
| 987 |         if (bearingHasChanged) { | 
| 988 |             emit bearingChanged(bearing); | 
| 989 |             // do not emit visibleRegionChanged() here, because, if the map isn't initialized, | 
| 990 |             // the getter won't return anything updated | 
| 991 |         } | 
| 992 |     } | 
| 993 | } | 
| 994 |  | 
| 995 | /*! | 
| 996 |     \qmlmethod void QtLocation::Map::setBearing(real bearing, coordinate coordinate) | 
| 997 |  | 
| 998 |     Sets the bearing for the map to \a bearing, rotating it around \a coordinate. | 
| 999 |     If the Plugin used for the Map supports bearing, the valid range for \a bearing is between 0 and 360. | 
| 1000 |     If the Plugin used for the Map does not support bearing, or if the map is tilted and \a coordinate happens | 
| 1001 |     to be behind the camera, or if the map is not ready (see \l mapReady), calling this method will have no effect. | 
| 1002 |  | 
| 1003 |     The release of this API with Qt 5.10 is a Technology Preview. | 
| 1004 |  | 
| 1005 |     \since 5.10 | 
| 1006 | */ | 
| 1007 | void QDeclarativeGeoMap::setBearing(qreal bearing, const QGeoCoordinate &coordinate) | 
| 1008 | { | 
| 1009 |     if (!m_initialized) | 
| 1010 |         return; | 
| 1011 |  | 
| 1012 |     const QGeoCoordinate currentCenter = center(); | 
| 1013 |     const qreal currentBearing = QDeclarativeGeoMap::bearing(); | 
| 1014 |     bearing = sanitizeBearing(bearing); | 
| 1015 |  | 
| 1016 |     if (!coordinate.isValid() | 
| 1017 |             || !qIsFinite(d: bearing) | 
| 1018 |             || (coordinate == currentCenter && bearing == currentBearing)) | 
| 1019 |         return; | 
| 1020 |  | 
| 1021 |     if (m_map->capabilities() & QGeoMap::SupportsSetBearing) | 
| 1022 |         m_map->setBearing(bearing, coordinate); | 
| 1023 | } | 
| 1024 |  | 
| 1025 | qreal QDeclarativeGeoMap::bearing() const | 
| 1026 | { | 
| 1027 |     if (m_initialized) | 
| 1028 |         return m_map->cameraData().bearing(); | 
| 1029 |     return m_cameraData.bearing(); | 
| 1030 | } | 
| 1031 |  | 
| 1032 | /*! | 
| 1033 |     \qmlproperty real QtLocation::Map::tilt | 
| 1034 |  | 
| 1035 |     This property holds the tilt for the map, in degrees. | 
| 1036 |     The default value is 0. | 
| 1037 |     The valid range for this value is [ minimumTilt, maximumTilt ]. | 
| 1038 |     If the Plugin used for the Map does not support tilting, changing this property will have no effect. | 
| 1039 |  | 
| 1040 |     \sa minimumTilt, maximumTilt | 
| 1041 |  | 
| 1042 |     \since QtLocation 5.9 | 
| 1043 | */ | 
| 1044 | void QDeclarativeGeoMap::setTilt(qreal tilt) | 
| 1045 | { | 
| 1046 |     tilt = qBound(min: minimumTilt(), val: tilt, max: maximumTilt()); | 
| 1047 |  | 
| 1048 |     if (m_initialized) { | 
| 1049 |         QGeoCameraData cameraData = m_map->cameraData(); | 
| 1050 |         cameraData.setTilt(tilt); | 
| 1051 |         m_map->setCameraData(cameraData); | 
| 1052 |     } else { | 
| 1053 |         const bool tiltHasChanged = tilt != m_cameraData.tilt(); | 
| 1054 |         m_cameraData.setTilt(tilt); | 
| 1055 |         if (tiltHasChanged) { | 
| 1056 |             emit tiltChanged(tilt); | 
| 1057 |             // do not emit visibleRegionChanged() here, because, if the map isn't initialized, | 
| 1058 |             // the getter won't return anything updated | 
| 1059 |         } | 
| 1060 |     } | 
| 1061 | } | 
| 1062 |  | 
| 1063 | qreal QDeclarativeGeoMap::tilt() const | 
| 1064 | { | 
| 1065 |     if (m_initialized) | 
| 1066 |         return m_map->cameraData().tilt(); | 
| 1067 |     return m_cameraData.tilt(); | 
| 1068 | } | 
| 1069 |  | 
| 1070 | void QDeclarativeGeoMap::setMinimumTilt(qreal minimumTilt, bool userSet) | 
| 1071 | { | 
| 1072 |     if (minimumTilt >= 0) { | 
| 1073 |         if (userSet) | 
| 1074 |             m_userMinimumTilt = minimumTilt; | 
| 1075 |         qreal oldMinimumTilt = this->minimumTilt(); | 
| 1076 |  | 
| 1077 |         m_minimumTilt = qBound<double>(min: m_cameraCapabilities.minimumTilt(), | 
| 1078 |                                        val: minimumTilt, | 
| 1079 |                                        max: m_cameraCapabilities.maximumTilt()); | 
| 1080 |  | 
| 1081 |         if (tilt() < m_minimumTilt) | 
| 1082 |             setTilt(m_minimumTilt); | 
| 1083 |  | 
| 1084 |         if (oldMinimumTilt != m_minimumTilt) | 
| 1085 |             emit minimumTiltChanged(minimumTilt: m_minimumTilt); | 
| 1086 |     } | 
| 1087 | } | 
| 1088 |  | 
| 1089 | /*! | 
| 1090 |     \qmlproperty real QtLocation::Map::fieldOfView | 
| 1091 |  | 
| 1092 |     This property holds the field of view of the camera used to look at the map, in degrees. | 
| 1093 |     If the plugin property of the map is not set, or the plugin does not support mapping, the value is 45 degrees. | 
| 1094 |  | 
| 1095 |     Note that changing this value implicitly changes also the distance between the camera and the map, | 
| 1096 |     so that, at a tilting angle of 0 degrees, the resulting image is identical for any value used for this property. | 
| 1097 |  | 
| 1098 |     For more information about this parameter, consult the Wikipedia articles about \l {https://en.wikipedia.org/wiki/Field_of_view} {Field of view} and | 
| 1099 |     \l {https://en.wikipedia.org/wiki/Angle_of_view} {Angle of view}. | 
| 1100 |  | 
| 1101 |     \sa minimumFieldOfView, maximumFieldOfView | 
| 1102 |  | 
| 1103 |     \since QtLocation 5.9 | 
| 1104 | */ | 
| 1105 | void QDeclarativeGeoMap::setFieldOfView(qreal fieldOfView) | 
| 1106 | { | 
| 1107 |     fieldOfView = qBound(min: minimumFieldOfView(), val: fieldOfView, max: maximumFieldOfView()); | 
| 1108 |  | 
| 1109 |     if (m_initialized) { | 
| 1110 |         QGeoCameraData cameraData = m_map->cameraData(); | 
| 1111 |         cameraData.setFieldOfView(fieldOfView); | 
| 1112 |         m_map->setCameraData(cameraData); | 
| 1113 |     } else { | 
| 1114 |         const bool fovChanged = fieldOfView != m_cameraData.fieldOfView(); | 
| 1115 |         m_cameraData.setFieldOfView(fieldOfView); | 
| 1116 |         if (fovChanged) { | 
| 1117 |             emit fieldOfViewChanged(fieldOfView); | 
| 1118 |             // do not emit visibleRegionChanged() here, because, if the map isn't initialized, | 
| 1119 |             // the getter won't return anything updated | 
| 1120 |         } | 
| 1121 |     } | 
| 1122 | } | 
| 1123 |  | 
| 1124 | qreal QDeclarativeGeoMap::fieldOfView() const | 
| 1125 | { | 
| 1126 |     if (m_initialized) | 
| 1127 |         return m_map->cameraData().fieldOfView(); | 
| 1128 |     return m_cameraData.fieldOfView(); | 
| 1129 | } | 
| 1130 |  | 
| 1131 | void QDeclarativeGeoMap::setMinimumFieldOfView(qreal minimumFieldOfView, bool userSet) | 
| 1132 | { | 
| 1133 |     if (minimumFieldOfView > 0 && minimumFieldOfView < 180.0) { | 
| 1134 |         if (userSet) | 
| 1135 |             m_userMinimumFieldOfView = minimumFieldOfView; | 
| 1136 |         qreal oldMinimumFoV = this->minimumFieldOfView(); | 
| 1137 |  | 
| 1138 |         m_minimumFieldOfView = qBound<double>(min: m_cameraCapabilities.minimumFieldOfView(), | 
| 1139 |                                               val: minimumFieldOfView, | 
| 1140 |                                               max: m_cameraCapabilities.maximumFieldOfView()); | 
| 1141 |  | 
| 1142 |         if (fieldOfView() < m_minimumFieldOfView) | 
| 1143 |             setFieldOfView(m_minimumFieldOfView); | 
| 1144 |  | 
| 1145 |         if (oldMinimumFoV != m_minimumFieldOfView) | 
| 1146 |             emit minimumFieldOfViewChanged(minimumFieldOfView: m_minimumFieldOfView); | 
| 1147 |     } | 
| 1148 | } | 
| 1149 |  | 
| 1150 | /*! | 
| 1151 |     \qmlproperty real QtLocation::Map::minimumFieldOfView | 
| 1152 |  | 
| 1153 |     This property holds the minimum valid field of view for the map, in degrees. | 
| 1154 |  | 
| 1155 |     The minimum tilt field of view by the \l plugin used is a lower bound for | 
| 1156 |     this property. | 
| 1157 |     If the \l plugin property is not set or the plugin does not support mapping, this property is \c 1. | 
| 1158 |  | 
| 1159 |     \sa fieldOfView, maximumFieldOfView | 
| 1160 |  | 
| 1161 |     \since QtLocation 5.9 | 
| 1162 | */ | 
| 1163 | qreal QDeclarativeGeoMap::minimumFieldOfView() const | 
| 1164 | { | 
| 1165 |     return m_minimumFieldOfView; | 
| 1166 | } | 
| 1167 |  | 
| 1168 | void QDeclarativeGeoMap::setMaximumFieldOfView(qreal maximumFieldOfView, bool userSet) | 
| 1169 | { | 
| 1170 |     if (maximumFieldOfView > 0 && maximumFieldOfView < 180.0) { | 
| 1171 |         if (userSet) | 
| 1172 |             m_userMaximumFieldOfView = maximumFieldOfView; | 
| 1173 |         qreal oldMaximumFoV = this->maximumFieldOfView(); | 
| 1174 |  | 
| 1175 |         m_maximumFieldOfView = qBound<double>(min: m_cameraCapabilities.minimumFieldOfView(), | 
| 1176 |                                               val: maximumFieldOfView, | 
| 1177 |                                               max: m_cameraCapabilities.maximumFieldOfView()); | 
| 1178 |  | 
| 1179 |         if (fieldOfView() > m_maximumFieldOfView) | 
| 1180 |             setFieldOfView(m_maximumFieldOfView); | 
| 1181 |  | 
| 1182 |         if (oldMaximumFoV != m_maximumFieldOfView) | 
| 1183 |             emit maximumFieldOfViewChanged(maximumFieldOfView: m_maximumFieldOfView); | 
| 1184 |     } | 
| 1185 | } | 
| 1186 |  | 
| 1187 | /*! | 
| 1188 |     \qmlproperty real QtLocation::Map::maximumFieldOfView | 
| 1189 |  | 
| 1190 |     This property holds the maximum valid field of view for the map, in degrees. | 
| 1191 |  | 
| 1192 |     The minimum tilt field of view by the \l plugin used is an upper bound for | 
| 1193 |     this property. | 
| 1194 |     If the \l plugin property is not set or the plugin does not support mapping, this property is \c 179. | 
| 1195 |  | 
| 1196 |     \sa fieldOfView, minimumFieldOfView | 
| 1197 |  | 
| 1198 |     \since QtLocation 5.9 | 
| 1199 | */ | 
| 1200 | qreal QDeclarativeGeoMap::maximumFieldOfView() const | 
| 1201 | { | 
| 1202 |     return m_maximumFieldOfView; | 
| 1203 | } | 
| 1204 |  | 
| 1205 | /*! | 
| 1206 |     \qmlproperty real QtLocation::Map::minimumTilt | 
| 1207 |  | 
| 1208 |     This property holds the minimum valid tilt for the map, in degrees. | 
| 1209 |  | 
| 1210 |     The minimum tilt defined by the \l plugin used is a lower bound for | 
| 1211 |     this property. | 
| 1212 |     If the \l plugin property is not set or the plugin does not support mapping, this property is \c 0. | 
| 1213 |  | 
| 1214 |     Since QtLocation 5.12, plugins can additionally restrict this value depending on the current zoom level. | 
| 1215 |  | 
| 1216 |     \sa tilt, maximumTilt | 
| 1217 |  | 
| 1218 |     \since QtLocation 5.9 | 
| 1219 | */ | 
| 1220 | qreal QDeclarativeGeoMap::minimumTilt() const | 
| 1221 | { | 
| 1222 |     return m_minimumTilt; | 
| 1223 | } | 
| 1224 |  | 
| 1225 | void QDeclarativeGeoMap::setMaximumTilt(qreal maximumTilt, bool userSet) | 
| 1226 | { | 
| 1227 |     if (maximumTilt >= 0) { | 
| 1228 |         if (userSet) | 
| 1229 |             m_userMaximumTilt = maximumTilt; | 
| 1230 |         qreal oldMaximumTilt = this->maximumTilt(); | 
| 1231 |  | 
| 1232 |         m_maximumTilt = qBound<double>(min: m_cameraCapabilities.minimumTilt(), | 
| 1233 |                                        val: maximumTilt, | 
| 1234 |                                        max: m_cameraCapabilities.maximumTilt()); | 
| 1235 |  | 
| 1236 |         if (tilt() > m_maximumTilt) | 
| 1237 |             setTilt(m_maximumTilt); | 
| 1238 |  | 
| 1239 |         if (oldMaximumTilt != m_maximumTilt) | 
| 1240 |             emit maximumTiltChanged(maximumTilt: m_maximumTilt); | 
| 1241 |     } | 
| 1242 | } | 
| 1243 |  | 
| 1244 | /*! | 
| 1245 |     \qmlproperty real QtLocation::Map::maximumTilt | 
| 1246 |  | 
| 1247 |     This property holds the maximum valid tilt for the map, in degrees. | 
| 1248 |  | 
| 1249 |     The maximum tilt defined by the \l plugin used is an upper bound for | 
| 1250 |     this property. | 
| 1251 |     If the \l plugin property is not set or the plugin does not support mapping, this property is \c 89.5. | 
| 1252 |  | 
| 1253 |     Since QtLocation 5.12, plugins can additionally restrict this value depending on the current zoom level. | 
| 1254 |  | 
| 1255 |     \sa tilt, minimumTilt | 
| 1256 |  | 
| 1257 |     \since QtLocation 5.9 | 
| 1258 | */ | 
| 1259 | qreal QDeclarativeGeoMap::maximumTilt() const | 
| 1260 | { | 
| 1261 |     return m_maximumTilt; | 
| 1262 | } | 
| 1263 |  | 
| 1264 | /*! | 
| 1265 |     \qmlproperty coordinate QtLocation::Map::center | 
| 1266 |  | 
| 1267 |     This property holds the coordinate which occupies the center of the | 
| 1268 |     mapping viewport. Invalid center coordinates are ignored. | 
| 1269 |  | 
| 1270 |     The default value is an arbitrary valid coordinate. | 
| 1271 | */ | 
| 1272 | void QDeclarativeGeoMap::setCenter(const QGeoCoordinate ¢er) | 
| 1273 | { | 
| 1274 |     if (!center.isValid()) | 
| 1275 |         return; | 
| 1276 |  | 
| 1277 |     if (m_initialized) { | 
| 1278 |         QGeoCoordinate coord(center); | 
| 1279 |         coord.setLatitude(qBound(min: m_minimumViewportLatitude, val: center.latitude(), max: m_maximumViewportLatitude)); | 
| 1280 |         QGeoCameraData cameraData = m_map->cameraData(); | 
| 1281 |         cameraData.setCenter(coord); | 
| 1282 |         m_map->setCameraData(cameraData); | 
| 1283 |     } else { | 
| 1284 |         const bool centerHasChanged = center != m_cameraData.center(); | 
| 1285 |         m_cameraData.setCenter(center); | 
| 1286 |         if (centerHasChanged) { | 
| 1287 |             emit centerChanged(coordinate: center); | 
| 1288 |             // do not emit visibleRegionChanged() here, because, if the map isn't initialized, | 
| 1289 |             // the getter won't return anything updated | 
| 1290 |         } | 
| 1291 |     } | 
| 1292 | } | 
| 1293 |  | 
| 1294 | QGeoCoordinate QDeclarativeGeoMap::center() const | 
| 1295 | { | 
| 1296 |     if (m_initialized) | 
| 1297 |         return m_map->cameraData().center(); | 
| 1298 |     return m_cameraData.center(); | 
| 1299 | } | 
| 1300 |  | 
| 1301 |  | 
| 1302 | /*! | 
| 1303 |     \qmlproperty geoshape QtLocation::Map::visibleRegion | 
| 1304 |  | 
| 1305 |     This property holds the region which occupies the viewport of | 
| 1306 |     the map. The camera is positioned in the center of the shape, and | 
| 1307 |     at the largest integral zoom level possible which allows the | 
| 1308 |     whole shape to be visible on the screen. This implies that | 
| 1309 |     reading this property back shortly after having been set the | 
| 1310 |     returned area is equal or larger than the set area. | 
| 1311 |  | 
| 1312 |     Setting this property implicitly changes the \l center and | 
| 1313 |     \l zoomLevel of the map. Any previously set value to those | 
| 1314 |     properties will be overridden. | 
| 1315 |  | 
| 1316 |     \note Since Qt 5.14 This property provides change notifications. | 
| 1317 |  | 
| 1318 |     \since 5.6 | 
| 1319 | */ | 
| 1320 | void QDeclarativeGeoMap::setVisibleRegion(const QGeoShape &shape) | 
| 1321 | { | 
| 1322 |     if (shape.boundingGeoRectangle() == visibleRegion()) | 
| 1323 |         return; | 
| 1324 |  | 
| 1325 |     m_visibleRegion = shape.boundingGeoRectangle(); | 
| 1326 |     if (!m_visibleRegion.isValid() | 
| 1327 |         || (m_visibleRegion.bottomRight().latitude() >= 85.0) // rect entirely outside web mercator | 
| 1328 |         || (m_visibleRegion.topLeft().latitude() <= -85.0)) { | 
| 1329 |         // shape invalidated -> nothing to fit anymore | 
| 1330 |         m_visibleRegion = QGeoRectangle(); | 
| 1331 |         m_pendingFitViewport = false; | 
| 1332 |         emit visibleRegionChanged(); | 
| 1333 |         return; | 
| 1334 |     } | 
| 1335 |  | 
| 1336 |     if (!m_map || !width() || !height()) { | 
| 1337 |         m_pendingFitViewport = true; | 
| 1338 |         emit visibleRegionChanged(); | 
| 1339 |         return; | 
| 1340 |     } | 
| 1341 |  | 
| 1342 |     fitViewportToGeoShape(shape: m_visibleRegion); | 
| 1343 |     emit visibleRegionChanged(); | 
| 1344 | } | 
| 1345 |  | 
| 1346 | QGeoShape QDeclarativeGeoMap::visibleRegion() const | 
| 1347 | { | 
| 1348 |     if (!m_map || !width() || !height()) | 
| 1349 |         return m_visibleRegion; | 
| 1350 |  | 
| 1351 |     if (m_map->capabilities() & QGeoMap::SupportsVisibleRegion) { | 
| 1352 |         return m_map->visibleRegion(); | 
| 1353 |     } else { | 
| 1354 |         // ToDo: handle projections not supporting visible region in a better way. | 
| 1355 |         // This approach will fail when horizon is in the view or the map is greatly zoomed out. | 
| 1356 |         QList<QGeoCoordinate> visiblePoly; | 
| 1357 |         visiblePoly << m_map->geoProjection().itemPositionToCoordinate(pos: QDoubleVector2D(0,0), clipToViewport: false); | 
| 1358 |         visiblePoly << m_map->geoProjection().itemPositionToCoordinate(pos: QDoubleVector2D(m_map->viewportWidth() - 1, | 
| 1359 |                                                                                        0), clipToViewport: false); | 
| 1360 |         visiblePoly << m_map->geoProjection().itemPositionToCoordinate(pos: QDoubleVector2D(m_map->viewportWidth() - 1, | 
| 1361 |                                                                                        m_map->viewportHeight() - 1), clipToViewport: false); | 
| 1362 |         visiblePoly << m_map->geoProjection().itemPositionToCoordinate(pos: QDoubleVector2D(0, | 
| 1363 |                                                                                        m_map->viewportHeight() - 1), clipToViewport: false); | 
| 1364 |         QGeoPath path; | 
| 1365 |         path.setPath(visiblePoly); | 
| 1366 |         return path.boundingGeoRectangle(); | 
| 1367 |     } | 
| 1368 | } | 
| 1369 |  | 
| 1370 | /*! | 
| 1371 |     \qmlproperty bool QtLocation::Map::copyrightsVisible | 
| 1372 |  | 
| 1373 |     This property holds the visibility of the copyrights notice. The notice is usually | 
| 1374 |     displayed in the bottom left corner. By default, this property is set to \c true. | 
| 1375 |  | 
| 1376 |     \note Many map providers require the notice to be visible as part of the terms and conditions. | 
| 1377 |     Please consult the relevant provider documentation before turning this notice off. | 
| 1378 |  | 
| 1379 |     \since 5.7 | 
| 1380 | */ | 
| 1381 | void QDeclarativeGeoMap::setCopyrightsVisible(bool visible) | 
| 1382 | { | 
| 1383 |     if (m_copyrightsVisible == visible) | 
| 1384 |         return; | 
| 1385 |  | 
| 1386 |     if (!m_copyrights.isNull()) | 
| 1387 |         m_copyrights->setCopyrightsVisible(visible); | 
| 1388 |  | 
| 1389 |     m_copyrightsVisible = visible; | 
| 1390 |     emit copyrightsVisibleChanged(visible); | 
| 1391 | } | 
| 1392 |  | 
| 1393 | bool QDeclarativeGeoMap::copyrightsVisible() const | 
| 1394 | { | 
| 1395 |     return m_copyrightsVisible; | 
| 1396 | } | 
| 1397 |  | 
| 1398 |  | 
| 1399 |  | 
| 1400 | /*! | 
| 1401 |     \qmlproperty color QtLocation::Map::color | 
| 1402 |  | 
| 1403 |     This property holds the background color of the map element. | 
| 1404 |  | 
| 1405 |     \since 5.6 | 
| 1406 | */ | 
| 1407 | void QDeclarativeGeoMap::setColor(const QColor &color) | 
| 1408 | { | 
| 1409 |     if (color != m_color) { | 
| 1410 |         m_color = color; | 
| 1411 |         update(); | 
| 1412 |         emit colorChanged(color: m_color); | 
| 1413 |     } | 
| 1414 | } | 
| 1415 |  | 
| 1416 | QColor QDeclarativeGeoMap::color() const | 
| 1417 | { | 
| 1418 |     return m_color; | 
| 1419 | } | 
| 1420 |  | 
| 1421 | /*! | 
| 1422 |     \qmlproperty rect QtLocation::Map::visibleArea | 
| 1423 |  | 
| 1424 |     This property holds the visible area inside the Map QML element. | 
| 1425 |     It is a rect whose coordinates are relative to the Map element. | 
| 1426 |     Its size will be clamped to the size of the Map element. | 
| 1427 |     A null visibleArea means that the whole Map is visible. | 
| 1428 |  | 
| 1429 |     \since 5.12 | 
| 1430 | */ | 
| 1431 | QRectF QDeclarativeGeoMap::visibleArea() const | 
| 1432 | { | 
| 1433 |     if (m_initialized) | 
| 1434 |         return m_map->visibleArea(); | 
| 1435 |     return m_visibleArea; | 
| 1436 | } | 
| 1437 |  | 
| 1438 | void QDeclarativeGeoMap::setVisibleArea(const QRectF &visibleArea) | 
| 1439 | { | 
| 1440 |     const QRectF oldVisibleArea = QDeclarativeGeoMap::visibleArea(); | 
| 1441 |     if (visibleArea == oldVisibleArea) | 
| 1442 |         return; | 
| 1443 |  | 
| 1444 |     if (!visibleArea.isValid() && !visibleArea.isEmpty()) // values < 0 | 
| 1445 |         return; | 
| 1446 |  | 
| 1447 |     if (m_initialized) { | 
| 1448 |         m_map->setVisibleArea(visibleArea); | 
| 1449 |         const QRectF newVisibleArea = QDeclarativeGeoMap::visibleArea(); | 
| 1450 |         if (newVisibleArea != oldVisibleArea) { | 
| 1451 |             // polish map items | 
| 1452 |             for (const QPointer<QDeclarativeGeoMapItemBase> &i: qAsConst(t&: m_mapItems)) { | 
| 1453 |                 if (i) | 
| 1454 |                     i->visibleAreaChanged(); | 
| 1455 |             } | 
| 1456 |         } | 
| 1457 |     } else { | 
| 1458 |         m_visibleArea = visibleArea; | 
| 1459 |         const QRectF newVisibleArea = QDeclarativeGeoMap::visibleArea(); | 
| 1460 |         if (newVisibleArea != oldVisibleArea) | 
| 1461 |             emit visibleAreaChanged(); | 
| 1462 |     } | 
| 1463 | } | 
| 1464 |  | 
| 1465 | /*! | 
| 1466 |     \qmlproperty bool QtLocation::Map::mapReady | 
| 1467 |  | 
| 1468 |     This property holds whether the map has been successfully initialized and is ready to be used. | 
| 1469 |     Some methods, such as \l fromCoordinate and \l toCoordinate, will not work before the map is ready. | 
| 1470 |     Due to the architecture of the \l Map, it's advised to use the signal emitted for this property | 
| 1471 |     in place of \l {QtQml::Component::completed()}{Component.onCompleted}, to make sure that everything behaves as expected. | 
| 1472 |  | 
| 1473 |     \since 5.9 | 
| 1474 | */ | 
| 1475 | bool QDeclarativeGeoMap::mapReady() const | 
| 1476 | { | 
| 1477 |     return m_initialized; | 
| 1478 | } | 
| 1479 |  | 
| 1480 | QMargins QDeclarativeGeoMap::mapMargins() const | 
| 1481 | { | 
| 1482 |     const QRectF va = m_map->visibleArea(); | 
| 1483 |     if (va.isEmpty()) | 
| 1484 |         return QMargins(); | 
| 1485 |     return QMargins( va.x() | 
| 1486 |                     , va.y() | 
| 1487 |                     , width() - va.width() - va.x() | 
| 1488 |                     , height() - va.height() - va.y()); | 
| 1489 | } | 
| 1490 |  | 
| 1491 | /*! | 
| 1492 |     \qmlproperty list<MapType> QtLocation::Map::supportedMapTypes | 
| 1493 |  | 
| 1494 |     This read-only property holds the set of \l{MapType}{map types} supported by this map. | 
| 1495 |  | 
| 1496 |     \sa activeMapType | 
| 1497 | */ | 
| 1498 | QQmlListProperty<QDeclarativeGeoMapType> QDeclarativeGeoMap::supportedMapTypes() | 
| 1499 | { | 
| 1500 |     return QQmlListProperty<QDeclarativeGeoMapType>(this, &m_supportedMapTypes); | 
| 1501 | } | 
| 1502 |  | 
| 1503 | /*! | 
| 1504 |     \qmlmethod void QtLocation::Map::alignCoordinateToPoint(coordinate coordinate, QPointF point) | 
| 1505 |  | 
| 1506 |     Aligns \a coordinate to \a point. | 
| 1507 |     This method effectively extends the functionality offered by the \l center qml property, allowing | 
| 1508 |     to align a coordinate to point of the Map element other than its center. | 
| 1509 |     This is useful in those applications where the center of the scene (e.g., a cursor) is not to be | 
| 1510 |     placed exactly in the center of the map. | 
| 1511 |  | 
| 1512 |     If the map is tilted, and \a coordinate happens to be behind the camera, or if the map is not ready | 
| 1513 |     (see \l mapReady), calling this method will have no effect. | 
| 1514 |  | 
| 1515 |     The release of this API with Qt 5.10 is a Technology Preview. | 
| 1516 |  | 
| 1517 |     \sa center | 
| 1518 |  | 
| 1519 |     \since 5.10 | 
| 1520 | */ | 
| 1521 | void QDeclarativeGeoMap::alignCoordinateToPoint(const QGeoCoordinate &coordinate, const QPointF &point) | 
| 1522 | { | 
| 1523 |     if (!m_map || !(m_map->capabilities() & QGeoMap::SupportsAnchoringCoordinate)) | 
| 1524 |         return; | 
| 1525 |  | 
| 1526 |     if (!coordinate.isValid() | 
| 1527 |             || !qIsFinite(d: point.x()) | 
| 1528 |             || !qIsFinite(d: point.y())) | 
| 1529 |         return; | 
| 1530 |  | 
| 1531 |     m_map->anchorCoordinateToPoint(coordinate, anchorPoint: point); | 
| 1532 | } | 
| 1533 |  | 
| 1534 | /*! | 
| 1535 |     \qmlmethod coordinate QtLocation::Map::toCoordinate(QPointF position, bool clipToViewPort) | 
| 1536 |  | 
| 1537 |     Returns the coordinate which corresponds to the \a position relative to the map item. | 
| 1538 |  | 
| 1539 |     If \a clipToViewPort is \c true, or not supplied then returns an invalid coordinate if | 
| 1540 |     \a position is not within the current viewport. | 
| 1541 | */ | 
| 1542 | QGeoCoordinate QDeclarativeGeoMap::toCoordinate(const QPointF &position, bool clipToViewPort) const | 
| 1543 | { | 
| 1544 |     if (m_map) | 
| 1545 |         return m_map->geoProjection().itemPositionToCoordinate(pos: QDoubleVector2D(position), clipToViewport: clipToViewPort); | 
| 1546 |     else | 
| 1547 |         return QGeoCoordinate(); | 
| 1548 | } | 
| 1549 |  | 
| 1550 | /*! | 
| 1551 |     \qmlmethod point QtLocation::Map::fromCoordinate(coordinate coordinate, bool clipToViewPort) | 
| 1552 |  | 
| 1553 |     Returns the position relative to the map item which corresponds to the \a coordinate. | 
| 1554 |  | 
| 1555 |     If \a clipToViewPort is \c true, or not supplied then returns an invalid QPointF if | 
| 1556 |     \a coordinate is not within the current viewport. | 
| 1557 | */ | 
| 1558 | QPointF QDeclarativeGeoMap::fromCoordinate(const QGeoCoordinate &coordinate, bool clipToViewPort) const | 
| 1559 | { | 
| 1560 |     if (m_map) | 
| 1561 |         return m_map->geoProjection().coordinateToItemPosition(coordinate, clipToViewport: clipToViewPort).toPointF(); | 
| 1562 |     else | 
| 1563 |         return QPointF(qQNaN(), qQNaN()); | 
| 1564 | } | 
| 1565 |  | 
| 1566 | /*! | 
| 1567 |     \qmlmethod void QtLocation::Map::pan(int dx, int dy) | 
| 1568 |  | 
| 1569 |     Starts panning the map by \a dx pixels along the x-axis and | 
| 1570 |     by \a dy pixels along the y-axis. | 
| 1571 |  | 
| 1572 |     Positive values for \a dx move the map right, negative values left. | 
| 1573 |     Positive values for \a dy move the map down, negative values up. | 
| 1574 |  | 
| 1575 |     During panning the \l center, and \l zoomLevel may change. | 
| 1576 | */ | 
| 1577 | void QDeclarativeGeoMap::pan(int dx, int dy) | 
| 1578 | { | 
| 1579 |     if (!m_map) | 
| 1580 |         return; | 
| 1581 |     if (dx == 0 && dy == 0) | 
| 1582 |         return; | 
| 1583 |  | 
| 1584 |     QGeoCoordinate coord = m_map->geoProjection().itemPositionToCoordinate( | 
| 1585 |                                 pos: QDoubleVector2D(m_map->viewportWidth() / 2 + dx, | 
| 1586 |                                         m_map->viewportHeight() / 2 + dy)); | 
| 1587 |     setCenter(coord); | 
| 1588 | } | 
| 1589 |  | 
| 1590 |  | 
| 1591 | /*! | 
| 1592 |     \qmlmethod void QtLocation::Map::prefetchData() | 
| 1593 |  | 
| 1594 |     Optional hint that allows the map to prefetch during this idle period | 
| 1595 | */ | 
| 1596 | void QDeclarativeGeoMap::prefetchData() | 
| 1597 | { | 
| 1598 |     if (!m_map) | 
| 1599 |         return; | 
| 1600 |     m_map->prefetchData(); | 
| 1601 | } | 
| 1602 |  | 
| 1603 | /*! | 
| 1604 |     \qmlmethod void QtLocation::Map::clearData() | 
| 1605 |  | 
| 1606 |     Clears map data collected by the currently selected plugin. | 
| 1607 |     \note This method will delete cached files. | 
| 1608 |     \sa plugin | 
| 1609 | */ | 
| 1610 | void QDeclarativeGeoMap::clearData() | 
| 1611 | { | 
| 1612 |     if (m_map) | 
| 1613 |         m_map->clearData(); | 
| 1614 | } | 
| 1615 |  | 
| 1616 | /*! | 
| 1617 |     \qmlmethod void QtLocation::Map::fitViewportToGeoShape(geoShape, margins) | 
| 1618 |  | 
| 1619 |     Fits the viewport to a specific geo shape \a geoShape. | 
| 1620 |     The \a margins are in screen pixels. | 
| 1621 |  | 
| 1622 |     \note If the projection used by the plugin is not WebMercator, and the plugin does not have fitting to | 
| 1623 |     shape capability, this method will do nothing. | 
| 1624 |  | 
| 1625 |     \sa visibleRegion | 
| 1626 |     \since 5.13 | 
| 1627 | */ | 
| 1628 | void QDeclarativeGeoMap::fitViewportToGeoShape(const QGeoShape &shape, QVariant margins) | 
| 1629 | { | 
| 1630 |     QMargins m(10, 10, 10, 10); // lets defaults to 10 if margins is invalid | 
| 1631 |     switch (static_cast<QMetaType::Type>(margins.type())) { | 
| 1632 |         case QMetaType::Int: | 
| 1633 |         case QMetaType::Double: { | 
| 1634 |             const int value = int(margins.toDouble()); | 
| 1635 |             m = QMargins(value, value, value, value); | 
| 1636 |         } | 
| 1637 |         break; | 
| 1638 |         // ToDo: Support distinct margins in some QML form. Perhaps QRect? | 
| 1639 |         default: | 
| 1640 |             break; | 
| 1641 |     } | 
| 1642 |     fitViewportToGeoShape(shape, borders: m); | 
| 1643 | } | 
| 1644 |  | 
| 1645 | void QDeclarativeGeoMap::fitViewportToGeoShape(const QGeoShape &shape, const QMargins &borders) | 
| 1646 | { | 
| 1647 |     if (!m_map  || !shape.isValid()) | 
| 1648 |         return; | 
| 1649 |  | 
| 1650 |     if (m_map->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) { | 
| 1651 |         // This case remains handled here, and not inside QGeoMap*::fitViewportToGeoRectangle, | 
| 1652 |         // in order to honor animations on center and zoomLevel | 
| 1653 |         const QMargins margins = borders + mapMargins(); | 
| 1654 |         const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection()); | 
| 1655 |         const QPair<QGeoCoordinate, qreal> fitData = p.fitViewportToGeoRectangle(rectangle: shape.boundingGeoRectangle(), | 
| 1656 |                                                                                  margins); | 
| 1657 |         if (!fitData.first.isValid()) | 
| 1658 |             return; | 
| 1659 |  | 
| 1660 |         // position camera to the center of bounding box | 
| 1661 |         setProperty(name: "center" , value: QVariant::fromValue(value: fitData.first)); // not using setCenter(centerCoordinate) to honor a possible animation set on the center property | 
| 1662 |  | 
| 1663 |         if (!qIsFinite(d: fitData.second)) | 
| 1664 |             return; | 
| 1665 |         double newZoom = qMax<double>(a: minimumZoomLevel(), b: fitData.second); | 
| 1666 |         setProperty(name: "zoomLevel" , value: QVariant::fromValue(value: newZoom)); // not using setZoomLevel(newZoom)  to honor a possible animation set on the zoomLevel property | 
| 1667 |     } else if (m_map->capabilities() & QGeoMap::SupportsFittingViewportToGeoRectangle) { | 
| 1668 |         // Animations cannot be honored in this case, as m_map acts as a black box | 
| 1669 |         m_map->fitViewportToGeoRectangle(rectangle: m_visibleRegion, borders); | 
| 1670 |     } | 
| 1671 |     // else out of luck | 
| 1672 | } | 
| 1673 |  | 
| 1674 | /*! | 
| 1675 |     \qmlproperty string QtLocation::Map::errorString | 
| 1676 |  | 
| 1677 |     This read-only property holds the textual presentation of the latest mapping provider error. | 
| 1678 |     If no error has occurred, an empty string is returned. | 
| 1679 |  | 
| 1680 |     An empty string may also be returned if an error occurred which has no associated | 
| 1681 |     textual representation. | 
| 1682 |  | 
| 1683 |     \sa QGeoServiceProvider::errorString() | 
| 1684 | */ | 
| 1685 |  | 
| 1686 | QString QDeclarativeGeoMap::errorString() const | 
| 1687 | { | 
| 1688 |     return m_errorString; | 
| 1689 | } | 
| 1690 |  | 
| 1691 | /*! | 
| 1692 |     \qmlproperty enumeration QtLocation::Map::error | 
| 1693 |  | 
| 1694 |     This read-only property holds the last occurred mapping service provider error. | 
| 1695 |  | 
| 1696 |     \list | 
| 1697 |     \li Map.NoError - No error has occurred. | 
| 1698 |     \li Map.NotSupportedError -The maps plugin property was not set or there is no mapping manager associated with the plugin. | 
| 1699 |     \li Map.UnknownParameterError -The plugin did not recognize one of the parameters it was given. | 
| 1700 |     \li Map.MissingRequiredParameterError - The plugin did not find one of the parameters it was expecting. | 
| 1701 |     \li Map.ConnectionError - The plugin could not connect to its backend service or database. | 
| 1702 |     \endlist | 
| 1703 |  | 
| 1704 |     \sa QGeoServiceProvider::Error | 
| 1705 | */ | 
| 1706 |  | 
| 1707 | QGeoServiceProvider::Error QDeclarativeGeoMap::error() const | 
| 1708 | { | 
| 1709 |     return m_error; | 
| 1710 | } | 
| 1711 |  | 
| 1712 | QGeoMap *QDeclarativeGeoMap::map() const | 
| 1713 | { | 
| 1714 |     return m_map; | 
| 1715 | } | 
| 1716 |  | 
| 1717 | void QDeclarativeGeoMap::itemChange(ItemChange change, const ItemChangeData &value) | 
| 1718 | { | 
| 1719 |     if (change == ItemChildAddedChange) { | 
| 1720 |         QQuickItem *child = value.item; | 
| 1721 |         QQuickItem *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(object: child); | 
| 1722 |         if (!mapItem) | 
| 1723 |             mapItem = qobject_cast<QDeclarativeGeoMapItemGroup *>(object: child); | 
| 1724 |  | 
| 1725 |         if (mapItem) { | 
| 1726 |             qreal z = mapItem->z(); | 
| 1727 |             if (z > m_maxChildZ) { // Ignore children removal | 
| 1728 |                 m_maxChildZ = z; | 
| 1729 |                 // put the copyrights notice object at the highest z order | 
| 1730 |                 if (m_copyrights) | 
| 1731 |                     m_copyrights->setCopyrightsZ(m_maxChildZ + 1); | 
| 1732 |             } | 
| 1733 |         } | 
| 1734 |     } | 
| 1735 |     QQuickItem::itemChange(change, value); | 
| 1736 | } | 
| 1737 |  | 
| 1738 | bool QDeclarativeGeoMap::isInteractive() | 
| 1739 | { | 
| 1740 |     return (m_gestureArea->enabled() && m_gestureArea->acceptedGestures()) || m_gestureArea->isActive(); | 
| 1741 | } | 
| 1742 |  | 
| 1743 | void QDeclarativeGeoMap::attachCopyrightNotice(bool initialVisibility) | 
| 1744 | { | 
| 1745 |     if (initialVisibility) { | 
| 1746 |         ++m_copyNoticesVisible; | 
| 1747 |         if (m_map) | 
| 1748 |             m_map->setCopyrightVisible(m_copyNoticesVisible > 0); | 
| 1749 |     } | 
| 1750 | } | 
| 1751 |  | 
| 1752 | void QDeclarativeGeoMap::detachCopyrightNotice(bool currentVisibility) | 
| 1753 | { | 
| 1754 |     if (currentVisibility) { | 
| 1755 |         --m_copyNoticesVisible; | 
| 1756 |         if (m_map) | 
| 1757 |             m_map->setCopyrightVisible(m_copyNoticesVisible > 0); | 
| 1758 |     } | 
| 1759 | } | 
| 1760 |  | 
| 1761 | void QDeclarativeGeoMap::onAttachedCopyrightNoticeVisibilityChanged() | 
| 1762 | { | 
| 1763 |     QDeclarativeGeoMapCopyrightNotice *copy = static_cast<QDeclarativeGeoMapCopyrightNotice *>(sender()); | 
| 1764 |     m_copyNoticesVisible += ( int(copy->copyrightsVisible()) * 2 - 1); | 
| 1765 |     if (m_map) | 
| 1766 |         m_map->setCopyrightVisible(m_copyNoticesVisible > 0); | 
| 1767 | } | 
| 1768 |  | 
| 1769 | void QDeclarativeGeoMap::onCameraDataChanged(const QGeoCameraData &cameraData) | 
| 1770 | { | 
| 1771 |     bool centerHasChanged = cameraData.center() != m_cameraData.center(); | 
| 1772 |     bool bearingHasChanged = cameraData.bearing() != m_cameraData.bearing(); | 
| 1773 |     bool tiltHasChanged = cameraData.tilt() != m_cameraData.tilt(); | 
| 1774 |     bool fovHasChanged = cameraData.fieldOfView() != m_cameraData.fieldOfView(); | 
| 1775 |     bool zoomHasChanged = cameraData.zoomLevel() != m_cameraData.zoomLevel(); | 
| 1776 |  | 
| 1777 |     m_cameraData = cameraData; | 
| 1778 |     // polish map items | 
| 1779 |     for (const QPointer<QDeclarativeGeoMapItemBase> &i: qAsConst(t&: m_mapItems)) { | 
| 1780 |         if (i) | 
| 1781 |             i->baseCameraDataChanged(camera: m_cameraData); // Consider optimizing this further, removing the contained duplicate if conditions. | 
| 1782 |     } | 
| 1783 |  | 
| 1784 |     if (centerHasChanged) | 
| 1785 |         emit centerChanged(coordinate: m_cameraData.center()); | 
| 1786 |     if (zoomHasChanged) | 
| 1787 |         emit zoomLevelChanged(zoomLevel: m_cameraData.zoomLevel()); | 
| 1788 |     if (bearingHasChanged) | 
| 1789 |         emit bearingChanged(bearing: m_cameraData.bearing()); | 
| 1790 |     if (tiltHasChanged) | 
| 1791 |         emit tiltChanged(tilt: m_cameraData.tilt()); | 
| 1792 |     if (fovHasChanged) | 
| 1793 |         emit fieldOfViewChanged(fieldOfView: m_cameraData.fieldOfView()); | 
| 1794 |     if (centerHasChanged || zoomHasChanged || bearingHasChanged | 
| 1795 |             || tiltHasChanged || fovHasChanged) | 
| 1796 |         emit visibleRegionChanged(); | 
| 1797 | } | 
| 1798 |  | 
| 1799 | /*! | 
| 1800 |     \qmlmethod void QtLocation::Map::addMapParameter(MapParameter parameter) | 
| 1801 |  | 
| 1802 |     Adds the \a parameter object to the map. The effect of this call is dependent | 
| 1803 |     on the combination of the content of the MapParameter and the type of | 
| 1804 |     underlying QGeoMap. If a MapParameter that is not supported by the underlying | 
| 1805 |     QGeoMap gets added, the call has no effect. | 
| 1806 |  | 
| 1807 |     The release of this API with Qt 5.9 is a Technology Preview. | 
| 1808 |  | 
| 1809 |     \sa MapParameter, removeMapParameter, mapParameters, clearMapParameters | 
| 1810 |  | 
| 1811 |     \since 5.9 | 
| 1812 | */ | 
| 1813 | void QDeclarativeGeoMap::addMapParameter(QDeclarativeGeoMapParameter *parameter) | 
| 1814 | { | 
| 1815 |     if (!parameter->isComponentComplete()) { | 
| 1816 |         connect(sender: parameter, signal: &QDeclarativeGeoMapParameter::completed, receiver: this, slot: &QDeclarativeGeoMap::addMapParameter); | 
| 1817 |         return; | 
| 1818 |     } | 
| 1819 |  | 
| 1820 |     disconnect(receiver: parameter); | 
| 1821 |     if (m_mapParameters.contains(t: parameter)) | 
| 1822 |         return; | 
| 1823 |     parameter->setParent(this); | 
| 1824 |     m_mapParameters.append(t: parameter); // parameter now owned by QDeclarativeGeoMap | 
| 1825 |     if (m_map) | 
| 1826 |         m_map->addParameter(param: parameter); | 
| 1827 | } | 
| 1828 |  | 
| 1829 | /*! | 
| 1830 |     \qmlmethod void QtLocation::Map::removeMapParameter(MapParameter parameter) | 
| 1831 |  | 
| 1832 |     Removes the given \a parameter object from the map. | 
| 1833 |  | 
| 1834 |     The release of this API with Qt 5.9 is a Technology Preview. | 
| 1835 |  | 
| 1836 |     \sa MapParameter, addMapParameter, mapParameters, clearMapParameters | 
| 1837 |  | 
| 1838 |     \since 5.9 | 
| 1839 | */ | 
| 1840 | void QDeclarativeGeoMap::removeMapParameter(QDeclarativeGeoMapParameter *parameter) | 
| 1841 | { | 
| 1842 |     if (!m_mapParameters.contains(t: parameter)) | 
| 1843 |         return; | 
| 1844 |     if (m_map) | 
| 1845 |         m_map->removeParameter(param: parameter); | 
| 1846 |     m_mapParameters.removeOne(t: parameter); | 
| 1847 | } | 
| 1848 |  | 
| 1849 | /*! | 
| 1850 |     \qmlmethod void QtLocation::Map::clearMapParameters() | 
| 1851 |  | 
| 1852 |     Removes all map parameters from the map. | 
| 1853 |  | 
| 1854 |     The release of this API with Qt 5.9 is a Technology Preview. | 
| 1855 |  | 
| 1856 |     \sa MapParameter, mapParameters, addMapParameter, removeMapParameter, clearMapParameters | 
| 1857 |  | 
| 1858 |     \since 5.9 | 
| 1859 | */ | 
| 1860 | void QDeclarativeGeoMap::clearMapParameters() | 
| 1861 | { | 
| 1862 |     if (m_map) | 
| 1863 |         m_map->clearParameters(); | 
| 1864 |     m_mapParameters.clear(); | 
| 1865 | } | 
| 1866 |  | 
| 1867 | /*! | 
| 1868 |     \qmlproperty list<MapParameters> QtLocation::Map::mapParameters | 
| 1869 |  | 
| 1870 |     Returns the list of all map parameters in no particular order. | 
| 1871 |     These items include map parameters that were declared statically as part of | 
| 1872 |     the type declaration, as well as dynamical map parameters (\l addMapParameter). | 
| 1873 |  | 
| 1874 |     The release of this API with Qt 5.9 is a Technology Preview. | 
| 1875 |  | 
| 1876 |     \sa MapParameter, addMapParameter, removeMapParameter, clearMapParameters | 
| 1877 |  | 
| 1878 |     \since 5.9 | 
| 1879 | */ | 
| 1880 | QList<QObject *> QDeclarativeGeoMap::mapParameters() | 
| 1881 | { | 
| 1882 |     QList<QObject *> ret; | 
| 1883 |     for (QDeclarativeGeoMapParameter *p : qAsConst(t&: m_mapParameters)) | 
| 1884 |         ret << p; | 
| 1885 |     return ret; | 
| 1886 | } | 
| 1887 |  | 
| 1888 | /* | 
| 1889 |     \internal | 
| 1890 | */ | 
| 1891 | void QDeclarativeGeoMap::addMapObject(QGeoMapObject *object) | 
| 1892 | { | 
| 1893 |     if (!object || object->map()) | 
| 1894 |         return; | 
| 1895 |  | 
| 1896 |     if (!m_initialized) { | 
| 1897 |         m_pendingMapObjects.append(t: object); | 
| 1898 |         return; | 
| 1899 |     } | 
| 1900 |  | 
| 1901 |     int curObjects = m_map->mapObjects().size(); | 
| 1902 |     // object adds itself to the map | 
| 1903 |     object->setMap(m_map); | 
| 1904 |  | 
| 1905 |     if (curObjects != m_map->mapObjects().size()) | 
| 1906 |         emit mapObjectsChanged(); | 
| 1907 | } | 
| 1908 |  | 
| 1909 | /* | 
| 1910 |     \internal | 
| 1911 | */ | 
| 1912 | void QDeclarativeGeoMap::removeMapObject(QGeoMapObject *object) | 
| 1913 | { | 
| 1914 |     if (!object || object->map() != m_map) // if !initialized this is fine, since both object and m_map are supposed to be NULL | 
| 1915 |         return; | 
| 1916 |  | 
| 1917 |     if (!m_initialized) { | 
| 1918 |         m_pendingMapObjects.removeOne(t: object); | 
| 1919 |         return; | 
| 1920 |     } | 
| 1921 |  | 
| 1922 |     int curObjects = m_map->mapObjects().size(); | 
| 1923 |     // object adds itself to the map | 
| 1924 |     object->setMap(nullptr); | 
| 1925 |  | 
| 1926 |     if (curObjects != m_map->mapObjects().size()) | 
| 1927 |         emit mapObjectsChanged(); | 
| 1928 | } | 
| 1929 |  | 
| 1930 | /* | 
| 1931 |     \internal | 
| 1932 | */ | 
| 1933 | void QDeclarativeGeoMap::clearMapObjects() | 
| 1934 | { | 
| 1935 |     if (!m_initialized) { | 
| 1936 |         m_pendingMapObjects.clear(); | 
| 1937 |     } else { | 
| 1938 |         const QList<QGeoMapObject *> objs = m_map->mapObjects(); | 
| 1939 |         for (QGeoMapObject *o: objs) | 
| 1940 |             o->setMap(nullptr); | 
| 1941 |         if (objs.size()) | 
| 1942 |             emit mapObjectsChanged(); | 
| 1943 |     } | 
| 1944 | } | 
| 1945 |  | 
| 1946 | /* | 
| 1947 |     \internal | 
| 1948 | */ | 
| 1949 | QList<QGeoMapObject *> QDeclarativeGeoMap::mapObjects() | 
| 1950 | { | 
| 1951 |     if (!m_initialized) | 
| 1952 |         return m_pendingMapObjects; | 
| 1953 |     else | 
| 1954 |         return m_map->mapObjects(); | 
| 1955 | } | 
| 1956 |  | 
| 1957 | /*! | 
| 1958 |     \qmlproperty list<MapItem> QtLocation::Map::mapItems | 
| 1959 |  | 
| 1960 |     Returns the list of all map items in no particular order. | 
| 1961 |     These items include items that were declared statically as part of | 
| 1962 |     the type declaration, as well as dynamical items (\l addMapItem, | 
| 1963 |     \l MapItemView). | 
| 1964 |  | 
| 1965 |     \sa addMapItem, removeMapItem, clearMapItems | 
| 1966 | */ | 
| 1967 |  | 
| 1968 | QList<QObject *> QDeclarativeGeoMap::mapItems() | 
| 1969 | { | 
| 1970 |     QList<QObject *> ret; | 
| 1971 |     foreach (const QPointer<QDeclarativeGeoMapItemBase> &ptr, m_mapItems) { | 
| 1972 |         if (ptr) | 
| 1973 |             ret << ptr.data(); | 
| 1974 |     } | 
| 1975 |     return ret; | 
| 1976 | } | 
| 1977 |  | 
| 1978 | /*! | 
| 1979 |     \qmlmethod void QtLocation::Map::addMapItem(MapItem item) | 
| 1980 |  | 
| 1981 |     Adds the given \a item to the Map (for example MapQuickItem, MapCircle). If the object | 
| 1982 |     already is on the Map, it will not be added again. | 
| 1983 |  | 
| 1984 |     As an example, consider the case where you have a MapCircle representing your current position: | 
| 1985 |  | 
| 1986 |     \snippet declarative/maps.qml QtQuick import | 
| 1987 |     \snippet declarative/maps.qml QtLocation import | 
| 1988 |     \codeline | 
| 1989 |     \snippet declarative/maps.qml Map addMapItem MapCircle at current position | 
| 1990 |  | 
| 1991 |     \note MapItemViews cannot be added with this method. | 
| 1992 |  | 
| 1993 |     \sa mapItems, removeMapItem, clearMapItems | 
| 1994 | */ | 
| 1995 |  | 
| 1996 | void QDeclarativeGeoMap::addMapItem(QDeclarativeGeoMapItemBase *item) | 
| 1997 | { | 
| 1998 |     if (addMapItem_real(item)) | 
| 1999 |         emit mapItemsChanged(); | 
| 2000 | } | 
| 2001 |  | 
| 2002 | bool QDeclarativeGeoMap::addMapItem_real(QDeclarativeGeoMapItemBase *item) | 
| 2003 | { | 
| 2004 |     if (!item || item->quickMap()) | 
| 2005 |         return false; | 
| 2006 |     // If the item comes from a MapItemGroup, do not reparent it. | 
| 2007 |     if (!qobject_cast<QDeclarativeGeoMapItemGroup *>(object: item->parentItem())) | 
| 2008 |         item->setParentItem(this); | 
| 2009 |     m_mapItems.append(t: item); | 
| 2010 |     if (m_map) { | 
| 2011 |         item->setMap(quickMap: this, map: m_map); | 
| 2012 |         m_map->addMapItem(item); | 
| 2013 |     } | 
| 2014 |     return true; | 
| 2015 | } | 
| 2016 |  | 
| 2017 | /*! | 
| 2018 |     \qmlmethod void QtLocation::Map::removeMapItem(MapItem item) | 
| 2019 |  | 
| 2020 |     Removes the given \a item from the Map (for example MapQuickItem, MapCircle). If | 
| 2021 |     the MapItem does not exist or was not previously added to the map, the | 
| 2022 |     method does nothing. | 
| 2023 |  | 
| 2024 |     \sa mapItems, addMapItem, clearMapItems | 
| 2025 | */ | 
| 2026 | void QDeclarativeGeoMap::removeMapItem(QDeclarativeGeoMapItemBase *ptr) | 
| 2027 | { | 
| 2028 |     if (removeMapItem_real(item: ptr)) | 
| 2029 |         emit mapItemsChanged(); | 
| 2030 | } | 
| 2031 |  | 
| 2032 | bool QDeclarativeGeoMap::removeMapItem_real(QDeclarativeGeoMapItemBase *ptr) | 
| 2033 | { | 
| 2034 |     if (!ptr) | 
| 2035 |         return false; | 
| 2036 |     QPointer<QDeclarativeGeoMapItemBase> item(ptr); | 
| 2037 |     if (!m_mapItems.contains(t: item)) | 
| 2038 |         return false; | 
| 2039 |     if (m_map) | 
| 2040 |         m_map->removeMapItem(item: ptr); | 
| 2041 |     if (item->parentItem() == this) | 
| 2042 |         item->setParentItem(0); | 
| 2043 |     item->setMap(quickMap: 0, map: 0); | 
| 2044 |     // these can be optimized for perf, as we already check the 'contains' above | 
| 2045 |     m_mapItems.removeOne(t: item); | 
| 2046 |     return true; | 
| 2047 | } | 
| 2048 |  | 
| 2049 | /*! | 
| 2050 |     \qmlmethod void QtLocation::Map::clearMapItems() | 
| 2051 |  | 
| 2052 |     Removes all items and item groups from the map. | 
| 2053 |  | 
| 2054 |     \sa mapItems, addMapItem, removeMapItem, addMapItemGroup, removeMapItemGroup | 
| 2055 | */ | 
| 2056 | void QDeclarativeGeoMap::clearMapItems() | 
| 2057 | { | 
| 2058 |     if (m_mapItems.isEmpty()) | 
| 2059 |         return; | 
| 2060 |  | 
| 2061 |     int removed = 0; | 
| 2062 |     for (auto i : qAsConst(t&: m_mapItemGroups)) { | 
| 2063 |         // Processing only top-level groups (!views) | 
| 2064 |         QDeclarativeGeoMapItemView *view = qobject_cast<QDeclarativeGeoMapItemView *>(object: i); | 
| 2065 |         if (view) | 
| 2066 |             continue; | 
| 2067 |  | 
| 2068 |         if (i->parentItem() != this) | 
| 2069 |             continue; | 
| 2070 |  | 
| 2071 |         removed += removeMapItemGroup_real(itemGroup: i); | 
| 2072 |     } | 
| 2073 |  | 
| 2074 |     for (auto i : qAsConst(t&: m_mapItems)) | 
| 2075 |         removed += removeMapItem_real(ptr: i); | 
| 2076 |  | 
| 2077 |     if (removed) | 
| 2078 |         emit mapItemsChanged(); | 
| 2079 | } | 
| 2080 |  | 
| 2081 | /*! | 
| 2082 |     \qmlmethod void QtLocation::Map::addMapItemGroup(MapItemGroup itemGroup) | 
| 2083 |  | 
| 2084 |     Adds the map items contained in the given \a itemGroup to the Map | 
| 2085 |     (for example MapQuickItem, MapCircle). | 
| 2086 |  | 
| 2087 |     \sa MapItemGroup, removeMapItemGroup | 
| 2088 |  | 
| 2089 |     \since 5.9 | 
| 2090 | */ | 
| 2091 | void QDeclarativeGeoMap::addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup) | 
| 2092 | { | 
| 2093 |     if (addMapItemGroup_real(itemGroup)) | 
| 2094 |         emit mapItemsChanged(); | 
| 2095 | } | 
| 2096 |  | 
| 2097 | bool QDeclarativeGeoMap::addMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup) | 
| 2098 | { | 
| 2099 |     if (!itemGroup || itemGroup->quickMap()) // Already added to some map | 
| 2100 |         return false; | 
| 2101 |  | 
| 2102 |     itemGroup->setQuickMap(this); | 
| 2103 |  | 
| 2104 |     if (!isGroupNested(group: itemGroup)) | 
| 2105 |         itemGroup->setParentItem(this); | 
| 2106 |  | 
| 2107 |     QPointer<QDeclarativeGeoMapItemGroup> g(itemGroup); | 
| 2108 |     m_mapItemGroups.append(t: g); | 
| 2109 |  | 
| 2110 |     const QList<QQuickItem *> quickKids = itemGroup->childItems(); | 
| 2111 |     int count = 0; | 
| 2112 |     for (auto c: quickKids) { | 
| 2113 |         count += addMapChild(child: c); // this calls addMapItemGroup recursively, if needed | 
| 2114 |     } | 
| 2115 |     return count; | 
| 2116 | } | 
| 2117 |  | 
| 2118 | /*! | 
| 2119 |     \qmlmethod void QtLocation::Map::removeMapItemGroup(MapItemGroup itemGroup) | 
| 2120 |  | 
| 2121 |     Removes \a itemGroup and the items contained therein from the Map. | 
| 2122 |  | 
| 2123 |     \sa MapItemGroup, addMapItemGroup | 
| 2124 |  | 
| 2125 |     \since 5.9 | 
| 2126 | */ | 
| 2127 | void QDeclarativeGeoMap::removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup) | 
| 2128 | { | 
| 2129 |     if (removeMapItemGroup_real(itemGroup)) | 
| 2130 |         emit mapItemsChanged(); | 
| 2131 | } | 
| 2132 |  | 
| 2133 | bool QDeclarativeGeoMap::removeMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup) | 
| 2134 | { | 
| 2135 |     if (!itemGroup || itemGroup->quickMap() != this) // cant remove an itemGroup added to another map | 
| 2136 |         return false; | 
| 2137 |  | 
| 2138 |     QPointer<QDeclarativeGeoMapItemGroup> g(itemGroup); | 
| 2139 |     if (!m_mapItemGroups.removeOne(t: g)) | 
| 2140 |         return false; | 
| 2141 |  | 
| 2142 |     const QList<QQuickItem *> quickKids = itemGroup->childItems(); | 
| 2143 |     int count = 0; | 
| 2144 |     for (auto c: quickKids) { | 
| 2145 |         count += removeMapChild(child: c); | 
| 2146 |     } | 
| 2147 |     itemGroup->setQuickMap(nullptr); | 
| 2148 |     if (itemGroup->parentItem() == this) | 
| 2149 |         itemGroup->setParentItem(0); | 
| 2150 |     return count; | 
| 2151 | } | 
| 2152 |  | 
| 2153 | /*! | 
| 2154 |     \qmlmethod void QtLocation::Map::removeMapItemView(MapItemView itemView) | 
| 2155 |  | 
| 2156 |     Removes \a itemView and the items instantiated by it from the Map. | 
| 2157 |  | 
| 2158 |     \sa MapItemView, addMapItemView | 
| 2159 |  | 
| 2160 |     \since 5.10 | 
| 2161 | */ | 
| 2162 | void QDeclarativeGeoMap::removeMapItemView(QDeclarativeGeoMapItemView *itemView) | 
| 2163 | { | 
| 2164 |     if (removeMapItemView_real(itemView)) | 
| 2165 |         emit mapItemsChanged(); | 
| 2166 | } | 
| 2167 |  | 
| 2168 | bool QDeclarativeGeoMap::removeMapItemView_real(QDeclarativeGeoMapItemView *itemView) | 
| 2169 | { | 
| 2170 |     if (!itemView || itemView->m_map != this) // can't remove a view that is already added to another map | 
| 2171 |         return false; | 
| 2172 |  | 
| 2173 |     itemView->removeInstantiatedItems(transition: false); // remove the items without using transitions AND abort ongoing ones | 
| 2174 |     itemView->m_map = 0; | 
| 2175 |     m_mapViews.removeOne(t: itemView); | 
| 2176 |     return removeMapItemGroup_real(itemGroup: itemView); // at this point, all delegate instances have been removed. | 
| 2177 | } | 
| 2178 |  | 
| 2179 | void QDeclarativeGeoMap::updateItemToWindowTransform() | 
| 2180 | { | 
| 2181 |     if (!m_initialized) | 
| 2182 |         return; | 
| 2183 |  | 
| 2184 |     // Update itemToWindowTransform into QGeoProjection | 
| 2185 |     const QTransform item2WindowOld = m_map->geoProjection().itemToWindowTransform(); | 
| 2186 |     QTransform item2Window = QQuickItemPrivate::get(item: this)->itemToWindowTransform(); | 
| 2187 |     if (!property(name: "layer" ).isNull() && property(name: "layer" ).value<QObject *>()->property(name: "enabled" ).toBool()) | 
| 2188 |         item2Window.reset(); // When layer is enabled, the item is rendered offscreen with no transformation, then the layer is applied | 
| 2189 |  | 
| 2190 |     m_map->setItemToWindowTransform(item2Window); | 
| 2191 |  | 
| 2192 |     // This method is called at every redraw, including those redraws not generated by | 
| 2193 |     // sgNodeChanged. | 
| 2194 |     // In these cases, *if* the item2windowTransform has changed (e.g., if transformation of | 
| 2195 |     // the item or one of its ancestors changed), a forced update of the map items using accelerated | 
| 2196 |     // GL implementation has to be performed in order to have them pulling the updated itemToWindowTransform. | 
| 2197 |     if (!m_sgNodeHasChanged && item2WindowOld != item2Window) { | 
| 2198 |         for (auto i: qAsConst(t&: m_mapItems)) | 
| 2199 |             i->setMaterialDirty(); | 
| 2200 |     } | 
| 2201 |  | 
| 2202 |     m_sgNodeHasChanged = false; | 
| 2203 | } | 
| 2204 |  | 
| 2205 | void QDeclarativeGeoMap::onSGNodeChanged() | 
| 2206 | { | 
| 2207 |     m_sgNodeHasChanged = true; | 
| 2208 |     update(); | 
| 2209 | } | 
| 2210 |  | 
| 2211 | /*! | 
| 2212 |     \qmlmethod void QtLocation::Map::addMapItemView(MapItemView itemView) | 
| 2213 |  | 
| 2214 |     Adds \a itemView to the Map. | 
| 2215 |  | 
| 2216 |     \sa MapItemView, removeMapItemView | 
| 2217 |  | 
| 2218 |     \since 5.10 | 
| 2219 | */ | 
| 2220 | void QDeclarativeGeoMap::addMapItemView(QDeclarativeGeoMapItemView *itemView) | 
| 2221 | { | 
| 2222 |     if (addMapItemView_real(itemView)) | 
| 2223 |         emit mapItemsChanged(); | 
| 2224 | } | 
| 2225 |  | 
| 2226 | bool QDeclarativeGeoMap::addMapItemView_real(QDeclarativeGeoMapItemView *itemView) | 
| 2227 | { | 
| 2228 |     if (!itemView || itemView->m_map) // can't add a view twice | 
| 2229 |         return false; | 
| 2230 |  | 
| 2231 |     int count = addMapItemGroup_real(itemGroup: itemView); // at this point, delegates aren't yet incubated. | 
| 2232 |     // Not appending it to m_mapViews because it seems unnecessary even if the | 
| 2233 |     // itemView is a child of this (in which case it would be destroyed | 
| 2234 |     m_mapViews.append(t: itemView); | 
| 2235 |     setupMapView(itemView); | 
| 2236 |     return count; | 
| 2237 | } | 
| 2238 |  | 
| 2239 | /*! | 
| 2240 |     \qmlproperty MapType QtLocation::Map::activeMapType | 
| 2241 |  | 
| 2242 |     \brief Access to the currently active \l{MapType}{map type}. | 
| 2243 |  | 
| 2244 |     This property can be set to change the active \l{MapType}{map type}. | 
| 2245 |     See the \l{Map::supportedMapTypes}{supportedMapTypes} property for possible values. | 
| 2246 |  | 
| 2247 |     \sa MapType | 
| 2248 | */ | 
| 2249 | void QDeclarativeGeoMap::setActiveMapType(QDeclarativeGeoMapType *mapType) | 
| 2250 | { | 
| 2251 |     if (m_activeMapType->mapType() != mapType->mapType()) { | 
| 2252 |         if (m_map) { | 
| 2253 |             if (mapType->mapType().pluginName() == m_plugin->name().toLatin1()) { | 
| 2254 |                 m_map->setActiveMapType(mapType->mapType()); | 
| 2255 |                 m_activeMapType = mapType; | 
| 2256 |                 emit activeMapTypeChanged(); | 
| 2257 |             } | 
| 2258 |         } else { | 
| 2259 |             m_activeMapType = mapType; | 
| 2260 |             emit activeMapTypeChanged(); | 
| 2261 |         } | 
| 2262 |     } | 
| 2263 | } | 
| 2264 |  | 
| 2265 | QDeclarativeGeoMapType * QDeclarativeGeoMap::activeMapType() const | 
| 2266 | { | 
| 2267 |     return m_activeMapType; | 
| 2268 | } | 
| 2269 |  | 
| 2270 | /*! | 
| 2271 |     \internal | 
| 2272 | */ | 
| 2273 | void QDeclarativeGeoMap::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) | 
| 2274 | { | 
| 2275 |     m_gestureArea->setSize(newGeometry.size()); | 
| 2276 |     QQuickItem::geometryChanged(newGeometry, oldGeometry); | 
| 2277 |  | 
| 2278 |     if (!m_map || newGeometry.size().isEmpty()) | 
| 2279 |         return; | 
| 2280 |  | 
| 2281 |     m_map->setViewportSize(newGeometry.size().toSize()); | 
| 2282 |  | 
| 2283 |     if (!m_initialized) { | 
| 2284 |         initialize(); | 
| 2285 |     } else { | 
| 2286 |         setMinimumZoomLevel(minimumZoomLevel: m_map->minimumZoom(), userSet: false); | 
| 2287 |  | 
| 2288 |         // Update the center latitudinal threshold | 
| 2289 |         QGeoCameraData cameraData = m_map->cameraData(); | 
| 2290 |         const double maximumCenterLatitudeAtZoom = m_map->maximumCenterLatitudeAtZoom(cameraData); | 
| 2291 |         const double minimumCenterLatitudeAtZoom = m_map->minimumCenterLatitudeAtZoom(cameraData); | 
| 2292 |         if (maximumCenterLatitudeAtZoom != m_maximumViewportLatitude | 
| 2293 |                 || minimumCenterLatitudeAtZoom != m_minimumViewportLatitude) { | 
| 2294 |             m_maximumViewportLatitude = maximumCenterLatitudeAtZoom; | 
| 2295 |             m_minimumViewportLatitude = minimumCenterLatitudeAtZoom; | 
| 2296 |             QGeoCoordinate coord = cameraData.center(); | 
| 2297 |             coord.setLatitude(qBound(min: m_minimumViewportLatitude, val: coord.latitude(), max: m_maximumViewportLatitude)); | 
| 2298 |             cameraData.setCenter(coord); | 
| 2299 |             m_map->setCameraData(cameraData); // this polishes map items | 
| 2300 |         } else if (oldGeometry.size() != newGeometry.size()) { | 
| 2301 |             // polish map items | 
| 2302 |             for (const QPointer<QDeclarativeGeoMapItemBase> &i: qAsConst(t&: m_mapItems)) { | 
| 2303 |                 if (i) | 
| 2304 |                     i->polishAndUpdate(); | 
| 2305 |             } | 
| 2306 |         } | 
| 2307 |     } | 
| 2308 |  | 
| 2309 |     /* | 
| 2310 |         The fitViewportTo*() functions depend on a valid map geometry. | 
| 2311 |         If they were called prior to the first resize they cause | 
| 2312 |         the zoomlevel to jump to 0 (showing the world). Therefore the | 
| 2313 |         calls were queued up until now. | 
| 2314 |  | 
| 2315 |         Multiple fitViewportTo*() calls replace each other. | 
| 2316 |      */ | 
| 2317 |     if (m_pendingFitViewport && width() && height()) { | 
| 2318 |         fitViewportToGeoShape(shape: m_visibleRegion); | 
| 2319 |         m_pendingFitViewport = false; | 
| 2320 |     } | 
| 2321 |  | 
| 2322 | } | 
| 2323 |  | 
| 2324 | /*! | 
| 2325 |     \qmlmethod void QtLocation::Map::fitViewportToMapItems(list<MapItems> items = {}) | 
| 2326 |  | 
| 2327 |     If no argument is provided, fits the current viewport to the boundary of all map items. | 
| 2328 |     The camera is positioned in the center of the map items, and at the largest integral zoom level | 
| 2329 |     possible which allows all map items to be visible on screen. | 
| 2330 |     If \a items is provided, fits the current viewport to the boundary of the specified map items only. | 
| 2331 |  | 
| 2332 |     \note This method gained the optional \a items argument since Qt 5.15. | 
| 2333 |     In previous releases, this method fitted the map to all map items. | 
| 2334 |  | 
| 2335 |     \sa fitViewportToVisibleMapItems | 
| 2336 | */ | 
| 2337 | void QDeclarativeGeoMap::fitViewportToMapItems(const QVariantList &items) | 
| 2338 | { | 
| 2339 |     if (items.size()) { | 
| 2340 |         QList<QPointer<QDeclarativeGeoMapItemBase> > itms; | 
| 2341 |         for (const QVariant &i: items) { | 
| 2342 |             QDeclarativeGeoMapItemBase *itm = qobject_cast<QDeclarativeGeoMapItemBase *>(object: i.value<QObject *>()); | 
| 2343 |             if (itm) | 
| 2344 |                 itms.append(t: itm); | 
| 2345 |         } | 
| 2346 |         fitViewportToMapItemsRefine(mapItems: itms, refine: true, onlyVisible: false); | 
| 2347 |     } else { | 
| 2348 |         fitViewportToMapItemsRefine(mapItems: m_mapItems, refine: true, onlyVisible: false); | 
| 2349 |     } | 
| 2350 | } | 
| 2351 |  | 
| 2352 | /*! | 
| 2353 |     \qmlmethod void QtLocation::Map::fitViewportToVisibleMapItems() | 
| 2354 |  | 
| 2355 |     Fits the current viewport to the boundary of all \b visible map items. | 
| 2356 |     The camera is positioned in the center of the map items, and at the largest integral | 
| 2357 |     zoom level possible which allows all map items to be visible on screen. | 
| 2358 |  | 
| 2359 |     \sa fitViewportToMapItems | 
| 2360 | */ | 
| 2361 | void QDeclarativeGeoMap::fitViewportToVisibleMapItems() | 
| 2362 | { | 
| 2363 |     fitViewportToMapItemsRefine(mapItems: m_mapItems, refine: true, onlyVisible: true); | 
| 2364 | } | 
| 2365 |  | 
| 2366 | /*! | 
| 2367 |     \internal | 
| 2368 | */ | 
| 2369 | void QDeclarativeGeoMap::fitViewportToMapItemsRefine(const QList<QPointer<QDeclarativeGeoMapItemBase> > &mapItems, | 
| 2370 |                                                      bool refine, | 
| 2371 |                                                      bool onlyVisible) | 
| 2372 | { | 
| 2373 |     if (!m_map) | 
| 2374 |         return; | 
| 2375 |  | 
| 2376 |     if (mapItems.size() == 0) | 
| 2377 |         return; | 
| 2378 |  | 
| 2379 |     double minX = qInf(); | 
| 2380 |     double maxX = -qInf(); | 
| 2381 |     double minY = qInf(); | 
| 2382 |     double maxY = -qInf(); | 
| 2383 |     double topLeftX = 0; | 
| 2384 |     double topLeftY = 0; | 
| 2385 |     double bottomRightX = 0; | 
| 2386 |     double bottomRightY = 0; | 
| 2387 |     bool haveQuickItem = false; | 
| 2388 |  | 
| 2389 |     // find bounds of all map items | 
| 2390 |     int itemCount = 0; | 
| 2391 |     for (int i = 0; i < mapItems.count(); ++i) { | 
| 2392 |         if (!mapItems.at(i)) | 
| 2393 |             continue; | 
| 2394 |         QDeclarativeGeoMapItemBase *item = mapItems.at(i).data(); | 
| 2395 |         if (!item || (onlyVisible && (!item->isVisible() || item->mapItemOpacity() <= 0.0))) | 
| 2396 |             continue; | 
| 2397 |  | 
| 2398 |         // skip quick items in the first pass and refine the fit later | 
| 2399 |         QDeclarativeGeoMapQuickItem *quickItem = | 
| 2400 |                 qobject_cast<QDeclarativeGeoMapQuickItem*>(object: item); | 
| 2401 |         if (refine && quickItem) { | 
| 2402 |                 haveQuickItem = true; | 
| 2403 |                 continue; | 
| 2404 |         } | 
| 2405 |         // Force map items to update immediately. Needed to ensure correct item size and positions | 
| 2406 |         // when recursively calling this function. | 
| 2407 |         // TODO: See if we really need updatePolish on delegated items, in particular | 
| 2408 |         // in relation to | 
| 2409 |         // a) fitViewportToMapItems | 
| 2410 |         // b) presence of MouseArea | 
| 2411 |         // | 
| 2412 |         // This is also legacy code. It must be updated to not operate on screen sizes. | 
| 2413 |         if (item->isPolishScheduled()) | 
| 2414 |            item->updatePolish(); | 
| 2415 |  | 
| 2416 |         if (quickItem && quickItem->matrix_ && !quickItem->matrix_->m_matrix.isIdentity()) { | 
| 2417 |             // TODO: recalculate the center/zoom level so that the item becomes projectable again | 
| 2418 |             if (quickItem->zoomLevel() == 0.0) // the item is unprojectable, should be skipped. | 
| 2419 |                 continue; | 
| 2420 |  | 
| 2421 |             QRectF brect = item->boundingRect(); | 
| 2422 |             brect = quickItem->matrix_->m_matrix.mapRect(rect: brect); | 
| 2423 |             QPointF transformedPosition = quickItem->matrix_->m_matrix * item->position(); | 
| 2424 |             topLeftX = transformedPosition.x(); | 
| 2425 |             topLeftY = transformedPosition.y(); | 
| 2426 |             bottomRightX = topLeftX + brect.width(); | 
| 2427 |             bottomRightY = topLeftY + brect.height(); | 
| 2428 |         } else { | 
| 2429 |             topLeftX = item->position().x(); | 
| 2430 |             topLeftY = item->position().y(); | 
| 2431 |             bottomRightX = topLeftX + item->width(); | 
| 2432 |             bottomRightY = topLeftY + item->height(); | 
| 2433 |         } | 
| 2434 |  | 
| 2435 |         minX = qMin(a: minX, b: topLeftX); | 
| 2436 |         maxX = qMax(a: maxX, b: bottomRightX); | 
| 2437 |         minY = qMin(a: minY, b: topLeftY); | 
| 2438 |         maxY = qMax(a: maxY, b: bottomRightY); | 
| 2439 |  | 
| 2440 |         ++itemCount; | 
| 2441 |     } | 
| 2442 |  | 
| 2443 |     if (itemCount == 0) { | 
| 2444 |         if (haveQuickItem) | 
| 2445 |             fitViewportToMapItemsRefine(mapItems, refine: false, onlyVisible); | 
| 2446 |         return; | 
| 2447 |     } | 
| 2448 |     double bboxWidth = maxX - minX; | 
| 2449 |     double bboxHeight = maxY - minY; | 
| 2450 |     double bboxCenterX = minX + (bboxWidth / 2.0); | 
| 2451 |     double bboxCenterY = minY + (bboxHeight / 2.0); | 
| 2452 |  | 
| 2453 |     // position camera to the center of bounding box | 
| 2454 |     QGeoCoordinate coordinate; | 
| 2455 |     coordinate = m_map->geoProjection().itemPositionToCoordinate(pos: QDoubleVector2D(bboxCenterX, bboxCenterY), clipToViewport: false); | 
| 2456 |     setProperty(name: "center" , value: QVariant::fromValue(value: coordinate)); | 
| 2457 |  | 
| 2458 |     // adjust zoom | 
| 2459 |     double bboxWidthRatio = bboxWidth / (bboxWidth + bboxHeight); | 
| 2460 |     double mapWidthRatio = width() / (width() + height()); | 
| 2461 |     double zoomRatio; | 
| 2462 |  | 
| 2463 |     if (bboxWidthRatio > mapWidthRatio) | 
| 2464 |         zoomRatio = bboxWidth / width(); | 
| 2465 |     else | 
| 2466 |         zoomRatio = bboxHeight / height(); | 
| 2467 |  | 
| 2468 |     qreal newZoom = std::log10(x: zoomRatio) / std::log10(x: 0.5); | 
| 2469 |     newZoom = std::floor(x: qMax(a: minimumZoomLevel(), b: (zoomLevel() + newZoom))); | 
| 2470 |     setProperty(name: "zoomLevel" , value: QVariant::fromValue(value: newZoom)); | 
| 2471 |  | 
| 2472 |     // as map quick items retain the same screen size after the camera zooms in/out | 
| 2473 |     // we refine the viewport again to achieve better results | 
| 2474 |     if (refine) | 
| 2475 |         fitViewportToMapItemsRefine(mapItems, refine: false, onlyVisible); | 
| 2476 | } | 
| 2477 |  | 
| 2478 | /*! | 
| 2479 |     \internal | 
| 2480 | */ | 
| 2481 | void QDeclarativeGeoMap::mousePressEvent(QMouseEvent *event) | 
| 2482 | { | 
| 2483 |     if (isInteractive()) | 
| 2484 |         m_gestureArea->handleMousePressEvent(event); | 
| 2485 |     else | 
| 2486 |         QQuickItem::mousePressEvent(event); | 
| 2487 | } | 
| 2488 |  | 
| 2489 | /*! | 
| 2490 |     \internal | 
| 2491 | */ | 
| 2492 | void QDeclarativeGeoMap::mouseMoveEvent(QMouseEvent *event) | 
| 2493 | { | 
| 2494 |     if (isInteractive()) | 
| 2495 |         m_gestureArea->handleMouseMoveEvent(event); | 
| 2496 |     else | 
| 2497 |         QQuickItem::mouseMoveEvent(event); | 
| 2498 | } | 
| 2499 |  | 
| 2500 | /*! | 
| 2501 |     \internal | 
| 2502 | */ | 
| 2503 | void QDeclarativeGeoMap::mouseReleaseEvent(QMouseEvent *event) | 
| 2504 | { | 
| 2505 |     if (isInteractive()) | 
| 2506 |         m_gestureArea->handleMouseReleaseEvent(event); | 
| 2507 |     else | 
| 2508 |         QQuickItem::mouseReleaseEvent(event); | 
| 2509 | } | 
| 2510 |  | 
| 2511 | /*! | 
| 2512 |     \internal | 
| 2513 | */ | 
| 2514 | void QDeclarativeGeoMap::mouseUngrabEvent() | 
| 2515 | { | 
| 2516 |     if (isInteractive()) | 
| 2517 |         m_gestureArea->handleMouseUngrabEvent(); | 
| 2518 |     else | 
| 2519 |         QQuickItem::mouseUngrabEvent(); | 
| 2520 | } | 
| 2521 |  | 
| 2522 | void QDeclarativeGeoMap::touchUngrabEvent() | 
| 2523 | { | 
| 2524 |     if (isInteractive()) | 
| 2525 |         m_gestureArea->handleTouchUngrabEvent(); | 
| 2526 |     else | 
| 2527 |         QQuickItem::touchUngrabEvent(); | 
| 2528 | } | 
| 2529 |  | 
| 2530 | /*! | 
| 2531 |     \internal | 
| 2532 | */ | 
| 2533 | void QDeclarativeGeoMap::touchEvent(QTouchEvent *event) | 
| 2534 | { | 
| 2535 |     if (isInteractive()) { | 
| 2536 |         m_gestureArea->handleTouchEvent(event); | 
| 2537 |     } else { | 
| 2538 |         //ignore event so sythesized event is generated; | 
| 2539 |         QQuickItem::touchEvent(event); | 
| 2540 |     } | 
| 2541 | } | 
| 2542 |  | 
| 2543 | #if QT_CONFIG(wheelevent) | 
| 2544 | /*! | 
| 2545 |     \internal | 
| 2546 | */ | 
| 2547 | void QDeclarativeGeoMap::wheelEvent(QWheelEvent *event) | 
| 2548 | { | 
| 2549 |     if (isInteractive()) | 
| 2550 |         m_gestureArea->handleWheelEvent(event); | 
| 2551 |     else | 
| 2552 |         QQuickItem::wheelEvent(event); | 
| 2553 |  | 
| 2554 | } | 
| 2555 | #endif | 
| 2556 |  | 
| 2557 | /*! | 
| 2558 |     \internal | 
| 2559 | */ | 
| 2560 | bool QDeclarativeGeoMap::childMouseEventFilter(QQuickItem *item, QEvent *event) | 
| 2561 | { | 
| 2562 |     Q_UNUSED(item); | 
| 2563 |     if (!isVisible() || !isEnabled() || !isInteractive()) | 
| 2564 |         return QQuickItem::childMouseEventFilter(item, event); | 
| 2565 |  | 
| 2566 |     switch (event->type()) { | 
| 2567 |     case QEvent::MouseButtonPress: | 
| 2568 |     case QEvent::MouseMove: | 
| 2569 |     case QEvent::MouseButtonRelease: | 
| 2570 |         return sendMouseEvent(event: static_cast<QMouseEvent *>(event)); | 
| 2571 |     case QEvent::UngrabMouse: { | 
| 2572 |         QQuickWindow *win = window(); | 
| 2573 |         if (!win) break; | 
| 2574 |         if (!win->mouseGrabberItem() || | 
| 2575 |                 (win->mouseGrabberItem() && | 
| 2576 |                  win->mouseGrabberItem() != this)) { | 
| 2577 |             // child lost grab, we could even lost | 
| 2578 |             // some events if grab already belongs for example | 
| 2579 |             // in item in diffrent window , clear up states | 
| 2580 |             mouseUngrabEvent(); | 
| 2581 |         } | 
| 2582 |         break; | 
| 2583 |     } | 
| 2584 |     case QEvent::TouchBegin: | 
| 2585 |     case QEvent::TouchUpdate: | 
| 2586 |     case QEvent::TouchEnd: | 
| 2587 |     case QEvent::TouchCancel: | 
| 2588 |         if (static_cast<QTouchEvent *>(event)->touchPoints().count() >= 2) { | 
| 2589 |             // 1 touch point = handle with MouseEvent (event is always synthesized) | 
| 2590 |             // let the synthesized mouse event grab the mouse, | 
| 2591 |             // note there is no mouse grabber at this point since | 
| 2592 |             // touch event comes first (see Qt::AA_SynthesizeMouseForUnhandledTouchEvents) | 
| 2593 |             return sendTouchEvent(event: static_cast<QTouchEvent *>(event)); | 
| 2594 |         } | 
| 2595 |     default: | 
| 2596 |         break; | 
| 2597 |     } | 
| 2598 |     return QQuickItem::childMouseEventFilter(item, event); | 
| 2599 | } | 
| 2600 |  | 
| 2601 | bool QDeclarativeGeoMap::sendMouseEvent(QMouseEvent *event) | 
| 2602 | { | 
| 2603 |     QPointF localPos = mapFromScene(point: event->windowPos()); | 
| 2604 |     QQuickWindow *win = window(); | 
| 2605 |     QQuickItem *grabber = win ? win->mouseGrabberItem() : 0; | 
| 2606 |     bool stealEvent = m_gestureArea->isActive(); | 
| 2607 |  | 
| 2608 |     if ((stealEvent || contains(point: localPos)) && (!grabber || (!grabber->keepMouseGrab() && !grabber->keepTouchGrab()))) { | 
| 2609 |         QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, transformedLocalPos: &localPos)); | 
| 2610 |         mouseEvent->setAccepted(false); | 
| 2611 |  | 
| 2612 |         switch (mouseEvent->type()) { | 
| 2613 |         case QEvent::MouseMove: | 
| 2614 |             m_gestureArea->handleMouseMoveEvent(event: mouseEvent.data()); | 
| 2615 |             break; | 
| 2616 |         case QEvent::MouseButtonPress: | 
| 2617 |             m_gestureArea->handleMousePressEvent(event: mouseEvent.data()); | 
| 2618 |             break; | 
| 2619 |         case QEvent::MouseButtonRelease: | 
| 2620 |             m_gestureArea->handleMouseReleaseEvent(event: mouseEvent.data()); | 
| 2621 |             break; | 
| 2622 |         default: | 
| 2623 |             break; | 
| 2624 |         } | 
| 2625 |  | 
| 2626 |         stealEvent = m_gestureArea->isActive(); | 
| 2627 |         grabber = win ? win->mouseGrabberItem() : 0; | 
| 2628 |  | 
| 2629 |         if (grabber && stealEvent && !grabber->keepMouseGrab() && !grabber->keepTouchGrab() && grabber != this) | 
| 2630 |             grabMouse(); | 
| 2631 |  | 
| 2632 |         if (stealEvent) { | 
| 2633 |             //do not deliver | 
| 2634 |             event->setAccepted(true); | 
| 2635 |             return true; | 
| 2636 |         } else { | 
| 2637 |             return false; | 
| 2638 |         } | 
| 2639 |     } | 
| 2640 |  | 
| 2641 |     return false; | 
| 2642 | } | 
| 2643 |  | 
| 2644 | bool QDeclarativeGeoMap::sendTouchEvent(QTouchEvent *event) | 
| 2645 | { | 
| 2646 |     QQuickPointerDevice *touchDevice = QQuickPointerDevice::touchDevice(d: event->device()); | 
| 2647 |     const QTouchEvent::TouchPoint &point = event->touchPoints().first(); | 
| 2648 |     QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(c: window()); | 
| 2649 |  | 
| 2650 |     auto touchPointGrabberItem = [touchDevice, windowPriv](const QTouchEvent::TouchPoint &point) -> QQuickItem* { | 
| 2651 |         if (QQuickEventPoint *eventPointer = windowPriv->pointerEventInstance(device: touchDevice)->pointById(pointId: point.id())) | 
| 2652 |             return eventPointer->grabberItem(); | 
| 2653 |         return nullptr; | 
| 2654 |     }; | 
| 2655 |  | 
| 2656 |     QQuickItem *grabber = touchPointGrabberItem(point); | 
| 2657 |  | 
| 2658 |     bool stealEvent = m_gestureArea->isActive(); | 
| 2659 |     bool containsPoint = contains(point: mapFromScene(point: point.scenePos())); | 
| 2660 |  | 
| 2661 |     if ((stealEvent || containsPoint) && (!grabber || !grabber->keepTouchGrab())) { | 
| 2662 |         QScopedPointer<QTouchEvent> touchEvent(new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints())); | 
| 2663 |         touchEvent->setTimestamp(event->timestamp()); | 
| 2664 |         touchEvent->setAccepted(false); | 
| 2665 |  | 
| 2666 |         m_gestureArea->handleTouchEvent(event: touchEvent.data()); | 
| 2667 |         stealEvent = m_gestureArea->isActive(); | 
| 2668 |         grabber = touchPointGrabberItem(point); | 
| 2669 |  | 
| 2670 |         if (grabber && stealEvent && !grabber->keepTouchGrab() && grabber != this) { | 
| 2671 |             QVector<int> ids; | 
| 2672 |             foreach (const QTouchEvent::TouchPoint &tp, event->touchPoints()) { | 
| 2673 |                 if (!(tp.state() & Qt::TouchPointReleased)) { | 
| 2674 |                     ids.append(t: tp.id()); | 
| 2675 |                 } | 
| 2676 |             } | 
| 2677 |             grabTouchPoints(ids); | 
| 2678 |         } | 
| 2679 |  | 
| 2680 |         if (stealEvent) { | 
| 2681 |             //do not deliver | 
| 2682 |             event->setAccepted(true); | 
| 2683 |             return true; | 
| 2684 |         } else { | 
| 2685 |             return false; | 
| 2686 |         } | 
| 2687 |     } | 
| 2688 |  | 
| 2689 |     return false; | 
| 2690 | } | 
| 2691 |  | 
| 2692 | QT_END_NAMESPACE | 
| 2693 |  |