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> class QVector;
30 #else
31 template<typename T>
32 class QList;
33 #endif
34 
35 namespace Akonadi
36 {
37 class ItemPrivate;
38 
39 /**
40  * @short Represents a PIM item stored in Akonadi storage.
41  *
42  * A PIM item consists of one or more parts, allowing a fine-grained access on its
43  * content where needed (eg. mail envelope, mail body and attachments).
44  *
45  * There is also a namespace (prefix) for special parts which are local to Akonadi.
46  * These parts, prefixed by "akonadi-", will never be fetched in the resource.
47  * They are useful for local extensions like agents which might want to add meta data
48  * to items in order to handle them but the meta data should not be stored back to the
49  * resource.
50  *
51  * This class is implicitly shared.
52  *
53  * <h4>Payload</h4>
54  *
55  * This class contains, beside some type-agnostic information (flags, revision),
56  * zero or more payload objects representing its actual data. Which objects these actually
57  * are depends on the mimetype of the item and the corresponding serializer plugin(s).
58  *
59  * Technically the only restriction on payload objects is that they have to be copyable.
60  * For safety reasons, pointer payloads are forbidden as well though, as the
61  * ownership would not be clear. In this case, usage of a shared pointer is
62  * recommended (such as QSharedPointer or std::shared_ptr).
63  *
64  * Using a shared pointer is also required in case the payload is a polymorphic
65  * type. For supported shared pointer types implicit casting is provided when possible.
66  *
67  * When using a value-based class as payload, it is recommended to use one that does
68  * support implicit sharing as setting and retrieving a payload as well as copying
69  * an Akonadi::Item object imply copying of the payload object.
70  *
71  * Since KDE 4.6, Item supports multiple payload types per mime type,
72  * and will automatically convert between them using the serialiser
73  * plugins (which is slow). It also supports mixing shared pointer
74  * types, e.g. inserting a std::shared_ptr<Foo> and extracting a
75  * QSharedPointer<Foo>. Since the two shared pointer types cannot
76  * share ownership of the same object, the payload class @c T needs to
77  * provide a @c clone() method with the usual signature, ie.
78  *
79  * @code
80  * virtual T * T::clone() const
81  * @endcode
82  *
83  * If the class that does not have a @c clone() method, asking for an
84  * incompatible shared pointer will throw a PayloadException.
85  *
86  * Since using different shared pointer types and different payload
87  * types for the same mimetype incurs slow conversions (between
88  * payload types) and cloning (between shared pointer types), as well
89  * as manifold memory usage (results of conversions are cached inside
90  * the Item, and only destroyed when a new payload is set by the user
91  * of the class), you want to restrict yourself to just one type and
92  * one shared pointer type. This mechanism was mainly introduced for
93  * backwards compatibility (e.g., putting in a
94  * std::shared_ptr<KCal::Incidence> and extracting a
95  * QSharedPointer<KCalCore::Incidence>), so it is not optimized for
96  * performance.
97  *
98  * The availability of a payload of a specific type can be checked using hasPayload(),
99  * payloads can be retrieved by using payload() and set by using setPayload(). Refer
100  * to the documentation of those methods for more details.
101  *
102  * @author Volker Krause <[email protected]>, Till Adam <[email protected]>, Marc Mutz <[email protected]>
103  */
104 class AKONADICORE_EXPORT Item
105 {
106 public:
107  /**
108  * Describes the unique id type.
109  */
110  using Id = qint64;
111 
112  /**
113  * Describes a list of items.
114  */
116 
117  /**
118  * Describes a flag name.
119  */
120  using Flag = QByteArray;
121 
122  /**
123  * Describes a set of flag names.
124  */
126 
127  /**
128  * Describes the part name that is used to fetch the
129  * full payload of an item.
130  */
131  static const char FullPayload[];
132 
133  /**
134  * Creates a new item.
135  */
136  Item();
137 
138  /**
139  * Creates a new item with the given unique @p id.
140  */
141  explicit Item(Id id);
142 
143  /**
144  * Creates a new item with the given mime type.
145  *
146  * @param mimeType The mime type of the item.
147  */
148  explicit Item(const QString &mimeType);
149 
150  /**
151  * Creates a new item from an @p other item.
152  */
153  Item(const Item &other);
154 
155  /**
156  * Move constructor.
157  */
158  Item(Item &&) noexcept;
159 
160  /**
161  * Destroys the item.
162  */
163  ~Item();
164 
165  /**
166  * Creates an item from the given @p url.
167  */
168  static Item fromUrl(const QUrl &url);
169 
170  /**
171  * Sets the unique @p identifier of the item.
172  */
173  void setId(Id identifier);
174 
175  /**
176  * Returns the unique identifier of the item.
177  */
178  Id id() const;
179 
180  /**
181  * Sets the remote @p id of the item.
182  */
183  void setRemoteId(const QString &id);
184 
185  /**
186  * Returns the remote id of the item.
187  */
188  QString remoteId() const;
189 
190  /**
191  * Sets the remote @p revision of the item.
192  * @param revision the item's remote revision
193  * The remote revision can be used by resources to store some
194  * revision information of the backend to detect changes there.
195  *
196  * @note This method is supposed to be used by resources only.
197  * @since 4.5
198  */
199  void setRemoteRevision(const QString &revision);
200 
201  /**
202  * Returns the remote revision of the item.
203  *
204  * @note This method is supposed to be used by resources only.
205  * @since 4.5
206  */
207  QString remoteRevision() const;
208 
209  /**
210  * Returns whether the item is valid.
211  */
212  bool isValid() const;
213 
214  /**
215  * Returns whether this item's id equals the id of the @p other item.
216  */
217  bool operator==(const Item &other) const;
218 
219  /**
220  * Returns whether the item's id does not equal the id of the @p other item.
221  */
222  bool operator!=(const Item &other) const;
223 
224  /**
225  * Assigns the @p other to this item and returns a reference to this item.
226  * @param other the item to assign
227  */
228  Item &operator=(const Item &other);
229 
230  /**
231  * @internal For use with containers only.
232  *
233  * @since 4.8
234  */
235  bool operator<(const Item &other) const;
236 
237  /**
238  * Returns the parent collection of this object.
239  * @note This will of course only return a useful value if it was explicitly retrieved
240  * from the Akonadi server.
241  * @since 4.4
242  */
243  Collection parentCollection() const;
244 
245  /**
246  * Returns a reference to the parent collection of this object.
247  * @note This will of course only return a useful value if it was explicitly retrieved
248  * from the Akonadi server.
249  * @since 4.4
250  */
251  Collection &parentCollection();
252 
253  /**
254  * Set the parent collection of this object.
255  * @note Calling this method has no immediate effect for the object itself,
256  * such as being moved to another collection.
257  * It is mainly relevant to provide a context for RID-based operations
258  * inside resources.
259  * @param parent The parent collection.
260  * @since 4.4
261  */
262  void setParentCollection(const Collection &parent);
263 
264  /**
265  * Adds an attribute to the item.
266  *
267  * If an attribute of the same type name already exists, it is deleted and
268  * replaced with the new one.
269  *
270  * @param attribute The new attribute.
271  *
272  * @note The collection takes the ownership of the attribute.
273  */
274  void addAttribute(Attribute *attribute);
275 
276  /**
277  * Removes and deletes the attribute of the given type @p name.
278  */
279  void removeAttribute(const QByteArray &name);
280 
281  /**
282  * Returns @c true if the item has an attribute of the given type @p name,
283  * false otherwise.
284  */
285  bool hasAttribute(const QByteArray &name) const;
286 
287  /**
288  * Returns a list of all attributes of the item.
289  *
290  * @warning Do not modify the attributes returned from this method,
291  * the change will not be reflected when updating the Item through
292  * ItemModifyJob.
293  */
294  Attribute::List attributes() const;
295 
296  /**
297  * Removes and deletes all attributes of the item.
298  */
299  void clearAttributes();
300 
301  /**
302  * Returns the attribute of the given type @p name if available, 0 otherwise.
303  */
304  Attribute *attribute(const QByteArray &name);
305  const Attribute *attribute(const QByteArray &name) const;
306 
307  /**
308  * Describes the options that can be passed to access attributes.
309  */
311  AddIfMissing, ///< Creates the attribute if it is missing
312  DontCreate ///< Do not create the attribute if it is missing (default)
313  };
314 
315  /**
316  * Returns the attribute of the requested type.
317  * If the item has no attribute of that type yet, a new one
318  * is created and added to the entity.
319  *
320  * @param option The create options.
321  */
322  template<typename T> inline T *attribute(CreateOption option = DontCreate);
323 
324  /**
325  * Returns the attribute of the requested type or 0 if it is not available.
326  */
327  template<typename T> inline const T *attribute() const;
328 
329  /**
330  * Removes and deletes the attribute of the requested type.
331  */
332  template<typename T> inline void removeAttribute();
333 
334  /**
335  * Returns whether the item has an attribute of the requested type.
336  */
337  template<typename T> 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  QVector<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> void setPayload(const T &p);
568  /// @cond PRIVATE
569  template<typename T> void setPayload(T *p);
570  /// @endcond
571 
572  /**
573  * Returns the payload object of this PIM item. This method will only succeed if either
574  * you requested the exact same payload type that was put in or the payload uses a
575  * supported shared pointer type (currently QSharedPointer and std::shared_ptr),
576  * and is castable to the requested type. For this to work there needs
577  * to be a specialization of Akonadi::super_trait of the used classes.
578  *
579  * If a mismatching or non-castable payload type is requested, an Akonadi::PayloadException
580  * is thrown. Therefore it is generally recommended to guard calls to payload() with a
581  * corresponding hasPayload() call.
582  *
583  * Trying to retrieve a pointer type will fail to compile.
584  */
585  template<typename T> T payload() const;
586 
587  /**
588  * Returns whether the item has a payload object.
589  */
590  bool hasPayload() const;
591 
592  /**
593  * Returns whether the item has a payload of type @c T.
594  * This method will only return @c true if either you requested the exact same payload type
595  * that was put in or the payload uses a supported shared pointer type (currently
596  * QSharedPointer and std::shared_ptr), and is castable to the requested type. For this to work there needs
597  * to be a specialization of Akonadi::super_trait of the used classes.
598  *
599  * Trying to retrieve a pointer type will fail to compile.
600  */
601  template<typename T> bool hasPayload() const;
602 
603  /**
604  * Describes the type of url which is returned in url().
605  */
606  enum UrlType {
607  UrlShort = 0, ///< A short url which contains the identifier only (default)
608  UrlWithMimeType = 1 ///< A url with identifier and mimetype
609  };
610 
611  /**
612  * Returns the url of the item.
613  */
614  QUrl url(UrlType type = UrlShort) const;
615 
616  /**
617  * Returns the parts available for this item.
618  *
619  * The returned set refers to parts available on the akonadi server or remotely,
620  * but does not include the loadedPayloadParts() of this item.
621  *
622  * @since 4.4
623  */
624  QSet<QByteArray> availablePayloadParts() const;
625 
626  /**
627  * Returns the parts available for this item in the cache. The list might be a subset
628  * of the actual parts in cache, as it contains only the requested parts. See @see ItemFetchJob and
629  * @see ItemFetchScope
630  *
631  * The returned set refers to parts available on the akonadi server.
632  *
633  * @since 4.11
634  */
635  QSet<QByteArray> cachedPayloadParts() const;
636 
637  /**
638  * Applies the parts of Item @p other to this item.
639  * Any parts or attributes available in other, will be applied to this item,
640  * and the payload parts of other will be inserted into this item, overwriting
641  * any existing parts with the same part name.
642  *
643  * If there is an ItemSerialzerPluginV2 for the type, the merge method in that plugin is
644  * used to perform the merge. If only an ItemSerialzerPlugin class is found, or the merge
645  * method of the -V2 plugin is not implemented, the merge is performed with multiple deserializations
646  * of the payload.
647  * @param other the item to get values from
648  * @since 4.4
649  */
650  void apply(const Item &other);
651 
652  void setCachedPayloadParts(const QSet<QByteArray> &cachedParts);
653 
654 private:
655  /// @cond PRIVATE
656  friend class ItemCreateJob;
657  friend class ItemCreateJobPrivate;
658  friend class ItemModifyJob;
659  friend class ItemModifyJobPrivate;
660  friend class ItemSync;
661  friend class ProtocolHelper;
662  Internal::PayloadBase *payloadBaseV2(int sharedPointerId, int metaTypeId) const;
663  void setPayloadBaseV2(int sharedPointerId, int metaTypeId, std::unique_ptr<Internal::PayloadBase> &p);
664  void addPayloadBaseVariant(int sharedPointerId, int metaTypeId, std::unique_ptr<Internal::PayloadBase> &p) const;
665 
666  /**
667  * Try to ensure that we have a variant of the payload for metatype id @a mtid.
668  * @return @c true if a type exists or could be created through conversion, @c false otherwise.
669  */
670  bool ensureMetaTypeId(int mtid) const;
671 
672  template<typename T>
673  typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, void>::type setPayloadImpl(const T &p, const int * /*disambiguate*/ = nullptr);
674  template<typename T> typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, void>::type setPayloadImpl(const T &p);
675 
676  template<typename T> typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, T>::type payloadImpl(const int * /*disambiguate*/ = nullptr) const;
677  template<typename T> typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, T>::type payloadImpl() const;
678 
679  template<typename T>
680  typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, bool>::type hasPayloadImpl(const int * /*disambiguate*/ = nullptr) const;
681  template<typename T> 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> typename std::enable_if<!Internal::is_shared_pointer<T>::value, bool>::type tryToClone(T *ret) const;
686 
687  template<typename T, typename NewT>
688  typename std::enable_if<!std::is_same<T, NewT>::value, bool>::type tryToCloneImpl(T *ret, const int * /*disambiguate*/ = nullptr) const;
689  template<typename T, typename NewT> typename std::enable_if<std::is_same<T, NewT>::value, bool>::type tryToCloneImpl(T *ret) const;
690 
691  /**
692  * Set the collection ID to where the item is stored in. Should be set only by the ItemFetchJob.
693  * @param collectionId the unique identifier of the collection where this item is stored in.
694  * @since 4.3
695  */
696  void setStorageCollectionId(Collection::Id collectionId);
697 
698 #if 0
699  /**
700  * Helper function for non-template throwing of PayloadException.
701  */
702  QString payloadExceptionText(int spid, int mtid) const;
703 
704  /**
705  * Non-template throwing of PayloadException.
706  * Needs to be inline, otherwise catch (Akonadi::PayloadException)
707  * won't work (only catch (Akonadi::Exception))
708  */
709  inline void throwPayloadException(int spid, int mtid) const
710  {
711  throw PayloadException(payloadExceptionText(spid, mtid));
712  }
713 #else
714  void throwPayloadException(int spid, int mtid) const;
715 #endif
716 
718  friend class ItemPrivate;
719  /// @endcond
720 };
721 
722 AKONADICORE_EXPORT uint qHash(const Akonadi::Item &item);
723 
724 template<typename T> inline T *Item::attribute(Item::CreateOption option)
725 {
726  const QByteArray type = T().type();
727  if (hasAttribute(type)) {
728  if (T *attr = dynamic_cast<T *>(attribute(type))) {
729  return attr;
730  }
731  qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?";
732  } else if (option == AddIfMissing) {
733  T *attr = new T();
734  addAttribute(attr);
735  return attr;
736  }
737 
738  return nullptr;
739 }
740 
741 template<typename T> inline const T *Item::attribute() const
742 {
743  const QByteArray type = T().type();
744  if (hasAttribute(type)) {
745  if (const T *attr = dynamic_cast<const T *>(attribute(type))) {
746  return attr;
747  }
748  qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?";
749  }
750 
751  return nullptr;
752 }
753 
754 template<typename T> inline void Item::removeAttribute()
755 {
756  removeAttribute(T().type());
757 }
758 
759 template<typename T> inline bool Item::hasAttribute() const
760 {
761  return hasAttribute(T().type());
762 }
763 
764 template<typename T> T Item::payload() const
765 {
766  static_assert(!std::is_pointer<T>::value, "Payload must not be a pointer");
767 
768  if (!hasPayload()) {
769  throwPayloadException(-1, -1);
770  }
771 
772  return payloadImpl<T>();
773 }
774 
775 template<typename T> typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, T>::type Item::payloadImpl(const int *) const
776 {
777  using PayloadType = Internal::PayloadTrait<T>;
778  static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is not allowed");
779 
780  using Root_T = typename Internal::get_hierarchy_root<T>::type;
781  using RootType = Internal::PayloadTrait<Root_T>;
782  static_assert(!RootType::isPolymorphic,
783  "Root type of payload type must not be polymorphic"); // prevent endless recursion
784 
785  return PayloadType::castFrom(payloadImpl<Root_T>());
786 }
787 
788 template<typename T> typename 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 
813 template<typename T, typename NewT> typename std::enable_if<!std::is_same<T, NewT>::value, bool>::type Item::tryToCloneImpl(T *ret, const int *) const
814 {
815  using PayloadType = Internal::PayloadTrait<T>;
816  using NewPayloadType = Internal::PayloadTrait<NewT>;
817 
818  const int metaTypeId = PayloadType::elementMetaTypeId();
819  Internal::PayloadBase *payloadBase = payloadBaseV2(NewPayloadType::sharedPointerId, metaTypeId);
820  if (const Internal::Payload<NewT> *const p = Internal::payload_cast<NewT>(payloadBase)) {
821  // If found, attempt to make a clone (required the payload to provide virtual T * T::clone() const)
822  const T nt = PayloadType::clone(p->payload);
823  if (!PayloadType::isNull(nt)) {
824  // if clone succeeded, add the clone to the Item:
825  std::unique_ptr<Internal::PayloadBase> npb(new Internal::Payload<T>(nt));
826  addPayloadBaseVariant(PayloadType::sharedPointerId, metaTypeId, npb);
827  // and return it
828  if (ret) {
829  *ret = nt;
830  }
831  return true;
832  }
833  }
834 
835  return tryToCloneImpl<T, typename Internal::shared_pointer_traits<NewT>::next_shared_ptr>(ret);
836 }
837 
838 template<typename T, typename NewT> typename std::enable_if<std::is_same<T, NewT>::value, bool>::type Item::tryToCloneImpl(T *) const
839 {
840  return false;
841 }
842 
843 template<typename T> typename std::enable_if<Internal::is_shared_pointer<T>::value, bool>::type Item::tryToClone(T *ret, const int *) const
844 {
845  using PayloadType = Internal::PayloadTrait<T>;
846  static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed");
847 
848  return tryToCloneImpl<T, typename Internal::shared_pointer_traits<T>::next_shared_ptr>(ret);
849 }
850 
851 template<typename T> typename std::enable_if<!Internal::is_shared_pointer<T>::value, bool>::type Item::tryToClone(T *) const
852 {
853  using PayloadType = Internal::PayloadTrait<T>;
854  static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed");
855 
856  return false;
857 }
858 
859 template<typename T> bool Item::hasPayload() const
860 {
861  static_assert(!std::is_pointer<T>::value, "Payload type cannot be a pointer");
862  return hasPayload() && hasPayloadImpl<T>();
863 }
864 
865 template<typename T> typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic, bool>::type Item::hasPayloadImpl(const int *) const
866 {
867  using PayloadType = Internal::PayloadTrait<T>;
868  static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is no allowed");
869 
870  using Root_T = typename Internal::get_hierarchy_root<T>::type;
871  using RootType = Internal::PayloadTrait<Root_T>;
872  static_assert(!RootType::isPolymorphic,
873  "Root type of payload type must not be polymorphic"); // prevent endless recursion
874 
875  try {
876  return hasPayloadImpl<Root_T>() && PayloadType::canCastFrom(payload<Root_T>());
877  } catch (const Akonadi::PayloadException &e) {
878  qDebug() << e.what();
879  Q_UNUSED(e)
880  return false;
881  }
882 }
883 
884 template<typename T> typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic, bool>::type Item::hasPayloadImpl() const
885 {
886  using PayloadType = Internal::PayloadTrait<T>;
887  static_assert(!PayloadType::isPolymorphic, "Polymorphic payload type in non-polymorphic implementation is not allowed");
888 
889  const int metaTypeId = PayloadType::elementMetaTypeId();
890 
891  // make sure that we have a payload format represented by 'metaTypeId':
892  if (!ensureMetaTypeId(metaTypeId)) {
893  return false;
894  }
895 
896  // Check whether we have the exact payload
897  // (metatype id and shared pointer type match)
898  if (const Internal::Payload<T> *const p = Internal::payload_cast<T>(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) {
899  return true;
900  }
901 
902  return tryToClone<T>(nullptr);
903 }
904 
905 template<typename T> void 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 
911 template<typename T> typename std::enable_if<Internal::PayloadTrait<T>::isPolymorphic>::type Item::setPayloadImpl(const T &p, const int *)
912 {
913  using PayloadType = Internal::PayloadTrait<T>;
914  static_assert(PayloadType::isPolymorphic, "Non-polymorphic payload type in polymorphic implementation is not allowed");
915 
916  using Root_T = typename Internal::get_hierarchy_root<T>::type;
917  using RootType = Internal::PayloadTrait<Root_T>;
918  static_assert(!RootType::isPolymorphic,
919  "Root type of payload type must not be polymorphic"); // prevent endless recursion
920 
921  setPayloadImpl<Root_T>(p);
922 }
923 
924 template<typename T> typename std::enable_if<!Internal::PayloadTrait<T>::isPolymorphic>::type Item::setPayloadImpl(const T &p)
925 {
926  using PayloadType = Internal::PayloadTrait<T>;
927  std::unique_ptr<Internal::PayloadBase> pb(new Internal::Payload<T>(p));
928  setPayloadBaseV2(PayloadType::sharedPointerId, PayloadType::elementMetaTypeId(), pb);
929 }
930 
931 template<typename T> void Item::setPayload(T *p)
932 {
933  p->You_MUST_NOT_use_a_pointer_as_payload;
934 }
935 
936 } // namespace Akonadi
937 
938 Q_DECLARE_METATYPE(Akonadi::Item)
939 Q_DECLARE_METATYPE(Akonadi::Item::List)
940 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:741
UrlType
Describes the type of url which is returned in url().
Definition: item.h:606
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:310
Definition: item.h:32
bool hasAttribute() const
Returns whether the item has an attribute of the requested type.
Definition: item.h:759
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:110
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:754
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:311
qint64 Id
Describes the unique id type.
Definition: collection.h:79
Represents a PIM item stored in Akonadi storage.
Definition: item.h:104
Helper integration between Akonadi and Qt.
void setPayload(const T &p)
Sets the payload object of this PIM item.
Definition: item.h:905
T payload() const
Returns the payload object of this PIM item.
Definition: item.h:764
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jul 2 2022 06:41:48 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.