Mailcommon

foldertreeview.cpp
1 /*
2 
3  SPDX-FileCopyrightText: 2009-2022 Laurent Montel <[email protected]>
4 
5  SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "foldertreeview.h"
9 #include "kernel/mailkernel.h"
10 #include "util/mailutil_p.h"
11 
12 #include <Akonadi/CollectionStatistics>
13 #include <Akonadi/CollectionStatisticsDelegate>
14 #include <Akonadi/EntityTreeModel>
15 
16 #include <KConfigGroup>
17 #include <KGuiItem>
18 #include <KLocalizedString>
19 #include <KMessageBox>
20 #include <QMenu>
21 
22 #include <QActionGroup>
23 #include <QHeaderView>
24 #include <QMouseEvent>
25 
26 using namespace MailCommon;
27 
28 FolderTreeView::FolderTreeView(QWidget *parent, bool showUnreadCount)
29  : Akonadi::EntityTreeView(parent)
30 {
31  init(showUnreadCount);
32 }
33 
34 FolderTreeView::FolderTreeView(KXMLGUIClient *xmlGuiClient, QWidget *parent, bool showUnreadCount)
35  : Akonadi::EntityTreeView(xmlGuiClient, parent)
36 {
37  init(showUnreadCount);
38 }
39 
40 FolderTreeView::~FolderTreeView() = default;
41 
42 void FolderTreeView::disableSaveConfig()
43 {
44  mbDisableSaveConfig = true;
45 }
46 
47 void FolderTreeView::setTooltipsPolicy(FolderTreeWidget::ToolTipDisplayPolicy policy)
48 {
49  if (mToolTipDisplayPolicy == policy) {
50  return;
51  }
52 
53  mToolTipDisplayPolicy = policy;
54  Q_EMIT changeTooltipsPolicy(mToolTipDisplayPolicy);
55  writeConfig();
56 }
57 
58 void FolderTreeView::disableContextMenuAndExtraColumn()
59 {
60  mbDisableContextMenuAndExtraColumn = true;
61  const int nbColumn = header()->count();
62  for (int i = 1; i < nbColumn; ++i) {
63  setColumnHidden(i, true);
64  }
65 }
66 
67 void FolderTreeView::init(bool showUnreadCount)
68 {
69  setIconSize(QSize(22, 22));
72  mToolTipDisplayPolicy = FolderTreeWidget::DisplayAlways;
73 
75  connect(header(), &QWidget::customContextMenuRequested, this, &FolderTreeView::slotHeaderContextMenuRequested);
76 
77  mCollectionStatisticsDelegate = new Akonadi::CollectionStatisticsDelegate(this);
78  mCollectionStatisticsDelegate->setProgressAnimationEnabled(true);
79  setItemDelegate(mCollectionStatisticsDelegate);
80  mCollectionStatisticsDelegate->setUnreadCountShown(showUnreadCount && !header()->isSectionHidden(1));
81 }
82 
83 void FolderTreeView::showStatisticAnimation(bool anim)
84 {
85  mCollectionStatisticsDelegate->setProgressAnimationEnabled(anim);
86 }
87 
88 void FolderTreeView::writeConfig()
89 {
90  if (mbDisableSaveConfig) {
91  return;
92  }
93 
94  KConfigGroup myGroup(KernelIf->config(), "MainFolderView");
95  myGroup.writeEntry("IconSize", iconSize().width());
96  myGroup.writeEntry("ToolTipDisplayPolicy", (int)mToolTipDisplayPolicy);
97  myGroup.writeEntry("SortingPolicy", (int)mSortingPolicy);
98 }
99 
100 void FolderTreeView::readConfig()
101 {
102  KConfigGroup myGroup(KernelIf->config(), "MainFolderView");
103  int iIconSize = myGroup.readEntry("IconSize", iconSize().width());
104  if ((iIconSize < 16) || (iIconSize > 32)) {
105  iIconSize = 22;
106  }
107  setIconSize(QSize(iIconSize, iIconSize));
108  mToolTipDisplayPolicy =
109  static_cast<FolderTreeWidget::ToolTipDisplayPolicy>(myGroup.readEntry("ToolTipDisplayPolicy", static_cast<int>(FolderTreeWidget::DisplayAlways)));
110 
111  Q_EMIT changeTooltipsPolicy(mToolTipDisplayPolicy);
112 
113  setSortingPolicy((FolderTreeWidget::SortingPolicy)myGroup.readEntry("SortingPolicy", (int)FolderTreeWidget::SortByCurrentColumn), false);
114 }
115 
116 void FolderTreeView::slotHeaderContextMenuRequested(const QPoint &pnt)
117 {
118  if (mbDisableContextMenuAndExtraColumn) {
119  readConfig();
120  return;
121  }
122 
123  // the menu for the columns
124  QMenu menu;
125  QAction *act = nullptr;
126  const int nbColumn = header()->count();
127  if (nbColumn > 1) {
128  menu.addSection(i18n("View Columns"));
129  for (int i = 1; i < nbColumn; ++i) {
130  act = menu.addAction(model()->headerData(i, Qt::Horizontal).toString());
131  act->setCheckable(true);
132  act->setChecked(!header()->isSectionHidden(i));
133  act->setData(QVariant(i));
134  connect(act, &QAction::triggered, this, &FolderTreeView::slotHeaderContextMenuChangeHeader);
135  }
136  }
137 
138  menu.addSection(i18n("Icon Size"));
139 
140  static const int icon_sizes[] = {16, 22, 32};
141 
142  auto grp = new QActionGroup(&menu);
143  for (int i : icon_sizes) {
144  act = menu.addAction(QStringLiteral("%1x%2").arg(i).arg(i));
145  act->setCheckable(true);
146  grp->addAction(act);
147  if (iconSize().width() == i) {
148  act->setChecked(true);
149  }
150  act->setData(QVariant(i));
151 
152  connect(act, &QAction::triggered, this, &FolderTreeView::slotHeaderContextMenuChangeIconSize);
153  }
154  menu.addSection(i18n("Display Tooltips"));
155 
156  grp = new QActionGroup(&menu);
157 
158  act = menu.addAction(i18nc("@action:inmenu Always display tooltips", "Always"));
159  act->setCheckable(true);
160  grp->addAction(act);
161  act->setChecked(mToolTipDisplayPolicy == FolderTreeWidget::DisplayAlways);
163  connect(act, &QAction::triggered, this, &FolderTreeView::slotHeaderContextMenuChangeToolTipDisplayPolicy);
164 
165  act = menu.addAction(i18nc("@action:inmenu Never display tooltips.", "Never"));
166  act->setCheckable(true);
167  grp->addAction(act);
168  act->setChecked(mToolTipDisplayPolicy == FolderTreeWidget::DisplayNever);
170  connect(act, &QAction::triggered, this, &FolderTreeView::slotHeaderContextMenuChangeToolTipDisplayPolicy);
171 
172  menu.addSection(i18nc("@action:inmenu", "Sort Items"));
173 
174  grp = new QActionGroup(&menu);
175 
176  act = menu.addAction(i18nc("@action:inmenu", "Automatically, by Current Column"));
177  act->setCheckable(true);
178  grp->addAction(act);
179  act->setChecked(mSortingPolicy == FolderTreeWidget::SortByCurrentColumn);
181  connect(act, &QAction::triggered, this, &FolderTreeView::slotHeaderContextMenuChangeSortingPolicy);
182 
183  act = menu.addAction(i18nc("@action:inmenu", "Manually, by Drag And Drop"));
184  act->setCheckable(true);
185  grp->addAction(act);
186  act->setChecked(mSortingPolicy == FolderTreeWidget::SortByDragAndDropKey);
188  connect(act, &QAction::triggered, this, &FolderTreeView::slotHeaderContextMenuChangeSortingPolicy);
189 
190  menu.exec(header()->mapToGlobal(pnt));
191 }
192 
193 void FolderTreeView::slotHeaderContextMenuChangeSortingPolicy(bool)
194 {
195  auto act = qobject_cast<QAction *>(sender());
196  if (!act) {
197  return;
198  }
199 
200  QVariant data = act->data();
201 
202  bool ok;
203  int policy = data.toInt(&ok);
204  if (!ok) {
205  return;
206  }
207 
208  setSortingPolicy((FolderTreeWidget::SortingPolicy)policy, true);
209 }
210 
211 void FolderTreeView::setSortingPolicy(FolderTreeWidget::SortingPolicy policy, bool writeInConfig)
212 {
213  if (mSortingPolicy == policy) {
214  return;
215  }
216 
217  mSortingPolicy = policy;
218  switch (mSortingPolicy) {
220  header()->setSectionsClickable(true);
221  header()->setSortIndicatorShown(true);
222  setSortingEnabled(true);
223  Q_EMIT manualSortingChanged(false);
224  break;
225 
227  header()->setSectionsClickable(false);
228  header()->setSortIndicatorShown(false);
229 
230  setSortingEnabled(false); // hack for qutie bug: this call shouldn't be here at all
231  Q_EMIT manualSortingChanged(true);
232 
233  break;
234  default:
235  // should never happen
236  break;
237  }
238  if (writeInConfig) {
239  writeConfig();
240  }
241 }
242 
243 void FolderTreeView::slotHeaderContextMenuChangeToolTipDisplayPolicy(bool)
244 {
245  auto act = qobject_cast<QAction *>(sender());
246  if (!act) {
247  return;
248  }
249 
250  QVariant data = act->data();
251 
252  bool ok;
253  const int id = data.toInt(&ok);
254  if (!ok) {
255  return;
256  }
257  Q_EMIT changeTooltipsPolicy((FolderTreeWidget::ToolTipDisplayPolicy)id);
258 }
259 
260 void FolderTreeView::slotHeaderContextMenuChangeHeader(bool)
261 {
262  auto act = qobject_cast<QAction *>(sender());
263  if (!act) {
264  return;
265  }
266 
267  QVariant data = act->data();
268 
269  bool ok;
270  const int id = data.toInt(&ok);
271  if (!ok) {
272  return;
273  }
274 
275  if (id >= header()->count()) {
276  return;
277  }
278 
279  if (id == 1) {
280  mCollectionStatisticsDelegate->setUnreadCountShown(!act->isChecked());
281  }
282 
283  setColumnHidden(id, !act->isChecked());
284 }
285 
286 void FolderTreeView::slotHeaderContextMenuChangeIconSize(bool)
287 {
288  auto act = qobject_cast<QAction *>(sender());
289  if (!act) {
290  return;
291  }
292 
293  QVariant data = act->data();
294 
295  bool ok;
296  const int size = data.toInt(&ok);
297  if (!ok) {
298  return;
299  }
300 
301  const QSize newIconSize(QSize(size, size));
302  if (newIconSize == iconSize()) {
303  return;
304  }
305  setIconSize(newIconSize);
306 
307  writeConfig();
308 }
309 
310 void FolderTreeView::setCurrentModelIndex(const QModelIndex &index)
311 {
312  if (index.isValid()) {
313  clearSelection();
314  scrollTo(index);
316  }
317 }
318 
319 void FolderTreeView::selectModelIndex(const QModelIndex &index)
320 {
321  if (index.isValid()) {
322  scrollTo(index);
324  }
325 }
326 
327 void FolderTreeView::slotSelectFocusFolder()
328 {
329  const QModelIndex index = currentIndex();
330  if (index.isValid()) {
331  setCurrentIndex(index);
332  }
333 }
334 
335 void FolderTreeView::slotFocusNextFolder()
336 {
337  const QModelIndex nextFolder = selectNextFolder(currentIndex());
338 
339  if (nextFolder.isValid()) {
340  expand(nextFolder);
341  setCurrentModelIndex(nextFolder);
342  }
343 }
344 
345 QModelIndex FolderTreeView::selectNextFolder(const QModelIndex &current)
346 {
347  QModelIndex below;
348  if (current.isValid()) {
349  model()->fetchMore(current);
350  if (model()->hasChildren(current)) {
351  expand(current);
352  below = indexBelow(current);
353  } else if (current.row() < model()->rowCount(model()->parent(current)) - 1) {
354  below = model()->index(current.row() + 1, current.column(), model()->parent(current));
355  } else {
356  below = indexBelow(current);
357  }
358  }
359  return below;
360 }
361 
362 void FolderTreeView::slotFocusPrevFolder()
363 {
364  const QModelIndex current = currentIndex();
365  if (current.isValid()) {
366  QModelIndex above = indexAbove(current);
367  setCurrentModelIndex(above);
368  }
369 }
370 
371 void FolderTreeView::slotFocusFirstFolder()
372 {
374  if (first.isValid()) {
375  setCurrentModelIndex(first);
376  }
377 }
378 
379 void FolderTreeView::slotFocusLastFolder()
380 {
382  if (last.isValid()) {
383  setCurrentModelIndex(last);
384  }
385 }
386 
387 void FolderTreeView::selectNextUnreadFolder(bool confirm)
388 {
389  // find next unread collection starting from current position
390  if (!trySelectNextUnreadFolder(currentIndex(), ForwardSearch, confirm)) {
391  // if there is none, jump to the last collection and try again
392  trySelectNextUnreadFolder(model()->index(0, 0), ForwardSearch, confirm);
393  }
394 }
395 
396 // helper method to find last item in the model tree
397 static QModelIndex lastChildOf(QAbstractItemModel *model, const QModelIndex &current)
398 {
399  if (model->rowCount(current) == 0) {
400  return current;
401  }
402 
403  return lastChildOf(model, model->index(model->rowCount(current) - 1, 0, current));
404 }
405 
406 void FolderTreeView::selectPrevUnreadFolder(bool confirm)
407 {
408  // find next unread collection starting from current position
409  if (!trySelectNextUnreadFolder(currentIndex(), BackwardSearch, confirm)) {
410  // if there is none, jump to top and try again
411  const QModelIndex index = lastChildOf(model(), QModelIndex());
412  trySelectNextUnreadFolder(index, BackwardSearch, confirm);
413  }
414 }
415 
416 bool FolderTreeView::trySelectNextUnreadFolder(const QModelIndex &current, SearchDirection direction, bool confirm)
417 {
418  QModelIndex index = current;
419  while (true) {
420  index = nextUnreadCollection(index, direction);
421 
422  if (!index.isValid()) {
423  return false;
424  }
425 
427  if (collection == Kernel::self()->trashCollectionFolder() || collection == Kernel::self()->outboxCollectionFolder()) {
428  continue;
429  }
430 
431  if (ignoreUnreadFolder(collection, confirm)) {
432  continue;
433  }
434 
435  if (allowedToEnterFolder(collection, confirm)) {
436  expand(index);
437  setCurrentIndex(index);
438  selectModelIndex(index);
439  return true;
440  } else {
441  return false;
442  }
443  }
444 
445  return false;
446 }
447 
448 bool FolderTreeView::ignoreUnreadFolder(const Akonadi::Collection &collection, bool confirm) const
449 {
450  if (!confirm) {
451  return false;
452  }
453 
454  // Skip drafts, sent mail and templates as well, when reading mail with the
455  // space bar - but not when changing into the next folder with unread mail
456  // via ctrl+ or ctrl- so we do this only if (confirm == true), which means
457  // we are doing readOn.
458 
459  return collection == Kernel::self()->draftsCollectionFolder() || collection == Kernel::self()->templatesCollectionFolder()
460  || collection == Kernel::self()->sentCollectionFolder();
461 }
462 
463 bool FolderTreeView::allowedToEnterFolder(const Akonadi::Collection &collection, bool confirm) const
464 {
465  if (!confirm) {
466  return true;
467  }
468 
469  // warn user that going to next folder - but keep track of
470  // whether he wishes to be notified again in "AskNextFolder"
471  // parameter (kept in the config file for kmail)
472  const int result = KMessageBox::questionYesNo(const_cast<FolderTreeView *>(this),
473  i18n("<qt>Go to the next unread message in folder <b>%1</b>?</qt>", collection.name()),
474  i18n("Go to Next Unread Message"),
475  KGuiItem(i18n("Go To")),
476  KGuiItem(i18n("Do Not Go To")), // defaults
477  QStringLiteral(":kmail_AskNextFolder"),
479 
480  return result == KMessageBox::Yes;
481 }
482 
483 bool FolderTreeView::isUnreadFolder(const QModelIndex &current, QModelIndex &index, FolderTreeView::Move move, bool confirm)
484 {
485  if (current.isValid()) {
486  if (move == FolderTreeView::Next) {
487  index = selectNextFolder(current);
488  } else if (move == FolderTreeView::Previous) {
489  index = indexAbove(current);
490  }
491 
492  if (index.isValid()) {
493  const auto collection = index.model()->data(current, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
494 
495  if (collection.isValid()) {
496  if (collection.statistics().unreadCount() > 0) {
497  if (!confirm) {
498  selectModelIndex(current);
499  return true;
500  } else {
501  // Skip drafts, sent mail and templates as well, when reading mail with the
502  // space bar - but not when changing into the next folder with unread mail
503  // via ctrl+ or ctrl- so we do this only if (confirm == true), which means
504  // we are doing readOn.
505 
506  if (collection == Kernel::self()->draftsCollectionFolder() || collection == Kernel::self()->templatesCollectionFolder()
507  || collection == Kernel::self()->sentCollectionFolder()) {
508  return false;
509  }
510 
511  // warn user that going to next folder - but keep track of
512  // whether he wishes to be notified again in "AskNextFolder"
513  // parameter (kept in the config file for kmail)
515  i18n("<qt>Go to the next unread message in folder <b>%1</b>?</qt>", collection.name()),
516  i18n("Go to Next Unread Message"),
517  KGuiItem(i18n("Go To")),
518  KGuiItem(i18n("Do Not Go To")), // defaults
519  QStringLiteral(":kmail_AskNextFolder"),
521  == KMessageBox::No) {
522  return true; // assume selected (do not continue looping)
523  }
524 
525  selectModelIndex(current);
526  return true;
527  }
528  }
529  }
530  }
531  }
532  return false;
533 }
534 
535 Akonadi::Collection FolderTreeView::currentFolder() const
536 {
537  const QModelIndex current = currentIndex();
538  if (current.isValid()) {
539  const auto collection = current.model()->data(current, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
540  return collection;
541  }
542  return {};
543 }
544 
545 void FolderTreeView::mousePressEvent(QMouseEvent *e)
546 {
547  const bool buttonPressedIsMiddle = (e->button() == Qt::MiddleButton);
548  Q_EMIT newTabRequested(buttonPressedIsMiddle);
549  EntityTreeView::mousePressEvent(e);
550 }
551 
552 void FolderTreeView::restoreHeaderState(const QByteArray &data)
553 {
554  if (data.isEmpty()) {
555  const int nbColumn = header()->count();
556  for (int i = 1; i < nbColumn; ++i) {
557  setColumnHidden(i, true);
558  }
559  } else {
560  header()->restoreState(data);
561  }
562  mCollectionStatisticsDelegate->setUnreadCountShown(header()->isSectionHidden(1));
563 }
564 
565 void FolderTreeView::updatePalette()
566 {
567  mCollectionStatisticsDelegate->updatePalette();
568 }
569 
570 void FolderTreeView::keyboardSearch(const QString &)
571 {
572  // Disable keyboardSearch: it interfers with filtering in the
573  // FolderSelectionDialog. We don't want it in KMail main window
574  // either because KMail has one-letter keyboard shortcuts.
575 }
576 
577 void FolderTreeView::setEnableDragDrop(bool enabled)
578 {
579 #ifndef QT_NO_DRAGANDDROP
581 #endif
582 }
583 
584 QModelIndex FolderTreeView::indexBelow(const QModelIndex &current) const
585 {
586  // if we have children, return first child
587  if (model()->rowCount(current) > 0) {
588  return model()->index(0, 0, current);
589  }
590 
591  // if we have siblings, return next sibling
592  const QModelIndex parent = model()->parent(current);
593  const QModelIndex sibling = model()->index(current.row() + 1, 0, parent);
594 
595  if (sibling.isValid()) { // found valid sibling
596  return sibling;
597  }
598 
599  if (!parent.isValid()) { // our parent is the tree root and we have no siblings
600  return {}; // we reached the bottom of the tree
601  }
602 
603  // We are the last child, the next index to check is our uncle, parent's first sibling
604  const QModelIndex parentsSibling = parent.sibling(parent.row() + 1, 0);
605  if (parentsSibling.isValid()) {
606  return parentsSibling;
607  }
608 
609  // iterate over our parents back to root until we find a parent with a valid sibling
610  QModelIndex currentParent = parent;
611  QModelIndex grandParent = model()->parent(currentParent);
612  while (currentParent.isValid()) {
613  // check if the parent has children except from us
614  if (model()->rowCount(grandParent) > currentParent.row() + 1) {
615  const auto index = indexBelow(model()->index(currentParent.row() + 1, 0, grandParent));
616  if (index.isValid()) {
617  return index;
618  }
619  }
620 
621  currentParent = grandParent;
622  grandParent = model()->parent(currentParent);
623  }
624 
625  return {}; // nothing found -> end of tree
626 }
627 
628 QModelIndex FolderTreeView::lastChild(const QModelIndex &current) const
629 {
630  if (model()->rowCount(current) == 0) {
631  return current;
632  }
633 
634  return lastChild(model()->index(model()->rowCount(current) - 1, 0, current));
635 }
636 
637 QModelIndex FolderTreeView::indexAbove(const QModelIndex &current) const
638 {
639  const QModelIndex parent = model()->parent(current);
640 
641  if (current.row() == 0) {
642  // we have no previous siblings -> our parent is the next item above us
643  return parent;
644  }
645 
646  // find previous sibling
647  const QModelIndex previousSibling = model()->index(current.row() - 1, 0, parent);
648 
649  // the item above us is the last child (or grandchild, or grandgrandchild... etc)
650  // of our previous sibling
651  return lastChild(previousSibling);
652 }
653 
654 QModelIndex FolderTreeView::nextUnreadCollection(const QModelIndex &current, SearchDirection direction) const
655 {
656  QModelIndex index = current;
657  while (true) {
658  if (direction == ForwardSearch) {
659  index = indexBelow(index);
660  } else if (direction == BackwardSearch) {
661  index = indexAbove(index);
662  }
663 
664  if (!index.isValid()) { // reach end or top of the model
665  return {};
666  }
667 
668  // check if the index is a collection
670 
671  if (collection.isValid()) {
672  // check if it is unread
673  if (collection.statistics().unreadCount() > 0) {
674  if (!MailCommon::Util::ignoreNewMailInFolder(collection)) {
675  return index; // we found the next unread collection
676  }
677  }
678  }
679  }
680 
681  return {}; // no unread collection found
682 }
void setProgressAnimationEnabled(bool enable)
virtual void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
virtual QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override
int count() const const
virtual int rowCount(const QModelIndex &parent) const const=0
QAction * addSection(const QString &text)
void setUniformRowHeights(bool uniform)
Q_EMITQ_EMIT
Qt::MouseButton button() const const
virtual QVariant data(const QModelIndex &index, int role) const const=0
void customContextMenuRequested(const QPoint &pos)
QAbstractItemModel * model() const const
QCA_EXPORT void init()
int column() const const
SortingPolicy
The available sorting policies.
T value() const const
void setItemDelegate(QAbstractItemDelegate *delegate)
QItemSelectionModel * selectionModel() const const
QObject * sender() const const
@ DisplayAlways
Always display a tooltip when hovering over an item.
void setSectionsClickable(bool clickable)
@ DisplayNever
Nevery display tooltips.
CustomContextMenu
MiddleButton
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual QModelIndex parent(const QModelIndex &index) const const=0
QAction * addAction(const QString &text)
QHeaderView * header() const const
QVariant data(int role) const const
bool restoreState(const QByteArray &state)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const T &value)
Horizontal
void setIconSize(const QSize &size)
int toInt(bool *ok) const const
virtual void fetchMore(const QModelIndex &parent)
ToolTipDisplayPolicy
The possible tooltip display policies.
QPoint mapToGlobal(const QPoint &pos) const const
This is an enhanced EntityTreeView specially suited for the folders in KMail's main folder widget.
virtual void scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint hint) override
bool isValid() const const
void setCheckable(bool)
int row() const const
virtual void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
@ SortByCurrentColumn
Columns are clickable, sorting is by the current column.
void setSortingEnabled(bool enable)
QVariant data() const const
void setData(const QVariant &userData)
void setCurrentIndex(const QModelIndex &index)
void triggered(bool checked)
bool isEmpty() const const
@ SortByDragAndDropKey
Columns are NOT clickable, sorting is done by drag and drop.
void setSortIndicatorShown(bool show)
CollectionStatistics statistics() const
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 move(int x, int y)
bool isValid() const
void expand(const QModelIndex &index)
void setDragDropMode(QAbstractItemView::DragDropMode behavior)
QModelIndex currentIndex() const const
void setChecked(bool)
NoModifier
ButtonCode questionYesNo(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const QString &dontAskAgainName=QString(), Options options=Notify)
QObject * parent() const const
const QAbstractItemModel * model() const const
QAction * exec()
void setColumnHidden(int column, bool hide)
The filter dialog.
QString name() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Oct 1 2022 04:00:53 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.