File indexing completed on 2025-04-27 03:58:07

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2006-01-11
0007  * Description : shared image loading and caching
0008  *
0009  * SPDX-FileCopyrightText: 2005-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #ifndef DIGIKAM_LOADING_CACHE_H
0016 #define DIGIKAM_LOADING_CACHE_H
0017 
0018 // Qt includes
0019 
0020 #include <QPixmap>
0021 
0022 // Local includes
0023 
0024 #include "dimg.h"
0025 #include "loadsavethread.h"
0026 #include "digikam_export.h"
0027 
0028 namespace Digikam
0029 {
0030 
0031 class ICCSettingsContainer;
0032 
0033 class LoadingProcessListener
0034 {
0035 public:
0036 
0037     LoadingProcessListener();
0038     virtual ~LoadingProcessListener();
0039     virtual bool querySendNotifyEvent()                                                     const = 0;
0040     virtual void setResult(const LoadingDescription& loadingDescription, const DImg& img)         = 0;
0041     virtual LoadSaveNotifier* loadSaveNotifier()                                            const = 0;
0042     virtual LoadSaveThread::AccessMode accessMode()                                         const = 0;
0043 
0044 private:
0045 
0046     // Disable
0047     LoadingProcessListener(const LoadingProcessListener&)            = delete;
0048     LoadingProcessListener& operator=(const LoadingProcessListener&) = delete;
0049 };
0050 
0051 // --------------------------------------------------------------------------------------------------------------
0052 
0053 class LoadingProcess
0054 {
0055 public:
0056 
0057     LoadingProcess();
0058     virtual ~LoadingProcess();
0059     virtual bool completed()                                                                             const = 0;
0060     virtual QString cacheKey()                                                                           const = 0;
0061     virtual void addListener(LoadingProcessListener* const listener)                                           = 0;
0062     virtual void removeListener(LoadingProcessListener* const listener)                                        = 0;
0063     virtual void notifyNewLoadingProcess(LoadingProcess* const process, const LoadingDescription& description) = 0;
0064 
0065 private:
0066 
0067     // Disable
0068     LoadingProcess(const LoadingProcess&)            = delete;
0069     LoadingProcess& operator=(const LoadingProcess&) = delete;
0070 };
0071 
0072 // --------------------------------------------------------------------------------------------------------------
0073 
0074 class DIGIKAM_EXPORT LoadingCacheFileWatch : public QObject
0075 {
0076     Q_OBJECT
0077 
0078 public:
0079 
0080     LoadingCacheFileWatch();
0081     ~LoadingCacheFileWatch() override;
0082 
0083     void addedImage(const QString& filePath);
0084     void removeImage(const QString& filePath);
0085     void checkFileWatch(const QString& filePath);
0086 
0087 protected:
0088 
0089     /**
0090      * Convenience method.
0091      * Call this to tell the cache to remove stored images for filePath from the cache.
0092      * Calling this method is fast, you do not need to check if the file is contained in the cache.
0093      * Do not hold the CacheLock when calling this method.
0094      */
0095     void notifyFileChanged(const QString& filePath);
0096 
0097 protected:
0098 
0099     friend class LoadingCache;
0100 
0101     QHash<QString, QPair<qint64, QDateTime> > m_watchHash;
0102     class LoadingCache*                       m_cache;
0103 
0104 private:
0105 
0106     // Disable
0107     LoadingCacheFileWatch(const LoadingCacheFileWatch&)            = delete;
0108     LoadingCacheFileWatch& operator=(const LoadingCacheFileWatch&) = delete;
0109     LoadingCacheFileWatch(QObject*)                                = delete;
0110 };
0111 
0112 // --------------------------------------------------------------------------------------------------------------
0113 
0114 class DIGIKAM_EXPORT LoadingCache : public QObject
0115 {
0116     Q_OBJECT
0117 
0118 public:
0119 
0120     /**
0121      * NOTE: !! All methods of LoadingCache shall only be called when a CacheLock is held !!
0122      */
0123 
0124     class DIGIKAM_EXPORT CacheLock
0125     {
0126     public:
0127 
0128         explicit CacheLock(LoadingCache* const cache);
0129         ~CacheLock();
0130         void wakeAll();
0131         void timedWait();
0132 
0133     private:
0134 
0135         LoadingCache* m_cache;
0136     };
0137 
0138 public:
0139 
0140     static LoadingCache* cache();
0141     static void cleanUp();
0142 
0143     /**
0144      * Retrieves an image for the given string from the cache,
0145      * or 0 if no image is found.
0146      */
0147     DImg* retrieveImage(const QString& cacheKey) const;
0148 
0149     /**
0150      * Returns whether the given DImg fits in the cache.
0151      */
0152     bool isCacheable(const DImg& img) const;
0153 
0154     /**
0155      * Put image into for given string into the cache.
0156      * Returns true if image has been put in the cache, false otherwise.
0157      * Ownership of the DImg instance is passed to the cache.
0158      * When it cannot be put in the cache it is deleted.
0159      * The third parameter specifies a file path that will be watched.
0160      * If this file changes, the object will be removed from the cache.
0161      */
0162     bool putImage(const QString& cacheKey, const DImg& img, const QString& filePath) const;
0163 
0164     /**
0165      * Remove entries for the given cacheKey from the cache
0166      */
0167     void removeImage(const QString& cacheKey);
0168 
0169     /**
0170      * Remove all entries from the cache
0171      */
0172     void removeImages();
0173 
0174     // ------- Loading process management -----------------------------------
0175 
0176     /**
0177      * Find the loading process for given cacheKey, or 0 if not found
0178      */
0179     LoadingProcess* retrieveLoadingProcess(const QString& cacheKey) const;
0180 
0181     /**
0182      * Add a loading process to the list. Only one loading process
0183      * for the same cache key is registered at a time.
0184      */
0185     void addLoadingProcess(LoadingProcess* const process);
0186 
0187     /**
0188      * Remove loading process for given cache key
0189      */
0190     void removeLoadingProcess(LoadingProcess* const process);
0191 
0192     /**
0193      * Notify all currently registered loading processes
0194      */
0195     void notifyNewLoadingProcess(LoadingProcess* const process, const LoadingDescription& description);
0196 
0197     /**
0198      * Sets the cache size in megabytes.
0199      * The thumbnail cache is not affected and setThumbnailCacheSize takes the maximum number.
0200      */
0201     void setCacheSize(int megabytes);
0202 
0203     /**
0204      * Get the cache size in bytes.
0205      */
0206     quint64 getCacheSize() const;
0207 
0208     // ------- Thumbnail cache -----------------------------------
0209 
0210     /**
0211      * The LoadingCache support both the caching of QImage and QPixmap objects.
0212      * QPixmaps can only be accessed from the main thread, so the tasks cannot access this cache.
0213      */
0214 
0215     /**
0216      * Retrieves a thumbnail for the given filePath from the thumbnail cache,
0217      * or a 0 if the thumbnail is not found.
0218      */
0219     const QImage* retrieveThumbnail(const QString& cacheKey) const;
0220     const QPixmap* retrieveThumbnailPixmap(const QString& cacheKey) const;
0221     bool  hasThumbnailPixmap(const QString& cacheKey) const;
0222 
0223     /**
0224      * Puts a thumbnail into the thumbnail cache.
0225      */
0226     void putThumbnail(const QString& cacheKey, const QImage& thumb, const QString& filePath);
0227     void putThumbnail(const QString& cacheKey, const QPixmap& thumb, const QString& filePath);
0228 
0229     /**
0230      * Remove the thumbnail for the given file path from the thumbnail cache
0231      */
0232     void removeThumbnail(const QString& cacheKey);
0233 
0234     /**
0235      * Remove all thumbnails
0236      */
0237     void removeThumbnails();
0238 
0239     /**
0240      * Sets the size of the thumbnail cache
0241      *  @param numberOfQImages  The maximum number of thumbnails of max possible size in QImage format
0242      *                          that will be cached. If the size of the images is smaller, a larger
0243      *                          number will be cached.
0244      *  @param numberOfQPixmaps The maximum number of thumbnails of max possible size in QPixmap format
0245      *                          that will be cached. If the size of the images is smaller, a larger
0246      *                          number will be cached.
0247      * Note: The main cache is unaffected by this method,
0248      *       and setCacheSize takes megabytes as parameter.
0249      * Note: A good caching strategy will be to set one of the numbers to 0
0250      * Default values: (0, 100)
0251      */
0252     void setThumbnailCacheSize(int numberOfQImages, int numberOfQPixmaps);
0253 
0254     // ------- File Watch Management -----------------------------------
0255 
0256     /**
0257      * Sets a LoadingCacheFileWatch to watch the files contained in this cache.
0258      * Ownership of this object is transferred to the cache.
0259      */
0260     void setFileWatch(LoadingCacheFileWatch* const watch);
0261 
0262     /**
0263      * Remove all entries from cache that were loaded from filePath.
0264      * Emits relevant signals if notify = true.
0265      */
0266     void notifyFileChanged(const QString& filePath, bool notify = true);
0267 
0268 Q_SIGNALS:
0269 
0270     /**
0271      * This signal is emitted when the cache is notified that a file was changed.
0272      * There is no information in this signal if the file was ever contained in the cache.
0273      * The signal may be emitted under CacheLock. Strongly consider a queued connection.
0274      */
0275     void fileChanged(const QString& filePath);
0276 
0277 private Q_SLOTS:
0278 
0279     void iccSettingsChanged(const ICCSettingsContainer& current, const ICCSettingsContainer& previous);
0280 
0281 private:
0282 
0283     // Disabled
0284     LoadingCache();
0285     explicit LoadingCache(QObject*)              = delete;
0286     ~LoadingCache() override;
0287 
0288     LoadingCache(const LoadingCache&)            = delete;
0289     LoadingCache& operator=(const LoadingCache&) = delete;
0290 
0291 private:
0292 
0293     friend class LoadingCacheFileWatch;
0294     friend class CacheLock;
0295 
0296 private:
0297 
0298     static LoadingCache* m_instance;
0299 
0300     class Private;
0301     Private* const d;
0302 };
0303 
0304 } // namespace Digikam
0305 
0306 #endif // DIGIKAM_LOADING_CACHE_H