1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 The Qt Company Ltd. |
4 | ** Copyright (C) 2017 Mapbox, Inc. |
5 | ** Contact: http://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the QtLocation module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL3$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see http://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at http://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU Lesser General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
22 | ** packaging of this file. Please review the following information to |
23 | ** ensure the GNU Lesser General Public License version 3 requirements |
24 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
25 | ** |
26 | ** GNU General Public License Usage |
27 | ** Alternatively, this file may be used under the terms of the GNU |
28 | ** General Public License version 2.0 or later as published by the Free |
29 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
30 | ** the packaging of this file. Please review the following information to |
31 | ** ensure the GNU General Public License version 2.0 requirements will be |
32 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
33 | ** |
34 | ** $QT_END_LICENSE$ |
35 | ** |
36 | ****************************************************************************/ |
37 | |
38 | #include "qgeomapmapboxgl.h" |
39 | #include "qgeomapmapboxgl_p.h" |
40 | #include "qsgmapboxglnode.h" |
41 | #include "qmapboxglstylechange_p.h" |
42 | |
43 | #include <QtCore/QByteArray> |
44 | #include <QtCore/QCoreApplication> |
45 | #include <QtGui/QOpenGLContext> |
46 | #include <QtGui/QOpenGLFramebufferObject> |
47 | #include <QtLocation/private/qdeclarativecirclemapitem_p.h> |
48 | #include <QtLocation/private/qdeclarativegeomapitembase_p.h> |
49 | #include <QtLocation/private/qdeclarativepolygonmapitem_p.h> |
50 | #include <QtLocation/private/qdeclarativepolylinemapitem_p.h> |
51 | #include <QtLocation/private/qdeclarativerectanglemapitem_p.h> |
52 | #include <QtLocation/private/qgeomapparameter_p.h> |
53 | #include <QtLocation/private/qgeoprojection_p.h> |
54 | #include <QtQuick/QQuickWindow> |
55 | #include <QtQuick/QSGImageNode> |
56 | #include <QtQuick/private/qsgtexture_p.h> |
57 | #include <QtQuick/private/qsgcontext_p.h> // for debugging the context name |
58 | |
59 | #include <QMapboxGL> |
60 | |
61 | #include <cmath> |
62 | |
63 | // FIXME: Expose from Mapbox GL constants |
64 | #define MBGL_TILE_SIZE 512.0 |
65 | |
66 | namespace { |
67 | |
68 | // WARNING! The development token is subject to Mapbox Terms of Services |
69 | // and must not be used in production. |
70 | static char developmentToken[] = |
71 | "pk.eyJ1IjoicXRzZGsiLCJhIjoiY2l5azV5MHh5MDAwdTMybzBybjUzZnhxYSJ9.9rfbeqPjX2BusLRDXHCOBA" ; |
72 | |
73 | static const double invLog2 = 1.0 / std::log(x: 2.0); |
74 | |
75 | static double zoomLevelFrom256(double zoomLevelFor256, double tileSize) |
76 | { |
77 | return std::log(x: std::pow(x: 2.0, y: zoomLevelFor256) * 256.0 / tileSize) * invLog2; |
78 | } |
79 | |
80 | } // namespace |
81 | |
82 | QGeoMapMapboxGLPrivate::QGeoMapMapboxGLPrivate(QGeoMappingManagerEngineMapboxGL *engine) |
83 | : QGeoMapPrivate(engine, new QGeoProjectionWebMercator) |
84 | { |
85 | } |
86 | |
87 | QGeoMapMapboxGLPrivate::~QGeoMapMapboxGLPrivate() |
88 | { |
89 | } |
90 | |
91 | QSGNode *QGeoMapMapboxGLPrivate::updateSceneGraph(QSGNode *node, QQuickWindow *window) |
92 | { |
93 | Q_Q(QGeoMapMapboxGL); |
94 | |
95 | if (m_viewportSize.isEmpty()) { |
96 | delete node; |
97 | return 0; |
98 | } |
99 | |
100 | QMapboxGL *map = 0; |
101 | if (!node) { |
102 | QOpenGLContext *currentCtx = QOpenGLContext::currentContext(); |
103 | if (!currentCtx) { |
104 | qWarning(msg: "QOpenGLContext is NULL!" ); |
105 | qWarning() << "You are running on QSG backend " << QSGContext::backend(); |
106 | qWarning(msg: "The MapboxGL plugin works with both Desktop and ES 2.0+ OpenGL versions." ); |
107 | qWarning(msg: "Verify that your Qt is built with OpenGL, and what kind of OpenGL." ); |
108 | qWarning(msg: "To force using a specific OpenGL version, check QSurfaceFormat::setRenderableType and QSurfaceFormat::setDefaultFormat" ); |
109 | |
110 | return node; |
111 | } |
112 | if (m_useFBO) { |
113 | QSGMapboxGLTextureNode *mbglNode = new QSGMapboxGLTextureNode(m_settings, m_viewportSize, window->devicePixelRatio(), q); |
114 | QObject::connect(sender: mbglNode->map(), signal: &QMapboxGL::mapChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapChanged); |
115 | m_syncState = MapTypeSync | CameraDataSync | ViewportSync | VisibleAreaSync; |
116 | node = mbglNode; |
117 | } else { |
118 | QSGMapboxGLRenderNode *mbglNode = new QSGMapboxGLRenderNode(m_settings, m_viewportSize, window->devicePixelRatio(), q); |
119 | QObject::connect(sender: mbglNode->map(), signal: &QMapboxGL::mapChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapChanged); |
120 | m_syncState = MapTypeSync | CameraDataSync | ViewportSync | VisibleAreaSync; |
121 | node = mbglNode; |
122 | } |
123 | } |
124 | map = (m_useFBO) ? static_cast<QSGMapboxGLTextureNode *>(node)->map() |
125 | : static_cast<QSGMapboxGLRenderNode *>(node)->map(); |
126 | |
127 | if (m_syncState & MapTypeSync) { |
128 | m_developmentMode = m_activeMapType.name().startsWith(s: "mapbox://" ) |
129 | && m_settings.accessToken() == developmentToken; |
130 | |
131 | map->setStyleUrl(m_activeMapType.name()); |
132 | } |
133 | |
134 | if (m_syncState & VisibleAreaSync) { |
135 | if (m_visibleArea.isEmpty()) { |
136 | map->setMargins(QMargins()); |
137 | } else { |
138 | QMargins margins(m_visibleArea.x(), // left |
139 | m_visibleArea.y(), // top |
140 | m_viewportSize.width() - m_visibleArea.width() - m_visibleArea.x(), // right |
141 | m_viewportSize.height() - m_visibleArea.height() - m_visibleArea.y()); // bottom |
142 | map->setMargins(margins); |
143 | } |
144 | } |
145 | |
146 | if (m_syncState & CameraDataSync || m_syncState & VisibleAreaSync) { |
147 | map->setZoom(zoomLevelFrom256(zoomLevelFor256: m_cameraData.zoomLevel() , MBGL_TILE_SIZE)); |
148 | map->setBearing(m_cameraData.bearing()); |
149 | map->setPitch(m_cameraData.tilt()); |
150 | |
151 | QGeoCoordinate coordinate = m_cameraData.center(); |
152 | map->setCoordinate(QMapbox::Coordinate(coordinate.latitude(), coordinate.longitude())); |
153 | } |
154 | |
155 | if (m_syncState & ViewportSync) { |
156 | if (m_useFBO) { |
157 | static_cast<QSGMapboxGLTextureNode *>(node)->resize(size: m_viewportSize, pixelRatio: window->devicePixelRatio()); |
158 | } else { |
159 | map->resize(size: m_viewportSize); |
160 | } |
161 | } |
162 | |
163 | if (m_styleLoaded) { |
164 | syncStyleChanges(map); |
165 | } |
166 | |
167 | if (m_useFBO) { |
168 | static_cast<QSGMapboxGLTextureNode *>(node)->render(window); |
169 | } |
170 | |
171 | threadedRenderingHack(window, map); |
172 | |
173 | m_syncState = NoSync; |
174 | |
175 | return node; |
176 | } |
177 | |
178 | void QGeoMapMapboxGLPrivate::addParameter(QGeoMapParameter *param) |
179 | { |
180 | Q_Q(QGeoMapMapboxGL); |
181 | |
182 | QObject::connect(sender: param, signal: &QGeoMapParameter::propertyUpdated, receiver: q, |
183 | slot: &QGeoMapMapboxGL::onParameterPropertyUpdated); |
184 | |
185 | if (m_styleLoaded) { |
186 | m_styleChanges << QMapboxGLStyleChange::addMapParameter(param); |
187 | emit q->sgNodeChanged(); |
188 | } |
189 | } |
190 | |
191 | void QGeoMapMapboxGLPrivate::removeParameter(QGeoMapParameter *param) |
192 | { |
193 | Q_Q(QGeoMapMapboxGL); |
194 | |
195 | q->disconnect(receiver: param); |
196 | |
197 | if (m_styleLoaded) { |
198 | m_styleChanges << QMapboxGLStyleChange::removeMapParameter(param); |
199 | emit q->sgNodeChanged(); |
200 | } |
201 | } |
202 | |
203 | QGeoMap::ItemTypes QGeoMapMapboxGLPrivate::supportedMapItemTypes() const |
204 | { |
205 | return QGeoMap::MapRectangle | QGeoMap::MapCircle | QGeoMap::MapPolygon | QGeoMap::MapPolyline; |
206 | } |
207 | |
208 | void QGeoMapMapboxGLPrivate::addMapItem(QDeclarativeGeoMapItemBase *item) |
209 | { |
210 | Q_Q(QGeoMapMapboxGL); |
211 | |
212 | switch (item->itemType()) { |
213 | case QGeoMap::NoItem: |
214 | case QGeoMap::MapQuickItem: |
215 | case QGeoMap::CustomMapItem: |
216 | return; |
217 | case QGeoMap::MapRectangle: { |
218 | QDeclarativeRectangleMapItem *mapItem = static_cast<QDeclarativeRectangleMapItem *>(item); |
219 | QObject::connect(sender: mapItem, signal: &QQuickItem::visibleChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
220 | QObject::connect(sender: mapItem, signal: &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
221 | QObject::connect(sender: mapItem, signal: &QDeclarativeRectangleMapItem::bottomRightChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemGeometryChanged); |
222 | QObject::connect(sender: mapItem, signal: &QDeclarativeRectangleMapItem::topLeftChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemGeometryChanged); |
223 | QObject::connect(sender: mapItem, signal: &QDeclarativeRectangleMapItem::colorChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
224 | QObject::connect(sender: mapItem->border(), signal: &QDeclarativeMapLineProperties::colorChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemSubPropertyChanged); |
225 | QObject::connect(sender: mapItem->border(), signal: &QDeclarativeMapLineProperties::widthChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged); |
226 | } break; |
227 | case QGeoMap::MapCircle: { |
228 | QDeclarativeCircleMapItem *mapItem = static_cast<QDeclarativeCircleMapItem *>(item); |
229 | QObject::connect(sender: mapItem, signal: &QQuickItem::visibleChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
230 | QObject::connect(sender: mapItem, signal: &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
231 | QObject::connect(sender: mapItem, signal: &QDeclarativeCircleMapItem::centerChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemGeometryChanged); |
232 | QObject::connect(sender: mapItem, signal: &QDeclarativeCircleMapItem::radiusChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemGeometryChanged); |
233 | QObject::connect(sender: mapItem, signal: &QDeclarativeCircleMapItem::colorChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
234 | QObject::connect(sender: mapItem->border(), signal: &QDeclarativeMapLineProperties::colorChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemSubPropertyChanged); |
235 | QObject::connect(sender: mapItem->border(), signal: &QDeclarativeMapLineProperties::widthChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged); |
236 | } break; |
237 | case QGeoMap::MapPolygon: { |
238 | QDeclarativePolygonMapItem *mapItem = static_cast<QDeclarativePolygonMapItem *>(item); |
239 | QObject::connect(sender: mapItem, signal: &QQuickItem::visibleChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
240 | QObject::connect(sender: mapItem, signal: &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
241 | QObject::connect(sender: mapItem, signal: &QDeclarativePolygonMapItem::pathChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemGeometryChanged); |
242 | QObject::connect(sender: mapItem, signal: &QDeclarativePolygonMapItem::colorChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
243 | QObject::connect(sender: mapItem->border(), signal: &QDeclarativeMapLineProperties::colorChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemSubPropertyChanged); |
244 | QObject::connect(sender: mapItem->border(), signal: &QDeclarativeMapLineProperties::widthChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged); |
245 | } break; |
246 | case QGeoMap::MapPolyline: { |
247 | QDeclarativePolylineMapItem *mapItem = static_cast<QDeclarativePolylineMapItem *>(item); |
248 | QObject::connect(sender: mapItem, signal: &QQuickItem::visibleChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
249 | QObject::connect(sender: mapItem, signal: &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
250 | QObject::connect(sender: mapItem, signal: &QDeclarativePolylineMapItem::pathChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemGeometryChanged); |
251 | QObject::connect(sender: mapItem->line(), signal: &QDeclarativeMapLineProperties::colorChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemSubPropertyChanged); |
252 | QObject::connect(sender: mapItem->line(), signal: &QDeclarativeMapLineProperties::widthChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemSubPropertyChanged); |
253 | } break; |
254 | } |
255 | |
256 | QObject::connect(sender: item, signal: &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, receiver: q, slot: &QGeoMapMapboxGL::onMapItemPropertyChanged); |
257 | |
258 | m_styleChanges << QMapboxGLStyleChange::addMapItem(item, before: m_mapItemsBefore); |
259 | |
260 | emit q->sgNodeChanged(); |
261 | } |
262 | |
263 | void QGeoMapMapboxGLPrivate::removeMapItem(QDeclarativeGeoMapItemBase *item) |
264 | { |
265 | Q_Q(QGeoMapMapboxGL); |
266 | |
267 | switch (item->itemType()) { |
268 | case QGeoMap::NoItem: |
269 | case QGeoMap::MapQuickItem: |
270 | case QGeoMap::CustomMapItem: |
271 | return; |
272 | case QGeoMap::MapRectangle: |
273 | q->disconnect(receiver: static_cast<QDeclarativeRectangleMapItem *>(item)->border()); |
274 | break; |
275 | case QGeoMap::MapCircle: |
276 | q->disconnect(receiver: static_cast<QDeclarativeCircleMapItem *>(item)->border()); |
277 | break; |
278 | case QGeoMap::MapPolygon: |
279 | q->disconnect(receiver: static_cast<QDeclarativePolygonMapItem *>(item)->border()); |
280 | break; |
281 | case QGeoMap::MapPolyline: |
282 | q->disconnect(receiver: static_cast<QDeclarativePolylineMapItem *>(item)->line()); |
283 | break; |
284 | } |
285 | |
286 | q->disconnect(receiver: item); |
287 | |
288 | m_styleChanges << QMapboxGLStyleChange::removeMapItem(item); |
289 | |
290 | emit q->sgNodeChanged(); |
291 | } |
292 | |
293 | void QGeoMapMapboxGLPrivate::changeViewportSize(const QSize &) |
294 | { |
295 | Q_Q(QGeoMapMapboxGL); |
296 | |
297 | m_syncState = m_syncState | ViewportSync; |
298 | emit q->sgNodeChanged(); |
299 | } |
300 | |
301 | void QGeoMapMapboxGLPrivate::changeCameraData(const QGeoCameraData &) |
302 | { |
303 | Q_Q(QGeoMapMapboxGL); |
304 | |
305 | m_syncState = m_syncState | CameraDataSync; |
306 | emit q->sgNodeChanged(); |
307 | } |
308 | |
309 | void QGeoMapMapboxGLPrivate::changeActiveMapType(const QGeoMapType) |
310 | { |
311 | Q_Q(QGeoMapMapboxGL); |
312 | |
313 | m_syncState = m_syncState | MapTypeSync; |
314 | emit q->sgNodeChanged(); |
315 | } |
316 | |
317 | void QGeoMapMapboxGLPrivate::setVisibleArea(const QRectF &visibleArea) |
318 | { |
319 | Q_Q(QGeoMapMapboxGL); |
320 | const QRectF va = clampVisibleArea(visibleArea); |
321 | if (va == m_visibleArea) |
322 | return; |
323 | |
324 | m_visibleArea = va; |
325 | m_geoProjection->setVisibleArea(va); |
326 | |
327 | m_syncState = m_syncState | VisibleAreaSync; |
328 | emit q->sgNodeChanged(); |
329 | } |
330 | |
331 | QRectF QGeoMapMapboxGLPrivate::visibleArea() const |
332 | { |
333 | return m_visibleArea; |
334 | } |
335 | |
336 | void QGeoMapMapboxGLPrivate::syncStyleChanges(QMapboxGL *map) |
337 | { |
338 | for (const auto& change : m_styleChanges) { |
339 | change->apply(map); |
340 | } |
341 | |
342 | m_styleChanges.clear(); |
343 | } |
344 | |
345 | void QGeoMapMapboxGLPrivate::threadedRenderingHack(QQuickWindow *window, QMapboxGL *map) |
346 | { |
347 | // FIXME: Optimal support for threaded rendering needs core changes |
348 | // in Mapbox GL Native. Meanwhile we need to set a timer to update |
349 | // the map until all the resources are loaded, which is not exactly |
350 | // battery friendly, because might trigger more paints than we need. |
351 | if (!m_warned) { |
352 | m_threadedRendering = window->openglContext()->thread() != QCoreApplication::instance()->thread(); |
353 | |
354 | if (m_threadedRendering) { |
355 | qWarning() << "Threaded rendering is not optimal in the Mapbox GL plugin." ; |
356 | } |
357 | |
358 | m_warned = true; |
359 | } |
360 | |
361 | if (m_threadedRendering) { |
362 | if (!map->isFullyLoaded()) { |
363 | QMetaObject::invokeMethod(obj: &m_refresh, member: "start" , type: Qt::QueuedConnection); |
364 | } else { |
365 | QMetaObject::invokeMethod(obj: &m_refresh, member: "stop" , type: Qt::QueuedConnection); |
366 | } |
367 | } |
368 | } |
369 | |
370 | /* |
371 | * QGeoMapMapboxGL implementation |
372 | */ |
373 | |
374 | QGeoMapMapboxGL::QGeoMapMapboxGL(QGeoMappingManagerEngineMapboxGL *engine, QObject *parent) |
375 | : QGeoMap(*new QGeoMapMapboxGLPrivate(engine), parent), m_engine(engine) |
376 | { |
377 | Q_D(QGeoMapMapboxGL); |
378 | |
379 | connect(sender: &d->m_refresh, signal: &QTimer::timeout, receiver: this, slot: &QGeoMap::sgNodeChanged); |
380 | d->m_refresh.setInterval(250); |
381 | } |
382 | |
383 | QGeoMapMapboxGL::~QGeoMapMapboxGL() |
384 | { |
385 | } |
386 | |
387 | QString QGeoMapMapboxGL::copyrightsStyleSheet() const |
388 | { |
389 | return QStringLiteral("* { vertical-align: middle; font-weight: normal }" ); |
390 | } |
391 | |
392 | void QGeoMapMapboxGL::setMapboxGLSettings(const QMapboxGLSettings& settings, bool useChinaEndpoint) |
393 | { |
394 | Q_D(QGeoMapMapboxGL); |
395 | |
396 | d->m_settings = settings; |
397 | |
398 | // If the access token is not set, use the development access token. |
399 | // This will only affect mapbox:// styles. |
400 | // Mapbox China requires a China-specific access token. |
401 | if (d->m_settings.accessToken().isEmpty()) { |
402 | if (useChinaEndpoint) { |
403 | qWarning(msg: "Mapbox China requires an access token: https://www.mapbox.com/contact/sales" ); |
404 | } else { |
405 | d->m_settings.setAccessToken(developmentToken); |
406 | } |
407 | } |
408 | } |
409 | |
410 | void QGeoMapMapboxGL::setUseFBO(bool useFBO) |
411 | { |
412 | Q_D(QGeoMapMapboxGL); |
413 | d->m_useFBO = useFBO; |
414 | } |
415 | |
416 | void QGeoMapMapboxGL::setMapItemsBefore(const QString &before) |
417 | { |
418 | Q_D(QGeoMapMapboxGL); |
419 | d->m_mapItemsBefore = before; |
420 | } |
421 | |
422 | QGeoMap::Capabilities QGeoMapMapboxGL::capabilities() const |
423 | { |
424 | return Capabilities(SupportsVisibleRegion |
425 | | SupportsSetBearing |
426 | | SupportsAnchoringCoordinate |
427 | | SupportsVisibleArea ); |
428 | } |
429 | |
430 | QSGNode *QGeoMapMapboxGL::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window) |
431 | { |
432 | Q_D(QGeoMapMapboxGL); |
433 | return d->updateSceneGraph(node: oldNode, window); |
434 | } |
435 | |
436 | void QGeoMapMapboxGL::onMapChanged(QMapboxGL::MapChange change) |
437 | { |
438 | Q_D(QGeoMapMapboxGL); |
439 | |
440 | if (change == QMapboxGL::MapChangeDidFinishLoadingStyle || change == QMapboxGL::MapChangeDidFailLoadingMap) { |
441 | d->m_styleLoaded = true; |
442 | } else if (change == QMapboxGL::MapChangeWillStartLoadingMap) { |
443 | d->m_styleLoaded = false; |
444 | d->m_styleChanges.clear(); |
445 | |
446 | for (QDeclarativeGeoMapItemBase *item : d->m_mapItems) |
447 | d->m_styleChanges << QMapboxGLStyleChange::addMapItem(item, before: d->m_mapItemsBefore); |
448 | |
449 | for (QGeoMapParameter *param : d->m_mapParameters) |
450 | d->m_styleChanges << QMapboxGLStyleChange::addMapParameter(param); |
451 | } |
452 | } |
453 | |
454 | void QGeoMapMapboxGL::onMapItemPropertyChanged() |
455 | { |
456 | Q_D(QGeoMapMapboxGL); |
457 | |
458 | QDeclarativeGeoMapItemBase *item = static_cast<QDeclarativeGeoMapItemBase *>(sender()); |
459 | d->m_styleChanges << QMapboxGLStyleSetPaintProperty::fromMapItem(item); |
460 | d->m_styleChanges << QMapboxGLStyleSetLayoutProperty::fromMapItem(item); |
461 | |
462 | emit sgNodeChanged(); |
463 | } |
464 | |
465 | void QGeoMapMapboxGL::onMapItemSubPropertyChanged() |
466 | { |
467 | Q_D(QGeoMapMapboxGL); |
468 | |
469 | QDeclarativeGeoMapItemBase *item = static_cast<QDeclarativeGeoMapItemBase *>(sender()->parent()); |
470 | d->m_styleChanges << QMapboxGLStyleSetPaintProperty::fromMapItem(item); |
471 | |
472 | emit sgNodeChanged(); |
473 | } |
474 | |
475 | void QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged() |
476 | { |
477 | // TODO https://bugreports.qt.io/browse/QTBUG-58872 |
478 | qWarning() << "Unsupported property for managed Map item" ; |
479 | } |
480 | |
481 | void QGeoMapMapboxGL::onMapItemGeometryChanged() |
482 | { |
483 | Q_D(QGeoMapMapboxGL); |
484 | |
485 | QDeclarativeGeoMapItemBase *item = static_cast<QDeclarativeGeoMapItemBase *>(sender()); |
486 | d->m_styleChanges << QMapboxGLStyleAddSource::fromMapItem(item); |
487 | |
488 | emit sgNodeChanged(); |
489 | } |
490 | |
491 | void QGeoMapMapboxGL::onParameterPropertyUpdated(QGeoMapParameter *param, const char *) |
492 | { |
493 | Q_D(QGeoMapMapboxGL); |
494 | |
495 | d->m_styleChanges.append(t: QMapboxGLStyleChange::addMapParameter(param)); |
496 | |
497 | emit sgNodeChanged(); |
498 | } |
499 | |
500 | void QGeoMapMapboxGL::copyrightsChanged(const QString ©rightsHtml) |
501 | { |
502 | Q_D(QGeoMapMapboxGL); |
503 | |
504 | QString copyrightsHtmlFinal = copyrightsHtml; |
505 | |
506 | if (d->m_developmentMode) { |
507 | copyrightsHtmlFinal.prepend(s: "<a href='https://www.mapbox.com/pricing'>" |
508 | + tr(s: "Development access token, do not use in production." ) + "</a> - " ); |
509 | } |
510 | |
511 | if (d->m_activeMapType.name().startsWith(s: "mapbox://" )) { |
512 | copyrightsHtmlFinal = "<table><tr><th><img src='qrc:/mapboxgl/logo.png'/></th><th>" |
513 | + copyrightsHtmlFinal + "</th></tr></table>" ; |
514 | } |
515 | |
516 | QGeoMap::copyrightsChanged(copyrightsHtml: copyrightsHtmlFinal); |
517 | } |
518 | |