Akonadi

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

KDE's Doxygen guidelines are available online.