File indexing completed on 2025-01-19 03:53:31
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2015-06-01 0007 * Description : DB Jobs for listing and scanning 0008 * 0009 * SPDX-FileCopyrightText: 2015 by Mohamed_Anwer <m_dot_anwer at gmx dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "dbjob.h" 0016 0017 // Local includes 0018 0019 #include "coredbaccess.h" 0020 #include "dbengineparameters.h" 0021 #include "coredb.h" 0022 #include "facetags.h" 0023 #include "itemlister.h" 0024 #include "digikam_debug.h" 0025 #include "dbjobsthread.h" 0026 0027 namespace Digikam 0028 { 0029 0030 DBJob::DBJob() 0031 : ActionJob() 0032 { 0033 } 0034 0035 DBJob::~DBJob() 0036 { 0037 } 0038 0039 // ---------------------------------------------- 0040 0041 AlbumsJob::AlbumsJob(const AlbumsDBJobInfo& jobInfo) 0042 : DBJob (), 0043 m_jobInfo(jobInfo) 0044 { 0045 } 0046 0047 AlbumsJob::~AlbumsJob() 0048 { 0049 } 0050 0051 void AlbumsJob::run() 0052 { 0053 if (m_jobInfo.isFoldersJob()) 0054 { 0055 const QHash<int, int>& albumNumberHash = CoreDbAccess().db()->getNumberOfImagesInAlbums(); 0056 0057 Q_EMIT foldersData(albumNumberHash); 0058 } 0059 else 0060 { 0061 ItemLister lister; 0062 lister.setRecursive(m_jobInfo.isRecursive()); 0063 lister.setListOnlyAvailable(m_jobInfo.isListAvailableImagesOnly()); 0064 0065 // Send data every 200 images to be more responsive 0066 0067 ItemListerJobGrowingPartsSendingReceiver receiver(this, 200, 2000, 100); 0068 lister.listPAlbum(&receiver, m_jobInfo.albumRootId(), m_jobInfo.album()); 0069 receiver.sendData(); 0070 } 0071 0072 Q_EMIT signalDone(); 0073 } 0074 0075 // ---------------------------------------------- 0076 0077 DatesJob::DatesJob(const DatesDBJobInfo& jobInfo) 0078 : DBJob (), 0079 m_jobInfo(jobInfo) 0080 { 0081 } 0082 0083 DatesJob::~DatesJob() 0084 { 0085 } 0086 0087 void DatesJob::run() 0088 { 0089 if (m_jobInfo.isFoldersJob()) 0090 { 0091 const QVariantList& values = CoreDbAccess().db()->getAllCreationDates(); 0092 0093 QHash<QDateTime, int> dateNumberHash; 0094 QHash<QDateTime, int>::iterator it; 0095 0096 Q_FOREACH (const QVariant& value, values) 0097 { 0098 if (!value.isNull()) 0099 { 0100 QDateTime dateTime = value.toDateTime(); 0101 dateTime.setTimeSpec(Qt::UTC); 0102 0103 if (!dateTime.isValid()) 0104 { 0105 continue; 0106 } 0107 0108 it = dateNumberHash.find(dateTime); 0109 0110 if (it == dateNumberHash.end()) 0111 { 0112 dateNumberHash.insert(dateTime, 1); 0113 } 0114 else 0115 { 0116 it.value()++; 0117 } 0118 } 0119 } 0120 0121 Q_EMIT foldersData(dateNumberHash); 0122 } 0123 else 0124 { 0125 ItemLister lister; 0126 lister.setListOnlyAvailable(m_jobInfo.isListAvailableImagesOnly()); 0127 0128 // Send data every 200 images to be more responsive 0129 0130 ItemListerJobPartsSendingReceiver receiver(this, 200); 0131 lister.listDateRange(&receiver, m_jobInfo.startDate(), m_jobInfo.endDate()); 0132 0133 // Send rest 0134 0135 receiver.sendData(); 0136 } 0137 0138 Q_EMIT signalDone(); 0139 } 0140 0141 // ---------------------------------------------- 0142 0143 GPSJob::GPSJob(const GPSDBJobInfo& jobInfo) 0144 : DBJob (), 0145 m_jobInfo(jobInfo) 0146 { 0147 } 0148 0149 GPSJob::~GPSJob() 0150 { 0151 } 0152 0153 void GPSJob::run() 0154 { 0155 if (m_jobInfo.isDirectQuery()) 0156 { 0157 QList<QVariant> imagesInfoFromArea = 0158 CoreDbAccess().db()->getImageIdsFromArea(m_jobInfo.lat1(), 0159 m_jobInfo.lat2(), 0160 m_jobInfo.lng1(), 0161 m_jobInfo.lng2(), 0162 0, 0163 QLatin1String("rating")); 0164 0165 Q_EMIT directQueryData(imagesInfoFromArea); 0166 } 0167 else 0168 { 0169 ItemLister lister; 0170 lister.setListOnlyAvailable(m_jobInfo.isListAvailableImagesOnly()); 0171 0172 // Send data every 200 images to be more responsive 0173 0174 ItemListerJobPartsSendingReceiver receiver(this, 200); 0175 lister.listAreaRange(&receiver, 0176 m_jobInfo.lat1(), 0177 m_jobInfo.lat2(), 0178 m_jobInfo.lng1(), 0179 m_jobInfo.lng2()); 0180 // send rest 0181 0182 receiver.sendData(); 0183 } 0184 0185 Q_EMIT signalDone(); 0186 } 0187 0188 // ---------------------------------------------- 0189 0190 TagsJob::TagsJob(const TagsDBJobInfo& jobInfo) 0191 : DBJob (), 0192 m_jobInfo(jobInfo) 0193 { 0194 } 0195 0196 TagsJob::~TagsJob() 0197 { 0198 } 0199 0200 void TagsJob::run() 0201 { 0202 if (m_jobInfo.isFoldersJob()) 0203 { 0204 const QHash<int, int>& tagNumberHash = CoreDbAccess().db()->getNumberOfImagesInTags(); 0205 0206 //qCDebug(DIGIKAM_DBJOB_LOG) << tagNumberHash; 0207 0208 Q_EMIT foldersData(tagNumberHash); 0209 } 0210 else if (m_jobInfo.isFaceFoldersJob()) 0211 { 0212 QString property; 0213 QHash<int, int> counts; 0214 QMap<QString, QHash<int, int> > facesNumberMap; 0215 0216 property = ImageTagPropertyName::autodetectedFace(); 0217 counts = CoreDbAccess().db()->getNumberOfImagesInTagProperties(property); 0218 0219 if (!counts.contains(FaceTags::unknownPersonTagId())) 0220 { 0221 counts[FaceTags::unknownPersonTagId()] = 0; 0222 } 0223 0224 facesNumberMap.insert(property, counts); 0225 0226 property = ImageTagPropertyName::autodetectedPerson(); 0227 counts = CoreDbAccess().db()->getNumberOfImagesInTagProperties(property); 0228 0229 facesNumberMap.insert(property, counts); 0230 0231 property = ImageTagPropertyName::ignoredFace(); 0232 counts = CoreDbAccess().db()->getNumberOfImagesInTagProperties(property); 0233 0234 facesNumberMap.insert(property, counts); 0235 0236 property = ImageTagPropertyName::tagRegion(); 0237 counts = CoreDbAccess().db()->getNumberOfImagesInTagProperties(property); 0238 0239 Q_FOREACH (int tagId, FaceTags::allPersonTags()) 0240 { 0241 if (!counts.contains(tagId)) 0242 { 0243 counts[tagId] = 0; 0244 } 0245 } 0246 0247 facesNumberMap.insert(property, counts); 0248 0249 Q_EMIT faceFoldersData(facesNumberMap); 0250 } 0251 else 0252 { 0253 ItemLister lister; 0254 lister.setRecursive(m_jobInfo.isRecursive()); 0255 lister.setListOnlyAvailable(m_jobInfo.isListAvailableImagesOnly()); 0256 0257 // Send data every 200 images to be more responsive 0258 0259 ItemListerJobPartsSendingReceiver receiver(this, 200); 0260 0261 if (!m_jobInfo.specialTag().isNull()) 0262 { 0263 QString searchXml = lister.tagSearchXml(m_jobInfo.tagsIds().constFirst(), 0264 m_jobInfo.specialTag(), 0265 m_jobInfo.isRecursive()); 0266 lister.listImageTagPropertySearch(&receiver, searchXml); 0267 } 0268 else 0269 { 0270 lister.listTag(&receiver, m_jobInfo.tagsIds()); 0271 } 0272 0273 // Finish sending 0274 0275 receiver.sendData(); 0276 } 0277 0278 Q_EMIT signalDone(); 0279 } 0280 0281 // ---------------------------------------------- 0282 0283 SearchesJob::SearchesJob(const SearchesDBJobInfo& jobInfo) 0284 : DBJob (), 0285 m_jobInfo(jobInfo), 0286 m_iface (nullptr) 0287 { 0288 } 0289 0290 SearchesJob::SearchesJob(const SearchesDBJobInfo& jobInfo, 0291 const QSet<qlonglong>::const_iterator& begin, 0292 const QSet<qlonglong>::const_iterator& end, 0293 HaarIface* iface) 0294 : DBJob (), 0295 m_jobInfo(jobInfo), 0296 m_begin (begin), 0297 m_end (end), 0298 m_iface (iface) 0299 { 0300 } 0301 0302 SearchesJob::~SearchesJob() 0303 { 0304 } 0305 0306 void SearchesJob::run() 0307 { 0308 m_jobInfo.isDuplicatesJob() ? runFindDuplicates() : runSearches(); 0309 } 0310 0311 void SearchesJob::runSearches() 0312 { 0313 QList<SearchInfo> infos; 0314 0315 Q_FOREACH (int id, m_jobInfo.searchIds()) 0316 { 0317 infos << CoreDbAccess().db()->getSearchInfo(id); 0318 } 0319 0320 ItemLister lister; 0321 lister.setListOnlyAvailable(m_jobInfo.isListAvailableImagesOnly()); 0322 0323 // Send data every 200 images to be more responsive 0324 0325 ItemListerJobPartsSendingReceiver receiver(this, 200); 0326 0327 Q_FOREACH (const SearchInfo& info, infos) 0328 { 0329 if (info.type == DatabaseSearch::HaarSearch) 0330 { 0331 lister.listHaarSearch(&receiver, info.query); 0332 } 0333 else 0334 { 0335 bool ok; 0336 qlonglong referenceImageId = info.name.toLongLong(&ok); 0337 0338 if (ok) 0339 { 0340 lister.listSearch(&receiver, info.query, 0, referenceImageId); 0341 } 0342 else 0343 { 0344 lister.listSearch(&receiver, info.query, 0, -1); 0345 } 0346 } 0347 0348 if (!receiver.hasError) 0349 { 0350 receiver.sendData(); 0351 } 0352 } 0353 0354 Q_EMIT signalDone(); 0355 } 0356 0357 void SearchesJob::runFindDuplicates() 0358 { 0359 if (m_jobInfo.imageIds().isEmpty()) 0360 { 0361 qCDebug(DIGIKAM_DBJOB_LOG) << "No image ids passed for duplicates search"; 0362 0363 Q_EMIT signalDuplicatesResults(HaarIface::DuplicatesResultsMap()); 0364 return; 0365 } 0366 0367 DuplicatesProgressObserver observer(this); 0368 0369 if (!m_iface) 0370 { 0371 qCDebug(DIGIKAM_DBJOB_LOG) << "Invalid HaarIface pointer"; 0372 0373 Q_EMIT signalDuplicatesResults(HaarIface::DuplicatesResultsMap()); 0374 return; 0375 } 0376 0377 auto restriction = static_cast<HaarIface::DuplicatesSearchRestrictions>(m_jobInfo.searchResultRestriction()); 0378 auto results = m_iface->findDuplicates(m_jobInfo.imageIds(), 0379 m_begin, 0380 m_end, 0381 m_jobInfo.refImageSelectionMethod(), 0382 m_jobInfo.refImageIds(), 0383 m_jobInfo.minThreshold(), 0384 m_jobInfo.maxThreshold(), 0385 restriction, 0386 &observer); 0387 0388 Q_EMIT signalDuplicatesResults(results); 0389 } 0390 0391 bool SearchesJob::isCanceled() const 0392 { 0393 return m_cancel; 0394 } 0395 0396 } // namespace Digikam 0397 0398 #include "moc_dbjob.cpp"