File indexing completed on 2025-01-19 03:55:49
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2007-01-05 0007 * Description : Metadata handling 0008 * 0009 * SPDX-FileCopyrightText: 2007-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2007-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2014-2015 by Veaceslav Munteanu <veaceslav dot munteanu90 at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "metadatahub.h" 0018 0019 // Qt includes 0020 0021 #include <QFileInfo> 0022 #include <QMutex> 0023 #include <QScopedPointer> 0024 #include <QMutexLocker> 0025 0026 // Local includes 0027 0028 #include "digikam_debug.h" 0029 #include "coredbaccess.h" 0030 #include "coredbwatch.h" 0031 #include "iteminfo.h" 0032 #include "itemcomments.h" 0033 #include "itemposition.h" 0034 #include "template.h" 0035 #include "templatemanager.h" 0036 #include "applicationsettings.h" 0037 #include "itemattributeswatch.h" 0038 #include "tagscache.h" 0039 #include "facetagseditor.h" 0040 #include "metadatahubmngr.h" 0041 0042 #ifdef HAVE_KFILEMETADATA 0043 # include "baloowrap.h" 0044 #endif 0045 0046 namespace Digikam 0047 { 0048 0049 class Q_DECL_HIDDEN MetadataHub::Private 0050 { 0051 public: 0052 0053 explicit Private() 0054 : pickLabel (-1), 0055 colorLabel (-1), 0056 rating (-1), 0057 count (0), 0058 dateTimeStatus (MetadataHub::MetadataInvalid), 0059 titlesStatus (MetadataHub::MetadataInvalid), 0060 commentsStatus (MetadataHub::MetadataInvalid), 0061 pickLabelStatus (MetadataHub::MetadataInvalid), 0062 colorLabelStatus(MetadataHub::MetadataInvalid), 0063 ratingStatus (MetadataHub::MetadataInvalid), 0064 templateStatus (MetadataHub::MetadataInvalid) 0065 { 0066 } 0067 0068 public: 0069 0070 int pickLabel; 0071 int colorLabel; 0072 int rating; 0073 int count; 0074 0075 QDateTime dateTime; 0076 QPair<QSize, int> imageProp; 0077 0078 CaptionsMap titles; 0079 CaptionsMap comments; 0080 0081 Template metadataTemplate; 0082 0083 QMap<int, MetadataHub::Status> tags; 0084 0085 QStringList tagList; 0086 0087 QList<FaceTagsIface> facesList; 0088 ItemPosition itemPosition; 0089 0090 MetadataHub::Status dateTimeStatus; 0091 MetadataHub::Status titlesStatus; 0092 MetadataHub::Status commentsStatus; 0093 MetadataHub::Status pickLabelStatus; 0094 MetadataHub::Status colorLabelStatus; 0095 MetadataHub::Status ratingStatus; 0096 MetadataHub::Status templateStatus; 0097 0098 public: 0099 0100 template <class T> void loadSingleValue(const T& data, T& storage, MetadataHub::Status& status); 0101 }; 0102 0103 // ------------------------------------------------------------------------------------------ 0104 0105 MetadataHub::MetadataHub() 0106 : d(new Private) 0107 { 0108 } 0109 0110 MetadataHub::~MetadataHub() 0111 { 0112 delete d; 0113 } 0114 0115 void MetadataHub::reset() 0116 { 0117 (*d) = Private(); 0118 } 0119 0120 // -------------------------------------------------- 0121 0122 void MetadataHub::load(const ItemInfo& info) 0123 { 0124 d->count++; 0125 0126 //qCDebug(DIGIKAM_GENERAL_LOG) << "---------------------------------Load from ItemInfo ----------------"; 0127 0128 CaptionsMap commentMap; 0129 CaptionsMap titleMap; 0130 0131 { 0132 CoreDbAccess access; 0133 ItemComments comments = info.imageComments(access); 0134 commentMap = comments.toCaptionsMap(); 0135 titleMap = comments.toCaptionsMap(DatabaseComment::Title); 0136 } 0137 0138 load(info.dateTime(), 0139 titleMap, 0140 commentMap, 0141 info.colorLabel(), 0142 info.pickLabel(), 0143 info.rating(), 0144 info.metadataTemplate()); 0145 0146 QList<int> tagIds = info.tagIds(); 0147 loadTags(tagIds); 0148 loadFaceTags(info); 0149 0150 d->itemPosition = info.imagePosition(); 0151 } 0152 0153 /** 0154 * private common code to merge tags 0155 */ 0156 void MetadataHub::loadTags(const QList<int>& loadedTags) 0157 { 0158 d->tags.clear(); 0159 0160 Q_FOREACH (int tagId, loadedTags) 0161 { 0162 if (TagsCache::instance()->isInternalTag(tagId)) 0163 { 0164 continue; 0165 } 0166 0167 d->tags[tagId] = MetadataAvailable; 0168 } 0169 } 0170 0171 /** 0172 * private common code to load dateTime, comment, color label, pick label, rating 0173 */ 0174 void MetadataHub::load(const QDateTime& dateTime, 0175 const CaptionsMap& titles, 0176 const CaptionsMap& comments, 0177 int colorLabel, int pickLabel, 0178 int rating, const Template& t) 0179 { 0180 if (dateTime.isValid()) 0181 { 0182 d->loadSingleValue<QDateTime>(dateTime, d->dateTime, d->dateTimeStatus); 0183 } 0184 0185 d->loadSingleValue<int>(pickLabel, d->pickLabel, d->pickLabelStatus); 0186 0187 d->loadSingleValue<int>(colorLabel, d->colorLabel, d->colorLabelStatus); 0188 0189 d->loadSingleValue<int>(rating, d->rating, d->ratingStatus); 0190 0191 d->loadSingleValue<CaptionsMap>(titles, d->titles, d->titlesStatus); 0192 0193 d->loadSingleValue<CaptionsMap>(comments, d->comments, d->commentsStatus); 0194 0195 d->loadSingleValue<Template>(t, d->metadataTemplate, d->templateStatus); 0196 } 0197 0198 /** 0199 * template method used by comment and template 0200 */ 0201 template <class T> void MetadataHub::Private::loadSingleValue(const T& data, T& storage, 0202 MetadataHub::Status& status) 0203 { 0204 switch (status) 0205 { 0206 case MetadataHub::MetadataInvalid: 0207 { 0208 storage = data; 0209 status = MetadataHub::MetadataAvailable; 0210 break; 0211 } 0212 0213 case MetadataHub::MetadataAvailable: 0214 { 0215 qCDebug(DIGIKAM_GENERAL_LOG) << "You should not load more than one image info in metadatahub"; 0216 break; 0217 } 0218 } 0219 } 0220 0221 // ------------------------------------------------------------------------------------------------------------ 0222 0223 /** 0224 * safe method 0225 **/ 0226 bool MetadataHub::writeToMetadata(const ItemInfo& info, 0227 WriteComponent writeMode, 0228 bool ignoreLazySync, 0229 const MetaEngineSettingsContainer &settings) 0230 { 0231 applyChangeNotifications(); 0232 0233 // if no metadata constainer is needed at all, don't construct one - 0234 // important optimization if writing to file is turned off in setup! 0235 0236 if (!willWriteMetadata(writeMode, settings)) 0237 { 0238 return false; 0239 } 0240 0241 if (!ignoreLazySync && settings.useLazySync) 0242 { 0243 MetadataHubMngr::instance()->addPending(info); 0244 0245 return true; 0246 } 0247 0248 writeToBaloo(info.filePath()); 0249 0250 QScopedPointer<DMetadata> metadata(new DMetadata(info.filePath())); 0251 0252 if (write(*metadata, writeMode, settings)) 0253 { 0254 bool success = metadata->applyChanges(); 0255 ItemAttributesWatch::instance()->fileMetadataChanged(QUrl::fromLocalFile(info.filePath())); 0256 return success; 0257 } 0258 0259 return false; 0260 } 0261 0262 bool MetadataHub::write(DMetadata& metadata, 0263 WriteComponent writeMode, 0264 const MetaEngineSettingsContainer& settings) 0265 { 0266 applyChangeNotifications(); 0267 0268 bool dirty = false; 0269 0270 metadata.setSettings(settings); 0271 0272 // find out in advance if we have something to write - needed for FullWriteIfChanged mode 0273 0274 bool saveTitle = (settings.saveComments && (d->titlesStatus == MetadataAvailable) && writeMode.testFlag(WRITE_TITLE)); 0275 bool saveComment = (settings.saveComments && (d->commentsStatus == MetadataAvailable) && writeMode.testFlag(WRITE_COMMENTS)); 0276 bool saveDateTime = (settings.saveDateTime && (d->dateTimeStatus == MetadataAvailable) && writeMode.testFlag(WRITE_DATETIME)); 0277 bool savePickLabel = (settings.savePickLabel && (d->pickLabelStatus == MetadataAvailable) && writeMode.testFlag(WRITE_PICKLABEL)); 0278 bool saveColorLabel = (settings.saveColorLabel && (d->colorLabelStatus == MetadataAvailable) && writeMode.testFlag(WRITE_COLORLABEL)); 0279 bool saveRating = (settings.saveRating && (d->ratingStatus == MetadataAvailable) && writeMode.testFlag(WRITE_RATING)); 0280 bool saveTemplate = (settings.saveTemplate && (d->templateStatus == MetadataAvailable) && writeMode.testFlag(WRITE_TEMPLATE)); 0281 bool saveTags = (settings.saveTags && writeMode.testFlag(WRITE_TAGS)); 0282 bool saveFaces = (settings.saveFaceTags && writeMode.testFlag(WRITE_TAGS)); 0283 bool savePosition = (settings.savePosition && writeMode.testFlag(WRITE_POSITION)); 0284 0285 if (saveTitle) 0286 { 0287 // Store titles in image as Iptc Object name and Xmp. 0288 0289 dirty |= metadata.setItemTitles(d->titles); 0290 } 0291 0292 if (saveComment) 0293 { 0294 // Store comments in image as JFIF comments, Exif comments, Iptc Caption, and Xmp. 0295 0296 dirty |= metadata.setItemComments(d->comments); 0297 } 0298 0299 if (saveDateTime) 0300 { 0301 // Store Image Date & Time as Exif and Iptc tags. 0302 0303 dirty |= metadata.setImageDateTime(d->dateTime, false); 0304 } 0305 0306 if (savePickLabel) 0307 { 0308 // Store Image Pick Label as XMP tag. 0309 0310 dirty |= metadata.setItemPickLabel(d->pickLabel); 0311 } 0312 0313 if (saveColorLabel) 0314 { 0315 // Store Image Color Label as XMP tag. 0316 0317 dirty |= metadata.setItemColorLabel(d->colorLabel); 0318 } 0319 0320 if (saveRating) 0321 { 0322 // Store Image rating as Iptc tag. 0323 0324 dirty |= metadata.setItemRating(d->rating); 0325 } 0326 0327 if (saveTemplate) 0328 { 0329 if (d->metadataTemplate.isEmpty()) 0330 { 0331 dirty |= metadata.removeMetadataTemplate(); 0332 } 0333 else 0334 { 0335 // Store metadata template as XMP tag. 0336 0337 dirty |= metadata.setMetadataTemplate(d->metadataTemplate); 0338 } 0339 } 0340 0341 if (savePosition) 0342 { 0343 if (d->itemPosition.hasCoordinates()) 0344 { 0345 double altitude = d->itemPosition.altitude(); 0346 0347 dirty |= metadata.setGPSInfo(d->itemPosition.hasAltitude() ? &altitude : nullptr, 0348 d->itemPosition.latitudeNumber(), 0349 d->itemPosition.longitudeNumber()); 0350 } 0351 else 0352 { 0353 dirty |= metadata.removeGPSInfo(); 0354 } 0355 } 0356 0357 dirty |= writeFaceTagsMap(metadata, saveFaces); 0358 0359 dirty |= writeTags(metadata, saveTags); 0360 0361 return dirty; 0362 } 0363 0364 bool MetadataHub::write(const QString& filePath, 0365 WriteComponent writeMode, 0366 bool ignoreLazySync, 0367 const MetaEngineSettingsContainer& settings) 0368 { 0369 applyChangeNotifications(); 0370 0371 // if no metadata container is needed at all, don't construct one - 0372 // important optimization if writing to file is turned off in setup! 0373 0374 if (!willWriteMetadata(writeMode, settings)) 0375 { 0376 return false; 0377 } 0378 0379 if (!ignoreLazySync && settings.useLazySync) 0380 { 0381 ItemInfo info = ItemInfo::fromLocalFile(filePath); 0382 MetadataHubMngr::instance()->addPending(info); 0383 0384 return true; 0385 } 0386 0387 writeToBaloo(filePath); 0388 0389 QScopedPointer<DMetadata> metadata(new DMetadata(filePath)); 0390 0391 if (write(*metadata, writeMode, settings)) 0392 { 0393 bool success = metadata->applyChanges(); 0394 ItemAttributesWatch::instance()->fileMetadataChanged(QUrl::fromLocalFile(filePath)); 0395 0396 return success; 0397 } 0398 0399 return false; 0400 } 0401 0402 bool MetadataHub::write(const DImg& image, 0403 WriteComponent writeMode, 0404 bool ignoreLazySync, 0405 const MetaEngineSettingsContainer& settings) 0406 { 0407 applyChangeNotifications(); 0408 0409 // if no metadata container is needed at all, don't construct one 0410 0411 if (!willWriteMetadata(writeMode, settings)) 0412 { 0413 return false; 0414 } 0415 0416 // See DImgLoader::readMetadata() and saveMetadata() 0417 0418 QScopedPointer<DMetadata> metadata(new DMetadata); 0419 metadata->setData(image.getMetadata()); 0420 0421 QString filePath = image.originalFilePath(); 0422 0423 if (filePath.isEmpty()) 0424 { 0425 filePath = image.lastSavedFilePath(); 0426 } 0427 0428 if (!ignoreLazySync && settings.useLazySync && !filePath.isEmpty()) 0429 { 0430 ItemInfo info = ItemInfo::fromLocalFile(filePath); 0431 MetadataHubMngr::instance()->addPending(info); 0432 0433 return true; 0434 } 0435 0436 if (!filePath.isEmpty()) 0437 { 0438 writeToBaloo(filePath); 0439 } 0440 0441 return write(*metadata, writeMode, settings); 0442 } 0443 0444 bool MetadataHub::writeTags(const QString& filePath, 0445 WriteComponent writeMode, 0446 const MetaEngineSettingsContainer& settings) 0447 { 0448 applyChangeNotifications(); 0449 0450 // if no metadata container is needed at all, don't construct one - 0451 // important optimization if writing to file is turned off in setup! 0452 0453 if (!willWriteMetadata(writeMode, settings)) 0454 { 0455 return false; 0456 } 0457 0458 QScopedPointer<DMetadata> metadata(new DMetadata(filePath)); 0459 metadata->setSettings(settings); 0460 bool saveFaces = settings.saveFaceTags; 0461 bool saveTags = settings.saveTags; 0462 0463 writeFaceTagsMap(*metadata, saveFaces); 0464 0465 writeToBaloo(filePath); 0466 0467 if (writeTags(*metadata, saveTags)) 0468 { 0469 bool success = metadata->applyChanges(); 0470 ItemAttributesWatch::instance()->fileMetadataChanged(QUrl::fromLocalFile(filePath)); 0471 0472 return success; 0473 } 0474 else 0475 { 0476 return false; 0477 } 0478 } 0479 0480 bool MetadataHub::writeTags(const DMetadata& metadata, bool saveTags) 0481 { 0482 qCDebug(DIGIKAM_GENERAL_LOG) << "Writing tags"; 0483 0484 bool dirty = false; 0485 0486 if (saveTags) 0487 { 0488 // Store tag paths as Iptc keywords tags. 0489 // DatabaseMode == ManagedTags is assumed. 0490 // To fix this constraint (not needed currently), an oldKeywords parameter is needed 0491 // create list of keywords to be added and to be removed 0492 0493 QStringList tagsPathList, newKeywords; 0494 0495 QList<int> keys = d->tags.keys(); 0496 0497 Q_FOREACH (int tagId, keys) 0498 { 0499 if (!TagsCache::instance()->canBeWrittenToMetadata(tagId)) 0500 { 0501 continue; 0502 } 0503 0504 // WARNING: Do not use write(QFilePath ...) when multiple image info are loaded 0505 // otherwise disjoint tags will not be used, use writeToMetadata(ItemInfo...) 0506 0507 if (d->tags.value(tagId) == MetadataAvailable) 0508 { 0509 // This works for single and multiple selection. 0510 // In both situations, tags which had originally been loaded 0511 // have explicitly been removed with setTag. 0512 0513 QString tagName = TagsCache::instance()->tagName(tagId); 0514 QString tagPath = TagsCache::instance()->tagPath(tagId, TagsCache::NoLeadingSlash); 0515 0516 if (!tagsPathList.contains(tagPath)) 0517 { 0518 tagsPathList << tagPath; 0519 } 0520 0521 if (!tagName.isEmpty()) 0522 { 0523 newKeywords << tagName; 0524 } 0525 } 0526 } 0527 0528 tagsPathList = cleanupTags(tagsPathList); 0529 newKeywords = cleanupTags(newKeywords); 0530 0531 if (!newKeywords.isEmpty()) 0532 { 0533 qCDebug(DIGIKAM_GENERAL_LOG) << "-------------------------- New Keywords" << newKeywords; 0534 0535 // NOTE: See bug #175321 : we remove all old keyword from IPTC and XMP before to 0536 // synchronize metadata, else contents is not coherent. 0537 0538 dirty |= metadata.setItemTagsPath(tagsPathList); 0539 } 0540 else 0541 { 0542 qCDebug(DIGIKAM_GENERAL_LOG) << "Delete all keywords"; 0543 0544 // Delete all IPTC and XMP keywords 0545 0546 dirty |= metadata.setItemTagsPath(QStringList()); 0547 } 0548 } 0549 0550 return dirty; 0551 } 0552 0553 bool MetadataHub::writeFaceTagsMap(const DMetadata& metadata, bool saveFaces) 0554 { 0555 QSize size = d->imageProp.first; 0556 int orientation = d->imageProp.second; 0557 0558 QMultiMap<QString, QVariant> faceTagsMap; 0559 0560 // Add confirmed face regions from the database. 0561 0562 Q_FOREACH (const FaceTagsIface& face, d->facesList) 0563 { 0564 if (face.isConfirmedName()) 0565 { 0566 QString faceName = FaceTags::faceNameForTag(face.tagId()); 0567 0568 // Rotate face region back to the unaligned image. 0569 0570 QRect tempRect = face.region().toRect(); 0571 TagRegion::reverseToOrientation(tempRect, orientation, size); 0572 QRectF faceRect = TagRegion::absoluteToRelative(tempRect, size); 0573 faceTagsMap.insert(faceName, faceRect); 0574 } 0575 } 0576 0577 // Add person tags to which no region is 0578 // assigned to Microsoft Photo Region schema. 0579 0580 Q_FOREACH (int tagId, d->tags.keys()) 0581 { 0582 if ((d->tags.value(tagId) == MetadataAvailable) && FaceTags::isPerson(tagId)) 0583 { 0584 QString faceName = FaceTags::faceNameForTag(tagId); 0585 0586 if (!faceName.isEmpty() && !faceTagsMap.contains(faceName)) 0587 { 0588 faceTagsMap.insert(faceName, QRectF()); 0589 } 0590 } 0591 } 0592 0593 return metadata.setItemFacesMap(faceTagsMap, saveFaces, size); 0594 } 0595 0596 QStringList MetadataHub::cleanupTags(const QStringList& toClean) 0597 { 0598 QSet<QString> deduplicator; 0599 0600 for (int index = 0 ; index < toClean.size() ; ++index) 0601 { 0602 QString keyword = toClean.at(index); 0603 0604 if (!keyword.isEmpty()) 0605 { 0606 // digiKam_root_tag is present in some photos tagged with older 0607 // version of digiKam, must be removed 0608 0609 if (keyword.contains(QRegularExpression(QLatin1String("(_Digikam_root_tag_/|/_Digikam_root_tag_|_Digikam_root_tag_)")))) 0610 { 0611 keyword = keyword.replace(QRegularExpression(QLatin1String("(_Digikam_root_tag_/|/_Digikam_root_tag_|_Digikam_root_tag_)")), 0612 QLatin1String("")); 0613 } 0614 0615 deduplicator.insert(keyword); 0616 } 0617 } 0618 0619 return deduplicator.values(); 0620 } 0621 0622 bool MetadataHub::willWriteMetadata(WriteComponent writeMode, const MetaEngineSettingsContainer& settings) const 0623 { 0624 // This is the same logic as in write(DMetadata) but without actually writing. 0625 // Adapt if the method above changes 0626 0627 bool saveTitle = (settings.saveComments && (d->titlesStatus == MetadataAvailable) && writeMode.testFlag(WRITE_TITLE)); 0628 bool saveComment = (settings.saveComments && (d->commentsStatus == MetadataAvailable) && writeMode.testFlag(WRITE_COMMENTS)); 0629 bool saveDateTime = (settings.saveDateTime && (d->dateTimeStatus == MetadataAvailable) && writeMode.testFlag(WRITE_DATETIME)); 0630 bool savePickLabel = (settings.savePickLabel && (d->pickLabelStatus == MetadataAvailable) && writeMode.testFlag(WRITE_PICKLABEL)); 0631 bool saveColorLabel = (settings.saveColorLabel && (d->colorLabelStatus == MetadataAvailable) && writeMode.testFlag(WRITE_COLORLABEL)); 0632 bool saveRating = (settings.saveRating && (d->ratingStatus == MetadataAvailable) && writeMode.testFlag(WRITE_RATING)); 0633 bool saveTemplate = (settings.saveTemplate && (d->templateStatus == MetadataAvailable) && writeMode.testFlag(WRITE_TEMPLATE)); 0634 bool saveTags = (settings.saveTags && writeMode.testFlag(WRITE_TAGS)); 0635 bool saveFaces = (settings.saveFaceTags && writeMode.testFlag(WRITE_TAGS)); 0636 bool savePosition = (settings.savePosition && writeMode.testFlag(WRITE_POSITION)); 0637 0638 return ( 0639 saveTitle || 0640 saveComment || 0641 saveDateTime || 0642 savePickLabel || 0643 saveColorLabel || 0644 saveRating || 0645 saveTemplate || 0646 saveTags || 0647 saveFaces || 0648 savePosition 0649 ); 0650 } 0651 0652 void MetadataHub::writeToBaloo(const QString& filePath, const MetaEngineSettingsContainer& settings) 0653 { 0654 0655 #ifdef HAVE_KFILEMETADATA 0656 0657 BalooWrap* const baloo = BalooWrap::instance(); 0658 0659 if (!baloo->getSyncToBaloo()) 0660 { 0661 qCDebug(DIGIKAM_GENERAL_LOG) << "No write to baloo +++++++++++++++++++++++++++++++++++++"; 0662 return; 0663 } 0664 0665 BalooInfo bInfo; 0666 0667 bool saveComment = (settings.saveComments && (d->commentsStatus == MetadataAvailable)); 0668 bool saveRating = (settings.saveRating && (d->ratingStatus == MetadataAvailable)); 0669 0670 QStringList tagPathList; 0671 0672 for (QMap<int, MetadataHub::Status>::iterator it = d->tags.begin() ; it != d->tags.end() ; ++it) 0673 { 0674 if (!TagsCache::instance()->canBeWrittenToMetadata(it.key())) 0675 { 0676 continue; 0677 } 0678 0679 // it is important that MetadataDisjoint keywords are not touched 0680 0681 if (it.value() == MetadataAvailable) 0682 { 0683 QString tagPath = TagsCache::instance()->tagPath(it.key(), TagsCache::NoLeadingSlash); 0684 0685 if (!tagPath.isEmpty()) 0686 { 0687 tagPathList << tagPath; 0688 } 0689 } 0690 } 0691 0692 if (saveComment) 0693 { 0694 bInfo.comment = d->comments.value(QLatin1String("x-default")).caption; 0695 } 0696 0697 if (saveRating) 0698 { 0699 bInfo.rating = d->rating; 0700 } 0701 0702 bInfo.tags = cleanupTags(tagPathList); 0703 baloo->setSemanticInfo(QUrl::fromLocalFile(filePath), bInfo); 0704 0705 #else 0706 0707 Q_UNUSED(filePath); 0708 Q_UNUSED(settings); 0709 0710 #endif 0711 0712 } 0713 0714 void MetadataHub::applyChangeNotifications() 0715 { 0716 } 0717 0718 void MetadataHub::loadFaceTags(const ItemInfo& info) 0719 { 0720 FaceTagsEditor editor; 0721 d->facesList = editor.databaseFaces(info.id()); 0722 d->imageProp = qMakePair(info.dimensions(), 0723 info.orientation()); 0724 } 0725 0726 // NOTE: Unused code 0727 //void MetadataHub::load(const DMetadata& metadata) 0728 //{ 0729 // d->count++; 0730 0731 // CaptionsMap comments; 0732 // CaptionsMap titles; 0733 // QStringList keywords; 0734 // QDateTime datetime; 0735 // int pickLabel; 0736 // int colorLabel; 0737 // int rating; 0738 0739 // titles = metadata.getItemTitles(); 0740 0741 // // Try to get comments from image : 0742 // // In first, from Xmp comments tag, 0743 // // In second, from standard JPEG JFIF comments section, 0744 // // In third, from Exif comments tag, 0745 // // In four, from Iptc comments tag. 0746 // comments = metadata.getItemComments(); 0747 0748 // // Try to get date and time from image : 0749 // // In first, from Exif date & time tags, 0750 // // In second, from Xmp date & time tags, or 0751 // // In third, from Iptc date & time tags. 0752 // // else use file system time stamp. 0753 // datetime = metadata.getItemDateTime(); 0754 0755 // if ( !datetime.isValid() ) 0756 // { 0757 // QFileInfo info( metadata.getFilePath() ); 0758 // datetime = info.lastModified(); 0759 // } 0760 0761 // // Try to get image pick label from Xmp tag 0762 // pickLabel = metadata.getItemPickLabel(); 0763 0764 // // Try to get image color label from Xmp tag 0765 // colorLabel = metadata.getItemColorLabel(); 0766 0767 // // Try to get image rating from Xmp tag, or Iptc Urgency tag 0768 // rating = metadata.getItemRating(); 0769 0770 // Template tref = metadata.getMetadataTemplate(); 0771 // Template t = TemplateManager::defaultManager()->findByContents(tref); 0772 0773 // qCDebug(DIGIKAM_GENERAL_LOG) << "Found Metadata Template: " << t.templateTitle(); 0774 0775 // load(datetime, titles, comments, colorLabel, pickLabel, rating, t.isNull() ? tref : t); 0776 0777 // // Try to get image tags from Xmp using digiKam namespace tags. 0778 0779 // QStringList tagPaths; 0780 0781 // if (metadata.getItemTagsPath(tagPaths)) 0782 // { 0783 // QList<int> tagIds = TagsCache::instance()->tagsForPaths(tagPaths); 0784 // loadTags(tagIds); 0785 // } 0786 //} 0787 0788 //bool MetadataHub::load(const QString& filePath, const MetaEngineSettingsContainer& settings) 0789 //{ 0790 0791 // QScopedPointer<DMetadata> metadata(new DMetadata); 0792 // metadata->setSettings(settings); 0793 // bool success = metadata->load(filePath); 0794 // load(*metadata); // increments count 0795 // return success; 0796 //} 0797 0798 /* 0799 // private code to merge tags with d->tagList 0800 void MetadataHub::loadTags(const QStringList& loadedTagPaths) 0801 { 0802 if (d->count == 1) 0803 { 0804 d->tagList = loadedTagPaths; 0805 } 0806 else 0807 { 0808 // a simple intersection 0809 QStringList toBeAdded; 0810 for (QStringList::iterator it = d->tagList.begin(); it != d->tagList.end(); ++it) 0811 { 0812 if (loadedTagPaths.indexOf(*it) == -1) 0813 { 0814 // it's not in the loadedTagPaths list. Remove it from intersection list. 0815 it = d->tagList.erase(it); 0816 } 0817 // else, it is in both lists, so no need to change d->tagList, it's already added. 0818 } 0819 } 0820 } 0821 */ 0822 0823 } // namespace Digikam