File indexing completed on 2024-04-21 14:55:57

0001 /*
0002  *
0003  * This file is part of the KDE project.
0004  * Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License version 2 as published by the Free Software Foundation.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #ifndef KPIXMAPCACHE_H
0022 #define KPIXMAPCACHE_H
0023 
0024 #include <kdelibs4support_export.h>
0025 
0026 #include <QList>
0027 #include <QSet>
0028 #include <QSize>
0029 #include <QDateTime>
0030 
0031 class QString;
0032 class QPixmap;
0033 
0034 /**
0035  * @brief General-purpose pixmap cache for KDE.
0036  *
0037  * The pixmap cache can be used to store pixmaps which can later be loaded
0038  *  from the cache very quickly.
0039  *
0040  * Its most common use is storing SVG images which might be expensive to
0041  *  render every time they are used. With the cache you can render each SVG
0042  *  only once and later use the stored version unless the SVG file or requested
0043  *  pixmap size changes.
0044  *
0045  * KPixmapCache's API is similar to that of the QPixmapCache so if you're
0046  *  already using the latter then all you need to do is creating a KPixmapCache
0047  *  object (unlike QPixmapCache, KPixmapCache doesn't have many static methods)
0048  *  and calling @ref insert() and @ref find() method on that object:
0049  *  @code
0050  *  // Create KPixmapCache object
0051  *  KPixmapCache* cache = new KPixmapCache("myapp-pixmaps");
0052  *  // Load a pixmap
0053  *  QPixmap pix;
0054  *  if (!cache->find("pixmap-1", pix)) {
0055  *      // Pixmap isn't in the cache, create it and insert to cache
0056  *      pix = createPixmapFromData();
0057  *      cache->insert("pixmap-1", pix);
0058  *  }
0059  *  // Use pix
0060  *  @endcode
0061  *
0062  * The above example illustrates that you can also cache pixmaps created from
0063  *  some data. In case such data is updated, you might need to discard cache
0064  *  contents using @ref discard() method:
0065  * @code
0066  * // Discard the cache if it's too old
0067  * if (cache->timestamp() < mydataTimestamp()) {
0068  *     cache->discard();
0069  * }
0070  * // Now the cache contains up-to-date data
0071  * @endcode
0072  * As demonstrated, you can use cache's @ref timestamp() method to see when
0073  *  the cache was created. If necessary, you can also change the timestamp
0074  *  using @ref setTimestamp() method.
0075  *
0076  * @deprecated KPixmapCache is susceptible to various non-trivial locking bugs and
0077  * inefficiencies, and is supported for backward compatibility only (since it exposes
0078  * a QDataStream API for subclasses). Users should port to KImageCache for a very close
0079  * work-alike, or KSharedDataCache if they need more control.
0080  *
0081  * @see KImageCache, KSharedDataCache
0082  *
0083  * @author Rivo Laks
0084  */
0085 class KDELIBS4SUPPORT_DEPRECATED_EXPORT KPixmapCache
0086 {
0087 public:
0088     /**
0089      * Constucts the pixmap cache object.
0090      * @param name unique name of the cache
0091      */
0092     KDELIBS4SUPPORT_DEPRECATED explicit KPixmapCache(const QString &name);
0093     virtual ~KPixmapCache();
0094 
0095     /**
0096      * Tries to load pixmap with the specified @a key from cache. If the pixmap
0097      * is found it is stored in @a pix, otherwise @a pix is unchanged.
0098      *
0099      * @return true when pixmap was found and loaded from cache, false otherwise
0100      */
0101     virtual bool find(const QString &key, QPixmap &pix);
0102 
0103     /**
0104      * Inserts the pixmap @a pix into the cache, associated with the key @a key.
0105      *
0106      * Any existing pixmaps associated with @a key are overwritten.
0107      */
0108     virtual void insert(const QString &key, const QPixmap &pix);
0109 
0110     /**
0111      * Loads a pixmap from given file, using the cache. If the file does not
0112      * exist on disk, an empty pixmap is returned, even if that file had
0113      * previously been cached.  In addition, if the file's modified-time is
0114      * more recent than cache's @ref timestamp(), the @em entire cache is
0115      * discarded (to be regenerated). This behavior may change in a future
0116      * KDE Platform release. If the cached data is current the pixmap
0117      * is returned directly from the cache without any file loading.
0118      *
0119      * @note The mapping between @a filename and the actual key used internally
0120      * is implementation-dependent and can change without warning. Use insert()
0121      * manually if you need control of the key, otherwise consistently use this
0122      * function.
0123      *
0124      * @param filename The name of the pixmap to load, cache, and return.
0125      * @return The given pixmap, or an empty pixmap if the file was invalid or did
0126      *         not exist.
0127      */
0128     QPixmap loadFromFile(const QString &filename);
0129 
0130     /**
0131      * Same as loadFromFile(), but using an SVG file instead. You may optionally
0132      * pass in a @a size to control the size of the output pixmap.
0133      *
0134      * @note The returned pixmap is only cached for identical filenames and sizes.
0135      *       If you change the size in between calls to this function then the
0136      *       pixmap will have to be regenerated again.
0137      *
0138      * @param filename The filename of the SVG file to load.
0139      * @param size size of the pixmap where the SVG is render to. If not given
0140      *        then the SVG file's default size is used.
0141      * @return an empty pixmap if the file does not exist or was invalid, otherwise
0142      *         a pixmap of the desired @a size.
0143      */
0144     QPixmap loadFromSvg(const QString &filename, const QSize &size = QSize());
0145 
0146     /**
0147      * @note KPixmapCache does not ever change the timestamp, so the application
0148      * must set the timestamp if it to be used.
0149      * @return Timestamp of the cache, set using the setTimestamp() method.
0150      */
0151     QDateTime timestamp() const;
0152 
0153     /**
0154      * Sets the timestamp of app-specific cache. It's saved in the cache file
0155      * and can later be retrieved using the timestamp() method.
0156      * By default the timestamp is set to the cache creation time.
0157      */
0158     void setTimestamp(const QDateTime &time);
0159 
0160     /**
0161      * Sets whether QPixmapCache (memory caching) should be used in addition
0162      * to disk cache. QPixmapCache is used by default.
0163      *
0164      * @note On most systems KPixmapCache can use shared-memory to share cached
0165      * pixmaps with other applications attached to the same shared pixmap,
0166      * which means additional memory caching is unnecessary and actually
0167      * wasteful of memory.
0168      *
0169      * @warning QPixmapCache is shared among the entire process and therefore
0170      * can cause strange interactions with other instances of KPixmapCache.
0171      * This may be fixed in the future and should be not relied upon.
0172      */
0173     // KDE5 Get rid of QPixmapCache and use a sane cache instead.
0174     void setUseQPixmapCache(bool use);
0175 
0176     /**
0177      * Whether QPixmapCache should be used to cache pixmaps in memory in
0178      * addition to caching them on the disk.
0179      *
0180      * @b NOTE: The design of QPixmapCache means that the entries stored in
0181      * the cache are shared throughout the entire process, and not just in
0182      * this particular KPixmapCache. KPixmapCache makes an effort to ensure
0183      * that entries from other KPixmapCaches do not inadvertently spill over
0184      * into this one, but is not entirely successful (see discard())
0185      */
0186     bool useQPixmapCache() const;
0187 
0188     /**
0189      * @return approximate size of the cache, in kilobytes (1 kilobyte == 1024 bytes)
0190      */
0191     int size() const;
0192 
0193     /**
0194      * @return maximum size of the cache (in kilobytes).
0195      * Default setting is 3 megabytes (1 megabyte = 2^20 bytes).
0196      */
0197     int cacheLimit() const;
0198 
0199     /**
0200      * Sets the maximum size of the cache (in kilobytes). If cache gets bigger
0201      * than the limit then some entries are removed (according to
0202      * removeEntryStrategy()).
0203      *
0204      * Setting the cache limit to 0 disables caching (as all entries will get
0205      * immediately removed).
0206      *
0207      * Note that the cleanup might not be done immediately, so the cache might
0208      * temporarily (for a few seconds) grow bigger than the limit.
0209      */
0210     void setCacheLimit(int kbytes);
0211 
0212     /**
0213      * Describes which entries will be removed first during cache cleanup.
0214      * @see removeEntryStrategy(), @see setRemoveEntryStrategy()
0215      */
0216     enum RemoveStrategy { /// oldest entries are removed first.
0217         RemoveOldest,
0218         /// least used entries are removed first.
0219         RemoveSeldomUsed,
0220         /// least recently used entries are removed first.
0221         RemoveLeastRecentlyUsed
0222     };
0223     /**
0224      * @return current entry removal strategy.
0225      * Default is RemoveLeastRecentlyUsed.
0226      */
0227     RemoveStrategy removeEntryStrategy() const;
0228 
0229     /**
0230      * Sets the removeEntryStrategy used when removing entries.
0231      */
0232     void setRemoveEntryStrategy(RemoveStrategy strategy);
0233 
0234     /**
0235      * Cache will be disabled when e.g. its data file cannot be created or
0236      * read.
0237      *
0238      * @return true when the cache is enabled.
0239      */
0240     bool isEnabled() const;
0241 
0242     /**
0243      * @return true when the cache is ready to be used. Not being valid usually
0244      * means that some additional initialization has to be done before the
0245      * cache can be used.
0246      */
0247     bool isValid() const;
0248 
0249     /**
0250      * Deletes a pixmap cache.
0251      * @param name unique name of the cache to be deleted
0252      */
0253     // KDE5: Static function oh how I hate you, this makes it very difficult to perform
0254     // appropriate locking and synchronization to actually remove the cache.
0255     static void deleteCache(const QString &name);
0256 
0257     /**
0258      * Deletes all entries and reinitializes this cache.
0259      *
0260      * @b NOTE: If useQPixmapCache is set to true then that cache must also
0261      * be cleared. There is only one QPixmapCache for the entire process
0262      * however so other KPixmapCaches and other QPixmapCache users may also
0263      * be affected, leading to a temporary slowdown until the QPixmapCache is
0264      * repopulated.
0265      */
0266     void discard();
0267 
0268     /**
0269      * Removes some of the entries in the cache according to current
0270      * removeEntryStrategy().
0271      *
0272      * @param newsize wanted size of the cache, in bytes. If 0 is given then
0273      * current cacheLimit() is used.
0274      *
0275      * @warning This currently works by copying some entries to a new cache and
0276      * then replacing the old cache with the new one. Thus it might be slow and
0277      * will temporarily use extra disk space.
0278      */
0279     void removeEntries(int newsize = 0);
0280 
0281 protected:
0282     /**
0283      * Makes sure that the cache is initialized correctly, including the loading of the
0284      * cache index and data, and any shared memory attachments (for systems where that
0285      * is enabled).
0286      *
0287      * @note Although this method is protected you should not use it from any subclasses.
0288      *
0289      * @internal
0290      */
0291     // KDE5: rename to ensureInitialized()
0292     // KDE5: Make private or move to Private
0293     void ensureInited() const;
0294 
0295     /**
0296      * Can be used by subclasses to load custom data from the stream.
0297      * This function will be called by KPixmapCache immediately following the
0298      * image data for a single image being read from @a stream.
0299      * (This function is called once for every single image).
0300      *
0301      * @see writeCustomData
0302      * @see loadCustomIndexHeader
0303      * @param stream the QDataStream to read data from
0304      * @return true if custom data was successfully loaded, false otherwise. If
0305      *         false is returned then the cached item is assumed to be invalid and
0306      *         will not be available to find() or contains().
0307      */
0308     virtual bool loadCustomData(QDataStream &stream);
0309 
0310     /**
0311      * Can be used by subclasses to write custom data into the stream.
0312      * This function will be called by KPixmapCache immediately after the
0313      * image data for a single image has been written to @a stream.
0314      * (This function is called once for every single image).
0315      *
0316      * @see loadCustomData
0317      * @see writeCustomIndexHeader
0318      * @param stream the QDataStream to write data to
0319      */
0320     virtual bool writeCustomData(QDataStream &stream);
0321 
0322     /**
0323      * Can be used by subclasses to load custom data from cache's header.
0324      * This function will be called by KPixmapCache immediately after the
0325      * index header has been written out. (This function is called one time
0326      * only for the entire cache).
0327      *
0328      * @see loadCustomData
0329      * @see writeCustomIndexHeader
0330      * @param stream the QDataStream to read data from
0331      * @return true if custom index header data was successfully read, false
0332      *         otherwise. If false is returned then the cache is assumed to
0333      *         be invalid and further processing does not occur.
0334      */
0335     virtual bool loadCustomIndexHeader(QDataStream &stream);
0336 
0337     /**
0338      * Can be used by subclasses to write custom data into cache's header.
0339      * This function will be called by KPixmapCache immediately following the
0340      * index header has being loaded. (This function is called one time
0341      * only for the entire cache).
0342      *
0343      * @see writeCustomData
0344      * @see loadCustomIndexHeader
0345      * @param stream the QDataStream to write data to
0346      */
0347     virtual void writeCustomIndexHeader(QDataStream &stream);
0348 
0349     /**
0350      * Sets whether this cache is valid or not. (The cache must be enabled in addition
0351      * for isValid() to return true. @see isEnabled(), @see setEnabled()).
0352      *
0353      * Most cache functions do not work if the cache is not valid. KPixmapCache assumes
0354      * the cache is valid as long as its cache files were able to be created (see
0355      * recreateCacheFiles()) even if the cache is not enabled.
0356      *
0357      * Can be used by subclasses to indicate that cache needs some additional
0358      * initialization before it can be used (note that KPixmapCache will @em not handle
0359      * actually performing this extra initialization).
0360      */
0361     void setValid(bool valid);
0362 
0363     /**
0364      * This function causes the cache files to be recreate by invalidating the cache.
0365      * Any shared memory mappings (if enabled) are dropped temporarily as well.
0366      *
0367      * @note The recreated cache will be initially empty, but with the same size limits
0368      * and entry removal strategy (see removeEntryStrategy()).
0369      *
0370      * If you use this in a subclass be prepared to handle writeCustomData() and
0371      * writeCustomIndexHeader().
0372      *
0373      * @return true if the cache was successfully recreated.
0374      */
0375     bool recreateCacheFiles();
0376 
0377 private:
0378     /// @internal
0379     class Private;
0380     friend class Private;
0381     Private *const d;  ///< @internal
0382 };
0383 
0384 #endif // KPIXMAPCACHE_H