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 - database helper.
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 #include "itemscanner_p.h"
0017 
0018 namespace Digikam
0019 {
0020 
0021 qlonglong ItemScanner::id() const
0022 {
0023     return d->scanInfo.id;
0024 }
0025 
0026 void ItemScanner::commit()
0027 {
0028     qCDebug(DIGIKAM_DATABASE_LOG) << "Scanning took" << d->timer.restart() << "ms";
0029 
0030     switch (d->commit.operation)
0031     {
0032         case ItemScannerCommit::NoOp:
0033         {
0034             return;
0035         }
0036 
0037         case ItemScannerCommit::AddItem:
0038         {
0039             if (!commitAddImage())
0040             {
0041                 return;
0042             }
0043 
0044             break;
0045         }
0046 
0047         case ItemScannerCommit::UpdateItem:
0048         {
0049             commitUpdateImage();
0050             break;
0051         }
0052     }
0053 
0054     if (d->commit.copyImageAttributesId != -1)
0055     {
0056         commitCopyImageAttributes();
0057         return;
0058     }
0059 
0060     if (d->commit.commitItemInformation)
0061     {
0062         commitItemInformation();
0063     }
0064 
0065     if (d->commit.commitImageMetadata)
0066     {
0067         commitImageMetadata();
0068     }
0069     else if (d->commit.commitVideoMetadata)
0070     {
0071         commitVideoMetadata();
0072     }
0073 
0074     if (d->commit.commitItemPosition)
0075     {
0076         commitItemPosition();
0077     }
0078 
0079     if (d->commit.commitItemComments)
0080     {
0081         commitItemComments();
0082     }
0083 
0084     if (d->commit.commitItemCopyright)
0085     {
0086         commitItemCopyright();
0087     }
0088 
0089     if (d->commit.commitIPTCCore)
0090     {
0091         commitIPTCCore();
0092     }
0093 
0094     if (!d->commit.tagIds.isEmpty())
0095     {
0096         commitTags();
0097     }
0098 
0099     if (d->commit.commitFaces)
0100     {
0101         commitFaces();
0102     }
0103 
0104     commitImageHistory();
0105 }
0106 
0107 void ItemScanner::newFile(int albumId)
0108 {
0109     loadFromDisk();
0110     prepareAddImage(albumId);
0111 
0112     if (!scanFromIdenticalFile())
0113     {
0114         scanFile(NewScan);
0115     }
0116 }
0117 
0118 void ItemScanner::newFileFullScan(int albumId)
0119 {
0120     loadFromDisk();
0121     prepareAddImage(albumId);
0122     scanFile(NewScan);
0123 }
0124 
0125 void ItemScanner::rescan()
0126 {
0127     loadFromDisk();
0128     prepareUpdateImage();
0129     scanFile(Rescan);
0130 }
0131 
0132 void ItemScanner::cleanScan()
0133 {
0134     loadFromDisk();
0135     prepareUpdateImage();
0136     scanFile(CleanScan);
0137 }
0138 
0139 void ItemScanner::copiedFrom(int albumId, qlonglong srcId)
0140 {
0141     loadFromDisk();
0142     prepareAddImage(albumId);
0143 
0144     // first use source, if it exists
0145 
0146     if (!copyFromSource(srcId))
0147     {
0148         // check if we can establish identity
0149 
0150         if (!scanFromIdenticalFile())
0151         {
0152             // scan newly
0153 
0154             scanFile(NewScan);
0155         }
0156     }
0157 }
0158 
0159 void ItemScanner::commitCopyImageAttributes()
0160 {
0161     CoreDbAccess().db()->copyImageAttributes(d->commit.copyImageAttributesId, d->scanInfo.id);
0162 
0163     // Also copy the similarity information
0164 
0165     SimilarityDbAccess().db()->copySimilarityAttributes(d->commit.copyImageAttributesId, d->scanInfo.id);
0166 
0167     // Remove grouping for copied or identical images.
0168 
0169     CoreDbAccess().db()->removeAllImageRelationsFrom(d->scanInfo.id, DatabaseRelation::Grouped);
0170     CoreDbAccess().db()->removeAllImageRelationsTo(d->scanInfo.id, DatabaseRelation::Grouped);
0171 }
0172 
0173 bool ItemScanner::copyFromSource(qlonglong srcId)
0174 {
0175     // some basic validity checking
0176 
0177     if (srcId == d->scanInfo.id)
0178     {
0179         return false;
0180     }
0181 
0182     ItemScanInfo info = CoreDbAccess().db()->getItemScanInfo(srcId);
0183 
0184     if (!info.id)
0185     {
0186         return false;
0187     }
0188 
0189     qCDebug(DIGIKAM_DATABASE_LOG) << "Recognized" << d->fileInfo.filePath() << "as copied from" << srcId;
0190     d->commit.copyImageAttributesId = srcId;
0191 
0192     return true;
0193 }
0194 
0195 void ItemScanner::prepareAddImage(int albumId)
0196 {
0197     d->scanInfo.albumID = albumId;
0198     d->scanInfo.status  = DatabaseItem::Visible;
0199 
0200     qCDebug(DIGIKAM_DATABASE_LOG) << "Adding new item" << d->fileInfo.filePath();
0201     d->commit.operation = ItemScannerCommit::AddItem;
0202 }
0203 
0204 bool ItemScanner::commitAddImage()
0205 {
0206     // find the image id of a deleted image info if existent and mark it as valid.
0207     // otherwise, create a new item.
0208 
0209     qlonglong imageId = CoreDbAccess().db()->findImageId(-1, d->scanInfo.itemName, DatabaseItem::Status::Trashed,
0210                                                          d->scanInfo.category, d->scanInfo.fileSize, d->scanInfo.uniqueHash);
0211 
0212     if (imageId != -1 && (d->commit.copyImageAttributesId == -1))
0213     {
0214         qCDebug(DIGIKAM_DATABASE_LOG) << "Detected identical image info with id" << imageId
0215                                       << "and album id NULL of a removed image for image" << d->scanInfo.itemName;
0216         qCDebug(DIGIKAM_DATABASE_LOG) << "Will reuse this image info and set the status to visible and the album id to" << d->scanInfo.albumID;
0217 
0218         d->scanInfo.id = imageId;
0219         CoreDbAccess().db()->setItemAlbum(imageId, d->scanInfo.albumID);
0220         CoreDbAccess().db()->setItemStatus(imageId, DatabaseItem::Status::Visible);
0221 
0222         return false;
0223     }
0224     else
0225     {
0226         d->scanInfo.id = CoreDbAccess().db()->addItem(d->scanInfo.albumID, d->scanInfo.itemName,
0227                                                       d->scanInfo.status, d->scanInfo.category,
0228                                                       d->scanInfo.modificationDate, d->scanInfo.fileSize,
0229                                                       d->scanInfo.uniqueHash);
0230     }
0231 
0232     return true;
0233 }
0234 
0235 void ItemScanner::cleanDatabaseMetadata()
0236 {
0237     if (d->scanInfo.id == -1)
0238     {
0239         return;
0240     }
0241 
0242     const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings();
0243     QList<int> removeTags;
0244 
0245     if (settings.saveColorLabel)
0246     {
0247         const QVector<int>& colorTags = TagsCache::instance()->colorLabelTags();
0248         removeTags << QList<int>(colorTags.begin(), colorTags.end());
0249     }
0250 
0251     if (settings.savePickLabel)
0252     {
0253         const QVector<int>& pickTags = TagsCache::instance()->pickLabelTags();
0254         removeTags << QList<int>(pickTags.begin(), pickTags.end());
0255     }
0256 
0257     if (settings.saveTags)
0258     {
0259         Q_FOREACH (int tag, CoreDbAccess().db()->getItemTagIDs(d->scanInfo.id))
0260         {
0261             if (!TagsCache::instance()->isInternalTag(tag))
0262             {
0263                 removeTags << tag;
0264             }
0265         }
0266     }
0267 
0268     if (!removeTags.isEmpty())
0269     {
0270         CoreDbAccess().db()->removeTagsFromItems(QList<qlonglong>() << d->scanInfo.id, removeTags);
0271     }
0272 
0273     if (settings.savePosition)
0274     {
0275         CoreDbAccess().db()->removeItemPosition(d->scanInfo.id);
0276     }
0277 
0278     if (settings.saveTemplate)
0279     {
0280         CoreDbAccess().db()->removeAllImageProperties(d->scanInfo.id);
0281         CoreDbAccess().db()->removeAllItemCopyrightProperties(d->scanInfo.id);
0282     }
0283 
0284     if (settings.saveComments)
0285     {
0286         CoreDbAccess().db()->removeAllImageComments(d->scanInfo.id);
0287     }
0288 
0289     if (settings.saveFaceTags)
0290     {
0291         Q_FOREACH (const ImageTagProperty& property, CoreDbAccess().db()->getImageTagProperties(d->scanInfo.id))
0292         {
0293             if (property.property == ImageTagPropertyName::tagRegion())
0294             {
0295                 CoreDbAccess().db()->removeImageTagProperties(d->scanInfo.id, property.tagId, property.property);
0296             }
0297         }
0298     }
0299 
0300     if (settings.saveRating)
0301     {
0302         CoreDbAccess().db()->changeItemInformation(d->scanInfo.id, QVariantList() << NoRating, DatabaseFields::Rating);
0303     }
0304 }
0305 
0306 } // namespace Digikam