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
45 QT_BEGIN_NAMESPACE
46
QGeoMapViewportChangeEvent()47 QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent()
48 : zoomLevelChanged(false),
49 centerChanged(false),
50 mapSizeChanged(false),
51 tiltChanged(false),
52 bearingChanged(false),
53 rollChanged(false)
54 {
55 }
56
QGeoMapViewportChangeEvent(const QGeoMapViewportChangeEvent & other)57 QGeoMapViewportChangeEvent::QGeoMapViewportChangeEvent(const QGeoMapViewportChangeEvent &other)
58 {
59 this->operator=(other);
60 }
61
operator =(const QGeoMapViewportChangeEvent & other)62 QGeoMapViewportChangeEvent &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
QDeclarativeGeoMapItemBase(QQuickItem * parent)79 QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent)
80 : QQuickItem(parent), map_(0), quickMap_(0), parentGroup_(0)
81 {
82 setFiltersChildMouseEvents(true);
83 connect(this, SIGNAL(childrenChanged()),
84 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(this, &QQuickItem::opacityChanged, this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
88 }
89
~QDeclarativeGeoMapItemBase()90 QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase()
91 {
92 disconnect(this, SLOT(afterChildrenChanged()));
93 if (quickMap_)
94 quickMap_->removeMapItem(this);
95 }
96
97 /*!
98 \internal
99 */
afterChildrenChanged()100 void 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 *>(i)) {
108 if (!printedWarning) {
109 qmlWarning(this) << "Geographic map items do not support child items";
110 printedWarning = true;
111 }
112
113 qmlWarning(i) << "deleting this child";
114 i->deleteLater();
115 }
116 }
117 }
118 }
119
120 /*!
121 \internal
122 */
setMap(QDeclarativeGeoMap * quickMap,QGeoMap * map)123 void 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 */
baseCameraDataChanged(const QGeoCameraData & cameraData)145 void 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(evt);
169 }
170
visibleAreaChanged()171 void QDeclarativeGeoMapItemBase::visibleAreaChanged()
172 {
173 QGeoMapViewportChangeEvent evt;
174 evt.mapSize = QSizeF(quickMap_->width(), quickMap_->height());
175 afterViewportChanged(evt);
176 }
177
178 /*!
179 \internal
180 */
setPositionOnMap(const QGeoCoordinate & coordinate,const QPointF & offset)181 void 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, false);
195 if (qIsNaN(pos.x()))
196 return;
197 }
198
199 QPointF topLeft = pos.toPointF() - offset;
200
201 setPosition(topLeft);
202 }
203
autoFadeIn() const204 bool QDeclarativeGeoMapItemBase::autoFadeIn() const
205 {
206 return m_autoFadeIn;
207 }
208
209 static const double opacityRampMin = 1.5;
210 static const double opacityRampMax = 2.5;
211
setAutoFadeIn(bool fadeIn)212 void 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
lodThreshold() const221 int QDeclarativeGeoMapItemBase::lodThreshold() const
222 {
223 return m_lodThreshold;
224 }
225
setLodThreshold(int lt)226 void 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 */
zoomForLOD(int zoom) const241 unsigned 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 */
zoomLevelOpacity() const251 float 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
childMouseEventFilter(QQuickItem * item,QEvent * event)263 bool QDeclarativeGeoMapItemBase::childMouseEventFilter(QQuickItem *item, QEvent *event)
264 {
265 Q_UNUSED(item);
266 if (event->type() == QEvent::MouseButtonPress && !contains(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 */
updatePaintNode(QSGNode * oldNode,UpdatePaintNodeData * pd)284 QSGNode *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(n);
305 } else {
306 delete oldN;
307 }
308
309 return opn;
310 }
311
312 /*!
313 \internal
314 */
updateMapItemPaintNode(QSGNode * oldNode,UpdatePaintNodeData *)315 QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
316 {
317 delete oldNode;
318 return 0;
319 }
320
itemType() const321 QGeoMap::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 */
mapItemOpacity() const332 qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const
333 {
334 if (parentGroup_)
335 return parentGroup_->mapItemOpacity() * opacity();
336 return opacity();
337 }
338
setParentGroup(QDeclarativeGeoMapItemGroup & parentGroup)339 void QDeclarativeGeoMapItemBase::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup)
340 {
341 parentGroup_ = &parentGroup;
342 if (parentGroup_) {
343 connect(parentGroup_, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged,
344 this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged);
345 }
346 }
347
isPolishScheduled() const348 bool QDeclarativeGeoMapItemBase::isPolishScheduled() const
349 {
350 return QQuickItemPrivate::get(this)->polishScheduled;
351 }
352
setMaterialDirty()353 void QDeclarativeGeoMapItemBase::setMaterialDirty() {}
354
polishAndUpdate()355 void QDeclarativeGeoMapItemBase::polishAndUpdate()
356 {
357 polish();
358 update();
359 }
360
361 QT_END_NAMESPACE
362