Messagelib

pane.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Kevin Ottens <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "pane.h"
8 
9 #include <KActionCollection>
10 #include <KActionMenu>
11 #include <KLocalizedString>
12 #include <KToggleAction>
13 #include <KXMLGUIClient>
14 #include <QAction>
15 #include <QIcon>
16 #include <QMenu>
17 
18 #include <QAbstractItemModel>
19 #include <QAbstractProxyModel>
20 #include <QApplication>
21 #include <QHeaderView>
22 #include <QItemSelectionModel>
23 #include <QMouseEvent>
24 #include <QRegularExpression>
25 #include <QTabBar>
26 #include <QToolButton>
27 
28 #include "core/model.h"
29 #include "core/widgets/quicksearchline.h"
30 #include "messagelistsettings.h"
31 #include "messagelistutil_p.h"
32 #include "storagemodel.h"
33 #include "widget.h"
34 #include <Akonadi/ETMViewStateSaver>
35 #include <Akonadi/MessageStatus>
36 
37 namespace MessageList
38 {
39 class Pane::PanePrivate
40 {
41 public:
42  PanePrivate(Pane *owner)
43  : q(owner)
44  {
45  }
46 
47  void setCurrentFolder(const QModelIndex &etmIndex);
48  void onNewTabClicked();
49  void onCloseTabClicked();
50  void activateTab();
51  void closeTab(QWidget *);
52  void onCurrentTabChanged();
53  void onTabContextMenuRequest(const QPoint &pos);
54  void activateNextTab();
55  void activatePreviousTab();
56  void moveTabLeft();
57  void moveTabRight();
58  void moveTabBackward();
59  void moveTabForward();
60  void changeQuicksearchVisibility(bool);
61  void addActivateTabAction(int i);
62  void slotTabCloseRequested(int index);
63  Q_REQUIRED_RESULT QItemSelection mapSelectionFromSource(const QItemSelection &selection) const;
64  void updateTabControls();
65 
66  Pane *const q;
67 
68  KXMLGUIClient *mXmlGuiClient = nullptr;
69  KActionMenu *mActionMenu = nullptr;
70 
71  QAbstractItemModel *mModel = nullptr;
72  QItemSelectionModel *mSelectionModel = nullptr;
73  Core::PreSelectionMode mPreSelectionMode = Core::PreSelectLastSelected;
74 
75  QHash<Widget *, QItemSelectionModel *> mWidgetSelectionHash;
77 
78  QToolButton *mNewTabButton = nullptr;
79  QToolButton *mCloseTabButton = nullptr;
80  QAction *mCloseTabAction = nullptr;
81  QAction *mActivateNextTabAction = nullptr;
82  QAction *mActivatePreviousTabAction = nullptr;
83  QAction *mMoveTabLeftAction = nullptr;
84  QAction *mMoveTabRightAction = nullptr;
85  QString mQuickSearchPlaceHolderMessage;
86  bool mPreferEmptyTab = false;
87  int mMaxTabCreated = 0;
88 };
89 } // namespace MessageList
90 
91 using namespace Akonadi;
92 using namespace MessageList;
93 
94 Pane::Pane(bool restoreSession, QAbstractItemModel *model, QItemSelectionModel *selectionModel, QWidget *parent)
95  : QTabWidget(parent)
96  , d(new PanePrivate(this))
97 {
98  setDocumentMode(true);
99  d->mModel = model;
100  d->mSelectionModel = selectionModel;
101 
102  // Build the proxy stack
103  const auto *proxyModel = qobject_cast<const QAbstractProxyModel *>(d->mSelectionModel->model());
104 
105  while (proxyModel) {
106  if (proxyModel == d->mModel) {
107  break;
108  }
109 
110  d->mProxyStack << proxyModel;
111  const auto nextProxyModel = qobject_cast<const QAbstractProxyModel *>(proxyModel->sourceModel());
112 
113  if (!nextProxyModel) {
114  // It's the final model in the chain, so it is necessarily the sourceModel.
115  Q_ASSERT(proxyModel->sourceModel() == d->mModel);
116  break;
117  }
118  proxyModel = nextProxyModel;
119  } // Proxy stack done
120 
121  d->mNewTabButton = new QToolButton(this);
122  d->mNewTabButton->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
123  d->mNewTabButton->adjustSize();
124  d->mNewTabButton->setToolTip(i18nc("@info:tooltip", "Open a new tab"));
125 #ifndef QT_NO_ACCESSIBILITY
126  d->mNewTabButton->setAccessibleName(i18n("New tab"));
127 #endif
128  setCornerWidget(d->mNewTabButton, Qt::TopLeftCorner);
129  connect(d->mNewTabButton, &QToolButton::clicked, this, [this]() {
130  d->onNewTabClicked();
131  });
132 
133  d->mCloseTabButton = new QToolButton(this);
134  d->mCloseTabButton->setIcon(QIcon::fromTheme(QStringLiteral("tab-close")));
135  d->mCloseTabButton->adjustSize();
136  d->mCloseTabButton->setToolTip(i18nc("@info:tooltip", "Close the current tab"));
137 #ifndef QT_NO_ACCESSIBILITY
138  d->mCloseTabButton->setAccessibleName(i18n("Close tab"));
139 #endif
140  setCornerWidget(d->mCloseTabButton, Qt::TopRightCorner);
141  connect(d->mCloseTabButton, &QToolButton::clicked, this, [this]() {
142  d->onCloseTabClicked();
143  });
144 
145  setTabsClosable(true);
146  connect(this, &Pane::tabCloseRequested, this, [this](int index) {
147  d->slotTabCloseRequested(index);
148  });
149 
150  readConfig(restoreSession);
151  setMovable(true);
152 
153  connect(this, &Pane::currentChanged, this, [this]() {
154  d->onCurrentTabChanged();
155  });
156 
158  connect(this, &Pane::customContextMenuRequested, this, [this](const QPoint &point) {
159  d->onTabContextMenuRequest(point);
160  });
161 
162  connect(MessageListSettings::self(), &MessageListSettings::configChanged, this, [this]() {
163  d->updateTabControls();
164  });
165 
166  // connect(this, &QTabWidget::tabBarDoubleClicked, this, &Pane::createNewTab);
167 
168  tabBar()->installEventFilter(this);
169 }
170 
171 Pane::~Pane()
172 {
173  saveCurrentSelection();
174  writeConfig(true);
175 }
176 
177 void Pane::PanePrivate::addActivateTabAction(int i)
178 {
179  const QString actionname = QString::asprintf("activate_tab_%02d", i);
180  auto action = new QAction(i18n("Activate Tab %1", i), q);
181  mXmlGuiClient->actionCollection()->addAction(actionname, action);
182  mXmlGuiClient->actionCollection()->setDefaultShortcut(action, QKeySequence(QStringLiteral("Alt+%1").arg(i)));
183  connect(action, &QAction::triggered, q, [this]() {
184  activateTab();
185  });
186 }
187 
188 void Pane::PanePrivate::slotTabCloseRequested(int index)
189 {
190  QWidget *w = q->widget(index);
191  if (w) {
192  closeTab(w);
193  }
194 }
195 
197 {
198  d->mXmlGuiClient = xmlGuiClient;
199 
200  auto const showHideQuicksearch = new KToggleAction(i18n("Show Quick Search Bar"), this);
201  d->mXmlGuiClient->actionCollection()->setDefaultShortcut(showHideQuicksearch, Qt::CTRL | Qt::Key_H);
202  showHideQuicksearch->setChecked(MessageListSettings::showQuickSearch());
203 
204  d->mXmlGuiClient->actionCollection()->addAction(QStringLiteral("show_quick_search"), showHideQuicksearch);
205  connect(showHideQuicksearch, &KToggleAction::triggered, this, [this](bool state) {
206  d->changeQuicksearchVisibility(state);
207  });
208 
209  for (int i = 0; i < count(); ++i) {
210  auto w = qobject_cast<Widget *>(widget(i));
211  if (w) {
212  w->setXmlGuiClient(d->mXmlGuiClient);
213  }
214  }
215 
216  // Setup "View->Message List" actions.
217  if (xmlGuiClient) {
218  if (d->mActionMenu) {
219  d->mXmlGuiClient->actionCollection()->removeAction(d->mActionMenu);
220  }
221  d->mActionMenu = new KActionMenu(QIcon(), i18n("Message List"), this);
222  d->mXmlGuiClient->actionCollection()->addAction(QStringLiteral("view_message_list"), d->mActionMenu);
223  MessageList::Util::fillViewMenu(d->mActionMenu->menu(), this);
224 
225  d->mActionMenu->addSeparator();
226 
227  auto action = new QAction(i18n("Create New Tab"), this);
228  d->mXmlGuiClient->actionCollection()->addAction(QStringLiteral("create_new_tab"), action);
229  d->mXmlGuiClient->actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_O));
230  connect(action, &QAction::triggered, this, [this]() {
231  d->onNewTabClicked();
232  });
233  d->mActionMenu->addAction(action);
234  d->mActionMenu->addSeparator();
235 
236  d->mMaxTabCreated = count();
237  for (int i = 1; i < 10 && i <= count(); ++i) {
238  d->addActivateTabAction(i);
239  }
240 
241  QList<QKeySequence> nextShortcut;
242  QList<QKeySequence> prevShortcut;
243 
244  QString nextIcon;
245  QString prevIcon;
247  nextShortcut.append(KStandardShortcut::tabPrev());
248  prevShortcut.append(KStandardShortcut::tabNext());
249  nextIcon = QStringLiteral("go-previous-view");
250  prevIcon = QStringLiteral("go-next-view");
251  } else {
252  nextShortcut.append(KStandardShortcut::tabNext());
253  prevShortcut.append(KStandardShortcut::tabPrev());
254  nextIcon = QStringLiteral("go-next-view");
255  prevIcon = QStringLiteral("go-previous-view");
256  }
257 
258  d->mActivateNextTabAction = new QAction(i18n("Activate Next Tab"), this);
259  d->mXmlGuiClient->actionCollection()->addAction(QStringLiteral("activate_next_tab"), d->mActivateNextTabAction);
260  d->mActivateNextTabAction->setEnabled(false);
261  d->mActivateNextTabAction->setIcon(QIcon::fromTheme(nextIcon));
262  d->mXmlGuiClient->actionCollection()->setDefaultShortcuts(d->mActivateNextTabAction, nextShortcut);
263  connect(d->mActivateNextTabAction, &QAction::triggered, this, [this]() {
264  d->activateNextTab();
265  });
266  d->mActionMenu->addAction(d->mActivateNextTabAction);
267 
268  d->mActivatePreviousTabAction = new QAction(i18n("Activate Previous Tab"), this);
269  d->mXmlGuiClient->actionCollection()->addAction(QStringLiteral("activate_previous_tab"), d->mActivatePreviousTabAction);
270  d->mXmlGuiClient->actionCollection()->setDefaultShortcuts(d->mActivatePreviousTabAction, prevShortcut);
271  d->mActivatePreviousTabAction->setIcon(QIcon::fromTheme(prevIcon));
272  d->mActivatePreviousTabAction->setEnabled(false);
273  connect(d->mActivatePreviousTabAction, &QAction::triggered, this, [this]() {
274  d->activatePreviousTab();
275  });
276  d->mActionMenu->addAction(d->mActivatePreviousTabAction);
277 
278  d->mActionMenu->addSeparator();
279 
280  d->mMoveTabLeftAction = new QAction(i18n("Move Tab Left"), this);
281  d->mXmlGuiClient->actionCollection()->addAction(QStringLiteral("move_tab_left"), d->mMoveTabLeftAction);
282  d->mMoveTabLeftAction->setEnabled(false);
283  connect(d->mMoveTabLeftAction, &QAction::triggered, this, [this]() {
284  d->moveTabLeft();
285  });
286  d->mActionMenu->addAction(d->mMoveTabLeftAction);
287 
288  d->mMoveTabRightAction = new QAction(i18n("Move Tab Right"), this);
289  d->mXmlGuiClient->actionCollection()->addAction(QStringLiteral("move_tab_right"), d->mMoveTabRightAction);
290  d->mMoveTabRightAction->setEnabled(false);
291  connect(d->mMoveTabRightAction, &QAction::triggered, this, [this]() {
292  d->moveTabRight();
293  });
294  d->mActionMenu->addAction(d->mMoveTabRightAction);
295 
296  d->mActionMenu->addSeparator();
297 
298  d->mCloseTabAction = new QAction(i18n("Close Tab"), this);
299  d->mXmlGuiClient->actionCollection()->addAction(QStringLiteral("close_current_tab"), d->mCloseTabAction);
300  d->mXmlGuiClient->actionCollection()->setDefaultShortcuts(d->mCloseTabAction,
303  connect(d->mCloseTabAction, &QAction::triggered, this, [this]() {
304  d->onCloseTabClicked();
305  });
306  d->mActionMenu->addAction(d->mCloseTabAction);
307  d->mCloseTabAction->setEnabled(false);
308  }
309 }
310 
312  MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
313  bool centerItem,
314  bool loop)
315 {
316  auto w = static_cast<Widget *>(currentWidget());
317 
318  if (w) {
319  if (w->view()->model()->isLoading()) {
320  return true;
321  }
322 
323  return w->selectNextMessageItem(messageTypeFilter, existingSelectionBehaviour, centerItem, loop);
324  } else {
325  return false;
326  }
327 }
328 
330  MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
331  bool centerItem,
332  bool loop)
333 {
334  auto w = static_cast<Widget *>(currentWidget());
335 
336  if (w) {
337  if (w->view()->model()->isLoading()) {
338  return true;
339  }
340 
341  return w->selectPreviousMessageItem(messageTypeFilter, existingSelectionBehaviour, centerItem, loop);
342  } else {
343  return false;
344  }
345 }
346 
347 bool Pane::focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
348 {
349  auto w = static_cast<Widget *>(currentWidget());
350 
351  if (w) {
352  if (w->view()->model()->isLoading()) {
353  return true;
354  }
355 
356  return w->focusNextMessageItem(messageTypeFilter, centerItem, loop);
357  } else {
358  return false;
359  }
360 }
361 
362 bool Pane::focusPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
363 {
364  auto w = static_cast<Widget *>(currentWidget());
365 
366  if (w) {
367  if (w->view()->model()->isLoading()) {
368  return true;
369  }
370 
371  return w->focusPreviousMessageItem(messageTypeFilter, centerItem, loop);
372  } else {
373  return false;
374  }
375 }
376 
377 void Pane::selectFocusedMessageItem(bool centerItem)
378 {
379  auto w = static_cast<Widget *>(currentWidget());
380 
381  if (w) {
382  if (w->view()->model()->isLoading()) {
383  return;
384  }
385 
386  w->selectFocusedMessageItem(centerItem);
387  }
388 }
389 
391 {
392  auto w = static_cast<Widget *>(currentWidget());
393 
394  if (w) {
395  if (w->view()->model()->isLoading()) {
396  return true;
397  }
398 
399  return w->selectFirstMessageItem(messageTypeFilter, centerItem);
400  } else {
401  return false;
402  }
403 }
404 
405 bool Pane::selectLastMessageItem(Core::MessageTypeFilter messageTypeFilter, bool centerItem)
406 {
407  auto w = static_cast<Widget *>(currentWidget());
408 
409  if (w) {
410  if (w->view()->model()->isLoading()) {
411  return true;
412  }
413 
414  return w->selectLastMessageItem(messageTypeFilter, centerItem);
415  } else {
416  return false;
417  }
418 }
419 
421 {
422  auto w = static_cast<Widget *>(currentWidget());
423 
424  if (w) {
425  if (w->view()->model()->isLoading()) {
426  return;
427  }
428 
429  w->selectAll();
430  }
431 }
432 
434 {
435  auto w = static_cast<Widget *>(currentWidget());
436 
437  if (w) {
438  if (w->view()->model()->isLoading()) {
439  return;
440  }
441 
442  w->setCurrentThreadExpanded(expand);
443  }
444 }
445 
447 {
448  auto w = static_cast<Widget *>(currentWidget());
449 
450  if (w) {
451  if (w->view()->model()->isLoading()) {
452  return;
453  }
454 
455  w->setAllThreadsExpanded(expand);
456  }
457 }
458 
459 void Pane::setAllGroupsExpanded(bool expand)
460 {
461  auto w = static_cast<Widget *>(currentWidget());
462 
463  if (w) {
464  if (w->view()->model()->isLoading()) {
465  return;
466  }
467 
468  w->setAllGroupsExpanded(expand);
469  }
470 }
471 
472 void Pane::focusQuickSearch(const QString &selectedText)
473 {
474  auto w = static_cast<Widget *>(currentWidget());
475 
476  if (w) {
477  w->focusQuickSearch(selectedText);
478  }
479 }
480 
481 void Pane::setQuickSearchClickMessage(const QString &msg)
482 {
483  d->mQuickSearchPlaceHolderMessage = msg;
484  for (int i = 0; i < count(); ++i) {
485  auto w = qobject_cast<Widget *>(widget(i));
486  if (w) {
487  w->setQuickSearchClickMessage(d->mQuickSearchPlaceHolderMessage);
488  }
489  }
490 }
491 
492 void Pane::PanePrivate::setCurrentFolder(const QModelIndex &etmIndex)
493 {
494  if (mPreferEmptyTab) {
495  q->createNewTab();
496  }
497 
498  auto w = static_cast<Widget *>(q->currentWidget());
499  QItemSelectionModel *s = mWidgetSelectionHash[w];
500 
501  w->saveCurrentSelection();
502 
503  // Deselect old before we select new - so that the messagelist can clear first.
504  s->clear();
505  if (s->selection().isEmpty()) {
506  w->view()->model()->setPreSelectionMode(mPreSelectionMode);
507  }
508  Q_ASSERT(s->model() == etmIndex.model());
509  s->select(etmIndex, QItemSelectionModel::Select);
510 
511  QString label;
512  QIcon icon;
513  QString toolTip;
514  for (const QModelIndex &index : s->selectedRows()) {
515  label += index.data(Qt::DisplayRole).toString() + QLatin1String(", ");
516  }
517  label.chop(2);
518 
519  if (label.isEmpty()) {
520  label = i18nc("@title:tab Empty messagelist", "Empty");
521  icon = QIcon();
522  } else if (s->selectedRows().size() == 1) {
523  icon = s->selectedRows().first().data(Qt::DecorationRole).value<QIcon>();
524  QModelIndex idx = s->selectedRows().first().parent();
525  toolTip = label;
526  while (idx != QModelIndex()) {
527  toolTip = idx.data().toString() + QLatin1Char('/') + toolTip;
528  idx = idx.parent();
529  }
530  } else {
531  icon = QIcon::fromTheme(QStringLiteral("folder"));
532  }
533 
534  const int index = q->indexOf(w);
535  q->setTabText(index, label);
536  q->setTabIcon(index, icon);
537  q->setTabToolTip(index, toolTip);
538  if (mPreferEmptyTab) {
539  mSelectionModel->select(mapSelectionFromSource(s->selection()), QItemSelectionModel::ClearAndSelect);
540  }
541  mPreferEmptyTab = false;
542 }
543 
544 void Pane::PanePrivate::activateTab()
545 {
546 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
547  q->tabBar()->setCurrentIndex(q->sender()->objectName().rightRef(2).toInt() - 1);
548 #else
549  q->tabBar()->setCurrentIndex(QStringView(q->sender()->objectName()).right(2).toInt() - 1);
550 #endif
551 }
552 
553 void Pane::PanePrivate::moveTabRight()
554 {
555  const int numberOfTab = q->tabBar()->count();
556  if (numberOfTab == 1) {
557  return;
558  }
560  moveTabForward();
561  } else {
562  moveTabBackward();
563  }
564 }
565 
566 void Pane::PanePrivate::moveTabLeft()
567 {
568  const int numberOfTab = q->tabBar()->count();
569  if (numberOfTab == 1) {
570  return;
571  }
573  moveTabBackward();
574  } else {
575  moveTabForward();
576  }
577 }
578 
579 void Pane::PanePrivate::moveTabForward()
580 {
581  const int currentIndex = q->tabBar()->currentIndex();
582  if (currentIndex == q->tabBar()->count() - 1) {
583  return;
584  }
585  q->tabBar()->moveTab(currentIndex, currentIndex + 1);
586 }
587 
588 void Pane::PanePrivate::moveTabBackward()
589 {
590  const int currentIndex = q->tabBar()->currentIndex();
591  if (currentIndex == 0) {
592  return;
593  }
594  q->tabBar()->moveTab(currentIndex, currentIndex - 1);
595 }
596 
597 void Pane::PanePrivate::activateNextTab()
598 {
599  const int numberOfTab = q->tabBar()->count();
600  if (numberOfTab == 1) {
601  return;
602  }
603 
604  int indexTab = (q->tabBar()->currentIndex() + 1);
605 
606  if (indexTab == numberOfTab) {
607  indexTab = 0;
608  }
609 
610  q->tabBar()->setCurrentIndex(indexTab);
611 }
612 
613 void Pane::PanePrivate::activatePreviousTab()
614 {
615  const int numberOfTab = q->tabBar()->count();
616  if (numberOfTab == 1) {
617  return;
618  }
619 
620  int indexTab = (q->tabBar()->currentIndex() - 1);
621 
622  if (indexTab == -1) {
623  indexTab = numberOfTab - 1;
624  }
625 
626  q->tabBar()->setCurrentIndex(indexTab);
627 }
628 
629 void Pane::PanePrivate::onNewTabClicked()
630 {
631  q->createNewTab();
632 }
633 
634 void Pane::PanePrivate::onCloseTabClicked()
635 {
636  closeTab(q->currentWidget());
637 }
638 
639 void Pane::PanePrivate::closeTab(QWidget *w)
640 {
641  if (!w || (q->count() < 2)) {
642  return;
643  }
644 
645  auto wWidget = qobject_cast<Widget *>(w);
646  if (wWidget) {
647  const bool isLocked = wWidget->isLocked();
648  if (isLocked) {
649  return;
650  }
651  wWidget->saveCurrentSelection();
652  }
653 
654  delete w;
655  updateTabControls();
656 }
657 
658 void Pane::PanePrivate::changeQuicksearchVisibility(bool show)
659 {
660  for (int i = 0; i < q->count(); ++i) {
661  auto w = qobject_cast<Widget *>(q->widget(i));
662  if (w) {
663  w->changeQuicksearchVisibility(show);
664  }
665  }
666 }
667 
668 bool Pane::eventFilter(QObject *object, QEvent *event)
669 {
670  if (event->type() == QEvent::MouseButtonPress) {
671  auto const mouseEvent = static_cast<QMouseEvent *>(event);
672  if (mouseEvent->button() == Qt::MiddleButton) {
673  return true;
674  }
675  }
676  return QTabWidget::eventFilter(object, event);
677 }
678 
679 void Pane::PanePrivate::onCurrentTabChanged()
680 {
681  Q_EMIT q->currentTabChanged();
682 
683  auto w = static_cast<Widget *>(q->currentWidget());
684  mCloseTabButton->setEnabled(!w->isLocked());
685 
686  QItemSelectionModel *s = mWidgetSelectionHash[w];
687 
688  mSelectionModel->select(mapSelectionFromSource(s->selection()), QItemSelectionModel::ClearAndSelect);
689 }
690 
691 void Pane::PanePrivate::onTabContextMenuRequest(const QPoint &pos)
692 {
693  QTabBar *bar = q->tabBar();
694  if (q->count() <= 1) {
695  return;
696  }
697 
698  const int indexBar = bar->tabAt(bar->mapFrom(q, pos));
699  if (indexBar == -1) {
700  return;
701  }
702 
703  auto w = qobject_cast<Widget *>(q->widget(indexBar));
704  if (!w) {
705  return;
706  }
707 
708  QMenu menu(q);
709 
710  QAction *closeTabAction = nullptr;
711  if (!w->isLocked()) {
712  closeTabAction = menu.addAction(i18nc("@action:inmenu", "Close Tab"));
713  closeTabAction->setIcon(QIcon::fromTheme(QStringLiteral("tab-close")));
714  }
715 
716  QAction *allOtherAction = menu.addAction(i18nc("@action:inmenu", "Close All Other Tabs"));
717  allOtherAction->setIcon(QIcon::fromTheme(QStringLiteral("tab-close-other")));
718 
719  menu.addSeparator();
720 
721  QAction *lockTabAction = menu.addAction(w->isLocked() ? i18nc("@action:inmenu", "Unlock Tab") : i18nc("@action:inmenu", "Lock Tab"));
722  lockTabAction->setIcon(w->isLocked() ? QIcon::fromTheme(QStringLiteral("lock")) : QIcon::fromTheme(QStringLiteral("unlock")));
723 
724  QAction *action = menu.exec(q->mapToGlobal(pos));
725 
726  if (action == allOtherAction) { // Close all other tabs
727  QVector<Widget *> widgets;
728  const int index = q->indexOf(w);
729 
730  for (int i = 0; i < q->count(); ++i) {
731  if (i == index) {
732  continue; // Skip the current one
733  }
734 
735  auto other = qobject_cast<Widget *>(q->widget(i));
736  const bool isLocked = other->isLocked();
737  if (!isLocked && other) {
738  widgets << other;
739  }
740  }
741 
742  for (Widget *other : std::as_const(widgets)) {
743  other->saveCurrentSelection();
744  delete other;
745  }
746 
747  updateTabControls();
748  } else if (closeTabAction && (action == closeTabAction)) {
749  closeTab(q->widget(indexBar));
750  } else if (action == lockTabAction) {
751  auto tab = qobject_cast<Widget *>(q->widget(indexBar));
752  const bool isLocked = !tab->isLocked();
753  tab->setLockTab(isLocked);
754  q->setTabIcon(indexBar, isLocked ? QIcon::fromTheme(QStringLiteral("lock")) : QIcon::fromTheme(QStringLiteral("unlock")));
755  q->tabBar()->tabButton(indexBar, QTabBar::RightSide)->setEnabled(!isLocked);
756  if (q->tabBar()->currentIndex() == indexBar) {
757  mCloseTabButton->setEnabled(!isLocked);
758  }
759  }
760 }
761 
762 MessageList::StorageModel *Pane::createStorageModel(QAbstractItemModel *model, QItemSelectionModel *selectionModel, QObject *parent)
763 {
764  return new MessageList::StorageModel(model, selectionModel, parent);
765 }
766 
767 Akonadi::Collection Pane::currentFolder() const
768 {
769  auto w = static_cast<Widget *>(currentWidget());
770  if (w) {
771  return w->currentCollection();
772  }
773  return {};
774 }
775 
777  const QModelIndex &etmIndex,
778  bool,
779  Core::PreSelectionMode preSelectionMode,
780  const QString &overrideLabel)
781 {
782  auto w = static_cast<Widget *>(currentWidget());
783  if (!w->isLocked()) {
784  d->setCurrentFolder(etmIndex);
785  d->mPreSelectionMode = preSelectionMode;
786  if (w) {
787  w->setCurrentFolder(collection);
788  QItemSelectionModel *s = d->mWidgetSelectionHash[w];
789  MessageList::StorageModel *m = createStorageModel(d->mModel, s, w);
790  w->setStorageModel(m, preSelectionMode);
791  if (!overrideLabel.isEmpty()) {
792  const int index = indexOf(w);
793  setTabText(index, overrideLabel);
794  }
795  }
796  }
797 }
798 
799 void Pane::updateTabIconText(const Akonadi::Collection &collection, const QString &label, const QIcon &icon)
800 {
801  for (int i = 0; i < count(); ++i) {
802  auto w = qobject_cast<Widget *>(widget(i));
803  if (w && (w->currentCollection() == collection)) {
804  const int index = indexOf(w);
805  setTabText(index, label);
806  setTabIcon(index, icon);
807  }
808  }
809 }
810 
812 {
813  auto w = new Widget(this);
814  w->setXmlGuiClient(d->mXmlGuiClient);
815 
816  addTab(w, i18nc("@title:tab Empty messagelist", "Empty"));
817  if (!d->mQuickSearchPlaceHolderMessage.isEmpty()) {
818  w->setQuickSearchClickMessage(d->mQuickSearchPlaceHolderMessage);
819  }
820  if (d->mXmlGuiClient && count() < 10) {
821  if (d->mMaxTabCreated < count()) {
822  d->mMaxTabCreated = count();
823  d->addActivateTabAction(d->mMaxTabCreated);
824  }
825  }
826 
827  auto s = new QItemSelectionModel(d->mModel, w);
828  MessageList::StorageModel *m = createStorageModel(d->mModel, s, w);
829  w->setStorageModel(m);
830 
831  d->mWidgetSelectionHash[w] = s;
832 
837 
839 
840  connect(w, &Core::Widget::forceLostFocus, this, &Pane::forceLostFocus);
841  connect(w, &Core::Widget::unlockTabRequested, this, [this, w]() {
842  for (int i = 0; i < count(); ++i) {
843  if (w == qobject_cast<Widget *>(widget(i))) {
844  setTabIcon(i, QIcon::fromTheme(QStringLiteral("unlock")));
845  }
846  }
847  });
848 
849  d->updateTabControls();
850  setCurrentWidget(w);
851  return s;
852 }
853 
854 QItemSelection Pane::PanePrivate::mapSelectionFromSource(const QItemSelection &selection) const
855 {
856  QItemSelection result = selection;
857 
859 
860  for (Iterator it = mProxyStack.end() - 1; it != mProxyStack.begin(); --it) {
861  result = (*it)->mapSelectionFromSource(result);
862  }
863  result = mProxyStack.first()->mapSelectionFromSource(result);
864 
865  return result;
866 }
867 
868 void Pane::PanePrivate::updateTabControls()
869 {
870  const bool enableAction = (q->count() > 1);
871  if (enableAction) {
872  q->setCornerWidget(mCloseTabButton, Qt::TopRightCorner);
873  mCloseTabButton->setVisible(true);
874  } else {
875  q->setCornerWidget(nullptr, Qt::TopRightCorner);
876  }
877  if (mCloseTabAction) {
878  mCloseTabAction->setEnabled(enableAction);
879  }
880  if (mActivatePreviousTabAction) {
881  mActivatePreviousTabAction->setEnabled(enableAction);
882  }
883  if (mActivateNextTabAction) {
884  mActivateNextTabAction->setEnabled(enableAction);
885  }
886  if (mMoveTabRightAction) {
887  mMoveTabRightAction->setEnabled(enableAction);
888  }
889  if (mMoveTabLeftAction) {
890  mMoveTabLeftAction->setEnabled(enableAction);
891  }
892 
893  q->tabBar()->setVisible(enableAction);
894  if (enableAction) {
895  q->setCornerWidget(mNewTabButton, Qt::TopLeftCorner);
896  mNewTabButton->setVisible(true);
897  } else {
898  q->setCornerWidget(nullptr, Qt::TopLeftCorner);
899  }
900 
901  q->setTabsClosable(true);
902  const int numberOfTab(q->count());
903  if (numberOfTab == 1) {
904  q->tabBar()->tabButton(0, QTabBar::RightSide)->setEnabled(false);
905  } else if (numberOfTab > 1) {
906  q->tabBar()->tabButton(0, QTabBar::RightSide)->setEnabled(true);
907  }
908 }
909 
911 {
912  auto w = static_cast<Widget *>(currentWidget());
913 
914  if (!w) {
915  return {};
916  }
917 
918  return w->currentItem();
919 }
920 
922 {
923  auto w = static_cast<Widget *>(currentWidget());
924 
925  if (!w) {
926  return {};
927  }
928 
929  return w->currentMessage();
930 }
931 
932 QVector<KMime::Message::Ptr> Pane::selectionAsMessageList(bool includeCollapsedChildren) const
933 {
934  auto w = static_cast<Widget *>(currentWidget());
935  if (!w) {
936  return {};
937  }
938  return w->selectionAsMessageList(includeCollapsedChildren);
939 }
940 
941 Akonadi::Item::List Pane::selectionAsMessageItemList(bool includeCollapsedChildren) const
942 {
943  auto w = static_cast<Widget *>(currentWidget());
944  if (!w) {
945  return {};
946  }
947  return w->selectionAsMessageItemList(includeCollapsedChildren);
948 }
949 
950 QVector<Akonadi::Item::Id> Pane::selectionAsListMessageId(bool includeCollapsedChildren) const
951 {
952  auto w = static_cast<Widget *>(currentWidget());
953  if (!w) {
954  return {};
955  }
956  return w->selectionAsListMessageId(includeCollapsedChildren);
957 }
958 
959 QVector<qlonglong> Pane::selectionAsMessageItemListId(bool includeCollapsedChildren) const
960 {
961  auto w = static_cast<Widget *>(currentWidget());
962  if (!w) {
963  return {};
964  }
965  return w->selectionAsMessageItemListId(includeCollapsedChildren);
966 }
967 
969 {
970  auto w = static_cast<Widget *>(currentWidget());
971  if (!w) {
972  return {};
973  }
974  return w->currentThreadAsMessageList();
975 }
976 
977 Akonadi::Item::List Pane::itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
978 {
979  auto w = static_cast<Widget *>(currentWidget());
980  if (w) {
981  return w->itemListFromPersistentSet(ref);
982  }
983  return {};
984 }
985 
986 void Pane::deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
987 {
988  auto w = static_cast<Widget *>(currentWidget());
989  if (w) {
990  w->deletePersistentSet(ref);
991  }
992 }
993 
994 void Pane::markMessageItemsAsAboutToBeRemoved(MessageList::Core::MessageItemSetReference ref, bool bMark)
995 {
996  auto w = static_cast<Widget *>(currentWidget());
997  if (w) {
998  w->markMessageItemsAsAboutToBeRemoved(ref, bMark);
999  }
1000 }
1001 
1003 {
1004  auto w = static_cast<Widget *>(currentWidget());
1005  if (!w) {
1006  return {};
1007  }
1008  return w->currentFilterStatus();
1009 }
1010 
1011 Core::QuickSearchLine::SearchOptions Pane::currentOptions() const
1012 {
1013  auto w = static_cast<Widget *>(currentWidget());
1014  if (!w) {
1015  return Core::QuickSearchLine::SearchEveryWhere;
1016  }
1017  return w->currentOptions();
1018 }
1019 
1021 {
1022  auto w = static_cast<Widget *>(currentWidget());
1023  if (w) {
1024  return w->currentFilterSearchString();
1025  }
1026  return {};
1027 }
1028 
1029 bool Pane::isThreaded() const
1030 {
1031  auto w = static_cast<Widget *>(currentWidget());
1032  if (w) {
1033  return w->isThreaded();
1034  }
1035  return false;
1036 }
1037 
1039 {
1040  auto w = static_cast<Widget *>(currentWidget());
1041  if (w) {
1042  return w->selectionEmpty();
1043  }
1044  return false;
1045 }
1046 
1048  Akonadi::Item::List &selectedVisibleItems,
1049  bool *allSelectedBelongToSameThread,
1050  bool includeCollapsedChildren) const
1051 {
1052  auto w = static_cast<Widget *>(currentWidget());
1053  if (!w) {
1054  return false;
1055  }
1056 
1057  return w->getSelectionStats(selectedItems, selectedVisibleItems, allSelectedBelongToSameThread, includeCollapsedChildren);
1058 }
1059 
1060 MessageList::Core::MessageItemSetReference Pane::selectionAsPersistentSet(bool includeCollapsedChildren) const
1061 {
1062  auto w = static_cast<Widget *>(currentWidget());
1063  if (w) {
1064  return w->selectionAsPersistentSet(includeCollapsedChildren);
1065  }
1066  return -1;
1067 }
1068 
1069 MessageList::Core::MessageItemSetReference Pane::currentThreadAsPersistentSet() const
1070 {
1071  auto w = static_cast<Widget *>(currentWidget());
1072  if (w) {
1073  return w->currentThreadAsPersistentSet();
1074  }
1075  return -1;
1076 }
1077 
1079 {
1080  auto w = static_cast<Widget *>(currentWidget());
1081  if (w) {
1082  QWidget *view = w->view();
1083  if (view) {
1084  view->setFocus();
1085  }
1086  }
1087 }
1088 
1090 {
1091  d->updateTabControls();
1092 }
1093 
1095 {
1096  auto w = static_cast<Widget *>(currentWidget());
1097  if (w) {
1098  return w->view()->selectionModel();
1099  }
1100  return nullptr;
1101 }
1102 
1103 void Pane::resetModelStorage()
1104 {
1105  auto w = static_cast<Widget *>(currentWidget());
1106  if (w) {
1107  auto m = static_cast<MessageList::StorageModel *>(w->storageModel());
1108  if (m) {
1109  m->resetModelStorage();
1110  }
1111  }
1112 }
1113 
1114 void Pane::setPreferEmptyTab(bool emptyTab)
1115 {
1116  d->mPreferEmptyTab = emptyTab;
1117 }
1118 
1119 void Pane::saveCurrentSelection()
1120 {
1121  for (int i = 0; i < count(); ++i) {
1122  auto w = qobject_cast<Widget *>(widget(i));
1123  if (w) {
1124  w->saveCurrentSelection();
1125  }
1126  }
1127 }
1128 
1129 void Pane::updateTagComboBox()
1130 {
1131  for (int i = 0; i < count(); ++i) {
1132  auto w = qobject_cast<Widget *>(widget(i));
1133  if (w) {
1134  w->populateStatusFilterCombo();
1135  }
1136  }
1137 }
1138 
1139 void Pane::writeConfig(bool restoreSession)
1140 {
1141  KConfigGroup conf(MessageList::MessageListSettings::self()->config(), "MessageListPane");
1142 
1143  // Delete list before
1144  const QStringList list = MessageList::MessageListSettings::self()->config()->groupList().filter(QRegularExpression(QStringLiteral("MessageListTab\\d+")));
1145  for (const QString &group : list) {
1146  MessageList::MessageListSettings::self()->config()->deleteGroup(group);
1147  }
1148 
1149  if (restoreSession) {
1150  conf.writeEntry(QStringLiteral("currentIndex"), currentIndex());
1151 
1152  int elementTab = 0;
1153  for (int i = 0; i < count(); ++i) {
1154  auto w = qobject_cast<Widget *>(widget(i));
1155  if (w && w->currentCollection().isValid()) {
1156  KConfigGroup grp(MessageList::MessageListSettings::self()->config(), QStringLiteral("MessageListTab%1").arg(elementTab));
1157  grp.writeEntry(QStringLiteral("collectionId"), w->currentCollection().id());
1158  grp.writeEntry(QStringLiteral("HeaderState"), w->view()->header()->saveState());
1159  elementTab++;
1160  }
1161  }
1162  conf.writeEntry(QStringLiteral("tabNumber"), elementTab);
1163  }
1164  conf.sync();
1165 }
1166 
1167 void Pane::readConfig(bool restoreSession)
1168 {
1169  if (MessageList::MessageListSettings::self()->config()->hasGroup(QStringLiteral("MessageListPane"))) {
1170  KConfigGroup conf(MessageList::MessageListSettings::self()->config(), "MessageListPane");
1171  const int numberOfTab = conf.readEntry(QStringLiteral("tabNumber"), 0);
1172  if (numberOfTab == 0) {
1173  createNewTab();
1174  } else {
1175  for (int i = 0; i < numberOfTab; ++i) {
1176  createNewTab();
1177  restoreHeaderSettings(i, restoreSession);
1178  }
1179  setCurrentIndex(conf.readEntry(QStringLiteral("currentIndex"), 0));
1180  }
1181  } else {
1182  createNewTab();
1183  restoreHeaderSettings(0, false);
1184  }
1185 }
1186 
1187 void Pane::restoreHeaderSettings(int index, bool restoreSession)
1188 {
1189  KConfigGroup grp(MessageList::MessageListSettings::self()->config(), QStringLiteral("MessageListTab%1").arg(index));
1190  if (grp.exists()) {
1191  auto w = qobject_cast<Widget *>(widget(index));
1192  if (w) {
1193  w->view()->header()->restoreState(grp.readEntry(QStringLiteral("HeaderState"), QByteArray()));
1194  }
1195  if (restoreSession) {
1196  const Akonadi::Collection::Id id = grp.readEntry(QStringLiteral("collectionId"), -1);
1197  if (id != -1) {
1198  Akonadi::ETMViewStateSaver *saver = new Akonadi::ETMViewStateSaver;
1199  saver->setSelectionModel(d->mSelectionModel);
1200  saver->selectCollections(Akonadi::Collection::List() << Akonadi::Collection(id));
1201  saver->restoreCurrentItem(QString::fromLatin1("c%1").arg(id));
1202  saver->restoreState(grp);
1203  }
1204  }
1205  }
1206 }
1207 
1208 bool Pane::searchEditHasFocus() const
1209 {
1210  auto w = static_cast<Widget *>(currentWidget());
1211  if (w) {
1212  return w->searchEditHasFocus();
1213  }
1214  return false;
1215 }
1216 
1217 void Pane::sortOrderMenuAboutToShow()
1218 {
1219  auto menu = qobject_cast<QMenu *>(sender());
1220  if (!menu) {
1221  return;
1222  }
1223  const Widget *const w = static_cast<Widget *>(currentWidget());
1224  w->view()->sortOrderMenuAboutToShow(menu);
1225 }
1226 
1227 void Pane::aggregationMenuAboutToShow()
1228 {
1229  auto menu = qobject_cast<QMenu *>(sender());
1230  if (!menu) {
1231  return;
1232  }
1233  const Widget *const w = static_cast<Widget *>(currentWidget());
1234  w->view()->aggregationMenuAboutToShow(menu);
1235 }
1236 
1237 void Pane::themeMenuAboutToShow()
1238 {
1239  auto menu = qobject_cast<QMenu *>(sender());
1240  if (!menu) {
1241  return;
1242  }
1243  const Widget *const w = static_cast<Widget *>(currentWidget());
1244  w->view()->themeMenuAboutToShow(menu);
1245 }
1246 
1247 void Pane::populateStatusFilterCombo()
1248 {
1249  for (int i = 0; i < count(); ++i) {
1250  auto w = qobject_cast<Widget *>(widget(i));
1251  if (w) {
1253  }
1254  }
1255 }
1256 
1257 #include "moc_pane.cpp"
void append(const T &value)
T & first()
const QList< QKeySequence > & tabPrev()
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 ...
Definition: pane.cpp:994
bool selectionEmpty() const
Fast function that determines if the selection is empty.
Definition: pane.cpp:1038
int indexOf(QWidget *w) const const
bool selectLastMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem)
Selects the last message item in the view that matches the specified Core::MessageTypeFilter.
Definition: pane.cpp:405
DisplayRole
MouseButtonPress
void focusQuickSearch(const QString &selectedText=QString())
Sets the focus on the quick search line of the currently active tab.
Definition: pane.cpp:472
QStringView right(qsizetype length) const const
QPoint mapFrom(const QWidget *parent, const QPoint &pos) const const
QVector< qlonglong > selectionAsMessageItemListId(bool includeCollapsedChildren=true) const
Returns the currently selected Items id(bound to current StorageModel).
Definition: pane.cpp:959
void reloadGlobalConfiguration()
Reloads global configuration and eventually reloads all the views.
Definition: pane.cpp:1089
const QItemSelection selection() const const
const QAbstractItemModel * model() const const
KMime::Message::Ptr currentMessage() const
Returns the current message for the list as KMime::Message::Ptr.
Definition: pane.cpp:921
void messageSelected(const Akonadi::Item &item)
Emitted when a message is selected (that is, single clicked and thus made current in the view) Note t...
void customContextMenuRequested(const QPoint &pos)
MessageList::Core::MessageItemSetReference selectionAsPersistentSet(bool includeCollapsedChildren=true) const
Return a persistent set from current selection.
Definition: pane.cpp:1060
void setCurrentThreadExpanded(bool expand)
If expand is true then it expands the current thread, otherwise collapses it.
Definition: pane.cpp:433
void setTabText(int index, const QString &label)
void messageSelected(const Akonadi::Item &item)
Emitted when a message is selected (that is, single clicked and thus made current in the view) Note t...
void clicked(bool checked)
QIcon fromTheme(const QString &name)
void chop(int n)
int indexOf(const T &value, int from) const const
void selectFocusedMessageItem(bool centerItem)
Selects the currently focused message item.
Definition: pane.cpp:377
QObject * sender() const const
bool isThreaded() const
Returns true if the current Aggregation is threaded, false otherwise (or if there is no current Aggre...
Definition: pane.cpp:1029
CustomContextMenu
void setTabsClosable(bool closeable)
TopLeftCorner
void setMovable(bool movable)
int tabAt(const QPoint &position) const const
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
MiddleButton
void selectionChanged()
Emitted when the selection in the view changes.
void setCornerWidget(QWidget *widget, Qt::Corner corner)
View * view() const
Returns the View attached to this Widget.
Definition: widgetbase.cpp:386
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
The Akonadi specific implementation of the Core::Widget.
Definition: widget.h:32
virtual bool eventFilter(QObject *watched, QEvent *event)
MessageList::Core::MessageItemSetReference currentThreadAsPersistentSet() const
Return a persistent set from current thread.
Definition: pane.cpp:1069
void setIcon(const QIcon &icon)
Akonadi::Item::List itemListFromPersistentSet(MessageList::Core::MessageItemSetReference ref)
Return Akonadi::Item from messageItemReference.
Definition: pane.cpp:977
QStringList filter(QStringView str, Qt::CaseSensitivity cs) const const
QString i18n(const char *text, const TYPE &arg...)
void setCurrentFolder(const Akonadi::Collection &fld, const QModelIndex &etmIndex, bool preferEmptyTab=false, MessageList::Core::PreSelectionMode preSelectionMode=MessageList::Core::PreSelectLastSelected, const QString &overrideLabel=QString())
Sets the current folder to be displayed by this Pane.
Definition: pane.cpp:776
bool selectFirstMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem)
Selects the first message item in the view that matches the specified Core::MessageTypeFilter.
Definition: pane.cpp:390
const QList< QKeySequence > & tabNext()
QWidget * widget(int index) const const
void installEventFilter(QObject *filterObj)
bool isEmpty() const const
void focusView()
Sets the focus on the view of the currently active tab.
Definition: pane.cpp:1078
void currentChanged(int index)
The Akonadi specific implementation of the Core::StorageModel.
Definition: storagemodel.h:35
void messageStatusChangeRequest(const Akonadi::Item &item, const Akonadi::MessageStatus &set, const Akonadi::MessageStatus &clear)
Emitted when a message wants its status to be changed.
bool isEmpty() const const
PreSelectionMode
Pre-selection is the action of automatically selecting a message just after the folder has finished l...
void setCurrentWidget(QWidget *widget)
Akonadi::Item::List currentThreadAsMessageList() const
Returns the Akonadi::Item bound to the current StorageModel that are part of the current thread.
Definition: pane.cpp:968
KSharedConfigPtr config()
bool selectPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, bool loop)
Selects the previous message item in the view.
Definition: pane.cpp:329
QWidget * currentWidget() const const
void setEnabled(bool)
void setXmlGuiClient(KXMLGUIClient *xmlGuiClient)
Sets the XML GUI client which the pane is used in.
Definition: pane.cpp:196
QItemSelectionModel * currentItemSelectionModel()
Returns the QItemSelectionModel for the currently displayed tab.
Definition: pane.cpp:1094
bool isRightToLeft()
void setAllGroupsExpanded(bool expand)
If expand is true then it expands all the groups (only the toplevel group item: inner threads are NOT...
Definition: pane.cpp:459
QString currentFilterSearchString() const
Returns the search term in the current quicksearch field.
Definition: pane.cpp:1020
virtual void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
void populateStatusFilterCombo()
This is called to setup the status filter's QComboBox.
Definition: widgetbase.cpp:212
QString label(StandardShortcut id)
void selectAll()
Selects all the items in the current folder.
Definition: pane.cpp:420
void setAllThreadsExpanded(bool expand)
If expand is true then it expands all the threads, otherwise collapses them.
Definition: pane.cpp:446
void statusMessage(const QString &message)
Notify the outside when updating the status bar with a message could be useful.
QTabBar * tabBar() const const
bool selectNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour, bool centerItem, bool loop)
Selects the next message item in the view.
Definition: pane.cpp:311
void triggered(bool checked)
void messageActivated(const Akonadi::Item &item)
Emitted when a message is doubleclicked or activated by other input means.
void statusMessage(const QString &message)
Notify the outside when updating the status bar with a message could be useful.
QModelIndexList selectedRows(int column) const const
QString fromLatin1(const char *str, int size)
void messageActivated(const Akonadi::Item &item)
Emitted when a message is doubleclicked or activated by other input means.
QItemSelectionModel * createNewTab()
Add a new tab to the Pane and select it.
Definition: pane.cpp:811
int addTab(QWidget *page, const QString &label)
bool focusNextMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
Focuses the next message item in the view without actually selecting it.
Definition: pane.cpp:347
void selectionChanged()
Emitted when the selection in the view changes.
ExistingSelectionBehaviour
This enum is used in the view message selection functions (for instance View::selectNextMessage())
This is the main MessageList panel for Akonadi applications.
Definition: pane.h:45
QVector< KMime::Message::Ptr > selectionAsMessageList(bool includeCollapsedChildren=true) const
Returns the currently selected KMime::Message::Ptr (bound to current StorageModel).
Definition: pane.cpp:932
bool getSelectionStats(Akonadi::Item::List &selectedItems, Akonadi::Item::List &selectedVisibleItems, bool *allSelectedBelongToSameThread, bool includeCollapsedChildren=true) const
Fills the lists of the selected message serial numbers and of the selected+visible ones.
Definition: pane.cpp:1047
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setDocumentMode(bool set)
bool focusPreviousMessageItem(MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop)
Focuses the previous message item in the view without actually selecting it.
Definition: pane.cpp:362
void messageStatusChangeRequest(const Akonadi::Item &item, const Akonadi::MessageStatus &set, const Akonadi::MessageStatus &clear)
Emitted when a message wants its status to be changed.
void setTabIcon(int index, const QIcon &icon)
QChar * data()
MessageTypeFilter
This enum is used in the view message selection functions (for instance View::nextMessageItem()).
QVector< Akonadi::MessageStatus > currentFilterStatus() const
Returns the Akonadi::MessageStatus in the current quicksearch field.
Definition: pane.cpp:1002
QString asprintf(const char *cformat,...)
virtual void clear()
void setFocus()
Akonadi::Item::List selectionAsMessageItemList(bool includeCollapsedChildren=true) const
Returns the currently selected Items (bound to current StorageModel).
Definition: pane.cpp:941
QObject * parent() const const
const QAbstractItemModel * model() const const
void deletePersistentSet(MessageList::Core::MessageItemSetReference ref)
Deletes the persistent set pointed by the specified reference.
Definition: pane.cpp:986
Akonadi::Item currentItem() const
Returns the current message for the list as Akonadi::Item.
Definition: pane.cpp:910
void tabCloseRequested(int index)
virtual bool event(QEvent *ev) override
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Apr 1 2023 04:01:57 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.