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