1 | /* |
2 | Copyright (c) 2006 Volker Krause <vkrause@kde.org> |
3 | 2007 Till Adam <adam@kde.org> |
4 | |
5 | This library is free software; you can redistribute it and/or modify it |
6 | under the terms of the GNU Library General Public License as published by |
7 | the Free Software Foundation; either version 2 of the License, or (at your |
8 | option) any later version. |
9 | |
10 | This library is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
13 | License for more details. |
14 | |
15 | You should have received a copy of the GNU Library General Public License |
16 | along with this library; see the file COPYING.LIB. If not, write to the |
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
18 | 02110-1301, USA. |
19 | */ |
20 | |
21 | #ifndef AKONADI_ITEM_H |
22 | #define AKONADI_ITEM_H |
23 | |
24 | #include "akonadi_export.h" |
25 | |
26 | #include <akonadi/entity.h> |
27 | #include <akonadi/exception.h> |
28 | #include <akonadi/tag.h> |
29 | #include <akonadi/collection.h> |
30 | #include "itempayloadinternals_p.h" |
31 | |
32 | #include <QtCore/QByteArray> |
33 | #include <QtCore/QMetaType> |
34 | #include <QtCore/QSet> |
35 | |
36 | #include <boost/static_assert.hpp> |
37 | #include <boost/type_traits/is_pointer.hpp> |
38 | #include <boost/utility/enable_if.hpp> |
39 | |
40 | #include <typeinfo> |
41 | #include <memory> |
42 | |
43 | class KUrl; |
44 | |
45 | template <typename T> |
46 | class QVector; |
47 | |
48 | namespace Akonadi { |
49 | |
50 | class ItemPrivate; |
51 | |
52 | /** |
53 | * @short Represents a PIM item stored in Akonadi storage. |
54 | * |
55 | * A PIM item consists of one or more parts, allowing a fine-grained access on its |
56 | * content where needed (eg. mail envelope, mail body and attachments). |
57 | * |
58 | * There is also a namespace (prefix) for special parts which are local to Akonadi. |
59 | * These parts, prefixed by "akonadi-", will never be fetched in the resource. |
60 | * They are useful for local extensions like agents which might want to add meta data |
61 | * to items in order to handle them but the meta data should not be stored back to the |
62 | * resource. |
63 | * |
64 | * This class is implicitly shared. |
65 | * |
66 | * <h4>Payload</h4> |
67 | * |
68 | * This class contains, beside some type-agnostic information (flags, revision), |
69 | * zero or more payload objects representing its actual data. Which objects these actually |
70 | * are depends on the mimetype of the item and the corresponding serializer plugin(s). |
71 | * |
72 | * Technically the only restriction on payload objects is that they have to be copyable. |
73 | * For safety reasons, pointer payloads are forbidden as well though, as the |
74 | * ownership would not be clear. In this case, usage of a shared pointer is |
75 | * recommended (such as boost::shared_ptr or QSharedPointer). |
76 | * |
77 | * Using a shared pointer is also required in case the payload is a polymorphic |
78 | * type. For supported shared pointer types implicit casting is provided when possible. |
79 | * |
80 | * When using a value-based class as payload, it is recommended to use one that does |
81 | * support implicit sharing as setting and retrieving a payload as well as copying |
82 | * an Akonadi::Item object imply copying of the payload object. |
83 | * |
84 | * Since KDE 4.6, Item supports multiple payload types per mime type, |
85 | * and will automatically convert between them using the serialiser |
86 | * plugins (which is slow). It also supports mixing shared pointer |
87 | * types, e.g. inserting a boost::shared_ptr<Foo> and extracting a |
88 | * QSharedPointer<Foo>. Since the two shared pointer types cannot |
89 | * share ownership of the same object, the payload class @c T needs to |
90 | * provide a @c clone() method with the usual signature, ie. |
91 | * |
92 | * @code |
93 | * virtual T * T::clone() const |
94 | * @endcode |
95 | * |
96 | * If the class that does not have a @c clone() method, asking for an |
97 | * incompatible shared pointer will throw a PayloadException. |
98 | * |
99 | * Since using different shared pointer types and different payload |
100 | * types for the same mimetype incurs slow conversions (between |
101 | * payload types) and cloning (between shared pointer types), as well |
102 | * as manifold memory usage (results of conversions are cached inside |
103 | * the Item, and only destroyed when a new payload is set by the user |
104 | * of the class), you want to restrict yourself to just one type and |
105 | * one shared pointer type. This mechanism was mainly introduced for |
106 | * backwards compatibility (e.g., putting in a |
107 | * boost::shared_ptr<KCal::Incidence> and extracting a |
108 | * QSharedPointer<KCalCore::Incidence>), so it is not optimized for |
109 | * performance. |
110 | * |
111 | * The availability of a payload of a specific type can be checked using hasPayload(), |
112 | * payloads can be retrieved by using payload() and set by using setPayload(). Refer |
113 | * to the documentation of those methods for more details. |
114 | * |
115 | * @author Volker Krause <vkrause@kde.org>, Till Adam <adam@kde.org>, Marc Mutz <mutz@kde.org> |
116 | */ |
117 | class AKONADI_EXPORT Item : public Entity |
118 | { |
119 | public: |
120 | /** |
121 | * Describes a list of items. |
122 | */ |
123 | typedef QList<Item> List; |
124 | |
125 | /** |
126 | * Describes a flag name. |
127 | */ |
128 | typedef QByteArray Flag; |
129 | |
130 | /** |
131 | * Describes a set of flag names. |
132 | */ |
133 | typedef QSet<QByteArray> Flags; |
134 | |
135 | /** |
136 | * Describes the part name that is used to fetch the |
137 | * full payload of an item. |
138 | */ |
139 | static const char *FullPayload; |
140 | |
141 | /** |
142 | * Creates a new item. |
143 | */ |
144 | Item(); |
145 | |
146 | /** |
147 | * Creates a new item with the given unique @p id. |
148 | */ |
149 | explicit Item(Id id); |
150 | |
151 | /** |
152 | * Creates a new item with the given mime type. |
153 | * |
154 | * @param mimeType The mime type of the item. |
155 | */ |
156 | explicit Item(const QString &mimeType); |
157 | |
158 | /** |
159 | * Creates a new item from an @p other item. |
160 | */ |
161 | Item(const Item &other); |
162 | |
163 | /** |
164 | * Destroys the item. |
165 | */ |
166 | ~Item(); |
167 | |
168 | /** |
169 | * Creates an item from the given @p url. |
170 | */ |
171 | static Item fromUrl(const KUrl &url); |
172 | |
173 | /** |
174 | * Returns all flags of this item. |
175 | */ |
176 | Flags flags() const; |
177 | |
178 | /** |
179 | * Returns the timestamp of the last modification of this item. |
180 | * @since 4.2 |
181 | */ |
182 | QDateTime modificationTime() const; |
183 | |
184 | /** |
185 | * Sets the timestamp of the last modification of this item. |
186 | * @param datetime the modification time to set |
187 | * @note Do not modify this value from within an application, |
188 | * it is updated automatically by the revision checking functions. |
189 | * @since 4.2 |
190 | */ |
191 | void setModificationTime(const QDateTime &datetime); |
192 | |
193 | /** |
194 | * Returns whether the flag with the given @p name is |
195 | * set in the item. |
196 | */ |
197 | bool hasFlag(const QByteArray &name) const; |
198 | |
199 | /** |
200 | * Sets the flag with the given @p name in the item. |
201 | */ |
202 | void setFlag(const QByteArray &name); |
203 | |
204 | /** |
205 | * Removes the flag with the given @p name from the item. |
206 | */ |
207 | void clearFlag(const QByteArray &name); |
208 | |
209 | /** |
210 | * Overwrites all flags of the item by the given @p flags. |
211 | */ |
212 | void setFlags(const Flags &flags); |
213 | |
214 | /** |
215 | * Removes all flags from the item. |
216 | */ |
217 | void clearFlags(); |
218 | |
219 | void setTags(const Tag::List &list); |
220 | |
221 | void setTag(const Tag &tag); |
222 | |
223 | Tag::List tags() const; |
224 | |
225 | bool hasTag(const Tag &tag) const; |
226 | |
227 | void clearTag(const Tag &tag); |
228 | |
229 | void clearTags(); |
230 | |
231 | /** |
232 | * Sets the payload based on the canonical representation normally |
233 | * used for data of this mime type. |
234 | * |
235 | * @param data The encoded data. |
236 | * @see fullPayloadData |
237 | */ |
238 | void setPayloadFromData(const QByteArray &data); |
239 | |
240 | /** |
241 | * Returns the full payload in its canonical representation, e.g. the |
242 | * binary or textual format usually used for data with this mime type. |
243 | * This is useful when communicating with non-Akonadi application by |
244 | * e.g. drag&drop, copy&paste or stored files. |
245 | */ |
246 | QByteArray payloadData() const; |
247 | |
248 | /** |
249 | * Returns the list of loaded payload parts. This is not necessarily |
250 | * identical to all parts in the cache or to all available parts on the backend. |
251 | */ |
252 | QSet<QByteArray> loadedPayloadParts() const; |
253 | |
254 | /** |
255 | * Marks that the payload shall be cleared from the cache when this |
256 | * item is passed to an ItemModifyJob the next time. |
257 | * This will trigger a refetch of the payload from the backend when the |
258 | * item is accessed afterwards. Only resources should have a need for |
259 | * this functionality. |
260 | * |
261 | * @since 4.5 |
262 | */ |
263 | void clearPayload(); |
264 | |
265 | /** |
266 | * Sets the @p revision number of the item. |
267 | * @param revision the revision number to set |
268 | * @note Do not modify this value from within an application, |
269 | * it is updated automatically by the revision checking functions. |
270 | */ |
271 | void setRevision(int revision); |
272 | |
273 | /** |
274 | * Returns the revision number of the item. |
275 | */ |
276 | int revision() const; |
277 | |
278 | /** |
279 | * Returns the unique identifier of the collection this item is stored in. There is only |
280 | * a single such collection, although the item can be linked into arbitrary many |
281 | * virtual collections. |
282 | * Calling this method makes sense only after running an ItemFetchJob on the item. |
283 | * @returns the collection ID if it is known, -1 otherwise. |
284 | * @since 4.3 |
285 | */ |
286 | Entity::Id storageCollectionId() const; |
287 | |
288 | /** |
289 | * Set the size of the item in bytes. |
290 | * @param size the size of the item in bytes |
291 | * @since 4.2 |
292 | */ |
293 | void setSize(qint64 size); |
294 | |
295 | /** |
296 | * Returns the size of the items in bytes. |
297 | * |
298 | * @since 4.2 |
299 | */ |
300 | qint64 size() const; |
301 | |
302 | /** |
303 | * Sets the mime type of the item to @p mimeType. |
304 | */ |
305 | void setMimeType(const QString &mimeType); |
306 | |
307 | /** |
308 | * Returns the mime type of the item. |
309 | */ |
310 | QString mimeType() const; |
311 | |
312 | /** |
313 | * Sets the @p gid of the entity. |
314 | * |
315 | * @since 4.12 |
316 | */ |
317 | void setGid(const QString &gid); |
318 | |
319 | /** |
320 | * Returns the gid of the entity. |
321 | * |
322 | * @since 4.12 |
323 | */ |
324 | QString gid() const; |
325 | |
326 | /** |
327 | * Sets the virtual @p collections that this item is linked into. |
328 | * |
329 | * @note Note that changing this value makes no effect on what collections |
330 | * this item is linked to. To link or unlink an item to/from a virtual |
331 | * collection, use LinkJob and UnlinkJob. |
332 | * |
333 | * @since 4.14 |
334 | */ |
335 | void setVirtualReferences(const Collection::List &collections); |
336 | |
337 | /** |
338 | * Lists virtual collections that this item is linked to. |
339 | * |
340 | * @note This value is populated only when this item was retrieved by |
341 | * ItemFetchJob with fetchVirtualReferences set to true in ItemFetchScope, |
342 | * otherwise this list is always empty. |
343 | * |
344 | * @since 4.14 |
345 | */ |
346 | Collection::List virtualReferences() const; |
347 | |
348 | /** |
349 | * Returns a list of metatype-ids, describing the different |
350 | * variants of payload that are currently contained in this item. |
351 | * |
352 | * The result is always sorted (increasing ids). |
353 | */ |
354 | QVector<int> availablePayloadMetaTypeIds() const; |
355 | |
356 | /** |
357 | * Sets the payload object of this PIM item. |
358 | * |
359 | * @param p The payload object. Must be copyable and must not be a pointer, |
360 | * will cause a compilation failure otherwise. Using a type that can be copied |
361 | * fast (such as implicitly shared classes) is recommended. |
362 | * If the payload type is polymorphic and you intend to set and retrieve payload |
363 | * objects with mismatching but castable types, make sure to use a supported |
364 | * shared pointer implementation (currently boost::shared_ptr and QSharedPointer) |
365 | * and make sure there is a specialization of Akonadi::super_trait for your class. |
366 | */ |
367 | template <typename T> void setPayload(const T &p); |
368 | //@cond PRIVATE |
369 | template <typename T> void setPayload(T *p); |
370 | template <typename T> void setPayload(std::auto_ptr<T> p); |
371 | //@endcond |
372 | |
373 | /** |
374 | * Returns the payload object of this PIM item. This method will only succeed if either |
375 | * you requested the exact same payload type that was put in or the payload uses a |
376 | * supported shared pointer type (currently boost::shared_ptr and QSharedPointer), and |
377 | * is castable to the requested type. For this to work there needs to be a specialization |
378 | * of Akonadi::super_trait of the used classes. |
379 | * |
380 | * If a mismatching or non-castable payload type is requested, an Akonadi::PayloadException |
381 | * is thrown. Therefore it is generally recommended to guard calls to payload() with a |
382 | * corresponding hasPayload() call. |
383 | * |
384 | * Trying to retrieve a pointer type will fail to compile. |
385 | */ |
386 | template <typename T> T payload() const; |
387 | |
388 | /** |
389 | * Returns whether the item has a payload object. |
390 | */ |
391 | bool hasPayload() const; |
392 | |
393 | /** |
394 | * Returns whether the item has a payload of type @c T. |
395 | * This method will only return @c true if either you requested the exact same payload type |
396 | * that was put in or the payload uses a supported shared pointer type (currently boost::shared_ptr |
397 | * and QSharedPointer), and is castable to the requested type. For this to work there needs |
398 | * to be a specialization of Akonadi::super_trait of the used classes. |
399 | * |
400 | * Trying to retrieve a pointer type will fail to compile. |
401 | */ |
402 | template <typename T> bool hasPayload() const; |
403 | |
404 | /** |
405 | * Describes the type of url which is returned in url(). |
406 | */ |
407 | enum UrlType { |
408 | UrlShort = 0, ///< A short url which contains the identifier only (default) |
409 | UrlWithMimeType = 1 ///< A url with identifier and mimetype |
410 | }; |
411 | |
412 | /** |
413 | * Returns the url of the item. |
414 | */ |
415 | KUrl url(UrlType type = UrlShort) const; |
416 | |
417 | /** |
418 | * Returns the parts available for this item. |
419 | * |
420 | * The returned set refers to parts available on the akonadi server or remotely, |
421 | * but does not include the loadedPayloadParts() of this item. |
422 | * |
423 | * @since 4.4 |
424 | */ |
425 | QSet<QByteArray> availablePayloadParts() const; |
426 | |
427 | /** |
428 | * Returns the parts available for this item in the cache. The list might be a subset |
429 | * of the actual parts in cache, as it contains only the requested parts. See @see ItemFetchJob and |
430 | * @see ItemFetchScope |
431 | * |
432 | * The returned set refers to parts available on the akonadi server. |
433 | * |
434 | * @since 4.11 |
435 | */ |
436 | QSet<QByteArray> cachedPayloadParts() const; |
437 | |
438 | /** |
439 | * Applies the parts of Item @p other to this item. |
440 | * Any parts or attributes available in other, will be applied to this item, |
441 | * and the payload parts of other will be inserted into this item, overwriting |
442 | * any existing parts with the same part name. |
443 | * |
444 | * If there is an ItemSerialzerPluginV2 for the type, the merge method in that plugin is |
445 | * used to perform the merge. If only an ItemSerialzerPlugin class is found, or the merge |
446 | * method of the -V2 plugin is not implemented, the merge is performed with multiple deserializations |
447 | * of the payload. |
448 | * @param other the item to get values from |
449 | * @since 4.4 |
450 | */ |
451 | void apply(const Item &other); |
452 | |
453 | /** |
454 | * Registers \a T as a legacy type for mime type \a mimeType. |
455 | * |
456 | * This is required information for Item to return the correct |
457 | * type from payload() when clients have not been recompiled to |
458 | * use the new code. |
459 | * @param mimeType the mimeType to register |
460 | * @since 4.6 |
461 | */ |
462 | template <typename T> static void addToLegacyMapping(const QString &mimeType); |
463 | void setCachedPayloadParts(const QSet<QByteArray> &cachedParts); |
464 | |
465 | private: |
466 | //@cond PRIVATE |
467 | friend class ItemCreateJob; |
468 | friend class ItemModifyJob; |
469 | friend class ItemModifyJobPrivate; |
470 | friend class ItemSync; |
471 | friend class ProtocolHelper; |
472 | PayloadBase *payloadBase() const; |
473 | void setPayloadBase(PayloadBase *p); |
474 | PayloadBase *payloadBaseV2(int sharedPointerId, int metaTypeId) const; |
475 | //std::auto_ptr<PayloadBase> takePayloadBase( int sharedPointerId, int metaTypeId ); |
476 | void setPayloadBaseV2(int sharedPointerId, int metaTypeId, std::auto_ptr<PayloadBase> p); |
477 | void addPayloadBaseVariant(int sharedPointerId, int metaTypeId, std::auto_ptr<PayloadBase> p) const; |
478 | static void addToLegacyMappingImpl(const QString &mimeType, int sharedPointerId, int metaTypeId, std::auto_ptr<PayloadBase> p); |
479 | |
480 | /** |
481 | * Try to ensure that we have a variant of the payload for metatype id @a mtid. |
482 | * @return @c true if a type exists or could be created through conversion, @c false otherwise. |
483 | */ |
484 | bool ensureMetaTypeId(int mtid) const; |
485 | |
486 | template <typename T> |
487 | typename boost::enable_if_c<Internal::PayloadTrait<T>::isPolymorphic, void>::type |
488 | setPayloadImpl(const T &p, const int * /*disambiguate*/ = 0); |
489 | template <typename T> |
490 | typename boost::disable_if_c<Internal::PayloadTrait<T>::isPolymorphic, void>::type |
491 | setPayloadImpl(const T &p); |
492 | |
493 | template <typename T> |
494 | typename boost::enable_if_c<Internal::PayloadTrait<T>::isPolymorphic, T>::type |
495 | payloadImpl(const int * /*disambiguate*/ = 0) const; |
496 | template <typename T> |
497 | typename boost::disable_if_c<Internal::PayloadTrait<T>::isPolymorphic, T>::type |
498 | payloadImpl() const; |
499 | |
500 | template <typename T> |
501 | typename boost::enable_if_c<Internal::PayloadTrait<T>::isPolymorphic, bool>::type |
502 | hasPayloadImpl(const int * /*disambiguate*/ = 0) const; |
503 | template <typename T> |
504 | typename boost::disable_if_c<Internal::PayloadTrait<T>::isPolymorphic, bool>::type |
505 | hasPayloadImpl() const; |
506 | |
507 | template <typename T> |
508 | typename boost::enable_if<Internal::is_shared_pointer<T>, bool>::type |
509 | tryToClone(T *ret, const int * /*disambiguate*/ = 0) const; |
510 | template <typename T> |
511 | typename boost::disable_if<Internal::is_shared_pointer<T>, bool>::type |
512 | tryToClone(T *) const; |
513 | |
514 | /** |
515 | * Set the collection ID to where the item is stored in. Should be set only by the ItemFetchJob. |
516 | * @param collectionId the unique identifier of the collection where this item is stored in. |
517 | * @since 4.3 |
518 | */ |
519 | void setStorageCollectionId(Entity::Id collectionId); |
520 | |
521 | #if 0 |
522 | /** |
523 | * Helper function for non-template throwing of PayloadException. |
524 | */ |
525 | QString payloadExceptionText(int spid, int mtid) const; |
526 | |
527 | /** |
528 | * Non-template throwing of PayloadException. |
529 | * Needs to be inline, otherwise catch (Akonadi::PayloadException) |
530 | * won't work (only catch (Akonadi::Exception)) |
531 | */ |
532 | inline void throwPayloadException(int spid, int mtid) const { |
533 | throw PayloadException(payloadExceptionText(spid, mtid)); |
534 | } |
535 | #else |
536 | void throwPayloadException(int spid, int mtid) const; |
537 | #endif |
538 | //@endcond |
539 | |
540 | AKONADI_DECLARE_PRIVATE(Item) |
541 | }; |
542 | |
543 | template <typename T> |
544 | T Item::payload() const |
545 | { |
546 | BOOST_STATIC_ASSERT(!boost::is_pointer<T>::value); |
547 | |
548 | if (!hasPayload()) { |
549 | throwPayloadException(-1, -1); |
550 | } |
551 | |
552 | return payloadImpl<T>(); |
553 | } |
554 | |
555 | template <typename T> |
556 | typename boost::enable_if_c<Internal::PayloadTrait<T>::isPolymorphic, T>::type |
557 | Item::payloadImpl(const int *) const |
558 | { |
559 | typedef Internal::PayloadTrait<T> PayloadType; |
560 | BOOST_STATIC_ASSERT((PayloadType::isPolymorphic)); |
561 | |
562 | typedef typename Internal::get_hierarchy_root<T>::type Root_T; |
563 | typedef Internal::PayloadTrait<Root_T> RootType; |
564 | BOOST_STATIC_ASSERT((!RootType::isPolymorphic)); // prevent endless recursion |
565 | |
566 | return PayloadType::castFrom(payloadImpl<Root_T>()); |
567 | } |
568 | |
569 | template <typename T> |
570 | typename boost::disable_if_c<Internal::PayloadTrait<T>::isPolymorphic, T>::type |
571 | Item::payloadImpl() const |
572 | { |
573 | typedef Internal::PayloadTrait<T> PayloadType; |
574 | BOOST_STATIC_ASSERT((!PayloadType::isPolymorphic)); |
575 | |
576 | const int metaTypeId = PayloadType::elementMetaTypeId(); |
577 | |
578 | // make sure that we have a payload format represented by 'metaTypeId': |
579 | if (!ensureMetaTypeId(metaTypeId)) { |
580 | throwPayloadException(PayloadType::sharedPointerId, metaTypeId); |
581 | } |
582 | |
583 | // Check whether we have the exact payload |
584 | // (metatype id and shared pointer type match) |
585 | if (const Payload<T> *const p = Internal::payload_cast<T>(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) { |
586 | return p->payload; |
587 | } |
588 | |
589 | T ret; |
590 | if (!tryToClone<T>(&ret)) { |
591 | throwPayloadException(PayloadType::sharedPointerId, metaTypeId); |
592 | } |
593 | return ret; |
594 | } |
595 | |
596 | template <typename T> |
597 | typename boost::enable_if<Internal::is_shared_pointer<T>, bool>::type |
598 | Item::tryToClone(T *ret, const int *) const |
599 | { |
600 | typedef Internal::PayloadTrait<T> PayloadType; |
601 | BOOST_STATIC_ASSERT((!PayloadType::isPolymorphic)); |
602 | |
603 | const int metaTypeId = PayloadType::elementMetaTypeId(); |
604 | |
605 | // Check whether we have the same payload in 'the other |
606 | // shared pointer' (### make it recurse, trying to find one, but |
607 | // don't introduce infinite recursion): |
608 | typedef typename Internal::shared_pointer_traits<T>::next_shared_ptr NewT; |
609 | typedef Internal::PayloadTrait<NewT> NewPayloadType; |
610 | |
611 | if (const Payload<NewT> *const p = Internal::payload_cast<NewT>(payloadBaseV2(NewPayloadType::sharedPointerId, metaTypeId))) { |
612 | // If found, attempt to make a clone (required the payload to provide virtual T * T::clone() const) |
613 | const T nt = PayloadType::clone(p->payload); |
614 | if (!PayloadType::isNull(nt)) { |
615 | // if clone succeeded, add the clone to the Item: |
616 | std::auto_ptr<PayloadBase> npb(new Payload<T>(nt)); |
617 | addPayloadBaseVariant(PayloadType::sharedPointerId, metaTypeId, npb); |
618 | // and return it |
619 | if (ret) { |
620 | *ret = nt; |
621 | } |
622 | return true; |
623 | } |
624 | } |
625 | |
626 | return false; |
627 | } |
628 | |
629 | template <typename T> |
630 | typename boost::disable_if<Internal::is_shared_pointer<T>, bool>::type |
631 | Item::tryToClone(T *) const |
632 | { |
633 | typedef Internal::PayloadTrait<T> PayloadType; |
634 | BOOST_STATIC_ASSERT((!PayloadType::isPolymorphic)); |
635 | |
636 | return false; |
637 | } |
638 | |
639 | template <typename T> |
640 | bool Item::hasPayload() const |
641 | { |
642 | BOOST_STATIC_ASSERT(!boost::is_pointer<T>::value); |
643 | return hasPayload() && hasPayloadImpl<T>(); |
644 | } |
645 | |
646 | template <typename T> |
647 | typename boost::enable_if_c<Internal::PayloadTrait<T>::isPolymorphic, bool>::type |
648 | Item::hasPayloadImpl(const int *) const |
649 | { |
650 | typedef Internal::PayloadTrait<T> PayloadType; |
651 | BOOST_STATIC_ASSERT((PayloadType::isPolymorphic)); |
652 | |
653 | typedef typename Internal::get_hierarchy_root<T>::type Root_T; |
654 | typedef Internal::PayloadTrait<Root_T> RootType; |
655 | BOOST_STATIC_ASSERT((!RootType::isPolymorphic)); // prevent endless recursion |
656 | |
657 | try { |
658 | return hasPayloadImpl<Root_T>() |
659 | && PayloadType::canCastFrom(payload<Root_T>()); |
660 | } catch (const Akonadi::PayloadException &) { |
661 | return false; |
662 | } |
663 | } |
664 | |
665 | template <typename T> |
666 | typename boost::disable_if_c<Internal::PayloadTrait<T>::isPolymorphic, bool>::type |
667 | Item::hasPayloadImpl() const |
668 | { |
669 | typedef Internal::PayloadTrait<T> PayloadType; |
670 | BOOST_STATIC_ASSERT((!PayloadType::isPolymorphic)); |
671 | |
672 | const int metaTypeId = PayloadType::elementMetaTypeId(); |
673 | |
674 | // make sure that we have a payload format represented by 'metaTypeId': |
675 | if (!ensureMetaTypeId(metaTypeId)) { |
676 | return false; |
677 | } |
678 | |
679 | // Check whether we have the exact payload |
680 | // (metatype id and shared pointer type match) |
681 | if (const Payload<T> *const p = Internal::payload_cast<T>(payloadBaseV2(PayloadType::sharedPointerId, metaTypeId))) { |
682 | return true; |
683 | } |
684 | |
685 | return tryToClone<T>(0); |
686 | } |
687 | |
688 | template <typename T> |
689 | void Item::setPayload(const T &p) |
690 | { |
691 | BOOST_STATIC_ASSERT((!boost::is_pointer<T>::value)); |
692 | setPayloadImpl(p); |
693 | } |
694 | |
695 | template <typename T> |
696 | typename boost::enable_if_c<Internal::PayloadTrait<T>::isPolymorphic>::type |
697 | Item::setPayloadImpl(const T &p, const int *) |
698 | { |
699 | typedef Internal::PayloadTrait<T> PayloadType; |
700 | BOOST_STATIC_ASSERT((PayloadType::isPolymorphic)); |
701 | |
702 | typedef typename Internal::get_hierarchy_root<T>::type Root_T; |
703 | typedef Internal::PayloadTrait<Root_T> RootType; |
704 | BOOST_STATIC_ASSERT((!RootType::isPolymorphic)); // prevent endless recursion |
705 | |
706 | setPayloadImpl<Root_T>(p); |
707 | } |
708 | |
709 | template <typename T> |
710 | typename boost::disable_if_c<Internal::PayloadTrait<T>::isPolymorphic>::type |
711 | Item::setPayloadImpl(const T &p) |
712 | { |
713 | typedef Internal::PayloadTrait<T> PayloadType; |
714 | std::auto_ptr<PayloadBase> pb(new Payload<T>(p)); |
715 | setPayloadBaseV2(PayloadType::sharedPointerId, |
716 | PayloadType::elementMetaTypeId(), |
717 | pb); |
718 | } |
719 | |
720 | template <typename T> |
721 | void Item::setPayload(T *p) |
722 | { |
723 | p->You_MUST_NOT_use_a_pointer_as_payload; |
724 | } |
725 | |
726 | template <typename T> |
727 | void Item::setPayload(std::auto_ptr<T> p) |
728 | { |
729 | p.Nice_try_but_a_std_auto_ptr_is_not_allowed_as_payload_either; |
730 | } |
731 | |
732 | template <typename T> |
733 | void Item::addToLegacyMapping(const QString &mimeType) { |
734 | typedef Internal::PayloadTrait<T> PayloadType; |
735 | BOOST_STATIC_ASSERT((!PayloadType::isPolymorphic)); |
736 | std::auto_ptr<PayloadBase> p(new Payload<T>); |
737 | addToLegacyMappingImpl(mimeType, PayloadType::sharedPointerId, PayloadType::elementMetaTypeId(), p); |
738 | } |
739 | |
740 | } |
741 | |
742 | Q_DECLARE_METATYPE(Akonadi::Item) |
743 | Q_DECLARE_METATYPE(Akonadi::Item::List) |
744 | |
745 | #endif |
746 | |