Akonadi

item.h
1/*
2 SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org>
3 2007 Till Adam <adam@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#pragma once
9
10#include "akonadicore_export.h"
11#include "attribute.h"
12#include "collection.h"
13#include "exceptionbase.h"
14#include "itempayloadinternals_p.h"
15#include "job.h"
16#include "relation.h"
17#include "tag.h"
18
19#include <QByteArray>
20#include <QMetaType>
21#include <QSet>
22
23#include <memory>
24#include <type_traits>
25#include <typeinfo>
26
27class QUrl;
28template<typename T>
29class QList;
30
31namespace Akonadi
32{
33class ItemPrivate;
34
35/**
36 * @short Represents a PIM item stored in Akonadi storage.
37 *
38 * A PIM item consists of one or more parts, allowing a fine-grained access on its
39 * content where needed (eg. mail envelope, mail body and attachments).
40 *
41 * There is also a namespace (prefix) for special parts which are local to Akonadi.
42 * These parts, prefixed by "akonadi-", will never be fetched in the resource.
43 * They are useful for local extensions like agents which might want to add meta data
44 * to items in order to handle them but the meta data should not be stored back to the
45 * resource.
46 *
47 * This class is implicitly shared.
48 *
49 * <h4>Payload</h4>
50 *
51 * This class contains, beside some type-agnostic information (flags, revision),
52 * zero or more payload objects representing its actual data. Which objects these actually
53 * are depends on the mimetype of the item and the corresponding serializer plugin(s).
54 *
55 * Technically the only restriction on payload objects is that they have to be copyable.
56 * For safety reasons, pointer payloads are forbidden as well though, as the
57 * ownership would not be clear. In this case, usage of a shared pointer is
58 * recommended (such as QSharedPointer or std::shared_ptr).
59 *
60 * Using a shared pointer is also required in case the payload is a polymorphic
61 * type. For supported shared pointer types implicit casting is provided when possible.
62 *
63 * When using a value-based class as payload, it is recommended to use one that does
64 * support implicit sharing as setting and retrieving a payload as well as copying
65 * an Akonadi::Item object imply copying of the payload object.
66 *
67 * Since KDE 4.6, Item supports multiple payload types per mime type,
68 * and will automatically convert between them using the serialiser
69 * plugins (which is slow). It also supports mixing shared pointer
70 * types, e.g. inserting a std::shared_ptr<Foo> and extracting a
71 * QSharedPointer<Foo>. Since the two shared pointer types cannot
72 * share ownership of the same object, the payload class @c T needs to
73 * provide a @c clone() method with the usual signature, ie.
74 *
75 * @code
76 * virtual T * T::clone() const
77 * @endcode
78 *
79 * If the class that does not have a @c clone() method, asking for an
80 * incompatible shared pointer will throw a PayloadException.
81 *
82 * Since using different shared pointer types and different payload
83 * types for the same mimetype incurs slow conversions (between
84 * payload types) and cloning (between shared pointer types), as well
85 * as manifold memory usage (results of conversions are cached inside
86 * the Item, and only destroyed when a new payload is set by the user
87 * of the class), you want to restrict yourself to just one type and
88 * one shared pointer type. This mechanism was mainly introduced for
89 * backwards compatibility (e.g., putting in a
90 * std::shared_ptr<KCal::Incidence> and extracting a
91 * QSharedPointer<KCalCore::Incidence>), so it is not optimized for
92 * performance.
93 *
94 * The availability of a payload of a specific type can be checked using hasPayload(),
95 * payloads can be retrieved by using payload() and set by using setPayload(). Refer
96 * to the documentation of those methods for more details.
97 *
98 * @author Volker Krause <vkrause@kde.org>, Till Adam <adam@kde.org>, Marc Mutz <mutz@kde.org>
99 */
100class AKONADICORE_EXPORT Item
101{
102public:
103 /**
104 * Describes the unique id type.
105 */
106 using Id = qint64;
107
108 /**
109 * Describes a list of items.
110 */
112
113 /**
114 * Describes a flag name.
115 */
117
118 /**
119 * Describes a set of flag names.
120 */
122
123 /**
124 * Describes the part name that is used to fetch the
125 * full payload of an item.
126 */
127 static const char FullPayload[];
128
129 /**
130 * Creates a new item.
131 */
132 Item();
133
134 /**
135 * Creates a new item with the given unique @p id.
136 */
137 explicit Item(Id id);
138
139 /**
140 * Creates a new item with the given mime type.
141 *
142 * @param mimeType The mime type of the item.
143 */
144 explicit Item(const QString &mimeType);
145
146 /**
147 * Creates a new item from an @p other item.
148 */
149 Item(const Item &other);
150
151 /**
152 * Move constructor.
153 */
154 Item(Item &&) noexcept;
155
156 /**
157 * Destroys the item.
158 */
160
161 /**
162 * Creates an item from the given @p url.
163 */
164 static Item fromUrl(const QUrl &url);
165
166 /**
167 * Sets the unique @p identifier of the item.
168 */
169 void setId(Id identifier);
170
171 /**
172 * Returns the unique identifier of the item.
173 */
174 Id id() const;
175
176 /**
177 * Sets the remote @p id of the item.
178 */
179 void setRemoteId(const QString &id);
180
181 /**
182 * Returns the remote id of the item.
183 */
184 QString remoteId() const;
185
186 /**
187 * Sets the remote @p revision of the item.
188 * @param revision the item's remote revision
189 * The remote revision can be used by resources to store some
190 * revision information of the backend to detect changes there.
191 *
192 * @note This method is supposed to be used by resources only.
193 * @since 4.5
194 */
195 void setRemoteRevision(const QString &revision);
196
197 /**
198 * Returns the remote revision of the item.
199 *
200 * @note This method is supposed to be used by resources only.
201 * @since 4.5
202 */
203 QString remoteRevision() const;
204
205 /**
206 * Returns whether the item is valid.
207 */
208 bool isValid() const;
209
210 /**
211 * Returns whether this item's id equals the id of the @p other item.
212 */
213 bool operator==(const Item &other) const;
214
215 /**
216 * Returns whether the item's id does not equal the id of the @p other item.
217 */
218 bool operator!=(const Item &other) const;
219
220 /**
221 * Assigns the @p other to this item and returns a reference to this item.
222 * @param other the item to assign
223 */
224 Item &operator=(const Item &other);
225
226 /**
227 * @internal For use with containers only.
228 *
229 * @since 4.8
230 */
231 bool operator<(const Item &other) const;
232
233 /**
234 * Returns the parent collection of this object.
235 * @note This will of course only return a useful value if it was explicitly retrieved
236 * from the Akonadi server.
237 * @since 4.4
238 */
239 Collection parentCollection() const;
240
241 /**
242 * Returns a reference to the parent collection of this object.
243 * @note This will of course only return a useful value if it was explicitly retrieved
244 * from the Akonadi server.
245 * @since 4.4
246 */
247 Collection &parentCollection();
248
249 /**
250 * Set the parent collection of this object.
251 * @note Calling this method has no immediate effect for the object itself,
252 * such as being moved to another collection.
253 * It is mainly relevant to provide a context for RID-based operations
254 * inside resources.
255 * @param parent The parent collection.
256 * @since 4.4
257 */
258 void setParentCollection(const Collection &parent);
259
260 /**
261 * Adds an attribute to the item.
262 *
263 * If an attribute of the same type name already exists, it is deleted and
264 * replaced with the new one.
265 *
266 * @param attribute The new attribute.
267 *
268 * @note The collection takes the ownership of the attribute.
269 */
270 void addAttribute(Attribute *attribute);
271
272 /**
273 * Removes and deletes the attribute of the given type @p name.
274 */
275 void removeAttribute(const QByteArray &name);
276
277 /**
278 * Returns @c true if the item has an attribute of the given type @p name,
279 * false otherwise.
280 */
281 bool hasAttribute(const QByteArray &name) const;
282
283 /**
284 * Returns a list of all attributes of the item.
285 *
286 * @warning Do not modify the attributes returned from this method,
287 * the change will not be reflected when updating the Item through
288 * ItemModifyJob.
289 */
290 Attribute::List attributes() const;
291
292 /**
293 * Removes and deletes all attributes of the item.
294 */
295 void clearAttributes();
296
297 /**
298 * Returns the attribute of the given type @p name if available, 0 otherwise.
299 */
300 Attribute *attribute(const QByteArray &name);
301 const Attribute *attribute(const QByteArray &name) const;
302
303 /**
304 * Describes the options that can be passed to access attributes.
305 */
307 AddIfMissing, ///< Creates the attribute if it is missing
308 DontCreate ///< Do not create the attribute if it is missing (default)
309 };
310
311 /**
312 * Returns the attribute of the requested type.
313 * If the item has no attribute of that type yet, a new one
314 * is created and added to the entity.
315 *
316 * @param option The create options.
317 */
318 template<typename T>
319 inline T *attribute(CreateOption option = DontCreate);
320
321 /**
322 * Returns the attribute of the requested type or 0 if it is not available.
323 */
324 template<typename T>
325 inline const T *attribute() const;
326
327 /**
328 * Removes and deletes the attribute of the requested type.
329 */
330 template<typename T>
331 inline void removeAttribute();
332
333 /**
334 * Returns whether the item has an attribute of the requested type.
335 */
336 template<typename T>
337 inline bool hasAttribute() const;
338
339 /**
340 * Returns all flags of this item.
341 */
342 Flags flags() const;
343
344 /**
345 * Returns the timestamp of the last modification of this item.
346 * @since 4.2
347 */
348 QDateTime modificationTime() const;
349
350 /**
351 * Sets the timestamp of the last modification of this item.
352 * @param datetime the modification time to set
353 * @note Do not modify this value from within an application,
354 * it is updated automatically by the revision checking functions.
355 * @since 4.2
356 */
357 void setModificationTime(const QDateTime &datetime);
358
359 /**
360 * Returns whether the flag with the given @p name is
361 * set in the item.
362 */
363 bool hasFlag(const QByteArray &name) const;
364
365 /**
366 * Sets the flag with the given @p name in the item.
367 */
368 void setFlag(const QByteArray &name);
369
370 /**
371 * Removes the flag with the given @p name from the item.
372 */
373 void clearFlag(const QByteArray &name);
374
375 /**
376 * Overwrites all flags of the item by the given @p flags.
377 */
378 void setFlags(const Flags &flags);
379
380 /**
381 * Removes all flags from the item.
382 */
383 void clearFlags();
384
385 void setTags(const Tag::List &list);
386
387 void setTag(const Tag &tag);
388
389 Tag::List tags() const;
390
391 bool hasTag(const Tag &tag) const;
392
393 void clearTag(const Tag &tag);
394
395 void clearTags();
396
397 /**
398 * Returns all relations of this item.
399 * @since 4.15
400 * @see RelationCreateJob, RelationDeleteJob to modify relations
401 */
402 Relation::List relations() const;
403
404 /**
405 * Sets the payload based on the canonical representation normally
406 * used for data of this mime type.
407 *
408 * @param data The encoded data.
409 * @see fullPayloadData
410 */
411 void setPayloadFromData(const QByteArray &data);
412
413 /**
414 * Returns the full payload in its canonical representation, e.g. the
415 * binary or textual format usually used for data with this mime type.
416 * This is useful when communicating with non-Akonadi application by
417 * e.g. drag&drop, copy&paste or stored files.
418 */
419 QByteArray payloadData() const;
420
421 /**
422 * Returns the list of loaded payload parts. This is not necessarily
423 * identical to all parts in the cache or to all available parts on the backend.
424 */
425 QSet<QByteArray> loadedPayloadParts() const;
426
427 /**
428 * Marks that the payload shall be cleared from the cache when this
429 * item is passed to an ItemModifyJob the next time.
430 * This will trigger a refetch of the payload from the backend when the
431 * item is accessed afterwards. Only resources should have a need for
432 * this functionality.
433 *
434 * @since 4.5
435 */
436 void clearPayload();
437
438 /**
439 * Sets the @p revision number of the item.
440 * @param revision the revision number to set
441 * @note Do not modify this value from within an application,
442 * it is updated automatically by the revision checking functions.
443 */
444 void setRevision(int revision);
445
446 /**
447 * Returns the revision number of the item.
448 */
449 int revision() const;
450
451 /**
452 * Returns the unique identifier of the collection this item is stored in. There is only
453 * a single such collection, although the item can be linked into arbitrary many
454 * virtual collections.
455 * Calling this method makes sense only after running an ItemFetchJob on the item.
456 * @returns the collection ID if it is known, -1 otherwise.
457 * @since 4.3
458 */
459 Collection::Id storageCollectionId() const;
460
461 /**
462 * Set the size of the item in bytes.
463 * @param size the size of the item in bytes
464 * @since 4.2
465 */
466 void setSize(qint64 size);
467
468 /**
469 * Returns the size of the items in bytes.
470 *
471 * @since 4.2
472 */
473 qint64 size() const;
474
475 /**
476 * Sets the mime type of the item to @p mimeType.
477 */
478 void setMimeType(const QString &mimeType);
479
480 /**
481 * Returns the mime type of the item.
482 */
483 QString mimeType() const;
484
485 /**
486 * Sets the @p gid of the entity.
487 *
488 * @since 4.12
489 */
490 void setGid(const QString &gid);
491
492 /**
493 * Returns the gid of the entity.
494 *
495 * @since 4.12
496 */
497 QString gid() const;
498
499 /**
500 * Sets the virtual @p collections that this item is linked into.
501 *
502 * @note Note that changing this value makes no effect on what collections
503 * this item is linked to. To link or unlink an item to/from a virtual
504 * collection, use LinkJob and UnlinkJob.
505 *
506 * @since 4.14
507 */
508 void setVirtualReferences(const Collection::List &collections);
509
510 /**
511 * Lists virtual collections that this item is linked to.
512 *
513 * @note This value is populated only when this item was retrieved by
514 * ItemFetchJob with fetchVirtualReferences set to true in ItemFetchScope,
515 * otherwise this list is always empty.
516 *
517 * @since 4.14
518 */
519 Collection::List virtualReferences() const;
520
521 /**
522 * Returns a list of metatype-ids, describing the different
523 * variants of payload that are currently contained in this item.
524 *
525 * The result is always sorted (increasing ids).
526 */
527 QList<int> availablePayloadMetaTypeIds() const;
528
529 /**
530 * Sets a path to a file with full payload.
531 *
532 * This method can only be used by Resources and should not be used by Akonadi
533 * clients. Clients should use setPayload() instead.
534 *
535 * Akonadi will not duplicate content of the file in its database but will
536 * instead directly refer to this file. This means that the file must be
537 * persistent (don't use this method with a temporary files), and the Akonadi
538 * resource that owns the storage is responsible for updating the file path
539 * if the file is changed, moved or removed.
540 *
541 * The payload can still be accessed via payload() methods.
542 *
543 * @see setPayload(), setPayloadFromData()
544 * @since 5.6
545 */
546 void setPayloadPath(const QString &filePath);
547
548 /**
549 * Returns path to the payload file set by setPayloadPath()
550 *
551 * If payload was set via setPayload() or setPayloadFromData() then this
552 * method will return a null string.
553 */
554 QString payloadPath() const;
555
556 /**
557 * Sets the payload object of this PIM item.
558 *
559 * @param p The payload object. Must be copyable and must not be a pointer,
560 * will cause a compilation failure otherwise. Using a type that can be copied
561 * fast (such as implicitly shared classes) is recommended.
562 * If the payload type is polymorphic and you intend to set and retrieve payload
563 * objects with mismatching but castable types, make sure to use a supported
564 * shared pointer implementation (currently QSharedPointer and std::shared_ptr)
565 * and make sure there is a specialization of Akonadi::super_trait for your class.
566 */
567 template<typename T>
568 void setPayload(const T &p);
569 /// @cond PRIVATE
570 template<typename T>
571 void setPayload(T *p);
572 /// @endcond
573
574 /**
575 * Returns the payload object of this PIM item. This method will only succeed if either
576 * you requested the exact same payload type that was put in or the payload uses a
577 * supported shared pointer type (currently QSharedPointer and std::shared_ptr),
578 * and is castable to the requested type. For this to work there needs
579 * to be a specialization of Akonadi::super_trait of the used classes.
580 *
581 * If a mismatching or non-castable payload type is requested, an Akonadi::PayloadException
582 * is thrown. Therefore it is generally recommended to guard calls to payload() with a
583 * corresponding hasPayload() call.
584 *
585 * Trying to retrieve a pointer type will fail to compile.
586 */
587 template<typename T>
588 T payload() const;
589
590 /**
591 * Returns whether the item has a payload object.
592 */
593 bool hasPayload() const;
594
595 /**
596 * Returns whether the item has a payload of type @c T.
597 * This method will only return @c true if either you requested the exact same payload type
598 * that was put in or the payload uses a supported shared pointer type (currently
599 * QSharedPointer and std::shared_ptr), and is castable to the requested type. For this to work there needs
600 * to be a specialization of Akonadi::super_trait of the used classes.
601 *
602 * Trying to retrieve a pointer type will fail to compile.
603 */
604 template<typename T>
605 bool hasPayload() const;
606
607 /**
608 * Describes the type of url which is returned in url().
609 */
610 enum UrlType {
611 UrlShort = 0, ///< A short url which contains the identifier only (default)
612 UrlWithMimeType = 1 ///< A url with identifier and mimetype
613 };
614
615 /**
616 * Returns the url of the item.
617 */
618 QUrl url(UrlType type = UrlShort) const;
619
620 /**
621 * Returns the parts available for this item.
622 *
623 * The returned set refers to parts available on the akonadi server or remotely,
624 * but does not include the loadedPayloadParts() of this item.
625 *
626 * @since 4.4
627 */
628 QSet<QByteArray> availablePayloadParts() const;
629
630 /**
631 * Returns the parts available for this item in the cache. The list might be a subset
632 * of the actual parts in cache, as it contains only the requested parts. See @see ItemFetchJob and
633 * @see ItemFetchScope
634 *
635 * The returned set refers to parts available on the akonadi server.
636 *
637 * @since 4.11
638 */
639 QSet<QByteArray> cachedPayloadParts() const;
640
641 /**
642 * Applies the parts of Item @p other to this item.
643 * Any parts or attributes available in other, will be applied to this item,
644 * and the payload parts of other will be inserted into this item, overwriting
645 * any existing parts with the same part name.
646 *
647 * If there is an ItemSerialzerPluginV2 for the type, the merge method in that plugin is
648 * used to perform the merge. If only an ItemSerialzerPlugin class is found, or the merge
649 * method of the -V2 plugin is not implemented, the merge is performed with multiple deserializations
650 * of the payload.
651 * @param other the item to get values from
652 * @since 4.4
653 */
654 void apply(const Item &other);
655
656 void setCachedPayloadParts(const QSet<QByteArray> &cachedParts);
657
658private:
659 /// @cond PRIVATE
660 friend class ItemCreateJob;
661 friend class ItemCreateJobPrivate;
662 friend class ItemModifyJob;
663 friend class ItemModifyJobPrivate;
664 friend class ItemSync;
665 friend class ProtocolHelper;
666 Internal::PayloadBase *payloadBaseV2(int sharedPointerId, int metaTypeId) const;
667 void setPayloadBaseV2(int sharedPointerId, int metaTypeId, std::unique_ptr<Internal::PayloadBase> &p);
668 void addPayloadBaseVariant(int sharedPointerId, int metaTypeId, std::unique_ptr<Internal::PayloadBase> &p) const;
669
670 /**
671 * Try to ensure that we have a variant of the payload for metatype id @a mtid.
672 * @return @c true if a type exists or could be created through conversion, @c false otherwise.
673 */
674 bool ensureMetaTypeId(int mtid) const;
675
676 template<typename T>
677 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, void>::type setPayloadImpl(const T &p, const int * /*disambiguate*/ = nullptr);
678 template<typename T>
679 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, void>::type setPayloadImpl(const T &p);
680
681 template<typename T>
682 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, T>::type payloadImpl(const int * /*disambiguate*/ = nullptr) const;
683 template<typename T>
684 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, T>::type payloadImpl() const;
685
686 template<typename T>
687 typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, bool>::type hasPayloadImpl(const int * /*disambiguate*/ = nullptr) const;
688 template<typename T>
689 typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, bool>::type hasPayloadImpl() const;
690
691 template<typename T>
692 typename std::enable_if<Internal::is_shared_pointer<T>::value, bool>::type tryToClone(T *ret, const int * /*disambiguate*/ = nullptr) const;
693 template<typename T>
694 typename std::enable_if<!Internal::is_shared_pointer<T>::value, bool>::type tryToClone(T *ret) const;
695
696 template<typename T, typename NewT>
697 typename std::enable_if<!std::is_same<T, NewT>::value, bool>::type tryToCloneImpl(T *ret, const int * /*disambiguate*/ = nullptr) const;
698 template<typename T, typename NewT>
699 typename std::enable_if<std::is_same<T, NewT>::value, bool>::type tryToCloneImpl(T *ret) const;
700
701 /**
702 * Set the collection ID to where the item is stored in. Should be set only by the ItemFetchJob.
703 * @param collectionId the unique identifier of the collection where this item is stored in.
704 * @since 4.3
705 */
706 void setStorageCollectionId(Collection::Id collectionId);
707
708 void throwPayloadException(int spid, int mtid) const;
709
711 friend class ItemPrivate;
712 /// @endcond
713};
714
715AKONADICORE_EXPORT size_t qHash(const Akonadi::Item &item, size_t seed = 0) noexcept;
716
717template<typename T>
718inline T *Item::attribute(Item::CreateOption option)
719{
720 const QByteArray type = T().type();
721 if (hasAttribute(type)) {
722 if (T *attr = dynamic_cast<T *>(attribute(type))) {
723 return attr;
724 }
725 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?";
726 } else if (option == AddIfMissing) {
727 T *attr = new T();
728 addAttribute(attr);
729 return attr;
730 }
731
732 return nullptr;
733}
734
735template<typename T>
736inline const T *Item::attribute() const
737{
738 const QByteArray type = T().type();
739 if (hasAttribute(type)) {
740 if (const T *attr = dynamic_cast<const T *>(attribute(type))) {
741 return attr;
742 }
743 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?";
744 }
745
746 return nullptr;
747}
748
749template<typename T>
751{
752 removeAttribute(T().type());
753}
754
755template<typename T>
756inline bool Item::hasAttribute() const
757{
758 return hasAttribute(T().type());
759}
760
761template<typename T>
763{
764 static_assert(!std::is_pointer<T>::value, "Payload must not be a pointer");
765
766 if (!hasPayload()) {
767 throwPayloadException(-1, -1);
768 }
769
770 return payloadImpl<T>();
771}
772
773template<typename T>
774typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, T>::type Item::payloadImpl(const int *) const
775{
776 using PayloadType = Internal::PayloadTrait<T>;
777 static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is not allowed");
778
779 using Root_T = typename Internal::get_hierarchy_root<T>::type;
780 using RootType = Internal::PayloadTrait<Root_T>;
781 static_assert(!RootType::isPolymorphic,
782 "Root type of payload type must not be polymorphic"); // prevent endless recursion
783
784 return PayloadType::castFrom(payloadImpl<Root_T>());
785}
786
787template<typename T>
788typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, T>::type Item::payloadImpl() const
789{
790 using PayloadType = Internal::PayloadTrait<T>;
791 static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed");
792
793 const int metaTypeId = PayloadType::elementMetaTypeId();
794
795 // make sure that we have a payload format represented by 'metaTypeId':
796 if (!ensureMetaTypeId(metaTypeId)) {
797 throwPayloadException(PayloadType::sharedPointerId, metaTypeId);
798 }
799
800 // Check whether we have the exact payload
801 // (metatype id and shared pointer type match)
802 if (const Internal::Payload<T> *const p = Internal::payload_cast<T>(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) {
803 return p->payload;
804 }
805
806 T ret;
807 if (!tryToClone<T>(&ret)) {
808 throwPayloadException(PayloadType::sharedPointerId, metaTypeId);
809 }
810 return ret;
811}
812
813template<typename T, typename NewT>
814typename std::enable_if<!std::is_same<T, NewT>::value, bool>::type Item::tryToCloneImpl(T *ret, const int *) const
815{
816 using PayloadType = Internal::PayloadTrait<T>;
817 using NewPayloadType = Internal::PayloadTrait<NewT>;
818
819 const int metaTypeId = PayloadType::elementMetaTypeId();
820 Internal::PayloadBase *payloadBase = payloadBaseV2(NewPayloadType::sharedPointerId, metaTypeId);
821 if (const Internal::Payload<NewT> *const p = Internal::payload_cast<NewT>(payloadBase)) {
822 // If found, attempt to make a clone (required the payload to provide virtual T * T::clone() const)
823 const T nt = PayloadType::clone(p->payload);
824 if (!PayloadType::isNull(nt)) {
825 // if clone succeeded, add the clone to the Item:
826 std::unique_ptr<Internal::PayloadBase> npb(new Internal::Payload<T>(nt));
827 addPayloadBaseVariant(PayloadType::sharedPointerId, metaTypeId, npb);
828 // and return it
829 if (ret) {
830 *ret = nt;
831 }
832 return true;
833 }
834 }
835
836 return tryToCloneImpl<T, typename Internal::shared_pointer_traits<NewT>::next_shared_ptr>(ret);
837}
838
839template<typename T, typename NewT>
840typename std::enable_if<std::is_same<T, NewT>::value, bool>::type Item::tryToCloneImpl(T *) const
841{
842 return false;
843}
844
845template<typename T>
846typename std::enable_if<Internal::is_shared_pointer<T>::value, bool>::type Item::tryToClone(T *ret, const int *) const
847{
848 using PayloadType = Internal::PayloadTrait<T>;
849 static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed");
850
851 return tryToCloneImpl<T, typename Internal::shared_pointer_traits<T>::next_shared_ptr>(ret);
852}
853
854template<typename T>
855typename std::enable_if<!Internal::is_shared_pointer<T>::value, bool>::type Item::tryToClone(T *) const
856{
857 using PayloadType = Internal::PayloadTrait<T>;
858 static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed");
859
860 return false;
861}
862
863template<typename T>
864bool Item::hasPayload() const
865{
866 static_assert(!std::is_pointer<T>::value, "Payload type cannot be a pointer");
867 return hasPayload() && hasPayloadImpl<T>();
868}
869
870template<typename T>
871typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, bool>::type Item::hasPayloadImpl(const int *) const
872{
873 using PayloadType = Internal::PayloadTrait<T>;
874 static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is no allowed");
875
876 using Root_T = typename Internal::get_hierarchy_root<T>::type;
877 using RootType = Internal::PayloadTrait<Root_T>;
878 static_assert(!RootType::isPolymorphic,
879 "Root type of payload type must not be polymorphic"); // prevent endless recursion
880
881 try {
882 return hasPayloadImpl<Root_T>() && PayloadType::canCastFrom(payload<Root_T>());
883 } catch (const Akonadi::PayloadException &e) {
884 qDebug() << e.what();
885 Q_UNUSED(e)
886 return false;
887 }
888}
889
890template<typename T>
891typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, bool>::type Item::hasPayloadImpl() const
892{
893 using PayloadType = Internal::PayloadTrait<T>;
894 static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed");
895
896 const int metaTypeId = PayloadType::elementMetaTypeId();
897
898 // make sure that we have a payload format represented by 'metaTypeId':
899 if (!ensureMetaTypeId(metaTypeId)) {
900 return false;
901 }
902
903 // Check whether we have the exact payload
904 // (metatype id and shared pointer type match)
905 if (const Internal::Payload<T> *const p = Internal::payload_cast<T>(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) {
906 return true;
907 }
908
909 return tryToClone<T>(nullptr);
910}
911
912template<typename T>
913void Item::setPayload(const T &p)
914{
915 static_assert(!std::is_pointer<T>::value, "Payload type must not be a pointer");
916 setPayloadImpl(p);
917}
918
919template<typename T>
920typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic>::type Item::setPayloadImpl(const T &p, const int *)
921{
922 using PayloadType = Internal::PayloadTrait<T>;
923 static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is not allowed");
924
925 using Root_T = typename Internal::get_hierarchy_root<T>::type;
926 using RootType = Internal::PayloadTrait<Root_T>;
927 static_assert(!RootType::isPolymorphic,
928 "Root type of payload type must not be polymorphic"); // prevent endless recursion
929
930 setPayloadImpl<Root_T>(p);
931}
932
933template<typename T>
934typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic>::type Item::setPayloadImpl(const T &p)
935{
936 using PayloadType = Internal::PayloadTrait<T>;
937 std::unique_ptr<Internal::PayloadBase> pb(new Internal::Payload<T>(p));
938 setPayloadBaseV2(PayloadType::sharedPointerId, PayloadType::elementMetaTypeId(), pb);
939}
940
941template<typename T>
942void Item::setPayload(T *p)
943{
944 p->You_MUST_NOT_use_a_pointer_as_payload;
945}
946
947} // namespace Akonadi
948
949Q_DECLARE_METATYPE(Akonadi::Item)
950Q_DECLARE_METATYPE(Akonadi::Item::List)
951Q_DECLARE_TYPEINFO(Akonadi::Item, Q_RELOCATABLE_TYPE);
Provides interface for custom attributes for Entity.
Definition attribute.h:132
Represents a collection of PIM items.
Definition collection.h:62
qint64 Id
Describes the unique id type.
Definition collection.h:79
Job that creates a new item in the Akonadi storage.
Job that modifies an existing item in the Akonadi storage.
Syncs between items known to a client (usually a resource) and the Akonadi storage.
Definition itemsync.h:41
Represents a PIM item stored in Akonadi storage.
Definition item.h:101
qint64 Id
Describes the unique id type.
Definition item.h:106
void setPayload(const T &p)
Sets the payload object of this PIM item.
Definition item.h:913
CreateOption
Describes the options that can be passed to access attributes.
Definition item.h:306
@ AddIfMissing
Creates the attribute if it is missing.
Definition item.h:307
Item(const Item &other)
Creates a new item from an other item.
bool hasPayload() const
Returns whether the item has a payload object.
Item(Item &&) noexcept
Move constructor.
T payload() const
Returns the payload object of this PIM item.
Definition item.h:762
bool hasAttribute() const
Returns whether the item has an attribute of the requested type.
Definition item.h:756
const T * attribute() const
Returns the attribute of the requested type or 0 if it is not available.
Definition item.h:736
void removeAttribute()
Removes and deletes the attribute of the requested type.
Definition item.h:750
UrlType
Describes the type of url which is returned in url().
Definition item.h:610
An Akonadi Tag.
Definition tag.h:26
Helper integration between Akonadi and Qt.
T qobject_cast(QObject *object)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:38:51 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.