diff --git a/autotests/libs/collectionattributetest.cpp b/autotests/libs/collectionattributetest.cpp index e264a37a2..9c4656105 100644 --- a/autotests/libs/collectionattributetest.cpp +++ b/autotests/libs/collectionattributetest.cpp @@ -1,242 +1,257 @@ /* Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "collectionattributetest.h" #include "collectionpathresolver.h" #include #include #include #include #include #include #include #include #include #include using namespace Akonadi; QTEST_AKONADIMAIN(CollectionAttributeTest) class TestAttribute : public Attribute { public: TestAttribute() : Attribute() { } TestAttribute(const QByteArray &data) : mData(data) { } TestAttribute *clone() const override { return new TestAttribute(mData); } QByteArray type() const override { return "TESTATTRIBUTE"; } QByteArray serialized() const override { return mData; } void deserialize(const QByteArray &data) override { mData = data; } private: QByteArray mData; }; static int parentColId = -1; void CollectionAttributeTest::initTestCase() { AkonadiTest::checkTestIsIsolated(); Control::start(); AttributeFactory::registerAttribute(); CollectionPathResolver *resolver = new CollectionPathResolver(QStringLiteral("res3"), this); AKVERIFYEXEC(resolver); parentColId = resolver->collection(); QVERIFY(parentColId > 0); } void CollectionAttributeTest::testAttributes_data() { QTest::addColumn("attr1"); QTest::addColumn("attr2"); QTest::newRow("basic") << QByteArray("foo") << QByteArray("bar"); QTest::newRow("empty1") << QByteArray("") << QByteArray("non-empty"); #if 0 // This one is failing on the CI with SQLite. Can't reproduce locally and // it works with other DB backends, so I have no idea what is going on... QTest::newRow("empty2") << QByteArray("non-empty") << QByteArray(""); #endif QTest::newRow("space") << QByteArray("foo bar") << QByteArray("bar foo"); QTest::newRow("newline") << QByteArray("\n") << QByteArray("no newline"); QTest::newRow("newline2") << QByteArray(" \\\n\\\nnn") << QByteArray("no newline"); QTest::newRow("cr") << QByteArray("\r") << QByteArray("\\\r\n"); QTest::newRow("quotes") << QByteArray("\"quoted \\ test\"") << QByteArray("single \" quote \\"); QTest::newRow("parenthesis") << QByteArray(")") << QByteArray("("); QTest::newRow("binary") << QByteArray("\000") << QByteArray("\001"); } void CollectionAttributeTest::testAttributes() { QFETCH(QByteArray, attr1); QFETCH(QByteArray, attr2); struct Cleanup { Cleanup(const Collection &col) : m_col(col) {} ~Cleanup() { // cleanup CollectionDeleteJob *del = new CollectionDeleteJob(m_col); AKVERIFYEXEC(del); } Collection m_col; }; // add a custom attribute TestAttribute *attr = new TestAttribute(); attr->deserialize(attr1); Collection col; col.setName(QStringLiteral("attribute test")); col.setParentCollection(Collection(parentColId)); col.addAttribute(attr); CollectionCreateJob *create = new CollectionCreateJob(col, this); AKVERIFYEXEC(create); col = create->collection(); QVERIFY(col.isValid()); Cleanup cleanup(col); attr = col.attribute(); QVERIFY(attr != nullptr); QCOMPARE(attr->serialized(), QByteArray(attr1)); CollectionFetchJob *list = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(list); QCOMPARE(list->collections().count(), 1); col = list->collections().first(); QVERIFY(col.isValid()); attr = col.attribute(); QVERIFY(attr != nullptr); QCOMPARE(attr->serialized(), QByteArray(attr1)); TestAttribute *attrB = new TestAttribute(); attrB->deserialize(attr2); col.addAttribute(attrB); attrB = col.attribute(); QVERIFY(attrB != nullptr); QCOMPARE(attrB->serialized(), QByteArray(attr2)); attrB->deserialize(attr1); col.addAttribute(attrB); attrB = col.attribute(); QVERIFY(attrB != nullptr); QCOMPARE(attrB->serialized(), QByteArray(attr1)); // modify a custom attribute col.attribute(Collection::AddIfMissing)->deserialize(attr2); CollectionModifyJob *modify = new CollectionModifyJob(col, this); AKVERIFYEXEC(modify); list = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(list); QCOMPARE(list->collections().count(), 1); col = list->collections().first(); QVERIFY(col.isValid()); attr = col.attribute(); QVERIFY(attr != nullptr); QCOMPARE(attr->serialized(), QByteArray(attr2)); // delete a custom attribute col.removeAttribute(); modify = new CollectionModifyJob(col, this); AKVERIFYEXEC(modify); list = new CollectionFetchJob(col, CollectionFetchJob::Base, this); AKVERIFYEXEC(list); QCOMPARE(list->collections().count(), 1); col = list->collections().first(); QVERIFY(col.isValid()); attr = col.attribute(); QVERIFY(attr == nullptr); // Give the knut resource a bit of time to modify the collection and add a remote ID (after adding) // and reparent attributes (after modifying). // Otherwise we can delete it faster than it can do that, and we end up with a confusing warning // "No such collection" from the resource's modify job. QTest::qWait(100); // ideally we'd loop over "fetch and check there's a remote id" } void CollectionAttributeTest::testDefaultAttributes() { Collection col; QCOMPARE(col.attributes().count(), 0); Attribute *attr = AttributeFactory::createAttribute("TYPE"); QVERIFY(attr); attr->deserialize("VALUE"); col.addAttribute(attr); QCOMPARE(col.attributes().count(), 1); QVERIFY(col.hasAttribute("TYPE")); QCOMPARE(col.attribute("TYPE")->serialized(), QByteArray("VALUE")); } void CollectionAttributeTest::testCollectionRightsAttribute() { CollectionRightsAttribute attribute; Collection::Rights rights; QCOMPARE(attribute.rights(), rights); for (int mask = 0; mask <= Collection::AllRights; ++mask) { rights = Collection::AllRights; rights &= mask; QCOMPARE(rights, mask); attribute.setRights(rights); QCOMPARE(attribute.rights(), rights); QByteArray data = attribute.serialized(); attribute.deserialize(data); QCOMPARE(attribute.rights(), rights); } } void CollectionAttributeTest::testCollectionIdentificationAttribute() { QByteArray id("identifier"); QByteArray ns("namespace"); CollectionIdentificationAttribute attribute(id, ns); QCOMPARE(attribute.identifier(), id); QCOMPARE(attribute.collectionNamespace(), ns); QByteArray result = attribute.serialized(); CollectionIdentificationAttribute parsed; parsed.deserialize(result); qDebug() << parsed.identifier() << parsed.collectionNamespace() << result; QCOMPARE(parsed.identifier(), id); QCOMPARE(parsed.collectionNamespace(), ns); } + +void CollectionAttributeTest::testDetach() +{ + // GIVEN a collection with an attribute + Collection col; + col.attribute(Akonadi::Collection::AddIfMissing); + Collection col2 = col; // and a copy, so that non-const access detaches + + // WHEN + TestAttribute *attr = col2.attribute(Akonadi::Collection::AddIfMissing); + TestAttribute *attr2 = col2.attribute(); + + // THEN + QCOMPARE(attr, attr2); +} diff --git a/autotests/libs/collectionattributetest.h b/autotests/libs/collectionattributetest.h index 420df7894..2afa9ebb0 100644 --- a/autotests/libs/collectionattributetest.h +++ b/autotests/libs/collectionattributetest.h @@ -1,37 +1,38 @@ /* Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef COLLECTIONATTRIBUTETEST_H #define COLLECTIONATTRIBUTETEST_H #include class CollectionAttributeTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testAttributes_data(); void testAttributes(); void testDefaultAttributes(); void testCollectionRightsAttribute(); void testCollectionIdentificationAttribute(); + void testDetach(); }; #endif diff --git a/src/core/collection.h b/src/core/collection.h index 52dc97188..8a51eb0eb 100644 --- a/src/core/collection.h +++ b/src/core/collection.h @@ -1,632 +1,632 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_COLLECTION_H #define AKONADI_COLLECTION_H #include "akonadicore_export.h" #include "attribute.h" #include #include #include class QUrl; namespace Akonadi { class CachePolicy; class CollectionPrivate; class CollectionStatistics; /** * @short Represents a collection of PIM items. * * This class represents a collection of PIM items, such as a folder on a mail- or * groupware-server. * * Collections are hierarchical, i.e., they may have a parent collection. * * @code * * using namespace Akonadi; * * // fetching all collections recursive, starting at the root collection * CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive ); * connect( job, SIGNAL(result(KJob*)), SLOT(fetchFinished(KJob*)) ); * * ... * * MyClass::fetchFinished( KJob *job ) * { * if ( job->error() ) { * qDebug() << "Error occurred"; * return; * } * * CollectionFetchJob *fetchJob = qobject_cast( job ); * * const Collection::List collections = fetchJob->collections(); * foreach ( const Collection &collection, collections ) { * qDebug() << "Name:" << collection.name(); * } * } * * @endcode * * @author Volker Krause */ class AKONADICORE_EXPORT Collection { public: /** * Describes the unique id type. */ typedef qint64 Id; /** * Describes a list of collections. */ typedef QVector List; /** * Describes rights of a collection. */ enum Right { ReadOnly = 0x0, ///< Can only read items or subcollection of this collection CanChangeItem = 0x1, ///< Can change items in this collection CanCreateItem = 0x2, ///< Can create new items in this collection CanDeleteItem = 0x4, ///< Can delete items in this collection CanChangeCollection = 0x8, ///< Can change this collection CanCreateCollection = 0x10, ///< Can create new subcollections in this collection CanDeleteCollection = 0x20, ///< Can delete this collection CanLinkItem = 0x40, ///< Can create links to existing items in this virtual collection @since 4.4 CanUnlinkItem = 0x80, ///< Can remove links to items in this virtual collection @since 4.4 AllRights = (CanChangeItem | CanCreateItem | CanDeleteItem | CanChangeCollection | CanCreateCollection | CanDeleteCollection) ///< Has all rights on this storage collection }; Q_DECLARE_FLAGS(Rights, Right) /** * Creates an invalid collection. */ Collection(); /** * Create a new collection. * * @param id The unique identifier of the collection. */ explicit Collection(Id id); /** * Destroys the collection. */ ~Collection(); /** * Creates a collection from an @p other collection. */ Collection(const Collection &other); /** * Creates a collection from the given @p url. */ static Collection fromUrl(const QUrl &url); /** * Sets the unique @p identifier of the collection. */ void setId(Id identifier); /** * Returns the unique identifier of the collection. */ Q_REQUIRED_RESULT Id id() const; /** * Sets the remote @p id of the collection. */ void setRemoteId(const QString &id); /** * Returns the remote id of the collection. */ Q_REQUIRED_RESULT QString remoteId() const; /** * Sets the remote @p revision of the collection. * @param revision the collections's remote revision * The remote revision can be used by resources to store some * revision information of the backend to detect changes there. * * @note This method is supposed to be used by resources only. * @since 4.5 */ void setRemoteRevision(const QString &revision); /** * Returns the remote revision of the collection. * * @note This method is supposed to be used by resources only. * @since 4.5 */ Q_REQUIRED_RESULT QString remoteRevision() const; /** * Returns whether the collection is valid. */ Q_REQUIRED_RESULT bool isValid() const; /** * Returns whether this collections's id equals the * id of the @p other collection. */ Q_REQUIRED_RESULT bool operator==(const Collection &other) const; /** * Returns whether the collection's id does not equal the id * of the @p other collection. */ Q_REQUIRED_RESULT bool operator!=(const Collection &other) const; /** * Assigns the @p other to this collection and returns a reference to this * collection. * @param other the collection to assign */ Collection &operator=(const Collection &other); /** * @internal For use with containers only. * * @since 4.8 */ Q_REQUIRED_RESULT bool operator<(const Collection &other) const; /** * Returns the parent collection of this object. * @note This will of course only return a useful value if it was explictely retrieved * from the Akonadi server. * @since 4.4 */ Q_REQUIRED_RESULT Collection parentCollection() const; /** * Returns a reference to the parent collection of this object. * @note This will of course only return a useful value if it was explictely retrieved * from the Akonadi server. * @since 4.4 */ Q_REQUIRED_RESULT Collection &parentCollection(); /** * Set the parent collection of this object. * @note Calling this method has no immediate effect for the object itself, * such as being moved to another collection. * It is mainly relevant to provide a context for RID-based operations * inside resources. * @param parent The parent collection. * @since 4.4 */ void setParentCollection(const Collection &parent); /** * Adds an attribute to the collection. * * If an attribute of the same type name already exists, it is deleted and * replaced with the new one. * * @param attribute The new attribute. * * @note The collection takes the ownership of the attribute. */ void addAttribute(Attribute *attribute); /** * Removes and deletes the attribute of the given type @p name. */ void removeAttribute(const QByteArray &name); /** * Returns @c true if the collection has an attribute of the given type @p name, * false otherwise. */ bool hasAttribute(const QByteArray &name) const; /** * Returns a list of all attributes of the collection. */ Q_REQUIRED_RESULT Attribute::List attributes() const; /** * Removes and deletes all attributes of the collection. */ void clearAttributes(); /** * Returns the attribute of the given type @p name if available, 0 otherwise. */ Attribute *attribute(const QByteArray &name) const; /** * Describes the options that can be passed to access attributes. */ enum CreateOption { AddIfMissing ///< Creates the attribute if it is missing }; /** * Returns the attribute of the requested type. * If the collection has no attribute of that type yet, a new one * is created and added to the entity. * * @param option The create options. */ template inline T *attribute(CreateOption option); /** * Returns the attribute of the requested type or 0 if it is not available. */ template inline T *attribute() const; /** * Removes and deletes the attribute of the requested type. */ template inline void removeAttribute(); /** * Returns whether the collection has an attribute of the requested type. */ template inline bool hasAttribute() const; /** * Returns the i18n'ed name of the collection. */ Q_REQUIRED_RESULT QString name() const; /** * Returns the display name (EntityDisplayAttribute::displayName()) if set, * and Collection::name() otherwise. For human-readable strings this is preferred * over Collection::name(). * * @since 4.11 */ Q_REQUIRED_RESULT QString displayName() const; /** * Sets the i18n'ed name of the collection. * * @param name The new collection name. */ void setName(const QString &name); /** * Returns the rights the user has on the collection. */ Q_REQUIRED_RESULT Rights rights() const; /** * Sets the @p rights the user has on the collection. */ void setRights(Rights rights); /** * Returns a list of possible content mimetypes, * e.g. message/rfc822, x-akonadi/collection for a mail folder that * supports sub-folders. */ Q_REQUIRED_RESULT QStringList contentMimeTypes() const; /** * Sets the list of possible content mime @p types. */ void setContentMimeTypes(const QStringList &types); /** * Returns the root collection. */ Q_REQUIRED_RESULT static Collection root(); /** * Returns the mimetype used for collections. */ Q_REQUIRED_RESULT static QString mimeType(); /** * Returns the mimetype used for virtual collections * * @since 4.11 */ Q_REQUIRED_RESULT static QString virtualMimeType(); /** * Returns the identifier of the resource owning the collection. */ Q_REQUIRED_RESULT QString resource() const; /** * Sets the @p identifier of the resource owning the collection. */ void setResource(const QString &identifier); /** * Returns the cache policy of the collection. */ Q_REQUIRED_RESULT CachePolicy cachePolicy() const; /** * Sets the cache @p policy of the collection. */ void setCachePolicy(const CachePolicy &policy); /** * Returns the collection statistics of the collection. */ Q_REQUIRED_RESULT CollectionStatistics statistics() const; /** * Sets the collection @p statistics for the collection. */ void setStatistics(const CollectionStatistics &statistics); /** * Describes the type of url which is returned in url(). * * @since 4.7 */ enum UrlType { UrlShort = 0, ///< A short url which contains the identifier only (equivalent to url()) UrlWithName = 1 ///< A url with identifier and name }; /** * Returns the url of the collection. * @param type the type of url * @since 4.7 */ Q_REQUIRED_RESULT QUrl url(UrlType type = UrlShort) const; /** * Returns whether the collection is virtual, for example a search collection. * * @since 4.6 */ Q_REQUIRED_RESULT bool isVirtual() const; /** * Sets whether the collection is virtual or not. * Virtual collections can't be converted to non-virtual and vice versa. * @param isVirtual virtual collection if @c true, otherwise a normal collection * @since 4.10 */ void setVirtual(bool isVirtual); /** * Sets the collection's enabled state. * * Use this mechanism to set if a collection should be available * to the user or not. * * This can be used in conjunction with the local list preference for finer grained control * to define if a collection should be included depending on the purpose. * * For example: A collection is by default enabled, meaning it is displayed to the user, synchronized by the resource, * and indexed by the indexer. A disabled collection on the other hand is not displayed, synchronized or indexed. * The local list preference allows to locally override that default value for each purpose individually. * * The enabled state can be synchronized by backends. * E.g. an imap resource may synchronize this with the subscription state. * * @since 4.14 * @see setLocalListPreference, setShouldList */ void setEnabled(bool enabled); /** * Returns the collection's enabled state. * @since 4.14 * @see localListPreference */ Q_REQUIRED_RESULT bool enabled() const; /** * Describes the list preference value * * @since 4.14 */ enum ListPreference { ListEnabled, ///< Enable collection for specified purpose ListDisabled, ///< Disable collection for specified purpose ListDefault ///< Fallback to enabled state }; /** * Describes the purpose of the listing * * @since 4.14 */ enum ListPurpose { ListSync, ///< Listing for synchronization ListDisplay, ///< Listing for display to the user ListIndex ///< Listing for indexing the content }; /** * Sets the local list preference for the specified purpose. * * The local list preference overrides the enabled state unless set to ListDefault. * In case of ListDefault the enabled state should be taken as fallback (shouldList() implements this logic). * * The default value is ListDefault. * * @since 4.14 * @see shouldList, setEnabled */ void setLocalListPreference(ListPurpose purpose, ListPreference preference); /** * Returns the local list preference for the specified purpose. * @since 4.14 * @see setLocalListPreference */ Q_REQUIRED_RESULT ListPreference localListPreference(ListPurpose purpose) const; /** * Returns whether the collection should be listed or not for the specified purpose * Takes enabled state and local preference into account. * * @since 4.14 * @see setLocalListPreference, setEnabled */ Q_REQUIRED_RESULT bool shouldList(ListPurpose purpose) const; /** * Sets whether the collection should be listed or not for the specified purpose. * Takes enabled state and local preference into account. * * Use this instead of sestEnabled and setLocalListPreference to automatically set * the right setting. * * @since 4.14 * @see setLocalListPreference, setEnabled */ void setShouldList(ListPurpose purpose, bool shouldList); /** * Sets a collection to be referenced. * * A referenced collection is temporarily shown and synchronized even when disabled. * A reference is only valid for the duration of a session, and is automatically removed afterwards. * * Referenced collections are only visible if explicitly monitored in the ETM. * * @since 4.14 */ void setReferenced(bool referenced); /** * Returns the referenced state of the collection. * @since 4.14 */ Q_REQUIRED_RESULT bool referenced() const; /** * Set during sync to indicate that the provided parts are only default values; * @since 4.15 */ void setKeepLocalChanges(const QSet &parts); /** * Returns what parts are only default values. */ QSet keepLocalChanges() const; private: friend class CollectionCreateJob; friend class CollectionFetchJob; friend class CollectionModifyJob; friend class ProtocolHelper; void markAttributeModified(const QByteArray &type); //@cond PRIVATE QSharedDataPointer d_ptr; friend class CollectionPrivate; //@endcond }; AKONADICORE_EXPORT uint qHash(const Akonadi::Collection &collection); template inline T *Akonadi::Collection::attribute(Collection::CreateOption option) { Q_UNUSED(option); const QByteArray type = T().type(); + markAttributeModified(type); // do this first in case it detaches if (hasAttribute(type)) { T *attr = dynamic_cast(attribute(type)); if (attr) { - markAttributeModified(type); return attr; } //Reuse 5250 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?"; } T *attr = new T(); addAttribute(attr); return attr; } template inline T *Akonadi::Collection::attribute() const { const QByteArray type = T().type(); if (hasAttribute(type)) { T *attr = dynamic_cast(attribute(type)); if (attr) { // FIXME: This method returns a non-const pointer, so callers may still modify the // attribute. Unfortunately, just making this function return a const pointer and // creating a non-const overload does not work, as many users of this function abuse the // non-const pointer and modify the attribute even on a const object. const_cast(this)->markAttributeModified(type); return attr; } //reuse 5250 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?"; } return nullptr; } template inline void Akonadi::Collection::removeAttribute() { const T dummy; removeAttribute(dummy.type()); } template inline bool Akonadi::Collection::hasAttribute() const { const T dummy; return hasAttribute(dummy.type()); } } // namespace Akonadi /** * Allows to output a collection for debugging purposes. */ AKONADICORE_EXPORT QDebug operator<<(QDebug d, const Akonadi::Collection &collection); Q_DECLARE_METATYPE(Akonadi::Collection) Q_DECLARE_METATYPE(Akonadi::Collection::List) Q_DECLARE_OPERATORS_FOR_FLAGS(Akonadi::Collection::Rights) Q_DECLARE_TYPEINFO(Akonadi::Collection, Q_MOVABLE_TYPE); #endif diff --git a/src/core/tag.h b/src/core/tag.h index 267120044..20ca6c9ab 100644 --- a/src/core/tag.h +++ b/src/core/tag.h @@ -1,273 +1,273 @@ /* Copyright (c) 2014 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_TAG_H #define AKONADI_TAG_H #include "akonadicore_export.h" #include "attribute.h" #include #include #include #include namespace Akonadi { class TagModifyJob; class TagPrivate; /** * An Akonadi Tag. */ class AKONADICORE_EXPORT Tag { public: typedef QVector List; typedef qint64 Id; /** * The PLAIN type has the following properties: * * gid == displayName * * immutable * * no hierarchy (no parent) * * PLAIN tags are general purpose tags that are easy to map by backends. */ static const char PLAIN[]; /** * The GENERIC type has the following properties: * * mutable * * gid is RFC 4122 compatible * * no hierarchy (no parent) * * GENERIC tags are general purpose tags, that are used, if you can change tag name. */ static const char GENERIC[]; Tag(); explicit Tag(Id id); /** * Creates a PLAIN tag */ explicit Tag(const QString &name); Tag(const Tag &other); ~Tag(); Tag &operator=(const Tag &); //Avoid slicing bool operator==(const Tag &) const; bool operator!=(const Tag &) const; static Tag fromUrl(const QUrl &url); /** * Adds an attribute to the entity. * * If an attribute of the same type name already exists, it is deleted and * replaced with the new one. * * @param attribute The new attribute. * * @note The entity takes the ownership of the attribute. */ void addAttribute(Attribute *attribute); /** * Removes and deletes the attribute of the given type @p name. */ void removeAttribute(const QByteArray &name); /** * Returns @c true if the entity has an attribute of the given type @p name, * false otherwise. */ bool hasAttribute(const QByteArray &name) const; /** * Returns a list of all attributes of the entity. */ Attribute::List attributes() const; /** * Removes and deletes all attributes of the entity. */ void clearAttributes(); /** * Returns the attribute of the given type @p name if available, 0 otherwise. */ Attribute *attribute(const QByteArray &name) const; /** * Describes the options that can be passed to access attributes. */ enum CreateOption { AddIfMissing ///< Creates the attribute if it is missing }; /** * Returns the attribute of the requested type. * If the entity has no attribute of that type yet, a new one * is created and added to the entity. * * @param option The create options. */ template inline T *attribute(CreateOption option); /** * Returns the attribute of the requested type or 0 if it is not available. */ template inline T *attribute() const; /** * Removes and deletes the attribute of the requested type. */ template inline void removeAttribute(); /** * Returns whether the entity has an attribute of the requested type. */ template inline bool hasAttribute() const; /** * Returns the url of the tag. */ QUrl url() const; /** * Sets the unique @p identifier of the tag. */ void setId(Id identifier); /** * Returns the unique identifier of the tag. */ Id id() const; void setGid(const QByteArray &gid); QByteArray gid() const; void setRemoteId(const QByteArray &remoteId); QByteArray remoteId() const; void setType(const QByteArray &type); QByteArray type() const; void setName(const QString &name); QString name() const; void setParent(const Tag &parent); Tag parent() const; bool isValid() const; /** * Returns true if the tag is immutable (cannot be modified after creation). * Note that the immutability does not affect the attributes. */ bool isImmutable() const; /** * Returns a GENERIC tag with the given name and a valid gid */ static Tag genericTag(const QString &name); private: bool checkAttribute(Attribute *attr, const QByteArray &type) const; void markAttributeModified(const QByteArray &type); //@cond PRIVATE friend class TagModifyJob; friend class TagFetchJob; friend class ProtocolHelper; QSharedDataPointer d_ptr; //@endcond }; AKONADICORE_EXPORT uint qHash(const Akonadi::Tag &); template inline T *Tag::attribute(CreateOption option) { Q_UNUSED(option); const QByteArray type = T().type(); + markAttributeModified(type); if (hasAttribute(type)) { T *attr = dynamic_cast(attribute(type)); if (checkAttribute(attr, type)) { - markAttributeModified(type); return attr; } } T *attr = new T(); addAttribute(attr); return attr; } template inline T *Tag::attribute() const { const QByteArray type = T().type(); if (hasAttribute(type)) { T *attr = dynamic_cast(attribute(type)); if (checkAttribute(attr, type)) { // FIXME: Make this a truly const method so that callers may not modify // the attribute returned from here. const_cast(this)->markAttributeModified(type); return attr; } } return nullptr; } template inline void Tag::removeAttribute() { const T dummy; removeAttribute(dummy.type()); } template inline bool Tag::hasAttribute() const { const T dummy; return hasAttribute(dummy.type()); } } // namespace Akonadi AKONADICORE_EXPORT QDebug &operator<<(QDebug &debug, const Akonadi::Tag &tag); Q_DECLARE_METATYPE(Akonadi::Tag) Q_DECLARE_METATYPE(Akonadi::Tag::List) Q_DECLARE_METATYPE(QSet) Q_DECLARE_TYPEINFO(Akonadi::Tag, Q_MOVABLE_TYPE); #endif