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