Mailcommon

foldertreeview.cpp
1/*
2
3 SPDX-FileCopyrightText: 2009-2024 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);
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);
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{
375 if (first.isValid()) {
376 setCurrentModelIndex(first);
377 }
378}
379
380void FolderTreeView::slotFocusLastFolder()
381{
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
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
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"
void setProgressAnimationEnabled(bool enable)
CollectionStatistics statistics() const
bool isValid() const
QString name() const
This is an enhanced EntityTreeView specially suited for the folders in KMail's main folder widget.
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-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:18:39 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.