KDEUI
kiconcache.cpp
Go to the documentation of this file.
00001 /* 00002 * 00003 * This file is part of the KDE project. 00004 * Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License version 2 as published by the Free Software Foundation. 00009 * 00010 * This library 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 GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kiconcache.h" 00022 00023 #include <QtCore/QString> 00024 #include <QtGui/QPixmap> 00025 #include <QtCore/QFile> 00026 #include <QtCore/QDataStream> 00027 #include <QtCore/QFileInfo> 00028 #include <QtCore/QDateTime> 00029 00030 #include <kglobal.h> 00031 #include <kstandarddirs.h> 00032 #include <kdebug.h> 00033 00034 #include <sys/file.h> 00035 #include <time.h> 00036 00037 00038 #define KDE_ICONCACHE_NAME "kde-icon-cache" 00039 #define KDE_ICONCACHE_VERSION 0x000100 00040 00041 00042 class KIconCache::Private 00043 { 00044 public: 00045 Private(KIconCache* _q) 00046 { 00047 q = _q; 00048 mUpdatesCheckedTime = 0; 00049 } 00050 bool themeDirsChanged() 00051 { 00052 if (q->existingIconThemeDirs(mThemeNames) != mThemeDirs || 00053 q->mostRecentMTime(mThemeDirs) != mThemesMTime) { 00054 kDebug(264) << "Theme directory has been modified"; 00055 return true; 00056 } else { 00057 return false; 00058 } 00059 } 00060 void checkForThemeUpdates() 00061 { 00062 if (!q->isEnabled()) { 00063 return; 00064 } 00065 // Don't check more often than every 5 secs 00066 const quint32 now = ::time(0); 00067 if (now < mUpdatesCheckedTime + 5) { 00068 return; 00069 } 00070 00071 mUpdatesCheckedTime = now; 00072 // Perhaps another process has already checked for updates in last 5 secs 00073 const QFileInfo fi(mUpdatesFile); 00074 if (fi.exists() && fi.lastModified().toTime_t() + 5 > now) { 00075 return; 00076 } 00077 // Check for theme updates 00078 if (themeDirsChanged()) { 00079 // Update themes info and discard the cache 00080 mThemeDirs = q->existingIconThemeDirs(mThemeNames); 00081 mThemesMTime = q->mostRecentMTime(mThemeDirs); 00082 q->discard(); 00083 } 00084 // Update timestamp file 00085 QFile f(mUpdatesFile); 00086 f.open(QIODevice::WriteOnly); 00087 } 00088 00089 KIconCache* q; 00090 00091 qint32 mDefaultIconSize[6]; 00092 QStringList mThemeNames; 00093 QSet<QString> mThemeDirs; 00094 quint32 mThemesMTime; 00095 QString mUpdatesFile; 00096 quint32 mUpdatesCheckedTime; 00097 00098 QString* mLoadPath; 00099 QString mSavePath; 00100 }; 00101 00102 00103 KIconCache::KIconCache() 00104 : KPixmapCache(KDE_ICONCACHE_NAME), d(new Private(this)) 00105 { 00106 d->mUpdatesFile = KGlobal::dirs()->locateLocal("cache", "kpc/"KDE_ICONCACHE_NAME".updated"); 00107 // Set limit to 10 MB 00108 setCacheLimit(10 * 1024); 00109 } 00110 00111 KIconCache::~KIconCache() 00112 { 00113 delete d; 00114 } 00115 00116 void KIconCache::deleteCache() 00117 { 00118 KPixmapCache::deleteCache(KDE_ICONCACHE_NAME); 00119 } 00120 00121 bool KIconCache::loadCustomIndexHeader(QDataStream& stream) 00122 { 00123 if (stream.atEnd()) { 00124 return false; 00125 } 00126 00127 // Load version 00128 quint32 version; 00129 stream >> version; 00130 if (version != KDE_ICONCACHE_VERSION) { 00131 kDebug(264) << "Obsolete iconcache version" << version << "will recreate"; 00132 return false; 00133 } 00134 00135 // Load default sizes of icons 00136 for (int i = 0; i < 6; i++) { 00137 stream >> d->mDefaultIconSize[i]; 00138 } 00139 00140 00141 stream >> d->mThemeNames; 00142 stream >> d->mThemeDirs; 00143 // TODO: use KPixmapCache's timestamp instead 00144 stream >> d->mThemesMTime; 00145 00146 if (stream.status() != QDataStream::Ok) { 00147 kWarning() << "Failed to read index file's header"; 00148 recreateCacheFiles(); 00149 return false; 00150 } 00151 00152 // Make sure at least one theme was read 00153 if (!d->mThemeNames.count()) { 00154 kDebug(264) << "Empty themes list"; 00155 return false; 00156 } 00157 00158 // Make sure the theme dirs haven't changed 00159 if (d->themeDirsChanged()) { 00160 return false; 00161 } 00162 d->mUpdatesCheckedTime= ::time(0); 00163 00164 return true; 00165 } 00166 00167 void KIconCache::writeCustomIndexHeader(QDataStream& stream) 00168 { 00169 setValid(false); 00170 00171 stream << (quint32)KDE_ICONCACHE_VERSION; 00172 00173 for (int i = 0; i < 6; i++) { 00174 stream << d->mDefaultIconSize[i]; 00175 } 00176 00177 // Save iconthemes info 00178 stream << d->mThemeNames; 00179 stream << d->mThemeDirs; 00180 stream << d->mThemesMTime; 00181 00182 // Cache is valid if header was successfully written and we actually have 00183 // the icontheme name(s) 00184 if (stream.status() == QDataStream::Ok && d->mThemeNames.count()) { 00185 setValid(true); 00186 } 00187 } 00188 00189 QSet<QString> KIconCache::existingIconThemeDirs(const QStringList& themeNames) const 00190 { 00191 // Find all possible icontheme dirs 00192 // This has been taken from kicontheme.cpp 00193 QStringList icondirs = KGlobal::dirs()->resourceDirs("icon") 00194 << KGlobal::dirs()->resourceDirs("xdgdata-icon") 00195 << "/usr/share/pixmaps/" 00196 // These are not in the icon spec, but e.g. GNOME puts some icons there anyway. 00197 << KGlobal::dirs()->resourceDirs("xdgdata-pixmap"); 00198 icondirs.removeDuplicates(); 00199 00200 // Check which of theme actually contain existing dir of one of the 00201 // given themes 00202 QSet<QString> dirs; 00203 for (QStringList::ConstIterator it = icondirs.constBegin(); it != icondirs.constEnd(); ++it) { 00204 QStringList::ConstIterator themeIt; 00205 for (themeIt = themeNames.begin(); themeIt != themeNames.end(); ++themeIt) { 00206 QString dirName = *it + *themeIt + '/'; 00207 if (KStandardDirs::exists(dirName)) { 00208 dirs.insert(dirName); 00209 } 00210 } 00211 } 00212 00213 return dirs; 00214 } 00215 00216 unsigned int KIconCache::mostRecentMTime(const QSet<QString>& dirNames) const 00217 { 00218 unsigned int timestamp = 0; 00219 foreach (const QString &dir, dirNames) { 00220 unsigned int mtime = QFileInfo(dir).lastModified().toTime_t(); 00221 if (timestamp < mtime) { 00222 timestamp = mtime; 00223 } 00224 } 00225 00226 return timestamp; 00227 } 00228 00229 int KIconCache::defaultIconSize(KIconLoader::Group group) const 00230 { 00231 if ((group < 0) || (group >= KIconLoader::LastGroup)) 00232 { 00233 kDebug(264) << "Illegal icon group:" << group; 00234 return -1; 00235 } 00236 return d->mDefaultIconSize[group]; 00237 } 00238 00239 void KIconCache::setThemeInfo(const QList<KIconTheme*>& themes) 00240 { 00241 if (themes.isEmpty()) { 00242 for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) { 00243 d->mDefaultIconSize[i] = 0; 00244 } 00245 return; 00246 } 00247 // This as to be done always, even if the cache itself is disabled 00248 for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) { 00249 d->mDefaultIconSize[i] = themes.first()->defaultSize(i); 00250 } 00251 00252 if (!isEnabled()) { 00253 return; 00254 } 00255 setValid(false); 00256 00257 // Save internal names and dirs of all themes 00258 d->mThemeNames.clear(); 00259 foreach (KIconTheme* theme, themes) { 00260 d->mThemeNames.append(theme->internalName()); 00261 } 00262 d->mThemeDirs = existingIconThemeDirs(d->mThemeNames); 00263 d->mThemesMTime = mostRecentMTime(d->mThemeDirs); 00264 d->mUpdatesCheckedTime= ::time(0); 00265 00266 // Recreate the cache 00267 recreateCacheFiles(); 00268 } 00269 00270 bool KIconCache::find(const QString& key, QPixmap& pix, QString* path) 00271 { 00272 d->checkForThemeUpdates(); 00273 00274 d->mLoadPath = path; 00275 // We can use QPixmapCache only if we don't need the path 00276 setUseQPixmapCache(!path); 00277 //kDebug(264) << "use QPC = " << useQPixmapCache(); 00278 bool ret = find(key, pix); 00279 d->mLoadPath = 0; 00280 return ret; 00281 } 00282 00283 void KIconCache::insert(const QString& key, const QPixmap& pix, const QString& path) 00284 { 00285 d->mSavePath = path; 00286 insert(key, pix); 00287 d->mSavePath.clear(); 00288 } 00289 00290 bool KIconCache::find(const QString& key, QPixmap& pix) 00291 { 00292 // TODO: make sure that cache is still valid 00293 return KPixmapCache::find(key, pix); 00294 } 00295 00296 void KIconCache::insert(const QString& key, const QPixmap& pix) 00297 { 00298 // TODO: make sure that cache is still valid 00299 KPixmapCache::insert(key, pix); 00300 } 00301 00302 bool KIconCache::loadCustomData(QDataStream& stream) 00303 { 00304 QString path; 00305 stream >> path; 00306 if (d->mLoadPath) { 00307 *d->mLoadPath = path; 00308 } 00309 00310 return true; 00311 } 00312 00313 bool KIconCache::writeCustomData(QDataStream& stream) 00314 { 00315 stream << d->mSavePath; 00316 return true; 00317 } 00318
KDE 4.6 API Reference