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 : 2013-08-09 0007 * Description : Thread actions manager for maintenance tools. 0008 * 0009 * SPDX-FileCopyrightText: 2013-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2017-2018 by Mario Frank <mario dot frank at uni minus potsdam dot de> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "maintenancethread.h" 0017 0018 // Qt includes 0019 0020 #include <QQueue> 0021 #include <QMutex> 0022 0023 // Local includes 0024 0025 #include "digikam_debug.h" 0026 #include "thumbstask.h" 0027 #include "metadatasynctask.h" 0028 #include "fingerprintstask.h" 0029 #include "autotagsassignmentask.h" 0030 #include "imagequalitytask.h" 0031 #include "imagequalitycontainer.h" 0032 #include "databasetask.h" 0033 #include "maintenancedata.h" 0034 #include "imagequalityparser.h" 0035 #include "metadataremovetask.h" 0036 0037 namespace Digikam 0038 { 0039 0040 MaintenanceThread::MaintenanceThread(QObject* const parent) 0041 : ActionThreadBase(parent), 0042 data(new MaintenanceData) 0043 { 0044 setObjectName(QLatin1String("MaintenanceThread")); 0045 0046 connect(this, SIGNAL(finished()), 0047 this, SLOT(slotThreadFinished())); 0048 } 0049 0050 MaintenanceThread::~MaintenanceThread() 0051 { 0052 cancel(); 0053 wait(); 0054 delete data; 0055 } 0056 0057 void MaintenanceThread::setUseMultiCore(const bool b) 0058 { 0059 if (!b) 0060 { 0061 setMaximumNumberOfThreads(1); 0062 } 0063 else 0064 { 0065 setDefaultMaximumNumberOfThreads(); 0066 //setMaximumNumberOfThreads(qMax( maximumNumberOfThreads() / 2, 1)); 0067 } 0068 } 0069 0070 void MaintenanceThread::syncMetadata(const ItemInfoList& items, MetadataSynchronizer::SyncDirection dir, bool tagsOnly) 0071 { 0072 ActionJobCollection collection; 0073 0074 data->setItemInfos(items); 0075 0076 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0077 { 0078 MetadataSyncTask* const t = new MetadataSyncTask(); 0079 t->setTagsOnly(tagsOnly); 0080 t->setDirection(dir); 0081 t->setMaintenanceData(data); 0082 0083 connect(t, SIGNAL(signalFinished(QImage)), 0084 this, SIGNAL(signalAdvance(QImage))); 0085 0086 collection.insert(t, 0); 0087 0088 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a metadata task for synchronizing metadata"; 0089 } 0090 0091 appendJobs(collection); 0092 } 0093 0094 void MaintenanceThread::removeMetadata(const ItemInfoList& items, MetadataRemover::RemoveAction action) 0095 { 0096 ActionJobCollection collection; 0097 0098 data->setItemInfos(items); 0099 0100 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0101 { 0102 MetadataRemoveTask* const t = new MetadataRemoveTask(); 0103 t->setRemoveAction(action); 0104 t->setMaintenanceData(data); 0105 0106 connect(t, SIGNAL(signalFinished(QImage)), 0107 this, SIGNAL(signalAdvance(QImage))); 0108 0109 collection.insert(t, 0); 0110 0111 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a remover task for removing metadata"; 0112 } 0113 0114 appendJobs(collection); 0115 } 0116 0117 void MaintenanceThread::generateThumbs(const QStringList& paths) 0118 { 0119 ActionJobCollection collection; 0120 0121 data->setImagePaths(paths); 0122 0123 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0124 { 0125 ThumbsTask* const t = new ThumbsTask(); 0126 0127 t->setMaintenanceData(data); 0128 0129 connect(t, SIGNAL(signalFinished(QImage)), 0130 this, SIGNAL(signalAdvance(QImage))); 0131 0132 collection.insert(t, 0); 0133 0134 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a thumbnails task for generating thumbnails"; 0135 } 0136 0137 appendJobs(collection); 0138 } 0139 0140 void MaintenanceThread::generateFingerprints(const QList<qlonglong>& itemIds, bool rebuildAll) 0141 { 0142 ActionJobCollection collection; 0143 0144 data->setImageIds(itemIds); 0145 data->setRebuildAllFingerprints(rebuildAll); 0146 0147 for (int i = 1 ; i <= (maximumNumberOfThreads()) ; ++i) 0148 { 0149 FingerprintsTask* const t = new FingerprintsTask(); 0150 0151 t->setMaintenanceData(data); 0152 0153 connect(t, SIGNAL(signalFinished(QImage)), 0154 this, SIGNAL(signalAdvance(QImage))); 0155 0156 collection.insert(t, 0); 0157 0158 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a fingerprints task for generating fingerprints"; 0159 } 0160 0161 appendJobs(collection); 0162 } 0163 0164 void MaintenanceThread::generateTags(const QStringList& paths, int modelType) 0165 { 0166 ActionJobCollection collection; 0167 0168 data->setImagePaths(paths); 0169 0170 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0171 { 0172 AutotagsAssignmentTask* const t = new AutotagsAssignmentTask(); 0173 0174 t->setMaintenanceData(data); 0175 t->setModelType(modelType); 0176 0177 connect(t, SIGNAL(signalFinished(QImage)), 0178 this, SIGNAL(signalAdvance(QImage))); 0179 0180 collection.insert(t, 0); 0181 0182 qCDebug(DIGIKAM_AUTOTAGSENGINE_LOG) << "Creating an autotagging task for autotags assignment items"; 0183 } 0184 0185 appendJobs(collection); 0186 } 0187 0188 void MaintenanceThread::sortByImageQuality(const QStringList& paths, const ImageQualityContainer& quality) 0189 { 0190 ActionJobCollection collection; 0191 0192 data->setImagePaths(paths); 0193 0194 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0195 { 0196 ImageQualityTask* const t = new ImageQualityTask(); 0197 t->setQuality(quality); 0198 t->setMaintenanceData(data); 0199 0200 connect(t, SIGNAL(signalFinished(QImage)), 0201 this, SIGNAL(signalAdvance(QImage))); 0202 0203 connect(this, SIGNAL(signalCanceled()), 0204 t, SLOT(slotCancel()), Qt::QueuedConnection); 0205 0206 collection.insert(t, 0); 0207 0208 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a image quality task for sorting items."; 0209 } 0210 0211 appendJobs(collection); 0212 } 0213 0214 void MaintenanceThread::computeDatabaseJunk(bool thumbsDb, bool facesDb, bool similarityDb) 0215 { 0216 ActionJobCollection collection; 0217 0218 DatabaseTask* const t = new DatabaseTask(); 0219 t->setMode(DatabaseTask::Mode::ComputeDatabaseJunk); 0220 t->computeDatabaseJunk(thumbsDb, facesDb, similarityDb); 0221 0222 connect(t, SIGNAL(signalFinished()), 0223 this, SIGNAL(signalAdvance())); 0224 0225 connect(t, SIGNAL(signalAddItemsToProcess(int)), 0226 this, SIGNAL(signalAddItemsToProcess(int))); 0227 0228 connect(t, SIGNAL(signalData(QList<qlonglong>,QList<int>,QList<Identity>,QList<qlonglong>)), 0229 this, SIGNAL(signalData(QList<qlonglong>,QList<int>,QList<Identity>,QList<qlonglong>))); 0230 0231 collection.insert(t, 0); 0232 0233 appendJobs(collection); 0234 } 0235 0236 void MaintenanceThread::cleanCoreDb(const QList<qlonglong>& imageIds) 0237 { 0238 ActionJobCollection collection; 0239 0240 data->setImageIds(imageIds); 0241 0242 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0243 { 0244 DatabaseTask* const t = new DatabaseTask(); 0245 0246 t->setMaintenanceData(data); 0247 t->setMode(DatabaseTask::Mode::CleanCoreDb); 0248 0249 connect(t, SIGNAL(signalFinished()), 0250 this, SIGNAL(signalAdvance())); 0251 0252 collection.insert(t, 0); 0253 0254 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a database task for removing stale items."; 0255 } 0256 0257 appendJobs(collection); 0258 } 0259 0260 void MaintenanceThread::cleanThumbsDb(const QList<int>& thumbnailIds) 0261 { 0262 ActionJobCollection collection; 0263 0264 data->setThumbnailIds(thumbnailIds); 0265 0266 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0267 { 0268 DatabaseTask* const t = new DatabaseTask(); 0269 0270 t->setMaintenanceData(data); 0271 t->setMode(DatabaseTask::Mode::CleanThumbsDb); 0272 0273 connect(t, SIGNAL(signalFinished()), 0274 this, SIGNAL(signalAdvance())); 0275 0276 collection.insert(t, 0); 0277 0278 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a database task for removing stale thumbnails."; 0279 } 0280 0281 appendJobs(collection); 0282 } 0283 0284 void MaintenanceThread::cleanFacesDb(const QList<Identity>& staleIdentities) 0285 { 0286 ActionJobCollection collection; 0287 0288 data->setIdentities(staleIdentities); 0289 0290 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0291 { 0292 DatabaseTask* const t = new DatabaseTask(); 0293 0294 t->setMaintenanceData(data); 0295 t->setMode(DatabaseTask::Mode::CleanRecognitionDb); 0296 0297 connect(t, SIGNAL(signalFinished()), 0298 this, SIGNAL(signalAdvance())); 0299 0300 collection.insert(t, 0); 0301 0302 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a database task for removing stale identities."; 0303 } 0304 0305 appendJobs(collection); 0306 } 0307 0308 void MaintenanceThread::cleanSimilarityDb(const QList<qlonglong>& imageIds) 0309 { 0310 ActionJobCollection collection; 0311 0312 data->setSimilarityImageIds(imageIds); 0313 0314 for (int i = 1 ; i <= maximumNumberOfThreads() ; ++i) 0315 { 0316 DatabaseTask* const t = new DatabaseTask(); 0317 0318 t->setMaintenanceData(data); 0319 t->setMode(DatabaseTask::Mode::CleanSimilarityDb); 0320 0321 connect(t, SIGNAL(signalFinished()), 0322 this, SIGNAL(signalAdvance())); 0323 0324 collection.insert(t, 0); 0325 0326 qCDebug(DIGIKAM_GENERAL_LOG) << "Creating a database task for removing stale image id entries from similarity db."; 0327 } 0328 0329 appendJobs(collection); 0330 } 0331 0332 void MaintenanceThread::shrinkDatabases() 0333 { 0334 ActionJobCollection collection; 0335 0336 DatabaseTask* const t = new DatabaseTask(); 0337 t->setMode(DatabaseTask::Mode::ShrinkDatabases); 0338 0339 connect(t, SIGNAL(signalStarted()), 0340 this, SIGNAL(signalStarted())); 0341 0342 connect(t, SIGNAL(signalFinished(bool,bool)), 0343 this, SIGNAL(signalFinished(bool,bool))); 0344 0345 collection.insert(t, 0); 0346 0347 appendJobs(collection); 0348 } 0349 0350 void MaintenanceThread::cancel() 0351 { 0352 if (isRunning()) 0353 { 0354 Q_EMIT signalCanceled(); 0355 } 0356 0357 ActionThreadBase::cancel(); 0358 } 0359 0360 void MaintenanceThread::slotThreadFinished() 0361 { 0362 if (isEmpty()) 0363 { 0364 ImageQualityParser::unloadDLModel(); 0365 qCDebug(DIGIKAM_GENERAL_LOG) << "List of Pending Jobs is empty"; 0366 Q_EMIT signalCompleted(); 0367 } 0368 } 0369 0370 /* 0371 int MaintenanceThread::getChunkSize(int elementCount) 0372 { 0373 int chunkSize = elementCount; 0374 0375 if (maximumNumberOfThreads() > 1) 0376 { 0377 chunkSize = elementCount / (maximumNumberOfThreads() - 1); 0378 } 0379 0380 // add a factor to the chunk size (do it dynamically depending on free mem?) 0381 chunkSize = chunkSize * 0.5; 0382 0383 return chunkSize; 0384 } 0385 */ 0386 0387 } // namespace Digikam 0388 0389 #include "moc_maintenancethread.cpp"