• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Plasma

svg.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
00003  *   Copyright 2008-2010 Marco Martin <notmart@gmail.com>
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU Library General Public License as
00007  *   published by the Free Software Foundation; either version 2, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details
00014  *
00015  *   You should have received a copy of the GNU Library General Public
00016  *   License along with this program; if not, write to the
00017  *   Free Software Foundation, Inc.,
00018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  */
00020 
00021 #include "svg.h"
00022 #include "private/svg_p.h"
00023 
00024 #include <cmath>
00025 
00026 #include <QDir>
00027 #include <QDomDocument>
00028 #include <QMatrix>
00029 #include <QPainter>
00030 #include <QStringBuilder>
00031 
00032 #include <kcolorscheme.h>
00033 #include <kconfiggroup.h>
00034 #include <kdebug.h>
00035 #include <kfilterdev.h>
00036 #include <kiconeffect.h>
00037 #include <kglobalsettings.h>
00038 #include <ksharedptr.h>
00039 
00040 #include "applet.h"
00041 #include "package.h"
00042 #include "theme.h"
00043 
00044 namespace Plasma
00045 {
00046 
00047 SharedSvgRenderer::SharedSvgRenderer(QObject *parent)
00048     : QSvgRenderer(parent)
00049 {
00050 }
00051 
00052 SharedSvgRenderer::SharedSvgRenderer(
00053     const QString &filename,
00054     const QString &styleSheet,
00055     QHash<QString, QRectF> &interestingElements,
00056     QObject *parent)
00057     : QSvgRenderer(parent)
00058 {
00059     QIODevice *file = KFilterDev::deviceForFile(filename, "application/x-gzip");
00060     if (!file->open(QIODevice::ReadOnly)) {
00061         delete file;
00062         return;
00063     }
00064     load(file->readAll(), styleSheet, interestingElements);
00065     delete file;
00066 }
00067 
00068 SharedSvgRenderer::SharedSvgRenderer(
00069     const QByteArray &contents,
00070     const QString &styleSheet,
00071     QHash<QString, QRectF> &interestingElements,
00072     QObject *parent)
00073     : QSvgRenderer(parent)
00074 {
00075     load(contents, styleSheet, interestingElements);
00076 }
00077 
00078 bool SharedSvgRenderer::load(
00079     const QByteArray &contents,
00080     const QString &styleSheet,
00081     QHash<QString, QRectF> &interestingElements)
00082 {
00083     // Apply the style sheet.
00084     if (!styleSheet.isEmpty() && contents.contains("current-color-scheme")) {
00085         QDomDocument svg;
00086         if (!svg.setContent(contents)) {
00087             return false;
00088         }
00089 
00090         QDomNode defs = svg.elementsByTagName("defs").item(0);
00091 
00092         for (QDomElement style = defs.firstChildElement("style"); !style.isNull();
00093              style = style.nextSiblingElement("style")) {
00094             if (style.attribute("id") == "current-color-scheme") {
00095                 QDomElement colorScheme = svg.createElement("style");
00096                 colorScheme.setAttribute("type", "text/css");
00097                 colorScheme.setAttribute("id", "current-color-scheme");
00098                 defs.replaceChild(colorScheme, style);
00099                 colorScheme.appendChild(svg.createCDATASection(styleSheet));
00100 
00101                 interestingElements.insert("current-color-scheme", QRect(0,0,1,1));
00102 
00103                 break;
00104             }
00105         }
00106         if (!QSvgRenderer::load(svg.toByteArray(-1))) {
00107             return false;
00108         }
00109     } else if (!QSvgRenderer::load(contents)) {
00110         return false;
00111     }
00112 
00113     // Search the SVG to find and store all ids that contain size hints.
00114     const QString contentsAsString(QString::fromLatin1(contents));
00115     QRegExp idExpr("id\\s*=\\s*(['\"])(\\d+-\\d+-.*)\\1");
00116     idExpr.setMinimal(true);
00117 
00118     int pos = 0;
00119     while ((pos = idExpr.indexIn(contentsAsString, pos)) != -1) {
00120         QString elementId = idExpr.cap(2);
00121 
00122         QRectF elementRect = boundsOnElement(elementId);
00123         if (elementRect.isValid()) {
00124             interestingElements.insert(elementId, elementRect);
00125         }
00126 
00127         pos += idExpr.matchedLength();
00128     }
00129 
00130     return true;
00131 }
00132 
00133 #define QLSEP QLatin1Char('_')
00134 #define CACHE_ID_WITH_SIZE(size, id) QString::number(int(size.width())) % QLSEP % QString::number(int(size.height())) % QLSEP % id
00135 #define CACHE_ID_NATURAL_SIZE(id) QLatin1Literal("Natural") % QLSEP % id
00136 
00137 SvgPrivate::SvgPrivate(Svg *svg)
00138     : q(svg),
00139       renderer(0),
00140       styleCrc(0),
00141       lastModified(0),
00142       multipleImages(false),
00143       themed(false),
00144       applyColors(false),
00145       usesColors(false),
00146       cacheRendering(true),
00147       themeFailed(false)
00148 {
00149 }
00150 
00151 SvgPrivate::~SvgPrivate()
00152 {
00153     eraseRenderer();
00154 }
00155 
00156 //This function is meant for the rects cache
00157 QString SvgPrivate::cacheId(const QString &elementId)
00158 {
00159     if (size.isValid() && size != naturalSize) {
00160         return CACHE_ID_WITH_SIZE(size, elementId);
00161     } else {
00162         return CACHE_ID_NATURAL_SIZE(elementId);
00163     }
00164 }
00165 
00166 //This function is meant for the pixmap cache
00167 QString SvgPrivate::cachePath(const QString &path, const QSize &size)
00168 {
00169     return CACHE_ID_WITH_SIZE(size, path);
00170 }
00171 
00172 bool SvgPrivate::setImagePath(const QString &imagePath)
00173 {
00174     const bool isThemed = !QDir::isAbsolutePath(imagePath);
00175 
00176     // lets check to see if we're already set to this file
00177     if (isThemed == themed &&
00178         ((themed && themePath == imagePath) ||
00179         (!themed && path == imagePath))) {
00180         return false;
00181     }
00182 
00183     eraseRenderer();
00184 
00185     // if we don't have any path right now and are going to set one,
00186     // then lets not schedule a repaint because we are just initializing!
00187     bool updateNeeded = true; 
00188 
00189     QObject::disconnect(actualTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()));
00190     if (isThemed && !themed && s_systemColorsCache) {
00191         // catch the case where we weren't themed, but now we are, and the colors cache was set up
00192         // ensure we are not connected to that theme previously
00193         QObject::disconnect(s_systemColorsCache.data(), 0, q, 0);
00194     }
00195 
00196     themed = isThemed;
00197     path.clear();
00198     themePath.clear();
00199     localRectCache.clear();
00200     elementsWithSizeHints.clear();
00201 
00202     if (themed) {
00203         themePath = imagePath;
00204         themeFailed = false;
00205         QObject::connect(actualTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()));
00206     } else if (QFile::exists(imagePath)) {
00207         QObject::connect(cacheAndColorsTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()), Qt::UniqueConnection);
00208         path = imagePath;
00209     } else {
00210         kDebug() << "file '" << path << "' does not exist!";
00211     }
00212 
00213     // check if svg wants colorscheme applied
00214     checkColorHints();
00215 
00216     // also images with absolute path needs to have a natural size initialized,
00217     // even if looks a bit weird using Theme to store non-themed stuff
00218     if (themed || QFile::exists(imagePath)) {
00219         QRectF rect;
00220         if (cacheAndColorsTheme()->findInRectsCache(path, "_Natural", rect)) {
00221             naturalSize = rect.size();
00222         } else {
00223             createRenderer();
00224             naturalSize = renderer->defaultSize();
00225             //kDebug() << "natural size for" << path << "from renderer is" << naturalSize;
00226             cacheAndColorsTheme()->insertIntoRectsCache(path, "_Natural", QRectF(QPointF(0,0), naturalSize));
00227             //kDebug() << "natural size for" << path << "from cache is" << naturalSize;
00228         }
00229     }
00230 
00231     if (!themed) {
00232         QFile f(imagePath);
00233         QFileInfo info(f);
00234         lastModified = info.lastModified().toTime_t();
00235     }
00236 
00237     return updateNeeded;
00238 }
00239 
00240 Theme *SvgPrivate::actualTheme()
00241 {
00242     if (!theme) {
00243         theme = Plasma::Theme::defaultTheme();
00244     }
00245 
00246     return theme.data();
00247 }
00248 
00249 Theme *SvgPrivate::cacheAndColorsTheme()
00250 {
00251     if (themed) {
00252         return actualTheme();
00253     } else {
00254         // use a separate cache source for unthemed svg's
00255         if (!s_systemColorsCache) {
00256             //FIXME: reference count this, so that it is deleted when no longer in use
00257             s_systemColorsCache = new Plasma::Theme("internal-system-colors");
00258         }
00259 
00260         return s_systemColorsCache.data();
00261     }
00262 }
00263 
00264 QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s)
00265 {
00266     QSize size;
00267     QString actualElementId;
00268 
00269     if (elementsWithSizeHints.isEmpty()) {
00270         // Fetch all size hinted element ids from the theme's rect cache
00271         // and store them locally.
00272         QRegExp sizeHintedKeyExpr(CACHE_ID_NATURAL_SIZE("(\\d+)-(\\d+)-(.+)"));
00273 
00274         foreach (const QString &key, cacheAndColorsTheme()->listCachedRectKeys(path)) {
00275             if (sizeHintedKeyExpr.exactMatch(key)) {
00276                 QString baseElementId = sizeHintedKeyExpr.cap(3);
00277                 QSize sizeHint(sizeHintedKeyExpr.cap(1).toInt(),
00278                                sizeHintedKeyExpr.cap(2).toInt());
00279 
00280                 if (sizeHint.isValid()) {
00281                     elementsWithSizeHints.insertMulti(baseElementId, sizeHint);
00282                 }
00283             }
00284         }
00285 
00286         if (elementsWithSizeHints.isEmpty()) {
00287             // Make sure we won't query the theme unnecessarily.
00288             elementsWithSizeHints.insert(QString(), QSize());
00289         }
00290     }
00291 
00292     // Look at the size hinted elements and try to find the smallest one with an
00293     // identical aspect ratio.
00294     if (s.isValid() && !elementId.isEmpty()) {
00295         QList<QSize> elementSizeHints = elementsWithSizeHints.values(elementId);
00296 
00297         if (!elementSizeHints.isEmpty()) {
00298             QSize bestFit(-1, -1);
00299 
00300             Q_FOREACH(const QSize &hint, elementSizeHints) {
00301 
00302                 if (hint.width() >= s.width() && hint.height() >= s.height() &&
00303                     (!bestFit.isValid() ||
00304                      (bestFit.width() * bestFit.height()) > (hint.width() * hint.height()))) {
00305                     bestFit = hint;
00306                 }
00307             }
00308 
00309             if (bestFit.isValid()) {
00310                 actualElementId = QString::number(bestFit.width()) % "-" %
00311                                   QString::number(bestFit.height()) % "-" % elementId;
00312             }
00313         }
00314     }
00315 
00316     if (elementId.isEmpty() || !q->hasElement(actualElementId)) {
00317         actualElementId = elementId;
00318     }
00319 
00320     if (elementId.isEmpty() || (multipleImages && s.isValid())) {
00321         size = s.toSize();
00322     } else {
00323         size = elementRect(actualElementId).size().toSize();
00324     }
00325 
00326     if (size.isEmpty()) {
00327         return QPixmap();
00328     }
00329 
00330     QString id = cachePath(path, size);
00331 
00332     if (!actualElementId.isEmpty()) {
00333         id.append(actualElementId);
00334     }
00335 
00336     //kDebug() << "id is " << id;
00337 
00338     QPixmap p;
00339     if (cacheRendering && cacheAndColorsTheme()->findInCache(id, p, lastModified)) {
00340         //kDebug() << "found cached version of " << id << p.size();
00341         return p;
00342     }
00343 
00344     //kDebug() << "didn't find cached version of " << id << ", so re-rendering";
00345 
00346     //kDebug() << "size for " << actualElementId << " is " << s;
00347     // we have to re-render this puppy
00348 
00349     createRenderer();
00350 
00351     QRectF finalRect = makeUniform(renderer->boundsOnElement(actualElementId), QRect(QPoint(0,0), size));
00352 
00353     //don't alter the pixmap size or it won't match up properly to, e.g., FrameSvg elements
00354     //makeUniform should never change the size so much that it gains or loses a whole pixel
00355     p = QPixmap(size);
00356 
00357     p.fill(Qt::transparent);
00358     QPainter renderPainter(&p);
00359 
00360     if (actualElementId.isEmpty()) {
00361         renderer->render(&renderPainter, finalRect);
00362     } else {
00363         renderer->render(&renderPainter, actualElementId, finalRect);
00364     }
00365 
00366     renderPainter.end();
00367 
00368     // Apply current color scheme if the svg asks for it
00369     if (applyColors) {
00370         QImage itmp = p.toImage();
00371         KIconEffect::colorize(itmp, cacheAndColorsTheme()->color(Theme::BackgroundColor), 1.0);
00372         p = p.fromImage(itmp);
00373     }
00374 
00375     if (cacheRendering) {
00376         cacheAndColorsTheme()->insertIntoCache(id, p, QString::number((qint64)q, 16) % QLSEP % actualElementId);
00377     }
00378 
00379     return p;
00380 }
00381 
00382 void SvgPrivate::createRenderer()
00383 {
00384     if (renderer) {
00385         return;
00386     }
00387 
00388     //kDebug() << kBacktrace();
00389     if (themed && path.isEmpty() && !themeFailed) {
00390         Applet *applet = qobject_cast<Applet*>(q->parent());
00391         if (applet && applet->package()) {
00392             path = applet->package()->filePath("images", themePath + ".svg");
00393 
00394             if (path.isEmpty()) {
00395                 path = applet->package()->filePath("images", themePath + ".svgz");
00396             }
00397         }
00398 
00399         if (path.isEmpty()) {
00400             path = actualTheme()->imagePath(themePath);
00401             themeFailed = path.isEmpty();
00402             if (themeFailed) {
00403                 kWarning() << "No image path found for" << themePath;
00404             }
00405         }
00406     }
00407 
00408     //kDebug() << "********************************";
00409     //kDebug() << "FAIL! **************************";
00410     //kDebug() << path << "**";
00411 
00412     QString styleSheet = cacheAndColorsTheme()->styleSheet("SVG");
00413     styleCrc = qChecksum(styleSheet.toUtf8(), styleSheet.size());
00414 
00415     QHash<QString, SharedSvgRenderer::Ptr>::const_iterator it = s_renderers.constFind(styleCrc + path);
00416 
00417     if (it != s_renderers.constEnd()) {
00418         //kDebug() << "gots us an existing one!";
00419         renderer = it.value();
00420     } else {
00421         if (path.isEmpty()) {
00422             renderer = new SharedSvgRenderer();
00423         } else {
00424             QHash<QString, QRectF> interestingElements;
00425             renderer = new SharedSvgRenderer(path, styleSheet, interestingElements);
00426 
00427             // Add interesting elements to the theme's rect cache.
00428             QHashIterator<QString, QRectF> i(interestingElements);
00429 
00430             while (i.hasNext()) {
00431                 i.next();
00432                 const QString &elementId = i.key();
00433                 const QRectF &elementRect = i.value();
00434 
00435                 const QString cacheId = CACHE_ID_NATURAL_SIZE(elementId);
00436                 localRectCache.insert(cacheId, elementRect);
00437                 cacheAndColorsTheme()->insertIntoRectsCache(path, cacheId, elementRect);
00438             }
00439         }
00440 
00441         s_renderers[styleCrc + path] = renderer;
00442     }
00443 
00444     if (size == QSizeF()) {
00445         size = renderer->defaultSize();
00446     }
00447 }
00448 
00449 void SvgPrivate::eraseRenderer()
00450 {
00451     if (renderer && renderer.count() == 2) {
00452         // this and the cache reference it
00453         s_renderers.erase(s_renderers.find(styleCrc + path));
00454 
00455         if (theme) {
00456             theme.data()->releaseRectsCache(path);
00457         }
00458     }
00459 
00460     renderer = 0;
00461     styleCrc = 0;
00462     localRectCache.clear();
00463     elementsWithSizeHints.clear();
00464 }
00465 
00466 QRectF SvgPrivate::elementRect(const QString &elementId)
00467 {
00468     if (themed && path.isEmpty()) {
00469         if (themeFailed) {
00470             return QRectF();
00471         }
00472 
00473         path = actualTheme()->imagePath(themePath);
00474         themeFailed = path.isEmpty();
00475 
00476         if (themeFailed) {
00477             return QRectF();
00478         }
00479     }
00480 
00481     QString id = cacheId(elementId);
00482     if (localRectCache.contains(id)) {
00483         return localRectCache.value(id);
00484     }
00485 
00486     QRectF rect;
00487     if (cacheAndColorsTheme()->findInRectsCache(path, id, rect)) {
00488         localRectCache.insert(id, rect);
00489         return rect;
00490     }
00491 
00492     return findAndCacheElementRect(elementId);
00493 }
00494 
00495 QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId)
00496 {
00497     createRenderer();
00498 
00499     // createRenderer() can insert some interesting rects in the cache, so check it
00500     const QString id = cacheId(elementId);
00501     if (localRectCache.contains(id)) {
00502         return localRectCache.value(id);
00503     }
00504     QRectF elementRect = renderer->elementExists(elementId) ?
00505         renderer->boundsOnElement(elementId) : QRectF();
00506     naturalSize = renderer->defaultSize();
00507     //kDebug() << "natural size for" << path << "is" << naturalSize;
00508     qreal dx = size.width() / naturalSize.width();
00509     qreal dy = size.height() / naturalSize.height();
00510 
00511     elementRect = QRectF(elementRect.x() * dx, elementRect.y() * dy,
00512             elementRect.width() * dx, elementRect.height() * dy);
00513 
00514     cacheAndColorsTheme()->insertIntoRectsCache(path, id, elementRect);
00515     return elementRect;
00516 }
00517 
00518 QMatrix SvgPrivate::matrixForElement(const QString &elementId)
00519 {
00520     createRenderer();
00521     return renderer->matrixForElement(elementId);
00522 }
00523 
00524 void SvgPrivate::checkColorHints()
00525 {
00526     if (elementRect("hint-apply-color-scheme").isValid()) {
00527         applyColors = true;
00528         usesColors = true;
00529     } else if (elementRect("current-color-scheme").isValid()) {
00530         applyColors = false;
00531         usesColors = true;
00532     } else {
00533         applyColors = false;
00534         usesColors = false;
00535     }
00536 
00537     // check to see if we are using colors, but the theme isn't being used or isn't providing
00538     // a colorscheme
00539     if (usesColors && (!themed || !actualTheme()->colorScheme())) {
00540         QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
00541                          q, SLOT(colorsChanged()), Qt::UniqueConnection);
00542     } else {
00543         QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()),
00544                             q, SLOT(colorsChanged()));
00545     }
00546 }
00547 
00548 //Folowing two are utility functions to snap rendered elements to the pixel grid
00549 //to and from are always 0 <= val <= 1
00550 qreal SvgPrivate::closestDistance(qreal to, qreal from)
00551 {
00552     qreal a = to - from;
00553     if (qFuzzyCompare(to, from))
00554         return 0;
00555     else if ( to > from ) {
00556         qreal b = to - from - 1;
00557         return (qAbs(a) > qAbs(b)) ?  b : a;
00558     } else {
00559         qreal b = 1 + to - from;
00560         return (qAbs(a) > qAbs(b)) ? b : a;
00561     }
00562 }
00563 
00564 QRectF SvgPrivate::makeUniform(const QRectF &orig, const QRectF &dst)
00565 {
00566     if (qFuzzyIsNull(orig.x()) || qFuzzyIsNull(orig.y())) {
00567         return dst;
00568     }
00569 
00570     QRectF res(dst);
00571     qreal div_w = dst.width() / orig.width();
00572     qreal div_h = dst.height() / orig.height();
00573 
00574     qreal div_x = dst.x() / orig.x();
00575     qreal div_y = dst.y() / orig.y();
00576 
00577     //horizontal snap
00578     if (!qFuzzyIsNull(div_x) && !qFuzzyCompare(div_w, div_x)) {
00579         qreal rem_orig = orig.x() - (floor(orig.x()));
00580         qreal rem_dst = dst.x() - (floor(dst.x()));
00581         qreal offset = closestDistance(rem_dst, rem_orig);
00582         res.translate(offset + offset*div_w, 0);
00583         res.setWidth(res.width() + offset);
00584     }
00585     //vertical snap
00586     if (!qFuzzyIsNull(div_y) && !qFuzzyCompare(div_h, div_y)) {
00587         qreal rem_orig = orig.y() - (floor(orig.y()));
00588         qreal rem_dst = dst.y() - (floor(dst.y()));
00589         qreal offset = closestDistance(rem_dst, rem_orig);
00590         res.translate(0, offset + offset*div_h);
00591         res.setHeight(res.height() + offset);
00592     }
00593 
00594     //kDebug()<<"Aligning Rects, origin:"<<orig<<"destination:"<<dst<<"result:"<<res;
00595     return res;
00596 }
00597 
00598 void SvgPrivate::themeChanged()
00599 {
00600     if (q->imagePath().isEmpty()) {
00601         return;
00602     }
00603 
00604     if (themed) {
00605         // check if new theme svg wants colorscheme applied
00606         checkColorHints();
00607     }
00608 
00609     QString currentPath = themed ? themePath : path;
00610     themePath.clear();
00611     eraseRenderer();
00612     setImagePath(currentPath);
00613 
00614     //kDebug() << themePath << ">>>>>>>>>>>>>>>>>> theme changed";
00615     emit q->repaintNeeded();
00616 }
00617 
00618 void SvgPrivate::colorsChanged()
00619 {
00620     if (!usesColors) {
00621         return;
00622     }
00623 
00624     eraseRenderer();
00625     //kDebug() << "repaint needed from colorsChanged";
00626     emit q->repaintNeeded();
00627 }
00628 
00629 QHash<QString, SharedSvgRenderer::Ptr> SvgPrivate::s_renderers;
00630 QWeakPointer<Theme> SvgPrivate::s_systemColorsCache;
00631 
00632 Svg::Svg(QObject *parent)
00633     : QObject(parent),
00634       d(new SvgPrivate(this))
00635 {
00636 }
00637 
00638 Svg::~Svg()
00639 {
00640     delete d;
00641 }
00642 
00643 QPixmap Svg::pixmap(const QString &elementID)
00644 {
00645     if (elementID.isNull() || d->multipleImages) {
00646         return d->findInCache(elementID, size());
00647     } else {
00648         return d->findInCache(elementID);
00649     }
00650 }
00651 
00652 void Svg::paint(QPainter *painter, const QPointF &point, const QString &elementID)
00653 {
00654     QPixmap pix((elementID.isNull() || d->multipleImages) ? d->findInCache(elementID, size()) :
00655                                                             d->findInCache(elementID));
00656 
00657     if (pix.isNull()) {
00658         return;
00659     }
00660 
00661     painter->drawPixmap(QRectF(point, pix.size()), pix, QRectF(QPointF(0, 0), pix.size()));
00662 }
00663 
00664 void Svg::paint(QPainter *painter, int x, int y, const QString &elementID)
00665 {
00666     paint(painter, QPointF(x, y), elementID);
00667 }
00668 
00669 void Svg::paint(QPainter *painter, const QRectF &rect, const QString &elementID)
00670 {
00671     QPixmap pix(d->findInCache(elementID, rect.size()));
00672     painter->drawPixmap(QRectF(rect.topLeft(), pix.size()), pix, QRectF(QPointF(0, 0), pix.size()));
00673 }
00674 
00675 void Svg::paint(QPainter *painter, int x, int y, int width, int height, const QString &elementID)
00676 {
00677     QPixmap pix(d->findInCache(elementID, QSizeF(width, height)));
00678     painter->drawPixmap(x, y, pix, 0, 0, pix.size().width(), pix.size().height());
00679 }
00680 
00681 QSize Svg::size() const
00682 {
00683     if (d->size.isEmpty()) {
00684         d->size = d->naturalSize;
00685     }
00686 
00687     return d->size.toSize();
00688 }
00689 
00690 void Svg::resize(qreal width, qreal height)
00691 {
00692     resize(QSize(width, height));
00693 }
00694 
00695 void Svg::resize(const QSizeF &size)
00696 {
00697     if (qFuzzyCompare(size.width(), d->size.width()) &&
00698         qFuzzyCompare(size.height(), d->size.height())) {
00699         return;
00700     }
00701 
00702     d->size = size;
00703     d->localRectCache.clear();
00704     emit sizeChanged();
00705 }
00706 
00707 void Svg::resize()
00708 {
00709     if (qFuzzyCompare(d->naturalSize.width(), d->size.width()) &&
00710         qFuzzyCompare(d->naturalSize.height(), d->size.height())) {
00711         return;
00712     }
00713 
00714     d->size = d->naturalSize;
00715     d->localRectCache.clear();
00716     emit sizeChanged();
00717 }
00718 
00719 QSize Svg::elementSize(const QString &elementId) const
00720 {
00721     return d->elementRect(elementId).size().toSize();
00722 }
00723 
00724 QRectF Svg::elementRect(const QString &elementId) const
00725 {
00726     return d->elementRect(elementId);
00727 }
00728 
00729 bool Svg::hasElement(const QString &elementId) const
00730 {
00731     if (d->path.isNull() && d->themePath.isNull()) {
00732         return false;
00733     }
00734 
00735     return d->elementRect(elementId).isValid();
00736 }
00737 
00738 QString Svg::elementAtPoint(const QPoint &point) const
00739 {
00740     Q_UNUSED(point)
00741 
00742     return QString();
00743 /*
00744 FIXME: implement when Qt can support us!
00745     d->createRenderer();
00746     QSizeF naturalSize = d->renderer->defaultSize();
00747     qreal dx = d->size.width() / naturalSize.width();
00748     qreal dy = d->size.height() / naturalSize.height();
00749     //kDebug() << point << "is really"
00750     //         << QPoint(point.x() *dx, naturalSize.height() - point.y() * dy);
00751 
00752     return QString(); // d->renderer->elementAtPoint(QPoint(point.x() *dx, naturalSize.height() - point.y() * dy));
00753     */
00754 }
00755 
00756 bool Svg::isValid() const
00757 {
00758     if (d->path.isNull() && d->themePath.isNull()) {
00759         return false;
00760     }
00761 
00762     d->createRenderer();
00763     return d->renderer->isValid();
00764 }
00765 
00766 void Svg::setContainsMultipleImages(bool multiple)
00767 {
00768     d->multipleImages = multiple;
00769 }
00770 
00771 bool Svg::containsMultipleImages() const
00772 {
00773     return d->multipleImages;
00774 }
00775 
00776 void Svg::setImagePath(const QString &svgFilePath)
00777 {
00778     //BIC FIXME: setImagePath should be virtual, or call an internal virtual protected method
00779     if (FrameSvg *frame = qobject_cast<FrameSvg *>(this)) {
00780         frame->setImagePath(svgFilePath);
00781         return;
00782     }
00783 
00784     d->setImagePath(svgFilePath);
00785     //kDebug() << "repaintNeeded";
00786     emit repaintNeeded();
00787 }
00788 
00789 QString Svg::imagePath() const
00790 {
00791    return d->themed ? d->themePath : d->path;
00792 }
00793 
00794 void Svg::setUsingRenderingCache(bool useCache)
00795 {
00796     d->cacheRendering = useCache;
00797 }
00798 
00799 bool Svg::isUsingRenderingCache() const
00800 {
00801     return d->cacheRendering;
00802 }
00803 
00804 void Svg::setTheme(Plasma::Theme *theme)
00805 {
00806     if (!theme || theme == d->theme.data()) {
00807         return;
00808     }
00809 
00810     if (d->theme) {
00811         disconnect(d->theme.data(), 0, this, 0);
00812     }
00813 
00814     d->theme = theme;
00815     connect(theme, SIGNAL(themeChanged()), this, SLOT(themeChanged()));
00816     d->themeChanged();
00817 }
00818 
00819 Theme *Svg::theme() const
00820 {
00821     return d->theme ? d->theme.data() : Theme::defaultTheme();
00822 }
00823 
00824 } // Plasma namespace
00825 
00826 #include "svg.moc"
00827 

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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