File indexing completed on 2025-03-09 03:52:41
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 - private containers. 0008 * 0009 * SPDX-FileCopyrightText: 2005-2006 by Tom Albers <tomalbers at kde dot nl> 0010 * SPDX-FileCopyrightText: 2007-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0011 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "collectionscanner_p.h" 0018 0019 namespace Digikam 0020 { 0021 0022 bool s_modificationDateEquals(const QDateTime& a, const QDateTime& b) 0023 { 0024 if (!a.isValid() || !b.isValid()) 0025 { 0026 return false; 0027 } 0028 0029 if (a != b) 0030 { 0031 // allow a "modify window" of one second. 0032 // FAT filesystems store the modify date in 2-second resolution. 0033 0034 int diff = a.secsTo(b); 0035 0036 if (abs(diff) > 1) 0037 { 0038 return false; 0039 } 0040 } 0041 0042 return true; 0043 } 0044 0045 // -------------------------------------------------------------------- 0046 0047 NewlyAppearedFile::NewlyAppearedFile() 0048 : albumId(0) 0049 { 0050 } 0051 0052 NewlyAppearedFile::NewlyAppearedFile(int albumId, const QString& fileName) 0053 : albumId (albumId), 0054 fileName(fileName) 0055 { 0056 } 0057 0058 bool NewlyAppearedFile::operator==(const NewlyAppearedFile& other) const 0059 { 0060 return ( 0061 (albumId == other.albumId) && 0062 (fileName == other.fileName) 0063 ); 0064 } 0065 0066 // -------------------------------------------------------------------- 0067 0068 bool CollectionScannerHintContainerImplementation::hasAnyNormalHint(qlonglong id) 0069 { 0070 QReadLocker locker(&lock); 0071 0072 return ( 0073 modifiedItemHints.contains(id) || 0074 rescanItemHints.contains(id) || 0075 metadataAboutToAdjustHints.contains(id) || 0076 metadataAdjustedHints.contains(id) 0077 ); 0078 } 0079 0080 bool CollectionScannerHintContainerImplementation::hasAlbumHints() 0081 { 0082 QReadLocker locker(&lock); 0083 0084 return !albumHints.isEmpty(); 0085 } 0086 0087 bool CollectionScannerHintContainerImplementation::hasModificationHint(qlonglong id) 0088 { 0089 QReadLocker locker(&lock); 0090 0091 return modifiedItemHints.contains(id); 0092 } 0093 0094 bool CollectionScannerHintContainerImplementation::hasRescanHint(qlonglong id) 0095 { 0096 QReadLocker locker(&lock); 0097 0098 return rescanItemHints.contains(id); 0099 } 0100 0101 bool CollectionScannerHintContainerImplementation::hasMetadataAboutToAdjustHint(qlonglong id) 0102 { 0103 QReadLocker locker(&lock); 0104 0105 return metadataAboutToAdjustHints.contains(id); 0106 } 0107 0108 bool CollectionScannerHintContainerImplementation::hasMetadataAdjustedHint(qlonglong id) 0109 { 0110 QReadLocker locker(&lock); 0111 0112 return metadataAdjustedHints.contains(id); 0113 } 0114 0115 void CollectionScannerHintContainerImplementation::recordHints(const QList<AlbumCopyMoveHint>& hints) 0116 { 0117 QWriteLocker locker(&lock); 0118 0119 Q_FOREACH (const AlbumCopyMoveHint& hint, hints) 0120 { 0121 // automagic casting to src and dst 0122 0123 albumHints[hint] = hint; 0124 } 0125 } 0126 0127 void CollectionScannerHintContainerImplementation::recordHints(const QList<ItemCopyMoveHint>& hints) 0128 { 0129 QWriteLocker locker(&lock); 0130 0131 Q_FOREACH (const ItemCopyMoveHint& hint, hints) 0132 { 0133 QList<qlonglong> ids = hint.srcIds(); 0134 QStringList dstNames = hint.dstNames(); 0135 0136 for (int i = 0 ; i < ids.size() ; ++i) 0137 { 0138 itemHints[NewlyAppearedFile(hint.albumIdDst(), dstNames.at(i))] = ids.at(i); 0139 } 0140 } 0141 } 0142 0143 void CollectionScannerHintContainerImplementation::recordHints(const QList<ItemChangeHint>& hints) 0144 { 0145 QWriteLocker locker(&lock); 0146 0147 Q_FOREACH (const ItemChangeHint& hint, hints) 0148 { 0149 const QList<qlonglong>& ids = hint.ids(); 0150 0151 for (int i = 0 ; i < ids.size() ; ++i) 0152 { 0153 if (hint.isModified()) 0154 { 0155 modifiedItemHints << ids.at(i); 0156 } 0157 else 0158 { 0159 rescanItemHints << ids.at(i); 0160 } 0161 } 0162 } 0163 } 0164 0165 void CollectionScannerHintContainerImplementation::recordHint(const ItemMetadataAdjustmentHint& hint) 0166 { 0167 if (hint.isAboutToEdit()) 0168 { 0169 ItemInfo info(hint.id()); 0170 0171 if (! 0172 (s_modificationDateEquals(hint.modificationDate(), info.modDateTime()) && 0173 (hint.fileSize() == info.fileSize())) 0174 ) 0175 { 0176 // refuse to create a hint as a rescan is required already before any metadata edit 0177 // or, in case of multiple edits, there is already a hint with an older date, then all is fine. 0178 0179 return; 0180 } 0181 0182 QWriteLocker locker(&lock); 0183 metadataAboutToAdjustHints[hint.id()] = hint.modificationDate(); 0184 } 0185 else if (hint.isEditingFinished()) 0186 { 0187 QWriteLocker locker(&lock); 0188 QHash<qlonglong, QDateTime>::iterator it = metadataAboutToAdjustHints.find(hint.id()); 0189 0190 if (it == metadataAboutToAdjustHints.end()) 0191 { 0192 return; 0193 } 0194 0195 QDateTime date = it.value(); 0196 metadataAboutToAdjustHints.erase(it); 0197 0198 metadataAdjustedHints[hint.id()] = hint.modificationDate(); 0199 } 0200 else // Aborted 0201 { 0202 QWriteLocker locker(&lock); 0203 QDateTime formerDate = metadataAboutToAdjustHints.take(hint.id()); 0204 } 0205 } 0206 0207 void CollectionScannerHintContainerImplementation::clear() 0208 { 0209 QWriteLocker locker(&lock); 0210 0211 albumHints.clear(); 0212 itemHints.clear(); 0213 modifiedItemHints.clear(); 0214 rescanItemHints.clear(); 0215 metadataAboutToAdjustHints.clear(); 0216 metadataAdjustedHints.clear(); 0217 } 0218 0219 // -------------------------------------------------------------------- 0220 0221 CollectionScanner::Private::Private() 0222 : wantSignals (false), 0223 needTotalFiles (false), 0224 performFastScan (true), 0225 hints (nullptr), 0226 updatingHashHint (false), 0227 recordHistoryIds (false), 0228 deferredFileScanning(false), 0229 observer (nullptr) 0230 { 0231 } 0232 0233 void CollectionScanner::Private::resetRemovedItemsTime() 0234 { 0235 removedItemsTime = QDateTime(); 0236 } 0237 0238 void CollectionScanner::Private::removedItems() 0239 { 0240 removedItemsTime = QDateTime::currentDateTime(); 0241 } 0242 0243 bool CollectionScanner::Private::checkObserver() 0244 { 0245 if (observer) 0246 { 0247 return observer->continueQuery(); 0248 } 0249 0250 return true; 0251 } 0252 0253 bool CollectionScanner::Private::checkDeferred(const QFileInfo& info) 0254 { 0255 if (deferredFileScanning) 0256 { 0257 deferredAlbumPaths << info.path(); 0258 0259 return true; 0260 } 0261 0262 return false; 0263 } 0264 0265 void CollectionScanner::Private::finishScanner(ItemScanner& scanner) 0266 { 0267 /** 0268 * Perform the actual write operation to the database 0269 */ 0270 { 0271 CoreDbOperationGroup group; 0272 scanner.commit(); 0273 } 0274 0275 if (recordHistoryIds && scanner.hasHistoryToResolve()) 0276 { 0277 needResolveHistorySet << scanner.id(); 0278 } 0279 } 0280 0281 } // namespace Digikam