File indexing completed on 2024-05-05 16:09:03

0001 /*
0002     This file is part of the KFileMetaData project
0003     SPDX-FileCopyrightText: 2014 Vishesh Handa <me@vhanda.in>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "propertyinfo.h"
0009 
0010 #include <KLazyLocalizedString>
0011 #include <KLocalizedString>
0012 
0013 #include "formatstrings_p.h"
0014 
0015 #include <array>
0016 
0017 #include <QLocale>
0018 
0019 using namespace KFileMetaData;
0020 
0021 class KFileMetaData::PropertyInfoData
0022 {
0023     using FormatFunction = QString (&)(const QVariant&);
0024 
0025 public:
0026     const Property::Property prop;
0027     const bool shouldBeIndexed = false;
0028     const QString name;
0029     const KLazyLocalizedString displayName;
0030     const QVariant::Type valueType = QVariant::Invalid;
0031     const FormatFunction formatAsString = FormatStrings::toStringFunction;
0032 };
0033 
0034 const static PropertyInfoData staticEmptyPropertyInfo{ Property::Empty, false, QStringLiteral("empty"), kli18n("Empty"), QVariant::Invalid };
0035 
0036 const static std::array<PropertyInfoData, 78> staticPropertyInfo
0037 {
0038     PropertyInfoData{ Property::Album,                      true,  QStringLiteral("album"),                      kli18nc("@label music album", "Album"),                QVariant::String },
0039     PropertyInfoData{ Property::AlbumArtist,                true,  QStringLiteral("albumArtist"),                kli18nc("@label", "Album Artist"),                     QVariant::String },
0040     PropertyInfoData{ Property::Artist,                     true,  QStringLiteral("artist"),                     kli18nc("@label", "Artist"),                           QVariant::String },
0041     PropertyInfoData{ Property::AspectRatio,                false, QStringLiteral("aspectRatio"),                kli18nc("@label", "Aspect Ratio"),                     QVariant::Double,   FormatStrings::formatAspectRatio },
0042     PropertyInfoData{ Property::Author,                     true,  QStringLiteral("author"),                     kli18nc("@label", "Author"),                           QVariant::String },
0043     PropertyInfoData{ Property::BitRate,                    false, QStringLiteral("bitRate"),                    kli18nc("@label", "Bitrate"),                          QVariant::Int,      FormatStrings::formatBitRate },
0044     PropertyInfoData{ Property::Channels,                   false, QStringLiteral("channels"),                   kli18nc("@label", "Channels"),                         QVariant::Int },
0045     PropertyInfoData{ Property::Comment,                    false, QStringLiteral("comment"),                    kli18nc("@label", "Comment"),                          QVariant::String },
0046     PropertyInfoData{ Property::Description,                false, QStringLiteral("description"),                kli18nc("@label", "Description"),                      QVariant::String },
0047     PropertyInfoData{ Property::Composer,                   true,  QStringLiteral("composer"),                   kli18nc("@label", "Composer"),                         QVariant::String },
0048     PropertyInfoData{ Property::Copyright,                  false, QStringLiteral("copyright"),                  kli18nc("@label", "Copyright"),                        QVariant::String },
0049     PropertyInfoData{ Property::CreationDate,               false, QStringLiteral("creationDate"),               kli18nc("@label", "Creation Date"),                    QVariant::DateTime, FormatStrings::formatDate },
0050     PropertyInfoData{ Property::Duration,                   false, QStringLiteral("duration"),                   kli18nc("@label", "Duration"),                         QVariant::Int,      FormatStrings::formatDuration },
0051     PropertyInfoData{ Property::FrameRate,                  false, QStringLiteral("frameRate"),                  kli18nc("@label", "Frame Rate"),                       QVariant::Double,   FormatStrings::formatAsFrameRate },
0052     PropertyInfoData{ Property::Generator,                  false, QStringLiteral("generator"),                  kli18nc("@label", "Document Generated By"),            QVariant::String },
0053     PropertyInfoData{ Property::Genre,                      true,  QStringLiteral("genre"),                      kli18nc("@label music genre", "Genre"),                QVariant::String },
0054     PropertyInfoData{ Property::Height,                     false, QStringLiteral("height"),                     kli18nc("@label", "Height"),                           QVariant::Int },
0055     PropertyInfoData{ Property::ImageDateTime,              false, QStringLiteral("imageDateTime"),              kli18nc("@label EXIF", "Image Date Time"),             QVariant::DateTime, FormatStrings::formatDate },
0056     PropertyInfoData{ Property::Manufacturer,               false, QStringLiteral("manufacturer"),               kli18nc("@label EXIF", "Manufacturer"),                QVariant::String },
0057     PropertyInfoData{ Property::Model,                      false, QStringLiteral("model"),                      kli18nc("@label EXIF", "Model"),                       QVariant::String },
0058     PropertyInfoData{ Property::ImageOrientation,           false, QStringLiteral("imageOrientation"),           kli18nc("@label EXIF", "Image Orientation"),           QVariant::Int,      FormatStrings::formatOrientationValue },
0059     PropertyInfoData{ Property::Keywords,                   false, QStringLiteral("keywords"),                   kli18nc("@label", "Keywords"),                         QVariant::String },
0060     PropertyInfoData{ Property::Language,                   false, QStringLiteral("language"),                   kli18nc("@label", "Language"),                         QVariant::String },
0061     PropertyInfoData{ Property::LineCount,                  false, QStringLiteral("lineCount"),                  kli18nc("@label number of lines", "Line Count"),       QVariant::Int },
0062     PropertyInfoData{ Property::Lyricist,                   true,  QStringLiteral("lyricist"),                   kli18nc("@label", "Lyricist"),                         QVariant::String },
0063     PropertyInfoData{ Property::PageCount,                  false, QStringLiteral("pageCount"),                  kli18nc("@label", "Page Count"),                       QVariant::Int },
0064     PropertyInfoData{ Property::PhotoApertureValue,         false, QStringLiteral("photoApertureValue"),         kli18nc("@label EXIF", "Aperture Value"),              QVariant::Double,   FormatStrings::formatAsFNumber },
0065     PropertyInfoData{ Property::PhotoDateTimeOriginal,      false, QStringLiteral("photoDateTimeOriginal"),      kli18nc("@label EXIF", "Original Date Time"),          QVariant::DateTime, FormatStrings::formatDate },
0066     PropertyInfoData{ Property::PhotoExposureBiasValue,     false, QStringLiteral("photoExposureBiasValue"),     kli18nc("@label EXIF", "Exposure Bias"),               QVariant::Double,   FormatStrings::formatPhotoExposureBias },
0067     PropertyInfoData{ Property::PhotoExposureTime,          false, QStringLiteral("photoExposureTime"),          kli18nc("@label EXIF", "Exposure Time"),               QVariant::Double,   FormatStrings::formatPhotoTime },
0068     PropertyInfoData{ Property::PhotoFlash,                 false, QStringLiteral("photoFlash"),                 kli18nc("@label EXIF", "Flash"),                       QVariant::Int,      FormatStrings::formatPhotoFlashValue },
0069     PropertyInfoData{ Property::PhotoFNumber,               false, QStringLiteral("photoFNumber"),               kli18nc("@label EXIF", "F Number"),                    QVariant::Double,   FormatStrings::formatAsFNumber },
0070     PropertyInfoData{ Property::PhotoFocalLength,           false, QStringLiteral("photoFocalLength"),           kli18nc("@label EXIF", "Focal Length"),                QVariant::Double,   FormatStrings::formatAsMilliMeter },
0071     PropertyInfoData{ Property::PhotoFocalLengthIn35mmFilm, false, QStringLiteral("photoFocalLengthIn35mmFilm"), kli18nc("@label EXIF", "Focal Length 35mm"),           QVariant::Double,   FormatStrings::formatAsMilliMeter },
0072     PropertyInfoData{ Property::PhotoGpsLatitude,           false, QStringLiteral("photoGpsLatitude"),           kli18nc("@label EXIF", "GPS Latitude"),                QVariant::Double,   FormatStrings::formatAsDegree },
0073     PropertyInfoData{ Property::PhotoGpsLongitude,          false, QStringLiteral("photoGpsLongitude"),          kli18nc("@label EXIF", "GPS Longitude"),               QVariant::Double,   FormatStrings::formatAsDegree },
0074     PropertyInfoData{ Property::PhotoGpsAltitude,           false, QStringLiteral("photoGpsAltitude"),           kli18nc("@label EXIF", "GPS Altitude"),                QVariant::Double,   FormatStrings::formatAsMeter },
0075     PropertyInfoData{ Property::PhotoISOSpeedRatings,       false, QStringLiteral("photoISOSpeedRatings"),       kli18nc("@label EXIF", "ISO Speed Rating"),            QVariant::Int },
0076     PropertyInfoData{ Property::PhotoMeteringMode,          false, QStringLiteral("photoMeteringMode"),          kli18nc("@label EXIF", "Metering Mode"),               QVariant::Int },
0077     PropertyInfoData{ Property::PhotoPixelXDimension,       false, QStringLiteral("photoPixelXDimension"),       kli18nc("@label EXIF", "X Dimension"),                 QVariant::Int },
0078     PropertyInfoData{ Property::PhotoPixelYDimension,       false, QStringLiteral("photoPixelYDimension"),       kli18nc("@label EXIF", "Y Dimension"),                 QVariant::Int },
0079     PropertyInfoData{ Property::PhotoSaturation,            false, QStringLiteral("photoSaturation"),            kli18nc("@label EXIF", "Saturation"),                  QVariant::Int },
0080     PropertyInfoData{ Property::PhotoSharpness,             false, QStringLiteral("photoSharpness"),             kli18nc("@label EXIF", "Sharpness"),                   QVariant::Int },
0081     PropertyInfoData{ Property::PhotoWhiteBalance,          false, QStringLiteral("photoWhiteBalance"),          kli18nc("@label EXIF", "White Balance"),               QVariant::Int },
0082     PropertyInfoData{ Property::Publisher,                  true,  QStringLiteral("publisher"),                  kli18nc("@label", "Publisher"),                        QVariant::String },
0083     PropertyInfoData{ Property::Label,                      true,  QStringLiteral("label"),                      kli18nc("@label", "Label"),                            QVariant::String },
0084     PropertyInfoData{ Property::ReleaseYear,                false, QStringLiteral("releaseYear"),                kli18nc("@label", "Release Year"),                     QVariant::Int },
0085     PropertyInfoData{ Property::SampleRate,                 false, QStringLiteral("sampleRate"),                 kli18nc("@label", "Sample Rate"),                      QVariant::Int,      FormatStrings::formatSampleRate },
0086     PropertyInfoData{ Property::Subject,                    false, QStringLiteral("subject"),                    kli18nc("@label", "Subject"),                          QVariant::String },
0087     PropertyInfoData{ Property::Title,                      true,  QStringLiteral("title"),                      kli18nc("@label", "Title"),                            QVariant::String },
0088     PropertyInfoData{ Property::TrackNumber,                false, QStringLiteral("trackNumber"),                kli18nc("@label music track number", "Track Number"),  QVariant::Int },
0089     PropertyInfoData{ Property::DiscNumber,                 false, QStringLiteral("discNumber"),                 kli18nc("@label music disc number", "Disc Number"),    QVariant::Int },
0090     PropertyInfoData{ Property::Location,                   true,  QStringLiteral("location"),                   kli18nc("@label", "Location"),                         QVariant::String },
0091     PropertyInfoData{ Property::Performer,                  true,  QStringLiteral("performer"),                  kli18nc("@label", "Performer"),                        QVariant::String },
0092     PropertyInfoData{ Property::Ensemble,                   true,  QStringLiteral("ensemble"),                   kli18nc("@label", "Ensemble"),                         QVariant::String },
0093     PropertyInfoData{ Property::Arranger,                   true,  QStringLiteral("arranger"),                   kli18nc("@label", "Arranger"),                         QVariant::String },
0094     PropertyInfoData{ Property::Conductor,                  true,  QStringLiteral("conductor"),                  kli18nc("@label", "Conductor"),                        QVariant::String },
0095     PropertyInfoData{ Property::Compilation,                true,  QStringLiteral("compilation"),                kli18nc("@label", "Compilation"),                      QVariant::String },
0096     PropertyInfoData{ Property::License,                    true,  QStringLiteral("license"),                    kli18nc("@label", "License"),                          QVariant::String },
0097     PropertyInfoData{ Property::Lyrics,                     true,  QStringLiteral("lyrics"),                     kli18nc("@label", "Lyrics"),                           QVariant::String },
0098     PropertyInfoData{ Property::Opus,                       false, QStringLiteral("opus"),                       kli18nc("@label", "Opus"),                             QVariant::Int },
0099     PropertyInfoData{ Property::Rating,                     false, QStringLiteral("embeddedRating"),             kli18nc("@label", "Rating"),                           QVariant::Int },
0100     PropertyInfoData{ Property::ReplayGainAlbumPeak,        false, QStringLiteral("replayGainAlbumPeak"),        kli18nc("@label ReplayGain is the name of a standard", "ReplayGain Album Peak"),           QVariant::Double, FormatStrings::formatDouble },
0101     PropertyInfoData{ Property::ReplayGainAlbumGain,        false, QStringLiteral("replayGainAlbumGain"),        kli18nc("@label ReplayGain is the name of a standard", "ReplayGain Album Gain"),           QVariant::Double, FormatStrings::formatDouble },
0102     PropertyInfoData{ Property::ReplayGainTrackPeak,        false, QStringLiteral("replayGainTrackPeak"),        kli18nc("@label ReplayGain is the name of a standard", "ReplayGain Track Peak"),           QVariant::Double, FormatStrings::formatDouble },
0103     PropertyInfoData{ Property::ReplayGainTrackGain,        false, QStringLiteral("replayGainTrackGain"),        kli18nc("@label ReplayGain is the name of a standard", "ReplayGain Track Gain"),           QVariant::Double, FormatStrings::formatDouble },
0104     PropertyInfoData{ Property::Width,                      false, QStringLiteral("width"),                      kli18nc("@label", "Width"),                            QVariant::Int },
0105     PropertyInfoData{ Property::WordCount,                  false, QStringLiteral("wordCount"),                  kli18nc("@label number of words", "Word Count"),       QVariant::Int },
0106     PropertyInfoData{ Property::TranslationUnitsTotal,                false, QStringLiteral("translationUnitsTotal"),                kli18nc("@label number of translatable strings", "Translatable Units"),      QVariant::Int },
0107     PropertyInfoData{ Property::TranslationUnitsWithTranslation,      false, QStringLiteral("translationUnitsWithTranslation"),      kli18nc("@label number of translated strings", "Translations"),              QVariant::Int },
0108     PropertyInfoData{ Property::TranslationUnitsWithDraftTranslation, false, QStringLiteral("translationUnitsWithDraftTranslation"), kli18nc("@label number of fuzzy translated strings", "Draft Translations"),  QVariant::Int },
0109     PropertyInfoData{ Property::TranslationLastAuthor,                false, QStringLiteral("translationLastAuthor"),                kli18nc("@label translation author", "Author"),                              QVariant::String },
0110     PropertyInfoData{ Property::TranslationLastUpDate,                false, QStringLiteral("translationLastUpDate"),                kli18nc("@label translations last update", "Last Update"),                   QVariant::String, FormatStrings::formatDate },
0111     PropertyInfoData{ Property::TranslationTemplateDate,              false, QStringLiteral("translationTemplateDate"),              kli18nc("@label date of template creation8", "Template Creation"),           QVariant::String, FormatStrings::formatDate },
0112     PropertyInfoData{ Property::OriginUrl,                  false, QStringLiteral("originUrl"),                  kli18nc("@label the URL a file was originally downloaded from", "Downloaded From"),                     QVariant::Url },
0113     PropertyInfoData{ Property::OriginEmailSubject,         false, QStringLiteral("originEmailSubject"),         kli18nc("@label the subject of an email this file was attached to", "E-Mail Attachment Subject"),       QVariant::String },
0114     PropertyInfoData{ Property::OriginEmailSender,          false, QStringLiteral("originEmailSender"),          kli18nc("@label the sender of an email this file was attached to", "E-Mail Attachment Sender"),         QVariant::String },
0115     PropertyInfoData{ Property::OriginEmailMessageId,       false, QStringLiteral("originEmailMessageId"),       kli18nc("@label the message ID of an email this file was attached to", "E-Mail Attachment Message ID"), QVariant::String }
0116 };
0117 
0118 namespace {
0119      auto constexpr propertyDataById(Property::Property property) {
0120          for (const auto& p : staticPropertyInfo) {
0121              if (p.prop == property)
0122                  return &p;
0123          }
0124          return &staticEmptyPropertyInfo;
0125      }
0126 }
0127 
0128 PropertyInfo::PropertyInfo(Property::Property property) : d(propertyDataById(property)) {};
0129 
0130 PropertyInfo::PropertyInfo() : d(&staticEmptyPropertyInfo) {};
0131 
0132 PropertyInfo::PropertyInfo(const PropertyInfo& pi)
0133     : d(pi.d)
0134 {
0135 }
0136 
0137 PropertyInfo::~PropertyInfo() = default;
0138 
0139 PropertyInfo& PropertyInfo::operator=(const PropertyInfo& rhs)
0140 {
0141     d = rhs.d;
0142     return *this;
0143 }
0144 
0145 bool PropertyInfo::operator==(const PropertyInfo& rhs) const
0146 {
0147     return d == rhs.d;
0148 }
0149 
0150 QString PropertyInfo::displayName() const
0151 {
0152     return d->displayName.toString();
0153 }
0154 
0155 QString PropertyInfo::name() const
0156 {
0157     return d->name;
0158 }
0159 
0160 Property::Property PropertyInfo::property() const
0161 {
0162     return d->prop;
0163 }
0164 
0165 QVariant::Type PropertyInfo::valueType() const
0166 {
0167     return d->valueType;
0168 }
0169 
0170 bool PropertyInfo::shouldBeIndexed() const
0171 {
0172     return d->shouldBeIndexed;
0173 }
0174 
0175 QString PropertyInfo::formatAsDisplayString(const QVariant &value) const
0176 {
0177     if (value.type() == QVariant::List || value.type() == QVariant::StringList) {
0178         if (d->valueType == QVariant::String) {
0179             return QLocale().createSeparatedList(value.toStringList());
0180         } else {
0181             QStringList displayList;
0182             const auto valueList = value.toList();
0183             for (const auto& entry : valueList) {
0184                 displayList << d->formatAsString(entry);
0185             }
0186             return QLocale().createSeparatedList(displayList);
0187         }
0188     } else {
0189         return d->formatAsString(value);
0190     }
0191 }
0192 
0193 namespace {
0194     class LcPropertyName
0195     {
0196     public:
0197         LcPropertyName(const QString& n) : name(n) {};
0198         QString name;
0199     };
0200 
0201     constexpr QChar trivialToLower(const QChar &c) {
0202         if (c.isUpper()) {
0203             return QChar::fromLatin1(c.toLatin1() ^ ('a' ^ 'A'));
0204         }
0205         return c;
0206     }
0207 
0208     inline bool operator==(const LcPropertyName &a, const LcPropertyName &b)
0209     {
0210         if (a.name.size() != b.name.size()) {
0211             return false;
0212         }
0213         for (int i = 0; i < a.name.size(); i++) {
0214             if ((a.name[i] != b.name[i]) && (trivialToLower(a.name[i]) != trivialToLower(b.name[i]))) {
0215                 return false;
0216             }
0217         }
0218         return true;
0219     }
0220 
0221     inline size_t qHash(const LcPropertyName &key, size_t seed = 0)
0222     {
0223         size_t val = seed;
0224         for (const auto& c : key.name) {
0225             val ^= qHash(trivialToLower(c));
0226         }
0227         return val;
0228     }
0229 
0230     static const QHash<LcPropertyName, PropertyInfo> propertyHash = []() {
0231         QHash<LcPropertyName, PropertyInfo> infoHash;
0232         infoHash.reserve(staticPropertyInfo.size());
0233 
0234         for (const auto& info: staticPropertyInfo) {
0235             infoHash[info.name] = info.prop;
0236         }
0237         return infoHash;
0238     }();
0239 }
0240 
0241 PropertyInfo PropertyInfo::fromName(const QString& name)
0242 {
0243     return propertyHash.value(LcPropertyName(name));
0244 }
0245 
0246 QStringList PropertyInfo::allNames()
0247 {
0248     static QStringList sNames = []() {
0249         QStringList names;
0250         names.reserve(staticPropertyInfo.size());
0251         for (auto info: staticPropertyInfo) {
0252             names.append(info.name);
0253         }
0254         return names;
0255     }();
0256     return sNames;
0257 }