kdelibs/kdeui/util/kimagecache.cpp
2014-11-13 01:04:59 +02:00

200 lines
5.1 KiB
C++

/*
* This file is part of the KDE project.
* Copyright © 2010 Michael Pyne <mpyne@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "kimagecache.h"
#include <QtGui/QPixmap>
#include <QtGui/QImage>
#include <QtCore/QBuffer>
#include <QtCore/QCache>
#include <QtCore/QCoreApplication>
#include <time.h>
/**
* This is a QObject subclass so we can catch the signal that the application is about
* to close and properly release any QPixmaps we have cached.
*/
class KImageCache::Private : public QObject
{
Q_OBJECT
public:
Private(QObject *parent = 0)
: QObject(parent)
, timestamp(::time(0))
, enablePixmapCaching(true)
{
QObject::connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
this, SLOT(clearPixmaps()));
}
/**
* Inserts a pixmap into the pixmap cache if the pixmap cache is enabled, with
* weighting based on image size and bit depth.
*/
bool insertPixmap(const QString &key, QPixmap *pixmap)
{
if (enablePixmapCaching && pixmap && !pixmap->isNull()) {
// "cost" parameter is based on both image size and depth to make cost
// based on size in bytes instead of area on-screen.
return pixmapCache.insert(key, pixmap,
pixmap->width() * pixmap->height() * pixmap->depth() / 8);
}
return false;
}
public slots:
void clearPixmaps()
{
pixmapCache.clear();
}
public:
time_t timestamp;
/**
* This is used to cache pixmaps as they are inserted, instead of always
* converting to image data and storing that in shared memory.
*/
QCache<QString, QPixmap> pixmapCache;
bool enablePixmapCaching;
};
KImageCache::KImageCache(const QString &cacheName,
unsigned defaultCacheSize,
unsigned expectedItemSize)
: KSharedDataCache(cacheName, defaultCacheSize, expectedItemSize)
, d(new Private)
{
// Use at least 16 KiB for the pixmap cache
d->pixmapCache.setMaxCost(qMax(defaultCacheSize / 8, (unsigned int) 16384));
}
KImageCache::~KImageCache()
{
delete d;
}
bool KImageCache::insertImage(const QString &key, const QImage &image)
{
QBuffer buffer;
buffer.open(QBuffer::WriteOnly);
image.save(&buffer, "PNG");
if (this->insert(key, buffer.buffer())) {
d->timestamp = ::time(0);
return true;
}
return false;
}
bool KImageCache::insertPixmap(const QString &key, const QPixmap &pixmap)
{
d->insertPixmap(key, new QPixmap(pixmap));
// One thing to think about is only inserting things to the shared cache
// that are frequently used. But that would require tracking the use count
// in our local cache too, which I think is probably too much work.
return insertImage(key, pixmap.toImage());
}
bool KImageCache::findImage(const QString &key, QImage *destination) const
{
QByteArray cachedData;
if (!this->find(key, &cachedData) || cachedData.isNull()) {
return false;
}
if (destination) {
destination->loadFromData(cachedData, "PNG");
}
return true;
}
bool KImageCache::findPixmap(const QString &key, QPixmap *destination) const
{
if (d->enablePixmapCaching) {
QPixmap *cachedPixmap = d->pixmapCache.object(key);
if (cachedPixmap) {
if (destination) {
*destination = *cachedPixmap;
}
return true;
}
}
QByteArray cachedData;
if (!this->find(key, &cachedData) || cachedData.isNull()) {
return false;
}
if (destination) {
destination->loadFromData(cachedData, "PNG");
// Manually re-insert to pixmap cache if we'll be using this one.
d->insertPixmap(key, new QPixmap(*destination));
}
return true;
}
void KImageCache::clear()
{
d->pixmapCache.clear();
KSharedDataCache::clear();
}
time_t KImageCache::lastModifiedTime() const
{
return d->timestamp;
}
bool KImageCache::pixmapCaching() const
{
return d->enablePixmapCaching;
}
void KImageCache::setPixmapCaching(bool enable)
{
if (enable != d->enablePixmapCaching) {
d->enablePixmapCaching = enable;
if (!enable) {
d->pixmapCache.clear();
}
}
}
int KImageCache::pixmapCacheLimit() const
{
return d->pixmapCache.maxCost();
}
void KImageCache::setPixmapCacheLimit(int size)
{
d->pixmapCache.setMaxCost(size);
}
#include "kimagecache.moc"