1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSvg module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41#include "qgraphicssvgitem.h"
42
43#ifndef QT_NO_GRAPHICSSVGITEM
44
45#include "qpainter.h"
46#include "qstyleoption.h"
47#include "qsvgrenderer.h"
48#include "qdebug.h"
49
50#include "private/qobject_p.h"
51#include "private/qgraphicsitem_p.h"
52
53QT_BEGIN_NAMESPACE
54
55class QGraphicsSvgItemPrivate : public QGraphicsItemPrivate
56{
57public:
58 Q_DECLARE_PUBLIC(QGraphicsSvgItem)
59
60 QGraphicsSvgItemPrivate()
61 : renderer(0), shared(false)
62 {
63 }
64
65 void init(QGraphicsItem *parent)
66 {
67 Q_Q(QGraphicsSvgItem);
68 q->setParentItem(parent);
69 renderer = new QSvgRenderer(q);
70 QObject::connect(renderer, SIGNAL(repaintNeeded()),
71 q, SLOT(_q_repaintItem()));
72 q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
73 q->setMaximumCacheSize(QSize(1024, 768));
74 }
75
76 void _q_repaintItem()
77 {
78 q_func()->update();
79 }
80
81 inline void updateDefaultSize()
82 {
83 QRectF bounds;
84 if (elemId.isEmpty()) {
85 bounds = QRectF(QPointF(0, 0), renderer->defaultSize());
86 } else {
87 bounds = renderer->boundsOnElement(elemId);
88 }
89 if (boundingRect.size() != bounds.size()) {
90 q_func()->prepareGeometryChange();
91 boundingRect.setSize(bounds.size());
92 }
93 }
94
95 QSvgRenderer *renderer;
96 QRectF boundingRect;
97 bool shared;
98 QString elemId;
99};
100
101/*!
102 \class QGraphicsSvgItem
103 \ingroup graphicsview-api
104 \brief The QGraphicsSvgItem class is a QGraphicsItem that can be used to render
105 the contents of SVG files.
106
107 \since 4.2
108
109 QGraphicsSvgItem provides a way of rendering SVG files onto QGraphicsView.
110 QGraphicsSvgItem can be created by passing the SVG file to be rendered to
111 its constructor or by explicit setting a shared QSvgRenderer on it.
112
113 Note that setting QSvgRenderer on a QGraphicsSvgItem doesn't make the item take
114 ownership of the renderer, therefore if using setSharedRenderer() method one has
115 to make sure that the lifetime of the QSvgRenderer object will be at least as long
116 as that of the QGraphicsSvgItem.
117
118 QGraphicsSvgItem provides a way of rendering only parts of the SVG files via
119 the setElementId. If setElementId() method is called, only the SVG element
120 (and its children) with the passed id will be renderer. This provides a convenient
121 way of selectively rendering large SVG files that contain a number of discrete
122 elements. For example the following code renders only jokers from a SVG file
123 containing a whole card deck:
124
125 \snippet doc/src/snippets/code/src_svg_qgraphicssvgitem.cpp 0
126
127 Size of the item can be set via the \l{QRectF::setSize()}
128 {setSize()} method of the \l{QGraphicsSvgItem::boundingRect()}
129 {bounding rectangle} or via direct manipulation of the items
130 transformation matrix.
131
132 By default the SVG rendering is cached using QGraphicsItem::DeviceCoordinateCache
133 mode to speedup the display of items. Caching can be disabled by passing
134 QGraphicsItem::NoCache to the QGraphicsItem::setCacheMode() method.
135
136 \sa QSvgWidget, {QtSvg Module}, QGraphicsItem, QGraphicsView
137*/
138
139/*!
140 Constructs a new SVG item with the given \a parent.
141*/
142QGraphicsSvgItem::QGraphicsSvgItem(QGraphicsItem *parent)
143 : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0, 0)
144{
145 Q_D(QGraphicsSvgItem);
146 d->init(parent);
147}
148
149/*!
150 Constructs a new item with the given \a parent and loads the contents of the
151 SVG file with the specified \a fileName.
152*/
153QGraphicsSvgItem::QGraphicsSvgItem(const QString &fileName, QGraphicsItem *parent)
154 : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0, 0)
155{
156 Q_D(QGraphicsSvgItem);
157 d->init(parent);
158 d->renderer->load(fileName);
159 d->updateDefaultSize();
160}
161
162/*!
163 Returns the currently use QSvgRenderer.
164*/
165QSvgRenderer *QGraphicsSvgItem::renderer() const
166{
167 return d_func()->renderer;
168}
169
170
171/*!
172 Returns the bounding rectangle of this item.
173*/
174QRectF QGraphicsSvgItem::boundingRect() const
175{
176 Q_D(const QGraphicsSvgItem);
177 return d->boundingRect;
178}
179
180/*!
181 \internal
182
183 Highlights \a item as selected.
184
185 NOTE: This function is a duplicate of qt_graphicsItem_highlightSelected() in qgraphicsitem.cpp!
186*/
187static void qt_graphicsItem_highlightSelected(
188 QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option)
189{
190 const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1));
191 if (qFuzzyIsNull(qMax(murect.width(), murect.height())))
192 return;
193
194 const QRectF mbrect = painter->transform().mapRect(item->boundingRect());
195 if (qMin(mbrect.width(), mbrect.height()) < qreal(1.0))
196 return;
197
198 qreal itemPenWidth;
199 switch (item->type()) {
200 case QGraphicsEllipseItem::Type:
201 itemPenWidth = static_cast<QGraphicsEllipseItem *>(item)->pen().widthF();
202 break;
203 case QGraphicsPathItem::Type:
204 itemPenWidth = static_cast<QGraphicsPathItem *>(item)->pen().widthF();
205 break;
206 case QGraphicsPolygonItem::Type:
207 itemPenWidth = static_cast<QGraphicsPolygonItem *>(item)->pen().widthF();
208 break;
209 case QGraphicsRectItem::Type:
210 itemPenWidth = static_cast<QGraphicsRectItem *>(item)->pen().widthF();
211 break;
212 case QGraphicsSimpleTextItem::Type:
213 itemPenWidth = static_cast<QGraphicsSimpleTextItem *>(item)->pen().widthF();
214 break;
215 case QGraphicsLineItem::Type:
216 itemPenWidth = static_cast<QGraphicsLineItem *>(item)->pen().widthF();
217 break;
218 default:
219 itemPenWidth = 1.0;
220 }
221 const qreal pad = itemPenWidth / 2;
222
223 const qreal penWidth = 0; // cosmetic pen
224
225 const QColor fgcolor = option->palette.windowText().color();
226 const QColor bgcolor( // ensure good contrast against fgcolor
227 fgcolor.red() > 127 ? 0 : 255,
228 fgcolor.green() > 127 ? 0 : 255,
229 fgcolor.blue() > 127 ? 0 : 255);
230
231 painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine));
232 painter->setBrush(Qt::NoBrush);
233 painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
234
235 painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine));
236 painter->setBrush(Qt::NoBrush);
237 painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
238}
239
240/*!
241 \reimp
242*/
243void QGraphicsSvgItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
244 QWidget *widget)
245{
246// Q_UNUSED(option);
247 Q_UNUSED(widget);
248
249 Q_D(QGraphicsSvgItem);
250 if (!d->renderer->isValid())
251 return;
252
253 if (d->elemId.isEmpty())
254 d->renderer->render(painter, d->boundingRect);
255 else
256 d->renderer->render(painter, d->elemId, d->boundingRect);
257
258 if (option->state & QStyle::State_Selected)
259 qt_graphicsItem_highlightSelected(this, painter, option);
260}
261
262/*!
263 \reimp
264*/
265int QGraphicsSvgItem::type() const
266{
267 return Type;
268}
269
270/*!
271 \property QGraphicsSvgItem::maximumCacheSize
272 \since 4.6
273
274 This property holds the maximum size of the device coordinate cache
275 for this item.
276 */
277
278/*!
279 Sets the maximum device coordinate cache size of the item to \a size.
280 If the item is cached using QGraphicsItem::DeviceCoordinateCache mode,
281 caching is bypassed if the extension of the item in device coordinates
282 is larger than \a size.
283
284 The cache corresponds to the QPixmap which is used to cache the
285 results of the rendering.
286 Use QPixmapCache::setCacheLimit() to set limitations on the whole cache
287 and use setMaximumCacheSize() when setting cache size for individual
288 items.
289
290 \sa QGraphicsItem::cacheMode()
291*/
292void QGraphicsSvgItem::setMaximumCacheSize(const QSize &size)
293{
294 QGraphicsItem::d_ptr->setExtra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize, size);
295 update();
296}
297
298/*!
299 Returns the current maximum size of the device coordinate cache for this item.
300 If the item is cached using QGraphicsItem::DeviceCoordinateCache mode,
301 caching is bypassed if the extension of the item in device coordinates
302 is larger than the maximum size.
303
304 The default maximum cache size is 1024x768.
305 QPixmapCache::cacheLimit() gives the
306 cumulative bounds of the whole cache, whereas maximumCacheSize() refers
307 to a maximum cache size for this particular item.
308
309 \sa QGraphicsItem::cacheMode()
310*/
311QSize QGraphicsSvgItem::maximumCacheSize() const
312{
313 return QGraphicsItem::d_ptr->extra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
314}
315
316/*!
317 \property QGraphicsSvgItem::elementId
318 \since 4.6
319
320 This property holds the element's XML ID.
321 */
322
323/*!
324 Sets the XML ID of the element to \a id.
325*/
326void QGraphicsSvgItem::setElementId(const QString &id)
327{
328 Q_D(QGraphicsSvgItem);
329 d->elemId = id;
330 d->updateDefaultSize();
331 update();
332}
333
334/*!
335 Returns the XML ID the element that is currently
336 being rendered. Returns an empty string if the whole
337 file is being rendered.
338*/
339QString QGraphicsSvgItem::elementId() const
340{
341 Q_D(const QGraphicsSvgItem);
342 return d->elemId;
343}
344
345/*!
346 Sets \a renderer to be a shared QSvgRenderer on the item. By
347 using this method one can share the same QSvgRenderer on a number
348 of items. This means that the SVG file will be parsed only once.
349 QSvgRenderer passed to this method has to exist for as long as
350 this item is used.
351*/
352void QGraphicsSvgItem::setSharedRenderer(QSvgRenderer *renderer)
353{
354 Q_D(QGraphicsSvgItem);
355 if (!d->shared)
356 delete d->renderer;
357
358 d->renderer = renderer;
359 d->shared = true;
360
361 d->updateDefaultSize();
362
363 update();
364}
365
366/*!
367 \obsolete
368
369 Use QGraphicsItem::setCacheMode() instead. Passing true to this function is equivalent
370 to QGraphicsItem::setCacheMode(QGraphicsItem::DeviceCoordinateCache).
371*/
372void QGraphicsSvgItem::setCachingEnabled(bool caching)
373{
374 setCacheMode(caching ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
375}
376
377/*!
378 \obsolete
379
380 Use QGraphicsItem::cacheMode() instead.
381*/
382bool QGraphicsSvgItem::isCachingEnabled() const
383{
384 return cacheMode() != QGraphicsItem::NoCache;
385}
386
387QT_END_NAMESPACE
388
389#include "moc_qgraphicssvgitem.cpp"
390
391#endif // QT_NO_GRAPHICSSVGITEM
392