1 /*
2 SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #pragma once
8
9 #include "akonadicore_export.h"
10 #include "attribute.h"
11
12 #include <QDebug>
13 #include <QMetaType>
14 #include <QSharedDataPointer>
15
16 class QUrl;
17
18 namespace Akonadi
19 {
20 class CachePolicy;
21 class CollectionPrivate;
22 class CollectionStatistics;
23
24 /**
25 * @short Represents a collection of PIM items.
26 *
27 * This class represents a collection of PIM items, such as a folder on a mail- or
28 * groupware-server.
29 *
30 * Collections are hierarchical, i.e., they may have a parent collection.
31 *
32 * @code
33 *
34 * using namespace Akonadi;
35 *
36 * // fetching all collections recursive, starting at the root collection
37 * CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive );
38 * connect( job, SIGNAL(result(KJob*)), SLOT(fetchFinished(KJob*)) );
39 *
40 * ...
41 *
42 * MyClass::fetchFinished( KJob *job )
43 * {
44 * if ( job->error() ) {
45 * qDebug() << "Error occurred";
46 * return;
47 * }
48 *
49 * CollectionFetchJob *fetchJob = qobject_cast<CollectionFetchJob*>( job );
50 *
51 * const Collection::List collections = fetchJob->collections();
52 * for ( const Collection &collection : collections ) {
53 * qDebug() << "Name:" << collection.name();
54 * }
55 * }
56 *
57 * @endcode
58 *
59 * @author Volker Krause <vkrause@kde.org>
60 */
61 class AKONADICORE_EXPORT Collection
62 {
63 public:
64 /**
65 * Describes the unique id type.
66 */
67 using Id = qint64;
68
69 /**
70 * Describes a list of collections.
71 */
72 using List = QVector<Collection>;
73
74 /**
75 * Describes rights of a collection.
76 */
77 enum Right {
78 ReadOnly = 0x0, ///< Can only read items or subcollection of this collection
79 CanChangeItem = 0x1, ///< Can change items in this collection
80 CanCreateItem = 0x2, ///< Can create new items in this collection
81 CanDeleteItem = 0x4, ///< Can delete items in this collection
82 CanChangeCollection = 0x8, ///< Can change this collection
83 CanCreateCollection = 0x10, ///< Can create new subcollections in this collection
84 CanDeleteCollection = 0x20, ///< Can delete this collection
85 CanLinkItem = 0x40, ///< Can create links to existing items in this virtual collection @since 4.4
86 CanUnlinkItem = 0x80, ///< Can remove links to items in this virtual collection @since 4.4
87 AllRights = (CanChangeItem | CanCreateItem | CanDeleteItem | CanChangeCollection | CanCreateCollection
88 | CanDeleteCollection) ///< Has all rights on this storage collection
89 };
90 Q_DECLARE_FLAGS(Rights, Right)
91
92 /**
93 * Creates an invalid collection.
94 */
95 Collection();
96
97 /**
98 * Create a new collection.
99 *
100 * @param id The unique identifier of the collection.
101 */
102 explicit Collection(Id id);
103
104 /**
105 * Destroys the collection.
106 */
107 ~Collection();
108
109 /**
110 * Creates a collection from an @p other collection.
111 */
112 Collection(const Collection &other);
113
114 /**
115 * Move constructor.
116 */
117 Collection(Collection &&other) noexcept;
118
119 /**
120 * Creates a collection from the given @p url.
121 */
122 static Collection fromUrl(const QUrl &url);
123
124 /**
125 * Sets the unique @p identifier of the collection.
126 */
127 void setId(Id identifier);
128
129 /**
130 * Returns the unique identifier of the collection.
131 */
132 Q_REQUIRED_RESULT Id id() const;
133
134 /**
135 * Sets the remote @p id of the collection.
136 */
137 void setRemoteId(const QString &id);
138
139 /**
140 * Returns the remote id of the collection.
141 */
142 Q_REQUIRED_RESULT QString remoteId() const;
143
144 /**
145 * Sets the remote @p revision of the collection.
146 * @param revision the collections's remote revision
147 * The remote revision can be used by resources to store some
148 * revision information of the backend to detect changes there.
149 *
150 * @note This method is supposed to be used by resources only.
151 * @since 4.5
152 */
153 void setRemoteRevision(const QString &revision);
154
155 /**
156 * Returns the remote revision of the collection.
157 *
158 * @note This method is supposed to be used by resources only.
159 * @since 4.5
160 */
161 Q_REQUIRED_RESULT QString remoteRevision() const;
162
163 /**
164 * Returns whether the collection is valid.
165 */
166 Q_REQUIRED_RESULT bool isValid() const;
167
168 /**
169 * Returns whether this collections's id equals the
170 * id of the @p other collection.
171 */
172 Q_REQUIRED_RESULT bool operator==(const Collection &other) const;
173
174 /**
175 * Returns whether the collection's id does not equal the id
176 * of the @p other collection.
177 */
178 Q_REQUIRED_RESULT bool operator!=(const Collection &other) const;
179
180 /**
181 * Assigns the @p other to this collection and returns a reference to this
182 * collection.
183 * @param other the collection to assign
184 */
185 Collection &operator=(const Collection &other);
186
187 /**
188 * @internal For use with containers only.
189 *
190 * @since 4.8
191 */
192 Q_REQUIRED_RESULT bool operator<(const Collection &other) const;
193
194 /**
195 * Returns the parent collection of this object.
196 * @note This will of course only return a useful value if it was explicitly retrieved
197 * from the Akonadi server.
198 * @since 4.4
199 */
200 Q_REQUIRED_RESULT Collection parentCollection() const;
201
202 /**
203 * Returns a reference to the parent collection of this object.
204 * @note This will of course only return a useful value if it was explicitly retrieved
205 * from the Akonadi server.
206 * @since 4.4
207 */
208 Q_REQUIRED_RESULT Collection &parentCollection();
209
210 /**
211 * Set the parent collection of this object.
212 * @note Calling this method has no immediate effect for the object itself,
213 * such as being moved to another collection.
214 * It is mainly relevant to provide a context for RID-based operations
215 * inside resources.
216 * @param parent The parent collection.
217 * @since 4.4
218 */
219 void setParentCollection(const Collection &parent);
220
221 /**
222 * Adds an attribute to the collection.
223 *
224 * If an attribute of the same type name already exists, it is deleted and
225 * replaced with the new one.
226 *
227 * @param attribute The new attribute.
228 *
229 * @note The collection takes the ownership of the attribute.
230 */
231 void addAttribute(Attribute *attribute);
232
233 /**
234 * Removes and deletes the attribute of the given type @p name.
235 */
236 void removeAttribute(const QByteArray &name);
237
238 /**
239 * Returns @c true if the collection has an attribute of the given type @p name,
240 * false otherwise.
241 */
242 bool hasAttribute(const QByteArray &name) const;
243
244 /**
245 * Returns a list of all attributes of the collection.
246 *
247 * @warning Do not modify the attributes returned from this method,
248 * the change will not be reflected when updating the Collection
249 * through CollectionModifyJob.
250 */
251 Q_REQUIRED_RESULT Attribute::List attributes() const;
252
253 /**
254 * Removes and deletes all attributes of the collection.
255 */
256 void clearAttributes();
257
258 /**
259 * Returns the attribute of the given type @p name if available, 0 otherwise.
260 */
261 Attribute *attribute(const QByteArray &name);
262 const Attribute *attribute(const QByteArray &name) const;
263
264 /**
265 * Describes the options that can be passed to access attributes.
266 */
267 enum CreateOption {
268 AddIfMissing, ///< Creates the attribute if it is missing
269 DontCreate ///< Default value
270 };
271
272 /**
273 * Returns the attribute of the requested type.
274 * If the collection has no attribute of that type yet, passing AddIfMissing
275 * as an argument will create and add it to the entity
276 *
277 * @param option The create options.
278 */
279 template<typename T> inline T *attribute(CreateOption option = DontCreate);
280
281 /**
282 * Returns the attribute of the requested type or 0 if it is not available.
283 */
284 template<typename T> inline const T *attribute() const;
285
286 /**
287 * Removes and deletes the attribute of the requested type.
288 */
289 template<typename T> inline void removeAttribute();
290
291 /**
292 * Returns whether the collection has an attribute of the requested type.
293 */
294 template<typename T> inline bool hasAttribute() const;
295
296 /**
297 * Returns the i18n'ed name of the collection.
298 */
299 Q_REQUIRED_RESULT QString name() const;
300
301 /**
302 * Returns the display name (EntityDisplayAttribute::displayName()) if set,
303 * and Collection::name() otherwise. For human-readable strings this is preferred
304 * over Collection::name().
305 *
306 * @since 4.11
307 */
308 Q_REQUIRED_RESULT QString displayName() const;
309
310 /**
311 * Sets the i18n'ed name of the collection.
312 *
313 * @param name The new collection name.
314 */
315 void setName(const QString &name);
316
317 /**
318 * Returns the rights the user has on the collection.
319 */
320 Q_REQUIRED_RESULT Rights rights() const;
321
322 /**
323 * Sets the @p rights the user has on the collection.
324 */
325 void setRights(Rights rights);
326
327 /**
328 * Returns a list of possible content mimetypes,
329 * e.g. message/rfc822, x-akonadi/collection for a mail folder that
330 * supports sub-folders.
331 */
332 Q_REQUIRED_RESULT QStringList contentMimeTypes() const;
333
334 /**
335 * Sets the list of possible content mime @p types.
336 */
337 void setContentMimeTypes(const QStringList &types);
338
339 /**
340 * Returns the root collection.
341 */
342 Q_REQUIRED_RESULT static Collection root();
343
344 /**
345 * Returns the mimetype used for collections.
346 */
347 Q_REQUIRED_RESULT static QString mimeType();
348
349 /**
350 * Returns the mimetype used for virtual collections
351 *
352 * @since 4.11
353 */
354 Q_REQUIRED_RESULT static QString virtualMimeType();
355
356 /**
357 * Returns the identifier of the resource owning the collection.
358 */
359 Q_REQUIRED_RESULT QString resource() const;
360
361 /**
362 * Sets the @p identifier of the resource owning the collection.
363 */
364 void setResource(const QString &identifier);
365
366 /**
367 * Returns the cache policy of the collection.
368 */
369 Q_REQUIRED_RESULT CachePolicy cachePolicy() const;
370
371 /**
372 * Sets the cache @p policy of the collection.
373 */
374 void setCachePolicy(const CachePolicy &policy);
375
376 /**
377 * Returns the collection statistics of the collection.
378 */
379 Q_REQUIRED_RESULT CollectionStatistics statistics() const;
380
381 /**
382 * Sets the collection @p statistics for the collection.
383 */
384 void setStatistics(const CollectionStatistics &statistics);
385
386 /**
387 * Describes the type of url which is returned in url().
388 *
389 * @since 4.7
390 */
391 enum UrlType {
392 UrlShort = 0, ///< A short url which contains the identifier only (equivalent to url())
393 UrlWithName = 1 ///< A url with identifier and name
394 };
395
396 /**
397 * Returns the url of the collection.
398 * @param type the type of url
399 * @since 4.7
400 */
401 Q_REQUIRED_RESULT QUrl url(UrlType type = UrlShort) const;
402
403 /**
404 * Returns whether the collection is virtual, for example a search collection.
405 *
406 * @since 4.6
407 */
408 Q_REQUIRED_RESULT bool isVirtual() const;
409
410 /**
411 * Sets whether the collection is virtual or not.
412 * Virtual collections can't be converted to non-virtual and vice versa.
413 * @param isVirtual virtual collection if @c true, otherwise a normal collection
414 * @since 4.10
415 */
416 void setVirtual(bool isVirtual);
417
418 /**
419 * Sets the collection's enabled state.
420 *
421 * Use this mechanism to set if a collection should be available
422 * to the user or not.
423 *
424 * This can be used in conjunction with the local list preference for finer grained control
425 * to define if a collection should be included depending on the purpose.
426 *
427 * For example: A collection is by default enabled, meaning it is displayed to the user, synchronized by the resource,
428 * and indexed by the indexer. A disabled collection on the other hand is not displayed, synchronized or indexed.
429 * The local list preference allows to locally override that default value for each purpose individually.
430 *
431 * The enabled state can be synchronized by backends.
432 * E.g. an imap resource may synchronize this with the subscription state.
433 *
434 * @since 4.14
435 * @see setLocalListPreference, setShouldList
436 */
437 void setEnabled(bool enabled);
438
439 /**
440 * Returns the collection's enabled state.
441 * @since 4.14
442 * @see localListPreference
443 */
444 Q_REQUIRED_RESULT bool enabled() const;
445
446 /**
447 * Describes the list preference value
448 *
449 * @since 4.14
450 */
451 enum ListPreference {
452 ListEnabled, ///< Enable collection for specified purpose
453 ListDisabled, ///< Disable collection for specified purpose
454 ListDefault ///< Fallback to enabled state
455 };
456
457 /**
458 * Describes the purpose of the listing
459 *
460 * @since 4.14
461 */
462 enum ListPurpose {
463 ListSync, ///< Listing for synchronization
464 ListDisplay, ///< Listing for display to the user
465 ListIndex ///< Listing for indexing the content
466 };
467
468 /**
469 * Sets the local list preference for the specified purpose.
470 *
471 * The local list preference overrides the enabled state unless set to ListDefault.
472 * In case of ListDefault the enabled state should be taken as fallback (shouldList() implements this logic).
473 *
474 * The default value is ListDefault.
475 *
476 * @since 4.14
477 * @see shouldList, setEnabled
478 */
479 void setLocalListPreference(ListPurpose purpose, ListPreference preference);
480
481 /**
482 * Returns the local list preference for the specified purpose.
483 * @since 4.14
484 * @see setLocalListPreference
485 */
486 Q_REQUIRED_RESULT ListPreference localListPreference(ListPurpose purpose) const;
487
488 /**
489 * Returns whether the collection should be listed or not for the specified purpose
490 * Takes enabled state and local preference into account.
491 *
492 * @since 4.14
493 * @see setLocalListPreference, setEnabled
494 */
495 Q_REQUIRED_RESULT bool shouldList(ListPurpose purpose) const;
496
497 /**
498 * Sets whether the collection should be listed or not for the specified purpose.
499 * Takes enabled state and local preference into account.
500 *
501 * Use this instead of sestEnabled and setLocalListPreference to automatically set
502 * the right setting.
503 *
504 * @since 4.14
505 * @see setLocalListPreference, setEnabled
506 */
507 void setShouldList(ListPurpose purpose, bool shouldList);
508
509 /**
510 * Set during sync to indicate that the provided parts are only default values;
511 * @since 4.15
512 */
513 void setKeepLocalChanges(const QSet<QByteArray> &parts);
514
515 /**
516 * Returns what parts are only default values.
517 */
518 QSet<QByteArray> keepLocalChanges() const;
519
520 private:
521 friend class CollectionCreateJob;
522 friend class CollectionFetchJob;
523 friend class CollectionModifyJob;
524 friend class ProtocolHelper;
525
526 void markAttributeModified(const QByteArray &type);
527
528 /// @cond PRIVATE
529 QSharedDataPointer<CollectionPrivate> d_ptr;
530 friend class CollectionPrivate;
531 /// @endcond
532 };
533
534 AKONADICORE_EXPORT uint qHash(const Akonadi::Collection &collection);
535
attribute(Collection::CreateOption option)536 template<typename T> inline T *Akonadi::Collection::attribute(Collection::CreateOption option)
537 {
538 const QByteArray type = T().type();
539 markAttributeModified(type); // do this first in case it detaches
540 if (hasAttribute(type)) {
541 if (T *attr = dynamic_cast<T *>(attribute(type))) {
542 return attr;
543 }
544 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?";
545 } else if (option == AddIfMissing) {
546 T *attr = new T();
547 addAttribute(attr);
548 return attr;
549 }
550
551 return nullptr;
552 }
553
attribute()554 template<typename T> inline const T *Akonadi::Collection::attribute() const
555 {
556 const QByteArray type = T().type();
557 if (hasAttribute(type)) {
558 if (const T *attr = dynamic_cast<const T *>(attribute(type))) {
559 return attr;
560 }
561 qWarning() << "Found attribute of unknown type" << type << ". Did you forget to call AttributeFactory::registerAttribute()?";
562 }
563
564 return nullptr;
565 }
566
removeAttribute()567 template<typename T> inline void Akonadi::Collection::removeAttribute()
568 {
569 removeAttribute(T().type());
570 }
571
hasAttribute()572 template<typename T> inline bool Akonadi::Collection::hasAttribute() const
573 {
574 return hasAttribute(T().type());
575 }
576
577 } // namespace Akonadi
578
579 /**
580 * Allows to output a collection for debugging purposes.
581 */
582 AKONADICORE_EXPORT QDebug operator<<(QDebug d, const Akonadi::Collection &collection);
583
584 Q_DECLARE_METATYPE(Akonadi::Collection)
585 Q_DECLARE_METATYPE(Akonadi::Collection::List)
586 Q_DECLARE_OPERATORS_FOR_FLAGS(Akonadi::Collection::Rights)
587 Q_DECLARE_TYPEINFO(Akonadi::Collection, Q_MOVABLE_TYPE);
588
589