00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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
00146
00147 if (!ids.contains(id)) {
00148 ids.append(id);
00149 }
00150
00151 if (QPixmapCache::find(id, p)) {
00152
00153 return;
00154 } else {
00155
00156 }
00157
00158
00159
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
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
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
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
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
00269 eraseRenderer();
00270
00271
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
00393
00394 return QString();
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 }
00426
00427 #include "svg.moc"
00428