1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qgraphicssvgitem.h"
4
5#if !defined(QT_NO_GRAPHICSVIEW)
6
7#include "qpainter.h"
8#include "qstyleoption.h"
9#include "qsvgrenderer.h"
10#include "qdebug.h"
11
12#include <QtCore/private/qobject_p.h>
13#include <QtWidgets/private/qgraphicsitem_p.h>
14
15QT_BEGIN_NAMESPACE
16
17class QGraphicsSvgItemPrivate : public QGraphicsItemPrivate
18{
19public:
20 Q_DECLARE_PUBLIC(QGraphicsSvgItem)
21
22 QGraphicsSvgItemPrivate()
23 : renderer(0), shared(false)
24 {
25 }
26
27 void init(QGraphicsItem *parent)
28 {
29 Q_Q(QGraphicsSvgItem);
30 q->setParentItem(parent);
31 renderer = new QSvgRenderer(q);
32 QObject::connect(sender: renderer, SIGNAL(repaintNeeded()),
33 receiver: q, SLOT(_q_repaintItem()));
34 q->setCacheMode(mode: QGraphicsItem::DeviceCoordinateCache);
35 q->setMaximumCacheSize(QSize(1024, 768));
36 }
37
38 void _q_repaintItem()
39 {
40 q_func()->update();
41 }
42
43 inline void updateDefaultSize()
44 {
45 QRectF bounds;
46 if (elemId.isEmpty()) {
47 bounds = QRectF(QPointF(0, 0), renderer->defaultSize());
48 } else {
49 bounds = renderer->boundsOnElement(id: elemId);
50 }
51 if (boundingRect.size() != bounds.size()) {
52 q_func()->prepareGeometryChange();
53 boundingRect.setSize(bounds.size());
54 }
55 }
56
57 QSvgRenderer *renderer;
58 QRectF boundingRect;
59 bool shared;
60 QString elemId;
61};
62
63/*!
64 \class QGraphicsSvgItem
65 \inmodule QtSvgWidgets
66 \ingroup graphicsview-api
67 \brief The QGraphicsSvgItem class is a QGraphicsItem that can be used to render
68 the contents of SVG files.
69
70 \since 4.2
71
72 QGraphicsSvgItem provides a way of rendering SVG files onto QGraphicsView.
73 QGraphicsSvgItem can be created by passing the SVG file to be rendered to
74 its constructor or by explicit setting a shared QSvgRenderer on it.
75
76 Note that setting QSvgRenderer on a QGraphicsSvgItem doesn't make the item take
77 ownership of the renderer, therefore if using setSharedRenderer() method one has
78 to make sure that the lifetime of the QSvgRenderer object will be at least as long
79 as that of the QGraphicsSvgItem.
80
81 QGraphicsSvgItem provides a way of rendering only parts of the SVG files via
82 the setElementId. If setElementId() method is called, only the SVG element
83 (and its children) with the passed id will be renderer. This provides a convenient
84 way of selectively rendering large SVG files that contain a number of discrete
85 elements. For example the following code renders only jokers from a SVG file
86 containing a whole card deck:
87
88 \snippet src_svg_qgraphicssvgitem.cpp 0
89
90 Size of the item can be set via direct manipulation of the items
91 transformation matrix.
92
93 By default the SVG rendering is cached using QGraphicsItem::DeviceCoordinateCache
94 mode to speedup the display of items. Caching can be disabled by passing
95 QGraphicsItem::NoCache to the QGraphicsItem::setCacheMode() method.
96
97 \sa QSvgWidget, {Qt SVG C++ Classes}, QGraphicsItem, QGraphicsView
98*/
99
100/*!
101 Constructs a new SVG item with the given \a parent.
102*/
103QGraphicsSvgItem::QGraphicsSvgItem(QGraphicsItem *parent)
104 : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0)
105{
106 Q_D(QGraphicsSvgItem);
107 d->init(parent);
108}
109
110/*!
111 Constructs a new item with the given \a parent and loads the contents of the
112 SVG file with the specified \a fileName.
113*/
114QGraphicsSvgItem::QGraphicsSvgItem(const QString &fileName, QGraphicsItem *parent)
115 : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0)
116{
117 Q_D(QGraphicsSvgItem);
118 d->init(parent);
119 d->renderer->load(filename: fileName);
120 d->updateDefaultSize();
121}
122
123/*!
124 Returns the currently use QSvgRenderer.
125*/
126QSvgRenderer *QGraphicsSvgItem::renderer() const
127{
128 return d_func()->renderer;
129}
130
131
132/*!
133 Returns the bounding rectangle of this item.
134*/
135QRectF QGraphicsSvgItem::boundingRect() const
136{
137 Q_D(const QGraphicsSvgItem);
138 return d->boundingRect;
139}
140
141// from qgraphicsitem.cpp
142void Q_WIDGETS_EXPORT qt_graphicsItem_highlightSelected(QGraphicsItem *item, QPainter *painter,
143 const QStyleOptionGraphicsItem *option);
144
145/*!
146 \reimp
147*/
148void QGraphicsSvgItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
149 QWidget *widget)
150{
151// Q_UNUSED(option);
152 Q_UNUSED(widget);
153
154 Q_D(QGraphicsSvgItem);
155 if (!d->renderer->isValid())
156 return;
157
158 if (d->elemId.isEmpty())
159 d->renderer->render(p: painter, bounds: d->boundingRect);
160 else
161 d->renderer->render(p: painter, elementId: d->elemId, bounds: d->boundingRect);
162
163 if (option->state & QStyle::State_Selected)
164 qt_graphicsItem_highlightSelected(item: this, painter, option);
165}
166
167/*!
168 \reimp
169*/
170int QGraphicsSvgItem::type() const
171{
172 return Type;
173}
174
175/*!
176 \property QGraphicsSvgItem::maximumCacheSize
177 \since 4.6
178
179 This property holds the maximum size of the device coordinate cache
180 for this item.
181 */
182
183/*!
184 Sets the maximum device coordinate cache size of the item to \a size.
185 If the item is cached using QGraphicsItem::DeviceCoordinateCache mode,
186 caching is bypassed if the extension of the item in device coordinates
187 is larger than \a size.
188
189 The cache corresponds to the QPixmap which is used to cache the
190 results of the rendering.
191 Use QPixmapCache::setCacheLimit() to set limitations on the whole cache
192 and use setMaximumCacheSize() when setting cache size for individual
193 items.
194
195 \sa QGraphicsItem::cacheMode()
196*/
197void QGraphicsSvgItem::setMaximumCacheSize(const QSize &size)
198{
199 QGraphicsItem::d_ptr->setExtra(type: QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize, value: size);
200 update();
201}
202
203/*!
204 Returns the current maximum size of the device coordinate cache for this item.
205 If the item is cached using QGraphicsItem::DeviceCoordinateCache mode,
206 caching is bypassed if the extension of the item in device coordinates
207 is larger than the maximum size.
208
209 The default maximum cache size is 1024x768.
210 QPixmapCache::cacheLimit() gives the
211 cumulative bounds of the whole cache, whereas maximumCacheSize() refers
212 to a maximum cache size for this particular item.
213
214 \sa QGraphicsItem::cacheMode()
215*/
216QSize QGraphicsSvgItem::maximumCacheSize() const
217{
218 return QGraphicsItem::d_ptr->extra(type: QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
219}
220
221/*!
222 \property QGraphicsSvgItem::elementId
223 \since 4.6
224
225 This property holds the element's XML ID.
226 */
227
228/*!
229 Sets the XML ID of the element to \a id.
230*/
231void QGraphicsSvgItem::setElementId(const QString &id)
232{
233 Q_D(QGraphicsSvgItem);
234 d->elemId = id;
235 d->updateDefaultSize();
236 update();
237}
238
239/*!
240 Returns the XML ID the element that is currently
241 being rendered. Returns an empty string if the whole
242 file is being rendered.
243*/
244QString QGraphicsSvgItem::elementId() const
245{
246 Q_D(const QGraphicsSvgItem);
247 return d->elemId;
248}
249
250/*!
251 Sets \a renderer to be a shared QSvgRenderer on the item. By
252 using this method one can share the same QSvgRenderer on a number
253 of items. This means that the SVG file will be parsed only once.
254 QSvgRenderer passed to this method has to exist for as long as
255 this item is used.
256*/
257void QGraphicsSvgItem::setSharedRenderer(QSvgRenderer *renderer)
258{
259 Q_D(QGraphicsSvgItem);
260 if (!d->shared)
261 delete d->renderer;
262
263 d->renderer = renderer;
264 d->shared = true;
265
266 d->updateDefaultSize();
267
268 update();
269}
270
271/*!
272 \deprecated
273
274 Use QGraphicsItem::setCacheMode() instead. Passing true to this function is equivalent
275 to QGraphicsItem::setCacheMode(QGraphicsItem::DeviceCoordinateCache).
276*/
277void QGraphicsSvgItem::setCachingEnabled(bool caching)
278{
279 setCacheMode(mode: caching ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
280}
281
282/*!
283 \deprecated
284
285 Use QGraphicsItem::cacheMode() instead.
286*/
287bool QGraphicsSvgItem::isCachingEnabled() const
288{
289 return cacheMode() != QGraphicsItem::NoCache;
290}
291
292QT_END_NAMESPACE
293
294#include "moc_qgraphicssvgitem.cpp"
295
296#endif // QT_NO_GRAPHICSVIEW
297

source code of qtsvg/src/svgwidgets/qgraphicssvgitem.cpp