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