diff --git a/messagelist/src/core/manager.h b/messagelist/src/core/manager.h index 9c3aff78..df4f5271 100644 --- a/messagelist/src/core/manager.h +++ b/messagelist/src/core/manager.h @@ -1,186 +1,185 @@ /****************************************************************************** * * Copyright 2008 Szymon Tomasz Stefanek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *******************************************************************************/ #ifndef __MESSAGELIST_CORE_MANAGER_H__ #define __MESSAGELIST_CORE_MANAGER_H__ #include #include #include #include #include -class QPixmap; namespace KMime { class DateFormatter; } namespace MessageList { namespace Core { class Aggregation; class Theme; class StorageModel; class Widget; /** * @brief: The manager for all the existing MessageList::Widget objects. * * This class is the "central" object of the whole MessageList framework. * It's a singleton that can be accessed only by the means of static methods, * is created automatically when the first MessageList::Widget object is created * and destroyed automatically when the last MessageList::Widget object is destroyed. * * This class takes care of loading/storing/mantaining the settings for the * whole MessageList framework. It also keeps track of all the existing * MessageList::Widget objects and takes care of uptdating them when settings change. */ class Manager : public QObject { Q_OBJECT protected: explicit Manager(); ~Manager(); private: static Manager *mInstance; QList< Widget * > mWidgetList; QHash< QString, Aggregation * > mAggregations; QHash< QString, Theme * > mThemes; KMime::DateFormatter *mDateFormatter; QString mCachedLocalizedUnknownText; public: // instance management static Manager *instance() { return mInstance; } // widget registration static void registerWidget(Widget *pWidget); static void unregisterWidget(Widget *pWidget); const KMime::DateFormatter *dateFormatter() const { return mDateFormatter; } const QString &cachedLocalizedUnknownText() const { return mCachedLocalizedUnknownText; } // aggregation sets management const Aggregation *aggregationForStorageModel(const StorageModel *storageModel, bool *storageUsesPrivateAggregation); const Aggregation *aggregationForStorageModel(const QString &storageModel, bool *storageUsesPrivateAggregation); const Aggregation *aggregationForStorageModel(const Akonadi::Collection &storageModel, bool *storageUsesPrivateAggregation); void saveAggregationForStorageModel(const StorageModel *storageModel, const QString &id, bool storageUsesPrivateAggregation); void saveAggregationForStorageModel(const QString &index, const QString &id, bool storageUsesPrivateAggregation); void saveAggregationForStorageModel(const Akonadi::Collection &col, const QString &id, bool storageUsesPrivateAggregation); const Aggregation *defaultAggregation(); const Aggregation *aggregation(const QString &id); void addAggregation(Aggregation *set); void removeAllAggregations(); const QHash< QString, Aggregation * > &aggregations() const { return mAggregations; } /** * This is called by the aggregation configuration dialog * once the sets have been changed. */ void aggregationsConfigurationCompleted(); // sort order management const SortOrder sortOrderForStorageModel(const StorageModel *storageModel, bool *storageUsesPrivateSortOrder); void saveSortOrderForStorageModel(const StorageModel *storageModel, const SortOrder &order, bool storageUsesPrivateSortOrder); // theme sets management const Theme *themeForStorageModel(const Akonadi::Collection &col, bool *storageUsesPrivateTheme); const Theme *themeForStorageModel(const StorageModel *storageModel, bool *storageUsesPrivateTheme); const Theme *themeForStorageModel(const QString &id, bool *storageUsesPrivateTheme); void saveThemeForStorageModel(const StorageModel *storageModel, const QString &id, bool storageUsesPrivateTheme); void saveThemeForStorageModel(int index, const QString &id, bool storageUsesPrivateTheme); void saveThemeForStorageModel(const QString &storageModelIndex, const QString &id, bool storageUsesPrivateTheme); const Theme *defaultTheme(); const Theme *theme(const QString &id); void addTheme(Theme *set); void removeAllThemes(); const QHash< QString, Theme * > &themes() const { return mThemes; } /** * This is called by the theme configuration dialog * once the sets have been changed. */ void themesConfigurationCompleted(); protected Q_SLOTS: /** * Reloads the global configuration from the config files (so we assume it has changed) * The settings private to MessageList (like Themes or Aggregations) aren't reloaded. * If the global configuration has changed then all the views are reloaded. */ void reloadGlobalConfiguration(); /** * Explicitly reloads the contents of all the widgets. */ void reloadAllWidgets(); Q_SIGNALS: void aggregationsChanged(); void themesChanged(); private: // internal configuration stuff void loadConfiguration(); void saveConfiguration(); void loadGlobalConfiguration(); void saveGlobalConfiguration(); // internal option set management void createDefaultAggregations(); void createDefaultThemes(); }; } // namespace Core } // namespace MessageList #endif //!__MESSAGELIST_CORE_MANAGER_H__ diff --git a/messagelist/src/core/model.h b/messagelist/src/core/model.h index 0e7c6193..84e8fdb2 100644 --- a/messagelist/src/core/model.h +++ b/messagelist/src/core/model.h @@ -1,234 +1,231 @@ /****************************************************************************** * * Copyright 2008 Szymon Tomasz Stefanek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *******************************************************************************/ #ifndef __MESSAGELIST_CORE_MODEL_H__ #define __MESSAGELIST_CORE_MODEL_H__ #include #include #include #include #include #include #include #include // time_t namespace MessageList { namespace Core { typedef long int MessageItemSetReference; -class ViewItemJob; class Filter; class GroupHeaderItem; class Item; class Manager; class MessageItem; class Theme; class StorageModel; -class ModelInvariantRowMapper; -class MessageItemSetManager; class View; class ModelPrivate; /** * This class manages the huge tree of displayable objects: GroupHeaderItems and MessageItems. * The tree is exposed via a 'hacked' QAbstractItemModel interface to a QTreeView * subclass (which is MessageList::View). * * The keypoint in this class is that it has to be non-blocking in manipulating the tree: * fill, cleanup and update operations are performed in timed chunks. Perfect non-blocking * behaviour is not possible since there are some small operations that basically can't be * split in chunks. However, these exceptions apply to a minority of tasks and in the * average case the user will not notice. * * The data for building the tree is obtained from a subclass of StorageModel. The * StorageModel must offer a consistent rappresentation of a "flat" folder containing * messages. */ class Model : public QAbstractItemModel { friend class Item; friend class ItemPrivate; Q_OBJECT public: /** * Creates the mighty Model attached to the specified View. */ explicit Model(View *pParent); /** * Destroys the mighty model along with the tree of items it manages. */ ~Model(); /** * Returns the StorageModel currently set. */ StorageModel *storageModel() const; /** * Sets the storage model from that the messages to be displayed should be fetched. * The model is then reset and a new fill operation is started. The fill operation may * or may not complete before setStorageModel() returns. This depends on the fill * strategy and the size of the folder. You can check if the fill operation has * completed by looking at the return value of isLoading(). * * Pre-selection is the action of automatically selecting a message just after the folder * has finished loading. We may want to select the message that was selected the last * time this folder has been open, or we may want to select the first unread message. * We also may want to do no pre-selection at all (for example, when the user * starts navigating the view before the pre-selection could actually be made * and pre-selecting would confuse him). The pre-selection is applied once * loading is complete. */ void setStorageModel(StorageModel *storageModel, PreSelectionMode preSelectionMode = PreSelectLastSelected); /** * Sets the pre-selection mode. * * Called with PreSelectNone to abort any pending message pre-selection. This may be done if the user * starts navigating the view and selecting items before we actually could * apply the pre-selection. */ void setPreSelectionMode(PreSelectionMode preSelect); /** * Returns the hidden root item that all the messages are (or will be) attached to. * The returned value is never 0. */ Item *rootItem() const; /** * Returns true if the view is currently loading, that is * it's in the first (possibly lenghty) job batch after attacching to a StorageModel. */ bool isLoading() const; /** * Returns the message item that is at the _current_ storage row index * or zero if no such storage item is found. Please note that this may return 0 * also if the specified storage row hasn't been actually read yet. This may happen * if isLoading() returns true. In this case the only thing you can do is to retry in a while. */ MessageItem *messageItemByStorageRow(int row) const; /** * Sets the Aggregation mode. * Does not reload the model in any way: you need to call setStorageModel( storageModel() ) for this to happen. * The pointer ownership remains of the caller which must ensure its validity until the next * call to setAggretation() or until this Model dies. The caller, in fact, is Widget which * takes care of meeting the above conditions. The aggregation pointer must not be null. */ void setAggregation(const Aggregation *aggregation); /** * Sets the Theme. * Does not reload the model in any way: you need to call setStorageModel( storageModel() ) for this to happen. * The pointer ownership remains of the caller which must ensure its validity until the next * call to setTheme() or until this Model dies. The caller, in fact, is Widget which * takes care of meeting the above conditions. The theme pointer must not be null. */ void setTheme(const Theme *theme); /** * Sets the sort order. As with setTheme() and setAggregation(), this does not reload the * model in any way. */ void setSortOrder(const SortOrder *sortOrder); /** * Returns the sort order */ const SortOrder *sortOrder() const; /** * Sets the Filter to be applied on messages. filter may be null (no filter is applied). * The pointer ownership remains of the caller which must ensure its validity until the next * call to setFilter() or until this Model dies. The caller, in fact, is Widget which * takes care of meeting the above conditions. The Filter pointer may be null. */ void setFilter(const Filter *filter); /** * Creates a persistent set for the specified MessageItems and * returns its reference. Later you can use this reference * to retrieve the list of MessageItems that are still valid. * See persistentSetActualMessageList() for that. * * Persistent sets consume resources (both memory and CPU time * while manipulating the view) so be sure to call deletePersistentSet() * when you no longer need it. */ MessageItemSetReference createPersistentSet(const QList< MessageItem * > &items); /** * Returns the list of MessageItems that are still existing in the * set pointed by the specified reference. This list will contain * at most the messages that you have passed to createPersistentSet() * but may contain less (even 0) if these MessageItem object were removed * from the view for some reason. */ QList< MessageItem * > persistentSetCurrentMessageItemList(MessageItemSetReference ref); /** * Deletes the persistent set pointed by the specified reference. * If the set does not exist anymore, nothing happens. */ void deletePersistentSet(MessageItemSetReference ref); // Mandatory QAbstractItemModel interface. int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex index(Item *item, int column) const; QModelIndex parent(const QModelIndex &index) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; /// Called when user initiates a drag from the messagelist QMimeData *mimeData(const QModelIndexList &indexes) const override; Q_SIGNALS: /** * Notify the outside when updating the status bar with a message * could be useful */ void statusMessage(const QString &message); private: friend class ModelPrivate; ModelPrivate *const d; }; } // namespace Core } // namespace MessageList #endif //!__MESSAGELIST_CORE_MODEL_H__ diff --git a/messagelist/src/core/model_p.h b/messagelist/src/core/model_p.h index 397991ca..aada5afc 100644 --- a/messagelist/src/core/model_p.h +++ b/messagelist/src/core/model_p.h @@ -1,456 +1,457 @@ /****************************************************************************** * * Copyright 2008 Szymon Tomasz Stefanek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *******************************************************************************/ #ifndef __MESSAGELIST_CORE_MODEL_P_H__ #define __MESSAGELIST_CORE_MODEL_P_H__ #include "model.h" #include "threadingcache.h" #include #include class QElapsedTimer; - namespace MessageList { namespace Core { - +class ViewItemJob; +class ModelInvariantRowMapper; +class MessageItemSetManager; class ModelPrivate { public: ModelPrivate(Model *owner) : q(owner) { } void fillView(); /** * This is called by MessageList::Manager once in a while. * It is a good place to check if the date has changed and * trigger a view reload. */ void checkIfDateChanged(); void viewItemJobStep(); /** * Attempt to find the threading parent for the specified message item. * Sets the message threading status to the appropriate value. * * This function performs In-Reply-To and References threading. */ MessageItem *findMessageParent(MessageItem *mi); /** * Attempt to find the threading parent for the specified message item. * Sets the message threading status to the appropriate value. * * This function performs Subject based threading. */ MessageItem *guessMessageParent(MessageItem *mi); enum AttachOptions { SkipCacheUpdate = 0, StoreInCache = 1 }; void attachMessageToParent(Item *pParent, MessageItem *mi, AttachOptions attachOptions = StoreInCache); void messageDetachedUpdateParentProperties(Item *oldParent, MessageItem *mi); void attachMessageToGroupHeader(MessageItem *mi); void attachGroup(GroupHeaderItem *ghi); enum ViewItemJobResult { ViewItemJobCompleted, ViewItemJobInterrupted }; ViewItemJobResult viewItemJobStepInternal(); ViewItemJobResult viewItemJobStepInternalForJob(ViewItemJob *job, const QElapsedTimer &elapsedTimer); // FIXME: Those look like they should be made virtual in some job class! -> Refactor ViewItemJobResult viewItemJobStepInternalForJobPass1Fill(ViewItemJob *job, const QElapsedTimer &elapsedTimer); ViewItemJobResult viewItemJobStepInternalForJobPass1Cleanup(ViewItemJob *job, const QElapsedTimer &elapsedTimer); ViewItemJobResult viewItemJobStepInternalForJobPass1Update(ViewItemJob *job, const QElapsedTimer &elapsedTimer); ViewItemJobResult viewItemJobStepInternalForJobPass2(ViewItemJob *job, const QElapsedTimer &elapsedTimer); ViewItemJobResult viewItemJobStepInternalForJobPass3(ViewItemJob *job, const QElapsedTimer &elapsedTimer); ViewItemJobResult viewItemJobStepInternalForJobPass4(ViewItemJob *job, const QElapsedTimer &elapsedTimer); ViewItemJobResult viewItemJobStepInternalForJobPass5(ViewItemJob *job, const QElapsedTimer &elapsedTimer); void clearJobList(); void clearUnassignedMessageLists(); void clearOrphanChildrenHash(); void clearThreadingCacheMessageSubjectMD5ToMessageItem(); void addMessageToSubjectBasedThreadingCache(MessageItem *mi); void removeMessageFromSubjectBasedThreadingCache(MessageItem *mi); void clear(); /** * Sync the expanded state of the subtree with the specified root. * This will cause the items that are marked with Item::ExpandNeeded to be * expanded also in the view. For optimization purposes the specified root * is assumed to be marked as Item::ExpandNeeded so be sure to check it * before calling this function. */ void syncExpandedStateOfSubtree(Item *root); /** * Save the expanded state of the subtree with the specified root. * The state will be saved in the initialExpandStatus() variable. * For optimization purposes the specified root is assumed to be expanded * and viewable. */ void saveExpandedStateOfSubtree(Item *root); #ifdef KDEPIM_FOLDEROPEN_PROFILE // This prints out all the stats we collected void printStatistics(); #endif enum PropertyChanges { DateChanged = 1, MaxDateChanged = (1 << 1), ActionItemStatusChanged = (1 << 2), UnreadStatusChanged = (1 << 3), ImportantStatusChanged = (1 << 4), AttachmentStatusChanged = (1 << 5) }; /** * Handle the specified property changes in item. Depending on the item * position inside the parent and the types of item and parent the item * might need re-grouping or re-sorting. This function takes care of that. * It is meant to be called from somewhere inside viewItemJobStepInternal() * as it postpones group updates to Pass5. * * parent and item must not be null. propertyChangeMask should not be zero. * * Return true if parent might be affected by the item property changes * and false otherwise. */ bool handleItemPropertyChanges(int propertyChangeMask, Item *parent, Item *item); /** * This one checks if the parent of item requires an update due to the * properties of item (that might have been changed or the item might * have been simply added to the parent). The properties * are propagated up to the root item. As optimization we ASSUME that * the item->parent() exists (is non 0) and is NOT the root item. * Be sure to check it before calling this function (it will assert in debug mode anyway). * ... ah... and don't be afraid: this is NOT (directly) recursive :) */ void propagateItemPropertiesToParent(Item *item); /** * Recursively applies the current filter to the tree originating at the specified item. * The item is hidden if the filter doesn't match (the item or any children of it) * and this function returns false. * If the filter matches somewhere in the subtree then the item isn't hidden * and this function returns true. * * Assumes that the specified item is viewable. */ bool applyFilterToSubtree(Item *item, const QModelIndex &parentIndex); // Slots connected to the underlying StorageModel. void slotStorageModelRowsInserted(const QModelIndex &parent, int from, int to); void slotStorageModelRowsRemoved(const QModelIndex &parent, int from, int to); void slotStorageModelDataChanged(const QModelIndex &fromIndex, const QModelIndex &toIndex); void slotStorageModelHeaderDataChanged(Qt::Orientation orientation, int first, int last); void slotStorageModelLayoutChanged(); void slotApplyFilter(); Model *const q; /** counter to avoid infinite recursions in the setStorageModel() function */ int mRecursionCounterForReset; /** * The currently set storage model: shallow pointer. */ StorageModel *mStorageModel; /** * The currently set aggregation mode: shallow pointer set by Widget */ const Aggregation *mAggregation; /** * The currently used theme: shallow pointer */ const Theme *mTheme; /** * The currently used sort order. Pointer not owned by us, but by the Widget. */ const SortOrder *mSortOrder; /** * The filter to apply on messages. Shallow. Never 0. */ const Filter *mFilter; /** * The timer involved in breaking the "fill" operation in steps */ QTimer mFillStepTimer; /** * Group Key (usually the label) -> GroupHeaderItem, used to quickly find groups, pointers are shallow copies */ QHash< QString, GroupHeaderItem * > mGroupHeaderItemHash; /** * Threading cache. * MessageIdMD5 -> MessageItem, pointers are shallow copies */ QHash< QByteArray, MessageItem * > mThreadingCacheMessageIdMD5ToMessageItem; /** * Threading cache. * MessageInReplyToIdMD5 -> MessageItem, pointers are shallow copies */ QMultiHash< QByteArray, MessageItem * > mThreadingCacheMessageInReplyToIdMD5ToMessageItem; /** * Threading cache. * SubjectMD5 -> MessageItem, pointers are shallow copies */ QHash< QByteArray, QList< MessageItem * > * > mThreadingCacheMessageSubjectMD5ToMessageItem; /** * List of group headers that either need to be re-sorted or must be removed because empty */ QHash< GroupHeaderItem *, GroupHeaderItem * > mGroupHeadersThatNeedUpdate; /** * List of unassigned messages, used to handle threading in two passes, pointers are owned! */ QList< MessageItem * > mUnassignedMessageListForPass2; /** * List of unassigned messages, used to handle threading in two passes, pointers are owned! */ QList< MessageItem * > mUnassignedMessageListForPass3; /** * List of unassigned messages, used to handle threading in two passes, pointers are owned! */ QList< MessageItem * > mUnassignedMessageListForPass4; /** * Hash of orphan children used in Pass1Cleanup. */ QHash< MessageItem *, MessageItem * > mOrphanChildrenHash; /** * Pending fill view jobs, pointers are owned */ QList< ViewItemJob * > mViewItemJobs; /** * The today's date. Set when the StorageModel is set and thus grouping is performed. * This is used to put the today's messages in the "Today" group, for instance. */ QDate mTodayDate; /** * Owned invisible root item, useful to implement algorithms that not need * to handle the special case of parentless items. This is never 0. */ Item *mRootItem; /** * The view we're attacched to. Shallow pointer (the View owns us). */ View *mView; /** * The time at the current ViewItemJob step started. Used to compute the time we * spent inside this step and eventually jump out on timeout. */ time_t mViewItemJobStepStartTime; /** * The timeout for a single ViewItemJob step */ int mViewItemJobStepChunkTimeout; /** * The idle time between two ViewItemJob steps */ int mViewItemJobStepIdleInterval; /** * The number of messages we process at once in a ViewItemJob step without * checking the timeouts above. */ int mViewItemJobStepMessageCheckCount; /** * Our mighty ModelInvariantRowMapper: used to workaround an * issue related to the Model/View architecture. * * \sa ModelInvariantRowMapper */ ModelInvariantRowMapper *mInvariantRowMapper; /** * The label for the "Today" group item, cached, so we don't translate it multiple times. */ QString mCachedTodayLabel; /** * The label for the "Yesterday" group item, cached, so we don't translate it multiple times. */ QString mCachedYesterdayLabel; /** * The label for the "Unknown" group item, cached, so we don't translate it multiple times. */ QString mCachedUnknownLabel; /** * The label for the "Last Week" group item, cached, so we don't translate it multiple times. */ QString mCachedLastWeekLabel; /** * The label for the "Two Weeks Ago" group item, cached, so we don't translate it multiple times. */ QString mCachedTwoWeeksAgoLabel; /** * The label for the "Three Weeks Ago" group item, cached, so we don't translate it multiple times. */ QString mCachedThreeWeeksAgoLabel; /** * The label for the "Four Weeks Ago" group item, cached, so we don't translate it multiple times. */ QString mCachedFourWeeksAgoLabel; /** * The label for the "Five Weeks Ago" group item, cached, so we don't translate it multiple times. */ QString mCachedFiveWeeksAgoLabel; /** * Cached bits that we use for fast status checks */ qint32 mCachedWatchedOrIgnoredStatusBits; /** * The labels for week days names group items, cached, so we don't query QLocale multiple times. */ QMap mCachedDayNameLabel; /* * The labels for month names group items, cached, so we don't query QLocale multiple times. */ QMap mCachedMonthNameLabel; /** * Flag signaling a possibly long job batch. This is checked by other * classes and used to display some kind of "please wait" feedback to the user. */ bool mInLengthyJobBatch; /** * We need to save the current item before each job step. This is because * our job may cause items to be reparented (thus removed and readded with the current Qt API) * and QTreeView will loose the current setting. We also use this to force the current * to a specific item after a cleanup job. */ Item *mCurrentItemToRestoreAfterViewItemJobStep; /** * Set to true in the first large loading job. * Reset to false when the job finishes. * * Please note that this is NOT set for later jobs: only for the first (possibly huge) one. */ bool mLoading; /** * Pre-selection is the action of automatically selecting a message just after the folder * has finished loading. We may want to select the message that was selected the last * time this folder has been open, or we may want to select the first unread message. * We also may want to do no pre-selection at all (for example, when the user * starts navigating the view before the pre-selection could actually be made * and pre-selecting would confuse him). This member holds the option. * * See also setStorageModel() and abortMessagePreSelection() */ PreSelectionMode mPreSelectionMode; // Oldest and newest item while loading the model // Not valid afterwards anymore. Used for pre-selection of the newest/oldest message MessageItem *mOldestItem; MessageItem *mNewestItem; /** * The id of the preselected ;essage is "translated" to a message pointer when it's fetched * from the storage. This message is then selected when it becomes viewable * (so at the end of the job). 0 if we have no message to select. * * See also setStorageModel() and abortMessagePreSelection() */ MessageItem *mLastSelectedMessageInFolder; /** * The "persistent message item sets" are (guess what?) sets of messages * that can be referenced globally via a persistent id. The MessageItemSetManager * and this class keep the persistent sets coherent: messages that are deleted * are automatically removed from all the sets. * * Users of this class typically create persistent sets when they start * an asynchronous job and they query them back on the way or when the job is terminated. * * So mPersistentSetManager is in fact the manager for the outstanding "user" jobs. * 0 if no jobs are pending (so there are no persistent sets at the moment). */ MessageItemSetManager *mPersistentSetManager; /** * This pointer is passed to the Item functions that insert children. * When we work with disconnected UI this pointer becomes 0. */ Model *mModelForItemFunctions; /** * The cached result of StorageModel::containsOutboundMessages(). * We access this property at each incoming message and StorageModel::containsOutboundMessages() is * virtual (so it's always an indirect function call). Caching makes sense. */ bool mStorageModelContainsOutboundMessages; /** * Vector of signal-slot connections between StorageModel and us */ QVector mStorageModelConnections; /** * Caches child - parent relation based on Akonadi ID and persists the cache * in a file for each Collection. This allows for very fast reconstruction of * threading. */ ThreadingCache mThreadingCache; }; } // namespace Core } // namespace MessageList #endif //!__MESSAGELIST_CORE_MODEL_P_H__