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