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

KDE's Doxygen guidelines are available online.