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

KDE's Doxygen guidelines are available online.