/* * * This file is part of the KDE project. * Copyright (C) 2007 Rivo Laks * * 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. */ #ifndef KPIXMAPCACHE_H #define KPIXMAPCACHE_H #include #include #include #include class QString; class QPixmap; /** * @brief General-purpose pixmap cache for KDE. * * The pixmap cache can be used to store pixmaps which can later be loaded * from the cache very quickly. * * Its most common use is storing SVG images which might be expensive to * render every time they are used. With the cache you can render each SVG * only once and later use the stored version unless the SVG file or requested * pixmap size changes. * * KPixmapCache's API is similar to that of the QPixmapCache so if you're * already using the latter then all you need to do is creating a KPixmapCache * object (unlike QPixmapCache, KPixmapCache doesn't have many static methods) * and calling @ref insert() and @ref find() method on that object: * @code * // Create KPixmapCache object * KPixmapCache* cache = new KPixmapCache("myapp-pixmaps"); * // Load a pixmap * QPixmap pix; * if (!cache->find("pixmap-1", pix)) { * // Pixmap isn't in the cache, create it and insert to cache * pix = createPixmapFromData(); * cache->insert("pixmap-1", pix); * } * // Use pix * @endcode * * The above example illustrates that you can also cache pixmaps created from * some data. In case such data is updated, you might need to discard cache * contents using @ref discard() method: * @code * // Discard the cache if it's too old * if (cache->timestamp() < mydataTimestamp()) { * cache->discard(); * } * // Now the cache contains up-to-date data * @endcode * As demonstrated, you can use cache's @ref timestamp() method to see when * the cache was created. If necessary, you can also change the timestamp * using @ref setTimestamp() method. * * @deprecated KPixmapCache is susceptible to various non-trivial locking bugs and * inefficiencies, and is supported for backward compatibility only (since it exposes * a QDataStream API for subclasses). Users should port to KImageCache for a very close * work-alike, or KSharedDataCache if they need more control. * * @see KImageCache, KSharedDataCache * * @author Rivo Laks */ class KDEUI_EXPORT KPixmapCache { public: /** * Constucts the pixmap cache object. * @param name unique name of the cache */ explicit KPixmapCache(const QString& name); virtual ~KPixmapCache(); /** * Tries to load pixmap with the specified @a key from cache. If the pixmap * is found it is stored in @a pix, otherwise @a pix is unchanged. * * @return true when pixmap was found and loaded from cache, false otherwise */ virtual bool find(const QString& key, QPixmap& pix); /** * Inserts the pixmap @a pix into the cache, associated with the key @a key. * * Any existing pixmaps associated with @a key are overwritten. */ virtual void insert(const QString& key, const QPixmap& pix); /** * Loads a pixmap from given file, using the cache. If the file does not * exist on disk, an empty pixmap is returned, even if that file had * previously been cached. In addition, if the file's modified-time is * more recent than cache's @ref timestamp(), the @em entire cache is * discarded (to be regenerated). This behavior may change in a future * KDE Platform release. If the cached data is current the pixmap * is returned directly from the cache without any file loading. * * @note The mapping between @a filename and the actual key used internally * is implementation-dependent and can change without warning. Use insert() * manually if you need control of the key, otherwise consistently use this * function. * * @param filename The name of the pixmap to load, cache, and return. * @return The given pixmap, or an empty pixmap if the file was invalid or did * not exist. */ QPixmap loadFromFile(const QString& filename); /** * Same as loadFromFile(), but using an SVG file instead. You may optionally * pass in a @a size to control the size of the output pixmap. * * @note The returned pixmap is only cached for identical filenames and sizes. * If you change the size in between calls to this function then the * pixmap will have to be regenerated again. * * @param filename The filename of the SVG file to load. * @param size size of the pixmap where the SVG is render to. If not given * then the SVG file's default size is used. * @return an empty pixmap if the file does not exist or was invalid, otherwise * a pixmap of the desired @a size. */ QPixmap loadFromSvg(const QString& filename, const QSize& size = QSize()); /** * @note KPixmapCache does not ever change the timestamp, so the application * must set the timestamp if it to be used. * @return Timestamp of the cache, set using the setTimestamp() method. */ unsigned int timestamp() const; /** * Sets the timestamp of app-specific cache. It's saved in the cache file * and can later be retrieved using the timestamp() method. * By default the timestamp is set to the cache creation time. */ void setTimestamp(unsigned int time); /** * Sets whether QPixmapCache (memory caching) should be used in addition * to disk cache. QPixmapCache is used by default. * * @note On most systems KPixmapCache can use shared-memory to share cached * pixmaps with other applications attached to the same shared pixmap, * which means additional memory caching is unnecessary and actually * wasteful of memory. * * @warning QPixmapCache is shared among the entire process and therefore * can cause strange interactions with other instances of KPixmapCache. * This may be fixed in the future and should be not relied upon. */ // KDE5 Get rid of QPixmapCache and use a sane cache instead. void setUseQPixmapCache(bool use); /** * Whether QPixmapCache should be used to cache pixmaps in memory in * addition to caching them on the disk. * * @b NOTE: The design of QPixmapCache means that the entries stored in * the cache are shared throughout the entire process, and not just in * this particular KPixmapCache. KPixmapCache makes an effort to ensure * that entries from other KPixmapCaches do not inadvertently spill over * into this one, but is not entirely successful (see discard()) */ bool useQPixmapCache() const; /** * @return approximate size of the cache, in kilobytes (1 kilobyte == 1024 bytes) */ int size() const; /** * @return maximum size of the cache (in kilobytes). * Default setting is 3 megabytes (1 megabyte = 2^20 bytes). */ int cacheLimit() const; /** * Sets the maximum size of the cache (in kilobytes). If cache gets bigger * than the limit then some entries are removed (according to * removeEntryStrategy()). * * Setting the cache limit to 0 disables caching (as all entries will get * immediately removed). * * Note that the cleanup might not be done immediately, so the cache might * temporarily (for a few seconds) grow bigger than the limit. */ void setCacheLimit(int kbytes); /** * Describes which entries will be removed first during cache cleanup. * @see removeEntryStrategy(), @see setRemoveEntryStrategy() */ enum RemoveStrategy { /// oldest entries are removed first. RemoveOldest, /// least used entries are removed first. RemoveSeldomUsed, /// least recently used entries are removed first. RemoveLeastRecentlyUsed }; /** * @return current entry removal strategy. * Default is RemoveLeastRecentlyUsed. */ RemoveStrategy removeEntryStrategy() const; /** * Sets the removeEntryStrategy used when removing entries. */ void setRemoveEntryStrategy(RemoveStrategy strategy); /** * Cache will be disabled when e.g. its data file cannot be created or * read. * * @return true when the cache is enabled. */ bool isEnabled() const; /** * @return true when the cache is ready to be used. Not being valid usually * means that some additional initialization has to be done before the * cache can be used. */ bool isValid() const; /** * Deletes a pixmap cache. * @param name unique name of the cache to be deleted */ // KDE5: Static function oh how I hate you, this makes it very difficult to perform // appropriate locking and synchronization to actually remove the cache. static void deleteCache(const QString& name); /** * Deletes all entries and reinitializes this cache. * * @b NOTE: If useQPixmapCache is set to true then that cache must also * be cleared. There is only one QPixmapCache for the entire process * however so other KPixmapCaches and other QPixmapCache users may also * be affected, leading to a temporary slowdown until the QPixmapCache is * repopulated. */ void discard(); /** * Removes some of the entries in the cache according to current * removeEntryStrategy(). * * @param newsize wanted size of the cache, in bytes. If 0 is given then * current cacheLimit() is used. * * @warning This currently works by copying some entries to a new cache and * then replacing the old cache with the new one. Thus it might be slow and * will temporarily use extra disk space. */ void removeEntries(int newsize = 0); protected: /** * Makes sure that the cache is initialized correctly, including the loading of the * cache index and data, and any shared memory attachments (for systems where that * is enabled). * * @note Although this method is protected you should not use it from any subclasses. * * @internal */ // KDE5: rename to ensureInitialized() // KDE5: Make private or move to Private void ensureInited() const; /** * Can be used by subclasses to load custom data from the stream. * This function will be called by KPixmapCache immediately following the * image data for a single image being read from @a stream. * (This function is called once for every single image). * * @see writeCustomData * @see loadCustomIndexHeader * @param stream the QDataStream to read data from * @return true if custom data was successfully loaded, false otherwise. If * false is returned then the cached item is assumed to be invalid and * will not be available to find() or contains(). */ virtual bool loadCustomData(QDataStream& stream); /** * Can be used by subclasses to write custom data into the stream. * This function will be called by KPixmapCache immediately after the * image data for a single image has been written to @a stream. * (This function is called once for every single image). * * @see loadCustomData * @see writeCustomIndexHeader * @param stream the QDataStream to write data to */ virtual bool writeCustomData(QDataStream& stream); /** * Can be used by subclasses to load custom data from cache's header. * This function will be called by KPixmapCache immediately after the * index header has been written out. (This function is called one time * only for the entire cache). * * @see loadCustomData * @see writeCustomIndexHeader * @param stream the QDataStream to read data from * @return true if custom index header data was successfully read, false * otherwise. If false is returned then the cache is assumed to * be invalid and further processing does not occur. */ virtual bool loadCustomIndexHeader(QDataStream& stream); /** * Can be used by subclasses to write custom data into cache's header. * This function will be called by KPixmapCache immediately following the * index header has being loaded. (This function is called one time * only for the entire cache). * * @see writeCustomData * @see loadCustomIndexHeader * @param stream the QDataStream to write data to */ virtual void writeCustomIndexHeader(QDataStream& stream); /** * Sets whether this cache is valid or not. (The cache must be enabled in addition * for isValid() to return true. @see isEnabled(), @see setEnabled()). * * Most cache functions do not work if the cache is not valid. KPixmapCache assumes * the cache is valid as long as its cache files were able to be created (see * recreateCacheFiles()) even if the cache is not enabled. * * Can be used by subclasses to indicate that cache needs some additional * initialization before it can be used (note that KPixmapCache will @em not handle * actually performing this extra initialization). */ void setValid(bool valid); /** * This function causes the cache files to be recreate by invalidating the cache. * Any shared memory mappings (if enabled) are dropped temporarily as well. * * @note The recreated cache will be initially empty, but with the same size limits * and entry removal strategy (see removeEntryStrategy()). * * If you use this in a subclass be prepared to handle writeCustomData() and * writeCustomIndexHeader(). * * @return true if the cache was successfully recreated. */ bool recreateCacheFiles(); private: /// @internal class Private; friend class Private; Private * const d; ///< @internal }; #endif // KPIXMAPCACHE_H