File indexing completed on 2024-12-08 04:18:15

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef WIKIDATA_ITEM_H
0008 #define WIKIDATA_ITEM_H
0009 
0010 #include <QColor>
0011 #include <QDebug>
0012 #include <QJsonObject>
0013 #include <QMetaType>
0014 #include <QVariant>
0015 
0016 #include <cstdint>
0017 #include <vector>
0018 
0019 namespace Wikidata {
0020 
0021 template <typename T, char Prefix>
0022 class Identifier
0023 {
0024 public:
0025     explicit inline constexpr Identifier() {}
0026     explicit inline constexpr Identifier(T id) : m_id(id) {}
0027     explicit inline Identifier(const QString &id) : m_id(fromString(id).m_id) {}
0028     explicit inline Identifier(const QByteArray &id) : m_id(fromString(id).m_id) {}
0029 
0030     inline constexpr bool isValid() const
0031     {
0032         return m_id > 0;
0033     }
0034 
0035     inline constexpr bool operator<(Identifier other) const
0036     {
0037         return m_id < other.m_id;
0038     }
0039     inline constexpr bool operator==(Identifier other) const
0040     {
0041         return m_id == other.m_id;
0042     }
0043     inline constexpr bool operator!=(Identifier other) const
0044     {
0045         return m_id != other.m_id;
0046     }
0047 
0048     inline QString toString() const
0049     {
0050         return QLatin1Char(Prefix) + QString::number(m_id);
0051     }
0052 
0053 protected:
0054     T m_id = 0;
0055 
0056 private:
0057     static inline Identifier fromString(const QString &id)
0058     {
0059         if (!id.startsWith(QLatin1Char(Prefix))) {
0060             return Identifier();
0061         }
0062         return Identifier(QStringView(id).mid(1).toULongLong());
0063     }
0064     static inline Identifier fromString(const QByteArray &id)
0065     {
0066         if (!id.startsWith(Prefix)) {
0067             return Identifier();
0068         }
0069         return Identifier(id.mid(1).toULongLong());
0070     }
0071 };
0072 
0073 /** Wikidata item identifier. */
0074 class Q : public Identifier<uint64_t, 'Q'>
0075 {
0076 public:
0077     explicit inline constexpr Q() = default;
0078     explicit inline constexpr Q(uint64_t id) : Identifier(id) {}
0079     explicit inline Q(const QString &id) : Identifier(id) {}
0080     explicit inline Q(const QByteArray &id) : Identifier(id) {}
0081 };
0082 
0083 /** Wikidata property identifier. */
0084 class P : public Identifier<uint32_t, 'P'>
0085 {
0086 public:
0087     enum Property : uint32_t {
0088         instanceOf = 31,
0089         logoImage = 154,
0090         partOf = 361,
0091     };
0092 
0093     explicit inline constexpr P() = default;
0094     /* implicit */ inline constexpr P(Property id) : Identifier(id) {}
0095     explicit inline constexpr P(uint32_t id) : Identifier(id) {}
0096     explicit inline P(const QString &id) : Identifier(id) {}
0097 };
0098 
0099 /** Wikidata item. */
0100 class Item
0101 {
0102 public:
0103     explicit Item();
0104     explicit Item(Q id, const QJsonObject &data);
0105     ~Item();
0106 
0107     inline constexpr bool isValid() const { return m_id.isValid(); }
0108     inline constexpr Q id() const { return m_id; }
0109 
0110     template <typename T>
0111     inline T value(P property) const
0112     {
0113         return convertValue<T>(value(property));
0114     }
0115 
0116     template <typename T>
0117     inline std::vector<T> values(P property) const
0118     {
0119         const auto vals = values(property);
0120         std::vector<T> v;
0121         v.reserve(vals.size());
0122         std::transform(vals.begin(), vals.end(), std::back_inserter(v), [](const QVariant &value) { return convertValue<T>(value); });
0123         return v;
0124     }
0125 
0126 private:
0127     std::vector<QVariant> values(P property) const;
0128     QVariant value(P property) const;
0129 
0130     template <typename T>
0131     static inline T convertValue(const QVariant &v)
0132     {
0133         return v.value<T>();
0134     }
0135 
0136     Q m_id;
0137     QJsonObject m_data;
0138 };
0139 
0140 template <>
0141 inline QColor Item::convertValue<QColor>(const QVariant &v)
0142 {
0143     const auto s = v.toString();
0144     if (s.size() == 6) {
0145         return QColor(QLatin1Char('#') + s);
0146     }
0147     return QColor(s);
0148 }
0149 
0150 /** Commons image metadata. */
0151 class Image
0152 {
0153 public:
0154     explicit Image();
0155     explicit Image(const QJsonObject &obj);
0156     ~Image();
0157 
0158     QString name() const;
0159     uint64_t fileSize() const;
0160     uint32_t width() const;
0161     uint32_t height() const;
0162     QString mimeType() const;
0163     QString license() const;
0164 
0165 private:
0166     QJsonObject imageInfo() const;
0167     QJsonObject m_data;
0168 };
0169 
0170 }
0171 
0172 Q_DECLARE_METATYPE(Wikidata::Q)
0173 Q_DECLARE_METATYPE(Wikidata::P)
0174 
0175 template <typename T, char Prefix>
0176 inline QDebug operator<<(QDebug debug, Wikidata::Identifier<T, Prefix> id)
0177 {
0178     QDebugStateSaver saver(debug);
0179     if (id.isValid()) {
0180         debug.noquote().nospace() << QStringLiteral("https://www.wikidata.org/wiki/") + id.toString();
0181     }
0182     return debug;
0183 }
0184 
0185 #endif // WIKIDATA_ITEM_H