File indexing completed on 2025-01-19 03:59:31
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2012-01-31 0007 * Description : maintenance manager 0008 * 0009 * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2012 by Andi Clemens <andi dot clemens at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "maintenancemngr.h" 0017 0018 // Qt includes 0019 0020 #include <QString> 0021 #include <QElapsedTimer> 0022 #include <QApplication> 0023 0024 // KDE includes 0025 0026 #include <klocalizedstring.h> 0027 0028 // Local includes 0029 0030 #include "digikam_debug.h" 0031 #include "digikam_config.h" 0032 #include "albummanager.h" 0033 #include "applicationsettings.h" 0034 #include "maintenancesettings.h" 0035 #include "newitemsfinder.h" 0036 #include "thumbsgenerator.h" 0037 #include "fingerprintsgenerator.h" 0038 #include "duplicatesfinder.h" 0039 #include "autotagsassignment.h" 0040 #include "imagequalitysorter.h" 0041 #include "metadatasynchronizer.h" 0042 #include "dnotificationwrapper.h" 0043 #include "progressmanager.h" 0044 #include "facesdetector.h" 0045 #include "dbcleaner.h" 0046 0047 namespace Digikam 0048 { 0049 0050 class Q_DECL_HIDDEN MaintenanceMngr::Private 0051 { 0052 public: 0053 0054 Private() = default; 0055 0056 public: 0057 0058 bool running = false; 0059 0060 QElapsedTimer duration; 0061 0062 MaintenanceSettings settings; 0063 0064 NewItemsFinder* newItemsFinder = nullptr; 0065 ThumbsGenerator* thumbsGenerator = nullptr; 0066 FingerPrintsGenerator* fingerPrintsGenerator = nullptr; 0067 DuplicatesFinder* duplicatesFinder = nullptr; 0068 MetadataSynchronizer* metadataSynchronizer = nullptr; 0069 AutotagsAssignment* autotagsAssignment = nullptr; 0070 ImageQualitySorter* imageQualitySorter = nullptr; 0071 FacesDetector* facesDetector = nullptr; 0072 DbCleaner* databaseCleaner = nullptr; 0073 }; 0074 0075 MaintenanceMngr::MaintenanceMngr(QObject* const parent) 0076 : QObject(parent), 0077 d(new Private) 0078 { 0079 connect(ProgressManager::instance(), SIGNAL(progressItemCompleted(ProgressItem*)), 0080 this, SLOT(slotToolCompleted(ProgressItem*))); 0081 0082 connect(ProgressManager::instance(), SIGNAL(progressItemCanceled(ProgressItem*)), 0083 this, SLOT(slotToolCanceled(ProgressItem*))); 0084 } 0085 0086 MaintenanceMngr::~MaintenanceMngr() 0087 { 0088 delete d; 0089 } 0090 0091 bool MaintenanceMngr::isRunning() const 0092 { 0093 return d->running; 0094 } 0095 0096 void MaintenanceMngr::setSettings(const MaintenanceSettings& settings) 0097 { 0098 d->settings = settings; 0099 qCDebug(DIGIKAM_GENERAL_LOG) << d->settings; 0100 0101 d->duration.start(); 0102 stage1(); 0103 } 0104 0105 void MaintenanceMngr::slotToolCompleted(ProgressItem* tool) 0106 { 0107 // At each stage, relevant tool instance is set to zero to prevent redondant call to this slot 0108 // from ProgressManager. This will disable multiple triggering in this method. 0109 // There is no memory leak. Each tool instance are delete later by ProgressManager. 0110 0111 if (tool == dynamic_cast<ProgressItem*>(d->newItemsFinder)) 0112 { 0113 d->newItemsFinder = nullptr; 0114 0115 // Update albums and tags for the other tools 0116 0117 if (d->settings.wholeAlbums) 0118 { 0119 d->settings.albums = AlbumManager::instance()->allPAlbums(); 0120 } 0121 0122 if (d->settings.wholeTags) 0123 { 0124 d->settings.tags = AlbumManager::instance()->allTAlbums(); 0125 } 0126 0127 stage2(); 0128 } 0129 else if (tool == dynamic_cast<ProgressItem*>(d->databaseCleaner)) 0130 { 0131 d->databaseCleaner = nullptr; 0132 stage3(); 0133 } 0134 else if (tool == dynamic_cast<ProgressItem*>(d->thumbsGenerator)) 0135 { 0136 d->thumbsGenerator = nullptr; 0137 stage4(); 0138 } 0139 else if (tool == dynamic_cast<ProgressItem*>(d->fingerPrintsGenerator)) 0140 { 0141 d->fingerPrintsGenerator = nullptr; 0142 stage5(); 0143 } 0144 else if (tool == dynamic_cast<ProgressItem*>(d->duplicatesFinder)) 0145 { 0146 d->duplicatesFinder = nullptr; 0147 stage6(); 0148 } 0149 else if (tool == dynamic_cast<ProgressItem*>(d->facesDetector)) 0150 { 0151 d->facesDetector = nullptr; 0152 stage7(); 0153 } 0154 else if(tool == dynamic_cast<ProgressItem*>(d->autotagsAssignment)) 0155 { 0156 d->autotagsAssignment = nullptr; 0157 stage8(); 0158 } 0159 else if (tool == dynamic_cast<ProgressItem*>(d->imageQualitySorter)) 0160 { 0161 d->imageQualitySorter = nullptr; 0162 stage9(); 0163 } 0164 else if (tool == dynamic_cast<ProgressItem*>(d->metadataSynchronizer)) 0165 { 0166 d->metadataSynchronizer = nullptr; 0167 done(); 0168 } 0169 } 0170 0171 void MaintenanceMngr::slotToolCanceled(ProgressItem* tool) 0172 { 0173 if ((tool == dynamic_cast<ProgressItem*>(d->newItemsFinder)) || 0174 (tool == dynamic_cast<ProgressItem*>(d->thumbsGenerator)) || 0175 (tool == dynamic_cast<ProgressItem*>(d->fingerPrintsGenerator)) || 0176 (tool == dynamic_cast<ProgressItem*>(d->duplicatesFinder)) || 0177 (tool == dynamic_cast<ProgressItem*>(d->databaseCleaner)) || 0178 (tool == dynamic_cast<ProgressItem*>(d->facesDetector)) || 0179 (tool == dynamic_cast<ProgressItem*>(d->imageQualitySorter)) || 0180 (tool == dynamic_cast<ProgressItem*>(d->metadataSynchronizer)) || 0181 (tool == dynamic_cast<ProgressItem*>(d->autotagsAssignment))) 0182 { 0183 cancel(); 0184 } 0185 } 0186 0187 void MaintenanceMngr::stage1() 0188 { 0189 qCDebug(DIGIKAM_GENERAL_LOG) << "stage1"; 0190 0191 if (d->settings.newItems) 0192 { 0193 if (d->settings.wholeAlbums) 0194 { 0195 d->newItemsFinder = new NewItemsFinder(); 0196 } 0197 else 0198 { 0199 QStringList paths; 0200 0201 Q_FOREACH (Album* const a, d->settings.albums) 0202 { 0203 PAlbum* const palbum = dynamic_cast<PAlbum*>(a); 0204 0205 if (palbum) 0206 { 0207 paths << palbum->folderPath(); 0208 } 0209 } 0210 0211 d->newItemsFinder = new NewItemsFinder(NewItemsFinder::ScheduleCollectionScan, paths); 0212 } 0213 0214 d->newItemsFinder->setNotificationEnabled(false); 0215 d->newItemsFinder->start(); 0216 } 0217 else 0218 { 0219 stage2(); 0220 } 0221 } 0222 0223 void MaintenanceMngr::stage2() 0224 { 0225 qCDebug(DIGIKAM_GENERAL_LOG) << "stage2"; 0226 0227 if (d->settings.databaseCleanup) 0228 { 0229 d->databaseCleaner = new DbCleaner(d->settings.cleanThumbDb, 0230 d->settings.cleanFacesDb, 0231 d->settings.cleanSimilarityDb, 0232 d->settings.shrinkDatabases); 0233 d->databaseCleaner->setNotificationEnabled(false); 0234 d->databaseCleaner->setUseMultiCoreCPU(d->settings.useMutiCoreCPU); 0235 d->databaseCleaner->start(); 0236 } 0237 else 0238 { 0239 stage3(); 0240 } 0241 } 0242 0243 void MaintenanceMngr::stage3() 0244 { 0245 qCDebug(DIGIKAM_GENERAL_LOG) << "stage3"; 0246 0247 if (d->settings.thumbnails) 0248 { 0249 bool rebuildAll = (d->settings.scanThumbs == false); 0250 AlbumList list; 0251 list << d->settings.albums; 0252 list << d->settings.tags; 0253 0254 d->thumbsGenerator = new ThumbsGenerator(rebuildAll, list); 0255 d->thumbsGenerator->setNotificationEnabled(false); 0256 d->thumbsGenerator->setUseMultiCoreCPU(d->settings.useMutiCoreCPU); 0257 d->thumbsGenerator->start(); 0258 } 0259 else 0260 { 0261 stage4(); 0262 } 0263 } 0264 0265 void MaintenanceMngr::stage4() 0266 { 0267 qCDebug(DIGIKAM_GENERAL_LOG) << "stage4"; 0268 0269 if (d->settings.fingerPrints) 0270 { 0271 bool rebuildAll = (d->settings.scanFingerPrints == false); 0272 AlbumList list; 0273 list << d->settings.albums; 0274 list << d->settings.tags; 0275 0276 d->fingerPrintsGenerator = new FingerPrintsGenerator(rebuildAll, list); 0277 d->fingerPrintsGenerator->setNotificationEnabled(false); 0278 d->fingerPrintsGenerator->setUseMultiCoreCPU(d->settings.useMutiCoreCPU); 0279 d->fingerPrintsGenerator->start(); 0280 } 0281 else 0282 { 0283 stage5(); 0284 } 0285 } 0286 0287 void MaintenanceMngr::stage5() 0288 { 0289 qCDebug(DIGIKAM_GENERAL_LOG) << "stage5"; 0290 0291 if (d->settings.duplicates) 0292 { 0293 d->duplicatesFinder = new DuplicatesFinder(d->settings.albums, d->settings.tags, (int)HaarIface::AlbumTagRelation::NoMix, 0294 d->settings.minSimilarity, d->settings.maxSimilarity,(int)d->settings.duplicatesRestriction); 0295 d->duplicatesFinder->setNotificationEnabled(false); 0296 d->duplicatesFinder->start(); 0297 } 0298 else 0299 { 0300 stage6(); 0301 } 0302 } 0303 0304 void MaintenanceMngr::stage6() 0305 { 0306 qCDebug(DIGIKAM_GENERAL_LOG) << "stage6"; 0307 0308 if (d->settings.faceManagement) 0309 { 0310 // NOTE : Use multi-core CPU option is passed through FaceScanSettings 0311 d->settings.faceSettings.wholeAlbums = d->settings.wholeAlbums; 0312 d->settings.faceSettings.useFullCpu = d->settings.useMutiCoreCPU; 0313 d->settings.faceSettings.useYoloV3 = ApplicationSettings::instance()->getFaceDetectionYoloV3(); 0314 d->settings.faceSettings.accuracy = ApplicationSettings::instance()->getFaceDetectionAccuracy(); 0315 d->facesDetector = new FacesDetector(d->settings.faceSettings); 0316 d->facesDetector->setNotificationEnabled(false); 0317 d->facesDetector->start(); 0318 } 0319 else 0320 { 0321 stage7(); 0322 } 0323 } 0324 0325 void MaintenanceMngr::stage7() 0326 { 0327 qCDebug(DIGIKAM_GENERAL_LOG) << "stage7"; 0328 0329 if (d->settings.autotagsAssignment) 0330 { 0331 AlbumList list; 0332 list << d->settings.albums; 0333 list << d->settings.tags; 0334 0335 d->autotagsAssignment = new AutotagsAssignment((AutotagsAssignment::AutotagsAssignmentScanMode)d->settings.autotaggingScanMode, list, d->settings.modelSelectionMode); 0336 d->autotagsAssignment->setNotificationEnabled(false); 0337 d->autotagsAssignment->setUseMultiCoreCPU(d->settings.useMutiCoreCPU); 0338 d->autotagsAssignment->start(); 0339 } 0340 else 0341 { 0342 stage8(); 0343 } 0344 } 0345 0346 void MaintenanceMngr::stage8() 0347 { 0348 qCDebug(DIGIKAM_GENERAL_LOG) << "stage8"; 0349 0350 if (d->settings.qualitySort) 0351 { 0352 AlbumList list; 0353 list << d->settings.albums; 0354 list << d->settings.tags; 0355 0356 d->imageQualitySorter = new ImageQualitySorter((ImageQualitySorter::QualityScanMode)d->settings.qualityScanMode, list, d->settings.quality); 0357 d->imageQualitySorter->setNotificationEnabled(false); 0358 d->imageQualitySorter->setUseMultiCoreCPU(d->settings.useMutiCoreCPU); 0359 d->imageQualitySorter->start(); 0360 } 0361 else 0362 { 0363 stage9(); 0364 } 0365 } 0366 0367 void MaintenanceMngr::stage9() 0368 { 0369 qCDebug(DIGIKAM_GENERAL_LOG) << "stage9"; 0370 0371 if (d->settings.metadataSync) 0372 { 0373 AlbumList list; 0374 list << d->settings.albums; 0375 list << d->settings.tags; 0376 d->metadataSynchronizer = new MetadataSynchronizer(list, MetadataSynchronizer::SyncDirection(d->settings.syncDirection)); 0377 d->metadataSynchronizer->setNotificationEnabled(false); 0378 // See Bug #329091 : Multicore CPU support with Exiv2 sound problematic, even with 0.25 release. 0379 d->metadataSynchronizer->setUseMultiCoreCPU(false); 0380 d->metadataSynchronizer->start(); 0381 } 0382 else 0383 { 0384 done(); 0385 } 0386 } 0387 0388 void MaintenanceMngr::done() 0389 { 0390 d->running = false; 0391 QTime t = QTime::fromMSecsSinceStartOfDay(d->duration.elapsed()); 0392 0393 // Pop-up a message to bring user when all is done. 0394 DNotificationWrapper(QLatin1String("digiKam Maintenance"), // not i18n 0395 i18n("All operations are done.\nDuration: %1", t.toString()), 0396 qApp->activeWindow(), i18n("digiKam Maintenance")); 0397 0398 Q_EMIT signalComplete(); 0399 } 0400 0401 void MaintenanceMngr::cancel() 0402 { 0403 d->running = false; 0404 Q_EMIT signalComplete(); 0405 } 0406 0407 } // namespace Digikam 0408 0409 #include "moc_maintenancemngr.cpp"