File indexing completed on 2024-06-23 05:06:55

0001 /*
0002     SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "akonadicore_export.h"
0010 #include "attribute.h"
0011 
0012 #include <QDebug>
0013 #include <QSharedPointer>
0014 #include <QString>
0015 #include <QUrl>
0016 
0017 namespace Akonadi
0018 {
0019 class TagModifyJob;
0020 class TagPrivate;
0021 
0022 /**
0023  * An Akonadi Tag.
0024  */
0025 class AKONADICORE_EXPORT Tag
0026 {
0027 public:
0028     using List = QList<Tag>;
0029     using Id = qint64;
0030 
0031     /**
0032      * The PLAIN type has the following properties:
0033      * * gid == displayName
0034      * * immutable
0035      * * no hierarchy (no parent)
0036      *
0037      * PLAIN tags are general purpose tags that are easy to map by backends.
0038      */
0039     static const char PLAIN[];
0040 
0041     /**
0042      * The GENERIC type has the following properties:
0043      * * mutable
0044      * * gid is RFC 4122 compatible
0045      * * no hierarchy (no parent)
0046      *
0047      * GENERIC tags are general purpose tags, that are used, if you can change tag name.
0048      */
0049     static const char GENERIC[];
0050 
0051     Tag();
0052     explicit Tag(Id id);
0053     /**
0054      * Creates a PLAIN tag
0055      */
0056     explicit Tag(const QString &name);
0057 
0058     Tag(const Tag &);
0059 
0060     Tag(Tag &&) noexcept;
0061 
0062     ~Tag();
0063 
0064     Tag &operator=(const Tag &);
0065     Tag &operator=(Tag &&) noexcept;
0066     // Avoid slicing
0067     bool operator==(const Tag &) const;
0068     bool operator!=(const Tag &) const;
0069 
0070     static Tag fromUrl(const QUrl &url);
0071 
0072     /**
0073      * Adds an attribute to the entity.
0074      *
0075      * If an attribute of the same type name already exists, it is deleted and
0076      * replaced with the new one.
0077      *
0078      * @param attribute The new attribute.
0079      *
0080      * @note The entity takes the ownership of the attribute.
0081      */
0082     void addAttribute(Attribute *attribute);
0083 
0084     /**
0085      * Removes and deletes the attribute of the given type @p name.
0086      */
0087     void removeAttribute(const QByteArray &name);
0088 
0089     /**
0090      * Returns @c true if the entity has an attribute of the given type @p name,
0091      * false otherwise.
0092      */
0093     bool hasAttribute(const QByteArray &name) const;
0094 
0095     /**
0096      * Returns a list of all attributes of the entity.
0097      */
0098     Attribute::List attributes() const;
0099 
0100     /**
0101      * Removes and deletes all attributes of the entity.
0102      */
0103     void clearAttributes();
0104 
0105     /**
0106      * Returns the attribute of the given type @p name if available, 0 otherwise.
0107      */
0108     const Attribute *attribute(const QByteArray &name) const;
0109     Attribute *attribute(const QByteArray &name);
0110 
0111     /**
0112      * Describes the options that can be passed to access attributes.
0113      */
0114     enum CreateOption {
0115         AddIfMissing, ///< Creates the attribute if it is missing
0116         DontCreate ///< Does not create an attribute if it is missing (default)
0117     };
0118 
0119     /**
0120      * Returns the attribute of the requested type.
0121      * If the entity has no attribute of that type yet, a new one
0122      * is created and added to the entity.
0123      *
0124      * @param option The create options.
0125      */
0126     template<typename T>
0127     inline T *attribute(CreateOption option = DontCreate);
0128 
0129     /**
0130      * Returns the attribute of the requested type or 0 if it is not available.
0131      */
0132     template<typename T>
0133     inline const T *attribute() const;
0134 
0135     /**
0136      * Removes and deletes the attribute of the requested type.
0137      */
0138     template<typename T>
0139     inline void removeAttribute();
0140 
0141     /**
0142      * Returns whether the entity has an attribute of the requested type.
0143      */
0144     template<typename T>
0145     inline bool hasAttribute() const;
0146 
0147     /**
0148      * Returns the url of the tag.
0149      */
0150     QUrl url() const;
0151 
0152     /**
0153      * Sets the unique @p identifier of the tag.
0154      */
0155     void setId(Id identifier);
0156 
0157     /**
0158      * Returns the unique identifier of the tag.
0159      */
0160     Id id() const;
0161 
0162     void setGid(const QByteArray &gid);
0163     QByteArray gid() const;
0164 
0165     void setRemoteId(const QByteArray &remoteId);
0166     QByteArray remoteId() const;
0167 
0168     void setType(const QByteArray &type);
0169     QByteArray type() const;
0170 
0171     void setName(const QString &name);
0172     QString name() const;
0173 
0174     void setParent(const Tag &parent);
0175     Tag parent() const;
0176 
0177     bool isValid() const;
0178 
0179     /**
0180      * Returns true if the tag is immutable (cannot be modified after creation).
0181      * Note that the immutability does not affect the attributes.
0182      */
0183     bool isImmutable() const;
0184 
0185     /**
0186      * Returns a GENERIC tag with the given name and a valid gid
0187      */
0188     static Tag genericTag(const QString &name);
0189 
0190 private:
0191     bool checkAttribute(const Attribute *attr, const QByteArray &type) const;
0192     void markAttributeModified(const QByteArray &type);
0193 
0194     /// @cond PRIVATE
0195     friend class TagModifyJob;
0196     friend class TagFetchJob;
0197     friend class ProtocolHelper;
0198 
0199     QSharedDataPointer<TagPrivate> d_ptr;
0200     /// @endcond
0201 };
0202 
0203 AKONADICORE_EXPORT size_t qHash(const Akonadi::Tag &, size_t sed = 0) noexcept;
0204 
0205 template<typename T>
0206 inline T *Tag::attribute(CreateOption option)
0207 {
0208     const QByteArray type = T().type();
0209     markAttributeModified(type);
0210     if (hasAttribute(type)) {
0211         T *attr = dynamic_cast<T *>(attribute(type));
0212         if (checkAttribute(attr, type)) {
0213             return attr;
0214         }
0215     } else if (option == AddIfMissing) {
0216         T *attr = new T();
0217         addAttribute(attr);
0218         return attr;
0219     }
0220 
0221     return nullptr;
0222 }
0223 
0224 template<typename T>
0225 inline const T *Tag::attribute() const
0226 {
0227     const QByteArray type = T().type();
0228     if (hasAttribute(type)) {
0229         const T *attr = dynamic_cast<const T *>(attribute(type));
0230         if (checkAttribute(attr, type)) {
0231             return attr;
0232         }
0233     }
0234 
0235     return nullptr;
0236 }
0237 
0238 template<typename T>
0239 inline void Tag::removeAttribute()
0240 {
0241     const T dummy;
0242     removeAttribute(dummy.type());
0243 }
0244 
0245 template<typename T>
0246 inline bool Tag::hasAttribute() const
0247 {
0248     const T dummy;
0249     return hasAttribute(dummy.type());
0250 }
0251 
0252 } // namespace Akonadi
0253 
0254 AKONADICORE_EXPORT QDebug operator<<(QDebug debug, const Akonadi::Tag &tag);
0255 
0256 Q_DECLARE_METATYPE(Akonadi::Tag)
0257 Q_DECLARE_METATYPE(Akonadi::Tag::List)
0258 Q_DECLARE_METATYPE(QSet<Akonadi::Tag>)
0259 Q_DECLARE_TYPEINFO(Akonadi::Tag, Q_RELOCATABLE_TYPE);