File indexing completed on 2025-01-19 03:53:37

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-04-21
0007  * Description : Handling access to one item and associated data - Properties
0008  *
0009  * SPDX-FileCopyrightText: 2005      by Renchi Raju <renchi dot raju at gmail dot com>
0010  * SPDX-FileCopyrightText: 2007-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0011  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0012  * SPDX-FileCopyrightText: 2013      by Michael G. Hansen <mike at mghansen dot de>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "iteminfo_p.h"
0019 
0020 namespace Digikam
0021 {
0022 
0023 bool ItemInfo::isNull() const
0024 {
0025     return !m_data;
0026 }
0027 
0028 qlonglong ItemInfo::id() const
0029 {
0030     return (m_data ? m_data->id : -1);
0031 }
0032 
0033 int ItemInfo::albumId() const
0034 {
0035     return (m_data ? m_data->albumId : -1);
0036 }
0037 
0038 int ItemInfo::albumRootId() const
0039 {
0040     return (m_data ? m_data->albumRootId : -1);
0041 }
0042 
0043 QString ItemInfo::name() const
0044 {
0045     if (!m_data)
0046     {
0047         return QString();
0048     }
0049 
0050     ItemInfoReadLocker lock;
0051 
0052     return m_data->name;
0053 }
0054 
0055 qlonglong ItemInfo::fileSize() const
0056 {
0057     if (!m_data)
0058     {
0059         return 0;
0060     }
0061 
0062     RETURN_IF_CACHED(fileSize)
0063 
0064     QVariantList values = CoreDbAccess().db()->getImagesFields(m_data->id, DatabaseFields::FileSize);
0065 
0066     STORE_IN_CACHE_AND_RETURN(fileSize, values.first().toLongLong())
0067 }
0068 
0069 QString ItemInfo::title() const
0070 {
0071     if (!m_data)
0072     {
0073         return QString();
0074     }
0075 
0076     RETURN_IF_CACHED(defaultTitle)
0077 
0078     QString title;
0079     {
0080         CoreDbAccess access;
0081         ItemComments comments(access, m_data->id);
0082         title = comments.defaultComment(DatabaseComment::Title);
0083     }
0084 
0085     ItemInfoWriteLocker lock;
0086     m_data.data()->defaultTitle       = title;
0087     m_data.data()->defaultTitleCached = true;
0088 
0089     return m_data->defaultTitle;
0090 }
0091 
0092 QString ItemInfo::comment() const
0093 {
0094     if (!m_data)
0095     {
0096         return QString();
0097     }
0098 
0099     RETURN_IF_CACHED(defaultComment)
0100 
0101     QString comment;
0102     {
0103         CoreDbAccess access;
0104         ItemComments comments(access, m_data->id);
0105         comment = comments.defaultComment();
0106     }
0107 
0108     ItemInfoWriteLocker lock;
0109     m_data.data()->defaultComment       = comment;
0110     m_data.data()->defaultCommentCached = true;
0111 
0112     return m_data->defaultComment;
0113 }
0114 
0115 double ItemInfo::aspectRatio() const
0116 {
0117     if (!m_data)
0118     {
0119         return 0;
0120     }
0121 
0122     RETURN_ASPECTRATIO_IF_IMAGESIZE_CACHED()
0123 
0124     return (double)m_data->imageSize.width() / m_data->imageSize.height();
0125 }
0126 
0127 qlonglong ItemInfo::manualOrder() const
0128 {
0129     if (!m_data)
0130     {
0131         return 0;
0132     }
0133 
0134     RETURN_IF_CACHED(manualOrder)
0135 
0136     QVariantList values = CoreDbAccess().db()->getImagesFields(m_data->id, DatabaseFields::ManualOrder);
0137 
0138     STORE_IN_CACHE_AND_RETURN(manualOrder, values.first().toLongLong())
0139 }
0140 
0141 QString ItemInfo::format() const
0142 {
0143     if (!m_data)
0144     {
0145         return QString();
0146     }
0147 
0148     RETURN_IF_CACHED(format)
0149 
0150     QVariantList values = CoreDbAccess().db()->getItemInformation(m_data->id, DatabaseFields::Format);
0151 
0152     STORE_IN_CACHE_AND_RETURN(format, values.first().toString())
0153 }
0154 
0155 DatabaseItem::Category ItemInfo::category() const
0156 {
0157     if (!m_data)
0158     {
0159         return DatabaseItem::UndefinedCategory;
0160     }
0161 
0162     RETURN_IF_CACHED(category)
0163 
0164     QVariantList values = CoreDbAccess().db()->getImagesFields(m_data->id, DatabaseFields::Category);
0165 
0166     STORE_IN_CACHE_AND_RETURN(category, (DatabaseItem::Category)values.first().toInt())
0167 }
0168 
0169 QDateTime ItemInfo::dateTime() const
0170 {
0171     if (!m_data)
0172     {
0173         return QDateTime();
0174     }
0175 
0176     RETURN_IF_CACHED(creationDate)
0177 
0178     QVariantList values = CoreDbAccess().db()->getItemInformation(m_data->id, DatabaseFields::CreationDate);
0179 
0180     STORE_IN_CACHE_AND_RETURN(creationDate, values.first().toDateTime())
0181 }
0182 
0183 QDateTime ItemInfo::modDateTime() const
0184 {
0185     if (!m_data)
0186     {
0187         return QDateTime();
0188     }
0189 
0190     RETURN_IF_CACHED(modificationDate)
0191 
0192     QVariantList values = CoreDbAccess().db()->getImagesFields(m_data->id, DatabaseFields::ModificationDate);
0193 
0194     STORE_IN_CACHE_AND_RETURN(modificationDate, values.first().toDateTime())
0195 }
0196 
0197 QSize ItemInfo::dimensions() const
0198 {
0199     if (!m_data)
0200     {
0201         return QSize();
0202     }
0203 
0204     RETURN_IF_CACHED(imageSize)
0205 
0206     QVariantList values = CoreDbAccess().db()->getItemInformation(m_data->id, DatabaseFields::Width | DatabaseFields::Height);
0207 
0208     ItemInfoWriteLocker lock;
0209     m_data.data()->imageSizeCached = true;
0210 
0211     if (values.size() == 2)
0212     {
0213         m_data.data()->imageSize = QSize(values.at(0).toInt(), values.at(1).toInt());
0214     }
0215 
0216     return m_data->imageSize;
0217 }
0218 
0219 int ItemInfo::faceCount() const
0220 {
0221     if (!m_data)
0222     {
0223         return 0;
0224     }
0225 
0226     RETURN_IF_CACHED(faceCount);
0227 
0228     FaceTagsEditor fte;
0229     int count = fte.databaseFaces(m_data->id).count();
0230 
0231     ItemInfoWriteLocker lock;
0232     m_data.data()->faceCountCached = true;
0233     m_data.data()->faceCount       = count;
0234 
0235     return m_data->faceCount;
0236 }
0237 
0238 int ItemInfo::unconfirmedFaceCount() const
0239 {
0240     if (!m_data)
0241     {
0242         return 0;
0243     }
0244 
0245     RETURN_IF_CACHED(unconfirmedFaceCount);
0246 
0247     FaceTagsEditor fte;
0248     int count = fte.unconfirmedNameFaceTagsIfaces(m_data->id).count();
0249 
0250     ItemInfoWriteLocker lock;
0251     m_data.data()->unconfirmedFaceCountCached = true;
0252     m_data.data()->unconfirmedFaceCount       = count;
0253 
0254     return m_data->unconfirmedFaceCount;
0255 }
0256 
0257 QMap<QString, QString> ItemInfo::getSuggestedNames() const
0258 {
0259     if (!m_data)
0260     {
0261         return QMap<QString, QString>();
0262     }
0263 
0264     RETURN_IF_CACHED(faceSuggestions);
0265 
0266     FaceTagsEditor fte;
0267     QMap<QString, QString> faceSuggestions = fte.getSuggestedNames(m_data->id);
0268 
0269     ItemInfoWriteLocker lock;
0270     m_data.data()->faceSuggestionsCached = true;
0271     m_data.data()->faceSuggestions       = faceSuggestions;
0272 
0273     return m_data->faceSuggestions;
0274 }
0275 
0276 int ItemInfo::orientation() const
0277 {
0278     if (!m_data)
0279     {
0280         return 0; // ORIENTATION_UNSPECIFIED
0281     }
0282 
0283     RETURN_IF_CACHED(orientation)
0284 
0285     QVariantList values = CoreDbAccess().db()->getItemInformation(m_data->id, DatabaseFields::Orientation);
0286 
0287     STORE_IN_CACHE_AND_RETURN(orientation, values.first().toInt());
0288 }
0289 
0290 QUrl ItemInfo::fileUrl() const
0291 {
0292     return QUrl::fromLocalFile(filePath());
0293 }
0294 
0295 QString ItemInfo::filePath() const
0296 {
0297     if (!m_data)
0298     {
0299         return QString();
0300     }
0301 
0302     QString albumRoot = CollectionManager::instance()->albumRootPath(m_data->albumRootId);
0303 
0304     if (albumRoot.isNull())
0305     {
0306         return QString();
0307     }
0308 
0309     QString album     = ItemInfoStatic::cache()->albumRelativePath(m_data->albumId);
0310     ItemInfoReadLocker lock;
0311 
0312     if (album == QLatin1String("/"))
0313     {
0314         return (albumRoot + album + m_data->name);
0315     }
0316     else
0317     {
0318         return (albumRoot + album + QLatin1Char('/') + m_data->name);
0319     }
0320 }
0321 
0322 QString ItemInfo::relativePath() const
0323 {
0324     if (!m_data)
0325     {
0326         return QString();
0327     }
0328 
0329     return (ItemInfoStatic::cache()->albumRelativePath(m_data->albumId));
0330 }
0331 
0332 bool ItemInfo::isVisible() const
0333 {
0334     if (!m_data)
0335     {
0336         return false;
0337     }
0338 
0339     QVariantList value = CoreDbAccess().db()->getImagesFields(m_data->id, DatabaseFields::Status);
0340 
0341     if (!value.isEmpty())
0342     {
0343         return (value.first().toInt() == DatabaseItem::Visible);
0344     }
0345 
0346     return false;
0347 }
0348 
0349 bool ItemInfo::isRemoved() const
0350 {
0351     if (!m_data)
0352     {
0353         return true;
0354     }
0355 
0356     QVariantList value = CoreDbAccess().db()->getImagesFields(m_data->id, DatabaseFields::Status);
0357 
0358     if (!value.isEmpty())
0359     {
0360         return (value.first().toInt() == DatabaseItem::Trashed) || (value.first().toInt() == DatabaseItem::Obsolete);
0361     }
0362 
0363     return false;
0364 }
0365 
0366 void ItemInfo::setVisible(bool isVisible)
0367 {
0368     if (!m_data)
0369     {
0370         return;
0371     }
0372 
0373     if (m_data->albumId == 0)
0374     {
0375         qCWarning(DIGIKAM_DATABASE_LOG) << "Attempt to make a Removed item visible with ItemInfo::setVisible";
0376         return;
0377     }
0378 
0379     CoreDbAccess().db()->setItemStatus(m_data->id, isVisible ? DatabaseItem::Visible : DatabaseItem::Hidden);
0380 }
0381 
0382 void ItemInfo::setManualOrder(qlonglong value)
0383 {
0384     if (!m_data)
0385     {
0386         return;
0387     }
0388 
0389     {
0390         ItemInfoWriteLocker lock;
0391         m_data->manualOrder       = value;
0392         m_data->manualOrderCached = true;
0393     }
0394 
0395     CoreDbAccess().db()->setItemManualOrder(m_data->id, value);
0396 }
0397 
0398 void ItemInfo::setOrientation(int value)
0399 {
0400     if (!m_data)
0401     {
0402         return;
0403     }
0404 
0405     {
0406         ItemInfoWriteLocker lock;
0407         m_data->orientation       = value;
0408         m_data->orientationCached = true;
0409     }
0410 
0411     CoreDbAccess().db()->changeItemInformation(m_data->id, QVariantList() << value, DatabaseFields::Orientation);
0412 }
0413 
0414 void ItemInfo::setName(const QString& newName)
0415 {
0416     if (!m_data || newName.isEmpty())
0417     {
0418         return;
0419     }
0420 
0421     {
0422         ItemInfoWriteLocker lock;
0423         m_data->name = newName;
0424         ItemInfoStatic::cache()->cacheByName(m_data);
0425     }
0426 
0427     CoreDbAccess().db()->renameItem(m_data->id, newName);
0428 }
0429 
0430 void ItemInfo::setDateTime(const QDateTime& dateTime)
0431 {
0432     if (!m_data || !dateTime.isValid())
0433     {
0434         return;
0435     }
0436 
0437     {
0438         ItemInfoWriteLocker lock;
0439         m_data->creationDate       = dateTime;
0440         m_data->creationDateCached = true;
0441     }
0442 
0443     CoreDbAccess().db()->changeItemInformation(m_data->id, QVariantList() << dateTime, DatabaseFields::CreationDate);
0444 }
0445 
0446 void ItemInfo::setModDateTime(const QDateTime& dateTime)
0447 {
0448     if (!m_data || !dateTime.isValid())
0449     {
0450         return;
0451     }
0452 
0453     {
0454         ItemInfoWriteLocker lock;
0455         m_data->modificationDate       = dateTime;
0456         m_data->modificationDateCached = true;
0457     }
0458 
0459     CoreDbAccess().db()->setItemModificationDate(m_data->id, dateTime);
0460 }
0461 
0462 ItemInfo::DatabaseFieldsHashRaw ItemInfo::getDatabaseFieldsRaw(const DatabaseFields::Set& requestedSet) const
0463 {
0464     if (!m_data || (!m_data->hasVideoMetadata && !m_data->hasImageMetadata))
0465     {
0466         return DatabaseFieldsHashRaw();
0467     }
0468 
0469     DatabaseFields::VideoMetadataMinSizeType cachedVideoMetadata;
0470     DatabaseFields::ImageMetadataMinSizeType cachedImageMetadata;
0471     ItemInfo::DatabaseFieldsHashRaw cachedHash;
0472 
0473     // consolidate to one ReadLocker. In particular, the shallow copy of the QHash must be done under protection
0474 
0475     {
0476         ItemInfoReadLocker lock;
0477         cachedVideoMetadata = m_data->videoMetadataCached;
0478         cachedImageMetadata = m_data->imageMetadataCached;
0479         cachedHash = m_data->databaseFieldsHashRaw;
0480     }
0481 
0482     if (requestedSet.hasFieldsFromVideoMetadata() && m_data->hasVideoMetadata)
0483     {
0484         const DatabaseFields::VideoMetadata requestedVideoMetadata = requestedSet.getVideoMetadata();
0485         const DatabaseFields::VideoMetadata missingVideoMetadata = requestedVideoMetadata & ~cachedVideoMetadata;
0486 
0487         if (missingVideoMetadata)
0488         {
0489             const QVariantList fieldValues = CoreDbAccess().db()->getVideoMetadata(m_data->id, missingVideoMetadata);
0490 
0491             ItemInfoWriteLocker lock;
0492 
0493             if (fieldValues.isEmpty())
0494             {
0495                 m_data.data()->hasVideoMetadata    = false;
0496                 m_data.data()->databaseFieldsHashRaw.removeAllFields(DatabaseFields::VideoMetadataAll);
0497                 m_data.data()->videoMetadataCached = DatabaseFields::VideoMetadataNone;
0498             }
0499             else
0500             {
0501                 int fieldsIndex = 0;
0502 
0503                 for (DatabaseFields::VideoMetadataIteratorSetOnly it(missingVideoMetadata) ; !it.atEnd() ; ++it)
0504                 {
0505                     const QVariant fieldValue = fieldValues.at(fieldsIndex);
0506                     ++fieldsIndex;
0507 
0508                     m_data.data()->databaseFieldsHashRaw.insertField(*it, fieldValue);
0509                 }
0510 
0511                 m_data.data()->videoMetadataCached |= missingVideoMetadata;
0512             }
0513 
0514             // update for return value
0515 
0516             cachedHash = m_data->databaseFieldsHashRaw;
0517         }
0518     }
0519 
0520     if (requestedSet.hasFieldsFromImageMetadata() && m_data->hasImageMetadata)
0521     {
0522         const DatabaseFields::ImageMetadata requestedImageMetadata = requestedSet.getImageMetadata();
0523         const DatabaseFields::ImageMetadata missingImageMetadata   = requestedImageMetadata & ~cachedImageMetadata;
0524 
0525         if (missingImageMetadata)
0526         {
0527             const QVariantList fieldValues = CoreDbAccess().db()->getImageMetadata(m_data->id, missingImageMetadata);
0528 
0529             ItemInfoWriteLocker lock;
0530 
0531             if (fieldValues.isEmpty())
0532             {
0533                 m_data.data()->hasImageMetadata    = false;
0534                 m_data.data()->databaseFieldsHashRaw.removeAllFields(DatabaseFields::ImageMetadataAll);
0535                 m_data.data()->imageMetadataCached = DatabaseFields::ImageMetadataNone;
0536             }
0537             else
0538             {
0539                 int fieldsIndex = 0;
0540 
0541                 for (DatabaseFields::ImageMetadataIteratorSetOnly it(missingImageMetadata) ; !it.atEnd() ; ++it)
0542                 {
0543                     const QVariant fieldValue = fieldValues.at(fieldsIndex);
0544                     ++fieldsIndex;
0545 
0546                     m_data.data()->databaseFieldsHashRaw.insertField(*it, fieldValue);
0547                 }
0548 
0549                 m_data.data()->imageMetadataCached |= missingImageMetadata;
0550             }
0551 
0552             cachedHash = m_data->databaseFieldsHashRaw;
0553         }
0554     }
0555 
0556     // We always return all fields, the caller can just retrieve the ones he needs.
0557 
0558     return cachedHash;
0559 }
0560 
0561 QVariant ItemInfo::getDatabaseFieldRaw(const DatabaseFields::Set& requestedField) const
0562 {
0563     DatabaseFieldsHashRaw rawHash = getDatabaseFieldsRaw(requestedField);
0564 
0565     if (requestedField.hasFieldsFromImageMetadata())
0566     {
0567         const DatabaseFields::ImageMetadata requestedFieldFlag = requestedField;
0568         const QVariant value                                   = rawHash.value(requestedFieldFlag);
0569 
0570         return value;
0571     }
0572 
0573     if (requestedField.hasFieldsFromVideoMetadata())
0574     {
0575         const DatabaseFields::VideoMetadata requestedFieldFlag = requestedField;
0576         const QVariant value                                   = rawHash.value(requestedFieldFlag);
0577 
0578         return value;
0579     }
0580 
0581     return QVariant();
0582 }
0583 
0584 } // namespace Digikam