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 {
390 DragCopy,
391 DragMove,
392 DragCancel
393};
394
396{
397 if (!canAcceptDrag(e)) {
398 e->ignore();
399 return;
400 }
401
402 const QList<QUrl> urls = e->mimeData()->urls();
403 if (urls.isEmpty()) {
404 qCWarning(MESSAGELIST_LOG) << "Could not decode drag data!";
405 e->ignore();
406 return;
407 }
408
409 e->accept();
410
411 int action;
412 if ((e->possibleActions() & Qt::MoveAction) == 0) { // We can't move anyway
413 action = DragCopy;
414 } else {
415 const auto keybstate = QApplication::keyboardModifiers();
416 if (keybstate & Qt::CTRL) {
417 action = DragCopy;
418 } else if (keybstate & Qt::SHIFT) {
419 action = DragMove;
420 } else {
421 QMenu menu;
422 QAction *moveAction =
423 menu.addAction(QIcon::fromTheme(QStringLiteral("edit-move"), QIcon::fromTheme(QStringLiteral("go-jump"))), i18n("&Move Here"));
424 QAction *copyAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("&Copy Here"));
425 menu.addSeparator();
426 menu.addAction(QIcon::fromTheme(QStringLiteral("dialog-cancel")), i18n("C&ancel"));
427
428 QAction *menuChoice = menu.exec(QCursor::pos());
429 if (menuChoice == moveAction) {
430 action = DragMove;
431 } else if (menuChoice == copyAction) {
432 action = DragCopy;
433 } else {
434 action = DragCancel;
435 }
436 }
437 }
438 if (action == DragCancel) {
439 return;
440 }
441
442 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
443 Collection target = collections.at(0);
445 items.reserve(urls.count());
446 for (const QUrl &url : std::as_const(urls)) {
447 items << Akonadi::Item::fromUrl(url);
448 }
449
450 if (action == DragCopy) {
451 new ItemCopyJob(items, target, this);
452 } else if (action == DragMove) {
453 new ItemMoveJob(items, target, this);
454 }
455}
456
458{
459 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
460
461 if (collections.isEmpty()) {
462 return; // no folder here
463 }
464
465 const QList<Core::MessageItem *> selection = view()->selectionAsMessageItemList();
466 if (selection.isEmpty()) {
467 return;
468 }
469
470 bool readOnly = false;
471
472 for (const Collection &c : std::as_const(collections)) {
473 // We won't be able to remove items from this collection
474 if ((c.rights() & Collection::CanDeleteItem) == 0) {
475 // So the drag will be read-only
476 readOnly = true;
477 break;
478 }
479 }
480
481 QList<QUrl> urls;
482 urls.reserve(selection.count());
483 for (Core::MessageItem *mi : selection) {
484 const Akonadi::Item i = d->itemForRow(mi->currentModelIndexRow());
486 QUrlQuery query(url);
487 query.addQueryItem(QStringLiteral("parent"), QString::number(mi->parentCollectionId()));
488 url.setQuery(query);
489 urls << url;
490 }
491
492 auto mimeData = new QMimeData;
493 mimeData->setUrls(urls);
494
495 auto drag = new QDrag(view()->viewport());
496 drag->setMimeData(mimeData);
497
498 // Set pixmap
499 QPixmap pixmap;
500 if (selection.size() == 1) {
501 pixmap = QIcon::fromTheme(QStringLiteral("mail-message")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize));
502 } else {
503 pixmap = QIcon::fromTheme(QStringLiteral("document-multiple")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize));
504 }
505
506 // Calculate hotspot (as in Konqueror)
507 if (!pixmap.isNull()) {
508 drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2));
509 drag->setPixmap(pixmap);
510 }
511
512 if (readOnly) {
513 drag->exec(Qt::CopyAction);
514 } else {
515 drag->exec(Qt::CopyAction | Qt::MoveAction);
516 }
517}
518
519Akonadi::Item::List MessageList::Widget::WidgetPrivate::selectionAsItems() const
520{
522 const QList<Core::MessageItem *> selection = q->view()->selectionAsMessageItemList();
523 res.reserve(selection.count());
524
525 for (Core::MessageItem *mi : std::as_const(selection)) {
526 Akonadi::Item i = itemForRow(mi->currentModelIndexRow());
527 Q_ASSERT(i.isValid());
528 res << i;
529 }
530
531 return res;
532}
533
534Akonadi::Item MessageList::Widget::WidgetPrivate::itemForRow(int row) const
535{
536 return static_cast<const MessageList::StorageModel *>(q->storageModel())->itemForRow(row);
537}
538
539KMime::Message::Ptr MessageList::Widget::WidgetPrivate::messageForRow(int row) const
540{
541 return static_cast<const MessageList::StorageModel *>(q->storageModel())->messageForRow(row);
542}
543
545{
547
548 if (mi == nullptr) {
549 return {};
550 }
551
552 return d->itemForRow(mi->currentModelIndexRow());
553}
554
556{
558
559 if (mi == nullptr) {
560 return {};
561 }
562
563 return d->messageForRow(mi->currentModelIndexRow());
564}
565
567{
569 const QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
570 if (lstMi.isEmpty()) {
571 return lstMiPtr;
572 }
573 lstMiPtr.reserve(lstMi.count());
574 for (Core::MessageItem *it : std::as_const(lstMi)) {
575 lstMiPtr.append(d->messageForRow(it->currentModelIndexRow()));
576 }
577 return lstMiPtr;
578}
579
581{
582 Akonadi::Item::List lstMiPtr;
583 const QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
584 if (lstMi.isEmpty()) {
585 return lstMiPtr;
586 }
587 lstMiPtr.reserve(lstMi.count());
588 for (Core::MessageItem *it : std::as_const(lstMi)) {
589 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()));
590 }
591 return lstMiPtr;
592}
593
595{
596 QList<qlonglong> lstMiPtr;
597 const QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
598 if (lstMi.isEmpty()) {
599 return lstMiPtr;
600 }
601 lstMiPtr.reserve(lstMi.count());
602 for (Core::MessageItem *it : std::as_const(lstMi)) {
603 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()).id());
604 }
605 return lstMiPtr;
606}
607
608QList<Akonadi::Item::Id> MessageList::Widget::selectionAsListMessageId(bool includeCollapsedChildren) const
609{
610 QList<qlonglong> lstMiPtr;
611 const QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
612 if (lstMi.isEmpty()) {
613 return lstMiPtr;
614 }
615 lstMiPtr.reserve(lstMi.count());
616 for (Core::MessageItem *it : std::as_const(lstMi)) {
617 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()).id());
618 }
619 return lstMiPtr;
620}
621
623{
624 Akonadi::Item::List lstMiPtr;
626 if (lstMi.isEmpty()) {
627 return lstMiPtr;
628 }
629 lstMiPtr.reserve(lstMi.count());
630 for (Core::MessageItem *it : std::as_const(lstMi)) {
631 lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()));
632 }
633 return lstMiPtr;
634}
635
636MessageList::Core::SearchMessageByButtons::SearchOptions MessageList::Widget::currentOptions() const
637{
638 return view()->currentOptions();
639}
640
642{
643 return view()->currentFilterStatus();
644}
645
647{
649}
650
652{
653 return view()->isThreaded();
654}
655
657{
658 return view()->selectionEmpty();
659}
660
662 Akonadi::Item::List &selectedVisibleItems,
663 bool *allSelectedBelongToSameThread,
664 bool includeCollapsedChildren) const
665{
666 if (!storageModel()) {
667 return false;
668 }
669
670 selectedItems.clear();
671 selectedVisibleItems.clear();
672
673 const QList<Core::MessageItem *> selected = view()->selectionAsMessageItemList(includeCollapsedChildren);
674
675 Core::MessageItem *topmost = nullptr;
676
677 *allSelectedBelongToSameThread = true;
678
679 for (Core::MessageItem *it : std::as_const(selected)) {
680 const Akonadi::Item item = d->itemForRow(it->currentModelIndexRow());
681 selectedItems.append(item);
682 if (view()->isDisplayedWithParentsExpanded(it)) {
683 selectedVisibleItems.append(item);
684 }
685 if (topmost == nullptr) {
686 topmost = (*it).topmostMessage();
687 } else {
688 if (topmost != (*it).topmostMessage()) {
689 *allSelectedBelongToSameThread = false;
690 }
691 }
692 }
693 return true;
694}
695
696void MessageList::Widget::deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
697{
699}
700
701void MessageList::Widget::markMessageItemsAsAboutToBeRemoved(MessageList::Core::MessageItemSetReference ref, bool bMark)
702{
704 if (!lstPersistent.isEmpty()) {
705 view()->markMessageItemsAsAboutToBeRemoved(lstPersistent, bMark);
706 }
707}
708
709Akonadi::Item::List MessageList::Widget::itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
710{
711 Akonadi::Item::List lstItem;
713 if (!refList.isEmpty()) {
714 lstItem.reserve(refList.count());
715 for (Core::MessageItem *it : std::as_const(refList)) {
716 lstItem.append(d->itemForRow(it->currentModelIndexRow()));
717 }
718 }
719 return lstItem;
720}
721
722MessageList::Core::MessageItemSetReference MessageList::Widget::selectionAsPersistentSet(bool includeCollapsedChildren) const
723{
724 QList<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
725 if (lstMi.isEmpty()) {
726 return -1;
727 }
728 return view()->createPersistentSet(lstMi);
729}
730
731MessageList::Core::MessageItemSetReference MessageList::Widget::currentThreadAsPersistentSet() const
732{
734 if (lstMi.isEmpty()) {
735 return -1;
736 }
737 return view()->createPersistentSet(lstMi);
738}
739
740Akonadi::Collection MessageList::Widget::currentCollection() const
741{
742 Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
743 if (collections.size() != 1) {
744 return {}; // no folder here or too many (in case we can't decide where the drop will end)
745 }
746 return collections.first();
747}
748
749void MessageList::Widget::slotCollapseItem()
750{
751 view()->setCollapseItem(d->mGroupHeaderItemIndex);
752}
753
754void MessageList::Widget::slotExpandItem()
755{
756 view()->setExpandItem(d->mGroupHeaderItemIndex);
757}
758
759#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: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::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()
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()
void setUrls(const QList< QUrl > &urls)
QList< QUrl > urls() const const
const QAbstractItemModel * model() 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-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:07:25 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.