File indexing completed on 2024-05-12 05:47:29

0001 /*
0002  * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
0003  * SPDX-FileCopyrightText: 2013 Vishesh Handa <me@vhanda.in>
0004  *
0005  * SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "kbaloorolesprovider.h"
0009 
0010 #include <Baloo/File>
0011 #include <KFileMetaData/PropertyInfo>
0012 #include <KFileMetaData/UserMetaData>
0013 
0014 #include <QCollator>
0015 #include <QSize>
0016 
0017 namespace
0018 {
0019 QString tagsFromValues(const QStringList &values)
0020 {
0021     if (values.size() == 1) {
0022         return values.at(0);
0023     }
0024 
0025     QStringList alphabeticalOrderTags = values;
0026     QCollator coll;
0027     coll.setNumericMode(true);
0028     std::sort(alphabeticalOrderTags.begin(), alphabeticalOrderTags.end(), [&](const QString &s1, const QString &s2) {
0029         return coll.compare(s1, s2) < 0;
0030     });
0031     return alphabeticalOrderTags.join(QLatin1String(", "));
0032 }
0033 
0034     using Property = KFileMetaData::Property::Property;
0035     // Mapping from the KFM::Property to the KFileItemModel roles.
0036     const QHash<Property, QByteArray> propertyRoleMap() {
0037         static const auto map = QHash<Property, QByteArray> {
0038             { Property::Rating,            QByteArrayLiteral("rating") },
0039             { Property::Comment,           QByteArrayLiteral("comment") },
0040             { Property::Title,             QByteArrayLiteral("title") },
0041             { Property::Author,            QByteArrayLiteral("author") },
0042             { Property::Publisher,         QByteArrayLiteral("publisher") },
0043             { Property::PageCount,         QByteArrayLiteral("pageCount") },
0044             { Property::WordCount,         QByteArrayLiteral("wordCount") },
0045             { Property::LineCount,         QByteArrayLiteral("lineCount") },
0046             { Property::Width,             QByteArrayLiteral("width") },
0047             { Property::Height,            QByteArrayLiteral("height") },
0048             { Property::ImageDateTime,     QByteArrayLiteral("imageDateTime") },
0049             { Property::ImageOrientation,  QByteArrayLiteral("orientation") },
0050             { Property::Artist,            QByteArrayLiteral("artist") },
0051             { Property::Genre,             QByteArrayLiteral("genre")  },
0052             { Property::Album,             QByteArrayLiteral("album") },
0053             { Property::Duration,          QByteArrayLiteral("duration") },
0054             { Property::BitRate,           QByteArrayLiteral("bitrate") },
0055             { Property::AspectRatio,       QByteArrayLiteral("aspectRatio") },
0056             { Property::FrameRate,         QByteArrayLiteral("frameRate") },
0057             { Property::ReleaseYear,       QByteArrayLiteral("releaseYear") },
0058             { Property::TrackNumber,       QByteArrayLiteral("track") }
0059         };
0060         return map;
0061     }
0062 }
0063 
0064 struct KBalooRolesProviderSingleton {
0065     KBalooRolesProvider instance;
0066 };
0067 Q_GLOBAL_STATIC(KBalooRolesProviderSingleton, s_balooRolesProvider)
0068 
0069 KBalooRolesProvider &KBalooRolesProvider::instance()
0070 {
0071     return s_balooRolesProvider->instance;
0072 }
0073 
0074 KBalooRolesProvider::~KBalooRolesProvider()
0075 {
0076 }
0077 
0078 QSet<QByteArray> KBalooRolesProvider::roles() const
0079 {
0080     return m_roles;
0081 }
0082 
0083 QHash<QByteArray, QVariant> KBalooRolesProvider::roleValues(const Baloo::File &file, const QSet<QByteArray> &roles) const
0084 {
0085     QHash<QByteArray, QVariant> values;
0086 
0087     using entry = std::pair<const KFileMetaData::Property::Property &, const QVariant &>;
0088 
0089     const auto &propMap = file.properties();
0090     auto rangeBegin = propMap.constKeyValueBegin();
0091 
0092     while (rangeBegin != propMap.constKeyValueEnd()) {
0093         auto key = (*rangeBegin).first;
0094 
0095         auto rangeEnd = std::find_if(rangeBegin, propMap.constKeyValueEnd(), [key](const entry &e) {
0096             return e.first != key;
0097         });
0098 
0099         const QByteArray role = propertyRoleMap().value(key);
0100         if (role.isEmpty() || !roles.contains(role)) {
0101             rangeBegin = rangeEnd;
0102             continue;
0103         }
0104 
0105         const KFileMetaData::PropertyInfo propertyInfo(key);
0106         auto distance = std::distance(rangeBegin, rangeEnd);
0107         if (distance > 1) {
0108             QVariantList list;
0109             list.reserve(static_cast<int>(distance));
0110             std::for_each(rangeBegin, rangeEnd, [&list](const entry &s) {
0111                 list.append(s.second);
0112             });
0113             values.insert(role, propertyInfo.formatAsDisplayString(list));
0114         } else {
0115             if (propertyInfo.valueType() == QMetaType::Type::QDateTime) {
0116                 // Let dolphin format later Dates
0117                 values.insert(role, (*rangeBegin).second);
0118             } else {
0119                 values.insert(role, propertyInfo.formatAsDisplayString((*rangeBegin).second));
0120             }
0121         }
0122         rangeBegin = rangeEnd;
0123     }
0124 
0125     if (roles.contains("dimensions")) {
0126         bool widthOk = false;
0127         bool heightOk = false;
0128 
0129         const int width = propMap.value(KFileMetaData::Property::Width).toInt(&widthOk);
0130         const int height = propMap.value(KFileMetaData::Property::Height).toInt(&heightOk);
0131 
0132         if (widthOk && heightOk && width >= 0 && height >= 0) {
0133             values.insert("dimensions", QSize(width, height));
0134         }
0135     }
0136 
0137     KFileMetaData::UserMetaData::Attributes attributes;
0138     if (roles.contains("tags")) {
0139         attributes |= KFileMetaData::UserMetaData::Tags;
0140     }
0141     if (roles.contains("rating")) {
0142         attributes |= KFileMetaData::UserMetaData::Rating;
0143     }
0144     if (roles.contains("comment")) {
0145         attributes |= KFileMetaData::UserMetaData::Comment;
0146     }
0147     if (roles.contains("originUrl")) {
0148         attributes |= KFileMetaData::UserMetaData::OriginUrl;
0149     }
0150 
0151     if (attributes == KFileMetaData::UserMetaData::None) {
0152         return values;
0153     }
0154 
0155     KFileMetaData::UserMetaData md(file.path());
0156     attributes = md.queryAttributes(attributes);
0157 
0158     if (attributes & KFileMetaData::UserMetaData::Tags) {
0159         values.insert("tags", tagsFromValues(md.tags()));
0160     }
0161     if (attributes & KFileMetaData::UserMetaData::Rating) {
0162         values.insert("rating", QString::number(md.rating()));
0163     }
0164     if (attributes & KFileMetaData::UserMetaData::Comment) {
0165         values.insert("comment", md.userComment());
0166     }
0167     if (attributes & KFileMetaData::UserMetaData::OriginUrl) {
0168         values.insert("originUrl", md.originUrl());
0169     }
0170 
0171     return values;
0172 }
0173 
0174 KBalooRolesProvider::KBalooRolesProvider()
0175 {
0176     // Display roles filled from Baloo property cache
0177     for (const auto &role : propertyRoleMap()) {
0178         m_roles.insert(role);
0179     }
0180     m_roles.insert("dimensions");
0181 
0182     // Display roles provided by UserMetaData
0183     m_roles.insert(QByteArrayLiteral("tags"));
0184     m_roles.insert(QByteArrayLiteral("rating"));
0185     m_roles.insert(QByteArrayLiteral("comment"));
0186     m_roles.insert(QByteArrayLiteral("originUrl"));
0187 }