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(2.0);
74
zoomLevelFrom256(double zoomLevelFor256,double tileSize)75 static double zoomLevelFrom256(double zoomLevelFor256, double tileSize)
76 {
77 return std::log(std::pow(2.0, zoomLevelFor256) * 256.0 / tileSize) * invLog2;
78 }
79
80 } // namespace
81
QGeoMapMapboxGLPrivate(QGeoMappingManagerEngineMapboxGL * engine)82 QGeoMapMapboxGLPrivate::QGeoMapMapboxGLPrivate(QGeoMappingManagerEngineMapboxGL *engine)
83 : QGeoMapPrivate(engine, new QGeoProjectionWebMercator)
84 {
85 }
86
~QGeoMapMapboxGLPrivate()87 QGeoMapMapboxGLPrivate::~QGeoMapMapboxGLPrivate()
88 {
89 }
90
updateSceneGraph(QSGNode * node,QQuickWindow * window)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("QOpenGLContext is NULL!");
105 qWarning() << "You are running on QSG backend " << QSGContext::backend();
106 qWarning("The MapboxGL plugin works with both Desktop and ES 2.0+ OpenGL versions.");
107 qWarning("Verify that your Qt is built with OpenGL, and what kind of OpenGL.");
108 qWarning("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(mbglNode->map(), &QMapboxGL::mapChanged, q, &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(mbglNode->map(), &QMapboxGL::mapChanged, q, &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("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(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(m_viewportSize, window->devicePixelRatio());
158 } else {
159 map->resize(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
addParameter(QGeoMapParameter * param)178 void QGeoMapMapboxGLPrivate::addParameter(QGeoMapParameter *param)
179 {
180 Q_Q(QGeoMapMapboxGL);
181
182 QObject::connect(param, &QGeoMapParameter::propertyUpdated, q,
183 &QGeoMapMapboxGL::onParameterPropertyUpdated);
184
185 if (m_styleLoaded) {
186 m_styleChanges << QMapboxGLStyleChange::addMapParameter(param);
187 emit q->sgNodeChanged();
188 }
189 }
190
removeParameter(QGeoMapParameter * param)191 void QGeoMapMapboxGLPrivate::removeParameter(QGeoMapParameter *param)
192 {
193 Q_Q(QGeoMapMapboxGL);
194
195 q->disconnect(param);
196
197 if (m_styleLoaded) {
198 m_styleChanges << QMapboxGLStyleChange::removeMapParameter(param);
199 emit q->sgNodeChanged();
200 }
201 }
202
supportedMapItemTypes() const203 QGeoMap::ItemTypes QGeoMapMapboxGLPrivate::supportedMapItemTypes() const
204 {
205 return QGeoMap::MapRectangle | QGeoMap::MapCircle | QGeoMap::MapPolygon | QGeoMap::MapPolyline;
206 }
207
addMapItem(QDeclarativeGeoMapItemBase * item)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(mapItem, &QQuickItem::visibleChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
220 QObject::connect(mapItem, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
221 QObject::connect(mapItem, &QDeclarativeRectangleMapItem::bottomRightChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
222 QObject::connect(mapItem, &QDeclarativeRectangleMapItem::topLeftChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
223 QObject::connect(mapItem, &QDeclarativeRectangleMapItem::colorChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
224 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
225 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged);
226 } break;
227 case QGeoMap::MapCircle: {
228 QDeclarativeCircleMapItem *mapItem = static_cast<QDeclarativeCircleMapItem *>(item);
229 QObject::connect(mapItem, &QQuickItem::visibleChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
230 QObject::connect(mapItem, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
231 QObject::connect(mapItem, &QDeclarativeCircleMapItem::centerChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
232 QObject::connect(mapItem, &QDeclarativeCircleMapItem::radiusChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
233 QObject::connect(mapItem, &QDeclarativeCircleMapItem::colorChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
234 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
235 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged);
236 } break;
237 case QGeoMap::MapPolygon: {
238 QDeclarativePolygonMapItem *mapItem = static_cast<QDeclarativePolygonMapItem *>(item);
239 QObject::connect(mapItem, &QQuickItem::visibleChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
240 QObject::connect(mapItem, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
241 QObject::connect(mapItem, &QDeclarativePolygonMapItem::pathChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
242 QObject::connect(mapItem, &QDeclarativePolygonMapItem::colorChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
243 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
244 QObject::connect(mapItem->border(), &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged);
245 } break;
246 case QGeoMap::MapPolyline: {
247 QDeclarativePolylineMapItem *mapItem = static_cast<QDeclarativePolylineMapItem *>(item);
248 QObject::connect(mapItem, &QQuickItem::visibleChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
249 QObject::connect(mapItem, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
250 QObject::connect(mapItem, &QDeclarativePolylineMapItem::pathChanged, q, &QGeoMapMapboxGL::onMapItemGeometryChanged);
251 QObject::connect(mapItem->line(), &QDeclarativeMapLineProperties::colorChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
252 QObject::connect(mapItem->line(), &QDeclarativeMapLineProperties::widthChanged, q, &QGeoMapMapboxGL::onMapItemSubPropertyChanged);
253 } break;
254 }
255
256 QObject::connect(item, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged, q, &QGeoMapMapboxGL::onMapItemPropertyChanged);
257
258 m_styleChanges << QMapboxGLStyleChange::addMapItem(item, m_mapItemsBefore);
259
260 emit q->sgNodeChanged();
261 }
262
removeMapItem(QDeclarativeGeoMapItemBase * item)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(static_cast<QDeclarativeRectangleMapItem *>(item)->border());
274 break;
275 case QGeoMap::MapCircle:
276 q->disconnect(static_cast<QDeclarativeCircleMapItem *>(item)->border());
277 break;
278 case QGeoMap::MapPolygon:
279 q->disconnect(static_cast<QDeclarativePolygonMapItem *>(item)->border());
280 break;
281 case QGeoMap::MapPolyline:
282 q->disconnect(static_cast<QDeclarativePolylineMapItem *>(item)->line());
283 break;
284 }
285
286 q->disconnect(item);
287
288 m_styleChanges << QMapboxGLStyleChange::removeMapItem(item);
289
290 emit q->sgNodeChanged();
291 }
292
changeViewportSize(const QSize &)293 void QGeoMapMapboxGLPrivate::changeViewportSize(const QSize &)
294 {
295 Q_Q(QGeoMapMapboxGL);
296
297 m_syncState = m_syncState | ViewportSync;
298 emit q->sgNodeChanged();
299 }
300
changeCameraData(const QGeoCameraData &)301 void QGeoMapMapboxGLPrivate::changeCameraData(const QGeoCameraData &)
302 {
303 Q_Q(QGeoMapMapboxGL);
304
305 m_syncState = m_syncState | CameraDataSync;
306 emit q->sgNodeChanged();
307 }
308
changeActiveMapType(const QGeoMapType)309 void QGeoMapMapboxGLPrivate::changeActiveMapType(const QGeoMapType)
310 {
311 Q_Q(QGeoMapMapboxGL);
312
313 m_syncState = m_syncState | MapTypeSync;
314 emit q->sgNodeChanged();
315 }
316
setVisibleArea(const QRectF & visibleArea)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
visibleArea() const331 QRectF QGeoMapMapboxGLPrivate::visibleArea() const
332 {
333 return m_visibleArea;
334 }
335
syncStyleChanges(QMapboxGL * map)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
threadedRenderingHack(QQuickWindow * window,QMapboxGL * map)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(&m_refresh, "start", Qt::QueuedConnection);
364 } else {
365 QMetaObject::invokeMethod(&m_refresh, "stop", Qt::QueuedConnection);
366 }
367 }
368 }
369
370 /*
371 * QGeoMapMapboxGL implementation
372 */
373
QGeoMapMapboxGL(QGeoMappingManagerEngineMapboxGL * engine,QObject * parent)374 QGeoMapMapboxGL::QGeoMapMapboxGL(QGeoMappingManagerEngineMapboxGL *engine, QObject *parent)
375 : QGeoMap(*new QGeoMapMapboxGLPrivate(engine), parent), m_engine(engine)
376 {
377 Q_D(QGeoMapMapboxGL);
378
379 connect(&d->m_refresh, &QTimer::timeout, this, &QGeoMap::sgNodeChanged);
380 d->m_refresh.setInterval(250);
381 }
382
~QGeoMapMapboxGL()383 QGeoMapMapboxGL::~QGeoMapMapboxGL()
384 {
385 }
386
copyrightsStyleSheet() const387 QString QGeoMapMapboxGL::copyrightsStyleSheet() const
388 {
389 return QStringLiteral("* { vertical-align: middle; font-weight: normal }");
390 }
391
setMapboxGLSettings(const QMapboxGLSettings & settings,bool useChinaEndpoint)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("Mapbox China requires an access token: https://www.mapbox.com/contact/sales");
404 } else {
405 d->m_settings.setAccessToken(developmentToken);
406 }
407 }
408 }
409
setUseFBO(bool useFBO)410 void QGeoMapMapboxGL::setUseFBO(bool useFBO)
411 {
412 Q_D(QGeoMapMapboxGL);
413 d->m_useFBO = useFBO;
414 }
415
setMapItemsBefore(const QString & before)416 void QGeoMapMapboxGL::setMapItemsBefore(const QString &before)
417 {
418 Q_D(QGeoMapMapboxGL);
419 d->m_mapItemsBefore = before;
420 }
421
capabilities() const422 QGeoMap::Capabilities QGeoMapMapboxGL::capabilities() const
423 {
424 return Capabilities(SupportsVisibleRegion
425 | SupportsSetBearing
426 | SupportsAnchoringCoordinate
427 | SupportsVisibleArea );
428 }
429
updateSceneGraph(QSGNode * oldNode,QQuickWindow * window)430 QSGNode *QGeoMapMapboxGL::updateSceneGraph(QSGNode *oldNode, QQuickWindow *window)
431 {
432 Q_D(QGeoMapMapboxGL);
433 return d->updateSceneGraph(oldNode, window);
434 }
435
onMapChanged(QMapboxGL::MapChange change)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, d->m_mapItemsBefore);
448
449 for (QGeoMapParameter *param : d->m_mapParameters)
450 d->m_styleChanges << QMapboxGLStyleChange::addMapParameter(param);
451 }
452 }
453
onMapItemPropertyChanged()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
onMapItemSubPropertyChanged()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
onMapItemUnsupportedPropertyChanged()475 void QGeoMapMapboxGL::onMapItemUnsupportedPropertyChanged()
476 {
477 // TODO https://bugreports.qt.io/browse/QTBUG-58872
478 qWarning() << "Unsupported property for managed Map item";
479 }
480
onMapItemGeometryChanged()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
onParameterPropertyUpdated(QGeoMapParameter * param,const char *)491 void QGeoMapMapboxGL::onParameterPropertyUpdated(QGeoMapParameter *param, const char *)
492 {
493 Q_D(QGeoMapMapboxGL);
494
495 d->m_styleChanges.append(QMapboxGLStyleChange::addMapParameter(param));
496
497 emit sgNodeChanged();
498 }
499
copyrightsChanged(const QString & copyrightsHtml)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("<a href='https://www.mapbox.com/pricing'>"
508 + tr("Development access token, do not use in production.") + "</a> - ");
509 }
510
511 if (d->m_activeMapType.name().startsWith("mapbox://")) {
512 copyrightsHtmlFinal = "<table><tr><th><img src='qrc:/mapboxgl/logo.png'/></th><th>"
513 + copyrightsHtmlFinal + "</th></tr></table>";
514 }
515
516 QGeoMap::copyrightsChanged(copyrightsHtmlFinal);
517 }
518