1/*
2 *
3 * This file is part of the KDE project.
4 * Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License version 2 as published by the Free Software Foundation.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#ifndef KPIXMAPCACHE_H
22#define KPIXMAPCACHE_H
23
24#include <kdeui_export.h>
25
26#include <QtCore/QList>
27#include <QtCore/QSet>
28#include <QtCore/QSize>
29
30class QString;
31class QPixmap;
32
33
34/**
35 * @brief General-purpose pixmap cache for KDE.
36 *
37 * The pixmap cache can be used to store pixmaps which can later be loaded
38 * from the cache very quickly.
39 *
40 * Its most common use is storing SVG images which might be expensive to
41 * render every time they are used. With the cache you can render each SVG
42 * only once and later use the stored version unless the SVG file or requested
43 * pixmap size changes.
44 *
45 * KPixmapCache's API is similar to that of the QPixmapCache so if you're
46 * already using the latter then all you need to do is creating a KPixmapCache
47 * object (unlike QPixmapCache, KPixmapCache doesn't have many static methods)
48 * and calling @ref insert() and @ref find() method on that object:
49 * @code
50 * // Create KPixmapCache object
51 * KPixmapCache* cache = new KPixmapCache("myapp-pixmaps");
52 * // Load a pixmap
53 * QPixmap pix;
54 * if (!cache->find("pixmap-1", pix)) {
55 * // Pixmap isn't in the cache, create it and insert to cache
56 * pix = createPixmapFromData();
57 * cache->insert("pixmap-1", pix);
58 * }
59 * // Use pix
60 * @endcode
61 *
62 * The above example illustrates that you can also cache pixmaps created from
63 * some data. In case such data is updated, you might need to discard cache
64 * contents using @ref discard() method:
65 * @code
66 * // Discard the cache if it's too old
67 * if (cache->timestamp() < mydataTimestamp()) {
68 * cache->discard();
69 * }
70 * // Now the cache contains up-to-date data
71 * @endcode
72 * As demonstrated, you can use cache's @ref timestamp() method to see when
73 * the cache was created. If necessary, you can also change the timestamp
74 * using @ref setTimestamp() method.
75 *
76 * @deprecated KPixmapCache is susceptible to various non-trivial locking bugs and
77 * inefficiencies, and is supported for backward compatibility only (since it exposes
78 * a QDataStream API for subclasses). Users should port to KImageCache for a very close
79 * work-alike, or KSharedDataCache if they need more control.
80 *
81 * @see KImageCache, KSharedDataCache
82 *
83 * @author Rivo Laks
84 */
85class KDEUI_EXPORT KPixmapCache
86{
87public:
88 /**
89 * Constucts the pixmap cache object.
90 * @param name unique name of the cache
91 */
92 explicit KPixmapCache(const QString& name);
93 virtual ~KPixmapCache();
94
95 /**
96 * Tries to load pixmap with the specified @a key from cache. If the pixmap
97 * is found it is stored in @a pix, otherwise @a pix is unchanged.
98 *
99 * @return true when pixmap was found and loaded from cache, false otherwise
100 */
101 virtual bool find(const QString& key, QPixmap& pix);
102
103 /**
104 * Inserts the pixmap @a pix into the cache, associated with the key @a key.
105 *
106 * Any existing pixmaps associated with @a key are overwritten.
107 */
108 virtual void insert(const QString& key, const QPixmap& pix);
109
110 /**
111 * Loads a pixmap from given file, using the cache. If the file does not
112 * exist on disk, an empty pixmap is returned, even if that file had
113 * previously been cached. In addition, if the file's modified-time is
114 * more recent than cache's @ref timestamp(), the @em entire cache is
115 * discarded (to be regenerated). This behavior may change in a future
116 * KDE Platform release. If the cached data is current the pixmap
117 * is returned directly from the cache without any file loading.
118 *
119 * @note The mapping between @a filename and the actual key used internally
120 * is implementation-dependent and can change without warning. Use insert()
121 * manually if you need control of the key, otherwise consistently use this
122 * function.
123 *
124 * @param filename The name of the pixmap to load, cache, and return.
125 * @return The given pixmap, or an empty pixmap if the file was invalid or did
126 * not exist.
127 */
128 QPixmap loadFromFile(const QString& filename);
129
130 /**
131 * Same as loadFromFile(), but using an SVG file instead. You may optionally
132 * pass in a @a size to control the size of the output pixmap.
133 *
134 * @note The returned pixmap is only cached for identical filenames and sizes.
135 * If you change the size in between calls to this function then the
136 * pixmap will have to be regenerated again.
137 *
138 * @param filename The filename of the SVG file to load.
139 * @param size size of the pixmap where the SVG is render to. If not given
140 * then the SVG file's default size is used.
141 * @return an empty pixmap if the file does not exist or was invalid, otherwise
142 * a pixmap of the desired @a size.
143 */
144 QPixmap loadFromSvg(const QString& filename, const QSize& size = QSize());
145
146 /**
147 * @note KPixmapCache does not ever change the timestamp, so the application
148 * must set the timestamp if it to be used.
149 * @return Timestamp of the cache, set using the setTimestamp() method.
150 */
151 unsigned int timestamp() const;
152
153 /**
154 * Sets the timestamp of app-specific cache. It's saved in the cache file
155 * and can later be retrieved using the timestamp() method.
156 * By default the timestamp is set to the cache creation time.
157 */
158 void setTimestamp(unsigned int time);
159
160 /**
161 * Sets whether QPixmapCache (memory caching) should be used in addition
162 * to disk cache. QPixmapCache is used by default.
163 *
164 * @note On most systems KPixmapCache can use shared-memory to share cached
165 * pixmaps with other applications attached to the same shared pixmap,
166 * which means additional memory caching is unnecessary and actually
167 * wasteful of memory.
168 *
169 * @warning QPixmapCache is shared among the entire process and therefore
170 * can cause strange interactions with other instances of KPixmapCache.
171 * This may be fixed in the future and should be not relied upon.
172 */
173 // KDE5 Get rid of QPixmapCache and use a sane cache instead.
174 void setUseQPixmapCache(bool use);
175
176 /**
177 * Whether QPixmapCache should be used to cache pixmaps in memory in
178 * addition to caching them on the disk.
179 *
180 * @b NOTE: The design of QPixmapCache means that the entries stored in
181 * the cache are shared throughout the entire process, and not just in
182 * this particular KPixmapCache. KPixmapCache makes an effort to ensure
183 * that entries from other KPixmapCaches do not inadvertently spill over
184 * into this one, but is not entirely successful (see discard())
185 */
186 bool useQPixmapCache() const;
187
188 /**
189 * @return approximate size of the cache, in kilobytes (1 kilobyte == 1024 bytes)
190 */
191 int size() const;
192
193 /**
194 * @return maximum size of the cache (in kilobytes).
195 * Default setting is 3 megabytes (1 megabyte = 2^20 bytes).
196 */
197 int cacheLimit() const;
198
199 /**
200 * Sets the maximum size of the cache (in kilobytes). If cache gets bigger
201 * than the limit then some entries are removed (according to
202 * removeEntryStrategy()).
203 *
204 * Setting the cache limit to 0 disables caching (as all entries will get
205 * immediately removed).
206 *
207 * Note that the cleanup might not be done immediately, so the cache might
208 * temporarily (for a few seconds) grow bigger than the limit.
209 */
210 void setCacheLimit(int kbytes);
211
212 /**
213 * Describes which entries will be removed first during cache cleanup.
214 * @see removeEntryStrategy(), @see setRemoveEntryStrategy()
215 */
216 enum RemoveStrategy { /// oldest entries are removed first.
217 RemoveOldest,
218 /// least used entries are removed first.
219 RemoveSeldomUsed,
220 /// least recently used entries are removed first.
221 RemoveLeastRecentlyUsed
222 };
223 /**
224 * @return current entry removal strategy.
225 * Default is RemoveLeastRecentlyUsed.
226 */
227 RemoveStrategy removeEntryStrategy() const;
228
229 /**
230 * Sets the removeEntryStrategy used when removing entries.
231 */
232 void setRemoveEntryStrategy(RemoveStrategy strategy);
233
234 /**
235 * Cache will be disabled when e.g. its data file cannot be created or
236 * read.
237 *
238 * @return true when the cache is enabled.
239 */
240 bool isEnabled() const;
241
242 /**
243 * @return true when the cache is ready to be used. Not being valid usually
244 * means that some additional initialization has to be done before the
245 * cache can be used.
246 */
247 bool isValid() const;
248
249 /**
250 * Deletes a pixmap cache.
251 * @param name unique name of the cache to be deleted
252 */
253 // KDE5: Static function oh how I hate you, this makes it very difficult to perform
254 // appropriate locking and synchronization to actually remove the cache.
255 static void deleteCache(const QString& name);
256
257 /**
258 * Deletes all entries and reinitializes this cache.
259 *
260 * @b NOTE: If useQPixmapCache is set to true then that cache must also
261 * be cleared. There is only one QPixmapCache for the entire process
262 * however so other KPixmapCaches and other QPixmapCache users may also
263 * be affected, leading to a temporary slowdown until the QPixmapCache is
264 * repopulated.
265 */
266 void discard();
267
268 /**
269 * Removes some of the entries in the cache according to current
270 * removeEntryStrategy().
271 *
272 * @param newsize wanted size of the cache, in bytes. If 0 is given then
273 * current cacheLimit() is used.
274 *
275 * @warning This currently works by copying some entries to a new cache and
276 * then replacing the old cache with the new one. Thus it might be slow and
277 * will temporarily use extra disk space.
278 */
279 void removeEntries(int newsize = 0);
280
281protected:
282 /**
283 * Makes sure that the cache is initialized correctly, including the loading of the
284 * cache index and data, and any shared memory attachments (for systems where that
285 * is enabled).
286 *
287 * @note Although this method is protected you should not use it from any subclasses.
288 *
289 * @internal
290 */
291 // KDE5: rename to ensureInitialized()
292 // KDE5: Make private or move to Private
293 void ensureInited() const;
294
295 /**
296 * Can be used by subclasses to load custom data from the stream.
297 * This function will be called by KPixmapCache immediately following the
298 * image data for a single image being read from @a stream.
299 * (This function is called once for every single image).
300 *
301 * @see writeCustomData
302 * @see loadCustomIndexHeader
303 * @param stream the QDataStream to read data from
304 * @return true if custom data was successfully loaded, false otherwise. If
305 * false is returned then the cached item is assumed to be invalid and
306 * will not be available to find() or contains().
307 */
308 virtual bool loadCustomData(QDataStream& stream);
309
310 /**
311 * Can be used by subclasses to write custom data into the stream.
312 * This function will be called by KPixmapCache immediately after the
313 * image data for a single image has been written to @a stream.
314 * (This function is called once for every single image).
315 *
316 * @see loadCustomData
317 * @see writeCustomIndexHeader
318 * @param stream the QDataStream to write data to
319 */
320 virtual bool writeCustomData(QDataStream& stream);
321
322 /**
323 * Can be used by subclasses to load custom data from cache's header.
324 * This function will be called by KPixmapCache immediately after the
325 * index header has been written out. (This function is called one time
326 * only for the entire cache).
327 *
328 * @see loadCustomData
329 * @see writeCustomIndexHeader
330 * @param stream the QDataStream to read data from
331 * @return true if custom index header data was successfully read, false
332 * otherwise. If false is returned then the cache is assumed to
333 * be invalid and further processing does not occur.
334 */
335 virtual bool loadCustomIndexHeader(QDataStream& stream);
336
337 /**
338 * Can be used by subclasses to write custom data into cache's header.
339 * This function will be called by KPixmapCache immediately following the
340 * index header has being loaded. (This function is called one time
341 * only for the entire cache).
342 *
343 * @see writeCustomData
344 * @see loadCustomIndexHeader
345 * @param stream the QDataStream to write data to
346 */
347 virtual void writeCustomIndexHeader(QDataStream& stream);
348
349 /**
350 * Sets whether this cache is valid or not. (The cache must be enabled in addition
351 * for isValid() to return true. @see isEnabled(), @see setEnabled()).
352 *
353 * Most cache functions do not work if the cache is not valid. KPixmapCache assumes
354 * the cache is valid as long as its cache files were able to be created (see
355 * recreateCacheFiles()) even if the cache is not enabled.
356 *
357 * Can be used by subclasses to indicate that cache needs some additional
358 * initialization before it can be used (note that KPixmapCache will @em not handle
359 * actually performing this extra initialization).
360 */
361 void setValid(bool valid);
362
363 /**
364 * This function causes the cache files to be recreate by invalidating the cache.
365 * Any shared memory mappings (if enabled) are dropped temporarily as well.
366 *
367 * @note The recreated cache will be initially empty, but with the same size limits
368 * and entry removal strategy (see removeEntryStrategy()).
369 *
370 * If you use this in a subclass be prepared to handle writeCustomData() and
371 * writeCustomIndexHeader().
372 *
373 * @return true if the cache was successfully recreated.
374 */
375 bool recreateCacheFiles();
376
377private:
378 /// @internal
379 class Private;
380 friend class Private;
381 Private * const d; ///< @internal
382};
383
384#endif // KPIXMAPCACHE_H
385