1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 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 "qmapiconobjectqsg_p_p.h"
38 #include <QtQuick/qsgimagenode.h>
39 #include <QtQuick/qsgnode.h>
40 #include <QtQuick/private/qquickimage_p.h>
41 #include <QtQuick/qquickimageprovider.h>
42 #include <QtQuick/qquickwindow.h>
43 #include <QtQml/qqmlengine.h>
44 #include <QtQml/qqml.h>
45 #include <QtNetwork/qnetworkaccessmanager.h>
46 #include <QtLocation/private/qdeclarativepolylinemapitem_p.h>
47
48 QT_BEGIN_NAMESPACE
49
50 class RootNode : public QSGTransformNode, public VisibleNode
51 {
52 public:
RootNode()53 RootNode() { }
54
isSubtreeBlocked() const55 bool isSubtreeBlocked() const override
56 {
57 return subtreeBlocked();
58 }
59 };
60
QMapIconObjectPrivateQSG(QGeoMapObject * q)61 QMapIconObjectPrivateQSG::QMapIconObjectPrivateQSG(QGeoMapObject *q)
62 : QMapIconObjectPrivateDefault(q)
63 {
64
65 }
66
QMapIconObjectPrivateQSG(const QMapIconObjectPrivate & other)67 QMapIconObjectPrivateQSG::QMapIconObjectPrivateQSG(const QMapIconObjectPrivate &other)
68 : QMapIconObjectPrivateDefault(other)
69 {
70 // Data already cloned by the *Default copy constructor, but necessary
71 // update operations triggered only by setters overrides
72 setContent(content());
73 // setCoordinate(coordinate());
74 }
75
~QMapIconObjectPrivateQSG()76 QMapIconObjectPrivateQSG::~QMapIconObjectPrivateQSG()
77 {
78 if (m_map)
79 m_map->removeMapObject(q);
80 }
81
updateGeometry()82 void QMapIconObjectPrivateQSG::updateGeometry()
83 {
84 if (!m_map)
85 return;
86
87 m_geometryDirty = true;
88 const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
89
90 m_itemPosition = p.coordinateToItemPosition(coordinate());
91 if (m_itemPosition.isFinite()) {
92 m_transformation.setToIdentity();
93 m_transformation.translate(QVector3D(m_itemPosition.x(), m_itemPosition.y(), 0));
94 }
95
96 // TODO: support and test for zoomLevel
97 }
98
updateMapObjectNode(QSGNode * oldNode,VisibleNode ** visibleNode,QSGNode * root,QQuickWindow * window)99 QSGNode *QMapIconObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
100 VisibleNode **visibleNode,
101 QSGNode *root,
102 QQuickWindow *window)
103 {
104 Q_UNUSED(visibleNode);
105 RootNode *node = static_cast<RootNode *>(oldNode);
106 if (!node) {
107 node = new RootNode();
108 m_imageNode = window->createImageNode();
109 m_imageNode->setOwnsTexture(true);
110 node->appendChildNode(m_imageNode);
111 *visibleNode = static_cast<VisibleNode *>(node);
112 }
113
114 if (m_imageDirty) {
115 m_imageDirty = false;
116 m_imageNode->setTexture(window->createTextureFromImage(m_image));
117 QRect rect = m_image.rect();
118 m_imageNode->setSourceRect(rect);
119 m_imageNode->setRect(QRectF(QPointF(0,0), iconSize()));
120 }
121
122 if (m_geometryDirty) {
123 m_geometryDirty = false;
124 if (!m_itemPosition.isFinite()) {
125 node->setSubtreeBlocked(true);
126 } else {
127 node->setSubtreeBlocked(false);
128 node->setMatrix(m_transformation);
129 }
130 }
131
132 root->appendChildNode(node);
133
134 return node;
135 }
136
setCoordinate(const QGeoCoordinate & coordinate)137 void QMapIconObjectPrivateQSG::setCoordinate(const QGeoCoordinate &coordinate)
138 {
139 QMapIconObjectPrivateDefault::setCoordinate(coordinate);
140 updateGeometry();
141 }
142
143 template<typename T>
getContent(const QVariant & content)144 static T *getContent(const QVariant &content)
145 {
146 QObject *obj = qvariant_cast<QObject *>(content);
147 return qobject_cast<T *>(obj);
148 }
149
imageId(const QUrl & url)150 static inline QString imageId(const QUrl &url)
151 {
152 return url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
153 }
154
clearContent()155 void QMapIconObjectPrivateQSG::clearContent()
156 {
157 m_image = QImage();
158 }
159
setContent(const QVariant & content)160 void QMapIconObjectPrivateQSG::setContent(const QVariant &content)
161 {
162 // First reset all local containers
163 clearContent();
164 QQmlEngine *engine = qmlEngine(q);
165
166 // Then pull the new content
167 QMapIconObjectPrivateDefault::setContent(content);
168 switch (content.type()) {
169 case QVariant::UserType: {
170 // TODO: Handle QObject subclasses -- first decide which ones
171 break;
172 }
173 case QVariant::String:
174 case QVariant::Url: {
175 // URL, including image/texture providers
176 // Supporting only image providers for now
177 const QUrl url = content.toUrl();
178 if (!url.isValid()) {
179 m_image = QImage(content.toString());
180 m_imageDirty = true;
181 updateGeometry();
182 } else if (url.scheme().isEmpty() || url.scheme() == QLatin1String("file")) {
183 m_image = QImage(url.toString(QUrl::RemoveScheme));
184 m_imageDirty = true;
185 updateGeometry();
186 } else if (url.scheme() == QLatin1String("image")) {
187 QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(url.host()));
188 QSize outSize;
189 m_image = provider->requestImage(imageId(url), &outSize, QSize());
190 if (outSize.isEmpty())
191 break;
192 m_imageDirty = true;
193 updateGeometry();
194 } else { // ToDo: Use QNAM
195
196 }
197
198 break;
199 }
200 case QVariant::ByteArray: {
201 // ToDo: Build the image from bytearray
202 break;
203 }
204 default:
205 qWarning() << "Unsupported parameter type: " << content.type();
206 break;
207 }
208
209 if (m_map && m_imageDirty)
210 emit m_map->sgNodeChanged();
211 }
212
setIconSize(const QSizeF & size)213 void QMapIconObjectPrivateQSG::setIconSize(const QSizeF &size)
214 {
215 QMapIconObjectPrivateDefault::setIconSize(size);
216 updateGeometry();
217 }
218
clone()219 QGeoMapObjectPrivate *QMapIconObjectPrivateQSG::clone()
220 {
221 return new QMapIconObjectPrivateQSG(static_cast<QMapIconObjectPrivate &>(*this));
222 }
223
224 QT_END_NAMESPACE
225