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#include "tagmanager.h"
37
38#include <Akonadi/Monitor>
39#include <Akonadi/Tag>
40#include <Akonadi/TagAttribute>
41#include <Akonadi/TagFetchJob>
42#include <Akonadi/TagFetchScope>
43
44namespace MessageList
45{
46class MessageList::Widget::WidgetPrivate
47{
48public:
49 WidgetPrivate(Widget *owner)
50 : q(owner)
51 {
52 }
53
54 [[nodiscard]] Akonadi::Item::List selectionAsItems() const;
55 [[nodiscard]] Akonadi::Item itemForRow(int row) const;
56 [[nodiscard]] KMime::Message::Ptr messageForRow(int row) const;
57
58 Widget *const q;
59
60 int mLastSelectedMessage = -1;
61 KXMLGUIClient *mXmlGuiClient = nullptr;
62 QModelIndex mGroupHeaderItemIndex;
63};
64} // namespace MessageList
65
66using namespace MessageList;
67using namespace Akonadi;
68
70 : Core::Widget(parent)
71 , d(new WidgetPrivate(this))
72{
73 // Init it.
74 (void)Core::TagManager::self();
75 connect(Core::TagManager::self(), &Core::TagManager::tagsFetched, this, &MessageList::Widget::slotTagsFetched);
76}
77
78MessageList::Widget::~Widget() = default;
79
81{
82 d->mXmlGuiClient = xmlGuiClient;
83}
84
85bool MessageList::Widget::canAcceptDrag(const QDropEvent *e)
86{
87 if (e->source() == view()->viewport()) {
88 return false;
89 }
90
91 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
92 if (collections.size() != 1) {
93 return false; // no folder here or too many (in case we can't decide where the drop will end)
94 }
95
96 const Collection target = collections.first();
97
98 if ((target.rights() & Collection::CanCreateItem) == 0) {
99 return false; // no way to drag into
100 }
101
102 const QList<QUrl> urls = e->mimeData()->urls();
103 for (const QUrl &url : urls) {
104 const Collection collection = Collection::fromUrl(url);
105 if (collection.isValid()) { // You're not supposed to drop collections here
106 return false;
107 } else { // Yay, this is an item!
108 QUrlQuery query(url);
109 const QString type = query.queryItemValue(QStringLiteral("type"));
110 if (!target.contentMimeTypes().contains(type)) {
111 return false;
112 }
113 }
114 }
115
116 return true;
117}
118
120 MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
121 bool centerItem,
122 bool loop)
123{
124 return view()->selectNextMessageItem(messageTypeFilter, existingSelectionBehaviour, centerItem, loop);
125}
126
128 MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
129 bool centerItem,
130 bool loop)
131{
132 return view()->selectPreviousMessageItem(messageTypeFilter, existingSelectionBehaviour, centerItem, loop);
133}
134
135bool MessageList::Widget::focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
136{
137 return view()->focusNextMessageItem(messageTypeFilter, centerItem, loop);
138}
139
140bool MessageList::Widget::focusPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
141{
142 return view()->focusPreviousMessageItem(messageTypeFilter, centerItem, loop);
143}
144
146{
147 view()->selectFocusedMessageItem(centerItem);
148}
149
151{
152 return view()->selectFirstMessageItem(messageTypeFilter, centerItem);
153}
154
155bool MessageList::Widget::selectLastMessageItem(Core::MessageTypeFilter messageTypeFilter, bool centerItem)
156{
157 return view()->selectLastMessageItem(messageTypeFilter, centerItem);
158}
159
161{
162 view()->setAllGroupsExpanded(true);
163 view()->selectAll();
164}
165
167{
168 view()->setCurrentThreadExpanded(expand);
169}
170
172{
173 view()->setAllThreadsExpanded(expand);
174}
175
177{
178 view()->setAllGroupsExpanded(expand);
179}
180
181void MessageList::Widget::focusQuickSearch(const QString &selectedText)
182{
183 view()->focusQuickSearch(selectedText);
184}
185
186void MessageList::Widget::setQuickSearchClickMessage(const QString &msg)
187{
188 view()->setQuickSearchClickMessage(msg);
189}
190
191void MessageList::Widget::slotTagsFetched(const Akonadi::Tag::List &tags)
192{
193 populateStatusFilterCombo();
194 KConfigGroup conf(MessageList::MessageListSettings::self()->config(), QStringLiteral("MessageListView"));
195 const QString tagSelected = conf.readEntry(QStringLiteral("TagSelected"));
196 if (tagSelected.isEmpty()) {
197 setCurrentStatusFilterItem();
198 return;
199 }
200 const QStringList tagSelectedLst = tagSelected.split(QLatin1Char(','));
201
202 addMessageTagItem(QIcon::fromTheme(QStringLiteral("mail-flag")).pixmap(16, 16),
203 i18nc("Item in list of Akonadi tags, to show all e-mails", "All"),
204 QVariant());
205
206 QStringList tagFound;
207 for (const Akonadi::Tag &akonadiTag : tags) {
208 const QString tagUrl = akonadiTag.url().url();
209 if (tagSelectedLst.contains(tagUrl)) {
210 tagFound.append(akonadiTag.url().url());
211 const QString label = akonadiTag.name();
212 const QString id = tagUrl;
213 const auto attr = akonadiTag.attribute<Akonadi::TagAttribute>();
214 const QString iconName = attr ? attr->iconName() : QStringLiteral("mail-tagged");
215 addMessageTagItem(QIcon::fromTheme(iconName).pixmap(16, 16), label, QVariant(id));
216 }
217 }
218 conf.writeEntry(QStringLiteral("TagSelected"), tagFound);
219 conf.sync();
220
221 setCurrentStatusFilterItem();
222}
223
224void MessageList::Widget::viewMessageSelected(MessageList::Core::MessageItem *msg)
225{
226 int row = -1;
227 if (msg) {
228 row = msg->currentModelIndexRow();
229 }
230
231 if (!msg || !msg->isValid() || !storageModel()) {
232 d->mLastSelectedMessage = -1;
233 Q_EMIT messageSelected(Akonadi::Item());
234 return;
235 }
236
237 Q_ASSERT(row >= 0);
238
239 d->mLastSelectedMessage = row;
240
241 Q_EMIT messageSelected(d->itemForRow(row)); // this MAY be null
242}
243
244void MessageList::Widget::viewMessageActivated(MessageList::Core::MessageItem *msg)
245{
246 Q_ASSERT(msg); // must not be null
247 Q_ASSERT(storageModel());
248
249 if (!msg->isValid()) {
250 return;
251 }
252
253 int row = msg->currentModelIndexRow();
254 Q_ASSERT(row >= 0);
255
256 // The assert below may fail when quickly opening and closing a non-selected thread.
257 // This will actually activate the item without selecting it...
258 // Q_ASSERT( d->mLastSelectedMessage == row );
259
260 if (d->mLastSelectedMessage != row) {
261 // Very ugly. We are activating a non selected message.
262 // This is very likely a double click on the plus sign near a thread leader.
263 // Dealing with mLastSelectedMessage here would be expensive: it would involve releasing the last selected,
264 // emitting signals, handling recursion... ugly.
265 // We choose a very simple solution: double clicking on the plus sign near a thread leader does
266 // NOT activate the message (i.e open it in a toplevel window) if it isn't previously selected.
267 return;
268 }
269
270 Q_EMIT messageActivated(d->itemForRow(row)); // this MAY be null
271}
272
274{
275 Q_EMIT selectionChanged();
276 if (!currentMessageItem()) {
277 Q_EMIT messageSelected(Akonadi::Item());
278 }
279}
280
281void MessageList::Widget::viewMessageListContextPopupRequest(const QList<MessageList::Core::MessageItem *> &selectedItems, const QPoint &globalPos)
282{
283 Q_UNUSED(selectedItems)
284
285 if (!d->mXmlGuiClient) {
286 return;
287 }
288
289 QMenu *popup = static_cast<QMenu *>(d->mXmlGuiClient->factory()->container(QStringLiteral("akonadi_messagelist_contextmenu"), d->mXmlGuiClient));
290 if (popup) {
291 popup->exec(globalPos);
292 }
293}
294
295void MessageList::Widget::viewMessageStatusChangeRequest(MessageList::Core::MessageItem *msg, Akonadi::MessageStatus set, Akonadi::MessageStatus clear)
296{
297 Q_ASSERT(msg); // must not be null
298 Q_ASSERT(storageModel());
299
300 if (!msg->isValid()) {
301 return;
302 }
303
304 int row = msg->currentModelIndexRow();
305 Q_ASSERT(row >= 0);
306
307 Akonadi::Item item = d->itemForRow(row);
308 Q_ASSERT(item.isValid());
309
310 Q_EMIT messageStatusChangeRequest(item, set, clear);
311}
312
313void MessageList::Widget::viewGroupHeaderContextPopupRequest(MessageList::Core::GroupHeaderItem *ghi, const QPoint &globalPos)
314{
315 Q_UNUSED(ghi)
316
317 QMenu menu(this);
318
319 QAction *act = nullptr;
320
321 QModelIndex index = view()->model()->index(ghi, 0);
322 d->mGroupHeaderItemIndex = index;
323
324 if (view()->isExpanded(index)) {
325 act = menu.addAction(i18n("Collapse Group"));
326 connect(act, &QAction::triggered, this, &Widget::slotCollapseItem);
327 } else {
328 act = menu.addAction(i18n("Expand Group"));
329 connect(act, &QAction::triggered, this, &Widget::slotExpandItem);
330 }
331
332 menu.addSeparator();
333
334 act = menu.addAction(i18n("Expand All Groups"));
336
337 act = menu.addAction(i18n("Collapse All Groups"));
339
340 menu.addSeparator();
341 act = menu.addAction(i18n("Expand All Threads"));
342 connect(act, &QAction::triggered, view(), &Core::View::slotExpandAllThreads);
343 act = menu.addAction(i18n("Collapse All Threads"));
344 connect(act, &QAction::triggered, view(), &Core::View::slotCollapseAllThreads);
345
346 menu.exec(globalPos);
347}
348
349void MessageList::Widget::viewDragEnterEvent(QDragEnterEvent *e)
350{
351 if (!canAcceptDrag(e)) {
352 e->ignore();
353 return;
354 }
355
356 e->accept();
357}
358
359void MessageList::Widget::viewDragMoveEvent(QDragMoveEvent *e)
360{
361 if (!canAcceptDrag(e)) {
362 e->ignore();
363 return;
364 }
365
366 e->accept();
367}
368
369enum DragMode {
370 DragCopy,
371 DragMove,
372 DragCancel
373};
374
375void MessageList::Widget::viewDropEvent(QDropEvent *e)
376{
377 if (!canAcceptDrag(e)) {
378 e->ignore();
379 return;
380 }
381
382 const QList<QUrl> urls = e->mimeData()->urls();
383 if (urls.isEmpty()) {
384 qCWarning(MESSAGELIST_LOG) << "Could not decode drag data!";
385 e->ignore();
386 return;
387 }
388
389 e->accept();
390
391 int action;
392 if ((e->possibleActions() & Qt::MoveAction) == 0) { // We can't move anyway
393 action = DragCopy;
394 } else {
395 const auto keybstate = QApplication::keyboardModifiers();
396 if (keybstate & Qt::CTRL) {
397 action = DragCopy;
398 } else if (keybstate & Qt::SHIFT) {
399 action = DragMove;
400 } else {
401 QMenu menu;
402 QAction *moveAction =
403 menu.addAction(QIcon::fromTheme(QStringLiteral("edit-move"), QIcon::fromTheme(QStringLiteral("go-jump"))), i18n("&Move Here"));
404 QAction *copyAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("&Copy Here"));
405 menu.addSeparator();
406 menu.addAction(QIcon::fromTheme(QStringLiteral("dialog-cancel")), i18n("C&ancel"));
407
408 QAction *menuChoice = menu.exec(QCursor::pos());
409 if (menuChoice == moveAction) {
410 action = DragMove;
411 } else if (menuChoice == copyAction) {
412 action = DragCopy;
413 } else {
414 action = DragCancel;
415 }
416 }
417 }
418 if (action == DragCancel) {
419 return;
420 }
421
422 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
423 Collection target = collections.at(0);
425 items.reserve(urls.count());
426 for (const QUrl &url : std::as_const(urls)) {
427 items << Akonadi::Item::fromUrl(url);
428 }
429
430 if (action == DragCopy) {
431 new ItemCopyJob(items, target, this);
432 } else if (action == DragMove) {
433 new ItemMoveJob(items, target, this);
434 }
435}
436
438{
439 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
440
441 if (collections.isEmpty()) {
442 return; // no folder here
443 }
444
445 const QList<Core::MessageItem *> selection = view()->selectionAsMessageItemList();
446 if (selection.isEmpty()) {
447 return;
448 }
449
450 bool readOnly = false;
451
452 for (const Collection &c : std::as_const(collections)) {
453 // We won't be able to remove items from this collection
454 if ((c.rights() & Collection::CanDeleteItem) == 0) {
455 // So the drag will be read-only
456 readOnly = true;
457 break;
458 }
459 }
460
461 QList<QUrl> urls;
462 urls.reserve(selection.count());
463 for (Core::MessageItem *mi : selection) {
464 const Akonadi::Item i = d->itemForRow(mi->currentModelIndexRow());
466 QUrlQuery query(url);
467 query.addQueryItem(QStringLiteral("parent"), QString::number(mi->parentCollectionId()));
468 url.setQuery(query);
469 urls << url;
470 }
471
472 auto mimeData = new QMimeData;
473 mimeData->setUrls(urls);
474
475 auto drag = new QDrag(view()->viewport());
476 drag->setMimeData(mimeData);
477
478 // Set pixmap
479 QPixmap pixmap;
480 if (selection.size() == 1) {
481 pixmap = QIcon::fromTheme(QStringLiteral("mail-message")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize));
482 } else {
483 pixmap = QIcon::fromTheme(QStringLiteral("document-multiple")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize));
484 }
485
486 // Calculate hotspot (as in Konqueror)
487 if (!pixmap.isNull()) {
488 drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2));
489 drag->setPixmap(pixmap);
490 }
491
492 if (readOnly) {
493 drag->exec(Qt::CopyAction);
494 } else {
495 drag->exec(Qt::CopyAction | Qt::MoveAction);
496 }
497}
498
499Akonadi::Item::List MessageList::Widget::WidgetPrivate::selectionAsItems() const
500{
502 const QList<Core::MessageItem *> selection = q->view()->selectionAsMessageItemList();
503 res.reserve(selection.count());
504
505 for (Core::MessageItem *mi : std::as_const(selection)) {
506 Akonadi::Item i = itemForRow(mi->currentModelIndexRow());
507 Q_ASSERT(i.isValid());
508 res << i;
509 }
510
511 return res;
512}
513
514Akonadi::Item MessageList::Widget::WidgetPrivate::itemForRow(int row) const
515{
516 return static_cast<const MessageList::StorageModel *>(q->storageModel())->itemForRow(row);
517}
518
519KMime::Message::Ptr MessageList::Widget::WidgetPrivate::messageForRow(int row) const
520{
521 return static_cast<const MessageList::StorageModel *>(q->storageModel())->messageForRow(row);
522}
523
524Akonadi::Item MessageList::Widget::currentItem() const
525{
526 Core::MessageItem *mi = view()->currentMessageItem();
527
528 if (mi == nullptr) {
529 return {};
530 }
531
532 return d->itemForRow(mi->currentModelIndexRow());
533}
534
536{
537 Core::MessageItem *mi = view()->currentMessageItem();
538
539 if (mi == nullptr) {
540 return {};
541 }
542
543 return d->messageForRow(mi->currentModelIndexRow());
544}
545
546QList<KMime::Message::Ptr> MessageList::Widget::selectionAsMessageList(bool includeCollapsedChildren) const
547{
548 QList<KMime::Message::Ptr> lstMiPtr;
549 const QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
550 if (lstMi.isEmpty()) {
551 return lstMiPtr;
552 }
553 lstMiPtr.reserve(lstMi.count());
554 for (Core::MessageItem *it : std::as_const(lstMi)) {
555 lstMiPtr.append(d->messageForRow(it->currentModelIndexRow()));
556 }
557 return lstMiPtr;
558}
559
561{
562 Akonadi::Item::List lstMiPtr;
563 const QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
564 if (lstMi.isEmpty()) {
565 return lstMiPtr;
566 }
567 lstMiPtr.reserve(lstMi.count());
568 for (Core::MessageItem *it : std::as_const(lstMi)) {
569 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()));
570 }
571 return lstMiPtr;
572}
573
574QList<qlonglong> MessageList::Widget::selectionAsMessageItemListId(bool includeCollapsedChildren) const
575{
576 QList<qlonglong> lstMiPtr;
577 const QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
578 if (lstMi.isEmpty()) {
579 return lstMiPtr;
580 }
581 lstMiPtr.reserve(lstMi.count());
582 for (Core::MessageItem *it : std::as_const(lstMi)) {
583 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()).id());
584 }
585 return lstMiPtr;
586}
587
588QList<Akonadi::Item::Id> MessageList::Widget::selectionAsListMessageId(bool includeCollapsedChildren) const
589{
590 QList<qlonglong> lstMiPtr;
591 const QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
592 if (lstMi.isEmpty()) {
593 return lstMiPtr;
594 }
595 lstMiPtr.reserve(lstMi.count());
596 for (Core::MessageItem *it : std::as_const(lstMi)) {
597 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()).id());
598 }
599 return lstMiPtr;
600}
601
603{
604 Akonadi::Item::List lstMiPtr;
605 const QList<Core::MessageItem *> lstMi = view()->currentThreadAsMessageItemList();
606 if (lstMi.isEmpty()) {
607 return lstMiPtr;
608 }
609 lstMiPtr.reserve(lstMi.count());
610 for (Core::MessageItem *it : std::as_const(lstMi)) {
611 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()));
612 }
613 return lstMiPtr;
614}
615
616MessageList::Core::SearchMessageByButtons::SearchOptions MessageList::Widget::currentOptions() const
617{
618 return view()->currentOptions();
619}
620
621QList<Akonadi::MessageStatus> MessageList::Widget::currentFilterStatus() const
622{
623 return view()->currentFilterStatus();
624}
625
627{
629}
630
631QList<MessageList::Core::SearchLineCommand::SearchLineInfo> MessageList::Widget::searchLineCommands() const
632{
633 return view()->searchLineCommands();
634}
635
637{
638 return view()->isThreaded();
639}
640
642{
643 return view()->selectionEmpty();
644}
645
647 Akonadi::Item::List &selectedVisibleItems,
648 bool *allSelectedBelongToSameThread,
649 bool includeCollapsedChildren) const
650{
651 if (!storageModel()) {
652 return false;
653 }
654
655 selectedItems.clear();
656 selectedVisibleItems.clear();
657
658 const QList<Core::MessageItem *> selected = view()->selectionAsMessageItemList(includeCollapsedChildren);
659
660 Core::MessageItem *topmost = nullptr;
661
662 *allSelectedBelongToSameThread = true;
663
664 for (Core::MessageItem *it : std::as_const(selected)) {
665 const Akonadi::Item item = d->itemForRow(it->currentModelIndexRow());
666 selectedItems.append(item);
667 if (view()->isDisplayedWithParentsExpanded(it)) {
668 selectedVisibleItems.append(item);
669 }
670 if (topmost == nullptr) {
671 topmost = (*it).topmostMessage();
672 } else {
673 if (topmost != (*it).topmostMessage()) {
674 *allSelectedBelongToSameThread = false;
675 }
676 }
677 }
678 return true;
679}
680
681void MessageList::Widget::deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
682{
684}
685
686void MessageList::Widget::markMessageItemsAsAboutToBeRemoved(MessageList::Core::MessageItemSetReference ref, bool bMark)
687{
688 QList<Core::MessageItem *> lstPersistent = view()->persistentSetCurrentMessageItemList(ref);
689 if (!lstPersistent.isEmpty()) {
690 view()->markMessageItemsAsAboutToBeRemoved(lstPersistent, bMark);
691 }
692}
693
694Akonadi::Item::List MessageList::Widget::itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
695{
696 Akonadi::Item::List lstItem;
697 const QList<Core::MessageItem *> refList = view()->persistentSetCurrentMessageItemList(ref);
698 if (!refList.isEmpty()) {
699 lstItem.reserve(refList.count());
700 for (Core::MessageItem *it : std::as_const(refList)) {
701 lstItem.append(d->itemForRow(it->currentModelIndexRow()));
702 }
703 }
704 return lstItem;
705}
706
707MessageList::Core::MessageItemSetReference MessageList::Widget::selectionAsPersistentSet(bool includeCollapsedChildren) const
708{
709 QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
710 if (lstMi.isEmpty()) {
711 return -1;
712 }
713 return view()->createPersistentSet(lstMi);
714}
715
716MessageList::Core::MessageItemSetReference MessageList::Widget::currentThreadAsPersistentSet() const
717{
718 QList<Core::MessageItem *> lstMi = view()->currentThreadAsMessageItemList();
719 if (lstMi.isEmpty()) {
720 return -1;
721 }
722 return view()->createPersistentSet(lstMi);
723}
724
725Akonadi::Collection MessageList::Widget::currentCollection() const
726{
727 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
728 if (collections.size() != 1) {
729 return {}; // no folder here or too many (in case we can't decide where the drop will end)
730 }
731 return collections.first();
732}
733
734void MessageList::Widget::slotCollapseItem()
735{
736 view()->setCollapseItem(d->mGroupHeaderItemIndex);
737}
738
739void MessageList::Widget::slotExpandItem()
740{
741 view()->setExpandItem(d->mGroupHeaderItemIndex);
742}
743
744#include "moc_widget.cpp"
QStringList contentMimeTypes() const
bool isValid() const
Rights rights() const
static Collection fromUrl(const QUrl &url)
QList< Collection > List
QUrl url(UrlType type=UrlShort) const
bool isValid() const
QList< Item > List
static Item fromUrl(const QUrl &url)
QSharedPointer< Message > Ptr
The MessageItem class.
Definition messageitem.h:36
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:887
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:1645
QString currentFilterSearchString() const
Returns the search term in the current quicksearch field.
Definition view.cpp:2522
MessageItemSetReference createPersistentSet(const QList< MessageItem * > &items)
Creates a persistent set for the specified MessageItems and returns its reference.
Definition view.cpp:1630
MessageItem * currentMessageItem(bool selectIfNeeded=true) const
Returns the current MessageItem (that is bound to current StorageModel).
Definition view.cpp:849
bool selectionEmpty() const
Fast function that determines if the selection is empty.
Definition view.cpp:882
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:1635
void deletePersistentSet(MessageItemSetReference ref)
Deletes the persistent set pointed by the specified reference.
Definition view.cpp:1640
QList< Akonadi::MessageStatus > currentFilterStatus() const
Returns the Akonadi::MessageStatus in the current quicksearch field.
Definition view.cpp:2512
QList< MessageItem * > currentThreadAsMessageItemList() const
Returns the MessageItems bound to the current StorageModel that are part of the current thread.
Definition view.cpp:930
void slotExpandAllGroups()
Expands all the group headers (if present in the current Aggregation)
Definition view.cpp:2492
void slotCollapseAllGroups()
Collapses all the group headers (if present in the current Aggregation)
Definition view.cpp:2487
bool isThreaded() const
Returns true if the current Aggregation is threaded, false otherwise (or if there is no current Aggre...
Definition view.cpp:1868
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::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 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)
The implementation independent part of the MessageList library.
Definition aggregation.h:22
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()).
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()
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
void clear()
qsizetype count() const const
T & first()
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
QAction * addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
QAction * addSeparator()
QAction * exec()
QList< QUrl > urls() const const
int height() const const
bool isNull() const const
int width() const const
bool isEmpty() const const
QString number(double n, char format, int precision)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
PM_SmallIconSize
MoveAction
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setQuery(const QString &query, ParsingMode mode)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Mar 28 2025 11:49:16 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.