Mailcommon

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

KDE's Doxygen guidelines are available online.