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 "qdeclarativegeomapitembase_p.h"
38#include "qgeocameradata_p.h"
39#include <QtLocation/private/qgeomap_p.h>
40#include <QtQml/QQmlInfo>
41#include <QtQuick/QSGOpacityNode>
42#include <QtQuick/private/qquickmousearea_p.h>
43#include <QtQuick/private/qquickitem_p.h>
44
45QT_BEGIN_NAMESPACE
46
47QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent()
48 : zoomLevelChanged(false),
49 centerChanged(false),
50 mapSizeChanged(false),
51 tiltChanged(false),
52 bearingChanged(false),
53 rollChanged(false)
54{
55}
56
57QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent(const QGeoMapViewportChangeEvent &other)
58{
59 this->operator=(other);
60}
61
62QGeoMapViewportChangeEvent &QGeoMapViewportChangeEvent::operator=(const QGeoMapViewportChangeEvent &other)
63{
64 if (this == &other)
65 return (*this);
66
67 cameraData = other.cameraData;
68 mapSize = other.mapSize;
69 zoomLevelChanged = other.zoomLevelChanged;
70 centerChanged = other.centerChanged;
71 mapSizeChanged = other.mapSizeChanged;
72 tiltChanged = other.tiltChanged;
73 bearingChanged = other.bearingChanged;
74 rollChanged = other.rollChanged;
75
76 return (*this);
77}
78
79QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent)
80: QQuickItem(parent), map_(0), quickMap_(0), parentGroup_(0)
81{
82 setFiltersChildMouseEvents(true);
83 connect(sender: this, SIGNAL(childrenChanged()),
84 receiver: this, SLOT(afterChildrenChanged()));
85 // Changing opacity on a mapItemGroup should affect also the opacity on the children.
86 // This must be notified to plugins, if they are to render the item.
87 connect(sender: this, signal: &QQuickItem::opacityChanged, receiver: this, slot: &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
88}
89
90QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase()
91{
92 disconnect(receiver: this, SLOT(afterChildrenChanged()));
93 if (quickMap_)
94 quickMap_->removeMapItem(item: this);
95}
96
97/*!
98 \internal
99*/
100void QDeclarativeGeoMapItemBase::afterChildrenChanged()
101{
102 QList<QQuickItem *> kids = childItems();
103 if (kids.size() > 0) {
104 bool printedWarning = false;
105 foreach (QQuickItem *i, kids) {
106 if (i->flags() & QQuickItem::ItemHasContents
107 && !qobject_cast<QQuickMouseArea *>(object: i)) {
108 if (!printedWarning) {
109 qmlWarning(me: this) << "Geographic map items do not support child items";
110 printedWarning = true;
111 }
112
113 qmlWarning(me: i) << "deleting this child";
114 i->deleteLater();
115 }
116 }
117 }
118}
119
120/*!
121 \internal
122*/
123void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
124{
125 if (quickMap == quickMap_)
126 return;
127 if (quickMap && quickMap_)
128 return; // don't allow association to more than one map
129
130 quickMap_ = quickMap;
131 map_ = map;
132
133 if (map_ && quickMap_) {
134 // For performance reasons we're not connecting map_'s and quickMap_'s signals to this.
135 // Rather, the handling of cameraDataChanged, visibleAreaChanged, heightChanged and widthChanged is done explicitly in QDeclarativeGeoMap by directly calling methods on the items.
136 // See QTBUG-76950
137 lastSize_ = QSizeF(quickMap_->width(), quickMap_->height());
138 lastCameraData_ = map_->cameraData();
139 }
140}
141
142/*!
143 \internal
144*/
145void QDeclarativeGeoMapItemBase::baseCameraDataChanged(const QGeoCameraData &cameraData)
146{
147 QGeoMapViewportChangeEvent evt;
148 evt.cameraData = cameraData;
149 evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
150
151 if (evt.mapSize != lastSize_)
152 evt.mapSizeChanged = true;
153
154 if (cameraData.bearing() != lastCameraData_.bearing())
155 evt.bearingChanged = true;
156 if (cameraData.center() != lastCameraData_.center())
157 evt.centerChanged = true;
158 if (cameraData.roll() != lastCameraData_.roll())
159 evt.rollChanged = true;
160 if (cameraData.tilt() != lastCameraData_.tilt())
161 evt.tiltChanged = true;
162 if (cameraData.zoomLevel() != lastCameraData_.zoomLevel())
163 evt.zoomLevelChanged = true;
164
165 lastSize_ = evt.mapSize;
166 lastCameraData_ = cameraData;
167
168 afterViewportChanged(event: evt);
169}
170
171void QDeclarativeGeoMapItemBase::visibleAreaChanged()
172{
173 QGeoMapViewportChangeEvent evt;
174 evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
175 afterViewportChanged(event: evt);
176}
177
178/*!
179 \internal
180*/
181void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset)
182{
183 if (!map_ || !quickMap_)
184 return;
185
186 QDoubleVector2D pos;
187 if (map()->geoProjection().projectionType() == QGeoProjection::ProjectionWebMercator) {
188 const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map()->geoProjection());
189 QDoubleVector2D wrappedProjection = p.geoToWrappedMapProjection(coordinate);
190 if (!p.isProjectable(wrappedProjection))
191 return;
192 pos = p.wrappedMapProjectionToItemPosition(wrappedProjection);
193 } else {
194 pos = map()->geoProjection().coordinateToItemPosition(coordinate, clipToViewport: false);
195 if (qIsNaN(d: pos.x()))
196 return;
197 }
198
199 QPointF topLeft = pos.toPointF() - offset;
200
201 setPosition(topLeft);
202}
203
204bool QDeclarativeGeoMapItemBase::autoFadeIn() const
205{
206 return m_autoFadeIn;
207}
208
209static const double opacityRampMin = 1.5;
210static const double opacityRampMax = 2.5;
211
212void QDeclarativeGeoMapItemBase::setAutoFadeIn(bool fadeIn)
213{
214 if (fadeIn == m_autoFadeIn)
215 return;
216 m_autoFadeIn = fadeIn;
217 if (quickMap_ && quickMap_->zoomLevel() < opacityRampMax)
218 polishAndUpdate();
219}
220
221int QDeclarativeGeoMapItemBase::lodThreshold() const
222{
223 return m_lodThreshold;
224}
225
226void QDeclarativeGeoMapItemBase::setLodThreshold(int lt)
227{
228 if (lt == m_lodThreshold)
229 return;
230 m_lodThreshold = lt;
231 update();
232}
233
234/*!
235 \internal
236
237 This returns the zoom level to be used when requesting the LOD.
238 Essentially it clamps to m_lodThreshold, and if above, it selects
239 a ZL higher than the maximum LODable level.
240*/
241unsigned int QDeclarativeGeoMapItemBase::zoomForLOD(int zoom) const
242{
243 if (zoom >= m_lodThreshold)
244 return 30; // some arbitrarily large zoom
245 return uint(zoom);
246}
247
248/*!
249 \internal
250*/
251float QDeclarativeGeoMapItemBase::zoomLevelOpacity() const
252{
253 if (!m_autoFadeIn) // Consider skipping the opacity node instead.
254 return 1.0;
255 else if (quickMap_->zoomLevel() > opacityRampMax)
256 return 1.0;
257 else if (quickMap_->zoomLevel() > opacityRampMin)
258 return quickMap_->zoomLevel() - opacityRampMin;
259 else
260 return 0.0;
261}
262
263bool QDeclarativeGeoMapItemBase::childMouseEventFilter(QQuickItem *item, QEvent *event)
264{
265 Q_UNUSED(item);
266 if (event->type() == QEvent::MouseButtonPress && !contains(point: static_cast<QMouseEvent*>(event)->pos())) {
267 // In case of items that are not rectangles, this filter is used to test if the event has landed
268 // inside the actual item shape.
269 // If so, the method returns true, meaning that it prevents the event delivery to child "*item" (for example,
270 // a mouse area that is on top of this map item).
271 // However, this method sets "accepted" to false, so that the event can still be passed further up,
272 // specifically to the parent Map, that is a sort of flickable.
273 // Otherwise, if the event is not contained within the map item, the method returns false, meaning the event
274 // is delivered to the child *item (like the mouse area associated).
275 event->setAccepted(false);
276 return true;
277 }
278 return false;
279}
280
281/*!
282 \internal
283*/
284QSGNode *QDeclarativeGeoMapItemBase::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *pd)
285{
286 if (!map_ || !quickMap_ || map_->supportedMapItemTypes() & itemType()) {
287 if (oldNode)
288 delete oldNode;
289 oldNode = 0;
290 return 0;
291 }
292
293 QSGOpacityNode *opn = static_cast<QSGOpacityNode *>(oldNode);
294 if (!opn)
295 opn = new QSGOpacityNode();
296
297 opn->setOpacity(zoomLevelOpacity());
298
299 QSGNode *oldN = opn->childCount() ? opn->firstChild() : 0;
300 opn->removeAllChildNodes();
301 if (opn->opacity() > 0.0) {
302 QSGNode *n = this->updateMapItemPaintNode(oldN, pd);
303 if (n)
304 opn->appendChildNode(node: n);
305 } else {
306 delete oldN;
307 }
308
309 return opn;
310}
311
312/*!
313 \internal
314*/
315QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
316{
317 delete oldNode;
318 return 0;
319}
320
321QGeoMap::ItemType QDeclarativeGeoMapItemBase::itemType() const
322{
323 return m_itemType;
324}
325
326/*!
327 \internal
328
329 The actual combined opacity of the item. Needed by custom renderer to look like
330 the scene-graph one.
331*/
332qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const
333{
334 if (parentGroup_)
335 return parentGroup_->mapItemOpacity() * opacity();
336 return opacity();
337}
338
339void QDeclarativeGeoMapItemBase::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup)
340{
341 parentGroup_ = &parentGroup;
342 if (parentGroup_) {
343 connect(sender: parentGroup_, signal: &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged,
344 receiver: this, slot: &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
345 }
346}
347
348bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
349{
350 return QQuickItemPrivate::get(item: this)->polishScheduled;
351}
352
353void QDeclarativeGeoMapItemBase::setMaterialDirty() {}
354
355void QDeclarativeGeoMapItemBase::polishAndUpdate()
356{
357 polish();
358 update();
359}
360
361QT_END_NAMESPACE
362

source code of qtlocation/src/location/declarativemaps/qdeclarativegeomapitembase.cpp