• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libplasma

svg.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License as
00006  *   published by the Free Software Foundation; either version 2, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details
00013  *
00014  *   You should have received a copy of the GNU Library General Public
00015  *   License along with this program; if not, write to the
00016  *   Free Software Foundation, Inc.,
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018  */
00019 
00020 #include "svg.h"
00021 
00022 #include <QDir>
00023 #include <QMatrix>
00024 #include <QPainter>
00025 #include <QPixmapCache>
00026 #include <QSharedData>
00027 
00028 #include <KDebug>
00029 #include <KSharedPtr>
00030 #include <KSvgRenderer>
00031 #include <KColorScheme>
00032 #include <KIconEffect>
00033 #include <KGlobalSettings>
00034 
00035 #include "theme.h"
00036 
00037 namespace Plasma
00038 {
00039 
00040 class SharedSvgRenderer : public KSvgRenderer, public QSharedData
00041 {
00042     public:
00043         typedef KSharedPtr<SharedSvgRenderer> Ptr;
00044 
00045         SharedSvgRenderer(QObject *parent = 0)
00046             : KSvgRenderer(parent)
00047         {}
00048 
00049         SharedSvgRenderer(const QString &filename, QObject *parent = 0)
00050             : KSvgRenderer(filename, parent)
00051         {}
00052 
00053         SharedSvgRenderer(const QByteArray &contents, QObject *parent = 0)
00054             : KSvgRenderer(contents, parent)
00055         {}
00056 
00057         ~SharedSvgRenderer()
00058         {
00059             //kDebug() << "leaving this world for a better one.";
00060         }
00061 };
00062 
00063 class SvgPrivate
00064 {
00065     public:
00066         SvgPrivate(Svg *svg)
00067             : q(svg),
00068               renderer(0),
00069               multipleImages(false),
00070               themed(false),
00071               applyColors(false)
00072         {
00073         }
00074 
00075         ~SvgPrivate()
00076         {
00077             eraseRenderer();
00078         }
00079 
00080         void setImagePath(const QString &imagePath, Svg *q)
00081         {
00082             if (themed) {
00083                 QObject::disconnect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()));
00084                 QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorsChanged()));
00085             }
00086 
00087             themed = !QDir::isAbsolutePath(imagePath);
00088             path = themePath = QString();
00089 
00090             if (themed) {
00091                 themePath = imagePath;
00092                 QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()));
00093 
00094                 // check if svg wants colorscheme applied
00095                 createRenderer();
00096                 applyColors = renderer->elementExists("hint-apply-color-scheme");
00097                 if (applyColors && !Theme::defaultTheme()->colorScheme()) {
00098                     QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorsChanged()));
00099                 }
00100 
00101             } else {
00102                 path = imagePath;
00103 
00104                 if (!QFile::exists(path)) {
00105                     kDebug() << "Plasma::Svg: file '" << path << "' does not exist!";
00106                 }
00107             }
00108         }
00109 
00110         void removeFromCache() {
00111             if (ids.isEmpty()) {
00112                 return;
00113             }
00114 
00115             foreach (const QString &id, ids) {
00116                 QPixmapCache::remove(id);
00117             }
00118 
00119             ids.clear();
00120         }
00121 
00122         void findInCache(QPixmap& p, const QString& elementId, const QPainter *itemPainter, const QSizeF &s = QSizeF())
00123         {
00124             createRenderer();
00125 
00126             QSize size;
00127             if (elementId.isEmpty() || multipleImages) {
00128                 size = s.toSize();
00129             } else {
00130                 size = elementSize(elementId);
00131             }
00132 
00133             if (!size.isValid()) {
00134                 p = QPixmap();
00135                 return;
00136             }
00137 
00138             QString id = QString::fromLatin1("%3_%2_%1_").arg(size.width())
00139                                                          .arg(size.height())
00140                                                          .arg(path);
00141 
00142             if (!elementId.isEmpty()) {
00143                 id.append(elementId);
00144             }
00145             //kDebug() << "id is " << id;
00146 
00147             if (!ids.contains(id)) {
00148                 ids.append(id);
00149             }
00150 
00151             if (QPixmapCache::find(id, p)) {
00152                 //kDebug() << "found cached version of " << id;
00153                 return;
00154             } else {
00155                 //kDebug() << "didn't find cached version of " << id << ", so re-rendering";
00156             }
00157 
00158             //kDebug() << "size for " << elementId << " is " << s;
00159             // we have to re-render this puppy
00160 
00161             p = QPixmap(size);
00162 
00163             p.fill(Qt::transparent);
00164             QPainter renderPainter(&p);
00165 
00166             if (elementId.isEmpty()) {
00167                 renderer->render(&renderPainter);
00168             } else {
00169                 renderer->render(&renderPainter, elementId);
00170             }
00171 
00172             renderPainter.end();
00173 
00174             // Apply current color scheme if the svg asks for it
00175             if (applyColors) {
00176                 QImage itmp = p.toImage();
00177                 KIconEffect::colorize(itmp, Theme::defaultTheme()->color(Theme::BackgroundColor), 1.0);
00178                 p = p.fromImage(itmp);
00179             }
00180 
00181             if (!QPixmapCache::insert(id, p)) {
00182                 //kDebug() << "pixmap cache is too small for inserting" << id << "of size" << s;
00183             }
00184         }
00185 
00186         void createRenderer()
00187         {
00188             if (renderer) {
00189                 return;
00190             }
00191 
00192             if (themed && path.isEmpty()) {
00193                 path = Plasma::Theme::defaultTheme()->imagePath(themePath);
00194             }
00195 
00196             QHash<QString, SharedSvgRenderer::Ptr>::const_iterator it = renderers.find(path);
00197 
00198             if (it != renderers.end()) {
00199                 //kDebug() << "gots us an existing one!";
00200                 renderer = it.value();
00201             } else {
00202                 renderer = new SharedSvgRenderer(path);
00203                 renderers[path] = renderer;
00204             }
00205 
00206             size = renderer->defaultSize();
00207         }
00208 
00209         void eraseRenderer()
00210         {
00211             if ( renderer && renderer.count() == 2) {
00212                 // this and the cache reference it; and boy is this not thread safe ;)
00213                 renderers.erase(renderers.find(themePath));
00214             }
00215 
00216             renderer = 0;
00217         }
00218 
00219         QSize elementSize(const QString& elementId)
00220         {
00221             createRenderer();
00222 
00223             if (!renderer->elementExists(elementId)) {
00224                 return QSize(0, 0);
00225             }
00226 
00227             QSizeF elementSize = renderer->boundsOnElement(elementId).size();
00228             QSizeF naturalSize = renderer->defaultSize();
00229             qreal dx = size.width() / naturalSize.width();
00230             qreal dy = size.height() / naturalSize.height();
00231             elementSize.scale(elementSize.width() * dx, elementSize.height() * dy, Qt::IgnoreAspectRatio);
00232 
00233             return elementSize.toSize();
00234         }
00235 
00236         QRectF elementRect(const QString& elementId)
00237         {
00238             createRenderer();
00239             QRectF elementRect = renderer->boundsOnElement(elementId);
00240             QSizeF naturalSize = renderer->defaultSize();
00241             qreal dx = size.width() / naturalSize.width();
00242             qreal dy = size.height() / naturalSize.height();
00243 
00244             return QRectF(elementRect.x() * dx, elementRect.y() * dy,
00245                          elementRect.width() * dx, elementRect.height() * dy);
00246         }
00247 
00248         QMatrix matrixForElement(const QString& elementId)
00249         {
00250             createRenderer();
00251             return renderer->matrixForElement(elementId);
00252         }
00253 
00254         void themeChanged()
00255         {
00256             if (!themed) {
00257                 return;
00258             }
00259 
00260             QString newPath = Theme::defaultTheme()->imagePath(themePath);
00261 
00262             if (path == newPath) {
00263                 return;
00264             }
00265 
00266             removeFromCache();
00267             path = newPath;
00268             //delete d->renderer; we're a KSharedPtr
00269             eraseRenderer();
00270 
00271             // check if new theme svg wants colorscheme applied
00272             createRenderer();
00273             applyColors = renderer->elementExists("hint-apply-color-scheme");
00274             if (applyColors && !Theme::defaultTheme()->colorScheme()) {
00275                 QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorsChanged()));
00276             } else {
00277                 QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorsChanged()));
00278             }
00279 
00280             emit q->repaintNeeded();
00281         }
00282 
00283         void colorsChanged()
00284         {
00285             if (!applyColors) {
00286                 return;
00287             }
00288 
00289             removeFromCache();
00290             eraseRenderer();
00291             emit q->repaintNeeded();
00292         }
00293 
00294         Svg *q;
00295         static QHash<QString, SharedSvgRenderer::Ptr> renderers;
00296         SharedSvgRenderer::Ptr renderer;
00297         QString themePath;
00298         QString path;
00299         QList<QString> ids;
00300         QSizeF size;
00301         bool multipleImages;
00302         bool themed;
00303         bool applyColors;
00304 };
00305 
00306 QHash<QString, SharedSvgRenderer::Ptr> SvgPrivate::renderers;
00307 
00308 Svg::Svg(QObject* parent)
00309     : QObject(parent),
00310       d(new SvgPrivate(this))
00311 {
00312 }
00313 
00314 Svg::~Svg()
00315 {
00316     delete d;
00317 }
00318 
00319 void Svg::paint(QPainter* painter, const QPointF& point, const QString& elementID)
00320 {
00321     QPixmap pix;
00322  
00323     if (elementID.isNull()) {
00324         d->findInCache(pix, elementID, painter, size());
00325     } else {
00326         d->findInCache(pix, elementID, painter);
00327     }
00328 
00329     if (pix.isNull()) {
00330         return;
00331     }
00332 
00333     painter->drawPixmap(QRectF(point, pix.size()), pix, QRectF(QPointF(0,0), pix.size()));
00334 }
00335 
00336 void Svg::paint(QPainter* painter, int x, int y, const QString& elementID)
00337 {
00338     paint(painter, QPointF(x, y), elementID);
00339 }
00340 
00341 void Svg::paint(QPainter* painter, const QRectF& rect, const QString& elementID)
00342 {
00343     QPixmap pix;
00344     d->findInCache(pix, elementID, painter, rect.size());
00345     painter->drawPixmap(rect, pix, QRectF(QPointF(0,0), pix.size()));
00346 }
00347 
00348 QSize Svg::size() const
00349 {
00350     return d->size.toSize();
00351 }
00352 
00353 void Svg::resize( qreal width, qreal height )
00354 {
00355     resize( QSize( width, height ) );
00356 }
00357 
00358 void Svg::resize( const QSizeF& size )
00359 {
00360     d->createRenderer();
00361     d->size = size;
00362 }
00363 
00364 void Svg::resize()
00365 {
00366     d->createRenderer();
00367     d->size = d->renderer->defaultSize();
00368 }
00369 
00370 QSize Svg::elementSize(const QString& elementId) const
00371 {
00372     return d->elementSize(elementId);
00373 }
00374 
00375 QRectF Svg::elementRect(const QString& elementId) const
00376 {
00377     return d->elementRect(elementId);
00378 }
00379 
00380 bool Svg::hasElement(const QString& elementId) const
00381 {
00382     d->createRenderer();
00383     return d->renderer->elementExists(elementId);
00384 }
00385 
00386 QString Svg::elementAtPoint(const QPoint &point) const
00387 {
00388     d->createRenderer();
00389     QSizeF naturalSize = d->renderer->defaultSize();
00390     qreal dx = d->size.width() / naturalSize.width();
00391     qreal dy = d->size.height() / naturalSize.height();
00392     //kDebug() << point << "is really" << QPoint(point.x() *dx, naturalSize.height() - point.y() * dy);
00393 
00394     return QString(); // d->renderer->elementAtPoint(QPoint(point.x() *dx, naturalSize.height() - point.y() * dy));
00395 }
00396 
00397 bool Svg::isValid() const
00398 {
00399     d->createRenderer();
00400     return d->renderer->isValid();
00401 }
00402 
00403 void Svg::setContainsMultipleImages(bool multiple)
00404 {
00405     d->multipleImages = multiple;
00406 }
00407 
00408 bool Svg::containsMultipleImages() const
00409 {
00410     return d->multipleImages;
00411 }
00412 
00413 void Svg::setImagePath(const QString &svgFilePath)
00414 {
00415    d->setImagePath(svgFilePath, this);
00416    d->eraseRenderer();
00417    emit repaintNeeded();
00418 }
00419 
00420 QString Svg::imagePath() const
00421 {
00422    return d->themed ? d->themePath : d->path;
00423 }
00424 
00425 } // Plasma namespace
00426 
00427 #include "svg.moc"
00428 

libplasma

Skip menu "libplasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal