src/svg/qgraphicssvgitem.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtSvg module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    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 
       
    53 QT_BEGIN_NAMESPACE
       
    54 
       
    55 class QGraphicsSvgItemPrivate : public QGraphicsItemPrivate
       
    56 {
       
    57 public:
       
    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 setSize() method or via
       
   128     direct manipulation of the items transformation matrix.
       
   129 
       
   130     By default the SVG rendering is cached using QGraphicsItem::DeviceCoordinateCache
       
   131     mode to speedup the display of items. Caching can be disabled by passing
       
   132     QGraphicsItem::NoCache to the QGraphicsItem::setCacheMode() method.
       
   133 
       
   134     \sa QSvgWidget, {QtSvg Module}, QGraphicsItem, QGraphicsView
       
   135 */
       
   136 
       
   137 /*!
       
   138     Constructs a new SVG item with the given \a parent.
       
   139 */
       
   140 QGraphicsSvgItem::QGraphicsSvgItem(QGraphicsItem *parent)
       
   141     : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0, 0)
       
   142 {
       
   143     Q_D(QGraphicsSvgItem);
       
   144     d->init(parent);
       
   145 }
       
   146 
       
   147 /*!
       
   148     Constructs a new item with the given \a parent and loads the contents of the
       
   149     SVG file with the specified \a fileName.
       
   150 */
       
   151 QGraphicsSvgItem::QGraphicsSvgItem(const QString &fileName, QGraphicsItem *parent)
       
   152     : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0, 0)
       
   153 {
       
   154     Q_D(QGraphicsSvgItem);
       
   155     d->init(parent);
       
   156     d->renderer->load(fileName);
       
   157     d->updateDefaultSize();
       
   158 }
       
   159 
       
   160 /*!
       
   161     Returns the currently use QSvgRenderer.
       
   162 */
       
   163 QSvgRenderer *QGraphicsSvgItem::renderer() const
       
   164 {
       
   165     return d_func()->renderer;
       
   166 }
       
   167 
       
   168 
       
   169 /*!
       
   170     Returns the bounding rectangle of this item.
       
   171 */
       
   172 QRectF QGraphicsSvgItem::boundingRect() const
       
   173 {
       
   174     Q_D(const QGraphicsSvgItem);
       
   175     return d->boundingRect;
       
   176 }
       
   177 
       
   178 /*!
       
   179     \internal
       
   180 
       
   181     Highlights \a item as selected.
       
   182 
       
   183     NOTE: This function is a duplicate of qt_graphicsItem_highlightSelected() in qgraphicsitem.cpp!
       
   184 */
       
   185 static void qt_graphicsItem_highlightSelected(
       
   186     QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option)
       
   187 {
       
   188     const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1));
       
   189     if (qFuzzyIsNull(qMax(murect.width(), murect.height())))
       
   190         return;
       
   191 
       
   192     const QRectF mbrect = painter->transform().mapRect(item->boundingRect());
       
   193     if (qMin(mbrect.width(), mbrect.height()) < qreal(1.0))
       
   194         return;
       
   195 
       
   196     qreal itemPenWidth;
       
   197     switch (item->type()) {
       
   198         case QGraphicsEllipseItem::Type:
       
   199             itemPenWidth = static_cast<QGraphicsEllipseItem *>(item)->pen().widthF();
       
   200             break;
       
   201         case QGraphicsPathItem::Type:
       
   202             itemPenWidth = static_cast<QGraphicsPathItem *>(item)->pen().widthF();
       
   203             break;
       
   204         case QGraphicsPolygonItem::Type:
       
   205             itemPenWidth = static_cast<QGraphicsPolygonItem *>(item)->pen().widthF();
       
   206             break;
       
   207         case QGraphicsRectItem::Type:
       
   208             itemPenWidth = static_cast<QGraphicsRectItem *>(item)->pen().widthF();
       
   209             break;
       
   210         case QGraphicsSimpleTextItem::Type:
       
   211             itemPenWidth = static_cast<QGraphicsSimpleTextItem *>(item)->pen().widthF();
       
   212             break;
       
   213         case QGraphicsLineItem::Type:
       
   214             itemPenWidth = static_cast<QGraphicsLineItem *>(item)->pen().widthF();
       
   215             break;
       
   216         default:
       
   217             itemPenWidth = 1.0;
       
   218     }
       
   219     const qreal pad = itemPenWidth / 2;
       
   220 
       
   221     const qreal penWidth = 0; // cosmetic pen
       
   222 
       
   223     const QColor fgcolor = option->palette.windowText().color();
       
   224     const QColor bgcolor( // ensure good contrast against fgcolor
       
   225         fgcolor.red()   > 127 ? 0 : 255,
       
   226         fgcolor.green() > 127 ? 0 : 255,
       
   227         fgcolor.blue()  > 127 ? 0 : 255);
       
   228 
       
   229     painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine));
       
   230     painter->setBrush(Qt::NoBrush);
       
   231     painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
       
   232 
       
   233     painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine));
       
   234     painter->setBrush(Qt::NoBrush);
       
   235     painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
       
   236 }
       
   237 
       
   238 /*!
       
   239     \reimp
       
   240 */
       
   241 void QGraphicsSvgItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
       
   242                              QWidget *widget)
       
   243 {
       
   244 //    Q_UNUSED(option);
       
   245     Q_UNUSED(widget);
       
   246 
       
   247     Q_D(QGraphicsSvgItem);
       
   248     if (!d->renderer->isValid())
       
   249         return;
       
   250 
       
   251     if (d->elemId.isEmpty())
       
   252         d->renderer->render(painter, d->boundingRect);
       
   253     else
       
   254         d->renderer->render(painter, d->elemId, d->boundingRect);
       
   255 
       
   256     if (option->state & QStyle::State_Selected)
       
   257         qt_graphicsItem_highlightSelected(this, painter, option);
       
   258 }
       
   259 
       
   260 /*!
       
   261     \reimp
       
   262 */
       
   263 int QGraphicsSvgItem::type() const
       
   264 {
       
   265     return Type;
       
   266 }
       
   267 
       
   268 /*!
       
   269   \property QGraphicsSvgItem::maximumCacheSize
       
   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 */
       
   289 void QGraphicsSvgItem::setMaximumCacheSize(const QSize &size)
       
   290 {
       
   291     QGraphicsItem::d_ptr->setExtra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize, 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 */
       
   308 QSize QGraphicsSvgItem::maximumCacheSize() const
       
   309 {
       
   310     return QGraphicsItem::d_ptr->extra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
       
   311 }
       
   312 
       
   313 /*!
       
   314   \property QGraphicsSvgItem::elementId
       
   315 
       
   316   This property holds the element's XML ID.
       
   317  */
       
   318 
       
   319 /*!
       
   320     Sets the XML ID of the element to \a id.
       
   321 */
       
   322 void QGraphicsSvgItem::setElementId(const QString &id)
       
   323 {
       
   324     Q_D(QGraphicsSvgItem);
       
   325     d->elemId = id;
       
   326     d->updateDefaultSize();
       
   327     update();
       
   328 }
       
   329 
       
   330 /*!
       
   331     Returns the XML ID the element that is currently
       
   332     being rendered. Returns an empty string if the whole
       
   333     file is being rendered.
       
   334 */
       
   335 QString QGraphicsSvgItem::elementId() const
       
   336 {
       
   337     Q_D(const QGraphicsSvgItem);
       
   338     return d->elemId;
       
   339 }
       
   340 
       
   341 /*!
       
   342     Sets \a renderer to be a shared QSvgRenderer on the item. By
       
   343     using this method one can share the same QSvgRenderer on a number
       
   344     of items. This means that the SVG file will be parsed only once.
       
   345     QSvgRenderer passed to this method has to exist for as long as
       
   346     this item is used.
       
   347 */
       
   348 void QGraphicsSvgItem::setSharedRenderer(QSvgRenderer *renderer)
       
   349 {
       
   350     Q_D(QGraphicsSvgItem);
       
   351     if (!d->shared)
       
   352         delete d->renderer;
       
   353 
       
   354     d->renderer = renderer;
       
   355     d->shared = true;
       
   356 
       
   357     d->updateDefaultSize();
       
   358 
       
   359     update();
       
   360 }
       
   361 
       
   362 /*!
       
   363     \obsolete
       
   364 
       
   365     Use QGraphicsItem::setCacheMode() instead. Passing true to this function is equivalent
       
   366     to QGraphicsItem::setCacheMode(QGraphicsItem::DeviceCoordinateCache).
       
   367 */
       
   368 void QGraphicsSvgItem::setCachingEnabled(bool caching)
       
   369 {
       
   370     setCacheMode(caching ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
       
   371 }
       
   372 
       
   373 /*!
       
   374     \obsolete
       
   375 
       
   376     Use QGraphicsItem::cacheMode() instead.
       
   377 */
       
   378 bool QGraphicsSvgItem::isCachingEnabled() const
       
   379 {
       
   380     return cacheMode() != QGraphicsItem::NoCache;
       
   381 }
       
   382 
       
   383 QT_END_NAMESPACE
       
   384 
       
   385 #include "moc_qgraphicssvgitem.cpp"
       
   386 
       
   387 #endif // QT_NO_GRAPHICSSVGITEM