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 | |
30 | class QString; |
31 | class 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 | */ |
85 | class KDEUI_EXPORT KPixmapCache |
86 | { |
87 | public: |
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 | |
281 | protected: |
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 (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 (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 | |
377 | private: |
378 | /// @internal |
379 | class Private; |
380 | friend class Private; |
381 | Private * const d; ///< @internal |
382 | }; |
383 | |
384 | #endif // KPIXMAPCACHE_H |
385 | |