File indexing completed on 2024-06-23 05:06:49
0001 /* 0002 SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org> 0003 2007 Till Adam <adam@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #pragma once 0009 0010 #include "akonadicore_export.h" 0011 #include "attribute.h" 0012 #include "collection.h" 0013 #include "exceptionbase.h" 0014 #include "itempayloadinternals_p.h" 0015 #include "job.h" 0016 #include "relation.h" 0017 #include "tag.h" 0018 0019 #include <QByteArray> 0020 #include <QMetaType> 0021 #include <QSet> 0022 0023 #include <memory> 0024 #include <type_traits> 0025 #include <typeinfo> 0026 0027 class QUrl; 0028 template<typename T> 0029 class QList; 0030 0031 namespace Akonadi 0032 { 0033 class ItemPrivate; 0034 0035 /** 0036 * @short Represents a PIM item stored in Akonadi storage. 0037 * 0038 * A PIM item consists of one or more parts, allowing a fine-grained access on its 0039 * content where needed (eg. mail envelope, mail body and attachments). 0040 * 0041 * There is also a namespace (prefix) for special parts which are local to Akonadi. 0042 * These parts, prefixed by "akonadi-", will never be fetched in the resource. 0043 * They are useful for local extensions like agents which might want to add meta data 0044 * to items in order to handle them but the meta data should not be stored back to the 0045 * resource. 0046 * 0047 * This class is implicitly shared. 0048 * 0049 * <h4>Payload</h4> 0050 * 0051 * This class contains, beside some type-agnostic information (flags, revision), 0052 * zero or more payload objects representing its actual data. Which objects these actually 0053 * are depends on the mimetype of the item and the corresponding serializer plugin(s). 0054 * 0055 * Technically the only restriction on payload objects is that they have to be copyable. 0056 * For safety reasons, pointer payloads are forbidden as well though, as the 0057 * ownership would not be clear. In this case, usage of a shared pointer is 0058 * recommended (such as QSharedPointer or std::shared_ptr). 0059 * 0060 * Using a shared pointer is also required in case the payload is a polymorphic 0061 * type. For supported shared pointer types implicit casting is provided when possible. 0062 * 0063 * When using a value-based class as payload, it is recommended to use one that does 0064 * support implicit sharing as setting and retrieving a payload as well as copying 0065 * an Akonadi::Item object imply copying of the payload object. 0066 * 0067 * Since KDE 4.6, Item supports multiple payload types per mime type, 0068 * and will automatically convert between them using the serialiser 0069 * plugins (which is slow). It also supports mixing shared pointer 0070 * types, e.g. inserting a std::shared_ptr<Foo> and extracting a 0071 * QSharedPointer<Foo>. Since the two shared pointer types cannot 0072 * share ownership of the same object, the payload class @c T needs to 0073 * provide a @c clone() method with the usual signature, ie. 0074 * 0075 * @code 0076 * virtual T * T::clone() const 0077 * @endcode 0078 * 0079 * If the class that does not have a @c clone() method, asking for an 0080 * incompatible shared pointer will throw a PayloadException. 0081 * 0082 * Since using different shared pointer types and different payload 0083 * types for the same mimetype incurs slow conversions (between 0084 * payload types) and cloning (between shared pointer types), as well 0085 * as manifold memory usage (results of conversions are cached inside 0086 * the Item, and only destroyed when a new payload is set by the user 0087 * of the class), you want to restrict yourself to just one type and 0088 * one shared pointer type. This mechanism was mainly introduced for 0089 * backwards compatibility (e.g., putting in a 0090 * std::shared_ptr<KCal::Incidence> and extracting a 0091 * QSharedPointer<KCalCore::Incidence>), so it is not optimized for 0092 * performance. 0093 * 0094 * The availability of a payload of a specific type can be checked using hasPayload(), 0095 * payloads can be retrieved by using payload() and set by using setPayload(). Refer 0096 * to the documentation of those methods for more details. 0097 * 0098 * @author Volker Krause <vkrause@kde.org>, Till Adam <adam@kde.org>, Marc Mutz <mutz@kde.org> 0099 */ 0100 class AKONADICORE_EXPORT Item 0101 { 0102 public: 0103 /** 0104 * Describes the unique id type. 0105 */ 0106 using Id = qint64; 0107 0108 /** 0109 * Describes a list of items. 0110 */ 0111 using List = QList<Item>; 0112 0113 /** 0114 * Describes a flag name. 0115 */ 0116 using Flag = QByteArray; 0117 0118 /** 0119 * Describes a set of flag names. 0120 */ 0121 using Flags = QSet<QByteArray>; 0122 0123 /** 0124 * Describes the part name that is used to fetch the 0125 * full payload of an item. 0126 */ 0127 static const char FullPayload[]; 0128 0129 /** 0130 * Creates a new item. 0131 */ 0132 Item(); 0133 0134 /** 0135 * Creates a new item with the given unique @p id. 0136 */ 0137 explicit Item(Id id); 0138 0139 /** 0140 * Creates a new item with the given mime type. 0141 * 0142 * @param mimeType The mime type of the item. 0143 */ 0144 explicit Item(const QString &mimeType); 0145 0146 /** 0147 * Creates a new item from an @p other item. 0148 */ 0149 Item(const Item &other); 0150 0151 /** 0152 * Move constructor. 0153 */ 0154 Item(Item &&) noexcept; 0155 0156 /** 0157 * Destroys the item. 0158 */ 0159 ~Item(); 0160 0161 /** 0162 * Creates an item from the given @p url. 0163 */ 0164 static Item fromUrl(const QUrl &url); 0165 0166 /** 0167 * Sets the unique @p identifier of the item. 0168 */ 0169 void setId(Id identifier); 0170 0171 /** 0172 * Returns the unique identifier of the item. 0173 */ 0174 Id id() const; 0175 0176 /** 0177 * Sets the remote @p id of the item. 0178 */ 0179 void setRemoteId(const QString &id); 0180 0181 /** 0182 * Returns the remote id of the item. 0183 */ 0184 QString remoteId() const; 0185 0186 /** 0187 * Sets the remote @p revision of the item. 0188 * @param revision the item's remote revision 0189 * The remote revision can be used by resources to store some 0190 * revision information of the backend to detect changes there. 0191 * 0192 * @note This method is supposed to be used by resources only. 0193 * @since 4.5 0194 */ 0195 void setRemoteRevision(const QString &revision); 0196 0197 /** 0198 * Returns the remote revision of the item. 0199 * 0200 * @note This method is supposed to be used by resources only. 0201 * @since 4.5 0202 */ 0203 QString remoteRevision() const; 0204 0205 /** 0206 * Returns whether the item is valid. 0207 */ 0208 bool isValid() const; 0209 0210 /** 0211 * Returns whether this item's id equals the id of the @p other item. 0212 */ 0213 bool operator==(const Item &other) const; 0214 0215 /** 0216 * Returns whether the item's id does not equal the id of the @p other item. 0217 */ 0218 bool operator!=(const Item &other) const; 0219 0220 /** 0221 * Assigns the @p other to this item and returns a reference to this item. 0222 * @param other the item to assign 0223 */ 0224 Item &operator=(const Item &other); 0225 0226 /** 0227 * @internal For use with containers only. 0228 * 0229 * @since 4.8 0230 */ 0231 bool operator<(const Item &other) const; 0232 0233 /** 0234 * Returns the parent collection of this object. 0235 * @note This will of course only return a useful value if it was explicitly retrieved 0236 * from the Akonadi server. 0237 * @since 4.4 0238 */ 0239 Collection parentCollection() const; 0240 0241 /** 0242 * Returns a reference to the parent collection of this object. 0243 * @note This will of course only return a useful value if it was explicitly retrieved 0244 * from the Akonadi server. 0245 * @since 4.4 0246 */ 0247 Collection &parentCollection(); 0248 0249 /** 0250 * Set the parent collection of this object. 0251 * @note Calling this method has no immediate effect for the object itself, 0252 * such as being moved to another collection. 0253 * It is mainly relevant to provide a context for RID-based operations 0254 * inside resources. 0255 * @param parent The parent collection. 0256 * @since 4.4 0257 */ 0258 void setParentCollection(const Collection &parent); 0259 0260 /** 0261 * Adds an attribute to the item. 0262 * 0263 * If an attribute of the same type name already exists, it is deleted and 0264 * replaced with the new one. 0265 * 0266 * @param attribute The new attribute. 0267 * 0268 * @note The collection takes the ownership of the attribute. 0269 */ 0270 void addAttribute(Attribute *attribute); 0271 0272 /** 0273 * Removes and deletes the attribute of the given type @p name. 0274 */ 0275 void removeAttribute(const QByteArray &name); 0276 0277 /** 0278 * Returns @c true if the item has an attribute of the given type @p name, 0279 * false otherwise. 0280 */ 0281 bool hasAttribute(const QByteArray &name) const; 0282 0283 /** 0284 * Returns a list of all attributes of the item. 0285 * 0286 * @warning Do not modify the attributes returned from this method, 0287 * the change will not be reflected when updating the Item through 0288 * ItemModifyJob. 0289 */ 0290 Attribute::List attributes() const; 0291 0292 /** 0293 * Removes and deletes all attributes of the item. 0294 */ 0295 void clearAttributes(); 0296 0297 /** 0298 * Returns the attribute of the given type @p name if available, 0 otherwise. 0299 */ 0300 Attribute *attribute(const QByteArray &name); 0301 const Attribute *attribute(const QByteArray &name) const; 0302 0303 /** 0304 * Describes the options that can be passed to access attributes. 0305 */ 0306 enum CreateOption { 0307 AddIfMissing, ///< Creates the attribute if it is missing 0308 DontCreate ///< Do not create the attribute if it is missing (default) 0309 }; 0310 0311 /** 0312 * Returns the attribute of the requested type. 0313 * If the item has no attribute of that type yet, a new one 0314 * is created and added to the entity. 0315 * 0316 * @param option The create options. 0317 */ 0318 template<typename T> 0319 inline T *attribute(CreateOption option = DontCreate); 0320 0321 /** 0322 * Returns the attribute of the requested type or 0 if it is not available. 0323 */ 0324 template<typename T> 0325 inline const T *attribute() const; 0326 0327 /** 0328 * Removes and deletes the attribute of the requested type. 0329 */ 0330 template<typename T> 0331 inline void removeAttribute(); 0332 0333 /** 0334 * Returns whether the item has an attribute of the requested type. 0335 */ 0336 template<typename T> 0337 inline bool hasAttribute() const; 0338 0339 /** 0340 * Returns all flags of this item. 0341 */ 0342 Flags flags() const; 0343 0344 /** 0345 * Returns the timestamp of the last modification of this item. 0346 * @since 4.2 0347 */ 0348 QDateTime modificationTime() const; 0349 0350 /** 0351 * Sets the timestamp of the last modification of this item. 0352 * @param datetime the modification time to set 0353 * @note Do not modify this value from within an application, 0354 * it is updated automatically by the revision checking functions. 0355 * @since 4.2 0356 */ 0357 void setModificationTime(const QDateTime &datetime); 0358 0359 /** 0360 * Returns whether the flag with the given @p name is 0361 * set in the item. 0362 */ 0363 bool hasFlag(const QByteArray &name) const; 0364 0365 /** 0366 * Sets the flag with the given @p name in the item. 0367 */ 0368 void setFlag(const QByteArray &name); 0369 0370 /** 0371 * Removes the flag with the given @p name from the item. 0372 */ 0373 void clearFlag(const QByteArray &name); 0374 0375 /** 0376 * Overwrites all flags of the item by the given @p flags. 0377 */ 0378 void setFlags(const Flags &flags); 0379 0380 /** 0381 * Removes all flags from the item. 0382 */ 0383 void clearFlags(); 0384 0385 void setTags(const Tag::List &list); 0386 0387 void setTag(const Tag &tag); 0388 0389 Tag::List tags() const; 0390 0391 bool hasTag(const Tag &tag) const; 0392 0393 void clearTag(const Tag &tag); 0394 0395 void clearTags(); 0396 0397 /** 0398 * Returns all relations of this item. 0399 * @since 4.15 0400 * @see RelationCreateJob, RelationDeleteJob to modify relations 0401 */ 0402 Relation::List relations() const; 0403 0404 /** 0405 * Sets the payload based on the canonical representation normally 0406 * used for data of this mime type. 0407 * 0408 * @param data The encoded data. 0409 * @see fullPayloadData 0410 */ 0411 void setPayloadFromData(const QByteArray &data); 0412 0413 /** 0414 * Returns the full payload in its canonical representation, e.g. the 0415 * binary or textual format usually used for data with this mime type. 0416 * This is useful when communicating with non-Akonadi application by 0417 * e.g. drag&drop, copy&paste or stored files. 0418 */ 0419 QByteArray payloadData() const; 0420 0421 /** 0422 * Returns the list of loaded payload parts. This is not necessarily 0423 * identical to all parts in the cache or to all available parts on the backend. 0424 */ 0425 QSet<QByteArray> loadedPayloadParts() const; 0426 0427 /** 0428 * Marks that the payload shall be cleared from the cache when this 0429 * item is passed to an ItemModifyJob the next time. 0430 * This will trigger a refetch of the payload from the backend when the 0431 * item is accessed afterwards. Only resources should have a need for 0432 * this functionality. 0433 * 0434 * @since 4.5 0435 */ 0436 void clearPayload(); 0437 0438 /** 0439 * Sets the @p revision number of the item. 0440 * @param revision the revision number to set 0441 * @note Do not modify this value from within an application, 0442 * it is updated automatically by the revision checking functions. 0443 */ 0444 void setRevision(int revision); 0445 0446 /** 0447 * Returns the revision number of the item. 0448 */ 0449 int revision() const; 0450 0451 /** 0452 * Returns the unique identifier of the collection this item is stored in. There is only 0453 * a single such collection, although the item can be linked into arbitrary many 0454 * virtual collections. 0455 * Calling this method makes sense only after running an ItemFetchJob on the item. 0456 * @returns the collection ID if it is known, -1 otherwise. 0457 * @since 4.3 0458 */ 0459 Collection::Id storageCollectionId() const; 0460 0461 /** 0462 * Set the size of the item in bytes. 0463 * @param size the size of the item in bytes 0464 * @since 4.2 0465 */ 0466 void setSize(qint64 size); 0467 0468 /** 0469 * Returns the size of the items in bytes. 0470 * 0471 * @since 4.2 0472 */ 0473 qint64 size() const; 0474 0475 /** 0476 * Sets the mime type of the item to @p mimeType. 0477 */ 0478 void setMimeType(const QString &mimeType); 0479 0480 /** 0481 * Returns the mime type of the item. 0482 */ 0483 QString mimeType() const; 0484 0485 /** 0486 * Sets the @p gid of the entity. 0487 * 0488 * @since 4.12 0489 */ 0490 void setGid(const QString &gid); 0491 0492 /** 0493 * Returns the gid of the entity. 0494 * 0495 * @since 4.12 0496 */ 0497 QString gid() const; 0498 0499 /** 0500 * Sets the virtual @p collections that this item is linked into. 0501 * 0502 * @note Note that changing this value makes no effect on what collections 0503 * this item is linked to. To link or unlink an item to/from a virtual 0504 * collection, use LinkJob and UnlinkJob. 0505 * 0506 * @since 4.14 0507 */ 0508 void setVirtualReferences(const Collection::List &collections); 0509 0510 /** 0511 * Lists virtual collections that this item is linked to. 0512 * 0513 * @note This value is populated only when this item was retrieved by 0514 * ItemFetchJob with fetchVirtualReferences set to true in ItemFetchScope, 0515 * otherwise this list is always empty. 0516 * 0517 * @since 4.14 0518 */ 0519 Collection::List virtualReferences() const; 0520 0521 /** 0522 * Returns a list of metatype-ids, describing the different 0523 * variants of payload that are currently contained in this item. 0524 * 0525 * The result is always sorted (increasing ids). 0526 */ 0527 QList<int> availablePayloadMetaTypeIds() const; 0528 0529 /** 0530 * Sets a path to a file with full payload. 0531 * 0532 * This method can only be used by Resources and should not be used by Akonadi 0533 * clients. Clients should use setPayload() instead. 0534 * 0535 * Akonadi will not duplicate content of the file in its database but will 0536 * instead directly refer to this file. This means that the file must be 0537 * persistent (don't use this method with a temporary files), and the Akonadi 0538 * resource that owns the storage is responsible for updating the file path 0539 * if the file is changed, moved or removed. 0540 * 0541 * The payload can still be accessed via payload() methods. 0542 * 0543 * @see setPayload(), setPayloadFromData() 0544 * @since 5.6 0545 */ 0546 void setPayloadPath(const QString &filePath); 0547 0548 /** 0549 * Returns path to the payload file set by setPayloadPath() 0550 * 0551 * If payload was set via setPayload() or setPayloadFromData() then this 0552 * method will return a null string. 0553 */ 0554 QString payloadPath() const; 0555 0556 /** 0557 * Sets the payload object of this PIM item. 0558 * 0559 * @param p The payload object. Must be copyable and must not be a pointer, 0560 * will cause a compilation failure otherwise. Using a type that can be copied 0561 * fast (such as implicitly shared classes) is recommended. 0562 * If the payload type is polymorphic and you intend to set and retrieve payload 0563 * objects with mismatching but castable types, make sure to use a supported 0564 * shared pointer implementation (currently QSharedPointer and std::shared_ptr) 0565 * and make sure there is a specialization of Akonadi::super_trait for your class. 0566 */ 0567 template<typename T> 0568 void setPayload(const T &p); 0569 /// @cond PRIVATE 0570 template<typename T> 0571 void setPayload(T *p); 0572 /// @endcond 0573 0574 /** 0575 * Returns the payload object of this PIM item. This method will only succeed if either 0576 * you requested the exact same payload type that was put in or the payload uses a 0577 * supported shared pointer type (currently QSharedPointer and std::shared_ptr), 0578 * and is castable to the requested type. For this to work there needs 0579 * to be a specialization of Akonadi::super_trait of the used classes. 0580 * 0581 * If a mismatching or non-castable payload type is requested, an Akonadi::PayloadException 0582 * is thrown. Therefore it is generally recommended to guard calls to payload() with a 0583 * corresponding hasPayload() call. 0584 * 0585 * Trying to retrieve a pointer type will fail to compile. 0586 */ 0587 template<typename T> 0588 T payload() const; 0589 0590 /** 0591 * Returns whether the item has a payload object. 0592 */ 0593 bool hasPayload() const; 0594 0595 /** 0596 * Returns whether the item has a payload of type @c T. 0597 * This method will only return @c true if either you requested the exact same payload type 0598 * that was put in or the payload uses a supported shared pointer type (currently 0599 * QSharedPointer and std::shared_ptr), and is castable to the requested type. For this to work there needs 0600 * to be a specialization of Akonadi::super_trait of the used classes. 0601 * 0602 * Trying to retrieve a pointer type will fail to compile. 0603 */ 0604 template<typename T> 0605 bool hasPayload() const; 0606 0607 /** 0608 * Describes the type of url which is returned in url(). 0609 */ 0610 enum UrlType { 0611 UrlShort = 0, ///< A short url which contains the identifier only (default) 0612 UrlWithMimeType = 1 ///< A url with identifier and mimetype 0613 }; 0614 0615 /** 0616 * Returns the url of the item. 0617 */ 0618 QUrl url(UrlType type = UrlShort) const; 0619 0620 /** 0621 * Returns the parts available for this item. 0622 * 0623 * The returned set refers to parts available on the akonadi server or remotely, 0624 * but does not include the loadedPayloadParts() of this item. 0625 * 0626 * @since 4.4 0627 */ 0628 QSet<QByteArray> availablePayloadParts() const; 0629 0630 /** 0631 * Returns the parts available for this item in the cache. The list might be a subset 0632 * of the actual parts in cache, as it contains only the requested parts. See @see ItemFetchJob and 0633 * @see ItemFetchScope 0634 * 0635 * The returned set refers to parts available on the akonadi server. 0636 * 0637 * @since 4.11 0638 */ 0639 QSet<QByteArray> cachedPayloadParts() const; 0640 0641 /** 0642 * Applies the parts of Item @p other to this item. 0643 * Any parts or attributes available in other, will be applied to this item, 0644 * and the payload parts of other will be inserted into this item, overwriting 0645 * any existing parts with the same part name. 0646 * 0647 * If there is an ItemSerialzerPluginV2 for the type, the merge method in that plugin is 0648 * used to perform the merge. If only an ItemSerialzerPlugin class is found, or the merge 0649 * method of the -V2 plugin is not implemented, the merge is performed with multiple deserializations 0650 * of the payload. 0651 * @param other the item to get values from 0652 * @since 4.4 0653 */ 0654 void apply(const Item &other); 0655 0656 void setCachedPayloadParts(const QSet<QByteArray> &cachedParts); 0657 0658 private: 0659 /// @cond PRIVATE 0660 friend class ItemCreateJob; 0661 friend class ItemCreateJobPrivate; 0662 friend class ItemModifyJob; 0663 friend class ItemModifyJobPrivate; 0664 friend class ItemSync; 0665 friend class ProtocolHelper; 0666 Internal::PayloadBase *payloadBaseV2(int sharedPointerId, int metaTypeId) const; 0667 void setPayloadBaseV2(int sharedPointerId, int metaTypeId, std::unique_ptr<Internal::PayloadBase> &p); 0668 void addPayloadBaseVariant(int sharedPointerId, int metaTypeId, std::unique_ptr<Internal::PayloadBase> &p) const; 0669 0670 /** 0671 * Try to ensure that we have a variant of the payload for metatype id @a mtid. 0672 * @return @c true if a type exists or could be created through conversion, @c false otherwise. 0673 */ 0674 bool ensureMetaTypeId(int mtid) const; 0675 0676 template<typename T> 0677 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, void>::type setPayloadImpl(const T &p, const int * /*disambiguate*/ = nullptr); 0678 template<typename T> 0679 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, void>::type setPayloadImpl(const T &p); 0680 0681 template<typename T> 0682 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, T>::type payloadImpl(const int * /*disambiguate*/ = nullptr) const; 0683 template<typename T> 0684 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, T>::type payloadImpl() const; 0685 0686 template<typename T> 0687 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, bool>::type hasPayloadImpl(const int * /*disambiguate*/ = nullptr) const; 0688 template<typename T> 0689 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, bool>::type hasPayloadImpl() const; 0690 0691 template<typename T> 0692 typename std::enable_if<Internal::is_shared_pointer<T>::value, bool>::type tryToClone(T *ret, const int * /*disambiguate*/ = nullptr) const; 0693 template<typename T> 0694 typename std::enable_if<!Internal::is_shared_pointer<T>::value, bool>::type tryToClone(T *ret) const; 0695 0696 template<typename T, typename NewT> 0697 typename std::enable_if<!std::is_same<T, NewT>::value, bool>::type tryToCloneImpl(T *ret, const int * /*disambiguate*/ = nullptr) const; 0698 template<typename T, typename NewT> 0699 typename std::enable_if<std::is_same<T, NewT>::value, bool>::type tryToCloneImpl(T *ret) const; 0700 0701 /** 0702 * Set the collection ID to where the item is stored in. Should be set only by the ItemFetchJob. 0703 * @param collectionId the unique identifier of the collection where this item is stored in. 0704 * @since 4.3 0705 */ 0706 void setStorageCollectionId(Collection::Id collectionId); 0707 0708 void throwPayloadException(int spid, int mtid) const; 0709 0710 QSharedDataPointer<ItemPrivate> d_ptr; 0711 friend class ItemPrivate; 0712 /// @endcond 0713 }; 0714 0715 AKONADICORE_EXPORT size_t qHash(const Akonadi::Item &item, size_t seed = 0) noexcept; 0716 0717 template<typename T> 0718 inline T *Item::attribute(Item::CreateOption option) 0719 { 0720 const QByteArray type = T().type(); 0721 if (hasAttribute(type)) { 0722 if (T *attr = dynamic_cast<T *>(attribute(type))) { 0723 return attr; 0724 } 0725 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?"; 0726 } else if (option == AddIfMissing) { 0727 T *attr = new T(); 0728 addAttribute(attr); 0729 return attr; 0730 } 0731 0732 return nullptr; 0733 } 0734 0735 template<typename T> 0736 inline const T *Item::attribute() const 0737 { 0738 const QByteArray type = T().type(); 0739 if (hasAttribute(type)) { 0740 if (const T *attr = dynamic_cast<const T *>(attribute(type))) { 0741 return attr; 0742 } 0743 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?"; 0744 } 0745 0746 return nullptr; 0747 } 0748 0749 template<typename T> 0750 inline void Item::removeAttribute() 0751 { 0752 removeAttribute(T().type()); 0753 } 0754 0755 template<typename T> 0756 inline bool Item::hasAttribute() const 0757 { 0758 return hasAttribute(T().type()); 0759 } 0760 0761 template<typename T> 0762 T Item::payload() const 0763 { 0764 static_assert(!std::is_pointer<T>::value, "Payload must not be a pointer"); 0765 0766 if (!hasPayload()) { 0767 throwPayloadException(-1, -1); 0768 } 0769 0770 return payloadImpl<T>(); 0771 } 0772 0773 template<typename T> 0774 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, T>::type Item::payloadImpl(const int *) const 0775 { 0776 using PayloadType = Internal::PayloadTrait<T>; 0777 static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is not allowed"); 0778 0779 using Root_T = typename Internal::get_hierarchy_root<T>::type; 0780 using RootType = Internal::PayloadTrait<Root_T>; 0781 static_assert(!RootType::isPolymorphic, 0782 "Root type of payload type must not be polymorphic"); // prevent endless recursion 0783 0784 return PayloadType::castFrom(payloadImpl<Root_T>()); 0785 } 0786 0787 template<typename T> 0788 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, T>::type Item::payloadImpl() const 0789 { 0790 using PayloadType = Internal::PayloadTrait<T>; 0791 static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed"); 0792 0793 const int metaTypeId = PayloadType::elementMetaTypeId(); 0794 0795 // make sure that we have a payload format represented by 'metaTypeId': 0796 if (!ensureMetaTypeId(metaTypeId)) { 0797 throwPayloadException(PayloadType::sharedPointerId, metaTypeId); 0798 } 0799 0800 // Check whether we have the exact payload 0801 // (metatype id and shared pointer type match) 0802 if (const Internal::Payload<T> *const p = Internal::payload_cast<T>(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) { 0803 return p->payload; 0804 } 0805 0806 T ret; 0807 if (!tryToClone<T>(&ret)) { 0808 throwPayloadException(PayloadType::sharedPointerId, metaTypeId); 0809 } 0810 return ret; 0811 } 0812 0813 template<typename T, typename NewT> 0814 typename std::enable_if<!std::is_same<T, NewT>::value, bool>::type Item::tryToCloneImpl(T *ret, const int *) const 0815 { 0816 using PayloadType = Internal::PayloadTrait<T>; 0817 using NewPayloadType = Internal::PayloadTrait<NewT>; 0818 0819 const int metaTypeId = PayloadType::elementMetaTypeId(); 0820 Internal::PayloadBase *payloadBase = payloadBaseV2(NewPayloadType::sharedPointerId, metaTypeId); 0821 if (const Internal::Payload<NewT> *const p = Internal::payload_cast<NewT>(payloadBase)) { 0822 // If found, attempt to make a clone (required the payload to provide virtual T * T::clone() const) 0823 const T nt = PayloadType::clone(p->payload); 0824 if (!PayloadType::isNull(nt)) { 0825 // if clone succeeded, add the clone to the Item: 0826 std::unique_ptr<Internal::PayloadBase> npb(new Internal::Payload<T>(nt)); 0827 addPayloadBaseVariant(PayloadType::sharedPointerId, metaTypeId, npb); 0828 // and return it 0829 if (ret) { 0830 *ret = nt; 0831 } 0832 return true; 0833 } 0834 } 0835 0836 return tryToCloneImpl<T, typename Internal::shared_pointer_traits<NewT>::next_shared_ptr>(ret); 0837 } 0838 0839 template<typename T, typename NewT> 0840 typename std::enable_if<std::is_same<T, NewT>::value, bool>::type Item::tryToCloneImpl(T *) const 0841 { 0842 return false; 0843 } 0844 0845 template<typename T> 0846 typename std::enable_if<Internal::is_shared_pointer<T>::value, bool>::type Item::tryToClone(T *ret, const int *) const 0847 { 0848 using PayloadType = Internal::PayloadTrait<T>; 0849 static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed"); 0850 0851 return tryToCloneImpl<T, typename Internal::shared_pointer_traits<T>::next_shared_ptr>(ret); 0852 } 0853 0854 template<typename T> 0855 typename std::enable_if<!Internal::is_shared_pointer<T>::value, bool>::type Item::tryToClone(T *) const 0856 { 0857 using PayloadType = Internal::PayloadTrait<T>; 0858 static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed"); 0859 0860 return false; 0861 } 0862 0863 template<typename T> 0864 bool Item::hasPayload() const 0865 { 0866 static_assert(!std::is_pointer<T>::value, "Payload type cannot be a pointer"); 0867 return hasPayload() && hasPayloadImpl<T>(); 0868 } 0869 0870 template<typename T> 0871 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, bool>::type Item::hasPayloadImpl(const int *) const 0872 { 0873 using PayloadType = Internal::PayloadTrait<T>; 0874 static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is no allowed"); 0875 0876 using Root_T = typename Internal::get_hierarchy_root<T>::type; 0877 using RootType = Internal::PayloadTrait<Root_T>; 0878 static_assert(!RootType::isPolymorphic, 0879 "Root type of payload type must not be polymorphic"); // prevent endless recursion 0880 0881 try { 0882 return hasPayloadImpl<Root_T>() && PayloadType::canCastFrom(payload<Root_T>()); 0883 } catch (const Akonadi::PayloadException &e) { 0884 qDebug() << e.what(); 0885 Q_UNUSED(e) 0886 return false; 0887 } 0888 } 0889 0890 template<typename T> 0891 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, bool>::type Item::hasPayloadImpl() const 0892 { 0893 using PayloadType = Internal::PayloadTrait<T>; 0894 static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed"); 0895 0896 const int metaTypeId = PayloadType::elementMetaTypeId(); 0897 0898 // make sure that we have a payload format represented by 'metaTypeId': 0899 if (!ensureMetaTypeId(metaTypeId)) { 0900 return false; 0901 } 0902 0903 // Check whether we have the exact payload 0904 // (metatype id and shared pointer type match) 0905 if (const Internal::Payload<T> *const p = Internal::payload_cast<T>(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) { 0906 return true; 0907 } 0908 0909 return tryToClone<T>(nullptr); 0910 } 0911 0912 template<typename T> 0913 void Item::setPayload(const T &p) 0914 { 0915 static_assert(!std::is_pointer<T>::value, "Payload type must not be a pointer"); 0916 setPayloadImpl(p); 0917 } 0918 0919 template<typename T> 0920 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic>::type Item::setPayloadImpl(const T &p, const int *) 0921 { 0922 using PayloadType = Internal::PayloadTrait<T>; 0923 static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is not allowed"); 0924 0925 using Root_T = typename Internal::get_hierarchy_root<T>::type; 0926 using RootType = Internal::PayloadTrait<Root_T>; 0927 static_assert(!RootType::isPolymorphic, 0928 "Root type of payload type must not be polymorphic"); // prevent endless recursion 0929 0930 setPayloadImpl<Root_T>(p); 0931 } 0932 0933 template<typename T> 0934 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic>::type Item::setPayloadImpl(const T &p) 0935 { 0936 using PayloadType = Internal::PayloadTrait<T>; 0937 std::unique_ptr<Internal::PayloadBase> pb(new Internal::Payload<T>(p)); 0938 setPayloadBaseV2(PayloadType::sharedPointerId, PayloadType::elementMetaTypeId(), pb); 0939 } 0940 0941 template<typename T> 0942 void Item::setPayload(T *p) 0943 { 0944 p->You_MUST_NOT_use_a_pointer_as_payload; 0945 } 0946 0947 } // namespace Akonadi 0948 0949 Q_DECLARE_METATYPE(Akonadi::Item) 0950 Q_DECLARE_METATYPE(Akonadi::Item::List) 0951 Q_DECLARE_TYPEINFO(Akonadi::Item, Q_RELOCATABLE_TYPE);