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