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

318 lines
8.3 KiB
C++

/*
*
* This file is part of the KDE project.
* Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
*
* 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 "kiconcache.h"
#include <QtCore/QString>
#include <QtGui/QPixmap>
#include <QtCore/QFile>
#include <QtCore/QDataStream>
#include <QtCore/QFileInfo>
#include <QtCore/QDateTime>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <sys/file.h>
#include <time.h>
#define KDE_ICONCACHE_NAME "kde-icon-cache"
#define KDE_ICONCACHE_VERSION 0x000100
class KIconCache::Private
{
public:
Private(KIconCache* _q)
{
q = _q;
mUpdatesCheckedTime = 0;
}
bool themeDirsChanged()
{
if (q->existingIconThemeDirs(mThemeNames) != mThemeDirs ||
q->mostRecentMTime(mThemeDirs) != mThemesMTime) {
kDebug(264) << "Theme directory has been modified";
return true;
} else {
return false;
}
}
void checkForThemeUpdates()
{
if (!q->isEnabled()) {
return;
}
// Don't check more often than every 5 secs
const quint32 now = ::time(0);
if (now < mUpdatesCheckedTime + 5) {
return;
}
mUpdatesCheckedTime = now;
// Perhaps another process has already checked for updates in last 5 secs
const QFileInfo fi(mUpdatesFile);
if (fi.exists() && fi.lastModified().toTime_t() + 5 > now) {
return;
}
// Check for theme updates
if (themeDirsChanged()) {
// Update themes info and discard the cache
mThemeDirs = q->existingIconThemeDirs(mThemeNames);
mThemesMTime = q->mostRecentMTime(mThemeDirs);
q->discard();
}
// Update timestamp file
QFile f(mUpdatesFile);
f.open(QIODevice::WriteOnly);
}
KIconCache* q;
qint32 mDefaultIconSize[6];
QStringList mThemeNames;
QSet<QString> mThemeDirs;
quint32 mThemesMTime;
QString mUpdatesFile;
quint32 mUpdatesCheckedTime;
QString* mLoadPath;
QString mSavePath;
};
KIconCache::KIconCache()
: KPixmapCache(KDE_ICONCACHE_NAME), d(new Private(this))
{
d->mUpdatesFile = KGlobal::dirs()->locateLocal("cache", "kpc/"KDE_ICONCACHE_NAME".updated");
// Set limit to 10 MB
setCacheLimit(10 * 1024);
}
KIconCache::~KIconCache()
{
delete d;
}
void KIconCache::deleteCache()
{
KPixmapCache::deleteCache(KDE_ICONCACHE_NAME);
}
bool KIconCache::loadCustomIndexHeader(QDataStream& stream)
{
if (stream.atEnd()) {
return false;
}
// Load version
quint32 version;
stream >> version;
if (version != KDE_ICONCACHE_VERSION) {
kDebug(264) << "Obsolete iconcache version" << version << "will recreate";
return false;
}
// Load default sizes of icons
for (int i = 0; i < 6; i++) {
stream >> d->mDefaultIconSize[i];
}
stream >> d->mThemeNames;
stream >> d->mThemeDirs;
// TODO: use KPixmapCache's timestamp instead
stream >> d->mThemesMTime;
if (stream.status() != QDataStream::Ok) {
kWarning() << "Failed to read index file's header";
recreateCacheFiles();
return false;
}
// Make sure at least one theme was read
if (!d->mThemeNames.count()) {
kDebug(264) << "Empty themes list";
return false;
}
// Make sure the theme dirs haven't changed
if (d->themeDirsChanged()) {
return false;
}
d->mUpdatesCheckedTime= ::time(0);
return true;
}
void KIconCache::writeCustomIndexHeader(QDataStream& stream)
{
setValid(false);
stream << (quint32)KDE_ICONCACHE_VERSION;
for (int i = 0; i < 6; i++) {
stream << d->mDefaultIconSize[i];
}
// Save iconthemes info
stream << d->mThemeNames;
stream << d->mThemeDirs;
stream << d->mThemesMTime;
// Cache is valid if header was successfully written and we actually have
// the icontheme name(s)
if (stream.status() == QDataStream::Ok && d->mThemeNames.count()) {
setValid(true);
}
}
QSet<QString> KIconCache::existingIconThemeDirs(const QStringList& themeNames) const
{
// Find all possible icontheme dirs
// This has been taken from kicontheme.cpp
QStringList icondirs = KGlobal::dirs()->resourceDirs("icon")
<< KGlobal::dirs()->resourceDirs("xdgdata-icon")
<< "/usr/share/pixmaps/"
// These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
<< KGlobal::dirs()->resourceDirs("xdgdata-pixmap");
icondirs.removeDuplicates();
// Check which of theme actually contain existing dir of one of the
// given themes
QSet<QString> dirs;
for (QStringList::ConstIterator it = icondirs.constBegin(); it != icondirs.constEnd(); ++it) {
QStringList::ConstIterator themeIt;
for (themeIt = themeNames.begin(); themeIt != themeNames.end(); ++themeIt) {
QString dirName = *it + *themeIt + '/';
if (KStandardDirs::exists(dirName)) {
dirs.insert(dirName);
}
}
}
return dirs;
}
unsigned int KIconCache::mostRecentMTime(const QSet<QString>& dirNames) const
{
unsigned int timestamp = 0;
foreach (const QString &dir, dirNames) {
unsigned int mtime = QFileInfo(dir).lastModified().toTime_t();
if (timestamp < mtime) {
timestamp = mtime;
}
}
return timestamp;
}
int KIconCache::defaultIconSize(KIconLoader::Group group) const
{
if ((group < 0) || (group >= KIconLoader::LastGroup))
{
kDebug(264) << "Illegal icon group:" << group;
return -1;
}
return d->mDefaultIconSize[group];
}
void KIconCache::setThemeInfo(const QList<KIconTheme*>& themes)
{
if (themes.isEmpty()) {
for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) {
d->mDefaultIconSize[i] = 0;
}
return;
}
// This as to be done always, even if the cache itself is disabled
for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) {
d->mDefaultIconSize[i] = themes.first()->defaultSize(i);
}
if (!isEnabled()) {
return;
}
setValid(false);
// Save internal names and dirs of all themes
d->mThemeNames.clear();
foreach (KIconTheme* theme, themes) {
d->mThemeNames.append(theme->internalName());
}
d->mThemeDirs = existingIconThemeDirs(d->mThemeNames);
d->mThemesMTime = mostRecentMTime(d->mThemeDirs);
d->mUpdatesCheckedTime= ::time(0);
// Recreate the cache
recreateCacheFiles();
}
bool KIconCache::find(const QString& key, QPixmap& pix, QString* path)
{
d->checkForThemeUpdates();
d->mLoadPath = path;
// We can use QPixmapCache only if we don't need the path
setUseQPixmapCache(!path);
//kDebug(264) << "use QPC = " << useQPixmapCache();
bool ret = find(key, pix);
d->mLoadPath = 0;
return ret;
}
void KIconCache::insert(const QString& key, const QPixmap& pix, const QString& path)
{
d->mSavePath = path;
insert(key, pix);
d->mSavePath.clear();
}
bool KIconCache::find(const QString& key, QPixmap& pix)
{
// TODO: make sure that cache is still valid
return KPixmapCache::find(key, pix);
}
void KIconCache::insert(const QString& key, const QPixmap& pix)
{
// TODO: make sure that cache is still valid
KPixmapCache::insert(key, pix);
}
bool KIconCache::loadCustomData(QDataStream& stream)
{
QString path;
stream >> path;
if (d->mLoadPath) {
*d->mLoadPath = path;
}
return true;
}
bool KIconCache::writeCustomData(QDataStream& stream)
{
stream << d->mSavePath;
return true;
}