File indexing completed on 2024-06-23 05:06:43
0001 /* 0002 SPDX-FileCopyrightText: 2008 Stephen Kelly <steveire@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include "akonadicore_export.h" 0010 #include "collection.h" 0011 #include "collectionfetchscope.h" 0012 #include "item.h" 0013 0014 #include <QAbstractItemModel> 0015 #include <QStringList> 0016 0017 #include <memory> 0018 0019 namespace Akonadi 0020 { 0021 class CollectionStatistics; 0022 class Item; 0023 class ItemFetchScope; 0024 class Monitor; 0025 class Session; 0026 0027 class EntityTreeModelPrivate; 0028 0029 /** 0030 * @short A model for collections and items together. 0031 * 0032 * Akonadi models and views provide a high level way to interact with the akonadi server. 0033 * Most applications will use these classes. 0034 * 0035 * Models provide an interface for viewing, updating, deleting and moving Items and Collections. 0036 * Additionally, the models are updated automatically if another application changes the 0037 * data or inserts of deletes items etc. 0038 * 0039 * @note The EntityTreeModel should be used with the EntityTreeView or the EntityListView class 0040 * either directly or indirectly via proxy models. 0041 * 0042 * <h3>Retrieving Collections and Items from the model</h3> 0043 * 0044 * If you want to retrieve and Item or Collection from the model, and already have a valid 0045 * QModelIndex for the correct row, the Collection can be retrieved like this: 0046 * 0047 * @code 0048 * Collection col = index.data(EntityTreeModel::CollectionRole).value<Collection>(); 0049 * @endcode 0050 * 0051 * And similarly for Items. This works even if there is a proxy model between the calling code 0052 * and the EntityTreeModel. 0053 * 0054 * If you want to retrieve a Collection for a particular Collection::Id and you do not yet 0055 * have a valid QModelIndex, use modelIndexForCollection. 0056 * 0057 * <h3>Using EntityTreeModel in your application</h3> 0058 * 0059 * The responsibilities which fall to the application developer are 0060 * - Configuring the Monitor and EntityTreeModel 0061 * - Making use of this class via proxy models 0062 * - Subclassing for type specific display information 0063 * 0064 * <h3>Creating and configuring the EntityTreeModel</h3> 0065 * 0066 * This class is a wrapper around a Akonadi::Monitor object. The model represents a 0067 * part of the collection and item tree configured in the Monitor. The structure of the 0068 * model mirrors the structure of Collections and Items on the %Akonadi server. 0069 * 0070 * The following code creates a model which fetches items and collections relevant to 0071 * addressees (contacts), and automatically manages keeping the items up to date. 0072 * 0073 * @code 0074 * 0075 * auto monitor = new Monitor(this); 0076 * monitor->setCollectionMonitored(Collection::root()); 0077 * monitor->setMimeTypeMonitored(KContacts::Addressee::mimeType()); 0078 * monitor->setSession(session); 0079 * 0080 * auto model = new EntityTreeModel(monitor, this); 0081 * 0082 * auto view = new EntityTreeView(this); 0083 * view->setModel(model); 0084 * 0085 * @endcode 0086 * 0087 * The EntityTreeModel will show items of a different type by changing the line 0088 * 0089 * @code 0090 * monitor->setMimeTypeMonitored(KContacts::Addressee::mimeType()); 0091 * @endcode 0092 * 0093 * to a different mimetype. KContacts::Addressee::mimeType() is an alias for "text/directory". If changed to KMime::Message::mimeType() 0094 * (an alias for "message/rfc822") the model would instead contain emails. The model can be configured to contain items of any mimetype 0095 * known to %Akonadi. 0096 * 0097 * @note The EntityTreeModel does some extra configuration on the Monitor, such as setting itemFetchScope() and collectionFetchScope() 0098 * to retrieve all ancestors. This is necessary for proper function of the model. 0099 * 0100 * @see Akonadi::ItemFetchScope::AncestorRetrieval. 0101 * 0102 * @see akonadi-mimetypes. 0103 * 0104 * The EntityTreeModel can be further configured for certain behaviours such as fetching of collections and items. 0105 * 0106 * The model can be configured to not fetch items into the model (ie, fetch collections only) by setting 0107 * 0108 * @code 0109 * entityTreeModel->setItemPopulationStrategy(EntityTreeModel::NoItemPopulation); 0110 * @endcode 0111 * 0112 * The items may be fetched lazily, i.e. not inserted into the model until request by the user for performance reasons. 0113 * 0114 * The Collection tree is always built immediately if Collections are to be fetched. 0115 * 0116 * @code 0117 * entityTreeModel->setItemPopulationStrategy(EntityTreeModel::LazyPopulation); 0118 * @endcode 0119 * 0120 * This will typically be used with a EntityMimeTypeFilterModel in a configuration such as KMail or AkonadiConsole. 0121 * 0122 * The CollectionFetchStrategy determines how the model will be populated with Collections. That is, if FetchNoCollections is set, 0123 * no collections beyond the root of the model will be fetched. This can be used in combination with setting a particular Collection to monitor. 0124 * 0125 * @code 0126 * // Get an collection id from a config file. 0127 * Collection::Id id; 0128 * monitor->setCollectionMonitored(Collection(id)); 0129 * // ... Other initialization code. 0130 * entityTree->setCollectionFetchStrategy(FetchNoCollections); 0131 * @endcode 0132 * 0133 * 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. 0134 * By using FetchFirstLevelCollections instead, a mixed list of entities can be created. 0135 * 0136 * @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. 0137 * If you need a model with a more complex structure, consider monitoring a common ancestor and using a SelectionProxyModel. 0138 * 0139 * @see lazy-model-population 0140 * 0141 * It is also possible to show the root Collection as part of the selectable model: 0142 * 0143 * @code 0144 * entityTree->setIncludeRootCollection(true); 0145 * @endcode 0146 * 0147 * 0148 * By default the displayed name of the root collection is '[*]', because it doesn't require i18n, and is generic. It can be changed too. 0149 * 0150 * @code 0151 * entityTree->setIncludeRootCollection(true); 0152 * entityTree->setRootCollectionDisplayName(i18nc("Name of top level for all addressbooks in the application", "[All AddressBooks]")) 0153 * @endcode 0154 * 0155 * This feature is used in KAddressBook. 0156 * 0157 * If items are to be fetched by the model, it is necessary to specify which parts of the items 0158 * are to be fetched, using the ItemFetchScope class. By default, only the basic metadata is 0159 * fetched. To fetch all item data, including all attributes: 0160 * 0161 * @code 0162 * monitor->itemFetchScope().fetchFullPayload(); 0163 * monitor->itemFetchScope().fetchAllAttributes(); 0164 * @endcode 0165 * 0166 * <h2>Using EntityTreeModel with Proxy models</h2> 0167 * 0168 * An Akonadi::SelectionProxyModel can be used to simplify managing selection in one view through multiple proxy models to a representation in another view. 0169 * The selectionModel of the initial view is used to create a proxied model which filters out anything not related to the current selection. 0170 * 0171 * @code 0172 * // ... create an EntityTreeModel 0173 * 0174 * collectionTree = new EntityMimeTypeFilterModel(this); 0175 * collectionTree->setSourceModel(entityTreeModel); 0176 * 0177 * // Include only collections in this proxy model. 0178 * collectionTree->addMimeTypeInclusionFilter(Collection::mimeType()); 0179 * collectionTree->setHeaderGroup(EntityTreeModel::CollectionTreeHeaders); 0180 * 0181 * treeview->setModel(collectionTree); 0182 * 0183 * // SelectionProxyModel can handle complex selections: 0184 * treeview->setSelectionMode(QAbstractItemView::ExtendedSelection); 0185 * 0186 * auto selProxy = new SelectionProxyModel(treeview->selectionModel(), this); 0187 * selProxy->setSourceModel(entityTreeModel); 0188 * 0189 * itemList = new EntityMimeTypeFilterModel(this); 0190 * itemList->setSourceModel(selProxy); 0191 * 0192 * // Filter out collections. Show only items. 0193 * itemList->addMimeTypeExclusionFilter(Collection::mimeType()); 0194 * itemList->setHeaderGroup(EntityTreeModel::ItemListHeaders); 0195 * 0196 * auto itemView = new EntityTreeView(splitter); 0197 * itemView->setModel(itemList); 0198 * @endcode 0199 * 0200 * The SelectionProxyModel can handle complex selections. 0201 * 0202 * See the KSelectionProxyModel documentation for the valid configurations of a Akonadi::SelectionProxyModel. 0203 * 0204 * Obviously, the SelectionProxyModel may be used in a view, or further processed with other proxy models. Typically, the result 0205 * from this model will be further filtered to remove collections from the item list as in the above example. 0206 * 0207 * There are several advantages of using EntityTreeModel with the SelectionProxyModel, namely the items can be fetched and cached 0208 * instead of being fetched many times, and the chain of proxies from the core model to the view is automatically handled. There is 0209 * no need to manage all the mapToSource and mapFromSource calls manually. 0210 * 0211 * A KDescendantsProxyModel can be used to represent all descendants of a model as a flat list. 0212 * For example, to show all descendant items in a selected Collection in a list: 0213 * @code 0214 * auto collectionTree = new EntityMimeTypeFilterModel(this); 0215 * collectionTree->setSourceModel(entityTreeModel); 0216 * 0217 * // Include only collections in this proxy model. 0218 * collectionTree->addMimeTypeInclusionFilter(Collection::mimeType()); 0219 * collectionTree->setHeaderGroup(EntityTreeModel::CollectionTreeHeaders); 0220 * 0221 * treeview->setModel(collectionTree); 0222 * 0223 * auto selProxy = new SelectionProxyModel(treeview->selectionModel(), this); 0224 * selProxy->setSourceModel(entityTreeModel); 0225 * 0226 * auto descendedList = new KDescendantsProxyModel(this); 0227 * descendedList->setSourceModel(selProxy); 0228 * 0229 * auto itemList = new EntityMimeTypeFilterModel(this); 0230 * itemList->setSourceModel(descendedList); 0231 * 0232 * // Exclude collections from the list view. 0233 * itemList->addMimeTypeExclusionFilter(Collection::mimeType()); 0234 * itemList->setHeaderGroup(EntityTreeModel::ItemListHeaders); 0235 * 0236 * listView = new EntityTreeView(this); 0237 * listView->setModel(itemList); 0238 * @endcode 0239 * 0240 * 0241 * Note that it is important in this case to use the KDescendantsProxyModel before the EntityMimeTypeFilterModel. 0242 * Otherwise, by filtering out the collections first, you would also be filtering out their child items. 0243 * 0244 * This pattern is used in KAddressBook. 0245 * 0246 * It would not make sense to use a KDescendantsProxyModel with LazyPopulation. 0247 * 0248 * <h3>Subclassing EntityTreeModel</h3> 0249 * 0250 * Usually an application will create a subclass of an EntityTreeModel and use that in several views via proxy models. 0251 * 0252 * The subclassing is necessary in order for the data in the model to have type-specific representation in applications 0253 * 0254 * For example, the headerData for an EntityTreeModel will be different depending on whether it is in a view showing only Collections 0255 * in which case the header data should be "AddressBooks" for example, or only Items, in which case the headerData would be 0256 * for example "Family Name", "Given Name" and "Email address" for contacts or "Subject", "Sender", "Date" in the case of emails. 0257 * 0258 * Additionally, the actual data shown in the rows of the model should be type specific. 0259 * 0260 * In summary, it must be possible to have different numbers of columns, different data in the rows of those columns, and different 0261 * titles for each column depending on the contents of the view. 0262 * 0263 * The way this is accomplished is by using the EntityMimeTypeFilterModel for splitting the model into a "CollectionTree" and an "Item List" 0264 * 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, 0265 * contacts or emails). 0266 * 0267 * The following protected virtual methods should be implemented in the subclass: 0268 * - `int entityColumnCount( HeaderGroup headerGroup ) const;` 0269 * -- Implement to return the number of columns for a HeaderGroup. If the HeaderGroup is CollectionTreeHeaders, return the number of columns to display for the 0270 * 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, 0271 * 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. 0272 * - `QVariant entityHeaderData( int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup ) const;` 0273 * -- Implement to return the data for each section for a HeaderGroup. For example, if the header group is CollectionTreeHeaders in a contacts model, 0274 * the string "Address books" might be returned for column 0, whereas if the headerGroup is ItemListHeaders, the strings "Given Name", "Family Name", 0275 * "Email Address" might be returned for the columns 0, 1, and 2. 0276 * - `QVariant entityData( const Collection &collection, int column, int role = Qt::DisplayRole ) const;` 0277 * -- Implement to return data for a particular Collection. Typically this will be the name of the collection or the EntityDisplayAttribute. 0278 * - `QVariant entityData(const Item &item, int column, int role = Qt::DisplayRole) const;` 0279 * -- 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 0280 * email. 0281 * 0282 * @note The entityData methods are just for convenience. the QAbstractItemModel::data method can be overridden if required. 0283 * 0284 * The application writer must then properly configure proxy models for the views, so that the correct data is shown in the correct view. 0285 * That is the purpose of these lines in the above example 0286 * 0287 * @code 0288 * collectionTree->setHeaderGroup(EntityTreeModel::CollectionTreeHeaders); 0289 * itemList->setHeaderGroup(EntityTreeModel::ItemListHeaders); 0290 * @endcode 0291 * 0292 * <h3>Progress reporting</h3> 0293 * 0294 * The EntityTreeModel uses asynchronous Akonadi::Job instances to fill and update itself. 0295 * For example, a job is run to fetch the contents of collections (that is, list the items in it). 0296 * Additionally, individual Akonadi::Items can be fetched in different parts at different times. 0297 * 0298 * To indicate that such a job is underway, the EntityTreeModel makes the FetchState available. The 0299 * FetchState returned from a QModelIndex representing a Akonadi::Collection will be FetchingState if a 0300 * listing of the items in that collection is underway, otherwise the state is IdleState. 0301 * 0302 * @author Stephen Kelly <steveire@gmail.com> 0303 * @since 4.4 0304 */ 0305 class AKONADICORE_EXPORT EntityTreeModel : public QAbstractItemModel 0306 { 0307 Q_OBJECT 0308 0309 public: 0310 /** 0311 * Describes the roles for items. Roles for collections are defined by the superclass. 0312 */ 0313 enum Roles { 0314 // sebsauer, 2009-05-07; to be able here to keep the akonadi_next EntityTreeModel compatible with 0315 // the akonadi_old ItemModel and CollectionModel, we need to use the same int-values for 0316 // ItemRole, ItemIdRole and MimeTypeRole like the Akonadi::ItemModel is using and the same 0317 // CollectionIdRole and CollectionRole like the Akonadi::CollectionModel is using. 0318 ItemIdRole = Qt::UserRole + 1, ///< The item id 0319 ItemRole = Qt::UserRole + 2, ///< The Item 0320 MimeTypeRole = Qt::UserRole + 3, ///< The mimetype of the entity 0321 0322 CollectionIdRole = Qt::UserRole + 10, ///< The collection id. 0323 CollectionRole = Qt::UserRole + 11, ///< The collection. 0324 0325 RemoteIdRole, ///< The remoteId of the entity 0326 CollectionChildOrderRole, ///< Ordered list of child items if available 0327 ParentCollectionRole, ///< The parent collection of the entity 0328 ColumnCountRole, ///< @internal Used by proxies to determine the number of columns for a header group. 0329 LoadedPartsRole, ///< Parts available in the model for the item 0330 AvailablePartsRole, ///< Parts available in the Akonadi server for the item 0331 SessionRole, ///< @internal The Session used by this model 0332 CollectionRefRole, ///< @internal Used to increase the reference count on a Collection 0333 CollectionDerefRole, ///< @internal Used to decrease the reference count on a Collection 0334 PendingCutRole, ///< Used to indicate items which are to be cut 0335 EntityUrlRole, ///< The akonadi:/ Url of the entity as a string. Item urls will contain the mimetype. 0336 UnreadCountRole, ///< Returns the number of unread items in a collection. @since 4.5 0337 FetchStateRole, ///< Returns the FetchState of a particular item. @since 4.5 0338 IsPopulatedRole, ///< Returns whether a Collection has been populated, i.e. whether its items have been fetched. @since 4.10 0339 OriginalCollectionNameRole, ///< Returns original name for collection @since 4.14 0340 DisplayNameRole, ///< Returns the same as Qt::DisplayRole 0341 UserRole = Qt::UserRole + 500, ///< First role for user extensions. 0342 TerminalUserRole = 2000, ///< Last role for user extensions. Don't use a role beyond this or headerData will break. 0343 EndRole = 65535 0344 }; 0345 0346 /** 0347 * Describes the state of fetch jobs related to particular collections. 0348 * 0349 * @code 0350 * QModelIndex collectionIndex = getIndex(); 0351 * if (collectionIndex.data(EntityTreeModel::FetchStateRole).toLongLong() == FetchingState) { 0352 * // There is a fetch underway 0353 * } else { 0354 * // There is no fetch underway. 0355 * } 0356 * @endcode 0357 * 0358 * @since 4.5 0359 */ 0360 enum FetchState { 0361 IdleState, ///< There is no fetch of items in this collection in progress. 0362 FetchingState ///< There is a fetch of items in this collection in progress. 0363 // TODO: Change states for reporting of fetching payload parts of items. 0364 }; 0365 Q_ENUM(FetchState) 0366 0367 /** 0368 * Describes what header information the model shall return. 0369 */ 0370 enum HeaderGroup { 0371 EntityTreeHeaders, ///< Header information for a tree with collections and items 0372 CollectionTreeHeaders, ///< Header information for a collection-only tree 0373 ItemListHeaders, ///< Header information for a list of items 0374 UserHeaders = 10, ///< Last header information for submodel extensions 0375 EndHeaderGroup = 32 ///< Last headergroup role. Don't use a role beyond this or headerData will break. 0376 // Note that we're splitting up available roles for the header data hack and int(EndRole / TerminalUserRole) == 32 0377 }; 0378 0379 /** 0380 * Creates a new entity tree model. 0381 * 0382 * @param monitor The Monitor whose entities should be represented in the model. 0383 * @param parent The parent object. 0384 */ 0385 explicit EntityTreeModel(Monitor *monitor, QObject *parent = nullptr); 0386 0387 /** 0388 * Destroys the entity tree model. 0389 */ 0390 ~EntityTreeModel() override; 0391 0392 /** 0393 * Describes how the model should populated its items. 0394 */ 0395 enum ItemPopulationStrategy { 0396 NoItemPopulation, ///< Do not include items in the model. 0397 ImmediatePopulation, ///< Retrieve items immediately when their parent is in the model. This is the default. 0398 LazyPopulation ///< Fetch items only when requested (using canFetchMore/fetchMore) 0399 }; 0400 0401 /** 0402 * Some Entities are hidden in the model, but exist for internal purposes, for example, custom object 0403 * directories in groupware resources. 0404 * They are hidden by default, but can be shown by setting @p show to true. 0405 * @param show enabled displaying of hidden entities if set as @c true 0406 * Most applications will not need to use this feature. 0407 */ 0408 void setShowSystemEntities(bool show); 0409 0410 /** 0411 * Returns @c true if internal system entities are shown, and @c false otherwise. 0412 */ 0413 [[nodiscard]] bool systemEntitiesShown() const; 0414 0415 /** 0416 * Returns the currently used listfilter. 0417 * 0418 * @since 4.14 0419 */ 0420 [[nodiscard]] Akonadi::CollectionFetchScope::ListFilter listFilter() const; 0421 0422 /** 0423 * Sets the currently used listfilter. 0424 * 0425 * @since 4.14 0426 */ 0427 void setListFilter(Akonadi::CollectionFetchScope::ListFilter filter); 0428 0429 /** 0430 * Monitors the specified collections and resets the model. 0431 * 0432 * @since 4.14 0433 */ 0434 void setCollectionsMonitored(const Akonadi::Collection::List &collections); 0435 0436 /** 0437 * Adds or removes a specific collection from the monitored set without resetting the model. 0438 * Only call this if you're monitoring specific collections (not mimetype/resources/items). 0439 * 0440 * @since 4.14 0441 * @see setCollectionsMonitored() 0442 */ 0443 void setCollectionMonitored(const Akonadi::Collection &col, bool monitored = true); 0444 0445 /** 0446 * Sets the item population @p strategy of the model. 0447 */ 0448 void setItemPopulationStrategy(ItemPopulationStrategy strategy); 0449 0450 /** 0451 * Returns the item population strategy of the model. 0452 */ 0453 [[nodiscard]] ItemPopulationStrategy itemPopulationStrategy() const; 0454 0455 /** 0456 * Sets whether the root collection shall be provided by the model. 0457 * @param include enables root collection if set as @c true 0458 * @see setRootCollectionDisplayName() 0459 */ 0460 void setIncludeRootCollection(bool include); 0461 0462 /** 0463 * Returns whether the root collection is provided by the model. 0464 */ 0465 [[nodiscard]] bool includeRootCollection() const; 0466 0467 /** 0468 * Sets the display @p name of the root collection of the model. 0469 * The default display name is "[*]". 0470 * @param name the name to display for the root collection 0471 * @note The display name for the root collection is only used if 0472 * the root collection has been included with setIncludeRootCollection(). 0473 */ 0474 void setRootCollectionDisplayName(const QString &name); 0475 0476 /** 0477 * Returns the display name of the root collection. 0478 */ 0479 [[nodiscard]] QString rootCollectionDisplayName() const; 0480 0481 /** 0482 * Describes what collections shall be fetched by and represent in the model. 0483 */ 0484 enum CollectionFetchStrategy { 0485 FetchNoCollections, ///< Fetches nothing. This creates an empty model. 0486 FetchFirstLevelChildCollections, ///< Fetches first level collections in the root collection. 0487 FetchCollectionsRecursive, ///< Fetches collections in the root collection recursively. This is the default. 0488 InvisibleCollectionFetch ///< Fetches collections, but does not put them in the model. This can be used to create a list of items in all collections. 0489 ///< The ParentCollectionRole can still be used to retrieve the parent collection of an Item. @since 4.5 0490 }; 0491 0492 /** 0493 * Sets the collection fetch @p strategy of the model. 0494 */ 0495 void setCollectionFetchStrategy(CollectionFetchStrategy strategy); 0496 0497 /** 0498 * Returns the collection fetch strategy of the model. 0499 */ 0500 [[nodiscard]] CollectionFetchStrategy collectionFetchStrategy() const; 0501 0502 [[nodiscard]] QHash<int, QByteArray> roleNames() const override; 0503 0504 [[nodiscard]] int columnCount(const QModelIndex &parent = QModelIndex()) const override; 0505 [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0506 0507 [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 0508 [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 0509 0510 [[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override; 0511 [[nodiscard]] QStringList mimeTypes() const override; 0512 0513 [[nodiscard]] Qt::DropActions supportedDropActions() const override; 0514 [[nodiscard]] QMimeData *mimeData(const QModelIndexList &indexes) const override; 0515 bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; 0516 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; 0517 0518 [[nodiscard]] QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 0519 [[nodiscard]] QModelIndex parent(const QModelIndex &index) const override; 0520 0521 // TODO: Review the implementations of these. I think they could be better. 0522 [[nodiscard]] bool canFetchMore(const QModelIndex &parent) const override; 0523 void fetchMore(const QModelIndex &parent) override; 0524 [[nodiscard]] bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; 0525 0526 /** 0527 * Returns whether the collection tree has been fetched at initialisation. 0528 * 0529 * @see collectionTreeFetched 0530 * @since 4.10 0531 */ 0532 [[nodiscard]] bool isCollectionTreeFetched() const; 0533 0534 /** 0535 * Returns whether the collection has been populated. 0536 * 0537 * @see collectionPopulated 0538 * @since 4.12 0539 */ 0540 [[nodiscard]] bool isCollectionPopulated(Akonadi::Collection::Id) const; 0541 0542 /** 0543 * Returns whether the model is fully populated. 0544 * 0545 * Returns true once the collection tree has been fetched and all collections have been populated. 0546 * 0547 * @see isCollectionPopulated 0548 * @see isCollectionTreeFetched 0549 * @since 4.14 0550 */ 0551 [[nodiscard]] bool isFullyPopulated() const; 0552 0553 /** 0554 * Reimplemented to handle the AmazingCompletionRole. 0555 */ 0556 [[nodiscard]] QModelIndexList match(const QModelIndex &start, 0557 int role, 0558 const QVariant &value, 0559 int hits = 1, 0560 Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override; 0561 0562 /** 0563 * Returns a QModelIndex in @p model which points to @p collection. 0564 * This method can be used through proxy models if @p model is a proxy model. 0565 * @code 0566 * EntityTreeModel *model = getEntityTreeModel(); 0567 * QSortFilterProxyModel *proxy1 = new QSortFilterProxyModel; 0568 * proxy1->setSourceModel(model); 0569 * QSortFilterProxyModel *proxy2 = new QSortFilterProxyModel; 0570 * proxy2->setSourceModel(proxy1); 0571 * 0572 * ... 0573 * 0574 * QModelIndex idx = EntityTreeModel::modelIndexForCollection(proxy2, Collection(colId)); 0575 * if (!idx.isValid()) 0576 * // Collection with id colId is not in the proxy2. 0577 * // Maybe it is filtered out if proxy 2 is only showing items? Make sure you use the correct proxy. 0578 * return; 0579 * 0580 * Collection collection = idx.data( EntityTreeModel::CollectionRole ).value<Collection>(); 0581 * // collection has the id colId, and all other attributes already fetched by the model such as name, remoteId, Akonadi::Attributes etc. 0582 * 0583 * @endcode 0584 * 0585 * This can be useful for example if an id is stored in a config file and needs to be used in the application. 0586 * 0587 * Note however, that to restore view state such as scrolling, selection and expansion of items in trees, the ETMViewStateSaver can be used for convenience. 0588 * 0589 * @see modelIndexesForItem 0590 * @since 4.5 0591 */ 0592 static QModelIndex modelIndexForCollection(const QAbstractItemModel *model, const Collection &collection); 0593 0594 /** 0595 * Returns a QModelIndex in @p model which points to @p item. 0596 * This method can be used through proxy models if @p model is a proxy model. 0597 * @param model the model to query for the item 0598 * @param item the item to look for 0599 * @see modelIndexForCollection 0600 * @since 4.5 0601 */ 0602 static QModelIndexList modelIndexesForItem(const QAbstractItemModel *model, const Item &item); 0603 0604 /** 0605 * Returns an Akonadi::Collection from the @p model based on given @p collectionId. 0606 * 0607 * This is faster and simpler than retrieving a full Collection from the ETM 0608 * by using modelIndexForCollection() and then querying for the index data. 0609 */ 0610 static Collection updatedCollection(const QAbstractItemModel *model, qint64 collectionId); 0611 static Collection updatedCollection(const QAbstractItemModel *model, const Collection &col); 0612 0613 Q_SIGNALS: 0614 /** 0615 * Signal emitted when the collection tree has been fetched for the first time. 0616 * @param collections list of collections which have been fetched 0617 * 0618 * @see isCollectionTreeFetched, collectionPopulated 0619 * @since 4.10 0620 */ 0621 void collectionTreeFetched(const Akonadi::Collection::List &collections); 0622 0623 /** 0624 * Signal emitted when a collection has been populated, i.e. its items have been fetched. 0625 * @param collectionId id of the collection which has been populated 0626 * 0627 * @see collectionTreeFetched 0628 * @since 4.10 0629 */ 0630 void collectionPopulated(Akonadi::Collection::Id collectionId); 0631 /** 0632 * Emitted once a collection has been fetched for the very first time. 0633 * This is like a dataChanged(), but specific to the initial loading, in order to update 0634 * the GUI (window caption, state of actions). 0635 * Usually, the GUI uses Akonadi::Monitor to be notified of further changes to the collections. 0636 * @param collectionId the identifier of the fetched collection 0637 * @since 4.9.3 0638 */ 0639 void collectionFetched(int collectionId); 0640 0641 protected: 0642 /** 0643 * Clears and resets the model. Always call this instead of the reset method in the superclass. 0644 * Using the reset method will not reliably clear or refill the model. 0645 */ 0646 void clearAndReset(); 0647 0648 /** 0649 * Provided for convenience of subclasses. 0650 */ 0651 virtual QVariant entityData(const Item &item, int column, int role = Qt::DisplayRole) const; 0652 0653 /** 0654 * Provided for convenience of subclasses. 0655 */ 0656 virtual QVariant entityData(const Collection &collection, int column, int role = Qt::DisplayRole) const; 0657 0658 /** 0659 * Reimplement this to provide different header data. This is needed when using one model 0660 * with multiple proxies and views, and each should show different header data. 0661 */ 0662 virtual QVariant entityHeaderData(int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup) const; 0663 0664 virtual int entityColumnCount(HeaderGroup headerGroup) const; 0665 0666 protected: 0667 /// @cond PRIVATE 0668 Q_DECLARE_PRIVATE(EntityTreeModel) 0669 std::unique_ptr<EntityTreeModelPrivate> const d_ptr; 0670 EntityTreeModel(Monitor *monitor, EntityTreeModelPrivate *d, QObject *parent = nullptr); 0671 /// @endcond 0672 0673 private: 0674 /// @cond PRIVATE 0675 // Make these private, they shouldn't be called by applications 0676 bool insertRows(int row, int count, const QModelIndex &index = QModelIndex()) override; 0677 bool insertColumns(int column, int count, const QModelIndex &index = QModelIndex()) override; 0678 bool removeColumns(int column, int count, const QModelIndex &index = QModelIndex()) override; 0679 bool removeRows(int row, int count, const QModelIndex &index = QModelIndex()) override; 0680 0681 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionStatisticsChanged(Akonadi::Collection::Id, const Akonadi::CollectionStatistics &)) 0682 0683 Q_PRIVATE_SLOT(d_func(), void startFirstListJob()) 0684 Q_PRIVATE_SLOT(d_func(), void serverStarted()) 0685 0686 Q_PRIVATE_SLOT(d_func(), void collectionFetchJobDone(KJob *job)) 0687 Q_PRIVATE_SLOT(d_func(), void rootFetchJobDone(KJob *job)) 0688 Q_PRIVATE_SLOT(d_func(), void pasteJobDone(KJob *job)) 0689 Q_PRIVATE_SLOT(d_func(), void updateJobDone(KJob *job)) 0690 0691 Q_PRIVATE_SLOT(d_func(), void itemsFetched(const Akonadi::Item::List &)) 0692 Q_PRIVATE_SLOT(d_func(), void collectionsFetched(Akonadi::Collection::List)) 0693 Q_PRIVATE_SLOT(d_func(), void topLevelCollectionsFetched(Akonadi::Collection::List)) 0694 Q_PRIVATE_SLOT(d_func(), void ancestorsFetched(Akonadi::Collection::List)) 0695 0696 Q_PRIVATE_SLOT(d_func(), void monitoredMimeTypeChanged(const QString &, bool)) 0697 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionsChanged(const Akonadi::Collection &, bool)) 0698 Q_PRIVATE_SLOT(d_func(), void monitoredItemsChanged(const Akonadi::Item &, bool)) 0699 Q_PRIVATE_SLOT(d_func(), void monitoredResourcesChanged(const QByteArray &, bool)) 0700 0701 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionAdded(const Akonadi::Collection &, const Akonadi::Collection &)) 0702 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionRemoved(const Akonadi::Collection &)) 0703 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionChanged(const Akonadi::Collection &)) 0704 Q_PRIVATE_SLOT(d_func(), void monitoredCollectionMoved(const Akonadi::Collection &, const Akonadi::Collection &, const Akonadi::Collection &)) 0705 0706 Q_PRIVATE_SLOT(d_func(), void monitoredItemAdded(const Akonadi::Item &, const Akonadi::Collection &)) 0707 Q_PRIVATE_SLOT(d_func(), void monitoredItemRemoved(const Akonadi::Item &)) 0708 Q_PRIVATE_SLOT(d_func(), void monitoredItemChanged(const Akonadi::Item &, const QSet<QByteArray> &)) 0709 Q_PRIVATE_SLOT(d_func(), void monitoredItemMoved(const Akonadi::Item &, const Akonadi::Collection &, const Akonadi::Collection &)) 0710 0711 Q_PRIVATE_SLOT(d_func(), void monitoredItemLinked(const Akonadi::Item &, const Akonadi::Collection &)) 0712 Q_PRIVATE_SLOT(d_func(), void monitoredItemUnlinked(const Akonadi::Item &, const Akonadi::Collection &)) 0713 Q_PRIVATE_SLOT(d_func(), void changeFetchState(const Akonadi::Collection &)) 0714 0715 Q_PRIVATE_SLOT(d_func(), void agentInstanceRemoved(Akonadi::AgentInstance)) 0716 Q_PRIVATE_SLOT(d_func(), void monitoredItemsRetrieved(KJob *job)) 0717 /// @endcond 0718 }; 0719 0720 } // namespace