File indexing completed on 2025-01-05 03:53:55
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 - scan utilities. 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 void CollectionScanner::loadNameFilters() 0023 { 0024 if (!d->nameFilters.isEmpty()) 0025 { 0026 return; 0027 } 0028 0029 QStringList imageFilter, audioFilter, videoFilter, ignoreDirectory; 0030 0031 CoreDbAccess().db()->getFilterSettings(&imageFilter, &videoFilter, &audioFilter); 0032 CoreDbAccess().db()->getIgnoreDirectoryFilterSettings(&ignoreDirectory); 0033 0034 // three sets to find category of a file 0035 0036 d->imageFilterSet = QSet<QString>(imageFilter.begin(), imageFilter.end()); 0037 d->audioFilterSet = QSet<QString>(audioFilter.begin(), audioFilter.end()); 0038 d->videoFilterSet = QSet<QString>(videoFilter.begin(), videoFilter.end()); 0039 d->ignoreDirectory = QSet<QString>(ignoreDirectory.begin(), ignoreDirectory.end()); 0040 0041 d->nameFilters = d->imageFilterSet + d->audioFilterSet + d->videoFilterSet; 0042 } 0043 0044 void CollectionScanner::mainEntryPoint(bool complete) 0045 { 0046 loadNameFilters(); 0047 d->recordHistoryIds = !complete; 0048 } 0049 0050 void CollectionScanner::safelyRemoveAlbums(const QList<int>& albumIds) 0051 { 0052 // Remove the items (orphan items, detach them from the album, but keep entries for a certain time) 0053 // Make album orphan (no album root, keep entries until next application start) 0054 0055 CoreDbAccess access; 0056 CoreDbTransaction transaction(&access); 0057 0058 Q_FOREACH (int albumId, albumIds) 0059 { 0060 QList<qlonglong> ids = access.db()->getItemIDsInAlbum(albumId); 0061 access.db()->removeItemsFromAlbum(albumId, ids); 0062 access.db()->makeStaleAlbum(albumId); 0063 itemsWereRemoved(ids); 0064 } 0065 } 0066 0067 int CollectionScanner::checkAlbum(const CollectionLocation& location, const QString& album) 0068 { 0069 // get album id if album exists 0070 0071 int albumID = CoreDbAccess().db()->getAlbumForPath(location.id(), album, false); 0072 0073 d->establishedSourceAlbums.remove(albumID); 0074 0075 // create if necessary 0076 0077 if (albumID == -1) 0078 { 0079 QFileInfo fi(location.albumRootPath() + album); 0080 albumID = CoreDbAccess().db()->addAlbum(location.id(), album, QString(), fi.lastModified().date(), QString()); 0081 0082 // have album this one was copied from? 0083 0084 if (d->hints) 0085 { 0086 CollectionScannerHints::Album src; 0087 { 0088 QReadLocker locker(&d->hints->lock); 0089 src = d->hints->albumHints.value(CollectionScannerHints::DstPath(location.id(), album)); 0090 } 0091 0092 if (!src.isNull()) 0093 { 0094 //qCDebug(DIGIKAM_DATABASE_LOG) << "Identified album" << src.albumId << "as source of new album" << fi.filePath(); 0095 0096 CoreDbAccess().db()->copyAlbumProperties(src.albumId, albumID); 0097 d->establishedSourceAlbums[albumID] = src.albumId; 0098 } 0099 } 0100 } 0101 0102 return albumID; 0103 } 0104 0105 void CollectionScanner::copyFileProperties(const ItemInfo& source, const ItemInfo& d) 0106 { 0107 if (source.isNull() || d.isNull()) 0108 { 0109 return; 0110 } 0111 0112 ItemInfo dest(d); 0113 CoreDbOperationGroup group; 0114 0115 qCDebug(DIGIKAM_DATABASE_LOG) << "Copying properties from" << source.id() << "to" << dest.id(); 0116 0117 // Rating, creation dates 0118 0119 DatabaseFields::ItemInformation imageInfoFields = DatabaseFields::Rating | 0120 DatabaseFields::CreationDate | 0121 DatabaseFields::DigitizationDate; 0122 0123 QVariantList imageInfos = CoreDbAccess().db()->getItemInformation(source.id(), imageInfoFields); 0124 0125 if (!imageInfos.isEmpty()) 0126 { 0127 CoreDbAccess().db()->changeItemInformation(dest.id(), imageInfos, imageInfoFields); 0128 } 0129 0130 // Copy public tags 0131 0132 Q_FOREACH (int tagId, TagsCache::instance()->publicTags(source.tagIds())) 0133 { 0134 dest.setTag(tagId); 0135 } 0136 0137 // Copy color and pick label 0138 0139 dest.setPickLabel(source.pickLabel()); 0140 dest.setColorLabel(source.colorLabel()); 0141 0142 // important: skip other internal tags, such a history tags. Therefore CoreDB::copyImageTags is not to be used. 0143 0144 // GPS data 0145 0146 QVariantList positionData = CoreDbAccess().db()->getItemPosition(source.id(), DatabaseFields::ItemPositionsAll); 0147 0148 if (!positionData.isEmpty()) 0149 { 0150 CoreDbAccess().db()->addItemPosition(dest.id(), positionData, DatabaseFields::ItemPositionsAll); 0151 } 0152 0153 // Comments 0154 0155 { 0156 CoreDbAccess access; 0157 ItemComments commentsSource(access, source.id()); 0158 ItemComments commentsDest(access, dest.id()); 0159 commentsDest.replaceFrom(commentsSource); 0160 commentsDest.apply(access); 0161 } 0162 0163 // Copyright info 0164 0165 ItemCopyright copyrightDest(dest.id()); 0166 copyrightDest.replaceFrom(ItemCopyright(source.id())); 0167 0168 // Image Properties 0169 0170 CoreDbAccess().db()->copyImageProperties(source.id(), dest.id()); 0171 } 0172 0173 void CollectionScanner::itemsWereRemoved(const QList<qlonglong>& removedIds) 0174 { 0175 // set time stamp 0176 0177 d->removedItems(); 0178 0179 // manage relations 0180 0181 QList<qlonglong> relatedImages = CoreDbAccess().db()->getOneRelatedImageEach(removedIds, DatabaseRelation::DerivedFrom); 0182 qCDebug(DIGIKAM_DATABASE_LOG) << "Removed items:" << removedIds << "related items:" << relatedImages; 0183 0184 if (d->recordHistoryIds) 0185 { 0186 Q_FOREACH (const qlonglong& id, relatedImages) 0187 { 0188 d->needTaggingHistorySet << id; 0189 } 0190 } 0191 else 0192 { 0193 int needTaggingTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::needTaggingHistoryGraph()); 0194 CoreDbAccess().db()->addTagsToItems(relatedImages, QList<int>() << needTaggingTag); 0195 } 0196 } 0197 0198 int CollectionScanner::countItemsInFolder(const QString& path) 0199 { 0200 QDir dir(path); 0201 0202 if (!dir.exists() || !dir.isReadable()) 0203 { 0204 return 0; 0205 } 0206 0207 CollectionLocation location = CollectionManager::instance()->locationForPath(path); 0208 0209 if (!location.isNull() && databaseInitialScanDone()) 0210 { 0211 QString album = CollectionManager::instance()->album(path); 0212 int albumID = CoreDbAccess().db()->getAlbumForPath(location.id(), album, false); 0213 0214 if (albumID != -1) 0215 { 0216 QPair<int, int> numberPair = CoreDbAccess().db()-> 0217 getNumberOfAllItemsAndAlbums(albumID); 0218 0219 if (numberPair.first) 0220 { 0221 return (numberPair.first + numberPair.second); 0222 } 0223 } 0224 } 0225 0226 // Also count the current folder 0227 0228 int items = 1; 0229 0230 QDirIterator it(dir.path(), QDir::Dirs | 0231 QDir::Files | 0232 QDir::NoDotAndDotDot, 0233 QDirIterator::Subdirectories); 0234 0235 while (it.hasNext()) 0236 { 0237 it.next(); 0238 ++items; 0239 } 0240 0241 return items; 0242 } 0243 0244 DatabaseItem::Category CollectionScanner::category(const QFileInfo& info) 0245 { 0246 QString suffix = info.suffix().toLower(); 0247 0248 if (d->imageFilterSet.contains(suffix)) 0249 { 0250 return DatabaseItem::Image; 0251 } 0252 else if (d->audioFilterSet.contains(suffix)) 0253 { 0254 return DatabaseItem::Audio; 0255 } 0256 else if (d->videoFilterSet.contains(suffix)) 0257 { 0258 return DatabaseItem::Video; 0259 } 0260 else 0261 { 0262 return DatabaseItem::Other; 0263 } 0264 } 0265 0266 void CollectionScanner::markDatabaseAsScanned() 0267 { 0268 CoreDbAccess access; 0269 access.db()->setSetting(QLatin1String("Scanned"), QDateTime::currentDateTime().toString(Qt::ISODate)); 0270 } 0271 0272 void CollectionScanner::updateRemovedItemsTime() 0273 { 0274 // Called after a complete or partial scan finishes, to write the value 0275 // held in d->removedItemsTime to the database 0276 0277 if (!d->removedItemsTime.isNull()) 0278 { 0279 CoreDbAccess().db()->setSetting(QLatin1String("RemovedItemsTime"), d->removedItemsTime.toString(Qt::ISODate)); 0280 d->removedItemsTime = QDateTime(); 0281 } 0282 } 0283 0284 void CollectionScanner::incrementDeleteRemovedCompleteScanCount() 0285 { 0286 CoreDbAccess access; 0287 int count = access.db()->getSetting(QLatin1String("DeleteRemovedCompleteScanCount")).toInt(); 0288 ++count; 0289 access.db()->setSetting(QLatin1String("DeleteRemovedCompleteScanCount"), QString::number(count)); 0290 } 0291 0292 void CollectionScanner::resetDeleteRemovedSettings() 0293 { 0294 CoreDbAccess().db()->setSetting(QLatin1String("RemovedItemsTime"), QString()); 0295 CoreDbAccess().db()->setSetting(QLatin1String("DeleteRemovedTime"), QDateTime::currentDateTime().toString(Qt::ISODate)); 0296 CoreDbAccess().db()->setSetting(QLatin1String("DeleteRemovedCompleteScanCount"), QString::number(0)); 0297 } 0298 0299 bool CollectionScanner::checkDeleteRemoved() 0300 { 0301 // returns true if removed items shall be deleted 0302 0303 CoreDbAccess access; 0304 0305 // retrieve last time an item was removed (not deleted, but set to status removed) 0306 0307 QString removedItemsTimeString = access.db()->getSetting(QLatin1String("RemovedItemsTime")); 0308 0309 if (removedItemsTimeString.isNull()) 0310 { 0311 return false; 0312 } 0313 0314 // retrieve last time removed items were (definitely) deleted from db 0315 0316 QString deleteRemovedTimeString = access.db()->getSetting(QLatin1String("DeleteRemovedTime")); 0317 QDateTime removedItemsTime, deleteRemovedTime; 0318 0319 if (!removedItemsTimeString.isNull()) 0320 { 0321 removedItemsTime = QDateTime::fromString(removedItemsTimeString, Qt::ISODate); 0322 } 0323 0324 if (!deleteRemovedTimeString.isNull()) 0325 { 0326 deleteRemovedTime = QDateTime::fromString(deleteRemovedTimeString, Qt::ISODate); 0327 } 0328 0329 QDateTime now = QDateTime::currentDateTime(); 0330 0331 // retrieve number of complete collection scans since the last time that removed items were deleted 0332 0333 int completeScans = access.db()->getSetting(QLatin1String("DeleteRemovedCompleteScanCount")).toInt(); 0334 0335 // No removed items? No need to delete any 0336 0337 if (!removedItemsTime.isValid()) 0338 { 0339 return false; 0340 } 0341 0342 // give at least a week between removed item deletions 0343 0344 if (deleteRemovedTime.isValid()) 0345 { 0346 if (deleteRemovedTime.daysTo(now) <= 7) 0347 { 0348 return false; 0349 } 0350 } 0351 0352 // Now look at time since items were removed, and the number of complete scans 0353 // since removed items were deleted. Values arbitrarily chosen. 0354 0355 int daysPast = removedItemsTime.daysTo(now); 0356 0357 return ( 0358 ((daysPast > 7) && (completeScans > 2)) || 0359 ((daysPast > 30) && (completeScans > 0)) || 0360 (completeScans > 30) 0361 ); 0362 } 0363 0364 // ------------------------------------------------------------------------------------------ 0365 0366 #if 0 0367 0368 void CollectionScanner::scanForStaleAlbums() 0369 { 0370 QStringList albumRootPaths = CollectionManager::instance()->allAvailableAlbumRootPaths(); 0371 0372 for (QStringList::const_iterator it = albumRootPaths.constBegin() ; 0373 it != albumRootPaths.constEnd() ; ++it) 0374 { 0375 scanForStaleAlbums(*it); 0376 } 0377 } 0378 0379 void CollectionScanner::scanForStaleAlbums(const QString& albumRoot) 0380 { 0381 Q_UNUSED(albumRoot); 0382 QList<AlbumShortInfo> albumList = CoreDbAccess().db()->getAlbumShortInfos(); 0383 QList<AlbumShortInfo> toBeDeleted; 0384 0385 QList<AlbumShortInfo>::const_iterator it; 0386 0387 for (it = albumList.constBegin() ; it != albumList.constEnd() ; ++it) 0388 { 0389 QFileInfo fileInfo((*it).albumRoot + (*it).url); 0390 0391 if (!fileInfo.exists() || !fileInfo.isDir()) 0392 { 0393 m_foldersToBeDeleted << (*it); 0394 } 0395 } 0396 } 0397 0398 QStringList CollectionScanner::formattedListOfStaleAlbums() 0399 { 0400 QStringList list; 0401 QList<AlbumShortInfo>::const_iterator it; 0402 0403 for (it = m_foldersToBeDeleted.constBegin() ; 0404 it != m_foldersToBeDeleted.constEnd() ; ++it) 0405 { 0406 list << (*it).url; 0407 } 0408 0409 return list; 0410 } 0411 0412 void CollectionScanner::removeStaleAlbums() 0413 { 0414 CoreDbAccess access; 0415 CoreDbTransaction transaction(&access); 0416 QList<AlbumShortInfo>::const_iterator it; 0417 0418 for (it = m_foldersToBeDeleted.constBegin() ; it != m_foldersToBeDeleted.constEnd() ; ++it) 0419 { 0420 qCDebug(DIGIKAM_DATABASE_LOG) << "Removing album " << (*it).albumRoot + QLatin1Char('/') + (*it).url; 0421 access.db()->deleteAlbum((*it).id); 0422 } 0423 } 0424 0425 QStringList CollectionScanner::formattedListOfStaleFiles() 0426 { 0427 QStringList listToBeDeleted; 0428 0429 CoreDbAccess access; 0430 QList<QPair<QString, int> >::const_iterator it; 0431 0432 for (it = m_filesToBeDeleted.constBegin() ; it != m_filesToBeDeleted.constEnd() ; ++it) 0433 { 0434 QString location = QLatin1String(" (") + access.db()->getAlbumPath((*it).second) + QLatin1Char(')'); 0435 0436 listToBeDeleted.append((*it).first + location); 0437 } 0438 0439 return listToBeDeleted; 0440 } 0441 0442 void CollectionScanner::removeStaleFiles() 0443 { 0444 CoreDbAccess access; 0445 CoreDbTransaction transaction(&access); 0446 QList<QPair<QString, int> >::const_iterator it; 0447 0448 for (it = m_filesToBeDeleted.constBegin() ; it != m_filesToBeDeleted.constEnd() ; ++it) 0449 { 0450 qCDebug(DIGIKAM_DATABASE_LOG) << "Removing: " << (*it).first << " in " << (*it).second; 0451 access.db()->deleteItem( (*it).second, (*it).first ); 0452 } 0453 } 0454 0455 void CollectionScanner::scanAlbums() 0456 { 0457 QStringList albumRootPaths = CollectionManager::instance()->allAvailableAlbumRootPaths(); 0458 int count = 0; 0459 0460 for (QStringList::const_iterator it = albumRootPaths.constBegin() ; it != albumRootPaths.constEnd() ; ++it) 0461 { 0462 count += countItemsInFolder(*it); 0463 } 0464 0465 Q_EMIT totalFilesToScan(count); 0466 0467 for (QStringList::const_iterator it = albumRootPaths.constBegin() ; it != albumRootPaths.constEnd() ; ++it) 0468 { 0469 QDir dir(*it); 0470 QStringList fileList(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)); 0471 CoreDbTransaction transaction; 0472 0473 Q_FOREACH (const QString& dir, fileList) 0474 { 0475 scanAlbum(*it, QLatin1Char('/') + dir); 0476 } 0477 } 0478 } 0479 0480 void CollectionScanner::scan(const QString& folderPath) 0481 { 0482 CollectionManager* const manager = CollectionManager::instance(); 0483 QUrl url; 0484 url.setPath(folderPath); 0485 QString albumRoot = manager->albumRootPath(url); 0486 QString album = manager->album(url); 0487 0488 if (albumRoot.isNull()) 0489 { 0490 qCWarning(DIGIKAM_DATABASE_LOG) << "scanAlbums(QString): folder " << folderPath << " not found in collection."; 0491 return; 0492 } 0493 0494 scan(albumRoot, album); 0495 } 0496 0497 void CollectionScanner::scan(const QString& albumRoot, const QString& album) 0498 { 0499 // Step one: remove invalid albums 0500 0501 scanForStaleAlbums(albumRoot); 0502 removeStaleAlbums(); 0503 0504 Q_EMIT totalFilesToScan(countItemsInFolder(albumRoot + album)); 0505 0506 // Step two: Scan directories 0507 0508 if (album == QLatin1String("/")) 0509 { 0510 // Don't scan files under album root, only descend into directories (?) 0511 0512 QDir dir(albumRoot + album); 0513 QStringList fileList(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)); 0514 0515 CoreDbTransaction transaction; 0516 0517 for (QStringList::const_iterator fileIt = fileList.constBegin() ; fileIt != fileList.constEnd() ; ++fileIt) 0518 { 0519 scanAlbum(albumRoot, QLatin1Char('/') + (*fileIt)); 0520 } 0521 } 0522 else 0523 { 0524 CoreDbTransaction transaction; 0525 scanAlbum(albumRoot, album); 0526 } 0527 0528 // Step three: Remove invalid files 0529 0530 removeStaleFiles(); 0531 } 0532 0533 void CollectionScanner::scanAlbum(const QString& filePath) 0534 { 0535 QUrl url; 0536 url.setPath(filePath); 0537 scanAlbum(CollectionManager::instance()->albumRootPath(url), CollectionManager::instance()->album(url)); 0538 } 0539 0540 void CollectionScanner::scanAlbum(const QString& albumRoot, const QString& album) 0541 { 0542 // + Adds album if it does not yet exist in the db. 0543 // + Recursively scans subalbums of album. 0544 // + Adds files if they do not yet exist in the db. 0545 // + Adds stale files from the db to m_filesToBeDeleted 0546 // - Does not add stale albums to m_foldersToBeDeleted. 0547 0548 QDir dir( albumRoot + album ); 0549 0550 if (!dir.exists() || !dir.isReadable()) 0551 { 0552 qCWarning(DIGIKAM_DATABASE_LOG) << "Folder does not exist or is not readable: " << dir.path(); 0553 0554 return; 0555 } 0556 0557 Q_EMIT startScanningAlbum(albumRoot, album); 0558 0559 // get album id if album exists 0560 0561 int albumID = CoreDbAccess().db()->getAlbumForPath(albumRoot, album, false); 0562 0563 if (albumID == -1) 0564 { 0565 QFileInfo fi(albumRoot + album); 0566 albumID = CoreDbAccess().db()->addAlbum(albumRoot, album, QString(), fi.lastModified().date(), QString()); 0567 } 0568 0569 QStringList filesInAlbum = CoreDbAccess().db()->getItemNamesInAlbum( albumID ); 0570 0571 QSet<QString> filesFoundInDB; 0572 0573 for (QStringList::const_iterator it = filesInAlbum.constBegin() ; 0574 it != filesInAlbum.constEnd() ; ++it) 0575 { 0576 filesFoundInDB << *it; 0577 } 0578 0579 const QFileInfoList list = dir.entryInfoList(m_nameFilters, QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot /*not CaseSensitive*/); 0580 0581 QFileInfoList::const_iterator fi; 0582 0583 for (fi = list.constBegin() ; fi != list.constEnd() ; ++fi) 0584 { 0585 if (fi->isFile()) 0586 { 0587 if (filesFoundInDB.contains(fi->fileName()) ) 0588 { 0589 filesFoundInDB.remove(fi->fileName()); 0590 } 0591 else if (fi->completeSuffix() == QLatin1String("digikamtempfile.tmp")) 0592 { 0593 // ignore temp files we created ourselves 0594 continue; 0595 } 0596 else 0597 { 0598 qCDebug(DIGIKAM_DATABASE_LOG) << "Adding item " << fi->fileName(); 0599 addItem(albumID, albumRoot, album, fi->fileName()); 0600 } 0601 } 0602 else if (fi->isDir()) 0603 { 0604 scanAlbum( albumRoot, album + QLatin1Char('/') + fi->fileName() ); 0605 } 0606 } 0607 0608 // Removing items from the db which we did not see on disk. 0609 0610 if (!filesFoundInDB.isEmpty()) 0611 { 0612 QSetIterator<QString> it(filesFoundInDB); 0613 0614 while (it.hasNext()) 0615 { 0616 QPair<QString, int> pair(it.next(),albumID); 0617 0618 if (m_filesToBeDeleted.indexOf(pair) == -1) 0619 { 0620 m_filesToBeDeleted << pair; 0621 } 0622 } 0623 } 0624 0625 Q_EMIT finishedScanningAlbum(albumRoot, album, list.count()); 0626 } 0627 0628 void CollectionScanner::updateItemsWithoutDate() 0629 { 0630 QStringList urls = CoreDbAccess().db()->getAllItemURLsWithoutDate(); 0631 0632 Q_EMIT totalFilesToScan(urls.count()); 0633 0634 QString albumRoot = CoreDbAccess::albumRoot(); 0635 0636 { 0637 CoreDbTransaction transaction; 0638 0639 for (QStringList::const_iterator it = urls.constBegin() ; it != urls.constEnd() ; ++it) 0640 { 0641 Q_EMIT scanningFile(*it); 0642 0643 QFileInfo fi(*it); 0644 QString albumURL = fi.path(); 0645 albumURL = QDir::cleanPath(albumURL.remove(albumRoot)); 0646 int albumID = CoreDbAccess().db()->getAlbumForPath(albumRoot, albumURL); 0647 0648 if (albumID <= 0) 0649 { 0650 qCWarning(DIGIKAM_DATABASE_LOG) << "Album ID == -1: " << albumURL; 0651 } 0652 0653 if (fi.exists()) 0654 { 0655 CollectionScanner::updateItemDate(albumID, albumRoot, albumURL, fi.fileName()); 0656 } 0657 else 0658 { 0659 QPair<QString, int> pair(fi.fileName(), albumID); 0660 0661 if (m_filesToBeDeleted.indexOf(pair) == -1) 0662 { 0663 m_filesToBeDeleted << pair; 0664 } 0665 } 0666 } 0667 } 0668 } 0669 0670 int CollectionScanner::countItemsInFolder(const QString& directory) 0671 { 0672 int items = 0; 0673 0674 QDir dir(directory); 0675 0676 if (!dir.exists() || !dir.isReadable()) 0677 { 0678 return 0; 0679 } 0680 0681 QFileInfoList list = dir.entryInfoList(); 0682 0683 items += list.count(); 0684 0685 QFileInfoList::const_iterator fi; 0686 0687 for (fi = list.constBegin() ; fi != list.constEnd() ; ++fi) 0688 { 0689 if (fi->isDir() && 0690 (fi->fileName() != QLatin1String(".")) && 0691 (fi->fileName() != QLatin1String(".."))) 0692 { 0693 items += countItemsInFolder( fi->filePath() ); 0694 } 0695 } 0696 0697 return items; 0698 } 0699 0700 void CollectionScanner::markDatabaseAsScanned() 0701 { 0702 CoreDbAccess access; 0703 access.db()->setSetting("Scanned", QDateTime::currentDateTime().toString(Qt::ISODate)); 0704 } 0705 0706 // ------------------- Tools ------------------------ 0707 0708 void CollectionScanner::addItem(int albumID, const QString& albumRoot, 0709 const QString& album, const QString& fileName) 0710 { 0711 CoreDbAccess access; 0712 addItem(access, albumID, albumRoot, album, fileName); 0713 } 0714 0715 void CollectionScanner::addItem(Digikam::CoreDbAccess& access, int albumID, 0716 const QString& albumRoot, const QString& album, 0717 const QString& fileName) 0718 { 0719 QString filePath = albumRoot + album + QLatin1Char('/') + fileName; 0720 0721 QString comment; 0722 QStringList keywords; 0723 QDateTime datetime; 0724 int rating; 0725 0726 QScopedPointer<DMetadata> metadata(new DMetadata(filePath)); 0727 0728 // Try to get comments from image : 0729 // In first, from standard JPEG comments, or 0730 // In second, from EXIF comments tag, or 0731 // In third, from IPTC comments tag. 0732 0733 comment = metadata->getImageComment(); 0734 0735 // Try to get date and time from image : 0736 // In first, from EXIF date & time tags, or 0737 // In second, from IPTC date & time tags. 0738 0739 datetime = metadata->getItemDateTime(); 0740 0741 // Try to get image rating from IPTC Urgency tag 0742 // else use file system time stamp. 0743 rating = metadata->getItemRating(); 0744 0745 if (!datetime.isValid()) 0746 { 0747 QFileInfo info(filePath); 0748 datetime = info.lastModified(); 0749 } 0750 0751 // Try to get image tags from IPTC keywords tags. 0752 0753 metadata->getItemTagsPath(keywords); 0754 0755 access.db()->addItem(albumID, fileName, datetime, comment, rating, keywords); 0756 } 0757 0758 void CollectionScanner::updateItemDate(int albumID, const QString& albumRoot, 0759 const QString& album, const QString& fileName) 0760 { 0761 CoreDbAccess access; 0762 updateItemDate(access, albumID, albumRoot, album, fileName); 0763 } 0764 0765 void CollectionScanner::updateItemDate(Digikam::CoreDbAccess& access, int albumID, 0766 const QString& albumRoot, const QString& album, 0767 const QString& fileName) 0768 { 0769 QString filePath = albumRoot + album + QLatin1Char('/') + fileName; 0770 0771 QDateTime datetime; 0772 0773 QScopedPointer<DMetadata> metadata(new DMetadata(filePath)); 0774 0775 // Trying to get date and time from image : 0776 // In first, from EXIF date & time tags, or 0777 // In second, from IPTC date & time tags. 0778 0779 datetime = metadata->getItemDateTime(); 0780 0781 if (!datetime.isValid()) 0782 { 0783 QFileInfo info(filePath); 0784 datetime = info.lastModified(); 0785 } 0786 0787 access.db()->setItemDate(albumID, fileName, datetime); 0788 } 0789 0790 #endif // 0 0791 0792 } // namespace Digikam