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 }
bool isValid() const
void append(const T &value)
bool isThreaded() const
Returns true if the current Aggregation is threaded, false otherwise (or if there is no current Aggre...
Qt::KeyboardModifiers keyboardModifiers()
void setCurrentThreadExpanded(bool expand)
If expand is true then it expands the current thread, otherwise collapses it.
bool canAcceptDrag(const QDropEvent *e)
Returns true if this drag can be accepted by the underlying view.
bool isEmpty() const const
The MessageItem class.
Definition: messageitem.h:34
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 viewSelectionChanged() override
Reimplemented from MessageList::Core::Widget.
QString number(int n, int base)
void setUrls(const QList< QUrl > &urls)
bool selectionEmpty() const
Fast function that determines if the selection is empty.
Qt::DropActions possibleActions() const const
void result(KJob *job)
void viewDragMoveEvent(QDragMoveEvent *e) override
Reimplemented from MessageList::Core::Widget.
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
void tagRemoved(const Akonadi::Tag &tag)
int count(const T &value) const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void append(const T &value)
QIcon fromTheme(const QString &name)
void tagAdded(const Akonadi::Tag &tag)
QAction * addSeparator()
bool focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
Focuses the next message item in the view without actually selecting it.
QString currentFilterSearchString() const
Returns the search term in the current quicksearch field.
const QMimeData * mimeData() const const
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 viewDragEnterEvent(QDragEnterEvent *e) override
Reimplemented from MessageList::Core::Widget.
T & first()
MessageList::Core::MessageItemSetReference currentThreadAsPersistentSet() const
Return a persistent set from current thread.
QAction * addAction(const QString &text)
void reserve(int alloc)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
The Akonadi specific implementation of the Core::Widget.
Definition: widget.h:32
bool focusPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
Focuses the previous message item in the view without actually selecting it.
QVector< Akonadi::MessageStatus > currentFilterStatus() const
Returns the Akonadi::MessageStatus in the current quicksearch field.
QUrl url(UrlType type=UrlShort) const
void viewGroupHeaderContextPopupRequest(MessageList::Core::GroupHeaderItem *group, const QPoint &globalPos) override
Reimplemented from MessageList::Core::Widget.
void clear()
QString i18n(const char *text, const TYPE &arg...)
MessageList::Core::MessageItemSetReference selectionAsPersistentSet(bool includeCollapsedChildren=true) const
Return a persistent set from current selection.
void selectFocusedMessageItem(bool centerItem)
Selects the currently focused message item.
void deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
Deletes the persistent set pointed by the specified reference.
QVector< qlonglong > selectionAsMessageItemListId(bool includeCollapsedChildren) const
Returns the currently selected Items id (bound to current StorageModel).
static Item fromUrl(const QUrl &url)
const T & at(int i) const const
void setAllThreadsExpanded(bool expand)
If expand is true then it expands all the threads, otherwise collapses them.
bool isEmpty() const const
The Akonadi specific implementation of the Core::StorageModel.
Definition: storagemodel.h:35
bool selectNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, bool loop)
Selects the next message item in the view.
QVector< KMime::Message::Ptr > selectionAsMessageList(bool includeCollapsedChildren=true) const
Returns the currently selected KMime::Message::Ptr (bound to current StorageModel).
bool isValid() const
Returns true if this ModelInvariantIndex is valid, that is, it has been attached to a ModelInvariantR...
Akonadi::Item::List currentThreadAsMessageList() const
Returns the Akonadi::Item bound to the current StorageModel that are part of the current thread.
bool isEmpty() const const
int height() const const
void setXmlGuiClient(KXMLGUIClient *xmlGuiClient)
Sets the XML GUI client which the view is used in.
KSharedConfigPtr config()
QPoint pos()
void reserve(int size)
PM_SmallIconSize
void viewMessageListContextPopupRequest(const QVector< Core::MessageItem * > &selectedItems, const QPoint &globalPos) override
Reimplemented from MessageList::Core::Widget.
QObject * source() const const
void setQuery(const QString &query, QUrl::ParsingMode mode)
bool isNull() const const
QString label(StandardShortcut id)
int currentModelIndexRow()
Returns the current model index row for this invariant index.
QList< QUrl > urls() const const
MoveAction
void triggered(bool checked)
void viewMessageSelected(MessageList::Core::MessageItem *msg) override
Reimplemented from MessageList::Core::Widget.
KMime::Message::Ptr currentMessage() const
Returns the current message for the list as KMime::Message::Ptr.
Widget(QWidget *parent)
Create a new message list widget.
Akonadi::Item::List selectionAsMessageItemList(bool includeCollapsedChildren=true) const
Returns the currently selected Items (bound to current StorageModel).
Akonadi::Item::List itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
Return Akonadi::Item from messageItemReference.
QStringList contentMimeTypes() const
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) const const
void viewDropEvent(QDropEvent *e) override
Reimplemented from MessageList::Core::Widget.
void ignore()
void viewStartDragRequest() override
Reimplemented from MessageList::Core::Widget.
void selectAll()
Selects all the items in the current folder.
ExistingSelectionBehaviour
This enum is used in the view message selection functions (for instance View::selectNextMessage())
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void viewMessageActivated(MessageList::Core::MessageItem *msg) 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...
int count(const T &value) const const
int size() const const
void viewMessageStatusChangeRequest(MessageList::Core::MessageItem *msg, Akonadi::MessageStatus set, Akonadi::MessageStatus clear) override
Reimplemented from MessageList::Core::Widget.
MessageTypeFilter
This enum is used in the view message selection functions (for instance View::nextMessageItem()).
void fillMessageTagCombo() override
Reimplemented from MessageList::Core::Widget.
bool selectFirstMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem)
Selects the first message item in the view that matches the specified Core::MessageTypeFilter.
Rights rights() const
void focusQuickSearch(const QString &selectedText)
Sets the focus on the quick search line of the currently active tab.
virtual QString errorString() const
int error() const
Akonadi::Item currentItem() const
Returns the current message for the list as Akonadi::Item.
bool selectPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, bool loop)
Selects the previous message item in the view.
bool selectLastMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem)
Selects the last message item in the view that matches the specified Core::MessageTypeFilter.
const QAbstractItemModel * model() const const
QAction * exec()
void tagChanged(const Akonadi::Tag &tag)
int width() const const
void accept()
bool isValid() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Tue May 17 2022 04:00:05 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.