File indexing completed on 2025-01-05 03:53:54

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2007-03-21
0007  * Description : Collection scanning to database.
0008  *
0009  * SPDX-FileCopyrightText: 2005      by Renchi Raju <renchi dot raju at gmail dot com>
0010  * SPDX-FileCopyrightText: 2005-2006 by Tom Albers <tomalbers at kde dot nl>
0011  * SPDX-FileCopyrightText: 2007-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0012  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #ifndef DIGIKAM_COLLECTION_SCANNER_H
0019 #define DIGIKAM_COLLECTION_SCANNER_H
0020 
0021 // Qt includes
0022 
0023 #include <QString>
0024 #include <QObject>
0025 #include <QList>
0026 
0027 // Local includes
0028 
0029 #include "iteminfo.h"
0030 #include "digikam_export.h"
0031 #include "coredbaccess.h"
0032 #include "coredbalbuminfo.h"
0033 #include "collectionscannerhints.h"
0034 
0035 class QFileInfo;
0036 
0037 namespace Digikam
0038 {
0039 
0040 class DIGIKAM_DATABASE_EXPORT CollectionScanner : public QObject
0041 {
0042     Q_OBJECT
0043 
0044 public:
0045 
0046     enum FileScanMode
0047     {
0048         /**
0049          * The file will be scanned like it is done for any usual scan.
0050          * If it was not modified, no further action is taken.
0051          * If the file is not known yet, it will be fully scanned, or,
0052          * if an identical file is found, this data will be copied.
0053          */
0054         NormalScan,
0055 
0056         /**
0057          * The file will scanned like a modified file. Only a selected portion
0058          * of the metadata will be updated into the database.
0059          * If the file is not known yet, it will be fully scanned, or,
0060          * if an identical file is found, this data will be copied.
0061          */
0062         ModifiedScan,
0063 
0064         /**
0065          * The file will be scanned like a completely new file.
0066          * The complete metadata is re-read into the database.
0067          * No search for identical files will be done.
0068          */
0069         Rescan,
0070 
0071         /**
0072          * This is the same as Rescan but the database metadata
0073          * will be cleaned up if the corresponding metadata
0074          * write option is enabled.
0075          */
0076         CleanScan
0077     };
0078 
0079 public:
0080 
0081     explicit CollectionScanner();
0082     ~CollectionScanner() override;
0083 
0084     //@{
0085     /**
0086      * Hints give the scanner additional info about things that happened in the past
0087      * carried out by higher level which the collection scanner cannot know.
0088      * They allow to carry out optimizations.
0089      * Record hints in a container, and provide the container to the collection scanner.
0090      * The Container set in setHintContainer must be one created by createContainer.
0091      */
0092     static CollectionScannerHintContainer* createHintContainer();
0093     void setHintContainer(CollectionScannerHintContainer* const container);
0094     void setUpdateHashHint(bool hint = true);
0095     //@}
0096 
0097     /**
0098      * Call this to enable the progress info signals.
0099      * Default is off.
0100      */
0101     void setSignalsEnabled(bool on);
0102 
0103     /**
0104      * Call this to enable emitting the total files to scan
0105      * (for progress info) before a complete collection scan.
0106      * Default is off. If on, setSignalEnabled() must be on to take effect.
0107      */
0108     void setNeedFileCount(bool on);
0109 
0110     /**
0111      * Call this to disable fast scan with album date check.
0112      * Default is on.
0113      */
0114     void setPerformFastScan(bool on);
0115 
0116     /**
0117      * Set an observer to be able to cancel a running scan
0118      */
0119     void setObserver(CollectionScannerObserver* const observer);
0120 
0121     void setDeferredFileScanning(bool defer);
0122     QStringList deferredAlbumPaths() const;
0123 
0124     /**
0125      * Returns item ids from new detected items
0126      */
0127     QList<qlonglong> getNewIdsList() const;
0128 
0129     // -----------------------------------------------------------------------------
0130 
0131     /** @name Scan operations
0132      */
0133 
0134     //@{
0135 
0136 public:
0137 
0138     /**
0139      * Carries out a full scan on all available parts of the collection.
0140      * Only a full scan can finally remove deleted files from the database,
0141      * only a full scan will mark the database as scanned.
0142      * The database will be locked while running (Note: this is not done for partialScans).
0143      */
0144     void completeScan();
0145 
0146     /**
0147      * If you enable deferred file scanning for a completeScan(), new files
0148      * will not be scanned. The relevant albums are available from
0149      * deferredAlbumPaths() when completeScan() has finished.
0150      * You need to call finishCompleteScan() afterwards with the list
0151      * to get the same complete scan than undeferred completeScan().
0152      */
0153     void finishCompleteScan(const QStringList& albumPaths);
0154 
0155     /**
0156      * Returns if the initial scan of the database has been done.
0157      * This is the first complete scan after creation of a new database file
0158      * (or update requiring a rescan)
0159      */
0160     static bool databaseInitialScanDone();
0161 
0162     /**
0163      * Carries out a partial scan on the specified path of the collection.
0164      * The includes scanning for new files + albums and updating modified file data.
0165      * Files no longer found in the specified path however are not completely
0166      * removed, but only marked as removed. They will be removed only after a complete scan.
0167      */
0168     void partialScan(const QString& filePath);
0169 
0170     /**
0171      * Same procedure as above, but albumRoot and album is provided.
0172      */
0173     void partialScan(const QString& albumRoot, const QString& album);
0174 
0175     /**
0176      * The given file will be scanned according to the given mode.
0177      * Returns the image id of the file.
0178      */
0179     qlonglong scanFile(const QString& filePath, FileScanMode mode = ModifiedScan);
0180 
0181     /**
0182      * Same procedure as above, but albumRoot and album is provided.
0183      * If you already have this info it need not be retrieved.
0184      * Returns the image id of the file, or -1 on failure.
0185      */
0186     qlonglong scanFile(const QString& albumRoot,
0187                        const QString& album,
0188                        const QString& fileName,
0189                        FileScanMode mode = ModifiedScan);
0190 
0191     /**
0192      * The given file represented by the ItemInfo will be scanned according to mode
0193      */
0194     void scanFile(const ItemInfo& info, FileScanMode mode = ModifiedScan);
0195 
0196 protected:
0197 
0198     void scanForStaleAlbums(const QList<CollectionLocation>& locations);
0199     void scanForStaleAlbums(const QList<int>& locationIdsToScan);
0200     void scanAlbumRoot(const CollectionLocation& location);
0201     void scanAlbum(const CollectionLocation& location, const QString& album, bool checkDate = false);
0202     void scanExistingFile(const QFileInfo& fi, qlonglong id);
0203     void scanFileNormal(const QFileInfo& info, const ItemScanInfo& scanInfo,
0204                         bool checkSidecar = true, const QFileInfo* const sidecarInfo = nullptr);
0205     void scanModifiedFile(const QFileInfo& info, const ItemScanInfo& scanInfo);
0206     void scanFileUpdateHashReuseThumbnail(const QFileInfo& fi, const ItemScanInfo& scanInfo, bool fileWasEdited);
0207     void cleanScanFile(const QFileInfo& info, const ItemScanInfo& scanInfo);
0208     void rescanFile(const QFileInfo& info, const ItemScanInfo& scanInfo);
0209     void completeScanCleanupPart();
0210     void completeHistoryScanning();
0211     void finishHistoryScanning();
0212     void historyScanningStage2(const QList<qlonglong>& ids);
0213     void historyScanningStage3(const QList<qlonglong>& ids);
0214 
0215     qlonglong scanFile(const QFileInfo& fi, int albumId, qlonglong id, FileScanMode mode);
0216     qlonglong scanNewFile(const QFileInfo& info, int albumId);
0217     qlonglong scanNewFileFullScan(const QFileInfo& info, int albumId);
0218 
0219     //@}
0220 
0221     // -----------------------------------------------------------------------------
0222 
0223     /** @name Scan utilities
0224      */
0225 
0226     //@{
0227 
0228 public:
0229 
0230     /**
0231      * Prepare the given albums to be removed,
0232      * typically by setting the albums as orphan
0233      * and removing all entries from the albums
0234      */
0235     void safelyRemoveAlbums(const QList<int>& albumIds);
0236 
0237     /**
0238      * When a file is derived from another file, typically through editing,
0239      * copy all relevant attributes from source file to the new file.
0240      */
0241     static void copyFileProperties(const ItemInfo& source, const ItemInfo& dest);
0242 
0243 protected:
0244 
0245     void markDatabaseAsScanned();
0246     void mainEntryPoint(bool complete);
0247     int  checkAlbum(const CollectionLocation& location, const QString& album);
0248     void itemsWereRemoved(const QList<qlonglong>& removedIds);
0249     void updateRemovedItemsTime();
0250     void incrementDeleteRemovedCompleteScanCount();
0251     void resetDeleteRemovedSettings();
0252     bool checkDeleteRemoved();
0253     void loadNameFilters();
0254     int  countItemsInFolder(const QString& path);
0255     DatabaseItem::Category category(const QFileInfo& info);
0256 
0257     //@}
0258 
0259 Q_SIGNALS:
0260 
0261     /**
0262      * Emitted once in scanAlbums(), the scan() methods, and updateItemsWithoutDate().
0263      * Gives the number of the files that need to be scanned.
0264      */
0265     void totalFilesToScan(int count);
0266 
0267     //@{
0268     /**
0269      * Notifies the begin of the scanning of the specified album root,
0270      * album, of stale files, or of the whole collection (after stale files)
0271      */
0272     void startScanningAlbumRoot(const QString& albumRoot);
0273     void startScanningAlbum(const QString& albumRoot, const QString& album);
0274     void startScanningForStaleAlbums();
0275     void startScanningAlbumRoots();
0276     void startCompleteScan();
0277     void signalScannedNewImage(const QFileInfo& info);
0278     //@}
0279 
0280     //@{
0281     /**
0282      * Emitted when the scanning has finished.
0283      * Note that start/finishScanningAlbum may be emitted recursively.
0284      */
0285     void finishedScanningAlbumRoot(const QString& albumRoot);
0286     void finishedScanningAlbum(const QString& albumRoot, const QString& album, int filesScanned);
0287     void finishedScanningForStaleAlbums();
0288     void finishedCompleteScan();
0289     //@}
0290 
0291     /**
0292      * Emitted between startScanningAlbum and finishedScanningAlbum.
0293      * In between these two signals, the sum of filesScanned of all sent signals
0294      * equals the one reported by finishedScanningAlbum()
0295      */
0296     void scannedFiles(int filesScanned);
0297 
0298     /**
0299      * Emitted when the observer told to cancel the scan
0300      */
0301     void cancelled();
0302 
0303 private:
0304 
0305     // Disable
0306     CollectionScanner(QObject*) = delete;
0307 
0308     class Private;
0309     Private* const d;
0310 };
0311 
0312 } // namespace Digikam
0313 
0314 #endif // DIGIKAM_COLLECTION_SCANNER_H