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