Messagelib

pane.h
1 /*
2  SPDX-FileCopyrightText: 2009 Kevin Ottens <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include <QHash>
10 #include <QTabWidget>
11 #include <QVector>
12 #include <messagelist/enums.h>
13 #include <messagelist/view.h>
14 
15 #include "messagelist_export.h"
16 #include <Akonadi/Collection>
17 #include <Akonadi/Item>
18 #include <KMime/KMimeMessage>
19 
20 class KXMLGUIClient;
21 class QAbstractItemModel;
23 class QItemSelection;
24 
25 namespace KPIM
26 {
27 class MessageStatus;
28 }
29 
30 namespace MessageList
31 {
32 class Widget;
33 class StorageModel;
34 
35 /**
36  * This is the main MessageList panel for Akonadi applications.
37  * It contains multiple MessageList::Widget tabs
38  * so it can actually display multiple folder sets at once.
39  *
40  * When a KXmlGuiWindow is passed to setXmlGuiClient, the XMLGUI
41  * defined context menu @c akonadi_messagelist_contextmenu is
42  * used if available.
43  *
44  */
45 class MESSAGELIST_EXPORT Pane : public QTabWidget
46 {
47  Q_OBJECT
48 
49 public:
50  /**
51  * Create a Pane wrapping the specified model and selection.
52  */
53  explicit Pane(bool restoreSession, QAbstractItemModel *model, QItemSelectionModel *selectionModel, QWidget *parent = nullptr);
54  ~Pane() override;
55 
56  virtual MessageList::StorageModel *createStorageModel(QAbstractItemModel *model, QItemSelectionModel *selectionModel, QObject *parent);
57 
58  virtual void writeConfig(bool restoreSession);
59 
60  /**
61  * Sets the XML GUI client which the pane is used in.
62  *
63  * This is needed if you want to use the built-in context menu.
64  * Passing 0 is ok and will disable the builtin context menu.
65  *
66  * @param xmlGuiClient The KXMLGUIClient the view is used in.
67  */
68  void setXmlGuiClient(KXMLGUIClient *xmlGuiClient);
69 
70  /**
71  * Returns the current message for the list as Akonadi::Item.
72  * May return an invalid Item if there is no current message or no current folder.
73  */
74  Q_REQUIRED_RESULT Akonadi::Item currentItem() const;
75 
76  /**
77  * Returns the current message for the list as KMime::Message::Ptr.
78  * May return 0 if there is no current message or no current folder.
79  */
80  KMime::Message::Ptr currentMessage() const;
81 
82  /**
83  * Returns the currently selected KMime::Message::Ptr (bound to current StorageModel).
84  * The list may be empty if there are no selected messages or no StorageModel.
85  *
86  * If includeCollapsedChildren is true then the children of the selected but
87  * collapsed items are also added to the list.
88  *
89  * The returned list is guaranteed to be valid only until you return control
90  * to the main even loop. Don't store it for any longer. If you need to reference
91  * this set of messages at a later stage then take a look at createPersistentSet().
92  */
93  Q_REQUIRED_RESULT QVector<KMime::Message::Ptr> selectionAsMessageList(bool includeCollapsedChildren = true) const;
94 
95  /**
96  * Returns the currently selected Items (bound to current StorageModel).
97  * The list may be empty if there are no selected messages or no StorageModel.
98  *
99  * If includeCollapsedChildren is true then the children of the selected but
100  * collapsed items are also added to the list.
101  *
102  * The returned list is guaranteed to be valid only until you return control
103  * to the main even loop. Don't store it for any longer. If you need to reference
104  * this set of messages at a later stage then take a look at createPersistentSet().
105  */
106  Q_REQUIRED_RESULT Akonadi::Item::List selectionAsMessageItemList(bool includeCollapsedChildren = true) const;
107 
108  /**
109  * Returns the currently selected Items id(bound to current StorageModel).
110  * The list may be empty if there are no selected messages or no StorageModel.
111  *
112  * If includeCollapsedChildren is true then the children of the selected but
113  * collapsed items are also added to the list.
114  *
115  * The returned list is guaranteed to be valid only until you return control
116  * to the main even loop. Don't store it for any longer. If you need to reference
117  * this set of messages at a later stage then take a look at createPersistentSet().
118  */
119  Q_REQUIRED_RESULT QVector<qlonglong> selectionAsMessageItemListId(bool includeCollapsedChildren = true) const;
120 
121  Q_REQUIRED_RESULT QVector<Akonadi::Item::Id> selectionAsListMessageId(bool includeCollapsedChildren = true) const;
122 
123  /**
124  * Returns the Akonadi::Item bound to the current StorageModel that
125  * are part of the current thread. The current thread is the thread
126  * that contains currentMessageItem().
127  * The list may be empty if there is no currentMessageItem() or no StorageModel.
128  *
129  * The returned list is guaranteed to be valid only until you return control
130  * to the main even loop. Don't store it for any longer. If you need to reference
131  * this set of messages at a later stage then take a look at createPersistentSet().
132  */
133  Q_REQUIRED_RESULT Akonadi::Item::List currentThreadAsMessageList() const;
134 
135  /**
136  * Selects the next message item in the view.
137  *
138  * messageTypeFilter can be used to restrict the selection to only certain message types.
139  *
140  * existingSelectionBehaviour specifies how the existing selection
141  * is manipulated. It may be cleared, expanded or grown/shrunk.
142  *
143  * If centerItem is true then the specified item will be positioned
144  * at the center of the view, if possible.
145  * If loop is true then the "next" algorithm will restart from the beginning
146  * of the list if the end is reached, otherwise it will just stop returning false.
147  */
148  Q_REQUIRED_RESULT bool selectNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter,
149  MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
150  bool centerItem,
151  bool loop);
152 
153  /**
154  * Selects the previous message item in the view.
155  * If centerItem is true then the specified item will be positioned
156  * at the center of the view, if possible.
157  *
158  * messageTypeFilter can be used to restrict the selection to only certain message types.
159  *
160  * existingSelectionBehaviour specifies how the existing selection
161  * is manipulated. It may be cleared, expanded or grown/shrunk.
162  *
163  * If loop is true then the "previous" algorithm will restart from the end
164  * of the list if the beginning is reached, otherwise it will just stop returning false.
165  */
166  Q_REQUIRED_RESULT bool selectPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter,
167  MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
168  bool centerItem,
169  bool loop);
170 
171  /**
172  * Focuses the next message item in the view without actually selecting it.
173  *
174  * messageTypeFilter can be used to restrict the selection to only certain message types.
175  *
176  * If centerItem is true then the specified item will be positioned
177  * at the center of the view, if possible.
178  * If loop is true then the "next" algorithm will restart from the beginning
179  * of the list if the end is reached, otherwise it will just stop returning false.
180  */
181  Q_REQUIRED_RESULT bool focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop);
182 
183  /**
184  * Focuses the previous message item in the view without actually selecting it.
185  *
186  * messageTypeFilter can be used to restrict the selection to only certain message types.
187  *
188  * If centerItem is true then the specified item will be positioned
189  * at the center of the view, if possible.
190  * If loop is true then the "previous" algorithm will restart from the end
191  * of the list if the beginning is reached, otherwise it will just stop returning false.
192  */
193  Q_REQUIRED_RESULT bool focusPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop);
194 
195  /**
196  * Selects the currently focused message item. May do nothing if the
197  * focused message item is already selected (which is very likely).
198  * If centerItem is true then the specified item will be positioned
199  * at the center of the view, if possible.
200  */
201  void selectFocusedMessageItem(bool centerItem);
202 
203  /**
204  * Selects the first message item in the view that matches the specified Core::MessageTypeFilter.
205  * If centerItem is true then the specified item will be positioned
206  * at the center of the view, if possible.
207  *
208  * If the current view is already loaded then the request will
209  * be satisfied immediately (well... if an unread message exists at all).
210  * If the current view is still loading then the selection of the first
211  * message will be scheduled to be executed when loading terminates.
212  *
213  * So this function doesn't actually guarantee that an unread or new message
214  * was selected when the call returns. Take care :)
215  *
216  * The function returns true if a message was selected and false otherwise.
217  */
218  Q_REQUIRED_RESULT bool selectFirstMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem);
219 
220  /**
221  * Selects the last message item in the view that matches the specified Core::MessageTypeFilter.
222  * If centerItem is true then the specified item will be positioned
223  * at the center of the view, if possible.
224  *
225  * The function returns true if a message was selected and false otherwise.
226  */
227  Q_REQUIRED_RESULT bool selectLastMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem);
228 
229  /**
230  * If expand is true then it expands the current thread, otherwise
231  * collapses it.
232  */
233  void setCurrentThreadExpanded(bool expand);
234 
235  /**
236  * If expand is true then it expands all the threads, otherwise
237  * collapses them.
238  */
239  void setAllThreadsExpanded(bool expand);
240 
241  /**
242  * If expand is true then it expands all the groups (only the toplevel
243  * group item: inner threads are NOT expanded). If expand is false
244  * then it collapses all the groups. If no grouping is in effect
245  * then this function does nothing.
246  */
247  void setAllGroupsExpanded(bool expand);
248 
249  /**
250  * Sets the focus on the quick search line of the currently active tab.
251  */
252  void focusQuickSearch(const QString &selectedText = QString());
253 
254  /**
255  * Returns the Akonadi::MessageStatus in the current quicksearch field.
256  */
257  Q_REQUIRED_RESULT QVector<Akonadi::MessageStatus> currentFilterStatus() const;
258 
259  /**
260  * Returns the search term in the current quicksearch field.
261  */
262  Q_REQUIRED_RESULT QString currentFilterSearchString() const;
263 
264  /**
265  * Returns true if the current Aggregation is threaded, false otherwise
266  * (or if there is no current Aggregation).
267  */
268  Q_REQUIRED_RESULT bool isThreaded() const;
269 
270  /**
271  * Fast function that determines if the selection is empty
272  */
273  Q_REQUIRED_RESULT bool selectionEmpty() const;
274  /**
275  * Fills the lists of the selected message serial numbers and of the selected+visible ones.
276  * Returns true if the returned stats are valid (there is a current folder after all)
277  * and false otherwise. This is called by KMMainWidget in a single place so we optimize by
278  * making it a single sweep on the selection.
279  *
280  * If includeCollapsedChildren is true then the children of the selected but
281  * collapsed items are also included in the stats
282  */
283  Q_REQUIRED_RESULT bool getSelectionStats(Akonadi::Item::List &selectedItems,
284  Akonadi::Item::List &selectedVisibleItems,
285  bool *allSelectedBelongToSameThread,
286  bool includeCollapsedChildren = true) const;
287  /**
288  * Deletes the persistent set pointed by the specified reference.
289  * If the set does not exist anymore, nothing happens.
290  */
291  void deletePersistentSet(MessageList::Core::MessageItemSetReference ref);
292 
293  /**
294  * If bMark is true this function marks the messages as "about to be removed"
295  * so they appear dimmer and aren't selectable in the view.
296  * If bMark is false then this function clears the "about to be removed" state
297  * for the specified MessageItems.
298  */
299  void markMessageItemsAsAboutToBeRemoved(MessageList::Core::MessageItemSetReference ref, bool bMark);
300 
301  /**
302  * Return Akonadi::Item from messageItemReference
303  */
304  Q_REQUIRED_RESULT Akonadi::Item::List itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref);
305 
306  /**
307  * Return a persistent set from current selection
308  */
309  Q_REQUIRED_RESULT MessageList::Core::MessageItemSetReference selectionAsPersistentSet(bool includeCollapsedChildren = true) const;
310 
311  /**
312  * Return a persistent set from current thread
313  */
314  Q_REQUIRED_RESULT MessageList::Core::MessageItemSetReference currentThreadAsPersistentSet() const;
315  /**
316  * Sets the focus on the view of the currently active tab.
317  */
318  void focusView();
319 
320  /**
321  * Reloads global configuration and eventually reloads all the views.
322  */
323  void reloadGlobalConfiguration();
324 
325  /**
326  * Returns the QItemSelectionModel for the currently displayed tab.
327  */
328  QItemSelectionModel *currentItemSelectionModel();
329 
330  /**
331  * Sets the current folder to be displayed by this Pane.
332  * If the specified folder is already open in one of the tabs
333  * then that tab is made current (and no reloading happens).
334  * If the specified folder is not open yet then behaviour
335  * depends on the preferEmptyTab value as follows.
336  *
337  * @param etmIndex the index for the collection in the EntityTreeModel (source model)
338  *
339  * If preferEmptyTab is set to false then the (new) folder is loaded
340  * in the current tab. If preferEmptyTab is set to true then the (new) folder is
341  * loaded in the first empty tab (or a new one if there are no empty ones).
342  *
343  * Pre-selection is the action of automatically selecting a message just after the folder
344  * has finished loading. See Model::setStorageModel() for more information.
345  *
346  * If overrideLabel is not empty then it's used as the tab text for the
347  * specified folder. This is useful to signal a particular folder state
348  * like "loading..."
349  */
350  void setCurrentFolder(const Akonadi::Collection &fld,
351  const QModelIndex &etmIndex,
352  bool preferEmptyTab = false,
353  MessageList::Core::PreSelectionMode preSelectionMode = MessageList::Core::PreSelectLastSelected,
354  const QString &overrideLabel = QString());
355 
356  void resetModelStorage();
357 
358  void setPreferEmptyTab(bool emptyTab);
359 
360  void updateTabIconText(const Akonadi::Collection &collection, const QString &label, const QIcon &icon);
361 
362  void saveCurrentSelection();
363 
364  void updateTagComboBox();
365 
366  bool searchEditHasFocus() const;
367 
368  void setQuickSearchClickMessage(const QString &msg);
369 
370  void populateStatusFilterCombo();
371 
372  Core::QuickSearchLine::SearchOptions currentOptions() const;
373 
374  Q_REQUIRED_RESULT Akonadi::Collection currentFolder() const;
375 
376 public Q_SLOTS:
377  /**
378  * Selects all the items in the current folder.
379  */
380  void selectAll();
381 
382  /**
383  * Add a new tab to the Pane and select it.
384  */
385  QItemSelectionModel *createNewTab();
386 
387  void sortOrderMenuAboutToShow();
388 
389  void aggregationMenuAboutToShow();
390 
391  void themeMenuAboutToShow();
392 
393 Q_SIGNALS:
394  /**
395  * Emitted when a message is selected (that is, single clicked and thus made current in the view)
396  * Note that this message CAN be 0 (when the current item is cleared, for example).
397  *
398  * This signal is emitted when a SINGLE message is selected in the view, probably
399  * by clicking on it or by simple keyboard navigation. When multiple items
400  * are selected at once (by shift+clicking, for example) then you will get
401  * this signal only for the last clicked message (or at all, if the last shift+clicked
402  * thing is a group header...). You should handle selection changed in this case.
403  */
404  void messageSelected(const Akonadi::Item &item);
405 
406  /**
407  * Emitted when a message is doubleclicked or activated by other input means
408  */
409  void messageActivated(const Akonadi::Item &item);
410 
411  /**
412  * Emitted when the selection in the view changes.
413  */
414  void selectionChanged();
415 
416  /**
417  * Emitted when a message wants its status to be changed
418  */
419  void messageStatusChangeRequest(const Akonadi::Item &item, const Akonadi::MessageStatus &set, const Akonadi::MessageStatus &clear);
420 
421  /**
422  * Notify the outside when updating the status bar with a message
423  * could be useful
424  */
425  void statusMessage(const QString &message);
426 
427  /**
428  * Emitted when the current tab has changed. Clients using the
429  * selection model from currentItemSelectionModel() should
430  * ask for it again, as it may be different now.
431  */
432  void currentTabChanged();
433 
434  void forceLostFocus();
435 
436 private:
437  void restoreHeaderSettings(int index, bool restoreSession);
438  void readConfig(bool restoreSession);
439 
440  bool eventFilter(QObject *obj, QEvent *event) override;
441 
442  class PanePrivate;
443  std::unique_ptr<PanePrivate> const d;
444 };
445 } // namespace MessageList
The Akonadi specific implementation of the Core::StorageModel.
Definition: storagemodel.h:35
PreSelectionMode
Pre-selection is the action of automatically selecting a message just after the folder has finished l...
ExistingSelectionBehaviour
This enum is used in the view message selection functions (for instance View::selectNextMessage())
This is the main MessageList panel for Akonadi applications.
Definition: pane.h:45
MessageTypeFilter
This enum is used in the view message selection functions (for instance View::nextMessageItem()).
QString message
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Fri Mar 24 2023 04:08:31 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.