File indexing completed on 2025-01-05 03:54:17

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-10-28
0007  * Description : scan item controller - start operations.
0008  *
0009  * SPDX-FileCopyrightText: 2005-2006 by Tom Albers <tomalbers at kde dot nl>
0010  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2007-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "scancontroller_p.h"
0018 
0019 namespace Digikam
0020 {
0021 
0022 void ScanController::restart()
0023 {
0024     if (isRunning())
0025     {
0026         return;
0027     }
0028 
0029     d->running       = true;
0030     d->scanSuspended = 0;
0031     start();
0032 }
0033 
0034 ScanController::Advice ScanController::databaseInitialization()
0035 {
0036     d->advice = Success;
0037     createProgressDialog();
0038     setInitializationMessage();
0039 
0040     {
0041         QMutexLocker lock(&d->mutex);
0042         d->needsInitialization = true;
0043         d->condVar.wakeAll();
0044     }
0045 
0046     // NOTE: loop is quit by signal
0047 
0048     d->eventLoop->exec();
0049 
0050     // setup file watch service for LoadingCache - now that we are sure we have a CoreDbWatch
0051 
0052     if (!d->fileWatchInstalled)
0053     {
0054         d->fileWatchInstalled     = true; // once per application lifetime only
0055         LoadingCache* const cache = LoadingCache::cache();
0056         LoadingCache::CacheLock lock(cache);
0057         cache->setFileWatch(new ScanControllerLoadingCacheFileWatch);
0058     }
0059 
0060     delete d->progressDialog;
0061     d->progressDialog = nullptr;
0062 
0063     return d->advice;
0064 }
0065 
0066 void ScanController::completeCollectionScanDeferFiles()
0067 {
0068     completeCollectionScan(true);
0069 }
0070 
0071 void ScanController::completeCollectionScan(bool defer)
0072 {
0073     createProgressDialog();
0074 
0075     // we only need to count the files in advance
0076     // if we show a progress percentage in progress dialog
0077 
0078     completeCollectionScanCore(!CollectionScanner::databaseInitialScanDone(), defer, false);
0079 
0080     delete d->progressDialog;
0081     d->progressDialog = nullptr;
0082 }
0083 
0084 void ScanController::completeCollectionScanInBackground(bool defer, bool fastScan)
0085 {
0086     completeCollectionScanCore(true, defer, fastScan);
0087 }
0088 
0089 void ScanController::completeCollectionScanCore(bool needTotalFiles, bool defer, bool fastScan)
0090 {
0091     d->performFastScan = fastScan;
0092     d->needTotalFiles  = needTotalFiles;
0093 
0094     {
0095         QMutexLocker lock(&d->mutex);
0096         d->needsCompleteScan = true;
0097         d->deferFileScanning = defer;
0098         d->condVar.wakeAll();
0099     }
0100 
0101     // NOTE: loop is quit by signal
0102 
0103     d->eventLoop->exec();
0104 
0105     d->needTotalFiles  = false;
0106     d->performFastScan = true;
0107 }
0108 
0109 void ScanController::scheduleCollectionScan(const QString& path)
0110 {
0111     QMutexLocker lock(&d->mutex);
0112 
0113     if (!d->scanTasks.contains(path))
0114     {
0115         d->scanTasks << path;
0116     }
0117 
0118     d->condVar.wakeAll();
0119 }
0120 
0121 void ScanController::scheduleCollectionScanRelaxed(const QString& path)
0122 {
0123     if (!d->relaxedTimer->isActive())
0124     {
0125         d->relaxedTimer->start();
0126     }
0127 
0128     QMutexLocker lock(&d->mutex);
0129 
0130     if (!d->scanTasks.contains(path))
0131     {
0132         d->scanTasks << path;
0133     }
0134 }
0135 
0136 void ScanController::scheduleCollectionScanExternal(const QString& path)
0137 {
0138     d->externalTimer->start();
0139 
0140     QMutexLocker lock(&d->mutex);
0141 
0142     if (!d->scanTasks.contains(path))
0143     {
0144         d->scanTasks << path;
0145     }
0146 }
0147 
0148 void ScanController::scanFileDirectly(const QString& filePath)
0149 {
0150     suspendCollectionScan();
0151 
0152     CollectionScanner scanner;
0153     scanner.setHintContainer(d->hints);
0154     scanner.scanFile(filePath);
0155 
0156     resumeCollectionScan();
0157 }
0158 
0159 void ScanController::scanFileDirectlyNormal(const ItemInfo& info)
0160 {
0161     CollectionScanner scanner;
0162     scanner.setHintContainer(d->hints);
0163     scanner.scanFile(info, CollectionScanner::NormalScan);
0164 }
0165 
0166 /*
0167 /// This variant shall be used when a new file is created which is a version
0168 /// of another image, and all relevant attributes shall be copied.
0169 void scanFileDirectlyCopyAttributes(const QString& filePath, qlonglong parentVersion);
0170 
0171 void ScanController::scanFileDirectlyCopyAttributes(const QString& filePath, qlonglong parentVersion)
0172 {
0173     suspendCollectionScan();
0174 
0175     CollectionScanner scanner;
0176     scanner.recordHints(d->itemHints);
0177     scanner.recordHints(d->itemChangeHints);
0178     qlonglong id = scanner.scanFile(filePath);
0179     ItemInfo dest(id), source(parentVersion);
0180     scanner.copyFileProperties(source, dest);
0181 
0182     resumeCollectionScan();
0183 }
0184 */
0185 
0186 void ScanController::resumeCollectionScan()
0187 {
0188     QMutexLocker lock(&d->mutex);
0189 
0190     if (d->scanSuspended)
0191     {
0192         d->scanSuspended--;
0193     }
0194 
0195     if (!d->scanSuspended)
0196     {
0197         d->condVar.wakeAll();
0198     }
0199 }
0200 
0201 void ScanController::restartCollectionScan()
0202 {
0203     QMutexLocker lock(&d->mutex);
0204 
0205     if (d->scanSuspended)
0206     {
0207         d->scanSuspended = 0;
0208         d->condVar.wakeAll();
0209     }
0210 }
0211 
0212 void ScanController::slotStartCompleteScan()
0213 {
0214     d->totalFilesToScan = 0;
0215     slotTriggerShowProgressDialog();
0216 
0217     QString message     = i18n("Preparing collection scan...");
0218 
0219     if (d->progressDialog)
0220     {
0221         d->progressDialog->addedAction(d->restartPixmap(), message);
0222     }
0223 }
0224 
0225 void ScanController::slotStartScanningAlbum(const QString& albumRoot, const QString& album)
0226 {
0227     Q_UNUSED(albumRoot);
0228 
0229     if (d->progressDialog)
0230     {
0231         d->progressDialog->addedAction(d->albumPixmap(), QLatin1Char(' ') + album);
0232     }
0233 }
0234 
0235 void ScanController::slotStartScanningAlbumRoot(const QString& albumRoot)
0236 {
0237     if (d->progressDialog)
0238     {
0239         d->progressDialog->addedAction(d->rootPixmap(), albumRoot);
0240     }
0241 }
0242 
0243 void ScanController::slotStartScanningForStaleAlbums()
0244 {
0245     QString message = i18n("Scanning for removed albums...");
0246 
0247     if (d->progressDialog)
0248     {
0249         d->progressDialog->addedAction(d->actionPixmap(), message);
0250     }
0251 }
0252 
0253 void ScanController::slotStartScanningAlbumRoots()
0254 {
0255     QString message = i18n("Scanning images in individual albums...");
0256 
0257     if (d->progressDialog)
0258     {
0259         d->progressDialog->addedAction(d->actionPixmap(), message);
0260     }
0261 }
0262 
0263 void ScanController::beginFileMetadataWrite(const ItemInfo& info)
0264 {
0265     {
0266         // throw in a lock to synchronize with all parallel writing
0267         FileReadLocker locker(info.filePath());
0268     }
0269 
0270     QFileInfo fi(info.filePath());
0271     d->hints->recordHint(ItemMetadataAdjustmentHint(info.id(),
0272                                                     ItemMetadataAdjustmentHint::AboutToEditMetadata,
0273                                                     fi.lastModified(),
0274                                                     fi.size()));
0275 }
0276 
0277 } // namespace Digikam