Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qabstractitemview.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qabstractitemview.h"
5
6#include <qpointer.h>
7#include <qapplication.h>
8#include <qclipboard.h>
9#include <qpainter.h>
10#include <qstyle.h>
11#if QT_CONFIG(draganddrop)
12#include <qdrag.h>
13#endif
14#include <qevent.h>
15#include <qscrollbar.h>
16#if QT_CONFIG(tooltip)
17#include <qtooltip.h>
18#endif
19#include <qdatetime.h>
20#if QT_CONFIG(lineedit)
21#include <qlineedit.h>
22#endif
23#if QT_CONFIG(spinbox)
24#include <qspinbox.h>
25#endif
26#include <qheaderview.h>
27#include <qstyleditemdelegate.h>
28#include <private/qabstractitemview_p.h>
29#include <private/qabstractitemmodel_p.h>
30#include <private/qapplication_p.h>
31#include <private/qguiapplication_p.h>
32#include <private/qscrollbar_p.h>
33#if QT_CONFIG(accessibility)
34#include <qaccessible.h>
35#endif
36#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
37# include <qscroller.h>
38#endif
39
40#include <algorithm>
41
43
45 : model(QAbstractItemModelPrivate::staticEmptyModel()),
46 itemDelegate(nullptr),
47 selectionModel(nullptr),
48 ctrlDragSelectionFlag(QItemSelectionModel::NoUpdate),
49 noSelectionOnMousePress(false),
50 selectionMode(QAbstractItemView::ExtendedSelection),
51 selectionBehavior(QAbstractItemView::SelectItems),
52 currentlyCommittingEditor(nullptr),
53 pressClosedEditor(false),
54 waitForIMCommit(false),
55 pressedModifiers(Qt::NoModifier),
56 pressedPosition(QPoint(-1, -1)),
57 pressedAlreadySelected(false),
58 releaseFromDoubleClick(false),
59 viewportEnteredNeeded(false),
60 state(QAbstractItemView::NoState),
61 stateBeforeAnimation(QAbstractItemView::NoState),
62 editTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed),
63 lastTrigger(QAbstractItemView::NoEditTriggers),
64 tabKeyNavigation(false),
65#if QT_CONFIG(draganddrop)
66 showDropIndicator(true),
67 dragEnabled(false),
68 dragDropMode(QAbstractItemView::NoDragDrop),
69 overwrite(false),
70 dropEventMoved(false),
71 dropIndicatorPosition(QAbstractItemView::OnItem),
72 defaultDropAction(Qt::IgnoreAction),
73#endif
74 autoScroll(true),
75 autoScrollMargin(16),
76 autoScrollCount(0),
77 shouldScrollToCurrentOnShow(false),
78 shouldClearStatusTip(false),
79 alternatingColors(false),
80 textElideMode(Qt::ElideRight),
81 verticalScrollMode(QAbstractItemView::ScrollPerItem),
82 horizontalScrollMode(QAbstractItemView::ScrollPerItem),
83 currentIndexSet(false),
84 wrapItemText(false),
85 delayedPendingLayout(true),
86 moveCursorUpdatedView(false),
87 verticalScrollModeSet(false),
88 horizontalScrollModeSet(false)
89{
91}
92
94{
95}
96
98{
100 q->setItemDelegate(new QStyledItemDelegate(q));
101
102 vbar->setRange(0, 0);
103 hbar->setRange(0, 0);
104
105 QObject::connect(vbar, SIGNAL(actionTriggered(int)),
106 q, SLOT(verticalScrollbarAction(int)));
107 QObject::connect(hbar, SIGNAL(actionTriggered(int)),
108 q, SLOT(horizontalScrollbarAction(int)));
109 QObject::connect(vbar, SIGNAL(valueChanged(int)),
110 q, SLOT(verticalScrollbarValueChanged(int)));
111 QObject::connect(hbar, SIGNAL(valueChanged(int)),
112 q, SLOT(horizontalScrollbarValueChanged(int)));
113
114 viewport->setBackgroundRole(QPalette::Base);
115
116 q->setAttribute(Qt::WA_InputMethodEnabled);
117
118 verticalScrollMode = static_cast<QAbstractItemView::ScrollMode>(q->style()->styleHint(QStyle::SH_ItemView_ScrollMode, nullptr, q, nullptr));
119 horizontalScrollMode = static_cast<QAbstractItemView::ScrollMode>(q->style()->styleHint(QStyle::SH_ItemView_ScrollMode, nullptr, q, nullptr));
120}
121
123{
125 if (hover == index)
126 return;
127
129 q->update(hover); //update the old one
130 q->update(index); //update the new one
131 } else {
132 QRect oldHoverRect = q->visualRect(hover);
133 QRect newHoverRect = q->visualRect(index);
134 viewport->update(QRect(0, newHoverRect.y(), viewport->width(), newHoverRect.height()));
135 viewport->update(QRect(0, oldHoverRect.y(), viewport->width(), oldHoverRect.height()));
136 }
137 hover = index;
138}
139
141{
142 //we take a persistent model index because the model might change by emitting signals
146 viewportEnteredNeeded = false;
147
148 if (index.isValid()) {
149 emit q->entered(index);
150#if QT_CONFIG(statustip)
152 if (parent && (shouldClearStatusTip || !statustip.isEmpty())) {
153 QStatusTipEvent tip(statustip);
155 shouldClearStatusTip = !statustip.isEmpty();
156 }
157#endif
158 } else {
159#if QT_CONFIG(statustip)
161 QString emptyString;
162 QStatusTipEvent tip( emptyString );
164 }
165#endif
166 emit q->viewportEntered();
167 }
169 }
170}
171
172#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
173
174// stores and restores the selection and current item when flicking
176{
178
180 switch (scroller->state()) {
182 // store the current selection in case we start scrolling
183 if (q->selectionModel()) {
184 oldSelection = q->selectionModel()->selection();
185 oldCurrent = q->selectionModel()->currentIndex();
186 }
187 break;
188
190 // restore the old selection if we really start scrolling
191 if (q->selectionModel()) {
192 q->selectionModel()->select(oldSelection, QItemSelectionModel::ClearAndSelect);
193 // block autoScroll logic while we are already handling scrolling
194 const bool wasAutoScroll = autoScroll;
195 autoScroll = false;
196 q->selectionModel()->setCurrentIndex(oldCurrent, QItemSelectionModel::NoUpdate);
197 autoScroll = wasAutoScroll;
198 }
200
201 default:
204 break;
205 }
206 }
207}
208
209#endif // QT_NO_GESTURES
210
212{
214 if (model) {
215 if (!model->checkIndex(index))
216 qWarning("Delegate size hint changed for a model index that does not belong to this view");
217 }
219}
220
606 : QAbstractScrollArea(*(new QAbstractItemViewPrivate), parent)
607{
608 d_func()->init();
609}
610
615 : QAbstractScrollArea(dd, parent)
616{
617 d_func()->init();
618}
619
624{
626 // stop these timers here before ~QObject
627 d->delayedReset.stop();
628 d->updateTimer.stop();
629 d->delayedEditing.stop();
630 d->delayedAutoScroll.stop();
631 d->autoScrollTimer.stop();
632 d->delayedLayout.stop();
633 d->fetchMoreTimer.stop();
634}
635
657{
659 if (model == d->model)
660 return;
661 if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
662 disconnect(d->model, SIGNAL(destroyed()),
663 this, SLOT(_q_modelDestroyed()));
666 disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
667 this, SLOT(_q_headerDataChanged()));
668 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
669 this, SLOT(rowsInserted(QModelIndex,int,int)));
671 this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
672 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
673 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
674 disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
675 this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
676 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
677 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
678 disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
679 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
680 disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
681 this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
682 disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
683 this, SLOT(_q_columnsInserted(QModelIndex,int,int)));
684 disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
685 this, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
686
687 disconnect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
688 disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
689 }
691
693 connect(d->model, SIGNAL(destroyed()),
694 this, SLOT(_q_modelDestroyed()));
697 connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
698 this, SLOT(_q_headerDataChanged()));
699 connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
700 this, SLOT(rowsInserted(QModelIndex,int,int)));
701 connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
702 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
704 this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
705 connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
706 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
707 connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
708 this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
709 connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
710 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
711 connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
712 this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
713 connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
714 this, SLOT(_q_columnsInserted(QModelIndex,int,int)));
715 connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
716 this, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
717
718 connect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
719 connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
720 }
721
722 QItemSelectionModel *selection_model = new QItemSelectionModel(d->model, this);
723 connect(d->model, SIGNAL(destroyed()), selection_model, SLOT(deleteLater()));
724 setSelectionModel(selection_model);
725
726 reset(); // kill editors, set new root and do layout
727}
728
733{
734 Q_D(const QAbstractItemView);
735 return (d->model == QAbstractItemModelPrivate::staticEmptyModel() ? nullptr : d->model);
736}
737
753{
754 // ### if the given model is null, we should use the original selection model
757
758 if (Q_UNLIKELY(selectionModel->model() != d->model)) {
759 qWarning("QAbstractItemView::setSelectionModel() failed: "
760 "Trying to set a selection model, which works on "
761 "a different model than the view.");
762 return;
763 }
764
765 QItemSelection oldSelection;
766 QModelIndex oldCurrentIndex;
767
768 if (d->selectionModel) {
769 if (d->selectionModel->model() == selectionModel->model()) {
770 oldSelection = d->selectionModel->selection();
771 oldCurrentIndex = d->selectionModel->currentIndex();
772 }
773
778 }
779
780 d->selectionModel = selectionModel;
781
782 if (d->selectionModel) {
787
788 selectionChanged(d->selectionModel->selection(), oldSelection);
789 currentChanged(d->selectionModel->currentIndex(), oldCurrentIndex);
790 }
791}
792
799{
800 Q_D(const QAbstractItemView);
801 return d->selectionModel;
802}
803
820{
822 if (delegate == d->itemDelegate)
823 return;
824
825 if (d->itemDelegate) {
826 if (d->delegateRefCount(d->itemDelegate) == 1) {
829 disconnect(d->itemDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
830 disconnect(d->itemDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
831 }
832 }
833
834 if (delegate) {
835 if (d->delegateRefCount(delegate) == 0) {
838 connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
839 connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
840 }
841 }
842 d->itemDelegate = delegate;
843 viewport()->update();
844 d->doDelayedItemsLayout();
845}
846
854{
855 return d_func()->itemDelegate;
856}
857
862{
863 Q_D(const QAbstractItemView);
864 const QModelIndex current = currentIndex();
866 if (current.isValid()) {
867 if (QWidget *currentEditor;
868 d->waitForIMCommit && (currentEditor = d->editorForIndex(current).widget)) {
869 // An editor is open but the initial preedit is still ongoing. Delegate
870 // queries to the editor and map coordinates from editor to this view.
871 result = currentEditor->inputMethodQuery(query);
872 if (result.typeId() == QMetaType::QRect) {
873 const QRect editorRect = result.value<QRect>();
874 result = QRect(currentEditor->mapTo(this, editorRect.topLeft()), editorRect.size());
875 }
876 } else if (query == Qt::ImCursorRectangle) {
877 result = visualRect(current);
878 }
879 }
880 if (!result.isValid())
881 result = QAbstractScrollArea::inputMethodQuery(query);
882 return result;
883}
884
907{
909 if (QAbstractItemDelegate *rowDelegate = d->rowDelegates.value(row, nullptr)) {
910 if (d->delegateRefCount(rowDelegate) == 1) {
913 disconnect(rowDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
914 disconnect(rowDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
915 }
916 d->rowDelegates.remove(row);
917 }
918 if (delegate) {
919 if (d->delegateRefCount(delegate) == 0) {
922 connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
923 connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
924 }
925 d->rowDelegates.insert(row, delegate);
926 }
927 viewport()->update();
928 d->doDelayedItemsLayout();
929}
930
941{
942 Q_D(const QAbstractItemView);
943 return d->rowDelegates.value(row, nullptr);
944}
945
967{
969 if (QAbstractItemDelegate *columnDelegate = d->columnDelegates.value(column, nullptr)) {
970 if (d->delegateRefCount(columnDelegate) == 1) {
973 disconnect(columnDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
974 disconnect(columnDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
975 }
976 d->columnDelegates.remove(column);
977 }
978 if (delegate) {
979 if (d->delegateRefCount(delegate) == 0) {
982 connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
983 connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
984 }
985 d->columnDelegates.insert(column, delegate);
986 }
987 viewport()->update();
988 d->doDelayedItemsLayout();
989}
990
1001{
1002 Q_D(const QAbstractItemView);
1003 return d->columnDelegates.value(column, nullptr);
1004}
1005
1022{
1023 Q_D(const QAbstractItemView);
1024 return d->delegateForIndex(index);
1025}
1026
1038{
1039 Q_D(QAbstractItemView);
1040 d->selectionMode = mode;
1041}
1042
1044{
1045 Q_D(const QAbstractItemView);
1046 return d->selectionMode;
1047}
1048
1060{
1061 Q_D(QAbstractItemView);
1062 d->selectionBehavior = behavior;
1063}
1064
1066{
1067 Q_D(const QAbstractItemView);
1068 return d->selectionBehavior;
1069}
1070
1086{
1087 Q_D(QAbstractItemView);
1088 if (d->selectionModel && (!index.isValid() || d->isIndexEnabled(index))) {
1089 QItemSelectionModel::SelectionFlags command = selectionCommand(index, nullptr);
1090 d->selectionModel->setCurrentIndex(index, command);
1091 d->currentIndexSet = true;
1092 if ((command & QItemSelectionModel::Current) == 0)
1093 d->currentSelectionStartIndex = index;
1094 }
1095}
1096
1103{
1104 Q_D(const QAbstractItemView);
1105 return d->selectionModel ? d->selectionModel->currentIndex() : QModelIndex();
1106}
1107
1108
1119{
1120 Q_D(QAbstractItemView);
1121 d->delayedReset.stop(); //make sure we stop the timer
1122 foreach (const QEditorInfo &info, d->indexEditorHash) {
1123 if (info.widget)
1124 d->releaseEditor(info.widget.data(), d->indexForEditor(info.widget.data()));
1125 }
1126 d->editorIndexHash.clear();
1127 d->indexEditorHash.clear();
1128 d->persistent.clear();
1129 d->currentIndexSet = false;
1132 if (d->selectionModel)
1133 d->selectionModel->reset();
1134#if QT_CONFIG(accessibility)
1135 if (QAccessible::isActive()) {
1136 QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::ModelReset);
1137 QAccessible::updateAccessibility(&accessibleEvent);
1138 }
1139#endif
1140 d->updateGeometry();
1141}
1142
1149{
1150 Q_D(QAbstractItemView);
1151 if (Q_UNLIKELY(index.isValid() && index.model() != d->model)) {
1152 qWarning("QAbstractItemView::setRootIndex failed : index must be from the currently set model");
1153 return;
1154 }
1155 d->root = index;
1156 d->doDelayedItemsLayout();
1157 d->updateGeometry();
1158}
1159
1167{
1168 return QModelIndex(d_func()->root);
1169}
1170
1179{
1180 Q_D(QAbstractItemView);
1181 const SelectionMode mode = d->selectionMode;
1182 switch (mode) {
1183 case MultiSelection:
1184 case ExtendedSelection:
1186 | d->selectionBehaviorFlags());
1187 break;
1188 case NoSelection:
1190 if (d->model->hasChildren(d->root))
1191 d->selectAll(selectionCommand(d->model->index(0, 0, d->root)));
1192 break;
1193 case SingleSelection:
1194 break;
1195 }
1196}
1197
1211{
1212 Q_D(QAbstractItemView);
1213 if (Q_UNLIKELY(!d->isIndexValid(index)))
1214 qWarning("edit: index was invalid");
1215 if (Q_UNLIKELY(!edit(index, AllEditTriggers, nullptr)))
1216 qWarning("edit: editing failed");
1217}
1218
1225{
1226 Q_D(QAbstractItemView);
1227 if (d->selectionModel)
1228 d->selectionModel->clearSelection();
1229}
1230
1238{
1239 Q_D(QAbstractItemView);
1240 d->interruptDelayedItemsLayout();
1242 d->viewport->update();
1243}
1244
1254void QAbstractItemView::setEditTriggers(EditTriggers actions)
1255{
1256 Q_D(QAbstractItemView);
1257 d->editTriggers = actions;
1258}
1259
1260QAbstractItemView::EditTriggers QAbstractItemView::editTriggers() const
1261{
1262 Q_D(const QAbstractItemView);
1263 return d->editTriggers;
1264}
1265
1277{
1278 Q_D(QAbstractItemView);
1279 d->verticalScrollModeSet = true;
1280 if (mode == d->verticalScrollMode)
1281 return;
1282 QModelIndex topLeft = indexAt(QPoint(0, 0));
1283 d->verticalScrollMode = mode;
1284 if (mode == ScrollPerItem)
1285 verticalScrollBar()->d_func()->itemviewChangeSingleStep(1); // setSingleStep(-1) => step with 1
1286 else
1287 verticalScrollBar()->setSingleStep(-1); // Ensure that the view can update single step
1288 updateGeometries(); // update the scroll bars
1290}
1291
1293{
1294 Q_D(const QAbstractItemView);
1295 return d->verticalScrollMode;
1296}
1297
1299{
1300 auto sm = static_cast<ScrollMode>(style()->styleHint(QStyle::SH_ItemView_ScrollMode, nullptr, this, nullptr));
1302 d_func()->verticalScrollModeSet = false;
1303}
1304
1316{
1317 Q_D(QAbstractItemView);
1318 d->horizontalScrollModeSet = true;
1319 if (mode == d->horizontalScrollMode)
1320 return;
1321 d->horizontalScrollMode = mode;
1322 if (mode == ScrollPerItem)
1323 horizontalScrollBar()->d_func()->itemviewChangeSingleStep(1); // setSingleStep(-1) => step with 1
1324 else
1325 horizontalScrollBar()->setSingleStep(-1); // Ensure that the view can update single step
1326 updateGeometries(); // update the scroll bars
1327}
1328
1330{
1331 Q_D(const QAbstractItemView);
1332 return d->horizontalScrollMode;
1333}
1334
1336{
1337 auto sm = static_cast<ScrollMode>(style()->styleHint(QStyle::SH_ItemView_ScrollMode, nullptr, this, nullptr));
1339 d_func()->horizontalScrollModeSet = false;
1340}
1341
1342#if QT_CONFIG(draganddrop)
1364void QAbstractItemView::setDragDropOverwriteMode(bool overwrite)
1365{
1366 Q_D(QAbstractItemView);
1367 d->overwrite = overwrite;
1368}
1369
1370bool QAbstractItemView::dragDropOverwriteMode() const
1371{
1372 Q_D(const QAbstractItemView);
1373 return d->overwrite;
1374}
1375#endif
1376
1392{
1393 Q_D(QAbstractItemView);
1394 d->autoScroll = enable;
1395}
1396
1398{
1399 Q_D(const QAbstractItemView);
1400 return d->autoScroll;
1401}
1402
1412{
1413 Q_D(QAbstractItemView);
1414 d->autoScrollMargin = margin;
1415}
1416
1418{
1419 Q_D(const QAbstractItemView);
1420 return d->autoScrollMargin;
1421}
1422
1429{
1430 Q_D(QAbstractItemView);
1431 d->tabKeyNavigation = enable;
1432}
1433
1435{
1436 Q_D(const QAbstractItemView);
1437 return d->tabKeyNavigation;
1438}
1439
1445{
1446 return QAbstractScrollArea::viewportSizeHint();
1447}
1448
1449#if QT_CONFIG(draganddrop)
1457void QAbstractItemView::setDropIndicatorShown(bool enable)
1458{
1459 Q_D(QAbstractItemView);
1460 d->showDropIndicator = enable;
1461}
1462
1463bool QAbstractItemView::showDropIndicator() const
1464{
1465 Q_D(const QAbstractItemView);
1466 return d->showDropIndicator;
1467}
1468
1476void QAbstractItemView::setDragEnabled(bool enable)
1477{
1478 Q_D(QAbstractItemView);
1479 d->dragEnabled = enable;
1480}
1481
1482bool QAbstractItemView::dragEnabled() const
1483{
1484 Q_D(const QAbstractItemView);
1485 return d->dragEnabled;
1486}
1487
1515void QAbstractItemView::setDragDropMode(DragDropMode behavior)
1516{
1517 Q_D(QAbstractItemView);
1518 d->dragDropMode = behavior;
1519 setDragEnabled(behavior == DragOnly || behavior == DragDrop || behavior == InternalMove);
1520 setAcceptDrops(behavior == DropOnly || behavior == DragDrop || behavior == InternalMove);
1521}
1522
1523QAbstractItemView::DragDropMode QAbstractItemView::dragDropMode() const
1524{
1525 Q_D(const QAbstractItemView);
1526 DragDropMode setBehavior = d->dragDropMode;
1527 if (!dragEnabled() && !acceptDrops())
1528 return NoDragDrop;
1529
1530 if (dragEnabled() && !acceptDrops())
1531 return DragOnly;
1532
1533 if (!dragEnabled() && acceptDrops())
1534 return DropOnly;
1535
1536 if (dragEnabled() && acceptDrops()) {
1537 if (setBehavior == InternalMove)
1538 return setBehavior;
1539 else
1540 return DragDrop;
1541 }
1542
1543 return NoDragDrop;
1544}
1545
1556void QAbstractItemView::setDefaultDropAction(Qt::DropAction dropAction)
1557{
1558 Q_D(QAbstractItemView);
1559 d->defaultDropAction = dropAction;
1560}
1561
1562Qt::DropAction QAbstractItemView::defaultDropAction() const
1563{
1564 Q_D(const QAbstractItemView);
1565 return d->defaultDropAction;
1566}
1567
1568#endif // QT_CONFIG(draganddrop)
1569
1581{
1582 Q_D(QAbstractItemView);
1583 d->alternatingColors = enable;
1584 if (isVisible())
1585 d->viewport->update();
1586}
1587
1589{
1590 Q_D(const QAbstractItemView);
1591 return d->alternatingColors;
1592}
1593
1602{
1603 Q_D(QAbstractItemView);
1604 if (size == d->iconSize)
1605 return;
1606 d->iconSize = size;
1607 d->doDelayedItemsLayout();
1609}
1610
1612{
1613 Q_D(const QAbstractItemView);
1614 return d->iconSize;
1615}
1616
1625{
1626 Q_D(QAbstractItemView);
1627 d->textElideMode = mode;
1628}
1629
1631{
1632 return d_func()->textElideMode;
1633}
1634
1639{
1640 Q_D(QAbstractItemView);
1641 if (d->tabKeyNavigation && isEnabled() && d->viewport->isEnabled()) {
1644 if (event.isAccepted())
1645 return true;
1646 }
1647 return QAbstractScrollArea::focusNextPrevChild(next);
1648}
1649
1654{
1655 Q_D(QAbstractItemView);
1656 switch (event->type()) {
1657 case QEvent::Paint:
1658 //we call this here because the scrollbars' visibility might be altered
1659 //so this can't be done in the paintEvent method
1660 d->executePostedLayout(); //make sure we set the layout properly
1661 break;
1662 case QEvent::Show:
1663 d->executePostedLayout(); //make sure we set the layout properly
1664 if (d->shouldScrollToCurrentOnShow) {
1665 d->shouldScrollToCurrentOnShow = false;
1666 const QModelIndex current = currentIndex();
1667 if (current.isValid() && (d->state == QAbstractItemView::EditingState || d->autoScroll))
1668 scrollTo(current);
1669 }
1670 break;
1672 viewport()->update();
1673 break;
1677 break;
1679 doItemsLayout();
1680 if (!d->verticalScrollModeSet)
1682 if (!d->horizontalScrollModeSet)
1684 break;
1685 case QEvent::FocusOut:
1686 d->checkPersistentEditorFocus();
1687 break;
1688 case QEvent::FontChange:
1689 d->doDelayedItemsLayout(); // the size of the items will change
1690 break;
1691 default:
1692 break;
1693 }
1694 return QAbstractScrollArea::event(event);
1695}
1696
1709{
1710 Q_D(QAbstractItemView);
1711 switch (event->type()) {
1712 case QEvent::Paint:
1713 // Similar to pre-painting in QAbstractItemView::event to update scrollbar
1714 // visibility, make sure that all pending layout requests have been executed
1715 // so that the view's data structures are up-to-date before rendering.
1716 d->executePostedLayout();
1717 break;
1718 case QEvent::HoverMove:
1719 case QEvent::HoverEnter:
1720 d->setHoverIndex(indexAt(static_cast<QHoverEvent*>(event)->position().toPoint()));
1721 break;
1722 case QEvent::HoverLeave:
1723 d->setHoverIndex(QModelIndex());
1724 break;
1725 case QEvent::Enter:
1726 d->viewportEnteredNeeded = true;
1727 break;
1728 case QEvent::Leave:
1729 d->setHoverIndex(QModelIndex()); // If we've left, no hover should be needed anymore
1730 #if QT_CONFIG(statustip)
1731 if (d->shouldClearStatusTip && d->parent) {
1732 QString empty;
1733 QStatusTipEvent tip(empty);
1734 QCoreApplication::sendEvent(d->parent, &tip);
1735 d->shouldClearStatusTip = false;
1736 }
1737 #endif
1738 d->enteredIndex = QModelIndex();
1739 break;
1740 case QEvent::ToolTip:
1742 case QEvent::WhatsThis: {
1743 QHelpEvent *he = static_cast<QHelpEvent*>(event);
1744 const QModelIndex index = indexAt(he->pos());
1745 QStyleOptionViewItem option;
1747 option.rect = visualRect(index);
1749
1751 if (!delegate)
1752 return false;
1753 return delegate->helpEvent(he, this, option, index);
1754 }
1755 case QEvent::FontChange:
1756 d->doDelayedItemsLayout(); // the size of the items will change
1757 break;
1760 d->viewport->update();
1761 break;
1764#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
1765 connect(QScroller::scroller(d->viewport), SIGNAL(stateChanged(QScroller::State)), this, SLOT(_q_scrollerStateChanged()), Qt::UniqueConnection);
1766#endif
1767 break;
1768
1769 default:
1770 break;
1771 }
1772 return QAbstractScrollArea::viewportEvent(event);
1773}
1774
1781{
1782 Q_D(QAbstractItemView);
1783 d->releaseFromDoubleClick = false;
1784 d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
1785 QPoint pos = event->position().toPoint();
1787
1788 // this is the mouse press event that closed the last editor (via focus event)
1789 d->pressClosedEditor = d->pressClosedEditorWatcher.isActive() && d->lastEditedIndex == index;
1790
1791 if (!d->selectionModel || (d->state == EditingState && d->hasEditor(index)))
1792 return;
1793
1794 d->pressedAlreadySelected = d->selectionModel->isSelected(index);
1795 d->pressedIndex = index;
1796 d->pressedModifiers = event->modifiers();
1797 QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1798 d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid();
1799 QPoint offset = d->offset();
1800 d->draggedPosition = pos + offset;
1801
1802#if QT_CONFIG(draganddrop)
1803 // update the pressed position when drag was enable
1804 if (d->dragEnabled)
1805 d->pressedPosition = d->draggedPosition;
1806#endif
1807
1808 if (!(command & QItemSelectionModel::Current)) {
1809 d->pressedPosition = pos + offset;
1810 d->currentSelectionStartIndex = index;
1811 }
1812 else if (!d->currentSelectionStartIndex.isValid())
1813 d->currentSelectionStartIndex = currentIndex();
1814
1816 return;
1817
1818 if (index.isValid() && d->isIndexEnabled(index)) {
1819 // we disable scrollTo for mouse press so the item doesn't change position
1820 // when the user is interacting with it (ie. clicking on it)
1821 bool autoScroll = d->autoScroll;
1822 d->autoScroll = false;
1823 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1824 d->autoScroll = autoScroll;
1825 if (command.testFlag(QItemSelectionModel::Toggle)) {
1826 command &= ~QItemSelectionModel::Toggle;
1827 d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
1828 command |= d->ctrlDragSelectionFlag;
1829 }
1830
1831 if (!(command & QItemSelectionModel::Current)) {
1832 setSelection(QRect(pos, QSize(1, 1)), command);
1833 } else {
1834 QRect rect(visualRect(d->currentSelectionStartIndex).center(), pos);
1835 setSelection(rect, command);
1836 }
1837
1838 // signal handlers may change the model
1840 if (d->autoScroll) {
1841 //we delay the autoscrolling to filter out double click event
1842 //100 is to be sure that there won't be a double-click misinterpreted as a 2 single clicks
1843 d->delayedAutoScroll.start(QApplication::doubleClickInterval()+100, this);
1844 }
1845
1846 } else {
1847 // Forces a finalize() even if mouse is pressed, but not on a item
1848 d->selectionModel->select(QModelIndex(), QItemSelectionModel::Select);
1849 }
1850}
1851
1858{
1859 Q_D(QAbstractItemView);
1860 QPoint bottomRight = event->position().toPoint();
1861
1862 d->draggedPosition = bottomRight + d->offset();
1863
1864 if (state() == ExpandingState || state() == CollapsingState)
1865 return;
1866
1867#if QT_CONFIG(draganddrop)
1868 if (state() == DraggingState) {
1869 d->maybeStartDrag(bottomRight);
1870 return;
1871 }
1872#endif // QT_CONFIG(draganddrop)
1873
1874 QPersistentModelIndex index = indexAt(bottomRight);
1875 QModelIndex buddy = d->model->buddy(d->pressedIndex);
1876 if ((state() == EditingState && d->hasEditor(buddy))
1878 return;
1879
1880 const QPoint topLeft =
1881 d->selectionMode != SingleSelection ? d->pressedPosition - d->offset() : bottomRight;
1882
1883 d->checkMouseMove(index);
1884
1885#if QT_CONFIG(draganddrop)
1886 if (d->pressedIndex.isValid()
1887 && d->dragEnabled
1888 && (state() != DragSelectingState)
1889 && (event->buttons() != Qt::NoButton)
1890 && !d->selectedDraggableIndexes().isEmpty()) {
1892 d->maybeStartDrag(bottomRight);
1893 return;
1894 }
1895#endif
1896
1897 if ((event->buttons() & Qt::LeftButton) && d->selectionAllowed(index) && d->selectionModel) {
1899 QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1900 if (d->ctrlDragSelectionFlag != QItemSelectionModel::NoUpdate && command.testFlag(QItemSelectionModel::Toggle)) {
1901 command &= ~QItemSelectionModel::Toggle;
1902 command |= d->ctrlDragSelectionFlag;
1903 }
1904
1905 // Do the normalize ourselves, since QRect::normalized() is flawed
1906 QRect selectionRect = QRect(topLeft, bottomRight);
1907 setSelection(selectionRect, command);
1908
1909 // set at the end because it might scroll the view
1910 if (index.isValid() && (index != d->selectionModel->currentIndex()) && d->isIndexEnabled(index))
1911 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1912 else if (d->shouldAutoScroll(event->pos()) && !d->autoScrollTimer.isActive())
1914 }
1915}
1916
1925{
1926 Q_D(QAbstractItemView);
1927 const bool releaseFromDoubleClick = d->releaseFromDoubleClick;
1928 d->releaseFromDoubleClick = false;
1929
1930 QPoint pos = event->position().toPoint();
1932
1933 if (state() == EditingState) {
1934 if (d->isIndexValid(index)
1935 && d->isIndexEnabled(index)
1936 && d->sendDelegateEvent(index, event))
1937 update(index);
1938 return;
1939 }
1940
1941 bool click = (index == d->pressedIndex && index.isValid() && !releaseFromDoubleClick);
1942 bool selectedClicked = click && d->pressedAlreadySelected
1943 && (event->button() == Qt::LeftButton)
1944 && (event->modifiers() == Qt::NoModifier);
1945 EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
1946 const bool edited = click && !d->pressClosedEditor ? edit(index, trigger, event) : false;
1947
1948 d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
1949
1950 if (d->selectionModel && d->noSelectionOnMousePress) {
1951 d->noSelectionOnMousePress = false;
1952 if (!d->pressClosedEditor)
1953 d->selectionModel->select(index, selectionCommand(index, event));
1954 }
1955
1956 d->pressClosedEditor = false;
1958
1959 if (click) {
1960 if (event->button() == Qt::LeftButton)
1962 if (edited)
1963 return;
1964 QStyleOptionViewItem option;
1966 if (d->pressedAlreadySelected)
1968 if ((d->model->flags(index) & Qt::ItemIsEnabled)
1969 && style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
1971 }
1972}
1973
1980{
1981 Q_D(QAbstractItemView);
1982
1983 QModelIndex index = indexAt(event->position().toPoint());
1984 if (!index.isValid()
1985 || !d->isIndexEnabled(index)
1986 || (d->pressedIndex != index)) {
1988 event->position(), event->scenePosition(), event->globalPosition(),
1989 event->button(), event->buttons(), event->modifiers(),
1990 event->source(), event->pointingDevice());
1991 mousePressEvent(&me);
1992 return;
1993 }
1994 // signal handlers may change the model
1995 QPersistentModelIndex persistent = index;
1996 emit doubleClicked(persistent);
1997 if ((event->button() == Qt::LeftButton) && !edit(persistent, DoubleClicked, event)
1998 && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this))
1999 emit activated(persistent);
2000 d->releaseFromDoubleClick = true;
2001}
2002
2003#if QT_CONFIG(draganddrop)
2004
2012void QAbstractItemView::dragEnterEvent(QDragEnterEvent *event)
2013{
2014 if (dragDropMode() == InternalMove
2015 && (event->source() != this|| !(event->possibleActions() & Qt::MoveAction)))
2016 return;
2017
2018 if (d_func()->canDrop(event)) {
2019 event->accept();
2021 } else {
2022 event->ignore();
2023 }
2024}
2025
2034void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event)
2035{
2036 Q_D(QAbstractItemView);
2037 d->draggedPosition = event->position().toPoint() + d->offset();
2038 if (dragDropMode() == InternalMove
2039 && (event->source() != this || !(event->possibleActions() & Qt::MoveAction)))
2040 return;
2041
2042 // ignore by default
2043 event->ignore();
2044
2045 QModelIndex index = indexAt(event->position().toPoint());
2046 d->hover = index;
2047 if (!d->droppingOnItself(event, index)
2048 && d->canDrop(event)) {
2049
2050 if (index.isValid() && d->showDropIndicator) {
2052 d->dropIndicatorPosition = d->position(event->position().toPoint(), rect, index);
2053 switch (d->dropIndicatorPosition) {
2054 case AboveItem:
2055 if (d->isIndexDropEnabled(index.parent())) {
2056 d->dropIndicatorRect = QRect(rect.left(), rect.top(), rect.width(), 0);
2057 event->acceptProposedAction();
2058 } else {
2059 d->dropIndicatorRect = QRect();
2060 }
2061 break;
2062 case BelowItem:
2063 if (d->isIndexDropEnabled(index.parent())) {
2064 d->dropIndicatorRect = QRect(rect.left(), rect.bottom(), rect.width(), 0);
2065 event->acceptProposedAction();
2066 } else {
2067 d->dropIndicatorRect = QRect();
2068 }
2069 break;
2070 case OnItem:
2071 if (d->isIndexDropEnabled(index)) {
2072 d->dropIndicatorRect = rect;
2073 event->acceptProposedAction();
2074 } else {
2075 d->dropIndicatorRect = QRect();
2076 }
2077 break;
2078 case OnViewport:
2079 d->dropIndicatorRect = QRect();
2080 if (d->isIndexDropEnabled(rootIndex())) {
2081 event->acceptProposedAction(); // allow dropping in empty areas
2082 }
2083 break;
2084 }
2085 } else {
2086 d->dropIndicatorRect = QRect();
2087 d->dropIndicatorPosition = OnViewport;
2088 if (d->isIndexDropEnabled(rootIndex())) {
2089 event->acceptProposedAction(); // allow dropping in empty areas
2090 }
2091 }
2092 d->viewport->update();
2093 } // can drop
2094
2095 if (d->shouldAutoScroll(event->position().toPoint()))
2097}
2098
2105{
2106 Q_Q(QAbstractItemView);
2107 Qt::DropAction dropAction = event->dropAction();
2108 if (q->dragDropMode() == QAbstractItemView::InternalMove)
2109 dropAction = Qt::MoveAction;
2110 if (event->source() == q
2111 && event->possibleActions() & Qt::MoveAction
2112 && dropAction == Qt::MoveAction) {
2113 QModelIndexList selectedIndexes = q->selectedIndexes();
2115 while (child.isValid() && child != root) {
2116 if (selectedIndexes.contains(child))
2117 return true;
2118 child = child.parent();
2119 }
2120 }
2121 return false;
2122}
2123
2130void QAbstractItemView::dragLeaveEvent(QDragLeaveEvent *)
2131{
2132 Q_D(QAbstractItemView);
2135 d->hover = QModelIndex();
2136 d->viewport->update();
2137}
2138
2146void QAbstractItemView::dropEvent(QDropEvent *event)
2147{
2148 Q_D(QAbstractItemView);
2149 if (dragDropMode() == InternalMove) {
2150 if (event->source() != this || !(event->possibleActions() & Qt::MoveAction))
2151 return;
2152 }
2153
2155 int col = -1;
2156 int row = -1;
2157 if (d->dropOn(event, &row, &col, &index)) {
2158 const Qt::DropAction action = dragDropMode() == InternalMove ? Qt::MoveAction : event->dropAction();
2159 if (d->model->dropMimeData(event->mimeData(), action, row, col, index)) {
2160 if (action != event->dropAction()) {
2161 event->setDropAction(action);
2162 event->accept();
2163 } else {
2164 event->acceptProposedAction();
2165 }
2166 }
2167 }
2170 d->viewport->update();
2171}
2172
2184bool QAbstractItemViewPrivate::dropOn(QDropEvent *event, int *dropRow, int *dropCol, QModelIndex *dropIndex)
2185{
2186 Q_Q(QAbstractItemView);
2187 if (event->isAccepted())
2188 return false;
2189
2191 // rootIndex() (i.e. the viewport) might be a valid index
2192 if (viewport->rect().contains(event->position().toPoint())) {
2193 index = q->indexAt(event->position().toPoint());
2194 if (!index.isValid() || !q->visualRect(index).contains(event->position().toPoint()))
2195 index = root;
2196 }
2197
2198 // If we are allowed to do the drop
2199 if (model->supportedDropActions() & event->dropAction()) {
2200 int row = -1;
2201 int col = -1;
2202 if (index != root) {
2203 dropIndicatorPosition = position(event->position().toPoint(), q->visualRect(index), index);
2204 switch (dropIndicatorPosition) {
2205 case QAbstractItemView::AboveItem:
2206 row = index.row();
2207 col = index.column();
2208 index = index.parent();
2209 break;
2210 case QAbstractItemView::BelowItem:
2211 row = index.row() + 1;
2212 col = index.column();
2213 index = index.parent();
2214 break;
2215 case QAbstractItemView::OnItem:
2216 case QAbstractItemView::OnViewport:
2217 break;
2218 }
2219 } else {
2220 dropIndicatorPosition = QAbstractItemView::OnViewport;
2221 }
2222 *dropIndex = index;
2223 *dropRow = row;
2224 *dropCol = col;
2226 return true;
2227 }
2228 return false;
2229}
2230
2231QAbstractItemView::DropIndicatorPosition
2232QAbstractItemViewPrivate::position(const QPoint &pos, const QRect &rect, const QModelIndex &index) const
2233{
2234 QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2235 if (!overwrite) {
2236 const int margin = qBound(2, qRound(qreal(rect.height()) / 5.5), 12);
2237 if (pos.y() - rect.top() < margin) {
2238 r = QAbstractItemView::AboveItem;
2239 } else if (rect.bottom() - pos.y() < margin) {
2240 r = QAbstractItemView::BelowItem;
2241 } else if (rect.contains(pos, true)) {
2242 r = QAbstractItemView::OnItem;
2243 }
2244 } else {
2245 QRect touchingRect = rect;
2246 touchingRect.adjust(-1, -1, 1, 1);
2247 if (touchingRect.contains(pos, false)) {
2248 r = QAbstractItemView::OnItem;
2249 }
2250 }
2251
2252 if (r == QAbstractItemView::OnItem && (!(model->flags(index) & Qt::ItemIsDropEnabled)))
2253 r = pos.y() < rect.center().y() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2254
2255 return r;
2256}
2257
2258#endif // QT_CONFIG(draganddrop)
2259
2267{
2268 Q_D(QAbstractItemView);
2269 QAbstractScrollArea::focusInEvent(event);
2270
2272 bool currentIndexValid = currentIndex().isValid();
2273
2274 if (model
2275 && !d->currentIndexSet
2276 && !currentIndexValid) {
2277 bool autoScroll = d->autoScroll;
2278 d->autoScroll = false;
2279 QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index
2280 if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason) {
2282 currentIndexValid = true;
2283 }
2284 d->autoScroll = autoScroll;
2285 }
2286
2287 if (model && currentIndexValid)
2289 else if (!currentIndexValid)
2291
2292 d->viewport->update();
2293}
2294
2302{
2303 Q_D(QAbstractItemView);
2304 QAbstractScrollArea::focusOutEvent(event);
2305 d->viewport->update();
2306}
2307
2320{
2321 Q_D(QAbstractItemView);
2322 d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
2323
2324#ifdef QT_KEYPAD_NAVIGATION
2325 switch (event->key()) {
2326 case Qt::Key_Select:
2327 if (QApplicationPrivate::keypadNavigationEnabled()) {
2328 if (!hasEditFocus()) {
2329 setEditFocus(true);
2330 return;
2331 }
2332 }
2333 break;
2334 case Qt::Key_Back:
2335 if (QApplicationPrivate::keypadNavigationEnabled() && hasEditFocus()) {
2336 setEditFocus(false);
2337 } else {
2338 event->ignore();
2339 }
2340 return;
2341 case Qt::Key_Down:
2342 case Qt::Key_Up:
2343 // Let's ignore vertical navigation events, only if there is no other widget
2344 // what can take the focus in vertical direction. This means widget can handle navigation events
2345 // even the widget don't have edit focus, and there is no other widget in requested direction.
2346 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()
2347 && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2348 event->ignore();
2349 return;
2350 }
2351 break;
2352 case Qt::Key_Left:
2353 case Qt::Key_Right:
2354 // Similar logic as in up and down events
2355 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()
2356 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this))) {
2357 event->ignore();
2358 return;
2359 }
2360 break;
2361 default:
2362 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()) {
2363 event->ignore();
2364 return;
2365 }
2366 }
2367#endif
2368
2369#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
2370 if (event == QKeySequence::Copy) {
2371 const QModelIndex index = currentIndex();
2372 if (index.isValid() && d->model) {
2373 const QVariant variant = d->model->data(index, Qt::DisplayRole);
2374 if (variant.canConvert<QString>())
2376 }
2377 event->accept();
2378 }
2379#endif
2380
2381 QPersistentModelIndex newCurrent;
2382 d->moveCursorUpdatedView = false;
2383 switch (event->key()) {
2384 case Qt::Key_Down:
2385 newCurrent = moveCursor(MoveDown, event->modifiers());
2386 break;
2387 case Qt::Key_Up:
2388 newCurrent = moveCursor(MoveUp, event->modifiers());
2389 break;
2390 case Qt::Key_Left:
2391 newCurrent = moveCursor(MoveLeft, event->modifiers());
2392 break;
2393 case Qt::Key_Right:
2394 newCurrent = moveCursor(MoveRight, event->modifiers());
2395 break;
2396 case Qt::Key_Home:
2397 newCurrent = moveCursor(MoveHome, event->modifiers());
2398 break;
2399 case Qt::Key_End:
2400 newCurrent = moveCursor(MoveEnd, event->modifiers());
2401 break;
2402 case Qt::Key_PageUp:
2403 newCurrent = moveCursor(MovePageUp, event->modifiers());
2404 break;
2405 case Qt::Key_PageDown:
2406 newCurrent = moveCursor(MovePageDown, event->modifiers());
2407 break;
2408 case Qt::Key_Tab:
2409 if (d->tabKeyNavigation)
2410 newCurrent = moveCursor(MoveNext, event->modifiers());
2411 break;
2412 case Qt::Key_Backtab:
2413 if (d->tabKeyNavigation)
2414 newCurrent = moveCursor(MovePrevious, event->modifiers());
2415 break;
2416 }
2417
2418 QPersistentModelIndex oldCurrent = currentIndex();
2419 if (newCurrent != oldCurrent && newCurrent.isValid() && d->isIndexEnabled(newCurrent)) {
2420 if (!hasFocus() && QApplication::focusWidget() == indexWidget(oldCurrent))
2421 setFocus();
2422 QItemSelectionModel::SelectionFlags command = selectionCommand(newCurrent, event);
2423 if (command != QItemSelectionModel::NoUpdate
2424 || style()->styleHint(QStyle::SH_ItemView_MovementWithoutUpdatingSelection, nullptr, this)) {
2425 // note that we don't check if the new current index is enabled because moveCursor() makes sure it is
2426 if (command & QItemSelectionModel::Current) {
2427 d->selectionModel->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
2428 if (!d->currentSelectionStartIndex.isValid())
2429 d->currentSelectionStartIndex = oldCurrent;
2430 QRect rect(visualRect(d->currentSelectionStartIndex).center(), visualRect(newCurrent).center());
2431 setSelection(rect, command);
2432 } else {
2433 d->selectionModel->setCurrentIndex(newCurrent, command);
2434 d->currentSelectionStartIndex = newCurrent;
2435 if (newCurrent.isValid()) {
2436 // We copy the same behaviour as for mousePressEvent().
2437 QRect rect(visualRect(newCurrent).center(), QSize(1, 1));
2438 setSelection(rect, command);
2439 }
2440 }
2441 event->accept();
2442 return;
2443 }
2444 }
2445
2446 switch (event->key()) {
2447 // ignored keys
2448 case Qt::Key_Down:
2449 case Qt::Key_Up:
2450#ifdef QT_KEYPAD_NAVIGATION
2451 if (QApplicationPrivate::keypadNavigationEnabled()
2452 && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2453 event->accept(); // don't change focus
2454 break;
2455 }
2456#endif
2457 case Qt::Key_Left:
2458 case Qt::Key_Right:
2459#ifdef QT_KEYPAD_NAVIGATION
2460 if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
2461 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal)
2462 || (QWidgetPrivate::inTabWidget(this) && d->model->columnCount(d->root) > 1))) {
2463 event->accept(); // don't change focus
2464 break;
2465 }
2466#endif // QT_KEYPAD_NAVIGATION
2467 case Qt::Key_Home:
2468 case Qt::Key_End:
2469 case Qt::Key_PageUp:
2470 case Qt::Key_PageDown:
2471 case Qt::Key_Escape:
2472 case Qt::Key_Shift:
2473 case Qt::Key_Control:
2474 case Qt::Key_Delete:
2475 case Qt::Key_Backspace:
2476 event->ignore();
2477 break;
2478 case Qt::Key_Space:
2479 case Qt::Key_Select:
2481 if (d->selectionModel)
2482 d->selectionModel->select(currentIndex(), selectionCommand(currentIndex(), event));
2483 if (event->key() == Qt::Key_Space) {
2484 keyboardSearch(event->text());
2485 event->accept();
2486 }
2487 }
2488#ifdef QT_KEYPAD_NAVIGATION
2489 if ( event->key()==Qt::Key_Select ) {
2490 // Also do Key_Enter action.
2491 if (currentIndex().isValid()) {
2492 if (state() != EditingState)
2494 } else {
2495 event->ignore();
2496 }
2497 }
2498#endif
2499 break;
2500#ifdef Q_OS_MACOS
2501 case Qt::Key_Enter:
2502 case Qt::Key_Return:
2503 // Propagate the enter if you couldn't edit the item and there are no
2504 // current editors (if there are editors, the event was most likely propagated from it).
2505 if (!edit(currentIndex(), EditKeyPressed, event) && d->editorIndexHash.isEmpty())
2506 event->ignore();
2507 break;
2508#else
2509 case Qt::Key_F2:
2511 event->ignore();
2512 break;
2513 case Qt::Key_Enter:
2514 case Qt::Key_Return:
2515 // ### we can't open the editor on enter, because
2516 // some widgets will forward the enter event back
2517 // to the viewport, starting an endless loop
2518 if (state() != EditingState || hasFocus()) {
2519 if (currentIndex().isValid())
2521 event->ignore();
2522 }
2523 break;
2524#endif
2525 default: {
2526#ifndef QT_NO_SHORTCUT
2528 selectAll();
2529 break;
2530 }
2531#endif
2532#ifdef Q_OS_MACOS
2533 if (event->key() == Qt::Key_O && event->modifiers() & Qt::ControlModifier && currentIndex().isValid()) {
2535 break;
2536 }
2537#endif
2538 bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier));
2539 if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) {
2540 keyboardSearch(event->text());
2541 event->accept();
2542 } else {
2543 event->ignore();
2544 }
2545 break; }
2546 }
2547 if (d->moveCursorUpdatedView)
2548 event->accept();
2549}
2550
2558{
2559 QAbstractScrollArea::resizeEvent(event);
2561}
2562
2570{
2571 Q_D(QAbstractItemView);
2572 if (event->timerId() == d->fetchMoreTimer.timerId())
2573 d->fetchMore();
2574 else if (event->timerId() == d->delayedReset.timerId())
2575 reset();
2576 else if (event->timerId() == d->autoScrollTimer.timerId())
2577 doAutoScroll();
2578 else if (event->timerId() == d->updateTimer.timerId())
2579 d->updateDirtyRegion();
2580 else if (event->timerId() == d->delayedEditing.timerId()) {
2581 d->delayedEditing.stop();
2582 edit(currentIndex());
2583 } else if (event->timerId() == d->delayedLayout.timerId()) {
2584 d->delayedLayout.stop();
2585 if (isVisible()) {
2586 d->interruptDelayedItemsLayout();
2587 doItemsLayout();
2588 const QModelIndex current = currentIndex();
2589 if (current.isValid() && d->state == QAbstractItemView::EditingState)
2590 scrollTo(current);
2591 }
2592 } else if (event->timerId() == d->delayedAutoScroll.timerId()) {
2593 d->delayedAutoScroll.stop();
2594 //end of the timer: if the current item is still the same as the one when the mouse press occurred
2595 //we only get here if there was no double click
2596 if (d->pressedIndex.isValid() && d->pressedIndex == currentIndex())
2597 scrollTo(d->pressedIndex);
2598 } else if (event->timerId() == d->pressClosedEditorWatcher.timerId()) {
2599 d->pressClosedEditorWatcher.stop();
2600 }
2601}
2602
2607{
2608 Q_D(QAbstractItemView);
2609 // When QAbstractItemView::AnyKeyPressed is used, a new IM composition might
2610 // start before the editor widget acquires focus. Changing focus would interrupt
2611 // the composition, so we keep focus on the view until that first composition
2612 // is complete, and pass QInputMethoEvents on to the editor widget so that the
2613 // user gets the expected feedback. See also inputMethodQuery, which redirects
2614 // calls to the editor widget during that period.
2615 bool forwardEventToEditor = false;
2616 const bool commit = !event->commitString().isEmpty();
2617 const bool preediting = !event->preeditString().isEmpty();
2618 if (QWidget *currentEditor = d->editorForIndex(currentIndex()).widget) {
2619 if (d->waitForIMCommit) {
2620 if (commit || !preediting) {
2621 // commit or cancel
2622 d->waitForIMCommit = false;
2623 QApplication::sendEvent(currentEditor, event);
2624 if (!commit) {
2626 if (delegate)
2627 delegate->setEditorData(currentEditor, currentIndex());
2628 d->selectAllInEditor(currentEditor);
2629 }
2630 if (currentEditor->focusPolicy() != Qt::NoFocus)
2631 currentEditor->setFocus();
2632 } else {
2633 // more pre-editing
2634 QApplication::sendEvent(currentEditor, event);
2635 }
2636 return;
2637 }
2638 } else if (preediting) {
2639 // don't set focus when the editor opens
2640 d->waitForIMCommit = true;
2641 // but pass preedit on to editor
2642 forwardEventToEditor = true;
2643 } else if (!commit) {
2644 event->ignore();
2645 return;
2646 }
2648 d->waitForIMCommit = false;
2649 if (commit)
2650 keyboardSearch(event->commitString());
2651 event->ignore();
2652 } else if (QWidget *currentEditor; forwardEventToEditor
2653 && (currentEditor = d->editorForIndex(currentIndex()).widget)) {
2654 QApplication::sendEvent(currentEditor, event);
2655 }
2656}
2657
2658#if QT_CONFIG(draganddrop)
2682QAbstractItemView::DropIndicatorPosition QAbstractItemView::dropIndicatorPosition() const
2683{
2684 Q_D(const QAbstractItemView);
2685 return d->dropIndicatorPosition;
2686}
2687#endif
2688
2697{
2698 Q_D(const QAbstractItemView);
2699 QModelIndexList indexes;
2700 if (d->selectionModel) {
2701 indexes = d->selectionModel->selectedIndexes();
2702 auto isHidden = [this](const QModelIndex &idx) {
2703 return isIndexHidden(idx);
2704 };
2705 indexes.removeIf(isHidden);
2706 }
2707 return indexes;
2708}
2709
2724{
2725 Q_D(QAbstractItemView);
2726
2727 if (!d->isIndexValid(index))
2728 return false;
2729
2730 if (QWidget *w = (d->persistent.isEmpty() ? static_cast<QWidget*>(nullptr) : d->editorForIndex(index).widget.data())) {
2731 if (w->focusPolicy() == Qt::NoFocus)
2732 return false;
2733 if (!d->waitForIMCommit)
2734 w->setFocus();
2735 else
2736 updateMicroFocus();
2737 return true;
2738 }
2739
2740 if (trigger == DoubleClicked) {
2741 d->delayedEditing.stop();
2742 d->delayedAutoScroll.stop();
2743 } else if (trigger == CurrentChanged) {
2744 d->delayedEditing.stop();
2745 }
2746
2747 // in case e.g. setData() triggers a reset()
2748 QPersistentModelIndex safeIndex(index);
2749
2750 if (d->sendDelegateEvent(index, event)) {
2751 update(safeIndex);
2752 return true;
2753 }
2754
2755 if (!safeIndex.isValid()) {
2756 return false;
2757 }
2758
2759 // save the previous trigger before updating
2760 EditTriggers lastTrigger = d->lastTrigger;
2761 d->lastTrigger = trigger;
2762
2763 if (!d->shouldEdit(trigger, d->model->buddy(safeIndex)))
2764 return false;
2765
2766 if (d->delayedEditing.isActive())
2767 return false;
2768
2769 // we will receive a mouseButtonReleaseEvent after a
2770 // mouseDoubleClickEvent, so we need to check the previous trigger
2771 if (lastTrigger == DoubleClicked && trigger == SelectedClicked)
2772 return false;
2773
2774 // we may get a double click event later
2775 if (trigger == SelectedClicked)
2776 d->delayedEditing.start(QApplication::doubleClickInterval(), this);
2777 else
2778 d->openEditor(safeIndex, d->shouldForwardEvent(trigger, event) ? event : nullptr);
2779
2780 return true;
2781}
2782
2788{
2789 Q_D(QAbstractItemView);
2790 d->updateEditorData(QModelIndex(), QModelIndex());
2791}
2792
2798{
2799 Q_D(QAbstractItemView);
2800 if (d->editorIndexHash.isEmpty())
2801 return;
2802 if (d->delayedPendingLayout) {
2803 // doItemsLayout() will end up calling this function again
2804 d->executePostedLayout();
2805 return;
2806 }
2807 QStyleOptionViewItem option;
2809 QEditorIndexHash::iterator it = d->editorIndexHash.begin();
2810 QWidgetList editorsToRelease;
2811 QWidgetList editorsToHide;
2812 while (it != d->editorIndexHash.end()) {
2813 QModelIndex index = it.value();
2814 QWidget *editor = it.key();
2815 if (index.isValid() && editor) {
2816 option.rect = visualRect(index);
2817 if (option.rect.isValid()) {
2818 editor->show();
2820 if (delegate)
2821 delegate->updateEditorGeometry(editor, option, index);
2822 } else {
2823 editorsToHide << editor;
2824 }
2825 ++it;
2826 } else {
2827 d->indexEditorHash.remove(it.value());
2828 it = d->editorIndexHash.erase(it);
2829 editorsToRelease << editor;
2830 }
2831 }
2832
2833 //we hide and release the editor outside of the loop because it might change the focus and try
2834 //to change the editors hashes.
2835 for (int i = 0; i < editorsToHide.size(); ++i) {
2836 editorsToHide.at(i)->hide();
2837 }
2838 for (int i = 0; i < editorsToRelease.size(); ++i) {
2839 d->releaseEditor(editorsToRelease.at(i));
2840 }
2841}
2842
2849{
2850 Q_D(QAbstractItemView);
2852 d->fetchMoreTimer.start(0, this); //fetch more later
2853 d->updateGeometry();
2854}
2855
2860{
2861 Q_D(QAbstractItemView);
2862 if (verticalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2863 d->model->fetchMore(d->root);
2864 QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2865 if (viewport()->rect().contains(posInVp))
2866 d->checkMouseMove(posInVp);
2867}
2868
2873{
2874 Q_D(QAbstractItemView);
2875 if (horizontalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2876 d->model->fetchMore(d->root);
2877 QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2878 if (viewport()->rect().contains(posInVp))
2879 d->checkMouseMove(posInVp);
2880}
2881
2886{
2887 //do nothing
2888}
2889
2894{
2895 //do nothing
2896}
2897
2908{
2909 Q_D(QAbstractItemView);
2910
2911 // Close the editor
2912 if (editor) {
2913 bool isPersistent = d->persistent.contains(editor);
2914 bool hadFocus = editor->hasFocus();
2915 QModelIndex index = d->indexForEditor(editor);
2916 if (!index.isValid()) {
2917 qWarning("QAbstractItemView::closeEditor called with an editor that does not belong to this view");
2918 return; // the editor was not registered
2919 }
2920
2921 // start a timer that expires immediately when we return to the event loop
2922 // to identify whether this close was triggered by a mousepress-initiated
2923 // focus event
2924 d->pressClosedEditorWatcher.start(0, this);
2925 d->lastEditedIndex = index;
2926
2927 if (!isPersistent) {
2929 QModelIndex index = d->indexForEditor(editor);
2930 editor->removeEventFilter(itemDelegateForIndex(index));
2931 d->removeEditor(editor);
2932 }
2933 if (hadFocus) {
2934 if (focusPolicy() != Qt::NoFocus)
2935 setFocus(); // this will send a focusLost event to the editor
2936 else
2937 editor->clearFocus();
2938 } else {
2939 d->checkPersistentEditorFocus();
2940 }
2941
2942 QPointer<QWidget> ed = editor;
2944 editor = ed;
2945
2946 if (!isPersistent && editor)
2947 d->releaseEditor(editor, index);
2948 }
2949
2950 // The EndEditHint part
2951 QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::NoUpdate;
2952 if (d->selectionMode != NoSelection)
2953 flags = QItemSelectionModel::ClearAndSelect | d->selectionBehaviorFlags();
2954 switch (hint) {
2957 if (index.isValid()) {
2958 QPersistentModelIndex persistent(index);
2959 d->selectionModel->setCurrentIndex(persistent, flags);
2960 // currentChanged signal would have already started editing
2961 if (index.flags() & Qt::ItemIsEditable
2963 edit(persistent);
2964 } break; }
2967 if (index.isValid()) {
2968 QPersistentModelIndex persistent(index);
2969 d->selectionModel->setCurrentIndex(persistent, flags);
2970 // currentChanged signal would have already started editing
2971 if (index.flags() & Qt::ItemIsEditable
2973 edit(persistent);
2974 } break; }
2976 d->model->submit();
2977 break;
2979 d->model->revert();
2980 break;
2981 default:
2982 break;
2983 }
2984}
2985
2992{
2993 Q_D(QAbstractItemView);
2994 if (!editor || !d->itemDelegate || d->currentlyCommittingEditor)
2995 return;
2996 QModelIndex index = d->indexForEditor(editor);
2997 if (!index.isValid()) {
2998 qWarning("QAbstractItemView::commitData called with an editor that does not belong to this view");
2999 return;
3000 }
3001 d->currentlyCommittingEditor = editor;
3003 editor->removeEventFilter(delegate);
3004 delegate->setModelData(editor, d->model, index);
3005 editor->installEventFilter(delegate);
3006 d->currentlyCommittingEditor = nullptr;
3007}
3008
3015{
3016 Q_D(QAbstractItemView);
3017 QWidget *w = qobject_cast<QWidget*>(editor);
3018 d->removeEditor(w);
3019 d->persistent.remove(w);
3020 if (state() == EditingState)
3022}
3023
3024
3025
3035{
3036 Q_D(QAbstractItemView);
3037 if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
3038 return;
3039
3041 : d->model->index(0, 0, d->root);
3042 bool skipRow = false;
3043 bool keyboardTimeWasValid = d->keyboardInputTime.isValid();
3044 qint64 keyboardInputTimeElapsed;
3045 if (keyboardTimeWasValid)
3046 keyboardInputTimeElapsed = d->keyboardInputTime.restart();
3047 else
3048 d->keyboardInputTime.start();
3049 if (search.isEmpty() || !keyboardTimeWasValid
3050 || keyboardInputTimeElapsed > QApplication::keyboardInputInterval()) {
3051 d->keyboardInput = search;
3052 skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0)
3053 } else {
3054 d->keyboardInput += search;
3055 }
3056
3057 // special case for searches with same key like 'aaaaa'
3058 bool sameKey = false;
3059 if (d->keyboardInput.size() > 1) {
3060 int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.size() - 1));
3061 sameKey = (c == d->keyboardInput.size());
3062 if (sameKey)
3063 skipRow = true;
3064 }
3065
3066 // skip if we are searching for the same key or a new search started
3067 if (skipRow) {
3068 QModelIndex parent = start.parent();
3069 int newRow = (start.row() < d->model->rowCount(parent) - 1) ? start.row() + 1 : 0;
3070 start = d->model->index(newRow, start.column(), parent);
3071 }
3072
3073 // search from start with wraparound
3074 QModelIndex current = start;
3076 QModelIndex firstMatch;
3077 QModelIndex startMatch;
3078 QModelIndexList previous;
3079 do {
3080 match = d->model->match(current, Qt::DisplayRole, d->keyboardInput);
3081 if (match == previous)
3082 break;
3083 firstMatch = match.value(0);
3084 previous = match;
3085 if (firstMatch.isValid()) {
3086 if (d->isIndexEnabled(firstMatch)) {
3087 setCurrentIndex(firstMatch);
3088 break;
3089 }
3090 int row = firstMatch.row() + 1;
3091 if (row >= d->model->rowCount(firstMatch.parent()))
3092 row = 0;
3093 current = firstMatch.sibling(row, firstMatch.column());
3094
3095 //avoid infinite loop if all the matching items are disabled.
3096 if (!startMatch.isValid())
3097 startMatch = firstMatch;
3098 else if (startMatch == firstMatch)
3099 break;
3100 }
3101 } while (current != start && firstMatch.isValid());
3102}
3103
3111{
3112 Q_D(const QAbstractItemView);
3113 if (!d->isIndexValid(index))
3114 return QSize();
3115 const auto delegate = itemDelegateForIndex(index);
3116 QStyleOptionViewItem option;
3118 return delegate ? delegate->sizeHint(option, index) : QSize();
3119}
3120
3138{
3139 Q_D(const QAbstractItemView);
3140
3141 if (row < 0 || row >= d->model->rowCount(d->root))
3142 return -1;
3143
3144 ensurePolished();
3145
3146 QStyleOptionViewItem option;
3148 int height = 0;
3149 int colCount = d->model->columnCount(d->root);
3150 for (int c = 0; c < colCount; ++c) {
3151 const QModelIndex index = d->model->index(row, c, d->root);
3152 if (QWidget *editor = d->editorForIndex(index).widget.data())
3153 height = qMax(height, editor->height());
3154 if (const QAbstractItemDelegate *delegate = itemDelegateForIndex(index))
3155 height = qMax(height, delegate->sizeHint(option, index).height());
3156 }
3157 return height;
3158}
3159
3169{
3170 Q_D(const QAbstractItemView);
3171
3172 if (column < 0 || column >= d->model->columnCount(d->root))
3173 return -1;
3174
3175 ensurePolished();
3176
3177 QStyleOptionViewItem option;
3179 int width = 0;
3180 int rows = d->model->rowCount(d->root);
3181 for (int r = 0; r < rows; ++r) {
3182 const QModelIndex index = d->model->index(r, column, d->root);
3183 if (QWidget *editor = d->editorForIndex(index).widget.data())
3184 width = qMax(width, editor->sizeHint().width());
3185 if (const QAbstractItemDelegate *delegate = itemDelegateForIndex(index))
3186 width = qMax(width, delegate->sizeHint(option, index).width());
3187 }
3188 return width;
3189}
3190
3198{
3199 Q_D(QAbstractItemView);
3200 QStyleOptionViewItem options;
3201 initViewItemOption(&options);
3202 options.rect = visualRect(index);
3203 options.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
3204
3205 QWidget *editor = d->editor(index, options);
3206 if (editor) {
3207 editor->show();
3208 d->persistent.insert(editor);
3209 }
3210}
3211
3218{
3219 Q_D(QAbstractItemView);
3220 if (QWidget *editor = d->editorForIndex(index).widget.data()) {
3221 if (index == selectionModel()->currentIndex())
3223 d->persistent.remove(editor);
3224 d->removeEditor(editor);
3225 d->releaseEditor(editor, index);
3226 }
3227}
3228
3237{
3238 Q_D(const QAbstractItemView);
3239 return d->editorForIndex(index).widget;
3240}
3241
3269{
3270 Q_D(QAbstractItemView);
3271 if (!d->isIndexValid(index))
3272 return;
3273 if (indexWidget(index) == widget)
3274 return;
3275 if (QWidget *oldWidget = indexWidget(index)) {
3276 d->persistent.remove(oldWidget);
3277 d->removeEditor(oldWidget);
3278 oldWidget->removeEventFilter(this);
3279 oldWidget->deleteLater();
3280 }
3281 if (widget) {
3283 d->persistent.insert(widget);
3284 d->addEditor(index, widget, true);
3286 widget->show();
3287 dataChanged(index, index); // update the geometry
3288 if (!d->delayedPendingLayout) {
3290 d->doDelayedItemsLayout(); // relayout due to updated geometry
3291 }
3292 }
3293}
3294
3301{
3302 Q_D(const QAbstractItemView);
3303 if (d->isIndexValid(index))
3304 if (QWidget *editor = d->editorForIndex(index).widget.data())
3305 return editor;
3306
3307 return nullptr;
3308}
3309
3318{
3319 verticalScrollBar()->setValue(verticalScrollBar()->minimum());
3320}
3321
3330{
3331 Q_D(QAbstractItemView);
3332 if (d->delayedPendingLayout) {
3333 d->executePostedLayout();
3335 }
3336 verticalScrollBar()->setValue(verticalScrollBar()->maximum());
3337}
3338
3346{
3347 Q_D(QAbstractItemView);
3348 if (index.isValid()) {
3349 const QRect rect = visualRect(index);
3350 //this test is important for performance reason
3351 //For example in dataChanged we simply update all the cells without checking
3352 //it can be a major bottleneck to update rects that aren't even part of the viewport
3353 if (d->viewport->rect().intersects(rect))
3354 d->viewport->update(rect);
3355 }
3356}
3357
3368void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
3369 const QList<int> &roles)
3370{
3371 Q_UNUSED(roles);
3372 // Single item changed
3373 Q_D(QAbstractItemView);
3374 if (topLeft == bottomRight && topLeft.isValid()) {
3375 const QEditorInfo &editorInfo = d->editorForIndex(topLeft);
3376 //we don't update the edit data if it is static
3377 if (!editorInfo.isStatic && editorInfo.widget) {
3378 QAbstractItemDelegate *delegate = itemDelegateForIndex(topLeft);
3379 if (delegate) {
3380 delegate->setEditorData(editorInfo.widget.data(), topLeft);
3381 }
3382 }
3383 if (isVisible() && !d->delayedPendingLayout) {
3384 // otherwise the items will be update later anyway
3385 update(topLeft);
3386 }
3387 } else {
3388 d->updateEditorData(topLeft, bottomRight);
3389 if (isVisible() && !d->delayedPendingLayout) {
3390 if (!topLeft.isValid() ||
3391 topLeft.parent() != bottomRight.parent() ||
3392 topLeft.row() > bottomRight.row() ||
3393 topLeft.column() > bottomRight.column()) {
3394 // invalid parameter - call update() to redraw all
3395 d->viewport->update();
3396 } else {
3397 const QRect updateRect = d->intersectedRect(d->viewport->rect(), topLeft, bottomRight);
3398 if (!updateRect.isEmpty())
3399 d->viewport->update(updateRect);
3400 }
3401 }
3402 }
3403
3404#if QT_CONFIG(accessibility)
3405 if (QAccessible::isActive()) {
3406 QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::DataChanged);
3407 accessibleEvent.setFirstRow(topLeft.row());
3408 accessibleEvent.setFirstColumn(topLeft.column());
3409 accessibleEvent.setLastRow(bottomRight.row());
3410 accessibleEvent.setLastColumn(bottomRight.column());
3411 QAccessible::updateAccessibility(&accessibleEvent);
3412 }
3413#endif
3414 d->updateGeometry();
3415}
3416
3426{
3427 if (!isVisible())
3428 d_func()->fetchMoreTimer.start(0, this); //fetch more later
3429 else
3431}
3432
3440{
3441 Q_D(QAbstractItemView);
3442
3444
3445 // Ensure one selected item in single selection mode.
3446 QModelIndex current = currentIndex();
3447 if (d->selectionMode == SingleSelection
3448 && current.isValid()
3449 && current.row() >= start
3450 && current.row() <= end
3451 && current.parent() == parent) {
3452 int totalToRemove = end - start + 1;
3453 if (d->model->rowCount(parent) <= totalToRemove) { // no more children
3455 while (index != d->root && !d->isIndexEnabled(index))
3456 index = index.parent();
3457 if (index != d->root)
3459 } else {
3460 int row = end + 1;
3462 const int rowCount = d->model->rowCount(parent);
3463 bool found = false;
3464 // find the next visible and enabled item
3465 while (row < rowCount && !found) {
3466 next = d->model->index(row++, current.column(), current.parent());
3467#ifdef QT_DEBUG
3468 if (!next.isValid()) {
3469 qWarning("Model unexpectedly returned an invalid index");
3470 break;
3471 }
3472#endif
3473 if (!isIndexHidden(next) && d->isIndexEnabled(next)) {
3474 found = true;
3475 break;
3476 }
3477 }
3478
3479 if (!found) {
3480 row = start - 1;
3481 // find the previous visible and enabled item
3482 while (row >= 0) {
3483 next = d->model->index(row--, current.column(), current.parent());
3484#ifdef QT_DEBUG
3485 if (!next.isValid()) {
3486 qWarning("Model unexpectedly returned an invalid index");
3487 break;
3488 }
3489#endif
3490 if (!isIndexHidden(next) && d->isIndexEnabled(next))
3491 break;
3492 }
3493 }
3494
3496 }
3497 }
3498
3499 // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
3500 QEditorIndexHash::iterator i = d->editorIndexHash.begin();
3501 while (i != d->editorIndexHash.end()) {
3502 const QModelIndex index = i.value();
3503 if (index.row() >= start && index.row() <= end && d->model->parent(index) == parent) {
3504 QWidget *editor = i.key();
3505 QEditorInfo info = d->indexEditorHash.take(index);
3506 i = d->editorIndexHash.erase(i);
3507 if (info.widget)
3508 d->releaseEditor(editor, index);
3509 } else {
3510 ++i;
3511 }
3512 }
3513}
3514
3523{
3524 Q_UNUSED(index);
3525 Q_UNUSED(start);
3526 Q_UNUSED(end);
3527
3528 Q_Q(QAbstractItemView);
3529 if (q->isVisible())
3530 q->updateEditorGeometries();
3531 q->setState(QAbstractItemView::NoState);
3532#if QT_CONFIG(accessibility)
3533 if (QAccessible::isActive()) {
3534 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::RowsRemoved);
3535 accessibleEvent.setFirstRow(start);
3536 accessibleEvent.setLastRow(end);
3537 QAccessible::updateAccessibility(&accessibleEvent);
3538 }
3539#endif
3541}
3542
3551{
3552 Q_Q(QAbstractItemView);
3553
3555
3556 // Ensure one selected item in single selection mode.
3557 QModelIndex current = q->currentIndex();
3558 if (current.isValid()
3560 && current.column() >= start
3561 && current.column() <= end) {
3562 int totalToRemove = end - start + 1;
3563 if (model->columnCount(parent) < totalToRemove) { // no more columns
3565 while (index.isValid() && !isIndexEnabled(index))
3566 index = index.parent();
3567 if (index.isValid())
3568 q->setCurrentIndex(index);
3569 } else {
3570 int column = end;
3572 const int columnCount = model->columnCount(current.parent());
3573 // find the next visible and enabled item
3574 while (column < columnCount) {
3575 next = model->index(current.row(), column++, current.parent());
3576#ifdef QT_DEBUG
3577 if (!next.isValid()) {
3578 qWarning("Model unexpectedly returned an invalid index");
3579 break;
3580 }
3581#endif
3582 if (!q->isIndexHidden(next) && isIndexEnabled(next))
3583 break;
3584 }
3585 q->setCurrentIndex(next);
3586 }
3587 }
3588
3589 // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
3591 while (it != editorIndexHash.end()) {
3592 QModelIndex index = it.value();
3593 if (index.column() <= start && index.column() >= end && model->parent(index) == parent) {
3594 QWidget *editor = it.key();
3597 if (info.widget)
3599 } else {
3600 ++it;
3601 }
3602 }
3603
3604}
3605
3614{
3615 Q_UNUSED(index);
3616 Q_UNUSED(start);
3617 Q_UNUSED(end);
3618
3619 Q_Q(QAbstractItemView);
3620 if (q->isVisible())
3621 q->updateEditorGeometries();
3622 q->setState(QAbstractItemView::NoState);
3623#if QT_CONFIG(accessibility)
3624 if (QAccessible::isActive()) {
3625 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ColumnsRemoved);
3626 accessibleEvent.setFirstColumn(start);
3627 accessibleEvent.setLastColumn(end);
3628 QAccessible::updateAccessibility(&accessibleEvent);
3629 }
3630#endif
3632}
3633
3634
3641{
3642 Q_UNUSED(index);
3643 Q_UNUSED(start);
3644 Q_UNUSED(end);
3645
3646#if QT_CONFIG(accessibility)
3647 Q_Q(QAbstractItemView);
3648 if (QAccessible::isActive()) {
3649 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::RowsInserted);
3650 accessibleEvent.setFirstRow(start);
3651 accessibleEvent.setLastRow(end);
3652 QAccessible::updateAccessibility(&accessibleEvent);
3653 }
3654#endif
3656}
3657
3664{
3665 Q_UNUSED(index);
3666 Q_UNUSED(start);
3667 Q_UNUSED(end);
3668
3669 Q_Q(QAbstractItemView);
3670 if (q->isVisible())
3671 q->updateEditorGeometries();
3672#if QT_CONFIG(accessibility)
3673 if (QAccessible::isActive()) {
3674 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ColumnsInserted);
3675 accessibleEvent.setFirstColumn(start);
3676 accessibleEvent.setLastColumn(end);
3677 QAccessible::updateAccessibility(&accessibleEvent);
3678 }
3679#endif
3681}
3682
3687{
3690}
3691
3698{
3700#if QT_CONFIG(accessibility)
3701 Q_Q(QAbstractItemView);
3702 if (QAccessible::isActive()) {
3703 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ModelReset);
3704 QAccessible::updateAccessibility(&accessibleEvent);
3705 }
3706#endif
3707}
3708
3710{
3712}
3713
3715{
3717}
3718
3720{
3721 Q_Q(const QAbstractItemView);
3722
3723 const auto parentIdx = topLeft.parent();
3724 QRect updateRect;
3725 for (int r = topLeft.row(); r <= bottomRight.row(); ++r) {
3726 for (int c = topLeft.column(); c <= bottomRight.column(); ++c)
3727 updateRect |= q->visualRect(model->index(r, c, parentIdx));
3728 }
3729 return rect.intersected(updateRect);
3730}
3731
3740 const QItemSelection &deselected)
3741{
3742 Q_D(QAbstractItemView);
3743 if (isVisible() && updatesEnabled()) {
3744 d->viewport->update(visualRegionForSelection(deselected) | visualRegionForSelection(selected));
3745 }
3746}
3747
3756void QAbstractItemView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
3757{
3758 Q_D(QAbstractItemView);
3759 Q_ASSERT(d->model);
3760
3761 if (previous.isValid()) {
3762 QModelIndex buddy = d->model->buddy(previous);
3763 QWidget *editor = d->editorForIndex(buddy).widget.data();
3764 if (editor && !d->persistent.contains(editor)) {
3765 commitData(editor);
3766 if (current.row() != previous.row())
3768 else
3770 }
3771 if (isVisible()) {
3772 update(previous);
3773 }
3774 }
3775
3776 if (current.isValid() && !d->autoScrollTimer.isActive()) {
3777 if (isVisible()) {
3778 if (d->autoScroll)
3779 scrollTo(current);
3780 update(current);
3781 edit(current, CurrentChanged, nullptr);
3782 if (current.row() == (d->model->rowCount(d->root) - 1))
3783 d->fetchMore();
3784 } else {
3785 d->shouldScrollToCurrentOnShow = d->autoScroll;
3786 }
3787 }
3789}
3790
3791#if QT_CONFIG(draganddrop)
3795void QAbstractItemView::startDrag(Qt::DropActions supportedActions)
3796{
3797 Q_D(QAbstractItemView);
3798 QModelIndexList indexes = d->selectedDraggableIndexes();
3799 if (indexes.size() > 0) {
3800 QMimeData *data = d->model->mimeData(indexes);
3801 if (!data)
3802 return;
3803 QRect rect;
3804 QPixmap pixmap = d->renderToPixmap(indexes, &rect);
3805 rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
3806 QDrag *drag = new QDrag(this);
3807 drag->setPixmap(pixmap);
3808 drag->setMimeData(data);
3809 drag->setHotSpot(d->pressedPosition - rect.topLeft());
3810 Qt::DropAction defaultDropAction = Qt::IgnoreAction;
3811 if (dragDropMode() == InternalMove)
3812 supportedActions &= ~Qt::CopyAction;
3813 if (d->defaultDropAction != Qt::IgnoreAction && (supportedActions & d->defaultDropAction))
3814 defaultDropAction = d->defaultDropAction;
3815 else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
3816 defaultDropAction = Qt::CopyAction;
3817 d->dropEventMoved = false;
3818 if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction && !d->dropEventMoved) {
3819 if (dragDropMode() != InternalMove || drag->target() == viewport())
3820 d->clearOrRemove();
3821 }
3822 d->dropEventMoved = false;
3823 // Reset the drop indicator
3824 d->dropIndicatorRect = QRect();
3825 d->dropIndicatorPosition = OnItem;
3826 }
3827}
3828#endif // QT_CONFIG(draganddrop)
3829
3840void QAbstractItemView::initViewItemOption(QStyleOptionViewItem *option) const
3841{
3842 Q_D(const QAbstractItemView);
3843 option->initFrom(this);
3844 option->state &= ~QStyle::State_MouseOver;
3845 option->font = font();
3846
3847 // On mac the focus appearance follows window activation
3848 // not widget activation
3849 if (!hasFocus())
3850 option->state &= ~QStyle::State_Active;
3851
3852 option->state &= ~QStyle::State_HasFocus;
3853 if (d->iconSize.isValid()) {
3854 option->decorationSize = d->iconSize;
3855 } else {
3856 int pm = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this);
3857 option->decorationSize = QSize(pm, pm);
3858 }
3859 option->decorationPosition = QStyleOptionViewItem::Left;
3860 option->decorationAlignment = Qt::AlignCenter;
3861 option->displayAlignment = Qt::AlignLeft|Qt::AlignVCenter;
3862 option->textElideMode = d->textElideMode;
3863 option->rect = QRect();
3864 option->showDecorationSelected = style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, this);
3865 if (d->wrapItemText)
3866 option->features = QStyleOptionViewItem::WrapText;
3867 option->locale = locale();
3868 option->locale.setNumberOptions(QLocale::OmitGroupSeparator);
3869 option->widget = this;
3870}
3871
3878{
3879 Q_D(const QAbstractItemView);
3880 return d->state;
3881}
3882
3889{
3890 Q_D(QAbstractItemView);
3891 d->state = state;
3892}
3893
3904{
3905 Q_D(QAbstractItemView);
3906 d->doDelayedItemsLayout();
3907}
3908
3916{
3917 Q_D(QAbstractItemView);
3918 d->executePostedLayout();
3919}
3920
3932{
3933 Q_D(QAbstractItemView);
3934 d->setDirtyRegion(region);
3935}
3936
3948{
3949 Q_D(QAbstractItemView);
3950 d->scrollDirtyRegion(dx, dy);
3951}
3952
3963{
3964 Q_D(const QAbstractItemView);
3965 return d->scrollDelayOffset;
3966}
3967
3972{
3973 d_func()->startAutoScroll();
3974}
3975
3980{
3981 d_func()->stopAutoScroll();
3982}
3983
3988{
3989 // find how much we should scroll with
3990 Q_D(QAbstractItemView);
3991 QScrollBar *verticalScroll = verticalScrollBar();
3992 QScrollBar *horizontalScroll = horizontalScrollBar();
3993
3994 // QHeaderView does not (normally) have scrollbars
3995 // It needs to use its parents scroll instead
3996 QHeaderView *hv = qobject_cast<QHeaderView*>(this);
3997 if (hv) {
3998 QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea*>(parentWidget());
3999 if (parent) {
4000 if (hv->orientation() == Qt::Horizontal) {
4001 if (!hv->horizontalScrollBar() || !hv->horizontalScrollBar()->isVisible())
4002 horizontalScroll = parent->horizontalScrollBar();
4003 } else {
4004 if (!hv->verticalScrollBar() || !hv->verticalScrollBar()->isVisible())
4005 verticalScroll = parent->verticalScrollBar();
4006 }
4007 }
4008 }
4009
4010 const int verticalStep = verticalScroll->pageStep();
4011 const int horizontalStep = horizontalScroll->pageStep();
4012 if (d->autoScrollCount < qMax(verticalStep, horizontalStep))
4013 ++d->autoScrollCount;
4014
4015 const int margin = d->autoScrollMargin;
4016 const int verticalValue = verticalScroll->value();
4017 const int horizontalValue = horizontalScroll->value();
4018
4019 const QPoint pos = d->draggedPosition - d->offset();
4020 const QRect area = QWidgetPrivate::get(d->viewport)->clipRect();
4021
4022 // do the scrolling if we are in the scroll margins
4023 if (pos.y() - area.top() < margin)
4024 verticalScroll->setValue(verticalValue - d->autoScrollCount);
4025 else if (area.bottom() - pos.y() < margin)
4026 verticalScroll->setValue(verticalValue + d->autoScrollCount);
4027 if (pos.x() - area.left() < margin)
4028 horizontalScroll->setValue(horizontalValue - d->autoScrollCount);
4029 else if (area.right() - pos.x() < margin)
4030 horizontalScroll->setValue(horizontalValue + d->autoScrollCount);
4031 // if nothing changed, stop scrolling
4032 const bool verticalUnchanged = (verticalValue == verticalScroll->value());
4033 const bool horizontalUnchanged = (horizontalValue == horizontalScroll->value());
4034 if (verticalUnchanged && horizontalUnchanged) {
4036 } else {
4037#if QT_CONFIG(draganddrop)
4038 d->dropIndicatorRect = QRect();
4039 d->dropIndicatorPosition = QAbstractItemView::OnViewport;
4040#endif
4041 switch (state()) {
4043 // mouseMoveEvent updates the drag-selection rectangle, so fake an event. This also
4044 // updates draggedPosition taking the now scrolled viewport into account.
4045 const QPoint globalPos = d->viewport->mapToGlobal(pos);
4046 const QPoint windowPos = window()->mapFromGlobal(globalPos);
4047 QMouseEvent mm(QEvent::MouseMove, pos, windowPos, globalPos,
4048 Qt::NoButton, Qt::LeftButton, d->pressedModifiers,
4051 break;
4052 }
4054 // we can't simulate mouse (it would throw off the drag'n'drop state logic) or drag
4055 // (we don't have the mime data or the actions) move events during drag'n'drop, so
4056 // update our dragged position manually after the scroll. "pos" is the old
4057 // draggedPosition - d->offset(), and d->offset() is now updated after scrolling, so
4058 // pos + d->offset() gives us the new position.
4059 d->draggedPosition = pos + d->offset();
4060 break;
4061 }
4062 default:
4063 break;
4064 }
4065 d->viewport->update();
4066 }
4067}
4068
4079QItemSelectionModel::SelectionFlags QAbstractItemView::selectionCommand(const QModelIndex &index,
4080 const QEvent *event) const
4081{
4082 Q_D(const QAbstractItemView);
4083 Qt::KeyboardModifiers keyModifiers = event && event->isInputEvent()
4084 ? static_cast<const QInputEvent*>(event)->modifiers()
4086 switch (d->selectionMode) {
4087 case NoSelection: // Never update selection model
4089 case SingleSelection: // ClearAndSelect on valid index otherwise NoUpdate
4090 if (event) {
4091 switch (event->type()) {
4093 // press with any modifiers on a selected item does nothing
4094 if (d->pressedAlreadySelected)
4096 break;
4098 // clicking into area with no items does nothing
4099 if (!index.isValid())
4101 Q_FALLTHROUGH();
4102 case QEvent::KeyPress:
4103 // ctrl-release on selected item deselects
4104 if ((keyModifiers & Qt::ControlModifier) && d->selectionModel->isSelected(index))
4105 return QItemSelectionModel::Deselect | d->selectionBehaviorFlags();
4106 break;
4107 default:
4108 break;
4109 }
4110 }
4111 return QItemSelectionModel::ClearAndSelect | d->selectionBehaviorFlags();
4112 case MultiSelection:
4113 return d->multiSelectionCommand(index, event);
4114 case ExtendedSelection:
4115 return d->extendedSelectionCommand(index, event);
4117 return d->contiguousSelectionCommand(index, event);
4118 }
4120}
4121
4122QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::multiSelectionCommand(
4123 const QModelIndex &index, const QEvent *event) const
4124{
4125 Q_UNUSED(index);
4126
4127 if (event) {
4128 switch (event->type()) {
4129 case QEvent::KeyPress:
4130 if (static_cast<const QKeyEvent*>(event)->key() == Qt::Key_Space
4131 || static_cast<const QKeyEvent*>(event)->key() == Qt::Key_Select)
4133 break;
4135 if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton) {
4136 // since the press might start a drag, deselect only on release
4138#if QT_CONFIG(draganddrop)
4139 || !dragEnabled || !isIndexDragEnabled(index)
4140#endif
4141 )
4143 }
4144 break;
4146 if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton) {
4148#if QT_CONFIG(draganddrop)
4149 && dragEnabled && isIndexDragEnabled(index)
4150#endif
4151 && index == pressedIndex)
4154 }
4155 break;
4156 case QEvent::MouseMove:
4157 if (static_cast<const QMouseEvent*>(event)->buttons() & Qt::LeftButton)
4158 return QItemSelectionModel::ToggleCurrent|selectionBehaviorFlags(); // toggle drag select
4159 break;
4160 default:
4161 break;
4162 }
4164 }
4165
4167}
4168
4169QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionCommand(
4170 const QModelIndex &index, const QEvent *event) const
4171{
4172 Qt::KeyboardModifiers modifiers = event && event->isInputEvent()
4173 ? static_cast<const QInputEvent*>(event)->modifiers()
4175 if (event) {
4176 switch (event->type()) {
4177 case QEvent::MouseMove: {
4178 // Toggle on MouseMove
4181 break;
4182 }
4184 const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
4185 const bool rightButtonPressed = button & Qt::RightButton;
4186 const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
4187 const bool controlKeyPressed = modifiers & Qt::ControlModifier;
4188 const bool indexIsSelected = selectionModel->isSelected(index);
4189 if ((shiftKeyPressed || controlKeyPressed) && rightButtonPressed)
4191 if (!shiftKeyPressed && !controlKeyPressed && indexIsSelected)
4193 if (!index.isValid() && !rightButtonPressed && !shiftKeyPressed && !controlKeyPressed)
4195 if (!index.isValid())
4197 // since the press might start a drag, deselect only on release
4198 if (controlKeyPressed && !rightButtonPressed && pressedAlreadySelected
4199#if QT_CONFIG(draganddrop)
4200 && dragEnabled && isIndexDragEnabled(index)
4201#endif
4202 ) {
4204 }
4205 break;
4206 }
4208 // ClearAndSelect on MouseButtonRelease if MouseButtonPress on selected item or empty area
4209 const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
4210 const bool rightButtonPressed = button & Qt::RightButton;
4211 const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
4212 const bool controlKeyPressed = modifiers & Qt::ControlModifier;
4215 && !shiftKeyPressed && !controlKeyPressed && (!rightButtonPressed || !index.isValid()))
4217 if (index == pressedIndex && controlKeyPressed && !rightButtonPressed
4218#if QT_CONFIG(draganddrop)
4219 && dragEnabled && isIndexDragEnabled(index)
4220#endif
4221 ) {
4222 break;
4223 }
4225 }
4226 case QEvent::KeyPress: {
4227 // NoUpdate on Key movement and Ctrl
4228 switch (static_cast<const QKeyEvent*>(event)->key()) {
4229 case Qt::Key_Backtab:
4230 modifiers = modifiers & ~Qt::ShiftModifier; // special case for backtab
4231 Q_FALLTHROUGH();
4232 case Qt::Key_Down:
4233 case Qt::Key_Up:
4234 case Qt::Key_Left:
4235 case Qt::Key_Right:
4236 case Qt::Key_Home:
4237 case Qt::Key_End:
4238 case Qt::Key_PageUp:
4239 case Qt::Key_PageDown:
4240 case Qt::Key_Tab:
4242#ifdef QT_KEYPAD_NAVIGATION
4243 // Preserve historical tab order navigation behavior
4244 || QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
4245#endif
4246 )
4248 break;
4249 case Qt::Key_Select:
4251 case Qt::Key_Space:// Toggle on Ctrl-Qt::Key_Space, Select on Space
4255 default:
4256 break;
4257 }
4258 }
4259 default:
4260 break;
4261 }
4262 }
4263
4269 //when drag-selecting we need to clear any previous selection and select the current one
4271 }
4272
4274}
4275
4276QItemSelectionModel::SelectionFlags
4278 const QEvent *event) const
4279{
4280 QItemSelectionModel::SelectionFlags flags = extendedSelectionCommand(index, event);
4284
4285 switch (flags & Mask) {
4289 return flags;
4291 if (event &&
4293 || event->type() == QEvent::MouseButtonRelease))
4294 return flags;
4296 default:
4298 }
4299}
4300
4302{
4303 fetchMoreTimer.stop();
4304 if (!model->canFetchMore(root))
4305 return;
4306 int last = model->rowCount(root) - 1;
4307 if (last < 0) {
4309 return;
4310 }
4311
4312 QModelIndex index = model->index(last, 0, root);
4313 QRect rect = q_func()->visualRect(index);
4314 if (viewport->rect().intersects(rect))
4316}
4317
4319 const QModelIndex &index) const
4320{
4321 if (!index.isValid())
4322 return false;
4323 Qt::ItemFlags flags = model->flags(index);
4324 if (((flags & Qt::ItemIsEditable) == 0) || ((flags & Qt::ItemIsEnabled) == 0))
4325 return false;
4327 return false;
4328 if (hasEditor(index))
4329 return false;
4330 if (trigger == QAbstractItemView::AllEditTriggers) // force editing
4331 return true;
4334 return false;
4335 return (trigger & editTriggers);
4336}
4337
4339 const QEvent *event) const
4340{
4342 return false;
4343
4344 switch (event->type()) {
4345 case QEvent::KeyPress:
4349 case QEvent::MouseMove:
4350 return true;
4351 default:
4352 break;
4353 };
4354
4355 return false;
4356}
4357
4359{
4360 if (!autoScroll)
4361 return false;
4362 QRect area = static_cast<QAbstractItemView*>(viewport)->d_func()->clipRect(); // access QWidget private by bending C++ rules
4363 return (pos.y() - area.top() < autoScrollMargin)
4364 || (area.bottom() - pos.y() < autoScrollMargin)
4365 || (pos.x() - area.left() < autoScrollMargin)
4366 || (area.right() - pos.x() < autoScrollMargin);
4367}
4368
4370{
4371 if (!delayedPendingLayout) {
4372 delayedPendingLayout = true;
4373 delayedLayout.start(delay, q_func());
4374 }
4375}
4376
4378{
4379 delayedLayout.stop();
4380 delayedPendingLayout = false;
4381}
4382
4384{
4385 Q_Q(QAbstractItemView);
4386 if (sizeAdjustPolicy == QAbstractScrollArea::AdjustIgnored)
4387 return;
4388 if (sizeAdjustPolicy == QAbstractScrollArea::AdjustToContents || !shownOnce)
4389 q->updateGeometry();
4390}
4391
4392/*
4393 Handles selection of content for some editors containing QLineEdit.
4394
4395 ### Qt 7 This should be done by a virtual method in QAbstractItemDelegate.
4396*/
4398{
4399 while (QWidget *fp = editor->focusProxy())
4400 editor = fp;
4401
4402#if QT_CONFIG(lineedit)
4403 if (QLineEdit *le = qobject_cast<QLineEdit*>(editor))
4404 le->selectAll();
4405#endif
4406#if QT_CONFIG(spinbox)
4407 if (QSpinBox *sb = qobject_cast<QSpinBox*>(editor))
4408 sb->selectAll();
4409 else if (QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox*>(editor))
4410 dsb->selectAll();
4411#endif
4412}
4413
4415 const QStyleOptionViewItem &options)
4416{
4417 Q_Q(QAbstractItemView);
4419 if (!w) {
4420 QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
4421 if (!delegate)
4422 return nullptr;
4423 w = delegate->createEditor(viewport, options, index);
4424 if (w) {
4425 w->installEventFilter(delegate);
4426 QObject::connect(w, SIGNAL(destroyed(QObject*)), q, SLOT(editorDestroyed(QObject*)));
4427 delegate->updateEditorGeometry(w, options, index);
4428 delegate->setEditorData(w, index);
4429 addEditor(index, w, false);
4430 if (w->parent() == viewport)
4432
4434 }
4435 }
4436
4437 return w;
4438}
4439
4441{
4442 Q_Q(QAbstractItemView);
4443 // we are counting on having relatively few editors
4444 const bool checkIndexes = tl.isValid() && br.isValid();
4445 const QModelIndex parent = tl.parent();
4446 // QTBUG-25370: We need to copy the indexEditorHash, because while we're
4447 // iterating over it, we are calling methods which can allow user code to
4448 // call a method on *this which can modify the member indexEditorHash.
4449 const QIndexEditorHash indexEditorHashCopy = indexEditorHash;
4450 QIndexEditorHash::const_iterator it = indexEditorHashCopy.constBegin();
4451 for (; it != indexEditorHashCopy.constEnd(); ++it) {
4452 QWidget *editor = it.value().widget.data();
4453 const QModelIndex index = it.key();
4454 if (it.value().isStatic || !editor || !index.isValid() ||
4455 (checkIndexes
4456 && (index.row() < tl.row() || index.row() > br.row()
4457 || index.column() < tl.column() || index.column() > br.column()
4458 || index.parent() != parent)))
4459 continue;
4460
4461 QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
4462 if (delegate) {
4463 delegate->setEditorData(editor, index);
4464 }
4465 }
4466}
4467
4478{
4479#if QT_CONFIG(draganddrop)
4482
4483 if (!overwrite) {
4484 for (; it != selection.constEnd(); ++it) {
4485 QModelIndex parent = (*it).parent();
4486 if ((*it).left() != 0)
4487 continue;
4488 if ((*it).right() != (model->columnCount(parent) - 1))
4489 continue;
4490 int count = (*it).bottom() - (*it).top() + 1;
4491 model->removeRows((*it).top(), count, parent);
4492 }
4493 } else {
4494 // we can't remove the rows so reset the items (i.e. the view is like a table)
4496 for (int i=0; i < list.size(); ++i) {
4499 for (QMap<int, QVariant>::Iterator it = roles.begin(); it != roles.end(); ++it)
4500 it.value() = QVariant();
4501 model->setItemData(index, roles);
4502 }
4503 }
4504#endif
4505}
4506
4514{
4515 Q_Q(QAbstractItemView);
4517 if (persistent.contains(widget)) {
4518 //a persistent editor has gained the focus
4521 q->setCurrentIndex(index);
4522 }
4523 }
4524}
4525
4526
4528{
4529 static QEditorInfo nullInfo;
4530
4531 // do not try to search to avoid slow implicit cast from QModelIndex to QPersistentModelIndex
4533 return nullInfo;
4534
4536 if (it == indexEditorHash.end())
4537 return nullInfo;
4538
4539 return it.value();
4540}
4541
4543{
4544 // Search's implicit cast (QModelIndex to QPersistentModelIndex) is slow; use cheap pre-test to avoid when we can.
4546}
4547
4549{
4550 // do not try to search to avoid slow implicit cast from QModelIndex to QPersistentModelIndex
4552 return QModelIndex();
4553
4555 if (it == editorIndexHash.end())
4556 return QModelIndex();
4557
4558 return it.value();
4559}
4560
4562{
4563 const auto it = editorIndexHash.constFind(editor);
4564 if (it != editorIndexHash.cend()) {
4565 indexEditorHash.remove(it.value());
4567 }
4568}
4569
4571{
4574}
4575
4577{
4578 Q_Q(const QAbstractItemView);
4579 QModelIndex buddy = model->buddy(index);
4580 QStyleOptionViewItem options;
4581 q->initViewItemOption(&options);
4582 options.rect = q->visualRect(buddy);
4583 options.state |= (buddy == q->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
4584 QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
4585 return (event && delegate && delegate->editorEvent(event, model, options, buddy));
4586}
4587
4589{
4590 Q_Q(QAbstractItemView);
4591
4592 QModelIndex buddy = model->buddy(index);
4593 QStyleOptionViewItem options;
4594 q->initViewItemOption(&options);
4595 options.rect = q->visualRect(buddy);
4596 options.state |= (buddy == q->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
4597
4598 QWidget *w = editor(buddy, options);
4599 if (!w)
4600 return false;
4601
4603 w->show();
4604 if (!waitForIMCommit)
4605 w->setFocus();
4606 else
4607 q->updateMicroFocus();
4608
4609 if (event)
4610 QCoreApplication::sendEvent(w->focusProxy() ? w->focusProxy() : w, event);
4611
4612 return true;
4613}
4614
4615/*
4616 \internal
4617
4618 returns the pair QRect/QModelIndex that should be painted on the viewports's rect
4619*/
4620
4622{
4623 Q_ASSERT(r);
4624 Q_Q(const QAbstractItemView);
4625 QRect &rect = *r;
4626 const QRect viewportRect = viewport->rect();
4628 for (const auto &index : indexes) {
4629 const QRect current = q->visualRect(index);
4630 if (current.intersects(viewportRect)) {
4631 ret.append({current, index});
4632 rect |= current;
4633 }
4634 }
4635 QRect clipped = rect & viewportRect;
4636 rect.setLeft(clipped.left());
4637 rect.setRight(clipped.right());
4638 return ret;
4639}
4640
4642{
4643 Q_Q(const QAbstractItemView);
4644 Q_ASSERT(r);
4645 QItemViewPaintPairs paintPairs = draggablePaintPairs(indexes, r);
4646 if (paintPairs.isEmpty())
4647 return QPixmap();
4648
4649 QWindow *window = windowHandle(WindowHandleMode::Closest);
4650 const qreal scale = window ? window->devicePixelRatio() : qreal(1);
4651
4652 QPixmap pixmap(r->size() * scale);
4653 pixmap.setDevicePixelRatio(scale);
4654
4655 pixmap.fill(Qt::transparent);
4657 QStyleOptionViewItem option;
4658 q->initViewItemOption(&option);
4660 for (int j = 0; j < paintPairs.size(); ++j) {
4661 option.rect = paintPairs.at(j).rect.translated(-r->topLeft());
4662 const QModelIndex &current = paintPairs.at(j).index;
4664 q->itemDelegateForIndex(current)->paint(&painter, option, current);
4665 }
4666 return pixmap;
4667}
4668
4669void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
4670{
4671 if (!selectionModel)
4672 return;
4673 if (!model->hasChildren(root))
4674 return;
4675
4677 QModelIndex tl = model->index(0, 0, root);
4679 model->columnCount(root) - 1,
4680 root);
4682 selectionModel->select(selection, command);
4683}
4684
4685#if QT_CONFIG(draganddrop)
4686QModelIndexList QAbstractItemViewPrivate::selectedDraggableIndexes() const
4687{
4688 Q_Q(const QAbstractItemView);
4689 QModelIndexList indexes = q->selectedIndexes();
4690 auto isNotDragEnabled = [this](const QModelIndex &index) {
4691 return !isIndexDragEnabled(index);
4692 };
4693 indexes.removeIf(isNotDragEnabled);
4694 return indexes;
4695}
4696
4697void QAbstractItemViewPrivate::maybeStartDrag(QPoint eventPosition)
4698{
4699 Q_Q(QAbstractItemView);
4700
4701 const QPoint topLeft = pressedPosition - offset();
4702 if ((topLeft - eventPosition).manhattanLength() > QApplication::startDragDistance()) {
4704 q->startDrag(model->supportedDragActions());
4705 q->setState(QAbstractItemView::NoState); // the startDrag will return when the dnd operation
4706 // is done
4707 q->stopAutoScroll();
4708 }
4709}
4710#endif
4711
4717{
4718 Q_D(QAbstractItemView);
4719 if (object == this || object == viewport() || event->type() != QEvent::FocusIn)
4720 return QAbstractScrollArea::eventFilter(object, event);
4722 // If it is not a persistent widget then we did not install
4723 // the event filter on it, so assume a base implementation is
4724 // filtering
4725 if (!widget || !d->persistent.contains(widget))
4726 return QAbstractScrollArea::eventFilter(object, event);
4727 setCurrentIndex(d->indexForEditor(widget));
4728 return false;
4729}
4730
4732
4733#include "moc_qabstractitemview.cpp"
The QAbstractItemDelegate class is used to display and edit data items from a model.
virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
Returns the editor to be used for editing the data item with the given index.
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
Updates the geometry of the editor for the item with the given index, according to the rectangle spec...
virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
When editing of an item starts, this function is called with the event that triggered the editing,...
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const
Sets the contents of the given editor to the data for the item at the given index.
EndEditHint
This enum describes the different hints that the delegate can give to the model and view components t...
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
Sets the data for the item at the given index in the model to the contents of the given editor.
virtual bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index)
static QAbstractItemModel * staticEmptyModel()
virtual Qt::DropActions supportedDropActions() const
Q_INVOKABLE int const QModelIndex & parent
Returns the parent of the model item with the given index.
virtual Q_INVOKABLE Qt::ItemFlags flags(const QModelIndex &index) const
Returns the item flags for the given index.
virtual Q_INVOKABLE bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Returns {true} if parent has any children; otherwise returns {false}.
virtual Q_INVOKABLE int rowCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of rows under the given parent.
virtual Q_INVOKABLE void fetchMore(const QModelIndex &parent)
Fetches any available data for the items with the parent specified by the parent index.
virtual QModelIndex buddy(const QModelIndex &index) const
Returns a model index for the buddy of the item represented by index.
bool checkIndex(const QModelIndex &index, CheckIndexOptions options=CheckIndexOption::NoOption) const
virtual Q_INVOKABLE bool canFetchMore(const QModelIndex &parent) const
Returns {true} if there is more data available for parent; otherwise returns {false}.
virtual QMap< int, QVariant > itemData(const QModelIndex &index) const
Returns a map with values for all predefined roles in the model for the item at the given index.
virtual bool setItemData(const QModelIndex &index, const QMap< int, QVariant > &roles)
Sets the role data for the item at index to the associated value in roles, for every Qt::ItemDataRole...
virtual Qt::DropActions supportedDragActions() const
Returns the actions supported by the data in this model.
virtual Q_INVOKABLE int columnCount(const QModelIndex &parent=QModelIndex()) const =0
Returns the number of columns for the children of the given parent.
virtual Q_INVOKABLE QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const =0
Returns the data stored under the given role for the item referred to by the index.
virtual Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
Returns the index of the item in the model specified by the given row, column and parent index.
const QEditorInfo & editorForIndex(const QModelIndex &index) const
virtual QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
void doDelayedItemsLayout(int delay=0)
QItemSelectionModel::SelectionFlags contiguousSelectionCommand(const QModelIndex &index, const QEvent *event) const
virtual void adjustViewOptionsForIndex(QStyleOptionViewItem *, const QModelIndex &) const
void removeEditor(QWidget *editor)
void updateEditorData(const QModelIndex &topLeft, const QModelIndex &bottomRight)
virtual void _q_rowsInserted(const QModelIndex &parent, int start, int end)
bool hasEditor(const QModelIndex &index) const
virtual void _q_rowsRemoved(const QModelIndex &parent, int start, int end)
void addEditor(const QModelIndex &index, QWidget *editor, bool isStatic)
QAbstractItemView::EditTriggers editTriggers
virtual QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const
bool shouldEdit(QAbstractItemView::EditTrigger trigger, const QModelIndex &index) const
QAbstractItemView::ScrollMode horizontalScrollMode
void setHoverIndex(const QPersistentModelIndex &index)
virtual void _q_columnsRemoved(const QModelIndex &parent, int start, int end)
virtual void _q_rowsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart)
QAbstractItemView::State state
void _q_delegateSizeHintChanged(const QModelIndex &index)
QPointer< QItemSelectionModel > selectionModel
bool shouldAutoScroll(const QPoint &pos) const
bool shouldForwardEvent(QAbstractItemView::EditTrigger trigger, const QEvent *event) const
QItemSelectionModel::SelectionFlags selectionBehaviorFlags() const
virtual void _q_columnsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart)
QPersistentModelIndex root
bool droppingOnItself(QDropEvent *event, const QModelIndex &index)
bool openEditor(const QModelIndex &index, QEvent *event)
void checkMouseMove(const QPersistentModelIndex &index)
QPersistentModelIndex pressedIndex
QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r) const
QAbstractItemView::SelectionMode selectionMode
bool sendDelegateEvent(const QModelIndex &index, QEvent *event) const
QItemSelectionModel::SelectionFlags extendedSelectionCommand(const QModelIndex &index, const QEvent *event) const
QPersistentModelIndex enteredIndex
virtual void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
QItemSelectionModel::SelectionFlags multiSelectionCommand(const QModelIndex &index, const QEvent *event) const
virtual void _q_columnsInserted(const QModelIndex &parent, int start, int end)
void releaseEditor(QWidget *editor, const QModelIndex &index=QModelIndex()) const
QWidget * editor(const QModelIndex &index, const QStyleOptionViewItem &options)
virtual void selectAll(QItemSelectionModel::SelectionFlags command)
QModelIndex indexForEditor(QWidget *editor) const
QAbstractItemView::SelectionBehavior selectionBehavior
QAbstractItemView::ScrollMode verticalScrollMode
QPersistentModelIndex hover
bool isIndexEnabled(const QModelIndex &index) const
The QAbstractItemView class provides the basic functionality for item view classes.
virtual QRect visualRect(const QModelIndex &index) const =0
Returns the rectangle on the viewport occupied by the item at index.
void inputMethodEvent(QInputMethodEvent *event) override
\reimp
void setVerticalScrollMode(ScrollMode mode)
SelectionMode
This enum indicates how the view responds to user selections:
QWidget * indexWidget(const QModelIndex &index) const
void activated(const QModelIndex &index)
This signal is emitted when the item specified by index is activated by the user.
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const =0
Returns the region from the viewport of the items in the given selection.
void setEditTriggers(EditTriggers triggers)
void iconSizeChanged(const QSize &size)
virtual void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)=0
Applies the selection flags to the items in or touched by the rectangle, rect.
QAbstractItemModel * model() const
Returns the model that this view is presenting.
virtual void horizontalScrollbarValueChanged(int value)
virtual int verticalOffset() const =0
Returns the vertical offset of the view.
void setCurrentIndex(const QModelIndex &index)
Sets the current item to be the item at index.
void setItemDelegateForRow(int row, QAbstractItemDelegate *delegate)
void doubleClicked(const QModelIndex &index)
This signal is emitted when a mouse button is double-clicked.
bool event(QEvent *event) override
\reimp
virtual void setSelectionModel(QItemSelectionModel *selectionModel)
Sets the current selection model to the given selectionModel.
QPoint dirtyRegionOffset() const
Returns the offset of the dirty regions in the view.
void timerEvent(QTimerEvent *event) override
This function is called with the given event when a timer event is sent to the widget.
ScrollMode verticalScrollMode
how the view scrolls its contents in the vertical direction
virtual void verticalScrollbarAction(int action)
virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
This slot is called when the selection is changed.
void focusOutEvent(QFocusEvent *event) override
This function is called with the given event when the widget loses the focus.
void setHorizontalScrollMode(ScrollMode mode)
SelectionBehavior
\value SelectItems Selecting single items.
void focusInEvent(QFocusEvent *event) override
This function is called with the given event when the widget obtains the focus.
State state() const
Returns the item view's state.
virtual void reset()
Reset the internal state of the view.
void mouseReleaseEvent(QMouseEvent *event) override
This function is called with the given event when a mouse button is released, after a mouse press eve...
void setTextElideMode(Qt::TextElideMode mode)
QAbstractItemView(QWidget *parent=nullptr)
Constructs an abstract item view with the given parent.
~QAbstractItemView()
Destroys the view.
void setItemDelegate(QAbstractItemDelegate *delegate)
Sets the item delegate for this view and its model to delegate.
virtual QAbstractItemDelegate * itemDelegateForIndex(const QModelIndex &index) const
bool tabKeyNavigation
whether item navigation with tab and backtab is enabled.
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >())
This slot is called when items with the given roles are changed in the model.
bool eventFilter(QObject *object, QEvent *event) override
\reimp
QModelIndex currentIndex() const
Returns the model index of the current item.
bool viewportEvent(QEvent *event) override
This function is used to handle tool tips, and What's This? mode, if the given event is a QEvent::Too...
void setDirtyRegion(const QRegion &region)
void setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
This slot is called when rows are about to be removed.
virtual void setModel(QAbstractItemModel *model)
Sets the model for the view to present.
EditTriggers editTriggers
which actions will initiate item editing
ScrollMode horizontalScrollMode
how the view scrolls its contents in the horizontal direction
void setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate)
virtual void updateEditorData()
State
Describes the different states the view can be in.
EditTrigger
This enum describes actions which will initiate item editing.
virtual void setRootIndex(const QModelIndex &index)
Sets the root item to the item at the given index.
void setAlternatingRowColors(bool enable)
virtual void initViewItemOption(QStyleOptionViewItem *option) const
bool focusNextPrevChild(bool next) override
\reimp
void setIconSize(const QSize &size)
virtual void doItemsLayout()
void scrollDirtyRegion(int dx, int dy)
Prepares the view for scrolling by ({dx},{dy}) pixels by moving the dirty regions in the opposite dir...
Qt::TextElideMode textElideMode
the position of the "..." in elided text.
void keyPressEvent(QKeyEvent *event) override
This function is called with the given event when a key event is sent to the widget.
virtual void scrollTo(const QModelIndex &index, ScrollHint hint=EnsureVisible)=0
Scrolls the view if necessary to ensure that the item at index is visible.
void update(const QModelIndex &index)
void setTabKeyNavigation(bool enable)
QModelIndex rootIndex() const
Returns the model index of the model's root item.
QAbstractItemDelegate * itemDelegateForRow(int row) const
QSize iconSize
the size of items' icons
void setAutoScroll(bool enable)
virtual int horizontalOffset() const =0
Returns the horizontal offset of the view.
void executeDelayedItemsLayout()
Executes the scheduled layouts without waiting for the event processing to begin.
QAbstractItemDelegate * itemDelegate() const
Returns the item delegate used by this view and model.
bool isPersistentEditorOpen(const QModelIndex &index) const
SelectionMode selectionMode
which selection mode the view operates in
virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)=0
Returns a QModelIndex object pointing to the next object in the view, based on the given cursorAction...
void setIndexWidget(const QModelIndex &index, QWidget *widget)
virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous)
This slot is called when a new item becomes the current item.
virtual void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
Closes the given editor, and releases it.
bool alternatingRowColors
whether to draw the background using alternating colors
void resizeEvent(QResizeEvent *event) override
This function is called with the given event when a resize event is sent to the widget.
void scheduleDelayedItemsLayout()
Schedules a layout of the items in the view to be executed when the event processing starts.
void openPersistentEditor(const QModelIndex &index)
Opens a persistent editor on the item at the given index.
QSize sizeHintForIndex(const QModelIndex &index) const
Returns the size hint for the item with the specified index or an invalid size for invalid indexes.
virtual void commitData(QWidget *editor)
Commit the data in the editor to the model.
bool autoScroll
whether autoscrolling in drag move events is enabled
void pressed(const QModelIndex &index)
This signal is emitted when a mouse button is pressed.
virtual void keyboardSearch(const QString &search)
Moves to and selects the item best matching the string search.
void mousePressEvent(QMouseEvent *event) override
This function is called with the given event when a mouse button is pressed while the cursor is insid...
virtual void rowsInserted(const QModelIndex &parent, int start, int end)
This slot is called when rows are inserted.
virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const override
\reimp
virtual QModelIndexList selectedIndexes() const
This convenience function returns a list of all selected and non-hidden item indexes in the view.
virtual void selectAll()
Selects all items in the view.
void setAutoScrollMargin(int margin)
void clicked(const QModelIndex &index)
This signal is emitted when a mouse button is left-clicked.
int autoScrollMargin
the size of the area when auto scrolling is triggered
virtual void updateEditorGeometries()
void edit(const QModelIndex &index)
Starts editing the item corresponding to the given index if it is editable.
virtual bool isIndexHidden(const QModelIndex &index) const =0
Returns true if the item referred to by the given index is hidden in the view, otherwise returns fals...
void setState(State state)
Sets the item view's state to the given state.
virtual QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &index, const QEvent *event=nullptr) const
Returns the SelectionFlags to be used when updating a selection model for the specified index.
virtual int sizeHintForColumn(int column) const
Returns the width size hint for the specified column or -1 if there is no model.
void clearSelection()
Deselects all selected items.
void mouseMoveEvent(QMouseEvent *event) override
This function is called with the given event when a mouse move event is sent to the widget.
QItemSelectionModel * selectionModel() const
Returns the current selection model.
virtual QModelIndex indexAt(const QPoint &point) const =0
Returns the model index of the item at the viewport coordinates point.
virtual void editorDestroyed(QObject *editor)
This function is called when the given editor has been destroyed.
void mouseDoubleClickEvent(QMouseEvent *event) override
This function is called with the given event when a mouse button is double clicked inside the widget.
QAbstractItemDelegate * itemDelegateForColumn(int column) const
void closePersistentEditor(const QModelIndex &index)
Closes the persistent editor for the item at the given index.
void setSelectionMode(QAbstractItemView::SelectionMode mode)
virtual void verticalScrollbarValueChanged(int value)
virtual void updateGeometries()
SelectionBehavior selectionBehavior
which selection behavior the view uses
QSize viewportSizeHint() const override
virtual void horizontalScrollbarAction(int action)
virtual int sizeHintForRow(int row) const
Returns the height size hint for the specified row or -1 if there is no model.
int value
the slider's current value
int pageStep
the page step.
static QWidget * focusWidget()
Returns the application widget that has the keyboard input focus, or \nullptr if no widget in this ap...
int doubleClickInterval
the time limit in milliseconds that distinguishes a double click from two consecutive mouse clicks
int startDragDistance
the minimum distance required for a drag and drop operation to start.
int keyboardInputInterval
the time limit in milliseconds that distinguishes a key press from two consecutive key presses
void start(int msec, QObject *obj)
\obsolete Use chrono overload instead.
void stop()
Stops the timer.
void setText(const QString &, Mode mode=Clipboard)
Copies text into the clipboard as plain text.
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static void sendPostedEvents(QObject *receiver=nullptr, int event_type=0)
Immediately dispatches all events which have been previously queued with QCoreApplication::postEvent(...
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
The QDoubleSpinBox class provides a spin box widget that takes doubles.
Definition qspinbox.h:82
\inmodule QtGui
Definition qdrag.h:22
void setHotSpot(const QPoint &hotspot)
Sets the position of the hot spot relative to the top-left corner of the pixmap used to the point spe...
Definition qdrag.cpp:146
Qt::DropAction exec(Qt::DropActions supportedActions=Qt::MoveAction)
Definition qdrag.cpp:199
void setMimeData(QMimeData *data)
Sets the data to be sent to the given MIME data.
Definition qdrag.cpp:99
void setPixmap(const QPixmap &)
Sets pixmap as the pixmap used to represent the data in a drag and drop operation.
Definition qdrag.cpp:123
QObject * target() const
Returns the target of the drag and drop operation.
Definition qdrag.cpp:176
void invalidate() noexcept
Marks this QElapsedTimer object as invalid.
\inmodule QtCore
Definition qcoreevent.h:45
@ QueryWhatsThis
Definition qcoreevent.h:169
@ LayoutDirectionChange
Definition qcoreevent.h:124
@ ApplicationLayoutDirectionChange
Definition qcoreevent.h:92
@ FocusOut
Definition qcoreevent.h:67
@ StyleChange
Definition qcoreevent.h:136
@ LocaleChange
Definition qcoreevent.h:122
@ FontChange
Definition qcoreevent.h:133
@ MouseMove
Definition qcoreevent.h:63
@ KeyPress
Definition qcoreevent.h:64
@ FocusIn
Definition qcoreevent.h:66
@ MouseButtonPress
Definition qcoreevent.h:60
@ HoverLeave
Definition qcoreevent.h:176
@ HoverEnter
Definition qcoreevent.h:175
@ WindowActivate
Definition qcoreevent.h:83
@ HoverMove
Definition qcoreevent.h:177
@ MouseButtonDblClick
Definition qcoreevent.h:62
@ WhatsThis
Definition qcoreevent.h:148
@ ScrollPrepare
Definition qcoreevent.h:256
@ WindowDeactivate
Definition qcoreevent.h:84
@ MouseButtonRelease
Definition qcoreevent.h:61
The QFocusEvent class contains event parameters for widget focus events.
Definition qevent.h:469
static QClipboard * clipboard()
Returns the object for interacting with the clipboard.
static Qt::KeyboardModifiers keyboardModifiers()
Returns the current state of the modifier keys on the keyboard.
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1202
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1279
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1209
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1258
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1205
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:975
iterator erase(const_iterator it)
Definition qhash.h:1223
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
const_iterator cend() const noexcept
Definition qhash.h:1208
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:926
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
The QHeaderView class provides a header row or header column for item views.
Definition qheaderview.h:18
Qt::Orientation orientation() const
Returns the orientation of the header.
The QHelpEvent class provides an event that is used to request helpful information about a particular...
Definition qevent.h:787
const QPoint & pos() const
Returns the mouse cursor position when the event was generated, relative to the widget to which the e...
Definition qevent.h:797
\inmodule QtGui
Definition qevent.h:245
\inmodule QtGui
Definition qevent.h:49
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:624
Q_INVOKABLE bool isSelected(const QModelIndex &index) const
Returns true if the given model item index is selected.
virtual void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
Sets the model item index to be the current item, and emits currentChanged().
virtual void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
Selects the model item index using the specified command, and emits selectionChanged().
QAbstractItemModel * model
\inmodule QtCore
Q_CORE_EXPORT QModelIndexList indexes() const
Returns a list of model indexes that correspond to the selected items.
The QKeyEvent class describes a key event.
Definition qevent.h:423
The QLineEdit widget is a one-line text editor.
Definition qlineedit.h:28
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
const_iterator constBegin() const noexcept
Definition qlist.h:615
qsizetype removeIf(Predicate pred)
Definition qlist.h:587
void append(parameter_type t)
Definition qlist.h:441
const_iterator constEnd() const noexcept
Definition qlist.h:616
@ OmitGroupSeparator
Definition qlocale.h:869
Definition qmap.h:186
iterator begin()
Definition qmap.h:597
iterator end()
Definition qmap.h:601
\inmodule QtCore
Definition qmimedata.h:16
\inmodule QtCore
constexpr int row() const noexcept
Returns the row this model index refers to.
QModelIndex parent() const
Returns the parent of the model index, or QModelIndex() if it has no parent.
Qt::ItemFlags flags() const
constexpr int column() const noexcept
Returns the column this model index refers to.
constexpr bool isValid() const noexcept
Returns {true} if this model index is valid; otherwise returns {false}.
QModelIndex sibling(int row, int column) const
Returns the sibling at row and column.
\inmodule QtGui
Definition qevent.h:195
\inmodule QtCore
Definition qobject.h:90
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2269
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
bool isValid() const
Returns {true} if this persistent model index is valid; otherwise returns {false}.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore
Definition qpointer.h:18
T * data() const
Definition qpointer.h:56
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:166
bool intersects(const QRect &r) const noexcept
Returns true if this rectangle intersects with the given rectangle (i.e., there is at least one pixel...
Definition qrect.cpp:1065
constexpr void adjust(int x1, int y1, int x2, int y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition qrect.h:372
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:851
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:172
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:241
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:187
constexpr QPoint center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:232
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:178
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
The QResizeEvent class contains event parameters for resize events.
Definition qevent.h:547
The QScrollBar widget provides a vertical or horizontal scroll bar.
Definition qscrollbar.h:20
The QScroller class enables kinetic scrolling for any scrolling widget or graphics item.
Definition qscroller.h:26
static QScroller * scroller(QObject *target)
Returns the scroller for the given target.
State state
the state of the scroller
Definition qscroller.h:28
State
This enum contains the different QScroller states.
Definition qscroller.h:34
bool contains(const T &value) const
Definition qset.h:71
\inmodule QtCore
Definition qsize.h:25
The QSpinBox class provides a spin box widget.
Definition qspinbox.h:16
The QStatusTipEvent class provides an event that is used to show messages in a status bar.
Definition qevent.h:807
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
@ State_HasFocus
Definition qstyle.h:75
@ State_Selected
Definition qstyle.h:82
@ State_None
Definition qstyle.h:66
@ SH_ItemView_MovementWithoutUpdatingSelection
Definition qstyle.h:657
@ SH_ItemView_ScrollMode
Definition qstyle.h:696
@ SH_ItemView_ActivateItemOnSingleClick
Definition qstyle.h:644
@ SH_ItemView_ShowDecorationSelected
Definition qstyle.h:643
@ PM_SmallIconSize
Definition qstyle.h:493
The QStyledItemDelegate class provides display and editing facilities for data items from a model.
\inmodule QtCore
Definition qcoreevent.h:359
\inmodule QtCore
Definition qvariant.h:64
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
bool canConvert(QMetaType targetType) const
Definition qvariant.h:342
static QWidgetPrivate * get(QWidget *w)
Definition qwidget_p.h:211
QRect clipRect() const
Definition qwidget.cpp:1872
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
void setGeometry(int x, int y, int w, int h)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qwidget.h:886
void setParent(QWidget *parent)
Sets the parent of the widget to parent, and resets the window flags.
QWidget * focusProxy() const
Returns the focus proxy, or \nullptr if there is no focus proxy.
Definition qwidget.cpp:6452
static void setTabOrder(QWidget *, QWidget *)
Puts the second widget after the first widget in the focus order.
Definition qwidget.cpp:7002
void hide()
Hides the widget.
Definition qwidget.cpp:8209
void show()
Shows the widget and its child widgets.
Definition qwidget.cpp:7956
\inmodule QtGui
Definition qwindow.h:63
EGLImageKHR int int EGLuint64KHR * modifiers
QOpenGLWidget * widget
[1]
QPushButton * button
[2]
QSet< QString >::iterator it
rect
[4]
else opt state
[0]
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
InputMethodQuery
@ ImCursorRectangle
@ AlignVCenter
Definition qnamespace.h:154
@ AlignCenter
Definition qnamespace.h:162
@ AlignLeft
Definition qnamespace.h:143
@ NavigationModeKeypadDirectional
@ NavigationModeKeypadTabOrder
MouseButton
Definition qnamespace.h:55
@ LeftButton
Definition qnamespace.h:57
@ RightButton
Definition qnamespace.h:58
@ NoButton
Definition qnamespace.h:56
@ WA_InputMethodEnabled
Definition qnamespace.h:294
@ NoFocus
Definition qnamespace.h:106
Orientation
Definition qnamespace.h:97
@ Horizontal
Definition qnamespace.h:98
@ Vertical
Definition qnamespace.h:99
@ MouseEventSynthesizedByQt
@ transparent
Definition qnamespace.h:46
@ StatusTipRole
@ DisplayRole
@ Key_Escape
Definition qnamespace.h:658
@ Key_O
Definition qnamespace.h:560
@ Key_Tab
Definition qnamespace.h:659
@ Key_Select
@ Key_Shift
Definition qnamespace.h:678
@ Key_Return
Definition qnamespace.h:662
@ Key_Right
Definition qnamespace.h:674
@ Key_Enter
Definition qnamespace.h:663
@ Key_PageUp
Definition qnamespace.h:676
@ Key_Space
Definition qnamespace.h:512
@ Key_Backspace
Definition qnamespace.h:661
@ Key_Backtab
Definition qnamespace.h:660
@ Key_Left
Definition qnamespace.h:672
@ Key_Control
Definition qnamespace.h:679
@ Key_Up
Definition qnamespace.h:673
@ Key_Down
Definition qnamespace.h:675
@ Key_F2
Definition qnamespace.h:686
@ Key_Delete
Definition qnamespace.h:665
@ Key_PageDown
Definition qnamespace.h:677
@ Key_Back
Definition qnamespace.h:841
@ Key_Home
Definition qnamespace.h:670
@ Key_End
Definition qnamespace.h:671
@ ShiftModifier
@ ControlModifier
@ MetaModifier
@ NoModifier
@ AltModifier
DropAction
@ CopyAction
@ IgnoreAction
@ MoveAction
@ QueuedConnection
@ UniqueConnection
TextElideMode
Definition qnamespace.h:187
@ ItemIsEditable
@ ItemIsEnabled
@ ItemIsDropEnabled
@ MouseFocusReason
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
static int area(const QSize &s)
Definition qicon.cpp:152
#define qWarning
Definition qlogging.h:162
return ret
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLenum mode
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLenum GLsizei count
GLint GLint GLint GLint GLsizei GLsizei GLsizei GLboolean commit
GLint GLsizei width
GLbitfield flags
GLboolean enable
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLenum GLenum GLsizei void GLsizei void * column
struct _cl_event * event
GLenum query
const GLubyte * c
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLuint GLenum option
GLenum GLenum GLenum GLenum GLenum scale
decorationRoleName toolTipRoleName whatsThisRoleName textAlignmentRoleName foregroundRoleName accessibleTextRoleName sizeHintChanged
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
#define fp
#define QT_CONFIG(feature)
#define emit
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
QSqlQueryModel * model
[16]
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
QFileInfo info(fileName)
[8]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QObject::connect nullptr
myObject disconnect()
[26]
QVariant variant
[1]
view viewport() -> scroll(dx, dy, deviceRect)
edit isVisible()
QItemSelection * selection
[0]
app setAttribute(Qt::AA_DontShowIconsInMenus)
QPointer< QLineEdit > le
QLayoutItem * child
[0]
widget render & pixmap
QPainter painter(this)
[7]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QScroller * scroller
QPointer< QWidget > widget
bool contains(const AT &t) const noexcept
Definition qlist.h:44
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent