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 | |
32 | namespace Akonadi |
33 | { |
34 | |
35 | class ChangeRecorder; |
36 | class CollectionStatistics; |
37 | class Item; |
38 | class ItemFetchScope; |
39 | class Monitor; |
40 | class Session; |
41 | |
42 | class 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 | */ |
318 | class AKONADI_EXPORT EntityTreeModel : public QAbstractItemModel |
319 | { |
320 | Q_OBJECT |
321 | |
322 | public: |
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 { |
383 | , ///< Header information for a tree with collections and items |
384 | , ///< Header information for a collection-only tree |
385 | , ///< Header information for a list of items |
386 | = 10, ///< Last header information for submodel extensions |
387 | = 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 (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 | |
639 | Q_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 | |
667 | protected: |
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 (int section, Qt::Orientation orientation, int role, HeaderGroup ) const; |
689 | |
690 | virtual int entityColumnCount(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 | |
702 | protected: |
703 | //@cond PRIVATE |
704 | Q_DECLARE_PRIVATE(EntityTreeModel) |
705 | EntityTreeModelPrivate *d_ptr; |
706 | EntityTreeModel(ChangeRecorder *monitor, EntityTreeModelPrivate *d, QObject *parent = 0); |
707 | //@endcond |
708 | |
709 | private: |
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 | |