-/***************************************************************************
- * Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
- * Copyright (C) 2013 by Vishesh Handa <me@vhanda.in> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
- ***************************************************************************/
+/*
+ * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
+ * SPDX-FileCopyrightText: 2013 Vishesh Handa <me@vhanda.in>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "kbaloorolesprovider.h"
-#include <QDebug>
-#include <KGlobal>
-#include <KLocalizedString>
-
#include <Baloo/File>
#include <KFileMetaData/PropertyInfo>
#include <KFileMetaData/UserMetaData>
-#include <QTime>
-#include <QMap>
+#include <QCollator>
+#include <QSize>
-struct KBalooRolesProviderSingleton
+namespace
+{
+QString tagsFromValues(const QStringList &values)
{
+ if (values.size() == 1) {
+ return values.at(0);
+ }
+
+ QStringList alphabeticalOrderTags = values;
+ QCollator coll;
+ coll.setNumericMode(true);
+ std::sort(alphabeticalOrderTags.begin(), alphabeticalOrderTags.end(), [&](const QString &s1, const QString &s2) {
+ return coll.compare(s1, s2) < 0;
+ });
+ return alphabeticalOrderTags.join(QLatin1String(", "));
+}
+
+ using Property = KFileMetaData::Property::Property;
+ // Mapping from the KFM::Property to the KFileItemModel roles.
+ const QHash<Property, QByteArray> propertyRoleMap() {
+ static const auto map = QHash<Property, QByteArray> {
+ { Property::Rating, QByteArrayLiteral("rating") },
+ { Property::Comment, QByteArrayLiteral("comment") },
+ { Property::Title, QByteArrayLiteral("title") },
+ { Property::Author, QByteArrayLiteral("author") },
+ { Property::Publisher, QByteArrayLiteral("publisher") },
+ { Property::PageCount, QByteArrayLiteral("pageCount") },
+ { Property::WordCount, QByteArrayLiteral("wordCount") },
+ { Property::LineCount, QByteArrayLiteral("lineCount") },
+ { Property::Width, QByteArrayLiteral("width") },
+ { Property::Height, QByteArrayLiteral("height") },
+ { Property::ImageDateTime, QByteArrayLiteral("imageDateTime") },
+ { Property::ImageOrientation, QByteArrayLiteral("orientation") },
+ { Property::Artist, QByteArrayLiteral("artist") },
+ { Property::Genre, QByteArrayLiteral("genre") },
+ { Property::Album, QByteArrayLiteral("album") },
+ { Property::Duration, QByteArrayLiteral("duration") },
+ { Property::BitRate, QByteArrayLiteral("bitrate") },
+ { Property::AspectRatio, QByteArrayLiteral("aspectRatio") },
+ { Property::FrameRate, QByteArrayLiteral("frameRate") },
+ { Property::ReleaseYear, QByteArrayLiteral("releaseYear") },
+ { Property::TrackNumber, QByteArrayLiteral("track") }
+ };
+ return map;
+ }
+}
+
+struct KBalooRolesProviderSingleton {
KBalooRolesProvider instance;
};
-K_GLOBAL_STATIC(KBalooRolesProviderSingleton, s_balooRolesProvider)
+Q_GLOBAL_STATIC(KBalooRolesProviderSingleton, s_balooRolesProvider)
-
-KBalooRolesProvider& KBalooRolesProvider::instance()
+KBalooRolesProvider &KBalooRolesProvider::instance()
{
return s_balooRolesProvider->instance;
}
return m_roles;
}
-QHash<QByteArray, QVariant> KBalooRolesProvider::roleValues(const Baloo::File& file,
- const QSet<QByteArray>& roles) const
+QHash<QByteArray, QVariant> KBalooRolesProvider::roleValues(const Baloo::File &file, const QSet<QByteArray> &roles) const
{
QHash<QByteArray, QVariant> values;
- int width = -1;
- int height = -1;
+ using entry = std::pair<const KFileMetaData::Property::Property &, const QVariant &>;
+
+ const auto &propMap = file.properties();
+ auto rangeBegin = propMap.constKeyValueBegin();
+
+ while (rangeBegin != propMap.constKeyValueEnd()) {
+ auto key = (*rangeBegin).first;
- QMapIterator<KFileMetaData::Property::Property, QVariant> it(file.properties());
- while (it.hasNext()) {
- it.next();
+ auto rangeEnd = std::find_if(rangeBegin, propMap.constKeyValueEnd(), [key](const entry &e) {
+ return e.first != key;
+ });
- const KFileMetaData::PropertyInfo pi(it.key());
- const QString property = pi.name();
- const QByteArray role = roleForProperty(property);
+ const QByteArray role = propertyRoleMap().value(key);
if (role.isEmpty() || !roles.contains(role)) {
+ rangeBegin = rangeEnd;
continue;
}
- const QVariant value = it.value();
-
- if (role == "imageSize") {
- // Merge the two properties for width and height
- // as one string into the "imageSize" role
- if (property == QLatin1String("width")) {
- width = value.toInt();
- }
- else if (property == QLatin1String("height")) {
- height = value.toInt();
+ const KFileMetaData::PropertyInfo propertyInfo(key);
+ auto distance = std::distance(rangeBegin, rangeEnd);
+ if (distance > 1) {
+ QVariantList list;
+ list.reserve(static_cast<int>(distance));
+ std::for_each(rangeBegin, rangeEnd, [&list](const entry &s) {
+ list.append(s.second);
+ });
+ values.insert(role, propertyInfo.formatAsDisplayString(list));
+ } else {
+ if (propertyInfo.valueTypeId() == QMetaType::Type::DateTime) {
+ // Let dolphin format later Dates
+ values.insert(role, (*rangeBegin).second);
+ } else {
+ values.insert(role, propertyInfo.formatAsDisplayString((*rangeBegin).second));
}
+ }
+ rangeBegin = rangeEnd;
+ }
- if (width >= 0 && height >= 0) {
- QString widthAndHeight = QString::number(width);
- widthAndHeight += QLatin1String(" x ");
- widthAndHeight += QString::number(height);
- values.insert(role, widthAndHeight);
- }
- } else if (role == "orientation") {
- const QString orientation = orientationFromValue(value.toInt());
- values.insert(role, orientation);
- } else if (role == "duration") {
- const QString duration = durationFromValue(value.toInt());
- values.insert(role, duration);
- } else {
- values.insert(role, value.toString());
+ if (roles.contains("dimensions")) {
+ bool widthOk = false;
+ bool heightOk = false;
+
+ const int width = propMap.value(KFileMetaData::Property::Width).toInt(&widthOk);
+ const int height = propMap.value(KFileMetaData::Property::Height).toInt(&heightOk);
+
+ if (widthOk && heightOk && width >= 0 && height >= 0) {
+ values.insert("dimensions", QSize(width, height));
}
}
- KFileMetaData::UserMetaData md(file.path());
+ KFileMetaData::UserMetaData::Attributes attributes;
if (roles.contains("tags")) {
- values.insert("tags", tagsFromValues(md.tags()));
+ attributes |= KFileMetaData::UserMetaData::Tags;
}
if (roles.contains("rating")) {
- values.insert("rating", QString::number(md.rating()));
+ attributes |= KFileMetaData::UserMetaData::Rating;
}
if (roles.contains("comment")) {
- values.insert("comment", md.userComment());
+ attributes |= KFileMetaData::UserMetaData::Comment;
+ }
+ if (roles.contains("originUrl")) {
+ attributes |= KFileMetaData::UserMetaData::OriginUrl;
}
- return values;
-}
+ if (attributes == KFileMetaData::UserMetaData::None) {
+ return values;
+ }
-QByteArray KBalooRolesProvider::roleForProperty(const QString& property) const
-{
- return m_roleForProperty.value(property);
-}
+ KFileMetaData::UserMetaData md(file.path());
+ attributes = md.queryAttributes(attributes);
-KBalooRolesProvider::KBalooRolesProvider() :
- m_roles(),
- m_roleForProperty()
-{
- struct PropertyInfo
- {
- const char* const property;
- const char* const role;
- };
-
- // Mapping from the URIs to the KFileItemModel roles. Note that this must not be
- // a 1:1 mapping: One role may contain several URI-values (e.g. the URIs for height and
- // width of an image are mapped to the role "imageSize")
- static const PropertyInfo propertyInfoList[] = {
- { "rating", "rating" },
- { "tag", "tags" },
- { "comment", "comment" },
- { "wordCount", "wordCount" },
- { "lineCount", "lineCount" },
- { "width", "imageSize" },
- { "height", "imageSize" },
- { "nexif.orientation", "orientation", },
- { "artist", "artist" },
- { "album", "album" },
- { "duration", "duration" },
- { "trackNumber", "track" }
- // { "http://www.semanticdesktop.org/ontologies/2010/04/30/ndo#copiedFrom", "copiedFrom" }
- };
-
- for (unsigned int i = 0; i < sizeof(propertyInfoList) / sizeof(PropertyInfo); ++i) {
- m_roleForProperty.insert(propertyInfoList[i].property, propertyInfoList[i].role);
- m_roles.insert(propertyInfoList[i].role);
+ if (attributes & KFileMetaData::UserMetaData::Tags) {
+ values.insert("tags", tagsFromValues(md.tags()));
+ }
+ if (attributes & KFileMetaData::UserMetaData::Rating) {
+ values.insert("rating", QString::number(md.rating()));
+ }
+ if (attributes & KFileMetaData::UserMetaData::Comment) {
+ values.insert("comment", md.userComment());
+ }
+ if (attributes & KFileMetaData::UserMetaData::OriginUrl) {
+ values.insert("originUrl", md.originUrl());
}
-}
-QString KBalooRolesProvider::tagsFromValues(const QStringList& values) const
-{
- return values.join(", ");
+ return values;
}
-QString KBalooRolesProvider::orientationFromValue(int value) const
+KBalooRolesProvider::KBalooRolesProvider()
{
- QString string;
- switch (value) {
- case 1: string = i18nc("@item:intable Image orientation", "Unchanged"); break;
- case 2: string = i18nc("@item:intable Image orientation", "Horizontally flipped"); break;
- case 3: string = i18nc("@item:intable image orientation", "180° rotated"); break;
- case 4: string = i18nc("@item:intable image orientation", "Vertically flipped"); break;
- case 5: string = i18nc("@item:intable image orientation", "Transposed"); break;
- case 6: string = i18nc("@item:intable image orientation", "90° rotated"); break;
- case 7: string = i18nc("@item:intable image orientation", "Transversed"); break;
- case 8: string = i18nc("@item:intable image orientation", "270° rotated"); break;
- default:
- break;
+ // Display roles filled from Baloo property cache
+ for (const auto &role : propertyRoleMap()) {
+ m_roles.insert(role);
}
- return string;
-}
+ m_roles.insert("dimensions");
-QString KBalooRolesProvider::durationFromValue(int value) const
-{
- QTime duration;
- duration = duration.addSecs(value);
- return duration.toString("hh:mm:ss");
+ // Display roles provided by UserMetaData
+ m_roles.insert(QByteArrayLiteral("tags"));
+ m_roles.insert(QByteArrayLiteral("rating"));
+ m_roles.insert(QByteArrayLiteral("comment"));
+ m_roles.insert(QByteArrayLiteral("originUrl"));
}
-