File indexing completed on 2025-01-05 03:54:17
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2005-10-28 0007 * Description : scan item controller. 0008 * 0009 * SPDX-FileCopyrightText: 2005-2006 by Tom Albers <tomalbers at kde dot nl> 0010 * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2007-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #ifndef DIGIKAM_SCAN_CONTROLLER_H 0018 #define DIGIKAM_SCAN_CONTROLLER_H 0019 0020 // Qt includes 0021 0022 #include <QThread> 0023 #include <QString> 0024 #include <QList> 0025 0026 // Local includes 0027 0028 #include "digikam_export.h" 0029 #include "collectionscannerobserver.h" 0030 #include "collectionscannerhints.h" 0031 #include "collectionscanner.h" 0032 #include "iteminfo.h" 0033 #include "loadingcache.h" 0034 #include "coredbchangesets.h" 0035 0036 namespace Digikam 0037 { 0038 0039 class CollectionScanner; 0040 class PAlbum; 0041 0042 class DIGIKAM_GUI_EXPORT ScanController : public QThread, 0043 public InitializationObserver 0044 { 0045 Q_OBJECT 0046 0047 public: 0048 0049 enum Advice 0050 { 0051 Success, 0052 ContinueWithoutDatabase, 0053 AbortImmediately 0054 }; 0055 0056 public: 0057 0058 /** 0059 * When writing metadata to the file, the file content on disk changes, 0060 * but the information is taken from the database; therefore, 0061 * the resulting scanning process can be optimized. 0062 * 0063 * Thus, if you write metadata of an ItemInfo from the database to disk, 0064 * do this in the scope of a FileMetadataWrite object. 0065 */ 0066 class FileMetadataWrite 0067 { 0068 public: 0069 0070 explicit FileMetadataWrite(const ItemInfo& info); 0071 ~FileMetadataWrite(); 0072 0073 void changed(bool wasChanged); 0074 0075 protected: 0076 0077 ItemInfo m_info; 0078 bool m_changed; 0079 }; 0080 0081 public: 0082 0083 static ScanController* instance(); 0084 0085 /** 0086 * Carries out a complete collection scan, at the same time updating 0087 * the unique hash in the database and thumbnail database. 0088 * Synchronous, returns when ready. 0089 * The database will be locked while the scan is running. 0090 */ 0091 void updateUniqueHash(); 0092 0093 void allowToScanDeferredFiles(); 0094 0095 /** 0096 * If necessary (modified or newly created, scans the file directly 0097 * Returns the up-to-date ItemInfo. 0098 */ 0099 ItemInfo scannedInfo(const QString& filePath, 0100 CollectionScanner::FileScanMode mode = CollectionScanner::NormalScan); 0101 0102 /** 0103 * Returns item ids from new detected items 0104 */ 0105 QList<qlonglong> getNewIdsList() const; 0106 0107 protected: 0108 0109 void run() override; 0110 0111 private: 0112 0113 explicit ScanController(); 0114 ~ScanController() override; 0115 0116 void setInitializationMessage(); 0117 void createProgressDialog(); 0118 0119 bool continueQuery() override; 0120 void connectCollectionScanner(CollectionScanner* const scanner) override; 0121 0122 // ----------------------------------------------------------------------------- 0123 0124 /** @name Start Operations 0125 */ 0126 0127 //@{ 0128 0129 public: 0130 0131 /** 0132 * Restart thread after shutdown. 0133 */ 0134 void restart(); 0135 0136 /** 0137 * Calls CoreDbAccess::checkReadyForUse(), providing progress 0138 * feedback if schema updating occurs. 0139 * Synchronous, returns when ready. 0140 */ 0141 Advice databaseInitialization(); 0142 0143 /** 0144 * Carries out a complete collection scan, providing progress feedback. 0145 * Synchronous, returns when ready. 0146 * The database will be locked while the scan is running. 0147 * With the DeferFiles variant, deep files scanning (new files), the part 0148 * which can take long, will be done during the time after the method returns, 0149 * shortening the synchronous wait. After completeCollectionScanDeferFiles, you 0150 * need to call allowToScanDeferredFiles() once to enable scanning the deferred files. 0151 */ 0152 void completeCollectionScan(bool defer = false); 0153 void completeCollectionScanDeferFiles(); 0154 0155 /** 0156 * Scan Whole collection without to display a progress dialog 0157 * or to manage splashscreen, as for NewItemsFinder tool. 0158 */ 0159 void completeCollectionScanInBackground(bool defer, bool fastScan = true); 0160 0161 /** 0162 * Schedules a scan of the specified part of the collection. 0163 * Asynchronous, returns immediately. 0164 */ 0165 void scheduleCollectionScan(const QString& path); 0166 0167 /** 0168 * Schedules a scan of the specified part of the collection. 0169 * Asynchronous, returns immediately. 0170 * A small delay may be introduced before the actual scanning starts, 0171 * so that you can call this often without checking for duplicates. 0172 * This method must only be used from the main thread. 0173 */ 0174 void scheduleCollectionScanRelaxed(const QString& path); 0175 0176 /** 0177 * Schedules a scan of the specified part of the collection. 0178 * Asynchronous, returns immediately. 0179 * A very long delay with timer restart may be introduced 0180 * before the actual scanning starts, so that you can call 0181 * this often without checking for duplicates. 0182 * This method is only for the QFileSystemWatcher. 0183 */ 0184 void scheduleCollectionScanExternal(const QString& path); 0185 0186 /** 0187 * Implementation of FileMetadataWrite, see there. Calling these methods is equivalent. 0188 */ 0189 void beginFileMetadataWrite(const ItemInfo& info); 0190 0191 /** 0192 * Resume a suspended collection scanning. 0193 * All scheduled scanning tasks are queued 0194 * and will be done when resumeCollectionScan() 0195 * has been called. 0196 * Calling these methods is recursive, you must resume 0197 * as often as you called suspend. 0198 */ 0199 void resumeCollectionScan(); 0200 0201 /** 0202 * Restart a suspended collection scanning. 0203 * All scheduled scanning tasks are queued 0204 * and will be done when restartCollectionScan() 0205 * has been called. 0206 */ 0207 void restartCollectionScan(); 0208 0209 Q_SIGNALS: 0210 0211 void databaseInitialized(bool success); 0212 void collectionScanStarted(const QString& message); 0213 0214 private Q_SLOTS: 0215 0216 void slotStartCompleteScan(); 0217 void slotStartScanningAlbum(const QString& albumRoot, const QString& album); 0218 void slotStartScanningAlbumRoot(const QString& albumRoot); 0219 void slotStartScanningForStaleAlbums(); 0220 void slotStartScanningAlbumRoots(); 0221 0222 private: 0223 0224 /** 0225 * The file pointed to by file path will be scanned. 0226 * The scan is finished when returning from the method. 0227 */ 0228 void scanFileDirectly(const QString& filePath); 0229 void scanFileDirectlyNormal(const ItemInfo& info); 0230 void completeCollectionScanCore(bool needTotalFiles, bool defer, bool fastScan); 0231 0232 //@} 0233 0234 // ----------------------------------------------------------------------------- 0235 0236 /** @name Progress Operations 0237 */ 0238 0239 //@{ 0240 0241 public: 0242 0243 /** 0244 * Hint at the imminent copy, move or rename of an album, so that the 0245 * collection scanner is informed about this. 0246 * If the album is renamed, give the new name in newAlbumName. 0247 * DstAlbum is the new parent album / 0248 * dstPath is the new parent directory of the album, so 0249 * do not include the album name to dstPath. 0250 */ 0251 void hintAtMoveOrCopyOfAlbum(const PAlbum* const album, 0252 const PAlbum* const dstAlbum, 0253 const QString& newAlbumName = QString()); 0254 void hintAtMoveOrCopyOfAlbum(const PAlbum* const album, 0255 const QString& dstPath, 0256 const QString& newAlbumName = QString()); 0257 0258 /** 0259 * Hint at the imminent copy, move or rename of items, so that the 0260 * collection scanner is informed about this. 0261 * Give the list of existing items, specify the destination with dstAlbum, 0262 * and give the names at destination in itemNames (Unless for rename, names wont usually change. 0263 * Give them nevertheless.) 0264 */ 0265 void hintAtMoveOrCopyOfItems(const QList<qlonglong>& ids, 0266 const PAlbum* const dstAlbum, 0267 const QStringList& itemNames); 0268 void hintAtMoveOrCopyOfItem(qlonglong id, 0269 const PAlbum* const dstAlbum, 0270 const QString& itemName); 0271 0272 /** 0273 * Hint at the fact that an item may have changed, although its modification date may not have changed. 0274 * Note that a scan of the containing directory will need to be triggered nonetheless for the hints to take effect. 0275 */ 0276 void hintAtModificationOfItems(const QList<qlonglong>& ids); 0277 void hintAtModificationOfItem(qlonglong id); 0278 0279 Q_SIGNALS: 0280 0281 void totalFilesToScan(int); 0282 void filesScanned(int); 0283 void scanningProgress(float progress); 0284 void triggerShowProgressDialog(); 0285 void incrementProgressDialog(int); 0286 void progressFromInitialization(const QString&, int); 0287 0288 private Q_SLOTS: 0289 0290 void slotTotalFilesToScan(int count); 0291 void slotScannedFiles(int scanned); 0292 void slotShowProgressDialog(); 0293 void slotTriggerShowProgressDialog(); 0294 void slotProgressFromInitialization(const QString& message, int numberOfSteps); 0295 void slotErrorFromInitialization(const QString& errorMessage); 0296 0297 private: 0298 0299 void moreSchemaUpdateSteps(int numberOfSteps) override; 0300 void schemaUpdateProgress(const QString& message, int numberOfSteps) override; 0301 void error(const QString& errorMessage) override; 0302 0303 AlbumCopyMoveHint hintForAlbum(const PAlbum* const album, 0304 int dstAlbumRootId, 0305 const QString& relativeDstPath, 0306 const QString& albumName); 0307 0308 QList<AlbumCopyMoveHint> hintsForAlbum(const PAlbum* const album, 0309 int dstAlbumRootId, 0310 const QString& relativeDstPath, 0311 const QString& albumName); 0312 //@} 0313 0314 // ----------------------------------------------------------------------------- 0315 0316 /** @name Stop Operations 0317 */ 0318 0319 //@{ 0320 0321 public: 0322 0323 /** 0324 * Wait for the thread to finish. Returns after all tasks are done. 0325 */ 0326 void shutDown(); 0327 0328 /** 0329 * If the controller is currently processing a database update 0330 * (typically after first run), 0331 * cancel this hard and as soon as possible. Any progress may be lost. 0332 */ 0333 void abortInitialization(); 0334 0335 /** 0336 * If the controller is currently doing a complete scan 0337 * (typically at startup), stop this operation. 0338 * It can be resumed later. 0339 */ 0340 void cancelCompleteScan(); 0341 0342 /** 0343 * Cancels all running or scheduled operations and suspends scanning. 0344 * This method returns when all scanning has stopped. 0345 * This includes a call to suspendCollectionScan(). 0346 * Restart with resumeCollectionScan. 0347 */ 0348 void cancelAllAndSuspendCollectionScan(); 0349 0350 /** 0351 * Temporarily suspend collection scanning. 0352 * All scheduled scanning tasks are queued 0353 * and will be done when resumeCollectionScan() 0354 * has been called. 0355 * Calling these methods is recursive, you must resume 0356 * as often as you called suspend. 0357 */ 0358 void suspendCollectionScan(); 0359 0360 /** 0361 * Implementation of FileMetadataWrite, see there. Calling these methods is equivalent. 0362 */ 0363 void finishFileMetadataWrite(const ItemInfo& info, bool changed); 0364 0365 Q_SIGNALS: 0366 0367 void collectionScanFinished(); 0368 void newImages(const ItemInfoList&); 0369 void partialScanDone(const QString& path); 0370 void completeScanDone(); 0371 void completeScanCanceled(); 0372 void errorFromInitialization(const QString&); 0373 0374 private Q_SLOTS: 0375 0376 void slotCancelPressed(); 0377 void slotRelaxedScanning(); 0378 0379 private: 0380 0381 void finishedSchemaUpdate(UpdateResult result) override; 0382 0383 //@} 0384 0385 private: 0386 0387 // Disable 0388 ScanController(QObject*) = delete; 0389 ScanController(const ScanController&) = delete; 0390 ScanController& operator=(const ScanController&) = delete; 0391 0392 private: 0393 0394 friend class ScanControllerCreator; 0395 0396 class Private; 0397 Private* const d; 0398 }; 0399 0400 } // namespace Digikam 0401 0402 #endif // DIGIKAM_SCAN_CONTROLLER_H