1/*
2 Copyright (c) 2008 Stephen Kelly <steveire@gmail.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#ifndef AKONADI_ENTITYTREEMODEL_H
21#define AKONADI_ENTITYTREEMODEL_H
22
23#include "akonadi_export.h"
24
25#include <akonadi/collection.h>
26#include <akonadi/collectionfetchscope.h>
27#include <akonadi/item.h>
28
29#include <QtCore/QAbstractItemModel>
30#include <QtCore/QStringList>
31
32namespace Akonadi
33{
34
35class ChangeRecorder;
36class CollectionStatistics;
37class Item;
38class ItemFetchScope;
39class Monitor;
40class Session;
41
42class EntityTreeModelPrivate;
43
44/**
45 * @short A model for collections and items together.
46 *
47 * Akonadi models and views provide a high level way to interact with the akonadi server.
48 * Most applications will use these classes.
49 *
50 * Models provide an interface for viewing, updating, deleting and moving Items and Collections.
51 * Additionally, the models are updated automatically if another application changes the
52 * data or inserts of deletes items etc.
53 *
54 * @note The EntityTreeModel should be used with the EntityTreeView or the EntityListView class
55 * either directly or indirectly via proxy models.
56 *
57 * <h3>Retrieving Collections and Items from the model</h3>
58 *
59 * If you want to retrieve and Item or Collection from the model, and already have a valid
60 * QModelIndex for the correct row, the Collection can be retrieved like this:
61 *
62 * @code
63 * Collection col = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
64 * @endcode
65 *
66 * And similarly for Items. This works even if there is a proxy model between the calling code
67 * and the EntityTreeModel.
68 *
69 * If you want to retrieve a Collection for a particular Collection::Id and you do not yet
70 * have a valid QModelIndex, use modelIndexForCollection.
71 *
72 * <h3>Using EntityTreeModel in your application</h3>
73 *
74 * The responsibilities which fall to the application developer are
75 * - Configuring the ChangeRecorder and EntityTreeModel
76 * - Making use of this class via proxy models
77 * - Subclassing for type specific display information
78 *
79 * <h3>Creating and configuring the EntityTreeModel</h3>
80 *
81 * This class is a wrapper around a Akonadi::ChangeRecorder object. The model represents a
82 * part of the collection and item tree configured in the ChangeRecorder. The structure of the
83 * model mirrors the structure of Collections and Items on the %Akonadi server.
84 *
85 * The following code creates a model which fetches items and collections relevant to
86 * addressees (contacts), and automatically manages keeping the items up to date.
87 *
88 * @code
89 *
90 * ChangeRecorder *changeRecorder = new ChangeRecorder( this );
91 * changeRecorder->setCollectionMonitored( Collection::root() );
92 * changeRecorder->setMimeTypeMonitored( KABC::addresseeMimeType() );
93 * changeRecorder->setSession( session );
94 *
95 * EntityTreeModel *model = new EntityTreeModel( changeRecorder, this );
96 *
97 * EntityTreeView *view = new EntityTreeView( this );
98 * view->setModel( model );
99 *
100 * @endcode
101 *
102 * The EntityTreeModel will show items of a different type by changing the line
103 *
104 * @code
105 * changeRecorder->setMimeTypeMonitored( KABC::addresseeMimeType() );
106 * @endcode
107 *
108 * to a different mimetype. KABC::addresseeMimeType() is an alias for "text/directory". If changed to KMime::Message::mimeType()
109 * (an alias for "message/rfc822") the model would instead contain emails. The model can be configured to contain items of any mimetype
110 * known to %Akonadi.
111 *
112 * @note The EntityTreeModel does some extra configuration on the Monitor, such as setting itemFetchScope() and collectionFetchScope()
113 * to retrieve all ancestors. This is necessary for proper function of the model.
114 *
115 * @see Akonadi::ItemFetchScope::AncestorRetrieval.
116 *
117 * @see akonadi-mimetypes.
118 *
119 * The EntityTreeModel can be further configured for certain behaviours such as fetching of collections and items.
120 *
121 * The model can be configured to not fetch items into the model (ie, fetch collections only) by setting
122 *
123 * @code
124 * entityTreeModel->setItemPopulationStrategy( EntityTreeModel::NoItemPopulation );
125 * @endcode
126 *
127 * The items may be fetched lazily, i.e. not inserted into the model until request by the user for performance reasons.
128 *
129 * The Collection tree is always built immediately if Collections are to be fetched.
130 *
131 * @code
132 * entityTreeModel->setItemPopulationStrategy( EntityTreeModel::LazyPopulation );
133 * @endcode
134 *
135 * This will typically be used with a EntityMimeTypeFilterModel in a configuration such as KMail4.5 or AkonadiConsole.
136 *
137 * The CollectionFetchStrategy determines how the model will be populated with Collections. That is, if FetchNoCollections is set,
138 * no collections beyond the root of the model will be fetched. This can be used in combination with setting a particular Collection to monitor.
139 *
140 * @code
141 * // Get an collection id from a config file.
142 * Collection::Id id;
143 * monitor->setCollectionMonitored( Collection( id ) );
144 * // ... Other initialization code.
145 * entityTree->setCollectionFetchStrategy( FetchNoCollections );
146 * @endcode
147 *
148 * This has the effect of creating a model of only a list of Items, and not collections. This is similar in behaviour and aims to the ItemModel.
149 * By using FetchFirstLevelCollections instead, a mixed list of entities can be created.
150 *
151 * @note It is important that you set only one Collection to be monitored in the monitor object. This one collection will be the root of the tree.
152 * If you need a model with a more complex structure, consider monitoring a common ancestor and using a SelectionProxyModel.
153 *
154 * @see lazy-model-population
155 *
156 * It is also possible to show the root Collection as part of the selectable model:
157 *
158 * @code
159 * entityTree->setIncludeRootCollection( true );
160 * @endcode
161 *
162 *
163 * By default the displayed name of the root collection is '[*]', because it doesn't require i18n, and is generic. It can be changed too.
164 *
165 * @code
166 * entityTree->setIncludeRootCollection( true );
167 * entityTree->setRootCollectionDisplayName( i18nc( "Name of top level for all addressbooks in the application", "[All AddressBooks]" ) )
168 * @endcode
169 *
170 * This feature is used in KAddressBook.
171 *
172 * If items are to be fetched by the model, it is necessary to specify which parts of the items
173 * are to be fetched, using the ItemFetchScope class. By default, only the basic metadata is
174 * fetched. To fetch all item data, including all attributes:
175 *
176 * @code
177 * changeRecorder->itemFetchScope().fetchFullPayload();
178 * changeRecorder->itemFetchScope().fetchAllAttributes();
179 * @endcode
180 *
181 * <h2>Using EntityTreeModel with Proxy models</h2>
182 *
183 * An Akonadi::SelectionProxyModel can be used to simplify managing selection in one view through multiple proxy models to a representation in another view.
184 * The selectionModel of the initial view is used to create a proxied model which filters out anything not related to the current selection.
185 *
186 * @code
187 * // ... create an EntityTreeModel
188 *
189 * collectionTree = new EntityMimeTypeFilterModel( this );
190 * collectionTree->setSourceModel( entityTreeModel );
191 *
192 * // Include only collections in this proxy model.
193 * collectionTree->addMimeTypeInclusionFilter( Collection::mimeType() );
194 * collectionTree->setHeaderGroup( EntityTreeModel::CollectionTreeHeaders );
195 *
196 * treeview->setModel(collectionTree);
197 *
198 * // SelectionProxyModel can handle complex selections:
199 * treeview->setSelectionMode( QAbstractItemView::ExtendedSelection );
200 *
201 * SelectionProxyModel *selProxy = new SelectionProxyModel( treeview->selectionModel(), this );
202 * selProxy->setSourceModel( entityTreeModel );
203 *
204 * itemList = new EntityMimeTypeFilterModel( this );
205 * itemList->setSourceModel( selProxy );
206 *
207 * // Filter out collections. Show only items.
208 * itemList->addMimeTypeExclusionFilter( Collection::mimeType() );
209 * itemList->setHeaderGroup( EntityTreeModel::ItemListHeaders );
210 *
211 * EntityTreeView *itemView = new EntityTreeView( splitter );
212 * itemView->setModel( itemList );
213 * @endcode
214 *
215 * The SelectionProxyModel can handle complex selections.
216 *
217 * See the KSelectionProxyModel documentation for the valid configurations of a Akonadi::SelectionProxyModel.
218 *
219 * Obviously, the SelectionProxyModel may be used in a view, or further processed with other proxy models. Typically, the result
220 * from this model will be further filtered to remove collections from the item list as in the above example.
221 *
222 * There are several advantages of using EntityTreeModel with the SelectionProxyModel, namely the items can be fetched and cached
223 * instead of being fetched many times, and the chain of proxies from the core model to the view is automatically handled. There is
224 * no need to manage all the mapToSource and mapFromSource calls manually.
225 *
226 * A KDescendantsProxyModel can be used to represent all descendants of a model as a flat list.
227 * For example, to show all descendant items in a selected Collection in a list:
228 * @code
229 * collectionTree = new EntityMimeTypeFilterModel( this );
230 * collectionTree->setSourceModel( entityTreeModel );
231 *
232 * // Include only collections in this proxy model.
233 * collectionTree->addMimeTypeInclusionFilter( Collection::mimeType() );
234 * collectionTree->setHeaderGroup( EntityTreeModel::CollectionTreeHeaders );
235 *
236 * treeview->setModel( collectionTree );
237 *
238 * SelectionProxyModel *selProxy = new SelectionProxyModel( treeview->selectionModel(), this );
239 * selProxy->setSourceModel( entityTreeModel );
240 *
241 * descendedList = new DescendantEntitiesProxyModel( this );
242 * descendedList->setSourceModel( selProxy );
243 *
244 * itemList = new EntityMimeTypeFilterModel( this );
245 * itemList->setSourceModel( descendedList );
246 *
247 * // Exclude collections from the list view.
248 * itemList->addMimeTypeExclusionFilter( Collection::mimeType() );
249 * itemList->setHeaderGroup( EntityTreeModel::ItemListHeaders );
250 *
251 * listView = new EntityTreeView( this );
252 * listView->setModel( itemList );
253 * @endcode
254 *
255 *
256 * Note that it is important in this case to use the DescendantEntitesProxyModel before the EntityMimeTypeFilterModel.
257 * Otherwise, by filtering out the collections first, you would also be filtering out their child items.
258 *
259 * This pattern is used in KAddressBook.
260 *
261 * It would not make sense to use a KDescendantsProxyModel with LazyPopulation.
262 *
263 * <h3>Subclassing EntityTreeModel</h3>
264 *
265 * Usually an application will create a subclass of an EntityTreeModel and use that in several views via proxy models.
266 *
267 * The subclassing is necessary in order for the data in the model to have type-specific representation in applications
268 *
269 * For example, the headerData for an EntityTreeModel will be different depending on whether it is in a view showing only Collections
270 * in which case the header data should be "AddressBooks" for example, or only Items, in which case the headerData would be
271 * for example "Family Name", "Given Name" and "Email addres" for contacts or "Subject", "Sender", "Date" in the case of emails.
272 *
273 * Additionally, the actual data shown in the rows of the model should be type specific.
274 *
275 * In summary, it must be possible to have different numbers of columns, different data in hte rows of those columns, and different
276 * titles for each column depending on the contents of the view.
277 *
278 * The way this is accomplished is by using the EntityMimeTypeFilterModel for splitting the model into a "CollectionTree" and an "Item List"
279 * as in the above example, and using a type-specific EntityTreeModel subclass to return the type-specific data, typically for only one type (for example, contacts or emails).
280 *
281 * The following protected virtual methods should be implemented in the subclass:
282 * - int entityColumnCount( HeaderGroup headerGroup ) const;
283 * -- Implement to return the number of columns for a HeaderGroup. If the HeaderGroup is CollectionTreeHeaders, return the number of columns to display for the
284 * Collection tree, and if it is ItemListHeaders, return the number of columns to display for the item. In the case of addressee, this could be for example,
285 * two (for given name and family name) or for emails it could be three (for subject, sender, date). This is a decision of the subclass implementor.
286 * - QVariant entityHeaderData( int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup ) const;
287 * -- Implement to return the data for each section for a HeaderGroup. For example, if the header group is CollectionTreeHeaders in a contacts model,
288 * the string "Address books" might be returned for column 0, whereas if the headerGroup is ItemListHeaders, the strings "Given Name", "Family Name",
289 * "Email Address" might be returned for the columns 0, 1, and 2.
290 * - QVariant entityData( const Collection &collection, int column, int role = Qt::DisplayRole ) const;
291 * -- Implement to return data for a particular Collection. Typically this will be the name of the collection or the EntityDisplayAttribute.
292 * - QVariant entityData( const Item &item, int column, int role = Qt::DisplayRole ) const;
293 * -- Implement to return the data for a particular item and column. In the case of email for example, this would be the actual subject, sender and date of the email.
294 *
295 * @note The entityData methods are just for convenience. the QAbstractItemMOdel::data method can be overridden if required.
296 *
297 * The application writer must then properly configure proxy models for the views, so that the correct data is shown in the correct view.
298 * That is the purpose of these lines in the above example
299 *
300 * @code
301 * collectionTree->setHeaderGroup( EntityTreeModel::CollectionTreeHeaders );
302 * itemList->setHeaderGroup( EntityTreeModel::ItemListHeaders );
303 * @endcode
304 *
305 * <h3>Progress reporting</h3>
306 *
307 * The EntityTreeModel uses asynchronous Akonadi::Job instances to fill and update itself.
308 * For example, a job is run to fetch the contents of collections (that is, list the items in it).
309 * Additionally, individual Akonadi::Items can be fetched in different parts at different times.
310 *
311 * To indicate that such a job is underway, the EntityTreeModel makes the FetchState available. The
312 * FetchState returned from a QModelIndex representing a Akonadi::Collection will be FetchingState if a
313 * listing of the items in that collection is underway, otherwise the state is IdleState.
314 *
315 * @author Stephen Kelly <steveire@gmail.com>
316 * @since 4.4
317 */
318class AKONADI_EXPORT EntityTreeModel : public QAbstractItemModel
319{
320 Q_OBJECT
321
322public:
323 /**
324 * Describes the roles for items. Roles for collections are defined by the superclass.
325 */
326 enum Roles {
327 //sebsauer, 2009-05-07; to be able here to keep the akonadi_next EntityTreeModel compatible with
328 //the akonadi_old ItemModel and CollectionModel, we need to use the same int-values for
329 //ItemRole, ItemIdRole and MimeTypeRole like the Akonadi::ItemModel is using and the same
330 //CollectionIdRole and CollectionRole like the Akonadi::CollectionModel is using.
331 ItemIdRole = Qt::UserRole + 1, ///< The item id
332 ItemRole = Qt::UserRole + 2, ///< The Item
333 MimeTypeRole = Qt::UserRole + 3, ///< The mimetype of the entity
334
335 CollectionIdRole = Qt::UserRole + 10, ///< The collection id.
336 CollectionRole = Qt::UserRole + 11, ///< The collection.
337
338 RemoteIdRole, ///< The remoteId of the entity
339 CollectionChildOrderRole, ///< Ordered list of child items if available
340 AmazingCompletionRole, ///< Role used to implement amazing completion
341 ParentCollectionRole, ///< The parent collection of the entity
342 ColumnCountRole, ///< @internal Used by proxies to determine the number of columns for a header group.
343 LoadedPartsRole, ///< Parts available in the model for the item
344 AvailablePartsRole, ///< Parts available in the Akonadi server for the item
345 SessionRole, ///< @internal The Session used by this model
346 CollectionRefRole, ///< @internal Used to increase the reference count on a Collection
347 CollectionDerefRole, ///< @internal Used to decrease the reference count on a Collection
348 PendingCutRole, ///< @internal Used to indicate items which are to be cut
349 EntityUrlRole, ///< The akonadi:/ Url of the entity as a string. Item urls will contain the mimetype.
350 UnreadCountRole, ///< Returns the number of unread items in a collection. @since 4.5
351 FetchStateRole, ///< Returns the FetchState of a particular item. @since 4.5
352 CollectionSyncProgressRole, ///< Returns the progress of synchronization in percent for a particular collection. @since 4.6
353 IsPopulatedRole, ///< Returns whether a Collection has been populated, i.e. whether its items have been fetched. @since 4.10
354 UserRole = Qt::UserRole + 500, ///< First role for user extensions.
355 TerminalUserRole = 2000, ///< Last role for user extensions. Don't use a role beyond this or headerData will break.
356 EndRole = 65535
357 };
358
359 /**
360 * Describes the state of fetch jobs related to particular collections.
361 *
362 * @code
363 * QModelIndex collectionIndex = getIndex();
364 * if (collectionIndex.data(EntityTreeModel::FetchStateRole).toLongLong() == FetchingState) {
365 * // There is a fetch underway
366 * } else {
367 * // There is no fetch underway.
368 * }
369 * @endcode
370 *
371 * @since 4.5
372 */
373 enum FetchState {
374 IdleState, ///< There is no fetch of items in this collection in progress.
375 FetchingState ///< There is a fetch of items in this collection in progress.
376 // TODO: Change states for reporting of fetching payload parts of items.
377 };
378
379 /**
380 * Describes what header information the model shall return.
381 */
382 enum HeaderGroup {
383 EntityTreeHeaders, ///< Header information for a tree with collections and items
384 CollectionTreeHeaders, ///< Header information for a collection-only tree
385 ItemListHeaders, ///< Header information for a list of items
386 UserHeaders = 10, ///< Last header information for submodel extensions
387 EndHeaderGroup = 32 ///< Last headergroup role. Don't use a role beyond this or headerData will break.
388 // Note that we're splitting up available roles for the header data hack and int(EndRole / TerminalUserRole) == 32
389 };
390
391 /**
392 * Creates a new entity tree model.
393 *
394 * @param monitor The ChangeRecorder whose entities should be represented in the model.
395 * @param parent The parent object.
396 */
397 explicit EntityTreeModel(ChangeRecorder *monitor, QObject *parent = 0);
398
399 /**
400 * Destroys the entity tree model.
401 */
402 virtual ~EntityTreeModel();
403
404 /**
405 * Describes how the model should populated its items.
406 */
407 enum ItemPopulationStrategy {
408 NoItemPopulation, ///< Do not include items in the model.
409 ImmediatePopulation, ///< Retrieve items immediately when their parent is in the model. This is the default.
410 LazyPopulation ///< Fetch items only when requested (using canFetchMore/fetchMore)
411 };
412
413 /**
414 * Some Entities are hidden in the model, but exist for internal purposes, for example, custom object
415 * directories in groupware resources.
416 * They are hidden by default, but can be shown by setting @p show to true.
417 * @param show enabled displaying of hidden entities if set as @c true
418 * Most applications will not need to use this feature.
419 */
420 void setShowSystemEntities(bool show);
421
422 /**
423 * Returns @c true if internal system entities are shown, and @c false otherwise.
424 */
425 bool systemEntitiesShown() const;
426
427 /**
428 * Returns whether unsubscribed entities will be included in the listing.
429 *
430 * @since 4.5
431 * @deprecated use listFilter instead
432 */
433 AKONADI_DEPRECATED bool includeUnsubscribed() const;
434
435 /**
436 * Sets whether unsubscribed entities will be included in the listing.
437 * By default it's true
438 * @param show enables displaying of unsubscribed entities if set as @c true
439 * Note that it is possible to change the monitor's fetchscope directly,
440 * bypassing this method, which will lead to inconsistencies. Use
441 * this method for turning on/off listing of subscribed folders.
442 *
443 * @since 4.5
444 * @deprecated use setListFilter instead
445 */
446 AKONADI_DEPRECATED void setIncludeUnsubscribed(bool show);
447
448 /**
449 * Returns the currently used listfilter.
450 *
451 * @since 4.14
452 */
453 Akonadi::CollectionFetchScope::ListFilter listFilter() const;
454
455 /**
456 * Sets the currently used listfilter.
457 *
458 * @since 4.14
459 */
460 void setListFilter(Akonadi::CollectionFetchScope::ListFilter filter);
461
462 /**
463 * Monitors the specified collections and resets the model.
464 *
465 * @since 4.14
466 */
467 void setCollectionsMonitored(const Akonadi::Collection::List &collections);
468
469 /**
470 * Adds or removes a specific collection from the monitored set without resetting the model.
471 * Only call this if you're monitoring specific collections (not mimetype/resources/items).
472 *
473 * @since 4.14
474 * @see setCollectionsMonitored()
475 */
476 void setCollectionMonitored(const Akonadi::Collection &col, bool monitored = true);
477
478 /**
479 * References a collection and starts to monitor it.
480 *
481 * Use this to temporarily include a collection that is not enabled.
482 *
483 * @since 4.14
484 */
485 void setCollectionReferenced(const Akonadi::Collection &col, bool referenced = true);
486
487 /**
488 * Sets the item population @p strategy of the model.
489 */
490 void setItemPopulationStrategy(ItemPopulationStrategy strategy);
491
492 /**
493 * Returns the item population strategy of the model.
494 */
495 ItemPopulationStrategy itemPopulationStrategy() const;
496
497 /**
498 * Sets whether the root collection shall be provided by the model.
499 * @param include enables root collection if set as @c true
500 * @see setRootCollectionDisplayName()
501 */
502 void setIncludeRootCollection(bool include);
503
504 /**
505 * Returns whether the root collection is provided by the model.
506 */
507 bool includeRootCollection() const;
508
509 /**
510 * Sets the display @p name of the root collection of the model.
511 * The default display name is "[*]".
512 * @param name the name to display for the root collection
513 * @note The display name for the root collection is only used if
514 * the root collection has been included with setIncludeRootCollection().
515 */
516 void setRootCollectionDisplayName(const QString &name);
517
518 /**
519 * Returns the display name of the root collection.
520 */
521 QString rootCollectionDisplayName() const;
522
523 /**
524 * Describes what collections shall be fetched by and represent in the model.
525 */
526 enum CollectionFetchStrategy {
527 FetchNoCollections, ///< Fetches nothing. This creates an empty model.
528 FetchFirstLevelChildCollections, ///< Fetches first level collections in the root collection.
529 FetchCollectionsRecursive, ///< Fetches collections in the root collection recursively. This is the default.
530 InvisibleCollectionFetch ///< Fetches collections, but does not put them in the model. This can be used to create a list of items in all collections. The ParentCollectionRole can still be used to retrieve the parent collection of an Item. @since 4.5
531 };
532
533 /**
534 * Sets the collection fetch @p strategy of the model.
535 */
536 void setCollectionFetchStrategy(CollectionFetchStrategy strategy);
537
538 /**
539 * Returns the collection fetch strategy of the model.
540 */
541 CollectionFetchStrategy collectionFetchStrategy() const;
542
543 virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
544 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
545
546 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
547 virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
548
549 virtual Qt::ItemFlags flags(const QModelIndex &index) const;
550 virtual QStringList mimeTypes() const;
551
552 virtual Qt::DropActions supportedDropActions() const;
553 virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
554 virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
555 virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
556
557 virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
558 virtual QModelIndex parent(const QModelIndex &index) const;
559
560 // TODO: Review the implementations of these. I think they could be better.
561 virtual bool canFetchMore(const QModelIndex &parent) const;
562 virtual void fetchMore(const QModelIndex &parent);
563 virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
564
565 /**
566 * Returns whether the collection tree has been fetched at initialisation.
567 *
568 * @see collectionTreeFetched
569 * @since 4.10
570 */
571 bool isCollectionTreeFetched() const;
572
573 /**
574 * Returns whether the collection has been populated.
575 *
576 * @see collectionPopulated
577 * @since 4.12
578 */
579 bool isCollectionPopulated(Akonadi::Collection::Id) const;
580
581 /**
582 * Returns whether the model is fully populated.
583 *
584 * Returns true once the collection tree has been fetched and all collections have been populated.
585 *
586 * @see isCollectionPopulated
587 * @see isCollectionTreeFetched
588 * @since 4.14
589 */
590 bool isFullyPopulated() const;
591
592 /**
593 * Reimplemented to handle the AmazingCompletionRole.
594 */
595 virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const;
596
597 /**
598 * Returns a QModelIndex in @p model which points to @p collection.
599 * This method can be used through proxy models if @p model is a proxy model.
600 * @code
601 * EntityTreeModel *model = getEntityTreeModel();
602 * QSortFilterProxyModel *proxy1 = new QSortFilterProxyModel;
603 * proxy1->setSourceModel(model);
604 * QSortFilterProxyModel *proxy2 = new QSortFilterProxyModel;
605 * proxy2->setSourceModel(proxy1);
606 *
607 * ...
608 *
609 * QModelIndex idx = EntityTreeModel::modelIndexForCollection(proxy2, Collection(colId));
610 * if (!idx.isValid())
611 * // Collection with id colId is not in the proxy2.
612 * // Maybe it is filtered out if proxy 2 is only showing items? Make sure you use the correct proxy.
613 * return;
614 *
615 * Collection collection = idx.data( EntityTreeModel::CollectionRole ).value<Collection>();
616 * // collection has the id colId, and all other attributes already fetched by the model such as name, remoteId, Akonadi::Attributes etc.
617 *
618 * @endcode
619 *
620 * This can be useful for example if an id is stored in a config file and needs to be used in the application.
621 *
622 * Note however, that to restore view state such as scrolling, selection and expansion of items in trees, the ETMViewStateSaver can be used for convenience.
623 *
624 * @see modelIndexesForItem
625 * @since 4.5
626 */
627 static QModelIndex modelIndexForCollection(const QAbstractItemModel *model, const Collection &collection);
628
629 /**
630 * Returns a QModelIndex in @p model which points to @p item.
631 * This method can be used through proxy models if @p model is a proxy model.
632 * @param model the model to query for the item
633 * @param item the item to look for
634 * @see modelIndexForCollection
635 * @since 4.5
636 */
637 static QModelIndexList modelIndexesForItem(const QAbstractItemModel *model, const Item &item);
638
639Q_SIGNALS:
640 /**
641 * Signal emitted when the collection tree has been fetched for the first time.
642 * @param collections list of collections which have been fetched
643 *
644 * @see isCollectionTreeFetched, collectionPopulated
645 * @since 4.10
646 */
647 void collectionTreeFetched(const Akonadi::Collection::List &collections);
648
649 /**
650 * Signal emitted when a collection has been populated, i.e. its items have been fetched.
651 * @param collectionId id of the collection which has been populated
652 *
653 * @see collectionTreeFetched
654 * @since 4.10
655 */
656 void collectionPopulated(Akonadi::Collection::Id collectionId);
657 /**
658 * Emitted once a collection has been fetched for the very first time.
659 * This is like a dataChanged(), but specific to the initial loading, in order to update
660 * the GUI (window caption, state of actions).
661 * Usually, the GUI uses Akonadi::Monitor to be notified of further changes to the collections.
662 * @param collectionId the identifier of the fetched collection
663 * @since 4.9.3
664 */
665 void collectionFetched(int collectionId);
666
667protected:
668 /**
669 * Clears and resets the model. Always call this instead of the reset method in the superclass.
670 * Using the reset method will not reliably clear or refill the model.
671 */
672 void clearAndReset();
673
674 /**
675 * Provided for convenience of subclasses.
676 */
677 virtual QVariant entityData(const Item &item, int column, int role = Qt::DisplayRole) const;
678
679 /**
680 * Provided for convenience of subclasses.
681 */
682 virtual QVariant entityData(const Collection &collection, int column, int role = Qt::DisplayRole) const;
683
684 /**
685 * Reimplement this to provide different header data. This is needed when using one model
686 * with multiple proxies and views, and each should show different header data.
687 */
688 virtual QVariant entityHeaderData(int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup) const;
689
690 virtual int entityColumnCount(HeaderGroup headerGroup) const;
691
692 /**
693 * Reimplement this in a subclass to return true if @p item matches @p value with @p flags in the AmazingCompletionRole.
694 */
695 virtual bool entityMatch(const Item &item, const QVariant &value, Qt::MatchFlags flags) const;
696
697 /**
698 * Reimplement this in a subclass to return true if @p collection matches @p value with @p flags in the AmazingCompletionRole.
699 */
700 virtual bool entityMatch(const Collection &collection, const QVariant &value, Qt::MatchFlags flags) const;
701
702protected:
703 //@cond PRIVATE
704 Q_DECLARE_PRIVATE(EntityTreeModel)
705 EntityTreeModelPrivate *d_ptr;
706 EntityTreeModel(ChangeRecorder *monitor, EntityTreeModelPrivate *d, QObject *parent = 0);
707 //@endcond
708
709private:
710 //@cond PRIVATE
711 // Make these private, they shouldn't be called by applications
712 virtual bool insertRows(int , int, const QModelIndex& = QModelIndex());
713 virtual bool insertColumns(int, int, const QModelIndex& = QModelIndex());
714 virtual bool removeColumns(int, int, const QModelIndex& = QModelIndex());
715 virtual bool removeRows(int, int, const QModelIndex& = QModelIndex());
716
717 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionStatisticsChanged(Akonadi::Collection::Id,
718 const Akonadi::CollectionStatistics &))
719
720 Q_PRIVATE_SLOT(d_func(), void startFirstListJob())
721 Q_PRIVATE_SLOT(d_func(), void serverStarted())
722
723 Q_PRIVATE_SLOT(d_func(), void itemFetchJobDone(KJob *job))
724 Q_PRIVATE_SLOT(d_func(), void collectionFetchJobDone(KJob *job))
725 Q_PRIVATE_SLOT(d_func(), void rootFetchJobDone(KJob *job))
726 Q_PRIVATE_SLOT(d_func(), void pasteJobDone(KJob *job))
727 Q_PRIVATE_SLOT(d_func(), void updateJobDone(KJob *job))
728 Q_PRIVATE_SLOT(d_func(), void finalCollectionFetchJobDone(KJob *job))
729
730 Q_PRIVATE_SLOT(d_func(), void itemsFetched(Akonadi::Item::List))
731 Q_PRIVATE_SLOT(d_func(), void collectionsFetched(Akonadi::Collection::List))
732 Q_PRIVATE_SLOT(d_func(), void collectionListFetched(Akonadi::Collection::List))
733 Q_PRIVATE_SLOT(d_func(), void topLevelCollectionsFetched(Akonadi::Collection::List))
734 Q_PRIVATE_SLOT(d_func(), void ancestorsFetched(Akonadi::Collection::List))
735
736 Q_PRIVATE_SLOT(d_func(), void monitoredMimeTypeChanged(const QString &, bool))
737 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionsChanged(const Akonadi::Collection &, bool))
738 Q_PRIVATE_SLOT(d_func(), void monitoredItemsChanged(const Akonadi::Item &, bool))
739 Q_PRIVATE_SLOT(d_func(), void monitoredResourcesChanged(const QByteArray &, bool))
740
741 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionAdded(const Akonadi::Collection &, const Akonadi::Collection &))
742 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionRemoved(const Akonadi::Collection &))
743 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionChanged(const Akonadi::Collection &))
744 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionMoved(const Akonadi::Collection &, const Akonadi::Collection &,
745 const Akonadi::Collection &))
746
747 Q_PRIVATE_SLOT(d_func(), void monitoredItemAdded(const Akonadi::Item &, const Akonadi::Collection &))
748 Q_PRIVATE_SLOT(d_func(), void monitoredItemRemoved(const Akonadi::Item &))
749 Q_PRIVATE_SLOT(d_func(), void monitoredItemChanged(const Akonadi::Item &, const QSet<QByteArray> &))
750 Q_PRIVATE_SLOT(d_func(), void monitoredItemMoved(const Akonadi::Item &, const Akonadi::Collection &,
751 const Akonadi::Collection &))
752
753 Q_PRIVATE_SLOT(d_func(), void monitoredItemLinked(const Akonadi::Item &, const Akonadi::Collection &))
754 Q_PRIVATE_SLOT(d_func(), void monitoredItemUnlinked(const Akonadi::Item &, const Akonadi::Collection &))
755 Q_PRIVATE_SLOT(d_func(), void changeFetchState(const Akonadi::Collection &))
756
757 Q_PRIVATE_SLOT(d_func(), void agentInstanceAdvancedStatusChanged(const QString &, const QVariantMap &))
758 Q_PRIVATE_SLOT(d_func(), void agentInstanceRemoved(Akonadi::AgentInstance))
759 Q_PRIVATE_SLOT(d_func(), void monitoredItemsRetrieved(KJob *job))
760 //@endcond
761};
762
763} // namespace
764
765#endif
766