1/****************************************************************************
2**
3** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com>
4** Copyright (C) 2015 The Qt Company Ltd.
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 "qdeclarativegeomapcopyrightsnotice_p.h"
39
40#include <QtGui/QTextDocument>
41#include <QtGui/QAbstractTextDocumentLayout>
42#include <QtGui/QPainter>
43#include <QtQuick/private/qquickanchors_p.h>
44#include <QtQuick/private/qquickanchors_p_p.h>
45#include <QtLocation/private/qdeclarativegeomap_p.h>
46#include <QtQuick/private/qquickpainteditem_p.h>
47
48QT_BEGIN_NAMESPACE
49
50class QDeclarativeGeoMapCopyrightNoticePrivate: public QQuickPaintedItemPrivate
51{
52 Q_DECLARE_PUBLIC(QDeclarativeGeoMapCopyrightNotice)
53public:
54 virtual void setVisible(bool visible);
55};
56
57/*!
58 \qmltype MapCopyrightNotice
59 \instantiates QDeclarativeGeoMapCopyrightNotice
60 \inqmlmodule QtLocation
61 \ingroup qml-QtLocation5-maps
62 \since QtLocation 5.9
63
64 \brief The MapCopyrightNotice item displays the current valid
65 copyright notice for a Map element.
66
67 This object can be used to place an additional copyright notices
68 programmatically.
69
70 Note that declaring a MapCopyrightNotice inside a QtLocation::Map element
71 is not possible, like for any other QQuickItem.
72
73 The release of this API with Qt 5.9 is a Technology Preview.
74*/
75
76/*!
77 \qmlproperty Map QtLocation::MapCopyrightNotice::mapSource
78
79 This property holds the current map source providing the copyright data shown
80 in this notice.
81 In order to let the MapCopyrightNotice display a copyright, this property must
82 be set, as it is the only data source for this element.
83*/
84
85/*!
86 \qmlproperty string QtLocation::MapCopyrightNotice::styleSheet
87
88 This property holds the current css2.1 style sheet used to style the copyright notice, if in HTML form.
89
90 Example:
91 \code
92 MapCopyrightNotice {
93 mapSource: myMap
94 styleSheet: "body { color : green; font-family: \"Lucida\"; font-size: 8px} a{ font-size: 8px; color:#A62900}"
95 }
96 \endcode
97*/
98
99QDeclarativeGeoMapCopyrightNotice::QDeclarativeGeoMapCopyrightNotice(QQuickItem *parent)
100: QQuickPaintedItem(parent), m_copyrightsHtml(0), m_copyrightsVisible(true), m_mapSource(0),
101 m_userDefinedStyleSheet(false)
102{
103 // If this item is constructed inside the map, automatically anchor it where it always used to be.
104 if (qobject_cast<QDeclarativeGeoMap *>(object: parent))
105 anchorToBottomLeft();
106}
107
108QDeclarativeGeoMapCopyrightNotice::~QDeclarativeGeoMapCopyrightNotice()
109{
110 setMapSource(nullptr);
111}
112
113void QDeclarativeGeoMapCopyrightNotice::anchorToBottomLeft()
114{
115 if (!parent())
116 return;
117 QQuickAnchors *anchors = property(name: "anchors").value<QQuickAnchors *>();
118 if (anchors) {
119 anchors->setLeft(QQuickAnchorLine(qobject_cast<QQuickItem *>(object: parent()), QQuickAnchors::LeftAnchor));
120 anchors->setBottom(QQuickAnchorLine(qobject_cast<QQuickItem *>(object: parent()), QQuickAnchors::BottomAnchor));
121 }
122}
123
124void QDeclarativeGeoMapCopyrightNotice::setMapSource(QDeclarativeGeoMap *map)
125{
126 if (m_mapSource == map)
127 return;
128
129 if (m_mapSource) {
130 // disconnect this object from current map source
131 m_mapSource->detachCopyrightNotice(currentVisibility: copyrightsVisible());
132 m_mapSource->disconnect(receiver: this);
133 m_mapSource->m_map->disconnect(receiver: this);
134 if (m_copyrightsHtml)
135 m_copyrightsHtml->clear();
136 m_copyrightsImage = QImage();
137 m_mapSource = nullptr;
138 }
139
140 if (map) {
141 m_mapSource = map;
142 m_mapSource->attachCopyrightNotice(initialVisibility: copyrightsVisible());
143 connect(sender: this, signal: &QDeclarativeGeoMapCopyrightNotice::copyrightsVisibleChanged,
144 receiver: mapSource(), slot: &QDeclarativeGeoMap::onAttachedCopyrightNoticeVisibilityChanged);
145
146 // First update the copyright. Only Image will do here, no need to store HTML right away.
147 if (m_mapSource->m_copyrights && !m_mapSource->m_copyrights->m_copyrightsImage.isNull())
148 m_copyrightsImage = m_mapSource->m_copyrights->m_copyrightsImage;
149
150 connect(sender: mapSource(), SIGNAL(copyrightsChanged(QImage)),
151 receiver: this, SLOT(copyrightsChanged(QImage)));
152 connect(sender: mapSource(), SIGNAL(copyrightsChanged(QString)),
153 receiver: this, SLOT(copyrightsChanged(QString)));
154
155 if (m_mapSource->m_map)
156 connectMap();
157 else
158 connect(sender: mapSource(), signal: &QDeclarativeGeoMap::mapReadyChanged, receiver: this, slot: &QDeclarativeGeoMapCopyrightNotice::connectMap);
159 }
160}
161
162void QDeclarativeGeoMapCopyrightNotice::connectMap()
163{
164 connect(sender: m_mapSource->m_map, SIGNAL(copyrightsStyleSheetChanged(QString)),
165 receiver: this, SLOT(onCopyrightsStyleSheetChanged(QString)));
166 connect(sender: this, SIGNAL(linkActivated(QString)),
167 receiver: mapSource(), SIGNAL(copyrightLinkActivated(QString)));
168
169 onCopyrightsStyleSheetChanged(styleSheet: m_mapSource->m_map->copyrightsStyleSheet());
170
171 update();
172 emit mapSourceChanged();
173}
174
175QDeclarativeGeoMap *QDeclarativeGeoMapCopyrightNotice::mapSource()
176{
177 return m_mapSource.data();
178}
179
180QString QDeclarativeGeoMapCopyrightNotice::styleSheet() const
181{
182 return m_styleSheet;
183}
184
185void QDeclarativeGeoMapCopyrightNotice::setStyleSheet(const QString &styleSheet)
186{
187 m_userDefinedStyleSheet = true;
188
189 if (styleSheet == m_styleSheet)
190 return;
191
192 m_styleSheet = styleSheet;
193 if (!m_html.isEmpty() && m_copyrightsHtml) {
194 delete m_copyrightsHtml;
195 createCopyright();
196#if QT_CONFIG(texthtmlparser)
197 m_copyrightsHtml->setHtml(m_html);
198#else
199 m_copyrightsHtml->setPlainText(m_html);
200#endif
201 }
202 rasterizeHtmlAndUpdate();
203 emit styleSheetChanged(styleSheet: m_styleSheet);
204}
205
206/*!
207 \internal
208*/
209void QDeclarativeGeoMapCopyrightNotice::paint(QPainter *painter)
210{
211 painter->drawImage(x: 0, y: 0, image: m_copyrightsImage);
212}
213
214void QDeclarativeGeoMapCopyrightNotice::mousePressEvent(QMouseEvent *event)
215{
216 if (m_copyrightsHtml) {
217 m_activeAnchor = m_copyrightsHtml->documentLayout()->anchorAt(pos: event->pos());
218 if (!m_activeAnchor.isEmpty())
219 return;
220 }
221
222 QQuickPaintedItem::mousePressEvent(event);
223}
224
225void QDeclarativeGeoMapCopyrightNotice::mouseReleaseEvent(QMouseEvent *event)
226{
227 if (m_copyrightsHtml) {
228 QString anchor = m_copyrightsHtml->documentLayout()->anchorAt(pos: event->pos());
229 if (anchor == m_activeAnchor && !anchor.isEmpty()) {
230 emit linkActivated(link: anchor);
231 m_activeAnchor.clear();
232 }
233 }
234}
235
236void QDeclarativeGeoMapCopyrightNotice::rasterizeHtmlAndUpdate()
237{
238 if (!m_copyrightsHtml || m_copyrightsHtml->isEmpty())
239 return;
240
241 m_copyrightsImage = QImage(m_copyrightsHtml->size().toSize(),
242 QImage::Format_ARGB32_Premultiplied);
243
244 m_copyrightsImage.fill(pixel: qPremultiply(x: QColor(Qt::transparent).rgba()));
245 QPainter painter(&m_copyrightsImage);
246 QAbstractTextDocumentLayout::PaintContext ctx;
247 ctx.palette.setColor(acr: QPalette::Text, QStringLiteral("black"));
248 m_copyrightsHtml->documentLayout()->draw(painter: &painter, context: ctx);
249
250 setImplicitSize(m_copyrightsImage.width(), m_copyrightsImage.height());
251 setContentsSize(m_copyrightsImage.size());
252
253 setKeepMouseGrab(true);
254 setAcceptedMouseButtons(Qt::LeftButton);
255
256 update();
257}
258
259void QDeclarativeGeoMapCopyrightNotice::createCopyright()
260{
261 m_copyrightsHtml = new QTextDocument(this);
262#if QT_CONFIG(cssparser)
263 if (!m_styleSheet.isEmpty())
264 m_copyrightsHtml->setDefaultStyleSheet(m_styleSheet);
265#endif
266
267 // The default 4 makes the copyright too wide and tall.
268 m_copyrightsHtml->setDocumentMargin(0);
269}
270
271void QDeclarativeGeoMapCopyrightNoticePrivate::setVisible(bool visible)
272{
273 Q_Q(QDeclarativeGeoMapCopyrightNotice);
274 q->m_copyrightsVisible = visible;
275 QQuickItemPrivate::setVisible(visible);
276}
277
278/*!
279 \internal
280*/
281void QDeclarativeGeoMapCopyrightNotice::setCopyrightsVisible(bool visible)
282{
283 Q_D(QDeclarativeGeoMapCopyrightNotice);
284 if (visible == m_copyrightsVisible)
285 return;
286
287 m_copyrightsVisible = visible;
288 d->QQuickItemPrivate::setVisible(!m_copyrightsImage.isNull() && visible);
289 emit copyrightsVisibleChanged();
290}
291
292bool QDeclarativeGeoMapCopyrightNotice::copyrightsVisible() const
293{
294 return m_copyrightsVisible;
295}
296
297/*!
298 \internal
299*/
300void QDeclarativeGeoMapCopyrightNotice::setCopyrightsZ(qreal copyrightsZ)
301{
302 setZ(copyrightsZ);
303 update();
304}
305
306/*!
307 \internal
308*/
309void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QImage &copyrightsImage)
310{
311 Q_D(QDeclarativeGeoMapCopyrightNotice);
312 delete m_copyrightsHtml;
313 m_copyrightsHtml = 0;
314
315 m_copyrightsImage = copyrightsImage;
316
317 setImplicitSize(m_copyrightsImage.width(), m_copyrightsImage.height());
318
319 setKeepMouseGrab(false);
320 setAcceptedMouseButtons(Qt::NoButton);
321 d->QQuickItemPrivate::setVisible(m_copyrightsVisible && !m_copyrightsImage.isNull());
322
323 update();
324}
325
326void QDeclarativeGeoMapCopyrightNotice::copyrightsChanged(const QString &copyrightsHtml)
327{
328 Q_D(QDeclarativeGeoMapCopyrightNotice);
329 if (copyrightsHtml.isEmpty()) {
330 d->QQuickItemPrivate::setVisible(false);
331 return;
332 } else {
333 d->QQuickItemPrivate::setVisible(m_copyrightsVisible);
334 }
335
336 // Divfy, so we can style the background. The extra <span> is a
337 // workaround to QTBUG-58838 and should be removed when it gets fixed.
338#if QT_CONFIG(texthtmlparser)
339 m_html = QStringLiteral("<div id='copyright-root'><span>") + copyrightsHtml + QStringLiteral("</span></div>");
340#else
341 m_html = copyrightsHtml;
342#endif
343
344 if (!m_copyrightsHtml)
345 createCopyright();
346
347#if QT_CONFIG(texthtmlparser)
348 m_copyrightsHtml->setHtml(m_html);
349#else
350 m_copyrightsHtml->setPlainText(m_html);
351#endif
352 rasterizeHtmlAndUpdate();
353}
354
355void QDeclarativeGeoMapCopyrightNotice::onCopyrightsStyleSheetChanged(const QString &styleSheet)
356{
357 if (m_userDefinedStyleSheet || styleSheet == m_styleSheet)
358 return;
359
360 m_styleSheet = styleSheet;
361 if (!m_html.isEmpty() && m_copyrightsHtml) {
362 delete m_copyrightsHtml;
363 createCopyright();
364#if QT_CONFIG(texthtmlparser)
365 m_copyrightsHtml->setHtml(m_html);
366#else
367 m_copyrightsHtml->setPlainText(m_html);
368#endif
369 }
370 rasterizeHtmlAndUpdate();
371 emit styleSheetChanged(styleSheet: m_styleSheet);
372}
373
374QT_END_NAMESPACE
375

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