Messagelib

widget.cpp
1/*
2 SPDX-FileCopyrightText: 2009 Kevin Ottens <ervin@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "widget.h"
8
9#include <Akonadi/Collection>
10#include <Akonadi/ItemCopyJob>
11#include <Akonadi/ItemMoveJob>
12
13#include "core/messageitem.h"
14#include "core/view.h"
15#include "storagemodel.h"
16#include <messagelistsettings.h>
17
18#include <QAction>
19#include <QApplication>
20#include <QDrag>
21#include <QDragMoveEvent>
22#include <QDropEvent>
23#include <QMimeData>
24#include <QUrlQuery>
25
26#include "messagelist_debug.h"
27#include <KJob>
28#include <KLocalizedString>
29#include <KXMLGUIClient>
30#include <KXMLGUIFactory>
31#include <QIcon>
32#include <QMenu>
33#include <QUrl>
34
35#include "core/groupheaderitem.h"
36
37#include <Akonadi/Monitor>
38#include <Akonadi/Tag>
39#include <Akonadi/TagAttribute>
40#include <Akonadi/TagFetchJob>
41#include <Akonadi/TagFetchScope>
42
43namespace MessageList
44{
45class MessageList::Widget::WidgetPrivate
46{
47public:
48 WidgetPrivate(Widget *owner)
49 : q(owner)
50 {
51 }
52
53 [[nodiscard]] Akonadi::Item::List selectionAsItems() const;
54 [[nodiscard]] Akonadi::Item itemForRow(int row) const;
55 [[nodiscard]] KMime::Message::Ptr messageForRow(int row) const;
56
57 Widget *const q;
58
59 int mLastSelectedMessage = -1;
60 KXMLGUIClient *mXmlGuiClient = nullptr;
61 QModelIndex mGroupHeaderItemIndex;
62 Akonadi::Monitor *mMonitor = nullptr;
63};
64} // namespace MessageList
65
66using namespace MessageList;
67using namespace Akonadi;
68
70 : Core::Widget(parent)
71 , d(new WidgetPrivate(this))
72{
73 populateStatusFilterCombo();
74
75 d->mMonitor = new Akonadi::Monitor(this);
76 d->mMonitor->setObjectName(QLatin1StringView("MessageListTagMonitor"));
77 d->mMonitor->setTypeMonitored(Akonadi::Monitor::Tags);
78 connect(d->mMonitor, &Akonadi::Monitor::tagAdded, this, &Widget::populateStatusFilterCombo);
79 connect(d->mMonitor, &Akonadi::Monitor::tagRemoved, this, &Widget::populateStatusFilterCombo);
80 connect(d->mMonitor, &Akonadi::Monitor::tagChanged, this, &Widget::populateStatusFilterCombo);
81}
82
83MessageList::Widget::~Widget() = default;
84
86{
87 d->mXmlGuiClient = xmlGuiClient;
88}
89
91{
92 if (e->source() == view()->viewport()) {
93 return false;
94 }
95
96 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
97 if (collections.size() != 1) {
98 return false; // no folder here or too many (in case we can't decide where the drop will end)
99 }
100
101 const Collection target = collections.first();
102
103 if ((target.rights() & Collection::CanCreateItem) == 0) {
104 return false; // no way to drag into
105 }
106
107 const QList<QUrl> urls = e->mimeData()->urls();
108 for (const QUrl &url : urls) {
109 const Collection collection = Collection::fromUrl(url);
110 if (collection.isValid()) { // You're not supposed to drop collections here
111 return false;
112 } else { // Yay, this is an item!
113 QUrlQuery query(url);
114 const QString type = query.queryItemValue(QStringLiteral("type"));
115 if (!target.contentMimeTypes().contains(type)) {
116 return false;
117 }
118 }
119 }
120
121 return true;
122}
123
125 MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
126 bool centerItem,
127 bool loop)
128{
129 return view()->selectNextMessageItem(messageTypeFilter, existingSelectionBehaviour, centerItem, loop);
130}
131
133 MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
134 bool centerItem,
135 bool loop)
136{
137 return view()->selectPreviousMessageItem(messageTypeFilter, existingSelectionBehaviour, centerItem, loop);
138}
139
140bool MessageList::Widget::focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
141{
142 return view()->focusNextMessageItem(messageTypeFilter, centerItem, loop);
143}
144
145bool MessageList::Widget::focusPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
146{
147 return view()->focusPreviousMessageItem(messageTypeFilter, centerItem, loop);
148}
149
151{
152 view()->selectFocusedMessageItem(centerItem);
153}
154
156{
157 return view()->selectFirstMessageItem(messageTypeFilter, centerItem);
158}
159
160bool MessageList::Widget::selectLastMessageItem(Core::MessageTypeFilter messageTypeFilter, bool centerItem)
161{
162 return view()->selectLastMessageItem(messageTypeFilter, centerItem);
163}
164
166{
167 view()->setAllGroupsExpanded(true);
168 view()->selectAll();
169}
170
172{
173 view()->setCurrentThreadExpanded(expand);
174}
175
177{
178 view()->setAllThreadsExpanded(expand);
179}
180
182{
183 view()->setAllGroupsExpanded(expand);
184}
185
186void MessageList::Widget::focusQuickSearch(const QString &selectedText)
187{
188 view()->focusQuickSearch(selectedText);
189}
190
191void MessageList::Widget::setQuickSearchClickMessage(const QString &msg)
192{
193 view()->setQuickSearchClickMessage(msg);
194}
195
197{
198 auto fetchJob = new Akonadi::TagFetchJob(this);
199 fetchJob->fetchScope().fetchAttribute<Akonadi::TagAttribute>();
200 connect(fetchJob, &Akonadi::TagFetchJob::result, this, &Widget::slotTagsFetched);
201}
202
203void MessageList::Widget::slotTagsFetched(KJob *job)
204{
205 if (job->error()) {
206 qCWarning(MESSAGELIST_LOG) << "Failed to load tags " << job->errorString();
207 return;
208 }
209 auto fetchJob = static_cast<Akonadi::TagFetchJob *>(job);
210
211 KConfigGroup conf(MessageList::MessageListSettings::self()->config(), QStringLiteral("MessageListView"));
212 const QString tagSelected = conf.readEntry(QStringLiteral("TagSelected"));
213 if (tagSelected.isEmpty()) {
214 setCurrentStatusFilterItem();
215 return;
216 }
217 const QStringList tagSelectedLst = tagSelected.split(QLatin1Char(','));
218
219 addMessageTagItem(QIcon::fromTheme(QStringLiteral("mail-flag")).pixmap(16, 16),
220 i18nc("Item in list of Akonadi tags, to show all e-mails", "All"),
221 QString());
222
223 QStringList tagFound;
224 const auto tags{fetchJob->tags()};
225 for (const Akonadi::Tag &akonadiTag : tags) {
226 if (tagSelectedLst.contains(akonadiTag.url().url())) {
227 tagFound.append(akonadiTag.url().url());
228 QString iconName = QStringLiteral("mail-tagged");
229 const QString label = akonadiTag.name();
230 const QString id = akonadiTag.url().url();
231 const auto attr = akonadiTag.attribute<Akonadi::TagAttribute>();
232 if (attr) {
233 iconName = attr->iconName();
234 }
235 addMessageTagItem(QIcon::fromTheme(iconName).pixmap(16, 16), label, QVariant(id));
236 }
237 }
238 conf.writeEntry(QStringLiteral("TagSelected"), tagFound);
239 conf.sync();
240
241 setCurrentStatusFilterItem();
242}
243
245{
246 int row = -1;
247 if (msg) {
248 row = msg->currentModelIndexRow();
249 }
250
251 if (!msg || !msg->isValid() || !storageModel()) {
252 d->mLastSelectedMessage = -1;
253 Q_EMIT messageSelected(Akonadi::Item());
254 return;
255 }
256
257 Q_ASSERT(row >= 0);
258
259 d->mLastSelectedMessage = row;
260
261 Q_EMIT messageSelected(d->itemForRow(row)); // this MAY be null
262}
263
265{
266 Q_ASSERT(msg); // must not be null
267 Q_ASSERT(storageModel());
268
269 if (!msg->isValid()) {
270 return;
271 }
272
273 int row = msg->currentModelIndexRow();
274 Q_ASSERT(row >= 0);
275
276 // The assert below may fail when quickly opening and closing a non-selected thread.
277 // This will actually activate the item without selecting it...
278 // Q_ASSERT( d->mLastSelectedMessage == row );
279
280 if (d->mLastSelectedMessage != row) {
281 // Very ugly. We are activating a non selected message.
282 // This is very likely a double click on the plus sign near a thread leader.
283 // Dealing with mLastSelectedMessage here would be expensive: it would involve releasing the last selected,
284 // emitting signals, handling recursion... ugly.
285 // We choose a very simple solution: double clicking on the plus sign near a thread leader does
286 // NOT activate the message (i.e open it in a toplevel window) if it isn't previously selected.
287 return;
288 }
289
290 Q_EMIT messageActivated(d->itemForRow(row)); // this MAY be null
291}
292
294{
295 Q_EMIT selectionChanged();
296 if (!currentMessageItem()) {
297 Q_EMIT messageSelected(Akonadi::Item());
298 }
299}
300
302{
303 Q_UNUSED(selectedItems)
304
305 if (!d->mXmlGuiClient) {
306 return;
307 }
308
309 QMenu *popup = static_cast<QMenu *>(d->mXmlGuiClient->factory()->container(QStringLiteral("akonadi_messagelist_contextmenu"), d->mXmlGuiClient));
310 if (popup) {
311 popup->exec(globalPos);
312 }
313}
314
316{
317 Q_ASSERT(msg); // must not be null
318 Q_ASSERT(storageModel());
319
320 if (!msg->isValid()) {
321 return;
322 }
323
324 int row = msg->currentModelIndexRow();
325 Q_ASSERT(row >= 0);
326
327 Akonadi::Item item = d->itemForRow(row);
328 Q_ASSERT(item.isValid());
329
330 Q_EMIT messageStatusChangeRequest(item, set, clear);
331}
332
333void MessageList::Widget::viewGroupHeaderContextPopupRequest(MessageList::Core::GroupHeaderItem *ghi, const QPoint &globalPos)
334{
335 Q_UNUSED(ghi)
336
337 QMenu menu(this);
338
339 QAction *act = nullptr;
340
341 QModelIndex index = view()->model()->index(ghi, 0);
342 d->mGroupHeaderItemIndex = index;
343
344 if (view()->isExpanded(index)) {
345 act = menu.addAction(i18n("Collapse Group"));
346 connect(act, &QAction::triggered, this, &Widget::slotCollapseItem);
347 } else {
348 act = menu.addAction(i18n("Expand Group"));
349 connect(act, &QAction::triggered, this, &Widget::slotExpandItem);
350 }
351
352 menu.addSeparator();
353
354 act = menu.addAction(i18n("Expand All Groups"));
356
357 act = menu.addAction(i18n("Collapse All Groups"));
359
360 menu.addSeparator();
361 act = menu.addAction(i18n("Expand All Threads"));
362 connect(act, &QAction::triggered, view(), &Core::View::slotExpandAllThreads);
363 act = menu.addAction(i18n("Collapse All Threads"));
364 connect(act, &QAction::triggered, view(), &Core::View::slotCollapseAllThreads);
365
366 menu.exec(globalPos);
367}
368
370{
371 if (!canAcceptDrag(e)) {
372 e->ignore();
373 return;
374 }
375
376 e->accept();
377}
378
380{
381 if (!canAcceptDrag(e)) {
382 e->ignore();
383 return;
384 }
385
386 e->accept();
387}
388
389enum DragMode { DragCopy, DragMove, DragCancel };
390
392{
393 if (!canAcceptDrag(e)) {
394 e->ignore();
395 return;
396 }
397
398 const QList<QUrl> urls = e->mimeData()->urls();
399 if (urls.isEmpty()) {
400 qCWarning(MESSAGELIST_LOG) << "Could not decode drag data!";
401 e->ignore();
402 return;
403 }
404
405 e->accept();
406
407 int action;
408 if ((e->possibleActions() & Qt::MoveAction) == 0) { // We can't move anyway
409 action = DragCopy;
410 } else {
411 const auto keybstate = QApplication::keyboardModifiers();
412 if (keybstate & Qt::CTRL) {
413 action = DragCopy;
414 } else if (keybstate & Qt::SHIFT) {
415 action = DragMove;
416 } else {
417 QMenu menu;
418 QAction *moveAction =
419 menu.addAction(QIcon::fromTheme(QStringLiteral("edit-move"), QIcon::fromTheme(QStringLiteral("go-jump"))), i18n("&Move Here"));
420 QAction *copyAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("&Copy Here"));
421 menu.addSeparator();
422 menu.addAction(QIcon::fromTheme(QStringLiteral("dialog-cancel")), i18n("C&ancel"));
423
424 QAction *menuChoice = menu.exec(QCursor::pos());
425 if (menuChoice == moveAction) {
426 action = DragMove;
427 } else if (menuChoice == copyAction) {
428 action = DragCopy;
429 } else {
430 action = DragCancel;
431 }
432 }
433 }
434 if (action == DragCancel) {
435 return;
436 }
437
438 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
439 Collection target = collections.at(0);
441 items.reserve(urls.count());
442 for (const QUrl &url : std::as_const(urls)) {
443 items << Akonadi::Item::fromUrl(url);
444 }
445
446 if (action == DragCopy) {
447 new ItemCopyJob(items, target, this);
448 } else if (action == DragMove) {
449 new ItemMoveJob(items, target, this);
450 }
451}
452
454{
455 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
456
457 if (collections.isEmpty()) {
458 return; // no folder here
459 }
460
461 const QList<Core::MessageItem *> selection = view()->selectionAsMessageItemList();
462 if (selection.isEmpty()) {
463 return;
464 }
465
466 bool readOnly = false;
467
468 for (const Collection &c : std::as_const(collections)) {
469 // We won't be able to remove items from this collection
470 if ((c.rights() & Collection::CanDeleteItem) == 0) {
471 // So the drag will be read-only
472 readOnly = true;
473 break;
474 }
475 }
476
477 QList<QUrl> urls;
478 urls.reserve(selection.count());
479 for (Core::MessageItem *mi : selection) {
480 const Akonadi::Item i = d->itemForRow(mi->currentModelIndexRow());
482 QUrlQuery query(url);
483 query.addQueryItem(QStringLiteral("parent"), QString::number(mi->parentCollectionId()));
484 url.setQuery(query);
485 urls << url;
486 }
487
488 auto mimeData = new QMimeData;
489 mimeData->setUrls(urls);
490
491 auto drag = new QDrag(view()->viewport());
492 drag->setMimeData(mimeData);
493
494 // Set pixmap
495 QPixmap pixmap;
496 if (selection.size() == 1) {
497 pixmap = QIcon::fromTheme(QStringLiteral("mail-message")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize));
498 } else {
499 pixmap = QIcon::fromTheme(QStringLiteral("document-multiple")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize));
500 }
501
502 // Calculate hotspot (as in Konqueror)
503 if (!pixmap.isNull()) {
504 drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2));
505 drag->setPixmap(pixmap);
506 }
507
508 if (readOnly) {
509 drag->exec(Qt::CopyAction);
510 } else {
511 drag->exec(Qt::CopyAction | Qt::MoveAction);
512 }
513}
514
515Akonadi::Item::List MessageList::Widget::WidgetPrivate::selectionAsItems() const
516{
518 const QList<Core::MessageItem *> selection = q->view()->selectionAsMessageItemList();
519 res.reserve(selection.count());
520
521 for (Core::MessageItem *mi : std::as_const(selection)) {
522 Akonadi::Item i = itemForRow(mi->currentModelIndexRow());
523 Q_ASSERT(i.isValid());
524 res << i;
525 }
526
527 return res;
528}
529
530Akonadi::Item MessageList::Widget::WidgetPrivate::itemForRow(int row) const
531{
532 return static_cast<const MessageList::StorageModel *>(q->storageModel())->itemForRow(row);
533}
534
535KMime::Message::Ptr MessageList::Widget::WidgetPrivate::messageForRow(int row) const
536{
537 return static_cast<const MessageList::StorageModel *>(q->storageModel())->messageForRow(row);
538}
539
541{
543
544 if (mi == nullptr) {
545 return {};
546 }
547
548 return d->itemForRow(mi->currentModelIndexRow());
549}
550
552{
554
555 if (mi == nullptr) {
556 return {};
557 }
558
559 return d->messageForRow(mi->currentModelIndexRow());
560}
561
563{
566 if (lstMi.isEmpty()) {
567 return lstMiPtr;
568 }
569 lstMiPtr.reserve(lstMi.count());
571 lstMiPtr.append(d->messageForRow(it->currentModelIndexRow()));
572 }
573 return lstMiPtr;
574}
575
577{
580 if (lstMi.isEmpty()) {
581 return lstMiPtr;
582 }
583 lstMiPtr.reserve(lstMi.count());
585 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()));
586 }
587 return lstMiPtr;
588}
589
591{
594 if (lstMi.isEmpty()) {
595 return lstMiPtr;
596 }
597 lstMiPtr.reserve(lstMi.count());
599 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()).id());
600 }
601 return lstMiPtr;
602}
603
604QList<Akonadi::Item::Id> MessageList::Widget::selectionAsListMessageId(bool includeCollapsedChildren) const
605{
608 if (lstMi.isEmpty()) {
609 return lstMiPtr;
610 }
611 lstMiPtr.reserve(lstMi.count());
613 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()).id());
614 }
615 return lstMiPtr;
616}
617
619{
622 if (lstMi.isEmpty()) {
623 return lstMiPtr;
624 }
625 lstMiPtr.reserve(lstMi.count());
627 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()));
628 }
629 return lstMiPtr;
630}
631
632MessageList::Core::QuickSearchLine::SearchOptions MessageList::Widget::currentOptions() const
633{
634 return view()->currentOptions();
635}
636
638{
639 return view()->currentFilterStatus();
640}
641
643{
645}
646
648{
649 return view()->isThreaded();
650}
651
653{
654 return view()->selectionEmpty();
655}
656
660 bool includeCollapsedChildren) const
661{
662 if (!storageModel()) {
663 return false;
664 }
665
666 selectedItems.clear();
667 selectedVisibleItems.clear();
668
670
671 Core::MessageItem *topmost = nullptr;
672
674
675 for (Core::MessageItem *it : std::as_const(selected)) {
676 const Akonadi::Item item = d->itemForRow(it->currentModelIndexRow());
677 selectedItems.append(item);
678 if (view()->isDisplayedWithParentsExpanded(it)) {
679 selectedVisibleItems.append(item);
680 }
681 if (topmost == nullptr) {
682 topmost = (*it).topmostMessage();
683 } else {
684 if (topmost != (*it).topmostMessage()) {
686 }
687 }
688 }
689 return true;
690}
691
692void MessageList::Widget::deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
693{
695}
696
697void MessageList::Widget::markMessageItemsAsAboutToBeRemoved(MessageList::Core::MessageItemSetReference ref, bool bMark)
698{
700 if (!lstPersistent.isEmpty()) {
702 }
703}
704
705Akonadi::Item::List MessageList::Widget::itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
706{
709 if (!refList.isEmpty()) {
710 lstItem.reserve(refList.count());
712 lstItem.append(d->itemForRow(it->currentModelIndexRow()));
713 }
714 }
715 return lstItem;
716}
717
718MessageList::Core::MessageItemSetReference MessageList::Widget::selectionAsPersistentSet(bool includeCollapsedChildren) const
719{
721 if (lstMi.isEmpty()) {
722 return -1;
723 }
724 return view()->createPersistentSet(lstMi);
725}
726
727MessageList::Core::MessageItemSetReference MessageList::Widget::currentThreadAsPersistentSet() const
728{
730 if (lstMi.isEmpty()) {
731 return -1;
732 }
733 return view()->createPersistentSet(lstMi);
734}
735
736Akonadi::Collection MessageList::Widget::currentCollection() const
737{
738 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
739 if (collections.size() != 1) {
740 return {}; // no folder here or too many (in case we can't decide where the drop will end)
741 }
742 return collections.first();
743}
744
745void MessageList::Widget::slotCollapseItem()
746{
747 view()->setCollapseItem(d->mGroupHeaderItemIndex);
748}
749
750void MessageList::Widget::slotExpandItem()
751{
752 view()->setExpandItem(d->mGroupHeaderItemIndex);
753}
754
755#include "moc_widget.cpp"
QStringList contentMimeTypes() const
bool isValid() const
Rights rights() const
static Collection fromUrl(const QUrl &url)
QUrl url(UrlType type=UrlShort) const
bool isValid() const
static Item fromUrl(const QUrl &url)
void tagRemoved(const Akonadi::Tag &tag)
void tagChanged(const Akonadi::Tag &tag)
void tagAdded(const Akonadi::Tag &tag)
virtual QString errorString() const
int error() const
void result(KJob *job)
The MessageItem class.
Definition messageitem.h:35
bool isValid() const
Returns true if this ModelInvariantIndex is valid, that is, it has been attached to a ModelInvariantR...
int currentModelIndexRow()
Returns the current model index row for this invariant index.
QList< MessageItem * > selectionAsMessageItemList(bool includeCollapsedChildren=true) const
Returns the currently selected MessageItems (bound to current StorageModel).
Definition view.cpp:889
void markMessageItemsAsAboutToBeRemoved(const QList< MessageItem * > &items, bool bMark)
If bMark is true this function marks the messages as "about to be removed" so they appear dimmer and ...
Definition view.cpp:1647
QString currentFilterSearchString() const
Returns the search term in the current quicksearch field.
Definition view.cpp:2532
MessageItemSetReference createPersistentSet(const QList< MessageItem * > &items)
Creates a persistent set for the specified MessageItems and returns its reference.
Definition view.cpp:1632
MessageItem * currentMessageItem(bool selectIfNeeded=true) const
Returns the current MessageItem (that is bound to current StorageModel).
Definition view.cpp:851
bool selectionEmpty() const
Fast function that determines if the selection is empty.
Definition view.cpp:884
QList< MessageItem * > persistentSetCurrentMessageItemList(MessageItemSetReference ref)
Returns the list of MessageItems that are still existing in the set pointed by the specified referenc...
Definition view.cpp:1637
void deletePersistentSet(MessageItemSetReference ref)
Deletes the persistent set pointed by the specified reference.
Definition view.cpp:1642
QList< Akonadi::MessageStatus > currentFilterStatus() const
Returns the Akonadi::MessageStatus in the current quicksearch field.
Definition view.cpp:2522
QList< MessageItem * > currentThreadAsMessageItemList() const
Returns the MessageItems bound to the current StorageModel that are part of the current thread.
Definition view.cpp:932
void slotExpandAllGroups()
Expands all the group headers (if present in the current Aggregation)
Definition view.cpp:2502
void slotCollapseAllGroups()
Collapses all the group headers (if present in the current Aggregation)
Definition view.cpp:2497
bool isThreaded() const
Returns true if the current Aggregation is threaded, false otherwise (or if there is no current Aggre...
Definition view.cpp:1870
View * view() const
Returns the View attached to this Widget.
StorageModel * storageModel() const
Returns the StorageModel currently set.
The Akonadi specific implementation of the Core::StorageModel.
The Akonadi specific implementation of the Core::Widget.
Definition widget.h:33
void setAllThreadsExpanded(bool expand)
If expand is true then it expands all the threads, otherwise collapses them.
QString currentFilterSearchString() const
Returns the search term in the current quicksearch field.
bool selectionEmpty() const
Fast function that determines if the selection is empty.
void selectAll()
Selects all the items in the current folder.
bool selectLastMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem)
Selects the last message item in the view that matches the specified Core::MessageTypeFilter.
void viewDropEvent(QDropEvent *e) override
Reimplemented from MessageList::Core::Widget.
MessageList::Core::MessageItemSetReference currentThreadAsPersistentSet() const
Return a persistent set from current thread.
QList< qlonglong > selectionAsMessageItemListId(bool includeCollapsedChildren) const
Returns the currently selected Items id (bound to current StorageModel).
bool focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
Focuses the next message item in the view without actually selecting it.
void deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
Deletes the persistent set pointed by the specified reference.
bool canAcceptDrag(const QDropEvent *e)
Returns true if this drag can be accepted by the underlying view.
bool focusPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
Focuses the previous message item in the view without actually selecting it.
QList< Akonadi::MessageStatus > currentFilterStatus() const
Returns the Akonadi::MessageStatus in the current quicksearch field.
MessageList::Core::MessageItemSetReference selectionAsPersistentSet(bool includeCollapsedChildren=true) const
Return a persistent set from current selection.
bool getSelectionStats(Akonadi::Item::List &selectedSernums, Akonadi::Item::List &selectedVisibleSernums, bool *allSelectedBelongToSameThread, bool includeCollapsedChildren=true) const
Fills the lists of the selected message serial numbers and of the selected+visible ones.
void selectFocusedMessageItem(bool centerItem)
Selects the currently focused message item.
void viewGroupHeaderContextPopupRequest(MessageList::Core::GroupHeaderItem *group, const QPoint &globalPos) override
Reimplemented from MessageList::Core::Widget.
void focusQuickSearch(const QString &selectedText)
Sets the focus on the quick search line of the currently active tab.
Akonadi::Item::List selectionAsMessageItemList(bool includeCollapsedChildren=true) const
Returns the currently selected Items (bound to current StorageModel).
void viewDragMoveEvent(QDragMoveEvent *e) override
Reimplemented from MessageList::Core::Widget.
void setCurrentThreadExpanded(bool expand)
If expand is true then it expands the current thread, otherwise collapses it.
Akonadi::Item currentItem() const
Returns the current message for the list as Akonadi::Item.
void viewStartDragRequest() override
Reimplemented from MessageList::Core::Widget.
bool isThreaded() const
Returns true if the current Aggregation is threaded, false otherwise (or if there is no current Aggre...
void markMessageItemsAsAboutToBeRemoved(MessageList::Core::MessageItemSetReference ref, bool bMark)
If bMark is true this function marks the messages as "about to be removed" so they appear dimmer and ...
bool selectNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, bool loop)
Selects the next message item in the view.
void viewMessageSelected(MessageList::Core::MessageItem *msg) override
Reimplemented from MessageList::Core::Widget.
void setXmlGuiClient(KXMLGUIClient *xmlGuiClient)
Sets the XML GUI client which the view is used in.
void viewMessageStatusChangeRequest(MessageList::Core::MessageItem *msg, Akonadi::MessageStatus set, Akonadi::MessageStatus clear) override
Reimplemented from MessageList::Core::Widget.
Akonadi::Item::List itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
Return Akonadi::Item from messageItemReference.
KMime::Message::Ptr currentMessage() const
Returns the current message for the list as KMime::Message::Ptr.
void fillMessageTagCombo() override
Reimplemented from MessageList::Core::Widget.
void viewDragEnterEvent(QDragEnterEvent *e) override
Reimplemented from MessageList::Core::Widget.
void viewSelectionChanged() override
Reimplemented from MessageList::Core::Widget.
void setAllGroupsExpanded(bool expand)
If expand is true then it expands all the groups (only the toplevel group item: inner threads are NOT...
QList< KMime::Message::Ptr > selectionAsMessageList(bool includeCollapsedChildren=true) const
Returns the currently selected KMime::Message::Ptr (bound to current StorageModel).
bool selectFirstMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem)
Selects the first message item in the view that matches the specified Core::MessageTypeFilter.
void viewMessageListContextPopupRequest(const QList< Core::MessageItem * > &selectedItems, const QPoint &globalPos) override
Reimplemented from MessageList::Core::Widget.
Akonadi::Item::List currentThreadAsMessageList() const
Returns the Akonadi::Item bound to the current StorageModel that are part of the current thread.
Widget(QWidget *parent)
Create a new message list widget.
void viewMessageActivated(MessageList::Core::MessageItem *msg) override
Reimplemented from MessageList::Core::Widget.
bool selectPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, bool loop)
Selects the previous message item in the view.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
QString label(StandardShortcut id)
ExistingSelectionBehaviour
This enum is used in the view message selection functions (for instance View::selectNextMessage())
MessageTypeFilter
This enum is used in the view message selection functions (for instance View::nextMessageItem()).
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
void triggered(bool checked)
QPoint pos()
const QMimeData * mimeData() const const
Qt::DropActions possibleActions() const const
QObject * source() const const
void accept()
void ignore()
Qt::KeyboardModifiers keyboardModifiers()
QIcon fromTheme(const QString &name)
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) const const
void append(const T &value)
const T & at(int i) const const
void clear()
int count(const T &value) const const
T & first()
bool isEmpty() const const
void reserve(int alloc)
int size() const const
QAction * addAction(const QString &text)
QAction * addSeparator()
QAction * exec()
void setUrls(const QList< QUrl > &urls)
QList< QUrl > urls() const const
const QAbstractItemModel * model() const const
T qobject_cast(QObject *object)
int height() const const
bool isNull() const const
int width() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString number(int n, int base)
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
PM_SmallIconSize
MoveAction
void setQuery(const QString &query, QUrl::ParsingMode mode)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:37:31 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.