File indexing completed on 2025-03-09 03:52:55

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2007-09-19
0007  * Description : Scanning a single item.
0008  *
0009  * SPDX-FileCopyrightText: 2007-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2013-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_ITEM_SCANNER_H
0017 #define DIGIKAM_ITEM_SCANNER_H
0018 
0019 // Qt includes
0020 
0021 #include <QFileInfo>
0022 
0023 // Local includes
0024 
0025 #include "dimg.h"
0026 #include "iteminfo.h"
0027 #include "dmetadata.h"
0028 #include "coredbalbuminfo.h"
0029 #include "coredbinfocontainers.h"
0030 
0031 namespace Digikam
0032 {
0033 
0034 class DIGIKAM_DATABASE_EXPORT ItemScanner
0035 {
0036 
0037 public:
0038 
0039     enum ScanMode
0040     {
0041         NewScan,
0042         ModifiedScan,
0043         Rescan,
0044         CleanScan
0045     };
0046 
0047 public:
0048 
0049     /**
0050      * Construct an ItemScanner object from an existing QFileInfo
0051      * and ItemScanInfo object.
0052      * This constructor shall be used with fileModified() or fullScan().
0053      */
0054     ItemScanner(const QFileInfo& info, const ItemScanInfo& Iteminfo);
0055 
0056     /**
0057      * Construct an ItemScanner from an existing QFileInfo object.
0058      * Use this constructor if you intend to call newFile().
0059      */
0060     explicit ItemScanner(const QFileInfo& info);
0061 
0062     /**
0063      * Construct an ItemScanner for an image in the database.
0064      * File info, Scan info and the category will be retrieved from the database.
0065      */
0066     explicit ItemScanner(qlonglong imageid);
0067 
0068     ~ItemScanner();
0069 
0070     /**
0071      * Inform the scanner about the category of the file.
0072      * Required at least for newFile() calls, recommended for calls with the
0073      * first constructor above as well.
0074      */
0075     void setCategory(DatabaseItem::Category category);
0076 
0077     /**
0078      * Provides access to the information retrieved by scanning.
0079      * The validity depends on the previously executed scan.
0080      */
0081     const ItemScanInfo& itemScanInfo() const;
0082 
0083     /**
0084      * Loads data from disk (metadata, image file properties).
0085      * This method is called from any of the main entry points above.
0086      * You can call it before if you want to control the time when it is executed.
0087      * Calling it a second time with data already loaded will do nothing.
0088      */
0089     void loadFromDisk();
0090 
0091     /**
0092      * Helper method to translate enum values to user presentable strings
0093      */
0094     static QString formatToString(const QString& format);
0095 
0096 private:
0097 
0098     static bool hasValidField(const QVariantList& list);
0099     static bool lessThanForIdentity(const ItemScanInfo& a, const ItemScanInfo& b);
0100 
0101     // -----------------------------------------------------------------------------
0102 
0103     /** @name Operations with Database
0104      */
0105 
0106     //@{
0107 
0108 public:
0109 
0110     /**
0111      * Call this when you want ItemScanner to add a new file to the database
0112      * and read all information into the database.
0113      */
0114     void newFile(int albumId);
0115 
0116     /**
0117      * Call this when you want ItemScanner to add a new file to the database
0118      * and read all information into the database. This variant will not use
0119      * the unique hash to establish identify with an existing entry, but
0120      * read all information newly from the file.
0121      */
0122     void newFileFullScan(int albumId);
0123 
0124     /**
0125      * Call this to take an existing image in the database, but re-read
0126      * all information from the file into the database, possibly overwriting
0127      * information there.
0128      */
0129     void rescan();
0130 
0131     /**
0132      * This is the same as rescan() but the database metadata
0133      * will be cleaned up if the corresponding metadata
0134      * write option is enabled.
0135      */
0136     void cleanScan();
0137 
0138     /**
0139      * Commits the scanned information to the database.
0140      * You must call this after scanning was done for any changes to take effect.
0141      * Only this method will perform write operations to the database.
0142      */
0143     void commit();
0144 
0145     /**
0146      * Returns the image id of the scanned file, if (yet) available.
0147      */
0148     qlonglong id() const;
0149 
0150     /**
0151      * Similar to newFile.
0152      * Call this when you want ItemScanner to add a new file to the database
0153      * which is a copy of another file, copying attributes from the src
0154      * and rescanning other attributes as appropriate.
0155      * Give the id of the album of the new file, and the id of the src file.
0156      */
0157     void copiedFrom(int albumId, qlonglong srcId);
0158 
0159     /**
0160      * Sort a list of infos by proximity to the given subject.
0161      * Infos are near if they are e.g. in the same album.
0162      * They are not near if they are e.g. in different collections.
0163      */
0164     static void sortByProximity(QList<ItemInfo>& infos, const ItemInfo& subject);
0165 
0166 protected:
0167 
0168     bool copyFromSource(qlonglong src);
0169     void commitCopyImageAttributes();
0170     void cleanDatabaseMetadata();
0171 
0172     void prepareAddImage(int albumId);
0173     bool commitAddImage();
0174 
0175     //@}
0176 
0177     // -----------------------------------------------------------------------------
0178 
0179     /** @name Operations on File Metadata
0180      */
0181 
0182     //@{
0183 
0184 public:
0185 
0186     /**
0187      * Call this when you have detected that a file in the database has been
0188      * modified on disk. Only two groups of fields will be updated in the database:
0189      * - filesystem specific properties (those that signaled you that the file has been modified
0190      *   because their state on disk differed from the state in the database)
0191      * - image specific properties, for which a difference in the database independent from
0192      *   the actual file does not make sense (width/height, bit depth, color model)
0193      */
0194     void fileModified();
0195 
0196     /**
0197      * Returns File-metadata container with user-presentable information.
0198      * These methods provide the reverse service: Not writing into the db, but reading from the db.
0199      */
0200     static void fillCommonContainer(qlonglong imageid, ImageCommonContainer* const container);
0201 
0202     /**
0203      * Returns a suitable creation date from file system information.
0204      * Use this as a fallback if metadata is not available.
0205      */
0206     static QDateTime creationDateFromFilesystem(const QFileInfo& info);
0207 
0208 protected:
0209 
0210     void prepareUpdateImage();
0211     void commitUpdateImage();
0212 
0213     bool scanFromIdenticalFile();
0214     void scanFile(ScanMode mode);
0215 
0216     void scanItemInformation();
0217     void commitItemInformation();
0218 
0219     //@}
0220 
0221     // -----------------------------------------------------------------------------
0222 
0223     /** @name Operations on Photo Metadata
0224      */
0225 
0226     //@{
0227 
0228 public:
0229 
0230     /**
0231      * Helper method to return official property name by which
0232      * IPTC core properties are stored in the database (ItemCopyright and ImageProperties table).
0233      * Allowed arguments: All MetadataInfo::Fields starting with "IptcCore..."
0234      */
0235     static QString iptcCorePropertyName(MetadataInfo::Field field);
0236 
0237     static MetadataFields allImageMetadataFields();
0238 
0239 protected:
0240 
0241     QString detectImageFormat() const;
0242 
0243     void scanImageMetadata();
0244     void commitImageMetadata();
0245     void scanItemPosition();
0246     void commitItemPosition();
0247     void scanItemComments();
0248     void commitItemComments();
0249     void scanItemCopyright();
0250     void commitItemCopyright();
0251     void scanIPTCCore();
0252     void commitIPTCCore();
0253     void scanTags();
0254     void commitTags();
0255     void scanFaces();
0256     void commitFaces();
0257 
0258     bool checkRatingFromMetadata(const QVariant& ratingFromMetadata) const;
0259     void checkCreationDateFromMetadata(QVariant& dateFromMetadata)   const;
0260 
0261     //@}
0262 
0263     // -----------------------------------------------------------------------------
0264 
0265     /** @name Operations on Video Metadata
0266      */
0267 
0268     //@{
0269 
0270 public:
0271 
0272     /**
0273      * Returns Video container with user-presentable information.
0274      * These methods provide the reverse service: Not writing into the db, but reading from the db.
0275      */
0276     static void fillVideoMetadataContainer(qlonglong imageid, VideoMetadataContainer* const container);
0277 
0278 protected:
0279 
0280     void scanVideoInformation();
0281     void scanVideoMetadata();
0282     void commitVideoMetadata();
0283     QString detectVideoFormat() const;
0284     QString detectAudioFormat() const;
0285     static MetadataFields allVideoMetadataFields();
0286 
0287     //@}
0288 
0289     // -----------------------------------------------------------------------------
0290 
0291     /** @name Operations on History Metadata
0292      */
0293 
0294     //@{
0295 
0296 public:
0297 
0298     /**
0299      * Returns true if this file has been marked as needing history resolution at a later stage
0300      */
0301     bool hasHistoryToResolve() const;
0302 
0303     //@{
0304     /**
0305      * Resolves the image history of the image id by filling the ImageRelations table
0306      * for all contained referred images.
0307      * If needTaggingIds is given, all ids marked for needing tagging of the history graph are added.
0308      */
0309     static bool resolveImageHistory(qlonglong id, QList<qlonglong>* needTaggingIds = nullptr);
0310     static bool resolveImageHistory(qlonglong imageId, const QString& historyXml, QList<qlonglong>* needTaggingIds = nullptr);
0311     //@}
0312 
0313     /**
0314      * Takes the history graph reachable from the given image, and assigns
0315      * versioning tags to all entries based on history image types and graph structure
0316      */
0317     static void tagItemHistoryGraph(qlonglong id);
0318 
0319     /**
0320      * All referred images of the given history will be resolved.
0321      * In the returned history, the actions are the same, while each
0322      * referred image actually exists in the collection
0323      * (if mustBeAvailable is true, it is even in a currently available collection).
0324      * That means the number of referred images may be less or greater than initially.
0325      * Note that this history may have peculiar properties, like multiple Original or Current entries
0326      * (if the source entry resolves to multiple collection images), so this history
0327      * is only for internal use, not for storage.
0328      */
0329     static DImageHistory resolvedImageHistory(const DImageHistory& history, bool mustBeAvailable = false);
0330 
0331     /**
0332      * Determines if the two ids refer to the same image.
0333      * Does not check if such a referred image really exists.
0334      */
0335     static bool sameReferredImage(const HistoryImageId& id1, const HistoryImageId& id2);
0336 
0337     /**
0338      * Returns all image ids fulfilling the given image id.
0339      */
0340     static QList<qlonglong> resolveHistoryImageId(const HistoryImageId& historyId);
0341 
0342 protected:
0343 
0344     void scanImageHistory();
0345     void commitImageHistory();
0346     void scanImageHistoryIfModified();
0347 
0348     QString uniqueHash() const;
0349 
0350     //@}
0351 
0352 public:
0353 
0354     /**
0355      * @brief scanBalooInfo - retrieve tags, comments and rating from Baloo Desktop service.
0356      */
0357     void scanBalooInfo();
0358 
0359 private:
0360 
0361     // Disable
0362     ItemScanner(const ItemScanner&)            = delete;
0363     ItemScanner& operator=(const ItemScanner&) = delete;
0364 
0365 private:
0366 
0367     class Private;
0368     Private* const d;
0369 };
0370 
0371 } // namespace Digikam
0372 
0373 #endif // DIGIKAM_ITEM_SCANNER_H