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

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