Messagelib

widget.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Kevin Ottens <[email protected]>
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 
43 namespace MessageList
44 {
45 class MessageList::Widget::WidgetPrivate
46 {
47 public:
48  WidgetPrivate(Widget *owner)
49  : q(owner)
50  {
51  }
52 
53  Q_REQUIRED_RESULT Akonadi::Item::List selectionAsItems() const;
54  Q_REQUIRED_RESULT Akonadi::Item itemForRow(int row) const;
55  Q_REQUIRED_RESULT 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 
66 using namespace MessageList;
67 using 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(QStringLiteral("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 
83 MessageList::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 
140 bool MessageList::Widget::focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
141 {
142  return view()->focusNextMessageItem(messageTypeFilter, centerItem, loop);
143 }
144 
145 bool 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 
160 bool 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 
186 void MessageList::Widget::focusQuickSearch(const QString &selectedText)
187 {
188  view()->focusQuickSearch(selectedText);
189 }
190 
191 void 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 
203 void 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(), "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 
333 void 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"));
355  connect(act, &QAction::triggered, view(), &Core::View::slotExpandAllGroups);
356 
357  act = menu.addAction(i18n("Collapse All Groups"));
358  connect(act, &QAction::triggered, view(), &Core::View::slotCollapseAllGroups);
359 
360  menu.exec(globalPos);
361 }
362 
364 {
365  if (!canAcceptDrag(e)) {
366  e->ignore();
367  return;
368  }
369 
370  e->accept();
371 }
372 
374 {
375  if (!canAcceptDrag(e)) {
376  e->ignore();
377  return;
378  }
379 
380  e->accept();
381 }
382 
383 enum DragMode { DragCopy, DragMove, DragCancel };
384 
386 {
387  if (!canAcceptDrag(e)) {
388  e->ignore();
389  return;
390  }
391 
392  const QList<QUrl> urls = e->mimeData()->urls();
393  if (urls.isEmpty()) {
394  qCWarning(MESSAGELIST_LOG) << "Could not decode drag data!";
395  e->ignore();
396  return;
397  }
398 
399  e->accept();
400 
401  int action;
402  if ((e->possibleActions() & Qt::MoveAction) == 0) { // We can't move anyway
403  action = DragCopy;
404  } else {
405  const auto keybstate = QApplication::keyboardModifiers();
406  if (keybstate & Qt::CTRL) {
407  action = DragCopy;
408  } else if (keybstate & Qt::SHIFT) {
409  action = DragMove;
410  } else {
411  QMenu menu;
412  QAction *moveAction =
413  menu.addAction(QIcon::fromTheme(QStringLiteral("edit-move"), QIcon::fromTheme(QStringLiteral("go-jump"))), i18n("&Move Here"));
414  QAction *copyAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("&Copy Here"));
415  menu.addSeparator();
416  menu.addAction(QIcon::fromTheme(QStringLiteral("dialog-cancel")), i18n("C&ancel"));
417 
418  QAction *menuChoice = menu.exec(QCursor::pos());
419  if (menuChoice == moveAction) {
420  action = DragMove;
421  } else if (menuChoice == copyAction) {
422  action = DragCopy;
423  } else {
424  action = DragCancel;
425  }
426  }
427  }
428  if (action == DragCancel) {
429  return;
430  }
431 
432  Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
433  Collection target = collections.at(0);
434  Akonadi::Item::List items;
435  items.reserve(urls.count());
436  for (const QUrl &url : std::as_const(urls)) {
437  items << Akonadi::Item::fromUrl(url);
438  }
439 
440  if (action == DragCopy) {
441  new ItemCopyJob(items, target, this);
442  } else if (action == DragMove) {
443  new ItemMoveJob(items, target, this);
444  }
445 }
446 
448 {
449  Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
450 
451  if (collections.isEmpty()) {
452  return; // no folder here
453  }
454 
455  const QVector<Core::MessageItem *> selection = view()->selectionAsMessageItemList();
456  if (selection.isEmpty()) {
457  return;
458  }
459 
460  bool readOnly = false;
461 
462  for (const Collection &c : std::as_const(collections)) {
463  // We won't be able to remove items from this collection
464  if ((c.rights() & Collection::CanDeleteItem) == 0) {
465  // So the drag will be read-only
466  readOnly = true;
467  break;
468  }
469  }
470 
471  QList<QUrl> urls;
472  urls.reserve(selection.count());
473  for (Core::MessageItem *mi : selection) {
474  const Akonadi::Item i = d->itemForRow(mi->currentModelIndexRow());
476  QUrlQuery query(url);
477  query.addQueryItem(QStringLiteral("parent"), QString::number(mi->parentCollectionId()));
478  url.setQuery(query);
479  urls << url;
480  }
481 
482  auto mimeData = new QMimeData;
483  mimeData->setUrls(urls);
484 
485  auto drag = new QDrag(view()->viewport());
486  drag->setMimeData(mimeData);
487 
488  // Set pixmap
489  QPixmap pixmap;
490  if (selection.size() == 1) {
491  pixmap = QIcon::fromTheme(QStringLiteral("mail-message")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize));
492  } else {
493  pixmap = QIcon::fromTheme(QStringLiteral("document-multiple")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize));
494  }
495 
496  // Calculate hotspot (as in Konqueror)
497  if (!pixmap.isNull()) {
498  drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2));
499  drag->setPixmap(pixmap);
500  }
501 
502  if (readOnly) {
503  drag->exec(Qt::CopyAction);
504  } else {
505  drag->exec(Qt::CopyAction | Qt::MoveAction);
506  }
507 }
508 
509 Akonadi::Item::List MessageList::Widget::WidgetPrivate::selectionAsItems() const
510 {
512  const QVector<Core::MessageItem *> selection = q->view()->selectionAsMessageItemList();
513  res.reserve(selection.count());
514 
515  for (Core::MessageItem *mi : std::as_const(selection)) {
516  Akonadi::Item i = itemForRow(mi->currentModelIndexRow());
517  Q_ASSERT(i.isValid());
518  res << i;
519  }
520 
521  return res;
522 }
523 
524 Akonadi::Item MessageList::Widget::WidgetPrivate::itemForRow(int row) const
525 {
526  return static_cast<const MessageList::StorageModel *>(q->storageModel())->itemForRow(row);
527 }
528 
529 KMime::Message::Ptr MessageList::Widget::WidgetPrivate::messageForRow(int row) const
530 {
531  return static_cast<const MessageList::StorageModel *>(q->storageModel())->messageForRow(row);
532 }
533 
535 {
536  Core::MessageItem *mi = view()->currentMessageItem();
537 
538  if (mi == nullptr) {
539  return {};
540  }
541 
542  return d->itemForRow(mi->currentModelIndexRow());
543 }
544 
546 {
547  Core::MessageItem *mi = view()->currentMessageItem();
548 
549  if (mi == nullptr) {
550  return {};
551  }
552 
553  return d->messageForRow(mi->currentModelIndexRow());
554 }
555 
557 {
559  const QVector<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
560  if (lstMi.isEmpty()) {
561  return lstMiPtr;
562  }
563  lstMiPtr.reserve(lstMi.count());
564  for (Core::MessageItem *it : std::as_const(lstMi)) {
565  lstMiPtr.append(d->messageForRow(it->currentModelIndexRow()));
566  }
567  return lstMiPtr;
568 }
569 
570 Akonadi::Item::List MessageList::Widget::selectionAsMessageItemList(bool includeCollapsedChildren) const
571 {
572  Akonadi::Item::List lstMiPtr;
573  const QVector<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
574  if (lstMi.isEmpty()) {
575  return lstMiPtr;
576  }
577  lstMiPtr.reserve(lstMi.count());
578  for (Core::MessageItem *it : std::as_const(lstMi)) {
579  lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()));
580  }
581  return lstMiPtr;
582 }
583 
585 {
586  QVector<qlonglong> lstMiPtr;
587  const QVector<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
588  if (lstMi.isEmpty()) {
589  return lstMiPtr;
590  }
591  lstMiPtr.reserve(lstMi.count());
592  for (Core::MessageItem *it : std::as_const(lstMi)) {
593  lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()).id());
594  }
595  return lstMiPtr;
596 }
597 
598 QVector<Akonadi::Item::Id> MessageList::Widget::selectionAsListMessageId(bool includeCollapsedChildren) const
599 {
600  QVector<qlonglong> lstMiPtr;
601  const QVector<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
602  if (lstMi.isEmpty()) {
603  return lstMiPtr;
604  }
605  lstMiPtr.reserve(lstMi.count());
606  for (Core::MessageItem *it : std::as_const(lstMi)) {
607  lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()).id());
608  }
609  return lstMiPtr;
610 }
611 
613 {
614  Akonadi::Item::List lstMiPtr;
615  const QVector<Core::MessageItem *> lstMi = view()->currentThreadAsMessageItemList();
616  if (lstMi.isEmpty()) {
617  return lstMiPtr;
618  }
619  lstMiPtr.reserve(lstMi.count());
620  for (Core::MessageItem *it : std::as_const(lstMi)) {
621  lstMiPtr.append(d->itemForRow(it->currentModelIndexRow()));
622  }
623  return lstMiPtr;
624 }
625 
626 MessageList::Core::QuickSearchLine::SearchOptions MessageList::Widget::currentOptions() const
627 {
628  return view()->currentOptions();
629 }
630 
632 {
633  return view()->currentFilterStatus();
634 }
635 
637 {
638  return view()->currentFilterSearchString();
639 }
640 
642 {
643  return view()->isThreaded();
644 }
645 
647 {
648  return view()->selectionEmpty();
649 }
650 
652  Akonadi::Item::List &selectedVisibleItems,
653  bool *allSelectedBelongToSameThread,
654  bool includeCollapsedChildren) const
655 {
656  if (!storageModel()) {
657  return false;
658  }
659 
660  selectedItems.clear();
661  selectedVisibleItems.clear();
662 
663  const QVector<Core::MessageItem *> selected = view()->selectionAsMessageItemList(includeCollapsedChildren);
664 
665  Core::MessageItem *topmost = nullptr;
666 
667  *allSelectedBelongToSameThread = true;
668 
669  for (Core::MessageItem *it : std::as_const(selected)) {
670  const Akonadi::Item item = d->itemForRow(it->currentModelIndexRow());
671  selectedItems.append(item);
672  if (view()->isDisplayedWithParentsExpanded(it)) {
673  selectedVisibleItems.append(item);
674  }
675  if (topmost == nullptr) {
676  topmost = (*it).topmostMessage();
677  } else {
678  if (topmost != (*it).topmostMessage()) {
679  *allSelectedBelongToSameThread = false;
680  }
681  }
682  }
683  return true;
684 }
685 
686 void MessageList::Widget::deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
687 {
688  view()->deletePersistentSet(ref);
689 }
690 
691 void MessageList::Widget::markMessageItemsAsAboutToBeRemoved(MessageList::Core::MessageItemSetReference ref, bool bMark)
692 {
693  QList<Core::MessageItem *> lstPersistent = view()->persistentSetCurrentMessageItemList(ref);
694  if (!lstPersistent.isEmpty()) {
695  view()->markMessageItemsAsAboutToBeRemoved(lstPersistent, bMark);
696  }
697 }
698 
699 Akonadi::Item::List MessageList::Widget::itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
700 {
701  Akonadi::Item::List lstItem;
702  const QList<Core::MessageItem *> refList = view()->persistentSetCurrentMessageItemList(ref);
703  if (!refList.isEmpty()) {
704  lstItem.reserve(refList.count());
705  for (Core::MessageItem *it : std::as_const(refList)) {
706  lstItem.append(d->itemForRow(it->currentModelIndexRow()));
707  }
708  }
709  return lstItem;
710 }
711 
712 MessageList::Core::MessageItemSetReference MessageList::Widget::selectionAsPersistentSet(bool includeCollapsedChildren) const
713 {
714  QVector<Core::MessageItem *> lstMi = view()->selectionAsMessageItemList(includeCollapsedChildren);
715  if (lstMi.isEmpty()) {
716  return -1;
717  }
718  return view()->createPersistentSet(lstMi);
719 }
720 
721 MessageList::Core::MessageItemSetReference MessageList::Widget::currentThreadAsPersistentSet() const
722 {
723  QVector<Core::MessageItem *> lstMi = view()->currentThreadAsMessageItemList();
724  if (lstMi.isEmpty()) {
725  return -1;
726  }
727  return view()->createPersistentSet(lstMi);
728 }
729 
730 Akonadi::Collection MessageList::Widget::currentCollection() const
731 {
732  Collection::List collections = static_cast<const MessageList::StorageModel *>(storageModel())->displayedCollections();
733  if (collections.size() != 1) {
734  return {}; // no folder here or too many (in case we can't decide where the drop will end)
735  }
736  return collections.first();
737 }
738 
739 void MessageList::Widget::slotCollapseItem()
740 {
741  view()->setCollapseItem(d->mGroupHeaderItemIndex);
742 }
743 
744 void MessageList::Widget::slotExpandItem()
745 {
746  view()->setExpandItem(d->mGroupHeaderItemIndex);
747 }
Akonadi::Item::List currentThreadAsMessageList() const
Returns the Akonadi::Item bound to the current StorageModel that are part of the current thread...
QObject * source() const const
bool focusPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
Focuses the previous message item in the view without actually selecting it.
static Item fromUrl(const QUrl &url)
Widget(QWidget *parent)
Create a new message list widget.
void triggered(bool checked)
bool isValid() const
bool selectPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, bool loop)
Selects the previous message item in the view.
QUrl url(UrlType type=UrlShort) const
bool isValid() const
int width() const const
bool canAcceptDrag(const QDropEvent *e)
Returns true if this drag can be accepted by the underlying view.
const QMimeData * mimeData() const const
MessageList::Core::MessageItemSetReference currentThreadAsPersistentSet() const
Return a persistent set from current thread.
Qt::DropActions possibleActions() const const
Akonadi::Item::List selectionAsMessageItemList(bool includeCollapsedChildren=true) const
Returns the currently selected Items (bound to current StorageModel).
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 ...
void append(const T &value)
The MessageItem class.
Definition: messageitem.h:34
Akonadi::Item::List itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
Return Akonadi::Item from messageItemReference.
void selectAll()
Selects all the items in the current folder.
std::optional< QSqlQuery > query(const QString &queryStatement)
void setAllThreadsExpanded(bool expand)
If expand is true then it expands all the threads, otherwise collapses them.
void reserve(int alloc)
virtual QString errorString() const
KMime::Message::Ptr currentMessage() const
Returns the current message for the list as KMime::Message::Ptr.
QVector< Akonadi::MessageStatus > currentFilterStatus() const
Returns the Akonadi::MessageStatus in the current quicksearch field.
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void setCurrentThreadExpanded(bool expand)
If expand is true then it expands the current thread, otherwise collapses it.
The Akonadi specific implementation of the Core::Widget.
Definition: widget.h:32
bool isThreaded() const
Returns true if the current Aggregation is threaded, false otherwise (or if there is no current Aggre...
T & first()
void viewMessageStatusChangeRequest(MessageList::Core::MessageItem *msg, Akonadi::MessageStatus set, Akonadi::MessageStatus clear) override
Reimplemented from MessageList::Core::Widget.
void viewSelectionChanged() override
Reimplemented from MessageList::Core::Widget.
Qt::KeyboardModifiers keyboardModifiers()
QAction * addAction(const QString &text)
bool selectLastMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem)
Selects the last message item in the view that matches the specified Core::MessageTypeFilter.
bool isValid() const
Returns true if this ModelInvariantIndex is valid, that is, it has been attached to a ModelInvariantR...
void tagAdded(const Akonadi::Tag &tag)
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) const const
KSharedConfigPtr config()
void viewDragMoveEvent(QDragMoveEvent *e) override
Reimplemented from MessageList::Core::Widget.
void clear()
QString number(int n, int base)
int count(const T &value) const const
void append(const T &value)
PartitionTable::TableType type
void ignore()
bool selectNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, bool loop)
Selects the next message item in the view.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setXmlGuiClient(KXMLGUIClient *xmlGuiClient)
Sets the XML GUI client which the view is used in.
QString label(StandardShortcut id)
bool isEmpty() const const
bool isEmpty() const const
bool selectFirstMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem)
Selects the first message item in the view that matches the specified Core::MessageTypeFilter.
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
void viewDropEvent(QDropEvent *e) override
Reimplemented from MessageList::Core::Widget.
void selectFocusedMessageItem(bool centerItem)
Selects the currently focused message item.
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 deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
Deletes the persistent set pointed by the specified reference.
void viewMessageSelected(MessageList::Core::MessageItem *msg) override
Reimplemented from MessageList::Core::Widget.
QAction * addSeparator()
int currentModelIndexRow()
Returns the current model index row for this invariant index.
QAction * exec()
void setAllGroupsExpanded(bool expand)
If expand is true then it expands all the groups (only the toplevel group item: inner threads are NOT...
Rights rights() const
void reserve(int size)
void accept()
bool isNull() const const
int height() const const
void tagRemoved(const Akonadi::Tag &tag)
QString i18n(const char *text, const TYPE &arg...)
void viewDragEnterEvent(QDragEnterEvent *e) override
Reimplemented from MessageList::Core::Widget.
const T & at(int i) const const
void viewStartDragRequest() override
Reimplemented from MessageList::Core::Widget.
MessageTypeFilter
This enum is used in the view message selection functions (for instance View::nextMessageItem()).
PM_SmallIconSize
MessageList::Core::MessageItemSetReference selectionAsPersistentSet(bool includeCollapsedChildren=true) const
Return a persistent set from current selection.
QPoint pos()
void viewMessageActivated(MessageList::Core::MessageItem *msg) override
Reimplemented from MessageList::Core::Widget.
QList< QUrl > urls() const const
void tagChanged(const Akonadi::Tag &tag)
bool isEmpty() const const
void viewGroupHeaderContextPopupRequest(MessageList::Core::GroupHeaderItem *group, const QPoint &globalPos) override
Reimplemented from MessageList::Core::Widget.
The Akonadi specific implementation of the Core::StorageModel.
Definition: storagemodel.h:35
int count(const T &value) const const
Akonadi::Item currentItem() const
Returns the current message for the list as Akonadi::Item.
QVector< qlonglong > selectionAsMessageItemListId(bool includeCollapsedChildren) const
Returns the currently selected Items id (bound to current StorageModel).
void fillMessageTagCombo() override
Reimplemented from MessageList::Core::Widget.
QStringList contentMimeTypes() const
void setQuery(const QString &query, QUrl::ParsingMode mode)
bool focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
Focuses the next message item in the view without actually selecting it.
QIcon fromTheme(const QString &name)
bool selectionEmpty() const
Fast function that determines if the selection is empty.
void result(KJob *job)
QObject * parent() const const
MoveAction
int size() const const
QString currentFilterSearchString() const
Returns the search term in the current quicksearch field.
void focusQuickSearch(const QString &selectedText)
Sets the focus on the quick search line of the currently active tab.
ExistingSelectionBehaviour
This enum is used in the view message selection functions (for instance View::selectNextMessage()) ...
void setUrls(const QList< QUrl > &urls)
QVector< KMime::Message::Ptr > selectionAsMessageList(bool includeCollapsedChildren=true) const
Returns the currently selected KMime::Message::Ptr (bound to current StorageModel).
void viewMessageListContextPopupRequest(const QVector< Core::MessageItem * > &selectedItems, const QPoint &globalPos) override
Reimplemented from MessageList::Core::Widget.
int error() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Dec 6 2021 23:04:59 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.