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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2007-06-05
0007  * Description : Thumbnail loading
0008  *
0009  * SPDX-FileCopyrightText: 2006-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #ifndef DIGIKAM_THUMB_NAIL_LOAD_THREAD_H
0017 #define DIGIKAM_THUMB_NAIL_LOAD_THREAD_H
0018 
0019 // Qt includes
0020 
0021 #include <QPixmap>
0022 #include <QImage>
0023 
0024 // Local includes
0025 
0026 #include "managedloadsavethread.h"
0027 #include "thumbnailinfo.h"
0028 
0029 namespace Digikam
0030 {
0031 
0032 class DbEngineParameters;
0033 class ThumbnailCreator;
0034 class ThumbnailInfoProvider;
0035 
0036 class DIGIKAM_EXPORT ThumbnailLoadThread : public ManagedLoadSaveThread
0037 {
0038     Q_OBJECT
0039 
0040 public:
0041 
0042     explicit ThumbnailLoadThread(QObject* const parent = nullptr);
0043     ~ThumbnailLoadThread() override;
0044 
0045     /**
0046      * Return application-wide default thumbnail threads.
0047      * It is perfectly all right to create an extra object of the class,
0048      * but it is useful to have default object
0049      */
0050     static ThumbnailLoadThread* defaultThread();
0051     static ThumbnailLoadThread* defaultIconViewThread();
0052 
0053     static void cleanUp();
0054 
0055     /**
0056      * Enable loading of thumbnails from a thumbnail database.
0057      * This shall be called once at application startup.
0058      * This need not be called, then the FreeDesktop standard is used.
0059      * You can optionally provide a thumbnail info provider.
0060      */
0061     static void initializeThumbnailDatabase(const DbEngineParameters& params, ThumbnailInfoProvider* const provider = nullptr);
0062 
0063     /**
0064      * For color management, this sets the widget the thumbnails will be color managed for.
0065      * (currently it is only possible to set one global widget)
0066      */
0067     static void setDisplayingWidget(QWidget* const widget);
0068 
0069     /**
0070      * Find a thumbnail.
0071      * If the pixmap is found in the cache, returns true and sets pixmap
0072      * to the found QPixmap.
0073      * If the pixmap is not found in the cache, load() is called to start the loading process,
0074      * false is returned and pixmap is not touched.
0075      */
0076     bool find(const ThumbnailIdentifier& identifier, QPixmap& pixmap);
0077 
0078     /**
0079      * Same as above, but does not use the global size, but an extra specified size.
0080      */
0081     bool find(const ThumbnailIdentifier& identifier,
0082               QPixmap& pixmap, int size, bool onlyStorage = false);
0083 
0084     /**
0085      * Find a thumbnail.
0086      * This method sends the signals and does not return values like the method above.
0087      * If you certainly need asynchronous return, connect with Qt::QueuedConnection to the signals.
0088      * If you connect directly, the signals may be sent from within the method call.
0089      */
0090     void find(const ThumbnailIdentifier& identifier);
0091 
0092     /**
0093      * Same as above, but does not use the global size, but an extra specified size.
0094      */
0095     void find(const ThumbnailIdentifier& identifier, int size);
0096 
0097     /**
0098      * Find a group of thumbnails. The items will be loaded in order and signals will be sent.
0099      * Can be used to ensure that thumbnails are loaded in a particular order
0100      */
0101     void findGroup(QList<ThumbnailIdentifier>& identifiers);
0102     void findGroup(QList<ThumbnailIdentifier>& identifiers, int size);
0103 
0104     /**
0105      * All tastes of find() methods, for loading the thumbnail of a detail
0106      */
0107     bool find(const ThumbnailIdentifier& identifier, const QRect& rect, QPixmap& pixmap);
0108     bool find(const ThumbnailIdentifier& identifier,
0109               const QRect& rect, QPixmap& pixmap, int size, bool onlyStorage = false);
0110     void find(const ThumbnailIdentifier& identifier, const QRect& rect);
0111     void find(const ThumbnailIdentifier& identifier, const QRect& rect, int size);
0112     void findGroup(const QList<QPair<ThumbnailIdentifier, QRect> >& filePathAndRects);
0113     void findGroup(const QList<QPair<ThumbnailIdentifier, QRect> >& filePathsAndRects, int size);
0114 
0115     /**
0116      * Preload the thumbnail or thumbnail group.
0117      * This is essentially the same as loading, but with a lower priority.
0118      */
0119     void preload(const ThumbnailIdentifier& identifier);
0120     void preload(const ThumbnailIdentifier& identifier, int size);
0121     void preloadGroup(QList<ThumbnailIdentifier>& identifiers);
0122     void preloadGroup(QList<ThumbnailIdentifier>& identifiers, int size);
0123 
0124     /**
0125      * Pregenerate the thumbnail group.
0126      * No signals will be emitted when these are loaded.
0127      */
0128     void pregenerateGroup(const QList<ThumbnailIdentifier>& identifiers);
0129     void pregenerateGroup(const QList<ThumbnailIdentifier>& identifiers, int size);
0130 
0131     /**
0132      * Load a thumbnail.
0133      * You do not need to use this method directly, it will not access the pixmap cache. Use find().
0134      * The LoadingDescription shall be constructed with the constructor for preview/thumbnail jobs.
0135      * (in the description constructor, you need to specify file path, thumbnail size and Exif rotation)
0136      */
0137     void load(const LoadingDescription& description);
0138 
0139     /**
0140      * Returns the descriptions used by the last call to any of the above methods.
0141      * After calling single-thumbnail methods (find, preload) the list will have size 1,
0142      * after the group methods (findGroup, preloadGroup, pregenerateGroup) the list can
0143      * be larger than 1.
0144      * There is no information if the description was ever scheduled in the thread,
0145      * already processed, skipped or canceled.
0146      */
0147     QList<LoadingDescription> lastDescriptions() const;
0148 
0149     /**
0150      * NOTE: If the thread is currently loading thumbnails, there is no guarantee as to when
0151      * the property change by one of the following methods takes effect.
0152      */
0153 
0154     /**
0155      * Set the requested thumbnail size.
0156      * Default value: 128
0157      */
0158     void setThumbnailSize(int size, bool forFace = false);
0159 
0160     /**
0161      * Returns the maximum possible size of a thumbnail.
0162      * If you request a larger size, the thumbnail will not load.
0163      * The size of the pixmap can slightly differ, especially when highlighting.
0164      */
0165     static int maximumThumbnailSize();
0166     static int maximumThumbnailPixmapSize(bool withHighlighting);
0167 
0168     /**
0169      * If you enable this, the signal thumbnailLoaded(LoadingDescription, QPixmap) will be emitted.
0170      * If you do not enable this, only the QImage-based signal (see LoadSaveThread) will be emitted.
0171      *
0172      * If you disable this, pay attention to the (global) setting of the LoadingCache, which per default
0173      * does not cache the images !!
0174      *
0175      * Default value: Enabled.
0176      */
0177     void setPixmapRequested(bool wantPixmap);
0178 
0179     /**
0180      * If you enable this, a highlighting border will be drawn around the pixmap.
0181      * This option has only an effect if pixmapRequested is true.
0182      * Default value: Enabled.
0183      */
0184     void setHighlightPixmap(bool highlight);
0185 
0186     /**
0187      * Computes the pixmap size for the give thumbnail size.
0188      * These can differ when highlighting is turned on.
0189      */
0190     int        thumbnailToPixmapSize(int size) const;
0191     static int thumbnailToPixmapSize(bool withHighlight, int size);
0192 
0193     /**
0194      * Computes the thumbnail size for the give pixmap size.
0195      */
0196     int pixmapToThumbnailSize(int size) const;
0197 
0198     /**
0199      * If you enable this, the thread will try hard to send a pixmap if thumbnail loading failed.
0200      * It will use standard system icons to replace the real thumbnail.
0201      * If you disable this, a null QPixmap will be sent.
0202      * This does not influence the QImage-based signal; this signal will be emitted with a null
0203      * QImage regardless of this setting here, if the loading failed.
0204      * Default value: Enabled.
0205      */
0206     void setSendSurrogatePixmap(bool send);
0207 
0208     /**
0209      * Stores the given detail thumbnail on disk.
0210      * Use this if possible because generation of detail thumbnails
0211      * is potentially slower.
0212      * The image should at least have storedSize().
0213      */
0214     void storeDetailThumbnail(const QString& filePath,
0215                               const QRect& detailRect,
0216                               const QImage& image,
0217                               bool isFace = false);
0218     int  storedSize() const;
0219 
0220     /**
0221      * This is a tool to force regeneration of thumbnails.
0222      * All thumbnail files for the given file will be removed from disk,
0223      * and the cached instances will be removed as well.
0224      * Use this method if you know that the contents of the file has changed.
0225      * This method works independently from the multithreaded thumbnail loading.
0226      */
0227     static void deleteThumbnail(const QString& filePath);
0228 
0229 Q_SIGNALS:
0230 
0231     /// NOTE: See LoadSaveThread for a QImage-based thumbnailLoaded() signal.
0232     void signalThumbnailLoaded(const LoadingDescription& loadingDescription, const QPixmap& pix);
0233 
0234 public:
0235 
0236     /// NOTE: For internal use - may only be used from the thread
0237     ThumbnailCreator* thumbnailCreator() const;
0238 
0239 protected:
0240 
0241     void thumbnailLoaded(const LoadingDescription& loadingDescription, const QImage& img) override;
0242 
0243 private:
0244 
0245     bool find(const ThumbnailIdentifier& identifier, int size, QPixmap* retPixmap,
0246               bool emitSignal, const QRect& detailRect, bool onlyStorage = false);
0247     void load(const LoadingDescription& description, bool pregenerate);
0248     bool checkSize(int size);
0249     QPixmap surrogatePixmap(const LoadingDescription& loadingDescription);
0250 
0251 Q_SIGNALS:
0252 
0253     /// NOTE: For internal use only.
0254     void thumbnailsAvailable();
0255     void ThumbnailLoaded(const LoadingDescription&, const QImage&);
0256 
0257 private Q_SLOTS:
0258 
0259     void slotThumbnailsAvailable();
0260     void slotThumbnailLoaded(const LoadingDescription&, const QImage&);
0261 
0262 private:
0263 
0264     // Disable
0265     ThumbnailLoadThread(const ThumbnailLoadThread&)            = delete;
0266     ThumbnailLoadThread& operator=(const ThumbnailLoadThread&) = delete;
0267 
0268 private:
0269 
0270     class Private;
0271     Private* const d;
0272 };
0273 
0274 // --------------------------------------------------------------------------------------------------
0275 
0276 class DIGIKAM_EXPORT ThumbnailImageCatcher : public QObject
0277 {
0278     Q_OBJECT
0279 
0280 public:
0281 
0282     /**
0283      *  Use this class to get a thumbnail synchronously.
0284      *  1. Create the ThumbnailImageCatcher object with your ThumbnailLoadThread
0285      *  2. a) Request a thumbnail
0286      *     b) Call enqueue()
0287      *  3. Call waitForThumbnails which returns the thumbnail QImage(s).
0288      *
0289      *  Note: Not meant for loading QPixmap thumbnails.
0290      */
0291 
0292     explicit ThumbnailImageCatcher(QObject* const parent = nullptr);
0293     explicit ThumbnailImageCatcher(ThumbnailLoadThread* const thread,
0294                                    QObject* const parent = nullptr);
0295     ~ThumbnailImageCatcher() override;
0296 
0297     ThumbnailLoadThread* thread() const;
0298     void setThumbnailLoadThread(ThumbnailLoadThread* const thread);
0299 
0300     /**
0301      * After requesting a thumbnail from the thread, call enqueue()
0302      * each time. Enqueue records the requested loading operation in an internal list.
0303      * A loading operation can result in the return of more than one thumbnail,
0304      * so enqueue() returns the number of expected results.
0305      * Then call waitForThumbnails. The returned list is the sum of previous calls
0306      * to enqueue, one entry per expected result, in order.
0307      * If stopped prematurely or loading failed, the respective entries will be null.
0308      */
0309     int           enqueue();
0310     QList<QImage> waitForThumbnails();
0311 
0312 public Q_SLOTS:
0313 
0314     /**
0315      * The catcher is active per default after construction.
0316      * Deactivate it if you use the catcher as a longer-lived
0317      * object and do not use it for some time,
0318      * then activate it before you request a thumbnail from the thread again.
0319      */
0320     void setActive(bool active);
0321 
0322     /**
0323      * If the catcher is waiting in waitForThumbnails() in a different thread,
0324      * cancels the waiting. The results will be returned as received so far.
0325      */
0326     void cancel();
0327 
0328 protected Q_SLOTS:
0329 
0330     void slotThumbnailLoaded(const LoadingDescription&, const QImage&);
0331 
0332 private:
0333 
0334     // Disable
0335     ThumbnailImageCatcher(const ThumbnailImageCatcher&)            = delete;
0336     ThumbnailImageCatcher& operator=(const ThumbnailImageCatcher&) = delete;
0337 
0338 private:
0339 
0340     class Private;
0341     Private* const d;
0342 };
0343 
0344 } // namespace Digikam
0345 
0346 #endif // DIGIKAM_THUMB_NAIL_LOAD_THREAD_H