Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
96
122
124{
126 if (hover == index)
127 return;
128
130 q->update(hover); //update the old one
131 q->update(index); //update the new one
132 } else {
133 const QRect oldHoverRect = visualRect(hover);
134 const QRect newHoverRect = visualRect(index);
135 viewport->update(QRect(0, newHoverRect.y(), viewport->width(), newHoverRect.height()));
136 viewport->update(QRect(0, oldHoverRect.y(), viewport->width(), oldHoverRect.height()));
137 }
138 hover = index;
139}
140
142{
143 //we take a persistent model index because the model might change by emitting signals
147 viewportEnteredNeeded = false;
148
149 if (index.isValid()) {
150 emit q->entered(index);
151#if QT_CONFIG(statustip)
152 QString statustip = model->data(index, Qt::StatusTipRole).toString();
153 if (parent && (shouldClearStatusTip || !statustip.isEmpty())) {
154 QStatusTipEvent tip(statustip);
155 QCoreApplication::sendEvent(parent, &tip);
156 shouldClearStatusTip = !statustip.isEmpty();
157 }
158#endif
159 } else {
160#if QT_CONFIG(statustip)
161 if (parent && shouldClearStatusTip) {
164 QCoreApplication::sendEvent(parent, &tip);
165 }
166#endif
167 emit q->viewportEntered();
168 }
170 }
171}
172
173#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
174
175// stores and restores the selection and current item when flicking
177{
179
181 switch (scroller->state()) {
183 // store the current selection in case we start scrolling
184 if (q->selectionModel()) {
185 oldSelection = q->selectionModel()->selection();
186 oldCurrent = q->selectionModel()->currentIndex();
187 }
188 break;
189
191 // restore the old selection if we really start scrolling
192 if (q->selectionModel()) {
193 q->selectionModel()->select(oldSelection, QItemSelectionModel::ClearAndSelect);
194 // block autoScroll logic while we are already handling scrolling
195 const bool wasAutoScroll = autoScroll;
196 autoScroll = false;
197 q->selectionModel()->setCurrentIndex(oldCurrent, QItemSelectionModel::NoUpdate);
198 autoScroll = wasAutoScroll;
199 }
201
202 default:
205 break;
206 }
207 }
208}
209
210#endif // QT_NO_GESTURES
211
213{
215 if (model) {
216 if (!model->checkIndex(index))
217 qWarning("Delegate size hint changed for a model index that does not belong to this view");
218 }
220}
221
222void QAbstractItemViewPrivate::connectDelegate(QAbstractItemDelegate *delegate)
223{
224 if (!delegate)
225 return;
233}
234
235void QAbstractItemViewPrivate::disconnectDelegate(QAbstractItemDelegate *delegate)
236{
237 if (!delegate)
238 return;
246}
247
248void QAbstractItemViewPrivate::disconnectAll()
249{
255 disconnectDelegate(itemDelegate);
256 for (QAbstractItemDelegate *delegate : std::as_const(rowDelegates))
257 disconnectDelegate(delegate);
258 for (QAbstractItemDelegate *delegate : std::as_const(columnDelegates))
259 disconnectDelegate(delegate);
260 if (model && selectionModel) {
263 }
264 if (selectionModel) {
269 }
270 for (const auto &info : std::as_const(indexEditorHash)) {
271 if (!info.isStatic && info.widget)
273 }
274#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
275 QObject::disconnect(scollerConnection);
276#endif
277}
278
664 : QAbstractScrollArea(*(new QAbstractItemViewPrivate), parent)
665{
666 d_func()->init();
667}
668
673 : QAbstractScrollArea(dd, parent)
674{
675 d_func()->init();
676}
677
682{
684 // stop these timers here before ~QObject
685 d->delayedReset.stop();
686 d->updateTimer.stop();
687 d->delayedEditing.stop();
688 d->delayedAutoScroll.stop();
689 d->autoScrollTimer.stop();
690 d->delayedLayout.stop();
691 d->fetchMoreTimer.stop();
692 d->disconnectAll();
693}
694
716{
718 if (model == d->model)
719 return;
720 if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
721 for (const QMetaObject::Connection &connection : d->modelConnections)
723 }
725
727 d->modelConnections = {
756 };
757 }
758
759 QItemSelectionModel *selection_model = new QItemSelectionModel(d->model, this);
761 selection_model, &QItemSelectionModel::deleteLater);
762 setSelectionModel(selection_model);
763
764 reset(); // kill editors, set new root and do layout
765}
766
771{
772 Q_D(const QAbstractItemView);
773 return (d->model == QAbstractItemModelPrivate::staticEmptyModel() ? nullptr : d->model);
774}
775
791{
792 // ### if the given model is null, we should use the original selection model
795
796 if (Q_UNLIKELY(selectionModel->model() != d->model)) {
797 qWarning("QAbstractItemView::setSelectionModel() failed: "
798 "Trying to set a selection model, which works on "
799 "a different model than the view.");
800 return;
801 }
802
803 QItemSelection oldSelection;
804 QModelIndex oldCurrentIndex;
805
806 if (d->selectionModel) {
807 if (d->selectionModel->model() == selectionModel->model()) {
808 oldSelection = d->selectionModel->selection();
809 oldCurrentIndex = d->selectionModel->currentIndex();
810 }
815 }
816
817 d->selectionModel = selectionModel;
818
819 if (d->selectionModel) {
824
825 selectionChanged(d->selectionModel->selection(), oldSelection);
826 currentChanged(d->selectionModel->currentIndex(), oldCurrentIndex);
827 }
828}
829
836{
837 Q_D(const QAbstractItemView);
838 return d->selectionModel;
839}
840
857{
859 if (delegate == d->itemDelegate)
860 return;
861
862 if (d->itemDelegate) {
863 if (d->delegateRefCount(d->itemDelegate) == 1)
864 d->disconnectDelegate(delegate);
865 }
866
867 if (delegate) {
868 if (d->delegateRefCount(delegate) == 0)
869 d->connectDelegate(delegate);
870 }
871 d->itemDelegate = delegate;
872 viewport()->update();
873 d->doDelayedItemsLayout();
874}
875
883{
884 return d_func()->itemDelegate;
885}
886
891{
892 Q_D(const QAbstractItemView);
893 const QModelIndex current = currentIndex();
895 if (current.isValid()) {
896 if (QWidget *currentEditor;
897 d->waitForIMCommit && (currentEditor = d->editorForIndex(current).widget)) {
898 // An editor is open but the initial preedit is still ongoing. Delegate
899 // queries to the editor and map coordinates from editor to this view.
900 result = currentEditor->inputMethodQuery(query);
901 if (result.typeId() == QMetaType::QRect) {
902 const QRect editorRect = result.value<QRect>();
903 result = QRect(currentEditor->mapTo(this, editorRect.topLeft()), editorRect.size());
904 }
905 } else if (query == Qt::ImCursorRectangle) {
906 result = visualRect(current);
907 }
908 }
909 if (!result.isValid())
910 result = QAbstractScrollArea::inputMethodQuery(query);
911 return result;
912}
913
936{
938 if (QAbstractItemDelegate *rowDelegate = d->rowDelegates.value(row, nullptr)) {
939 if (d->delegateRefCount(rowDelegate) == 1)
940 d->disconnectDelegate(rowDelegate);
941 d->rowDelegates.remove(row);
942 }
943 if (delegate) {
944 if (d->delegateRefCount(delegate) == 0)
945 d->connectDelegate(delegate);
946 d->rowDelegates.insert(row, delegate);
947 }
948 viewport()->update();
949 d->doDelayedItemsLayout();
950}
951
962{
963 Q_D(const QAbstractItemView);
964 return d->rowDelegates.value(row, nullptr);
965}
966
988{
990 if (QAbstractItemDelegate *columnDelegate = d->columnDelegates.value(column, nullptr)) {
991 if (d->delegateRefCount(columnDelegate) == 1)
992 d->disconnectDelegate(columnDelegate);
993 d->columnDelegates.remove(column);
994 }
995 if (delegate) {
996 if (d->delegateRefCount(delegate) == 0)
997 d->connectDelegate(delegate);
998 d->columnDelegates.insert(column, delegate);
999 }
1000 viewport()->update();
1001 d->doDelayedItemsLayout();
1002}
1003
1014{
1015 Q_D(const QAbstractItemView);
1016 return d->columnDelegates.value(column, nullptr);
1017}
1018
1035{
1036 Q_D(const QAbstractItemView);
1037 return d->delegateForIndex(index);
1038}
1039
1051{
1052 Q_D(QAbstractItemView);
1053 d->selectionMode = mode;
1054}
1055
1057{
1058 Q_D(const QAbstractItemView);
1059 return d->selectionMode;
1060}
1061
1073{
1074 Q_D(QAbstractItemView);
1075 d->selectionBehavior = behavior;
1076}
1077
1079{
1080 Q_D(const QAbstractItemView);
1081 return d->selectionBehavior;
1082}
1083
1099{
1100 Q_D(QAbstractItemView);
1101 if (d->selectionModel && (!index.isValid() || d->isIndexEnabled(index))) {
1102 QItemSelectionModel::SelectionFlags command = selectionCommand(index, nullptr);
1103 d->selectionModel->setCurrentIndex(index, command);
1104 d->currentIndexSet = true;
1105 if ((command & QItemSelectionModel::Current) == 0)
1106 d->currentSelectionStartIndex = index;
1107 }
1108}
1109
1116{
1117 Q_D(const QAbstractItemView);
1118 return d->selectionModel ? d->selectionModel->currentIndex() : QModelIndex();
1119}
1120
1121
1132{
1133 Q_D(QAbstractItemView);
1134 d->delayedReset.stop(); //make sure we stop the timer
1135 // Taking a copy because releaseEditor() eventurally calls deleteLater() on the
1136 // editor, which calls QCoreApplication::postEvent(), the latter may invoke unknown
1137 // code that may modify d->indexEditorHash.
1138 const auto copy = d->indexEditorHash;
1139 for (const auto &[index, info] : copy.asKeyValueRange()) {
1140 if (info.widget)
1141 d->releaseEditor(info.widget.data(), d->indexForEditor(info.widget.data()));
1142 }
1143 d->editorIndexHash.clear();
1144 d->indexEditorHash.clear();
1145 d->persistent.clear();
1146 d->currentIndexSet = false;
1149 if (d->selectionModel)
1150 d->selectionModel->reset();
1151#if QT_CONFIG(accessibility)
1152 if (QAccessible::isActive()) {
1153 QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::ModelReset);
1154 QAccessible::updateAccessibility(&accessibleEvent);
1155 }
1156#endif
1157 d->updateGeometry();
1158}
1159
1166{
1167 Q_D(QAbstractItemView);
1168 if (Q_UNLIKELY(index.isValid() && index.model() != d->model)) {
1169 qWarning("QAbstractItemView::setRootIndex failed : index must be from the currently set model");
1170 return;
1171 }
1172 d->root = index;
1173#if QT_CONFIG(accessibility)
1174 if (QAccessible::isActive()) {
1175 QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::ModelReset);
1176 QAccessible::updateAccessibility(&accessibleEvent);
1177 }
1178#endif
1179 d->doDelayedItemsLayout();
1180 d->updateGeometry();
1181}
1182
1190{
1191 return QModelIndex(d_func()->root);
1192}
1193
1202{
1203 Q_D(QAbstractItemView);
1204 const SelectionMode mode = d->selectionMode;
1205 switch (mode) {
1206 case MultiSelection:
1207 case ExtendedSelection:
1209 | d->selectionBehaviorFlags());
1210 break;
1211 case NoSelection:
1213 if (d->model->hasChildren(d->root))
1214 d->selectAll(selectionCommand(d->model->index(0, 0, d->root)));
1215 break;
1216 case SingleSelection:
1217 break;
1218 }
1219}
1220
1234{
1235 Q_D(QAbstractItemView);
1236 if (Q_UNLIKELY(!d->isIndexValid(index)))
1237 qWarning("edit: index was invalid");
1238 if (Q_UNLIKELY(!edit(index, AllEditTriggers, nullptr)))
1239 qWarning("edit: editing failed");
1240}
1241
1248{
1249 Q_D(QAbstractItemView);
1250 if (d->selectionModel)
1251 d->selectionModel->clearSelection();
1252}
1253
1261{
1262 Q_D(QAbstractItemView);
1263 d->interruptDelayedItemsLayout();
1265 d->viewport->update();
1266}
1267
1277void QAbstractItemView::setEditTriggers(EditTriggers actions)
1278{
1279 Q_D(QAbstractItemView);
1280 d->editTriggers = actions;
1281}
1282
1283QAbstractItemView::EditTriggers QAbstractItemView::editTriggers() const
1284{
1285 Q_D(const QAbstractItemView);
1286 return d->editTriggers;
1287}
1288
1300{
1301 Q_D(QAbstractItemView);
1302 d->verticalScrollModeSet = true;
1303 if (mode == d->verticalScrollMode)
1304 return;
1305 QModelIndex topLeft = indexAt(QPoint(0, 0));
1306 d->verticalScrollMode = mode;
1307 if (mode == ScrollPerItem)
1308 verticalScrollBar()->d_func()->itemviewChangeSingleStep(1); // setSingleStep(-1) => step with 1
1309 else
1310 verticalScrollBar()->setSingleStep(-1); // Ensure that the view can update single step
1311 updateGeometries(); // update the scroll bars
1313}
1314
1316{
1317 Q_D(const QAbstractItemView);
1318 return d->verticalScrollMode;
1319}
1320
1322{
1323 auto sm = static_cast<ScrollMode>(style()->styleHint(QStyle::SH_ItemView_ScrollMode, nullptr, this, nullptr));
1325 d_func()->verticalScrollModeSet = false;
1326}
1327
1339{
1340 Q_D(QAbstractItemView);
1341 d->horizontalScrollModeSet = true;
1342 if (mode == d->horizontalScrollMode)
1343 return;
1344 d->horizontalScrollMode = mode;
1345 if (mode == ScrollPerItem)
1346 horizontalScrollBar()->d_func()->itemviewChangeSingleStep(1); // setSingleStep(-1) => step with 1
1347 else
1348 horizontalScrollBar()->setSingleStep(-1); // Ensure that the view can update single step
1349 updateGeometries(); // update the scroll bars
1350}
1351
1353{
1354 Q_D(const QAbstractItemView);
1355 return d->horizontalScrollMode;
1356}
1357
1359{
1360 auto sm = static_cast<ScrollMode>(style()->styleHint(QStyle::SH_ItemView_ScrollMode, nullptr, this, nullptr));
1362 d_func()->horizontalScrollModeSet = false;
1363}
1364
1365#if QT_CONFIG(draganddrop)
1387void QAbstractItemView::setDragDropOverwriteMode(bool overwrite)
1388{
1389 Q_D(QAbstractItemView);
1390 d->overwrite = overwrite;
1391}
1392
1393bool QAbstractItemView::dragDropOverwriteMode() const
1394{
1395 Q_D(const QAbstractItemView);
1396 return d->overwrite;
1397}
1398#endif
1399
1415{
1416 Q_D(QAbstractItemView);
1417 d->autoScroll = enable;
1418}
1419
1421{
1422 Q_D(const QAbstractItemView);
1423 return d->autoScroll;
1424}
1425
1435{
1436 Q_D(QAbstractItemView);
1437 d->autoScrollMargin = margin;
1438}
1439
1441{
1442 Q_D(const QAbstractItemView);
1443 return d->autoScrollMargin;
1444}
1445
1452{
1453 Q_D(QAbstractItemView);
1454 d->tabKeyNavigation = enable;
1455}
1456
1458{
1459 Q_D(const QAbstractItemView);
1460 return d->tabKeyNavigation;
1461}
1462
1468{
1469 return QAbstractScrollArea::viewportSizeHint();
1470}
1471
1472#if QT_CONFIG(draganddrop)
1480void QAbstractItemView::setDropIndicatorShown(bool enable)
1481{
1482 Q_D(QAbstractItemView);
1483 d->showDropIndicator = enable;
1484}
1485
1486bool QAbstractItemView::showDropIndicator() const
1487{
1488 Q_D(const QAbstractItemView);
1489 return d->showDropIndicator;
1490}
1491
1499void QAbstractItemView::setDragEnabled(bool enable)
1500{
1501 Q_D(QAbstractItemView);
1502 d->dragEnabled = enable;
1503}
1504
1505bool QAbstractItemView::dragEnabled() const
1506{
1507 Q_D(const QAbstractItemView);
1508 return d->dragEnabled;
1509}
1510
1538void QAbstractItemView::setDragDropMode(DragDropMode behavior)
1539{
1540 Q_D(QAbstractItemView);
1541 d->dragDropMode = behavior;
1542 setDragEnabled(behavior == DragOnly || behavior == DragDrop || behavior == InternalMove);
1543 setAcceptDrops(behavior == DropOnly || behavior == DragDrop || behavior == InternalMove);
1544}
1545
1546QAbstractItemView::DragDropMode QAbstractItemView::dragDropMode() const
1547{
1548 Q_D(const QAbstractItemView);
1549 DragDropMode setBehavior = d->dragDropMode;
1550 if (!dragEnabled() && !acceptDrops())
1551 return NoDragDrop;
1552
1553 if (dragEnabled() && !acceptDrops())
1554 return DragOnly;
1555
1556 if (!dragEnabled() && acceptDrops())
1557 return DropOnly;
1558
1559 if (dragEnabled() && acceptDrops()) {
1560 if (setBehavior == InternalMove)
1561 return setBehavior;
1562 else
1563 return DragDrop;
1564 }
1565
1566 return NoDragDrop;
1567}
1568
1579void QAbstractItemView::setDefaultDropAction(Qt::DropAction dropAction)
1580{
1581 Q_D(QAbstractItemView);
1582 d->defaultDropAction = dropAction;
1583}
1584
1585Qt::DropAction QAbstractItemView::defaultDropAction() const
1586{
1587 Q_D(const QAbstractItemView);
1588 return d->defaultDropAction;
1589}
1590
1591#endif // QT_CONFIG(draganddrop)
1592
1604{
1605 Q_D(QAbstractItemView);
1606 d->alternatingColors = enable;
1607 if (isVisible())
1608 d->viewport->update();
1609}
1610
1612{
1613 Q_D(const QAbstractItemView);
1614 return d->alternatingColors;
1615}
1616
1625{
1626 Q_D(QAbstractItemView);
1627 if (size == d->iconSize)
1628 return;
1629 d->iconSize = size;
1630 d->doDelayedItemsLayout();
1632}
1633
1635{
1636 Q_D(const QAbstractItemView);
1637 return d->iconSize;
1638}
1639
1648{
1649 Q_D(QAbstractItemView);
1650 d->textElideMode = mode;
1651}
1652
1654{
1655 return d_func()->textElideMode;
1656}
1657
1662{
1663 Q_D(QAbstractItemView);
1664 if (d->tabKeyNavigation && isVisible() && isEnabled() && d->viewport->isEnabled()) {
1667 if (event.isAccepted())
1668 return true;
1669 }
1670 return QAbstractScrollArea::focusNextPrevChild(next);
1671}
1672
1677{
1678 Q_D(QAbstractItemView);
1679 switch (event->type()) {
1680 case QEvent::Paint:
1681 //we call this here because the scrollbars' visibility might be altered
1682 //so this can't be done in the paintEvent method
1683 d->executePostedLayout(); //make sure we set the layout properly
1684 break;
1685 case QEvent::Show:
1686 d->executePostedLayout(); //make sure we set the layout properly
1687 if (d->shouldScrollToCurrentOnShow) {
1688 d->shouldScrollToCurrentOnShow = false;
1689 const QModelIndex current = currentIndex();
1690 if (current.isValid() && (d->state == QAbstractItemView::EditingState || d->autoScroll))
1691 scrollTo(current);
1692 }
1693 break;
1695 viewport()->update();
1696 break;
1700 break;
1702 doItemsLayout();
1703 if (!d->verticalScrollModeSet)
1705 if (!d->horizontalScrollModeSet)
1707 break;
1708 case QEvent::FocusOut:
1709 d->checkPersistentEditorFocus();
1710 break;
1711 case QEvent::FontChange:
1712 d->doDelayedItemsLayout(); // the size of the items will change
1713 break;
1714 default:
1715 break;
1716 }
1717 return QAbstractScrollArea::event(event);
1718}
1719
1732{
1733 Q_D(QAbstractItemView);
1734 switch (event->type()) {
1735 case QEvent::Paint:
1736 // Similar to pre-painting in QAbstractItemView::event to update scrollbar
1737 // visibility, make sure that all pending layout requests have been executed
1738 // so that the view's data structures are up-to-date before rendering.
1739 d->executePostedLayout();
1740 break;
1741 case QEvent::HoverMove:
1742 case QEvent::HoverEnter:
1743 d->setHoverIndex(indexAt(static_cast<QHoverEvent*>(event)->position().toPoint()));
1744 break;
1745 case QEvent::HoverLeave:
1746 d->setHoverIndex(QModelIndex());
1747 break;
1748 case QEvent::Enter:
1749 d->viewportEnteredNeeded = true;
1750 break;
1751 case QEvent::Leave:
1752 d->setHoverIndex(QModelIndex()); // If we've left, no hover should be needed anymore
1753 #if QT_CONFIG(statustip)
1754 if (d->shouldClearStatusTip && d->parent) {
1755 QString empty;
1756 QStatusTipEvent tip(empty);
1757 QCoreApplication::sendEvent(d->parent, &tip);
1758 d->shouldClearStatusTip = false;
1759 }
1760 #endif
1761 d->enteredIndex = QModelIndex();
1762 break;
1763 case QEvent::ToolTip:
1765 case QEvent::WhatsThis: {
1766 QHelpEvent *he = static_cast<QHelpEvent*>(event);
1767 const QModelIndex index = indexAt(he->pos());
1768 QStyleOptionViewItem option;
1770 option.rect = visualRect(index);
1772
1774 if (!delegate)
1775 return false;
1776 return delegate->helpEvent(he, this, option, index);
1777 }
1778 case QEvent::FontChange:
1779 d->doDelayedItemsLayout(); // the size of the items will change
1780 break;
1783 d->viewport->update();
1784 break;
1787#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
1788 d->scollerConnection = QObjectPrivate::connect(
1792#endif
1793 break;
1794
1795 default:
1796 break;
1797 }
1798 return QAbstractScrollArea::viewportEvent(event);
1799}
1800
1807{
1808 Q_D(QAbstractItemView);
1809 d->releaseFromDoubleClick = false;
1810 d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
1811 QPoint pos = event->position().toPoint();
1813
1814 // this is the mouse press event that closed the last editor (via focus event)
1815 d->pressClosedEditor = d->pressClosedEditorWatcher.isActive() && d->lastEditedIndex == index;
1816
1817 if (!d->selectionModel || (d->state == EditingState && d->hasEditor(index)))
1818 return;
1819
1820 d->pressedAlreadySelected = d->selectionModel->isSelected(index);
1821 d->pressedIndex = index;
1822 d->pressedModifiers = event->modifiers();
1823 QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1824 d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid();
1825 QPoint offset = d->offset();
1826 d->draggedPosition = pos + offset;
1827
1828#if QT_CONFIG(draganddrop)
1829 // update the pressed position when drag was enable
1830 if (d->dragEnabled)
1831 d->pressedPosition = d->draggedPosition;
1832#endif
1833
1834 if (!(command & QItemSelectionModel::Current)) {
1835 d->pressedPosition = pos + offset;
1836 d->currentSelectionStartIndex = index;
1837 }
1838 else if (!d->currentSelectionStartIndex.isValid())
1839 d->currentSelectionStartIndex = currentIndex();
1840
1842 return;
1843
1844 if (index.isValid() && d->isIndexEnabled(index)) {
1845 // we disable scrollTo for mouse press so the item doesn't change position
1846 // when the user is interacting with it (ie. clicking on it)
1847 bool autoScroll = d->autoScroll;
1848 d->autoScroll = false;
1849 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1850 d->autoScroll = autoScroll;
1851 if (command.testFlag(QItemSelectionModel::Toggle)) {
1852 command &= ~QItemSelectionModel::Toggle;
1853 d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
1854 command |= d->ctrlDragSelectionFlag;
1855 }
1856
1857 if (!(command & QItemSelectionModel::Current)) {
1858 setSelection(QRect(pos, QSize(1, 1)), command);
1859 } else {
1860 QRect rect(visualRect(d->currentSelectionStartIndex).center(), pos);
1861 setSelection(rect, command);
1862 }
1863
1864 // signal handlers may change the model
1866 if (d->autoScroll) {
1867 //we delay the autoscrolling to filter out double click event
1868 //100 is to be sure that there won't be a double-click misinterpreted as a 2 single clicks
1869 d->delayedAutoScroll.start(QApplication::doubleClickInterval()+100, this);
1870 }
1871
1872 } else {
1873 // Forces a finalize() even if mouse is pressed, but not on a item
1874 d->selectionModel->select(QModelIndex(), QItemSelectionModel::Select);
1875 }
1876}
1877
1884{
1885 Q_D(QAbstractItemView);
1886 QPoint bottomRight = event->position().toPoint();
1887
1888 d->draggedPosition = bottomRight + d->offset();
1889
1890 if (state() == ExpandingState || state() == CollapsingState)
1891 return;
1892
1893#if QT_CONFIG(draganddrop)
1894 if (state() == DraggingState) {
1895 d->maybeStartDrag(bottomRight);
1896 return;
1897 }
1898#endif // QT_CONFIG(draganddrop)
1899
1900 QPersistentModelIndex index = indexAt(bottomRight);
1901 QModelIndex buddy = d->model->buddy(d->pressedIndex);
1902 if ((state() == EditingState && d->hasEditor(buddy))
1904 return;
1905
1906 const QPoint topLeft =
1907 d->selectionMode != SingleSelection ? d->pressedPosition - d->offset() : bottomRight;
1908
1909 d->checkMouseMove(index);
1910
1911#if QT_CONFIG(draganddrop)
1912 if (d->pressedIndex.isValid()
1913 && d->dragEnabled
1914 && (state() != DragSelectingState)
1915 && (event->buttons() != Qt::NoButton)
1916 && !d->selectedDraggableIndexes().isEmpty()) {
1918 d->maybeStartDrag(bottomRight);
1919 return;
1920 }
1921#endif
1922
1923 if ((event->buttons() & Qt::LeftButton) && d->selectionAllowed(index) && d->selectionModel) {
1925 QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1926 if (d->ctrlDragSelectionFlag != QItemSelectionModel::NoUpdate && command.testFlag(QItemSelectionModel::Toggle)) {
1927 command &= ~QItemSelectionModel::Toggle;
1928 command |= d->ctrlDragSelectionFlag;
1929 }
1930
1931 // Do the normalize ourselves, since QRect::normalized() is flawed
1932 QRect selectionRect = QRect(topLeft, bottomRight);
1933 setSelection(selectionRect, command);
1934
1935 // set at the end because it might scroll the view
1936 if (index.isValid() && (index != d->selectionModel->currentIndex()) && d->isIndexEnabled(index))
1937 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1938 else if (d->shouldAutoScroll(event->pos()) && !d->autoScrollTimer.isActive())
1940 }
1941}
1942
1951{
1952 Q_D(QAbstractItemView);
1953 const bool releaseFromDoubleClick = d->releaseFromDoubleClick;
1954 d->releaseFromDoubleClick = false;
1955
1956 QPoint pos = event->position().toPoint();
1958
1959 if (state() == EditingState) {
1960 if (d->isIndexValid(index)
1961 && d->isIndexEnabled(index)
1962 && d->sendDelegateEvent(index, event))
1963 update(index);
1964 return;
1965 }
1966
1967 bool click = (index == d->pressedIndex && index.isValid() && !releaseFromDoubleClick);
1968 bool selectedClicked = click && d->pressedAlreadySelected
1969 && (event->button() == Qt::LeftButton)
1970 && (event->modifiers() == Qt::NoModifier);
1971 EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
1972 const bool edited = click && !d->pressClosedEditor ? edit(index, trigger, event) : false;
1973
1974 d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
1975
1976 if (d->selectionModel && d->noSelectionOnMousePress) {
1977 d->noSelectionOnMousePress = false;
1978 if (!d->pressClosedEditor)
1979 d->selectionModel->select(index, selectionCommand(index, event));
1980 }
1981
1982 d->pressClosedEditor = false;
1984
1985 if (click) {
1986 if (event->button() == Qt::LeftButton)
1988 if (edited)
1989 return;
1990 QStyleOptionViewItem option;
1992 if (d->pressedAlreadySelected)
1994 if ((d->model->flags(index) & Qt::ItemIsEnabled)
1995 && style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
1997 }
1998}
1999
2006{
2007 Q_D(QAbstractItemView);
2008
2009 QModelIndex index = indexAt(event->position().toPoint());
2010 if (!index.isValid()
2011 || !d->isIndexEnabled(index)
2012 || (d->pressedIndex != index)) {
2014 event->position(), event->scenePosition(), event->globalPosition(),
2015 event->button(), event->buttons(), event->modifiers(),
2016 event->source(), event->pointingDevice());
2017 mousePressEvent(&me);
2018 return;
2019 }
2020 // signal handlers may change the model
2021 QPersistentModelIndex persistent = index;
2022 emit doubleClicked(persistent);
2023 if ((event->button() == Qt::LeftButton) && !edit(persistent, DoubleClicked, event)
2024 && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this))
2025 emit activated(persistent);
2026 d->releaseFromDoubleClick = true;
2027}
2028
2029#if QT_CONFIG(draganddrop)
2030
2038void QAbstractItemView::dragEnterEvent(QDragEnterEvent *event)
2039{
2040 if (dragDropMode() == InternalMove
2041 && (event->source() != this|| !(event->possibleActions() & Qt::MoveAction)))
2042 return;
2043
2044 if (d_func()->canDrop(event)) {
2045 event->accept();
2047 } else {
2048 event->ignore();
2049 }
2050}
2051
2060void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event)
2061{
2062 Q_D(QAbstractItemView);
2063 d->draggedPosition = event->position().toPoint() + d->offset();
2064 if (dragDropMode() == InternalMove
2065 && (event->source() != this || !(event->possibleActions() & Qt::MoveAction)))
2066 return;
2067
2068 // ignore by default
2069 event->ignore();
2070
2071 QModelIndex index = indexAt(event->position().toPoint());
2072 d->hover = index;
2073 if (!d->droppingOnItself(event, index)
2074 && d->canDrop(event)) {
2075
2076 if (index.isValid() && d->showDropIndicator) {
2078 d->dropIndicatorPosition = d->position(event->position().toPoint(), rect, index);
2079 switch (d->dropIndicatorPosition) {
2080 case AboveItem:
2081 if (d->isIndexDropEnabled(index.parent())) {
2082 d->dropIndicatorRect = QRect(rect.left(), rect.top(), rect.width(), 0);
2083 event->acceptProposedAction();
2084 } else {
2085 d->dropIndicatorRect = QRect();
2086 }
2087 break;
2088 case BelowItem:
2089 if (d->isIndexDropEnabled(index.parent())) {
2090 d->dropIndicatorRect = QRect(rect.left(), rect.bottom(), rect.width(), 0);
2091 event->acceptProposedAction();
2092 } else {
2093 d->dropIndicatorRect = QRect();
2094 }
2095 break;
2096 case OnItem:
2097 if (d->isIndexDropEnabled(index)) {
2098 d->dropIndicatorRect = rect;
2099 event->acceptProposedAction();
2100 } else {
2101 d->dropIndicatorRect = QRect();
2102 }
2103 break;
2104 case OnViewport:
2105 d->dropIndicatorRect = QRect();
2106 if (d->isIndexDropEnabled(rootIndex())) {
2107 event->acceptProposedAction(); // allow dropping in empty areas
2108 }
2109 break;
2110 }
2111 } else {
2112 d->dropIndicatorRect = QRect();
2113 d->dropIndicatorPosition = OnViewport;
2114 if (d->isIndexDropEnabled(rootIndex())) {
2115 event->acceptProposedAction(); // allow dropping in empty areas
2116 }
2117 }
2118 d->viewport->update();
2119 } // can drop
2120
2121 if (d->shouldAutoScroll(event->position().toPoint()))
2123}
2124
2131{
2132 Q_Q(QAbstractItemView);
2133 Qt::DropAction dropAction = event->dropAction();
2134 if (q->dragDropMode() == QAbstractItemView::InternalMove)
2135 dropAction = Qt::MoveAction;
2136 if (event->source() == q
2137 && event->possibleActions() & Qt::MoveAction
2138 && dropAction == Qt::MoveAction) {
2139 QModelIndexList selectedIndexes = q->selectedIndexes();
2141 while (child.isValid() && child != root) {
2142 if (selectedIndexes.contains(child))
2143 return true;
2144 child = child.parent();
2145 }
2146 }
2147 return false;
2148}
2149
2156void QAbstractItemView::dragLeaveEvent(QDragLeaveEvent *)
2157{
2158 Q_D(QAbstractItemView);
2161 d->hover = QModelIndex();
2162 d->viewport->update();
2163}
2164
2172void QAbstractItemView::dropEvent(QDropEvent *event)
2173{
2174 Q_D(QAbstractItemView);
2175 if (dragDropMode() == InternalMove) {
2176 if (event->source() != this || !(event->possibleActions() & Qt::MoveAction))
2177 return;
2178 }
2179
2181 int col = -1;
2182 int row = -1;
2183 if (d->dropOn(event, &row, &col, &index)) {
2184 const Qt::DropAction action = dragDropMode() == InternalMove ? Qt::MoveAction : event->dropAction();
2185 if (d->model->dropMimeData(event->mimeData(), action, row, col, index)) {
2186 if (action != event->dropAction()) {
2187 event->setDropAction(action);
2188 event->accept();
2189 } else {
2190 event->acceptProposedAction();
2191 }
2192 }
2193 }
2196 d->viewport->update();
2197}
2198
2210bool QAbstractItemViewPrivate::dropOn(QDropEvent *event, int *dropRow, int *dropCol, QModelIndex *dropIndex)
2211{
2212 Q_Q(QAbstractItemView);
2213 if (event->isAccepted())
2214 return false;
2215
2217 // rootIndex() (i.e. the viewport) might be a valid index
2218 if (viewport->rect().contains(event->position().toPoint())) {
2219 index = q->indexAt(event->position().toPoint());
2220 if (!index.isValid() || !q->visualRect(index).contains(event->position().toPoint()))
2221 index = root;
2222 }
2223
2224 // If we are allowed to do the drop
2225 if (model->supportedDropActions() & event->dropAction()) {
2226 int row = -1;
2227 int col = -1;
2228 if (index != root) {
2229 dropIndicatorPosition = position(event->position().toPoint(), q->visualRect(index), index);
2230 switch (dropIndicatorPosition) {
2231 case QAbstractItemView::AboveItem:
2232 row = index.row();
2233 col = index.column();
2234 index = index.parent();
2235 break;
2236 case QAbstractItemView::BelowItem:
2237 row = index.row() + 1;
2238 col = index.column();
2239 index = index.parent();
2240 break;
2241 case QAbstractItemView::OnItem:
2242 case QAbstractItemView::OnViewport:
2243 break;
2244 }
2245 } else {
2246 dropIndicatorPosition = QAbstractItemView::OnViewport;
2247 }
2248 *dropIndex = index;
2249 *dropRow = row;
2250 *dropCol = col;
2252 return true;
2253 }
2254 return false;
2255}
2256
2257QAbstractItemView::DropIndicatorPosition
2258QAbstractItemViewPrivate::position(const QPoint &pos, const QRect &rect, const QModelIndex &index) const
2259{
2260 QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2261 if (!overwrite) {
2262 const int margin = qBound(2, qRound(qreal(rect.height()) / 5.5), 12);
2263 if (pos.y() - rect.top() < margin) {
2264 r = QAbstractItemView::AboveItem;
2265 } else if (rect.bottom() - pos.y() < margin) {
2266 r = QAbstractItemView::BelowItem;
2267 } else if (rect.contains(pos, true)) {
2268 r = QAbstractItemView::OnItem;
2269 }
2270 } else {
2271 QRect touchingRect = rect;
2272 touchingRect.adjust(-1, -1, 1, 1);
2273 if (touchingRect.contains(pos, false)) {
2274 r = QAbstractItemView::OnItem;
2275 }
2276 }
2277
2278 if (r == QAbstractItemView::OnItem && (!(model->flags(index) & Qt::ItemIsDropEnabled)))
2279 r = pos.y() < rect.center().y() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2280
2281 return r;
2282}
2283
2284#endif // QT_CONFIG(draganddrop)
2285
2293{
2294 Q_D(QAbstractItemView);
2295 QAbstractScrollArea::focusInEvent(event);
2296
2298 bool currentIndexValid = currentIndex().isValid();
2299
2300 if (model
2301 && !d->currentIndexSet
2302 && !currentIndexValid) {
2303 bool autoScroll = d->autoScroll;
2304 d->autoScroll = false;
2305 QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index
2306 if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason) {
2308 currentIndexValid = true;
2309 }
2310 d->autoScroll = autoScroll;
2311 }
2312
2313 if (model && currentIndexValid)
2315 else if (!currentIndexValid)
2317
2318 d->viewport->update();
2319}
2320
2328{
2329 Q_D(QAbstractItemView);
2330 QAbstractScrollArea::focusOutEvent(event);
2331 d->viewport->update();
2332}
2333
2346{
2347 Q_D(QAbstractItemView);
2348 d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
2349
2350#ifdef QT_KEYPAD_NAVIGATION
2351 switch (event->key()) {
2352 case Qt::Key_Select:
2353 if (QApplicationPrivate::keypadNavigationEnabled()) {
2354 if (!hasEditFocus()) {
2355 setEditFocus(true);
2356 return;
2357 }
2358 }
2359 break;
2360 case Qt::Key_Back:
2361 if (QApplicationPrivate::keypadNavigationEnabled() && hasEditFocus()) {
2362 setEditFocus(false);
2363 } else {
2364 event->ignore();
2365 }
2366 return;
2367 case Qt::Key_Down:
2368 case Qt::Key_Up:
2369 // Let's ignore vertical navigation events, only if there is no other widget
2370 // what can take the focus in vertical direction. This means widget can handle navigation events
2371 // even the widget don't have edit focus, and there is no other widget in requested direction.
2372 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()
2373 && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2374 event->ignore();
2375 return;
2376 }
2377 break;
2378 case Qt::Key_Left:
2379 case Qt::Key_Right:
2380 // Similar logic as in up and down events
2381 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()
2382 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this))) {
2383 event->ignore();
2384 return;
2385 }
2386 break;
2387 default:
2388 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus()) {
2389 event->ignore();
2390 return;
2391 }
2392 }
2393#endif
2394
2395#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
2396 if (event == QKeySequence::Copy) {
2397 const QModelIndex index = currentIndex();
2398 if (index.isValid() && d->model) {
2399 const QVariant variant = d->model->data(index, Qt::DisplayRole);
2400 if (variant.canConvert<QString>())
2402 }
2403 event->accept();
2404 }
2405#endif
2406
2407 QPersistentModelIndex newCurrent;
2408 d->moveCursorUpdatedView = false;
2409 switch (event->key()) {
2410 case Qt::Key_Down:
2411 newCurrent = moveCursor(MoveDown, event->modifiers());
2412 break;
2413 case Qt::Key_Up:
2414 newCurrent = moveCursor(MoveUp, event->modifiers());
2415 break;
2416 case Qt::Key_Left:
2417 newCurrent = moveCursor(MoveLeft, event->modifiers());
2418 break;
2419 case Qt::Key_Right:
2420 newCurrent = moveCursor(MoveRight, event->modifiers());
2421 break;
2422 case Qt::Key_Home:
2423 newCurrent = moveCursor(MoveHome, event->modifiers());
2424 break;
2425 case Qt::Key_End:
2426 newCurrent = moveCursor(MoveEnd, event->modifiers());
2427 break;
2428 case Qt::Key_PageUp:
2429 newCurrent = moveCursor(MovePageUp, event->modifiers());
2430 break;
2431 case Qt::Key_PageDown:
2432 newCurrent = moveCursor(MovePageDown, event->modifiers());
2433 break;
2434 case Qt::Key_Tab:
2435 if (d->tabKeyNavigation)
2436 newCurrent = moveCursor(MoveNext, event->modifiers());
2437 break;
2438 case Qt::Key_Backtab:
2439 if (d->tabKeyNavigation)
2440 newCurrent = moveCursor(MovePrevious, event->modifiers());
2441 break;
2442 }
2443
2444 QPersistentModelIndex oldCurrent = currentIndex();
2445 if (newCurrent != oldCurrent && newCurrent.isValid() && d->isIndexEnabled(newCurrent)) {
2446 if (!hasFocus() && QApplication::focusWidget() == indexWidget(oldCurrent))
2447 setFocus();
2448 QItemSelectionModel::SelectionFlags command = selectionCommand(newCurrent, event);
2449 if (command != QItemSelectionModel::NoUpdate
2450 || style()->styleHint(QStyle::SH_ItemView_MovementWithoutUpdatingSelection, nullptr, this)) {
2451 // note that we don't check if the new current index is enabled because moveCursor() makes sure it is
2452 if (command & QItemSelectionModel::Current) {
2453 d->selectionModel->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
2454 if (!d->currentSelectionStartIndex.isValid())
2455 d->currentSelectionStartIndex = oldCurrent;
2456 QRect rect(visualRect(d->currentSelectionStartIndex).center(), visualRect(newCurrent).center());
2457 setSelection(rect, command);
2458 } else {
2459 d->selectionModel->setCurrentIndex(newCurrent, command);
2460 d->currentSelectionStartIndex = newCurrent;
2461 if (newCurrent.isValid()) {
2462 // We copy the same behaviour as for mousePressEvent().
2463 QRect rect(visualRect(newCurrent).center(), QSize(1, 1));
2464 setSelection(rect, command);
2465 }
2466 }
2467 event->accept();
2468 return;
2469 }
2470 }
2471
2472 switch (event->key()) {
2473 // ignored keys
2474 case Qt::Key_Down:
2475 case Qt::Key_Up:
2476#ifdef QT_KEYPAD_NAVIGATION
2477 if (QApplicationPrivate::keypadNavigationEnabled()
2478 && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2479 event->accept(); // don't change focus
2480 break;
2481 }
2482#endif
2483 case Qt::Key_Left:
2484 case Qt::Key_Right:
2485#ifdef QT_KEYPAD_NAVIGATION
2486 if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
2487 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal)
2488 || (QWidgetPrivate::inTabWidget(this) && d->model->columnCount(d->root) > 1))) {
2489 event->accept(); // don't change focus
2490 break;
2491 }
2492#endif // QT_KEYPAD_NAVIGATION
2493 case Qt::Key_Home:
2494 case Qt::Key_End:
2495 case Qt::Key_PageUp:
2496 case Qt::Key_PageDown:
2497 case Qt::Key_Escape:
2498 case Qt::Key_Shift:
2499 case Qt::Key_Control:
2500 case Qt::Key_Delete:
2501 case Qt::Key_Backspace:
2502 event->ignore();
2503 break;
2504 case Qt::Key_Space:
2505 case Qt::Key_Select:
2507 if (d->selectionModel)
2508 d->selectionModel->select(currentIndex(), selectionCommand(currentIndex(), event));
2509 if (event->key() == Qt::Key_Space) {
2510 keyboardSearch(event->text());
2511 event->accept();
2512 }
2513 }
2514#ifdef QT_KEYPAD_NAVIGATION
2515 if ( event->key()==Qt::Key_Select ) {
2516 // Also do Key_Enter action.
2517 if (currentIndex().isValid()) {
2518 if (state() != EditingState)
2520 } else {
2521 event->ignore();
2522 }
2523 }
2524#endif
2525 break;
2526#ifdef Q_OS_MACOS
2527 case Qt::Key_Enter:
2528 case Qt::Key_Return:
2529 // Propagate the enter if you couldn't edit the item and there are no
2530 // current editors (if there are editors, the event was most likely propagated from it).
2531 if (!edit(currentIndex(), EditKeyPressed, event) && d->editorIndexHash.isEmpty())
2532 event->ignore();
2533 break;
2534#else
2535 case Qt::Key_F2:
2537 event->ignore();
2538 break;
2539 case Qt::Key_Enter:
2540 case Qt::Key_Return:
2541 // ### we can't open the editor on enter, because
2542 // some widgets will forward the enter event back
2543 // to the viewport, starting an endless loop
2544 if (state() != EditingState || hasFocus()) {
2545 if (currentIndex().isValid())
2547 event->ignore();
2548 }
2549 break;
2550#endif
2551 default: {
2552#ifndef QT_NO_SHORTCUT
2554 selectAll();
2555 break;
2556 }
2557#endif
2558#ifdef Q_OS_MACOS
2559 if (event->key() == Qt::Key_O && event->modifiers() & Qt::ControlModifier && currentIndex().isValid()) {
2561 break;
2562 }
2563#endif
2564 bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier));
2565 if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) {
2566 keyboardSearch(event->text());
2567 event->accept();
2568 } else {
2569 event->ignore();
2570 }
2571 break; }
2572 }
2573 if (d->moveCursorUpdatedView)
2574 event->accept();
2575}
2576
2584{
2585 QAbstractScrollArea::resizeEvent(event);
2587}
2588
2596{
2597 Q_D(QAbstractItemView);
2598 if (event->timerId() == d->fetchMoreTimer.timerId())
2599 d->fetchMore();
2600 else if (event->timerId() == d->delayedReset.timerId())
2601 reset();
2602 else if (event->timerId() == d->autoScrollTimer.timerId())
2603 doAutoScroll();
2604 else if (event->timerId() == d->updateTimer.timerId())
2605 d->updateDirtyRegion();
2606 else if (event->timerId() == d->delayedEditing.timerId()) {
2607 d->delayedEditing.stop();
2608 edit(currentIndex());
2609 } else if (event->timerId() == d->delayedLayout.timerId()) {
2610 d->delayedLayout.stop();
2611 if (isVisible()) {
2612 d->interruptDelayedItemsLayout();
2613 doItemsLayout();
2614 const QModelIndex current = currentIndex();
2615 if (current.isValid() && d->state == QAbstractItemView::EditingState)
2616 scrollTo(current);
2617 }
2618 } else if (event->timerId() == d->delayedAutoScroll.timerId()) {
2619 d->delayedAutoScroll.stop();
2620 //end of the timer: if the current item is still the same as the one when the mouse press occurred
2621 //we only get here if there was no double click
2622 if (d->pressedIndex.isValid() && d->pressedIndex == currentIndex())
2623 scrollTo(d->pressedIndex);
2624 } else if (event->timerId() == d->pressClosedEditorWatcher.timerId()) {
2625 d->pressClosedEditorWatcher.stop();
2626 }
2627}
2628
2633{
2634 Q_D(QAbstractItemView);
2635 // When QAbstractItemView::AnyKeyPressed is used, a new IM composition might
2636 // start before the editor widget acquires focus. Changing focus would interrupt
2637 // the composition, so we keep focus on the view until that first composition
2638 // is complete, and pass QInputMethoEvents on to the editor widget so that the
2639 // user gets the expected feedback. See also inputMethodQuery, which redirects
2640 // calls to the editor widget during that period.
2641 bool forwardEventToEditor = false;
2642 const bool commit = !event->commitString().isEmpty();
2643 const bool preediting = !event->preeditString().isEmpty();
2644 if (QWidget *currentEditor = d->editorForIndex(currentIndex()).widget) {
2645 if (d->waitForIMCommit) {
2646 if (commit || !preediting) {
2647 // commit or cancel
2648 d->waitForIMCommit = false;
2649 QApplication::sendEvent(currentEditor, event);
2650 if (!commit) {
2652 if (delegate)
2653 delegate->setEditorData(currentEditor, currentIndex());
2654 d->selectAllInEditor(currentEditor);
2655 }
2656 if (currentEditor->focusPolicy() != Qt::NoFocus)
2657 currentEditor->setFocus();
2658 } else {
2659 // more pre-editing
2660 QApplication::sendEvent(currentEditor, event);
2661 }
2662 return;
2663 }
2664 } else if (preediting) {
2665 // don't set focus when the editor opens
2666 d->waitForIMCommit = true;
2667 // but pass preedit on to editor
2668 forwardEventToEditor = true;
2669 } else if (!commit) {
2670 event->ignore();
2671 return;
2672 }
2674 d->waitForIMCommit = false;
2675 if (commit)
2676 keyboardSearch(event->commitString());
2677 event->ignore();
2678 } else if (QWidget *currentEditor; forwardEventToEditor
2679 && (currentEditor = d->editorForIndex(currentIndex()).widget)) {
2680 QApplication::sendEvent(currentEditor, event);
2681 }
2682}
2683
2684#if QT_CONFIG(draganddrop)
2708QAbstractItemView::DropIndicatorPosition QAbstractItemView::dropIndicatorPosition() const
2709{
2710 Q_D(const QAbstractItemView);
2711 return d->dropIndicatorPosition;
2712}
2713#endif
2714
2723{
2724 Q_D(const QAbstractItemView);
2725 QModelIndexList indexes;
2726 if (d->selectionModel) {
2727 indexes = d->selectionModel->selectedIndexes();
2728 auto isHidden = [this](const QModelIndex &idx) {
2729 return isIndexHidden(idx);
2730 };
2731 indexes.removeIf(isHidden);
2732 }
2733 return indexes;
2734}
2735
2750{
2751 Q_D(QAbstractItemView);
2752
2753 if (!d->isIndexValid(index))
2754 return false;
2755
2756 if (QWidget *w = (d->persistent.isEmpty() ? static_cast<QWidget*>(nullptr) : d->editorForIndex(index).widget.data())) {
2757 if (w->focusPolicy() == Qt::NoFocus)
2758 return false;
2759 if (!d->waitForIMCommit)
2760 w->setFocus();
2761 else
2762 updateMicroFocus();
2763 return true;
2764 }
2765
2766 if (trigger == DoubleClicked) {
2767 d->delayedEditing.stop();
2768 d->delayedAutoScroll.stop();
2769 } else if (trigger == CurrentChanged) {
2770 d->delayedEditing.stop();
2771 }
2772
2773 // in case e.g. setData() triggers a reset()
2774 QPersistentModelIndex safeIndex(index);
2775
2776 if (d->sendDelegateEvent(index, event)) {
2777 update(safeIndex);
2778 return true;
2779 }
2780
2781 if (!safeIndex.isValid()) {
2782 return false;
2783 }
2784
2785 // save the previous trigger before updating
2786 EditTriggers lastTrigger = d->lastTrigger;
2787 d->lastTrigger = trigger;
2788
2789 if (!d->shouldEdit(trigger, d->model->buddy(safeIndex)))
2790 return false;
2791
2792 if (d->delayedEditing.isActive())
2793 return false;
2794
2795 // we will receive a mouseButtonReleaseEvent after a
2796 // mouseDoubleClickEvent, so we need to check the previous trigger
2797 if (lastTrigger == DoubleClicked && trigger == SelectedClicked)
2798 return false;
2799
2800 // we may get a double click event later
2801 if (trigger == SelectedClicked)
2802 d->delayedEditing.start(QApplication::doubleClickInterval(), this);
2803 else
2804 d->openEditor(safeIndex, d->shouldForwardEvent(trigger, event) ? event : nullptr);
2805
2806 return true;
2807}
2808
2814{
2815 Q_D(QAbstractItemView);
2816 d->updateEditorData(QModelIndex(), QModelIndex());
2817}
2818
2824{
2825 Q_D(QAbstractItemView);
2826 if (d->editorIndexHash.isEmpty())
2827 return;
2828 if (d->delayedPendingLayout) {
2829 // doItemsLayout() will end up calling this function again
2830 d->executePostedLayout();
2831 return;
2832 }
2833 QStyleOptionViewItem option;
2835 QEditorIndexHash::iterator it = d->editorIndexHash.begin();
2836 QWidgetList editorsToRelease;
2837 QWidgetList editorsToHide;
2838 while (it != d->editorIndexHash.end()) {
2839 QModelIndex index = it.value();
2840 QWidget *editor = it.key();
2841 if (index.isValid() && editor) {
2842 option.rect = visualRect(index);
2843 if (option.rect.isValid()) {
2844 editor->show();
2846 if (delegate)
2847 delegate->updateEditorGeometry(editor, option, index);
2848 } else {
2849 editorsToHide << editor;
2850 }
2851 ++it;
2852 } else {
2853 d->indexEditorHash.remove(it.value());
2854 it = d->editorIndexHash.erase(it);
2855 editorsToRelease << editor;
2856 }
2857 }
2858
2859 //we hide and release the editor outside of the loop because it might change the focus and try
2860 //to change the editors hashes.
2861 for (int i = 0; i < editorsToHide.size(); ++i) {
2862 editorsToHide.at(i)->hide();
2863 }
2864 for (int i = 0; i < editorsToRelease.size(); ++i) {
2865 d->releaseEditor(editorsToRelease.at(i));
2866 }
2867}
2868
2875{
2876 Q_D(QAbstractItemView);
2878 d->fetchMoreTimer.start(0, this); //fetch more later
2879 d->updateGeometry();
2880}
2881
2886{
2887 Q_D(QAbstractItemView);
2888 if (verticalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2889 d->model->fetchMore(d->root);
2890 QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2891 if (viewport()->rect().contains(posInVp))
2892 d->checkMouseMove(posInVp);
2893}
2894
2899{
2900 Q_D(QAbstractItemView);
2901 if (horizontalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2902 d->model->fetchMore(d->root);
2903 QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2904 if (viewport()->rect().contains(posInVp))
2905 d->checkMouseMove(posInVp);
2906}
2907
2912{
2913 //do nothing
2914}
2915
2920{
2921 //do nothing
2922}
2923
2934{
2935 Q_D(QAbstractItemView);
2936
2937 // Close the editor
2938 if (editor) {
2939 const bool isPersistent = d->persistent.contains(editor);
2940 const QModelIndex index = d->indexForEditor(editor);
2941 if (!index.isValid()) {
2942 if (!editor->isVisible()) {
2943 // The commit might have removed the index (e.g. it might get filtered), in
2944 // which case the editor is already hidden and scheduled for deletion. We
2945 // don't have to do anything, except reset the state, and continue with
2946 // EndEditHint processing.
2947 if (!isPersistent)
2949 } else {
2950 qWarning("QAbstractItemView::closeEditor called with an editor that does not belong to this view");
2951 return;
2952 }
2953 } else {
2954 const bool hadFocus = editor->hasFocus();
2955 // start a timer that expires immediately when we return to the event loop
2956 // to identify whether this close was triggered by a mousepress-initiated
2957 // focus event
2958 d->pressClosedEditorWatcher.start(0, this);
2959 d->lastEditedIndex = index;
2960
2961 if (!isPersistent) {
2963 QModelIndex index = d->indexForEditor(editor);
2964 editor->removeEventFilter(itemDelegateForIndex(index));
2965 d->removeEditor(editor);
2966 }
2967 if (hadFocus) {
2968 if (focusPolicy() != Qt::NoFocus)
2969 setFocus(); // this will send a focusLost event to the editor
2970 else
2971 editor->clearFocus();
2972 } else {
2973 d->checkPersistentEditorFocus();
2974 }
2975
2976 QPointer<QWidget> ed = editor;
2978 editor = ed;
2979
2980 if (!isPersistent && editor)
2981 d->releaseEditor(editor, index);
2982 }
2983 }
2984
2985 // The EndEditHint part
2986 QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::NoUpdate;
2987 if (d->selectionMode != NoSelection)
2988 flags = QItemSelectionModel::ClearAndSelect | d->selectionBehaviorFlags();
2989 switch (hint) {
2992 if (index.isValid()) {
2993 QPersistentModelIndex persistent(index);
2994 d->selectionModel->setCurrentIndex(persistent, flags);
2995 // currentChanged signal would have already started editing
2996 if (index.flags() & Qt::ItemIsEditable
2998 edit(persistent);
2999 } break; }
3002 if (index.isValid()) {
3003 QPersistentModelIndex persistent(index);
3004 d->selectionModel->setCurrentIndex(persistent, flags);
3005 // currentChanged signal would have already started editing
3006 if (index.flags() & Qt::ItemIsEditable
3008 edit(persistent);
3009 } break; }
3011 d->model->submit();
3012 break;
3014 d->model->revert();
3015 break;
3016 default:
3017 break;
3018 }
3019}
3020
3027{
3028 Q_D(QAbstractItemView);
3029 if (!editor || !d->itemDelegate || d->currentlyCommittingEditor)
3030 return;
3031 QModelIndex index = d->indexForEditor(editor);
3032 if (!index.isValid()) {
3033 qWarning("QAbstractItemView::commitData called with an editor that does not belong to this view");
3034 return;
3035 }
3036 d->currentlyCommittingEditor = editor;
3038 editor->removeEventFilter(delegate);
3039 delegate->setModelData(editor, d->model, index);
3040 editor->installEventFilter(delegate);
3041 d->currentlyCommittingEditor = nullptr;
3042}
3043
3050{
3051 Q_D(QAbstractItemView);
3052 QWidget *w = qobject_cast<QWidget*>(editor);
3053 d->removeEditor(w);
3054 d->persistent.remove(w);
3055 if (state() == EditingState)
3057}
3058
3059
3060
3070{
3071 Q_D(QAbstractItemView);
3072 if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
3073 return;
3074
3076 : d->model->index(0, 0, d->root);
3077 bool skipRow = false;
3078 bool keyboardTimeWasValid = d->keyboardInputTime.isValid();
3079 qint64 keyboardInputTimeElapsed;
3080 if (keyboardTimeWasValid)
3081 keyboardInputTimeElapsed = d->keyboardInputTime.restart();
3082 else
3083 d->keyboardInputTime.start();
3084 if (search.isEmpty() || !keyboardTimeWasValid
3085 || keyboardInputTimeElapsed > QApplication::keyboardInputInterval()) {
3086 d->keyboardInput = search;
3087 skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0)
3088 } else {
3089 d->keyboardInput += search;
3090 }
3091
3092 // special case for searches with same key like 'aaaaa'
3093 bool sameKey = false;
3094 if (d->keyboardInput.size() > 1) {
3095 int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.size() - 1));
3096 sameKey = (c == d->keyboardInput.size());
3097 if (sameKey)
3098 skipRow = true;
3099 }
3100
3101 // skip if we are searching for the same key or a new search started
3102 if (skipRow) {
3103 QModelIndex parent = start.parent();
3104 int newRow = (start.row() < d->model->rowCount(parent) - 1) ? start.row() + 1 : 0;
3105 start = d->model->index(newRow, start.column(), parent);
3106 }
3107
3108 // search from start with wraparound
3109 QModelIndex current = start;
3111 QModelIndex firstMatch;
3112 QModelIndex startMatch;
3113 QModelIndexList previous;
3114 do {
3115 match = d->model->match(current, Qt::DisplayRole, d->keyboardInput);
3116 if (match == previous)
3117 break;
3118 firstMatch = match.value(0);
3119 previous = match;
3120 if (firstMatch.isValid()) {
3121 if (d->isIndexEnabled(firstMatch)) {
3122 setCurrentIndex(firstMatch);
3123 break;
3124 }
3125 int row = firstMatch.row() + 1;
3126 if (row >= d->model->rowCount(firstMatch.parent()))
3127 row = 0;
3128 current = firstMatch.sibling(row, firstMatch.column());
3129
3130 //avoid infinite loop if all the matching items are disabled.
3131 if (!startMatch.isValid())
3132 startMatch = firstMatch;
3133 else if (startMatch == firstMatch)
3134 break;
3135 }
3136 } while (current != start && firstMatch.isValid());
3137}
3138
3146{
3147 Q_D(const QAbstractItemView);
3148 if (!d->isIndexValid(index))
3149 return QSize();
3150 const auto delegate = itemDelegateForIndex(index);
3151 QStyleOptionViewItem option;
3153 return delegate ? delegate->sizeHint(option, index) : QSize();
3154}
3155
3173{
3174 Q_D(const QAbstractItemView);
3175
3176 if (row < 0 || row >= d->model->rowCount(d->root))
3177 return -1;
3178
3179 ensurePolished();
3180
3181 QStyleOptionViewItem option;
3183 int height = 0;
3184 int colCount = d->model->columnCount(d->root);
3185 for (int c = 0; c < colCount; ++c) {
3186 const QModelIndex index = d->model->index(row, c, d->root);
3187 if (QWidget *editor = d->editorForIndex(index).widget.data())
3188 height = qMax(height, editor->height());
3189 if (const QAbstractItemDelegate *delegate = itemDelegateForIndex(index))
3190 height = qMax(height, delegate->sizeHint(option, index).height());
3191 }
3192 return height;
3193}
3194
3204{
3205 Q_D(const QAbstractItemView);
3206
3207 if (column < 0 || column >= d->model->columnCount(d->root))
3208 return -1;
3209
3210 ensurePolished();
3211
3212 QStyleOptionViewItem option;
3214 int width = 0;
3215 int rows = d->model->rowCount(d->root);
3216 for (int r = 0; r < rows; ++r) {
3217 const QModelIndex index = d->model->index(r, column, d->root);
3218 if (QWidget *editor = d->editorForIndex(index).widget.data())
3219 width = qMax(width, editor->sizeHint().width());
3220 if (const QAbstractItemDelegate *delegate = itemDelegateForIndex(index))
3221 width = qMax(width, delegate->sizeHint(option, index).width());
3222 }
3223 return width;
3224}
3225
3233{
3234 Q_D(QAbstractItemView);
3235 QStyleOptionViewItem options;
3236 initViewItemOption(&options);
3237 options.rect = visualRect(index);
3238 options.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
3239
3240 QWidget *editor = d->editor(index, options);
3241 if (editor) {
3242 editor->show();
3243 d->persistent.insert(editor);
3244 }
3245}
3246
3253{
3254 Q_D(QAbstractItemView);
3255 if (QWidget *editor = d->editorForIndex(index).widget.data()) {
3256 if (index == selectionModel()->currentIndex())
3258 d->persistent.remove(editor);
3259 d->removeEditor(editor);
3260 d->releaseEditor(editor, index);
3261 }
3262}
3263
3272{
3273 Q_D(const QAbstractItemView);
3274 return d->editorForIndex(index).widget;
3275}
3276
3304{
3305 Q_D(QAbstractItemView);
3306 if (!d->isIndexValid(index))
3307 return;
3308 if (indexWidget(index) == widget)
3309 return;
3310 if (QWidget *oldWidget = indexWidget(index)) {
3311 d->persistent.remove(oldWidget);
3312 d->removeEditor(oldWidget);
3313 oldWidget->removeEventFilter(this);
3314 oldWidget->deleteLater();
3315 }
3316 if (widget) {
3318 d->persistent.insert(widget);
3319 d->addEditor(index, widget, true);
3321 widget->show();
3322 dataChanged(index, index); // update the geometry
3323 if (!d->delayedPendingLayout) {
3325 d->doDelayedItemsLayout(); // relayout due to updated geometry
3326 }
3327 }
3328}
3329
3336{
3337 Q_D(const QAbstractItemView);
3338 if (d->isIndexValid(index))
3339 if (QWidget *editor = d->editorForIndex(index).widget.data())
3340 return editor;
3341
3342 return nullptr;
3343}
3344
3353{
3354 verticalScrollBar()->setValue(verticalScrollBar()->minimum());
3355}
3356
3365{
3366 Q_D(QAbstractItemView);
3367 if (d->delayedPendingLayout) {
3368 d->executePostedLayout();
3370 }
3371 verticalScrollBar()->setValue(verticalScrollBar()->maximum());
3372}
3373
3381{
3382 Q_D(QAbstractItemView);
3383 if (index.isValid()) {
3384 const QRect rect = d->visualRect(index);
3385 //this test is important for performance reason
3386 //For example in dataChanged we simply update all the cells without checking
3387 //it can be a major bottleneck to update rects that aren't even part of the viewport
3388 if (d->viewport->rect().intersects(rect))
3389 d->viewport->update(rect);
3390 }
3391}
3392
3403void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
3404 const QList<int> &roles)
3405{
3406 Q_UNUSED(roles);
3407 // Single item changed
3408 Q_D(QAbstractItemView);
3409 if (topLeft == bottomRight && topLeft.isValid()) {
3410 const QEditorInfo &editorInfo = d->editorForIndex(topLeft);
3411 //we don't update the edit data if it is static
3412 if (!editorInfo.isStatic && editorInfo.widget) {
3413 QAbstractItemDelegate *delegate = itemDelegateForIndex(topLeft);
3414 if (delegate) {
3415 delegate->setEditorData(editorInfo.widget.data(), topLeft);
3416 }
3417 }
3418 if (isVisible() && !d->delayedPendingLayout) {
3419 // otherwise the items will be update later anyway
3420 update(topLeft);
3421 }
3422 } else {
3423 d->updateEditorData(topLeft, bottomRight);
3424 if (isVisible() && !d->delayedPendingLayout) {
3425 if (!topLeft.isValid() ||
3426 topLeft.parent() != bottomRight.parent() ||
3427 topLeft.row() > bottomRight.row() ||
3428 topLeft.column() > bottomRight.column()) {
3429 // invalid parameter - call update() to redraw all
3430 d->viewport->update();
3431 } else {
3432 const QRect updateRect = d->intersectedRect(d->viewport->rect(), topLeft, bottomRight);
3433 if (!updateRect.isEmpty())
3434 d->viewport->update(updateRect);
3435 }
3436 }
3437 }
3438
3439#if QT_CONFIG(accessibility)
3440 if (QAccessible::isActive()) {
3441 QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::DataChanged);
3442 accessibleEvent.setFirstRow(topLeft.row());
3443 accessibleEvent.setFirstColumn(topLeft.column());
3444 accessibleEvent.setLastRow(bottomRight.row());
3445 accessibleEvent.setLastColumn(bottomRight.column());
3446 QAccessible::updateAccessibility(&accessibleEvent);
3447 }
3448#endif
3449 d->updateGeometry();
3450}
3451
3461{
3462 if (!isVisible())
3463 d_func()->fetchMoreTimer.start(0, this); //fetch more later
3464 else
3466}
3467
3475{
3476 Q_D(QAbstractItemView);
3477
3479
3480 // Ensure one selected item in single selection mode.
3481 QModelIndex current = currentIndex();
3482 if (d->selectionMode == SingleSelection
3483 && current.isValid()
3484 && current.row() >= start
3485 && current.row() <= end
3486 && current.parent() == parent) {
3487 int totalToRemove = end - start + 1;
3488 if (d->model->rowCount(parent) <= totalToRemove) { // no more children
3489 QModelIndex index = parent;
3490 while (index != d->root && !d->isIndexEnabled(index))
3491 index = index.parent();
3492 if (index != d->root)
3494 } else {
3495 int row = end + 1;
3497 const int rowCount = d->model->rowCount(parent);
3498 bool found = false;
3499 // find the next visible and enabled item
3500 while (row < rowCount && !found) {
3501 next = d->model->index(row++, current.column(), current.parent());
3502#ifdef QT_DEBUG
3503 if (!next.isValid()) {
3504 qWarning("Model unexpectedly returned an invalid index");
3505 break;
3506 }
3507#endif
3508 if (!isIndexHidden(next) && d->isIndexEnabled(next)) {
3509 found = true;
3510 break;
3511 }
3512 }
3513
3514 if (!found) {
3515 row = start - 1;
3516 // find the previous visible and enabled item
3517 while (row >= 0) {
3518 next = d->model->index(row--, current.column(), current.parent());
3519#ifdef QT_DEBUG
3520 if (!next.isValid()) {
3521 qWarning("Model unexpectedly returned an invalid index");
3522 break;
3523 }
3524#endif
3525 if (!isIndexHidden(next) && d->isIndexEnabled(next))
3526 break;
3527 }
3528 }
3529
3531 }
3532 }
3533
3534 // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
3535 const auto findDirectChildOf = [](const QModelIndex &parent, QModelIndex child)
3536 {
3537 while (child.isValid()) {
3538 const auto parentIndex = child.parent();
3539 if (parentIndex == parent)
3540 return child;
3541 child = parentIndex;
3542 }
3543 return QModelIndex();
3544 };
3545 QEditorIndexHash::iterator i = d->editorIndexHash.begin();
3546 while (i != d->editorIndexHash.end()) {
3547 const QModelIndex index = i.value();
3548 const QModelIndex directChild = findDirectChildOf(parent, index);
3549 if (directChild.isValid() && directChild.row() >= start && directChild.row() <= end) {
3550 QWidget *editor = i.key();
3551 QEditorInfo info = d->indexEditorHash.take(index);
3552 i = d->editorIndexHash.erase(i);
3553 if (info.widget)
3554 d->releaseEditor(editor, index);
3555 } else {
3556 ++i;
3557 }
3558 }
3559}
3560
3569{
3570 Q_UNUSED(index);
3571 Q_UNUSED(start);
3572 Q_UNUSED(end);
3573
3574 Q_Q(QAbstractItemView);
3575 if (q->isVisible())
3576 q->updateEditorGeometries();
3577 q->setState(QAbstractItemView::NoState);
3578#if QT_CONFIG(accessibility)
3579 if (QAccessible::isActive()) {
3580 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::RowsRemoved);
3581 accessibleEvent.setFirstRow(start);
3582 accessibleEvent.setLastRow(end);
3583 QAccessible::updateAccessibility(&accessibleEvent);
3584 }
3585#endif
3587}
3588
3597{
3598 Q_Q(QAbstractItemView);
3599
3601
3602 // Ensure one selected item in single selection mode.
3603 QModelIndex current = q->currentIndex();
3604 if (current.isValid()
3606 && current.column() >= start
3607 && current.column() <= end) {
3608 int totalToRemove = end - start + 1;
3609 if (model->columnCount(parent) < totalToRemove) { // no more columns
3610 QModelIndex index = parent;
3611 while (index.isValid() && !isIndexEnabled(index))
3612 index = index.parent();
3613 if (index.isValid())
3614 q->setCurrentIndex(index);
3615 } else {
3616 int column = end;
3618 const int columnCount = model->columnCount(current.parent());
3619 // find the next visible and enabled item
3620 while (column < columnCount) {
3621 next = model->index(current.row(), column++, current.parent());
3622#ifdef QT_DEBUG
3623 if (!next.isValid()) {
3624 qWarning("Model unexpectedly returned an invalid index");
3625 break;
3626 }
3627#endif
3628 if (!q->isIndexHidden(next) && isIndexEnabled(next))
3629 break;
3630 }
3631 q->setCurrentIndex(next);
3632 }
3633 }
3634
3635 // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
3637 while (it != editorIndexHash.end()) {
3638 QModelIndex index = it.value();
3639 if (index.column() <= start && index.column() >= end && model->parent(index) == parent) {
3640 QWidget *editor = it.key();
3643 if (info.widget)
3645 } else {
3646 ++it;
3647 }
3648 }
3649
3650}
3651
3660{
3661 Q_UNUSED(index);
3662 Q_UNUSED(start);
3663 Q_UNUSED(end);
3664
3665 Q_Q(QAbstractItemView);
3666 if (q->isVisible())
3667 q->updateEditorGeometries();
3668 q->setState(QAbstractItemView::NoState);
3669#if QT_CONFIG(accessibility)
3670 if (QAccessible::isActive()) {
3671 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ColumnsRemoved);
3672 accessibleEvent.setFirstColumn(start);
3673 accessibleEvent.setLastColumn(end);
3674 QAccessible::updateAccessibility(&accessibleEvent);
3675 }
3676#endif
3678}
3679
3680
3687{
3688 Q_UNUSED(index);
3689 Q_UNUSED(start);
3690 Q_UNUSED(end);
3691
3692#if QT_CONFIG(accessibility)
3693 Q_Q(QAbstractItemView);
3694 if (QAccessible::isActive()) {
3695 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::RowsInserted);
3696 accessibleEvent.setFirstRow(start);
3697 accessibleEvent.setLastRow(end);
3698 QAccessible::updateAccessibility(&accessibleEvent);
3699 }
3700#endif
3702}
3703
3710{
3711 Q_UNUSED(index);
3712 Q_UNUSED(start);
3713 Q_UNUSED(end);
3714
3715 Q_Q(QAbstractItemView);
3716 if (q->isVisible())
3717 q->updateEditorGeometries();
3718#if QT_CONFIG(accessibility)
3719 if (QAccessible::isActive()) {
3720 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ColumnsInserted);
3721 accessibleEvent.setFirstColumn(start);
3722 accessibleEvent.setLastColumn(end);
3723 QAccessible::updateAccessibility(&accessibleEvent);
3724 }
3725#endif
3727}
3728
3737
3744{
3746#if QT_CONFIG(accessibility)
3747 Q_Q(QAbstractItemView);
3748 if (QAccessible::isActive()) {
3749 QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ModelReset);
3750 QAccessible::updateAccessibility(&accessibleEvent);
3751 }
3752#endif
3753}
3754
3756{
3757 layoutChanged();
3758}
3759
3761{
3762 layoutChanged();
3763}
3764
3766{
3767 Q_Q(const QAbstractItemView);
3768
3769 const auto parentIdx = topLeft.parent();
3770 QRect updateRect;
3771 for (int r = topLeft.row(); r <= bottomRight.row(); ++r) {
3772 for (int c = topLeft.column(); c <= bottomRight.column(); ++c)
3773 updateRect |= q->visualRect(model->index(r, c, parentIdx));
3774 }
3775 return rect.intersected(updateRect);
3776}
3777
3786 const QItemSelection &deselected)
3787{
3788 Q_D(QAbstractItemView);
3789 if (isVisible() && updatesEnabled()) {
3790 d->viewport->update(visualRegionForSelection(deselected) | visualRegionForSelection(selected));
3791 }
3792}
3793
3802void QAbstractItemView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
3803{
3804 Q_D(QAbstractItemView);
3805 Q_ASSERT(d->model);
3806
3807 if (previous.isValid()) {
3808 QModelIndex buddy = d->model->buddy(previous);
3809 QWidget *editor = d->editorForIndex(buddy).widget.data();
3810 if (editor && !d->persistent.contains(editor)) {
3811 commitData(editor);
3812 if (current.row() != previous.row())
3814 else
3816 }
3817 if (isVisible()) {
3818 update(previous);
3819 }
3820 }
3821
3822 if (current.isValid() && !d->autoScrollTimer.isActive()) {
3823 if (isVisible()) {
3824 if (d->autoScroll)
3825 scrollTo(current);
3826 update(current);
3827 edit(current, CurrentChanged, nullptr);
3828 if (current.row() == (d->model->rowCount(d->root) - 1))
3829 d->fetchMore();
3830 } else {
3831 d->shouldScrollToCurrentOnShow = d->autoScroll;
3832 }
3833 }
3835}
3836
3837#if QT_CONFIG(draganddrop)
3841void QAbstractItemView::startDrag(Qt::DropActions supportedActions)
3842{
3843 Q_D(QAbstractItemView);
3844 QModelIndexList indexes = d->selectedDraggableIndexes();
3845 if (indexes.size() > 0) {
3846 QMimeData *data = d->model->mimeData(indexes);
3847 if (!data)
3848 return;
3849 QRect rect;
3850 QPixmap pixmap = d->renderToPixmap(indexes, &rect);
3851 rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
3852 QDrag *drag = new QDrag(this);
3853 drag->setPixmap(pixmap);
3854 drag->setMimeData(data);
3855 drag->setHotSpot(d->pressedPosition - rect.topLeft());
3856 Qt::DropAction defaultDropAction = Qt::IgnoreAction;
3857 if (dragDropMode() == InternalMove)
3858 supportedActions &= ~Qt::CopyAction;
3859 if (d->defaultDropAction != Qt::IgnoreAction && (supportedActions & d->defaultDropAction))
3860 defaultDropAction = d->defaultDropAction;
3861 else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
3862 defaultDropAction = Qt::CopyAction;
3863 d->dropEventMoved = false;
3864 if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction && !d->dropEventMoved) {
3865 if (dragDropMode() != InternalMove || drag->target() == viewport())
3866 d->clearOrRemove();
3867 }
3868 d->dropEventMoved = false;
3869 // Reset the drop indicator
3870 d->dropIndicatorRect = QRect();
3871 d->dropIndicatorPosition = OnItem;
3872 }
3873}
3874#endif // QT_CONFIG(draganddrop)
3875
3886void QAbstractItemView::initViewItemOption(QStyleOptionViewItem *option) const
3887{
3888 Q_D(const QAbstractItemView);
3889 option->initFrom(this);
3890 option->state &= ~QStyle::State_MouseOver;
3891 option->font = font();
3892
3893 // On mac the focus appearance follows window activation
3894 // not widget activation
3895 if (!hasFocus())
3896 option->state &= ~QStyle::State_Active;
3897
3898 option->state &= ~QStyle::State_HasFocus;
3899 if (d->iconSize.isValid()) {
3900 option->decorationSize = d->iconSize;
3901 } else {
3902 int pm = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this);
3903 option->decorationSize = QSize(pm, pm);
3904 }
3905 option->decorationPosition = QStyleOptionViewItem::Left;
3906 option->decorationAlignment = Qt::AlignCenter;
3907 option->displayAlignment = Qt::AlignLeft|Qt::AlignVCenter;
3908 option->textElideMode = d->textElideMode;
3909 option->rect = QRect();
3910 option->showDecorationSelected = style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, this);
3911 if (d->wrapItemText)
3912 option->features = QStyleOptionViewItem::WrapText;
3913 option->locale = locale();
3914 option->locale.setNumberOptions(QLocale::OmitGroupSeparator);
3915 option->widget = this;
3916}
3917
3924{
3925 Q_D(const QAbstractItemView);
3926 return d->state;
3927}
3928
3935{
3936 Q_D(QAbstractItemView);
3937 d->state = state;
3938}
3939
3950{
3951 Q_D(QAbstractItemView);
3952 d->doDelayedItemsLayout();
3953}
3954
3962{
3963 Q_D(QAbstractItemView);
3964 d->executePostedLayout();
3965}
3966
3978{
3979 Q_D(QAbstractItemView);
3980 d->setDirtyRegion(region);
3981}
3982
3994{
3995 Q_D(QAbstractItemView);
3996 d->scrollDirtyRegion(dx, dy);
3997}
3998
4009{
4010 Q_D(const QAbstractItemView);
4011 return d->scrollDelayOffset;
4012}
4013
4018{
4019 d_func()->startAutoScroll();
4020}
4021
4026{
4027 d_func()->stopAutoScroll();
4028}
4029
4034{
4035 // find how much we should scroll with
4036 Q_D(QAbstractItemView);
4037 QScrollBar *verticalScroll = verticalScrollBar();
4038 QScrollBar *horizontalScroll = horizontalScrollBar();
4039
4040 // QHeaderView does not (normally) have scrollbars
4041 // It needs to use its parents scroll instead
4042 QHeaderView *hv = qobject_cast<QHeaderView*>(this);
4043 if (hv) {
4044 QAbstractScrollArea *parent = qobject_cast<QAbstractScrollArea*>(parentWidget());
4045 if (parent) {
4046 if (hv->orientation() == Qt::Horizontal) {
4047 if (!hv->horizontalScrollBar() || !hv->horizontalScrollBar()->isVisible())
4048 horizontalScroll = parent->horizontalScrollBar();
4049 } else {
4050 if (!hv->verticalScrollBar() || !hv->verticalScrollBar()->isVisible())
4051 verticalScroll = parent->verticalScrollBar();
4052 }
4053 }
4054 }
4055
4056 const int verticalStep = verticalScroll->pageStep();
4057 const int horizontalStep = horizontalScroll->pageStep();
4058 if (d->autoScrollCount < qMax(verticalStep, horizontalStep))
4059 ++d->autoScrollCount;
4060
4061 const int margin = d->autoScrollMargin;
4062 const int verticalValue = verticalScroll->value();
4063 const int horizontalValue = horizontalScroll->value();
4064
4065 const QPoint pos = d->draggedPosition - d->offset();
4066 const QRect area = QWidgetPrivate::get(d->viewport)->clipRect();
4067
4068 // do the scrolling if we are in the scroll margins
4069 if (pos.y() - area.top() < margin)
4070 verticalScroll->setValue(verticalValue - d->autoScrollCount);
4071 else if (area.bottom() - pos.y() < margin)
4072 verticalScroll->setValue(verticalValue + d->autoScrollCount);
4073 if (pos.x() - area.left() < margin)
4074 horizontalScroll->setValue(horizontalValue - d->autoScrollCount);
4075 else if (area.right() - pos.x() < margin)
4076 horizontalScroll->setValue(horizontalValue + d->autoScrollCount);
4077 // if nothing changed, stop scrolling
4078 const bool verticalUnchanged = (verticalValue == verticalScroll->value());
4079 const bool horizontalUnchanged = (horizontalValue == horizontalScroll->value());
4080 if (verticalUnchanged && horizontalUnchanged) {
4082 } else {
4083#if QT_CONFIG(draganddrop)
4084 d->dropIndicatorRect = QRect();
4085 d->dropIndicatorPosition = QAbstractItemView::OnViewport;
4086#endif
4087 switch (state()) {
4089 // mouseMoveEvent updates the drag-selection rectangle, so fake an event. This also
4090 // updates draggedPosition taking the now scrolled viewport into account.
4091 const QPoint globalPos = d->viewport->mapToGlobal(pos);
4092 const QPoint windowPos = window()->mapFromGlobal(globalPos);
4093 QMouseEvent mm(QEvent::MouseMove, pos, windowPos, globalPos,
4094 Qt::NoButton, Qt::LeftButton, d->pressedModifiers,
4097 break;
4098 }
4100 // we can't simulate mouse (it would throw off the drag'n'drop state logic) or drag
4101 // (we don't have the mime data or the actions) move events during drag'n'drop, so
4102 // update our dragged position manually after the scroll. "pos" is the old
4103 // draggedPosition - d->offset(), and d->offset() is now updated after scrolling, so
4104 // pos + d->offset() gives us the new position.
4105 d->draggedPosition = pos + d->offset();
4106 break;
4107 }
4108 default:
4109 break;
4110 }
4111 d->viewport->update();
4112 }
4113}
4114
4125QItemSelectionModel::SelectionFlags QAbstractItemView::selectionCommand(const QModelIndex &index,
4126 const QEvent *event) const
4127{
4128 Q_D(const QAbstractItemView);
4129 Qt::KeyboardModifiers keyModifiers = event && event->isInputEvent()
4130 ? static_cast<const QInputEvent*>(event)->modifiers()
4132 switch (d->selectionMode) {
4133 case NoSelection: // Never update selection model
4135 case SingleSelection: // ClearAndSelect on valid index otherwise NoUpdate
4136 if (event) {
4137 switch (event->type()) {
4139 // press with any modifiers on a selected item does nothing
4140 if (d->pressedAlreadySelected)
4142 break;
4144 // clicking into area with no items does nothing
4145 if (!index.isValid())
4147 Q_FALLTHROUGH();
4148 case QEvent::KeyPress:
4149 // ctrl-release on selected item deselects
4150 if ((keyModifiers & Qt::ControlModifier) && d->selectionModel->isSelected(index))
4151 return QItemSelectionModel::Deselect | d->selectionBehaviorFlags();
4152 break;
4153 default:
4154 break;
4155 }
4156 }
4157 return QItemSelectionModel::ClearAndSelect | d->selectionBehaviorFlags();
4158 case MultiSelection:
4159 return d->multiSelectionCommand(index, event);
4160 case ExtendedSelection:
4161 return d->extendedSelectionCommand(index, event);
4163 return d->contiguousSelectionCommand(index, event);
4164 }
4166}
4167
4168QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::multiSelectionCommand(
4169 const QModelIndex &index, const QEvent *event) const
4170{
4171 Q_UNUSED(index);
4172
4173 if (event) {
4174 switch (event->type()) {
4175 case QEvent::KeyPress:
4176 if (static_cast<const QKeyEvent*>(event)->key() == Qt::Key_Space
4177 || static_cast<const QKeyEvent*>(event)->key() == Qt::Key_Select)
4179 break;
4181 if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton) {
4182 // since the press might start a drag, deselect only on release
4184#if QT_CONFIG(draganddrop)
4185 || !dragEnabled || !isIndexDragEnabled(index)
4186#endif
4187 )
4189 }
4190 break;
4192 if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton) {
4194#if QT_CONFIG(draganddrop)
4195 && dragEnabled && isIndexDragEnabled(index)
4196#endif
4197 && index == pressedIndex)
4200 }
4201 break;
4202 case QEvent::MouseMove:
4203 if (static_cast<const QMouseEvent*>(event)->buttons() & Qt::LeftButton)
4204 return QItemSelectionModel::ToggleCurrent|selectionBehaviorFlags(); // toggle drag select
4205 break;
4206 default:
4207 break;
4208 }
4210 }
4211
4213}
4214
4215QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionCommand(
4216 const QModelIndex &index, const QEvent *event) const
4217{
4218 Qt::KeyboardModifiers modifiers = event && event->isInputEvent()
4219 ? static_cast<const QInputEvent*>(event)->modifiers()
4221 if (event) {
4222 switch (event->type()) {
4223 case QEvent::MouseMove: {
4224 // Toggle on MouseMove
4227 break;
4228 }
4230 const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
4231 const bool rightButtonPressed = button & Qt::RightButton;
4232 const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
4233 const bool controlKeyPressed = modifiers & Qt::ControlModifier;
4234 const bool indexIsSelected = selectionModel->isSelected(index);
4235 if ((shiftKeyPressed || controlKeyPressed) && rightButtonPressed)
4237 if (!shiftKeyPressed && !controlKeyPressed && indexIsSelected)
4239 if (!index.isValid() && !rightButtonPressed && !shiftKeyPressed && !controlKeyPressed)
4241 if (!index.isValid())
4243 // since the press might start a drag, deselect only on release
4244 if (controlKeyPressed && !rightButtonPressed && pressedAlreadySelected
4245#if QT_CONFIG(draganddrop)
4246 && dragEnabled && isIndexDragEnabled(index)
4247#endif
4248 ) {
4250 }
4251 break;
4252 }
4254 // ClearAndSelect on MouseButtonRelease if MouseButtonPress on selected item or empty area
4255 const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
4256 const bool rightButtonPressed = button & Qt::RightButton;
4257 const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
4258 const bool controlKeyPressed = modifiers & Qt::ControlModifier;
4261 && !shiftKeyPressed && !controlKeyPressed && (!rightButtonPressed || !index.isValid()))
4263 if (index == pressedIndex && controlKeyPressed && !rightButtonPressed
4264#if QT_CONFIG(draganddrop)
4265 && dragEnabled && isIndexDragEnabled(index)
4266#endif
4267 ) {
4268 break;
4269 }
4271 }
4272 case QEvent::KeyPress: {
4273 // NoUpdate on Key movement and Ctrl
4274 switch (static_cast<const QKeyEvent*>(event)->key()) {
4275 case Qt::Key_Backtab:
4276 modifiers = modifiers & ~Qt::ShiftModifier; // special case for backtab
4277 Q_FALLTHROUGH();
4278 case Qt::Key_Down:
4279 case Qt::Key_Up:
4280 case Qt::Key_Left:
4281 case Qt::Key_Right:
4282 case Qt::Key_Home:
4283 case Qt::Key_End:
4284 case Qt::Key_PageUp:
4285 case Qt::Key_PageDown:
4286 case Qt::Key_Tab:
4288#ifdef QT_KEYPAD_NAVIGATION
4289 // Preserve historical tab order navigation behavior
4290 || QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
4291#endif
4292 )
4294 break;
4295 case Qt::Key_Select:
4297 case Qt::Key_Space:// Toggle on Ctrl-Qt::Key_Space, Select on Space
4301 default:
4302 break;
4303 }
4304 break;
4305 }
4306 default:
4307 break;
4308 }
4309 }
4310
4316 //when drag-selecting we need to clear any previous selection and select the current one
4318 }
4319
4321}
4322
4323QItemSelectionModel::SelectionFlags
4347
4349{
4350 fetchMoreTimer.stop();
4351 if (!model->canFetchMore(root))
4352 return;
4353 int last = model->rowCount(root) - 1;
4354 if (last < 0) {
4356 return;
4357 }
4358
4359 QModelIndex index = model->index(last, 0, root);
4360 QRect rect = q_func()->visualRect(index);
4361 if (viewport->rect().intersects(rect))
4363}
4364
4366 const QModelIndex &index) const
4367{
4368 if (!index.isValid())
4369 return false;
4370 Qt::ItemFlags flags = model->flags(index);
4371 if (((flags & Qt::ItemIsEditable) == 0) || ((flags & Qt::ItemIsEnabled) == 0))
4372 return false;
4374 return false;
4375 if (hasEditor(index))
4376 return false;
4377 if (trigger == QAbstractItemView::AllEditTriggers) // force editing
4378 return true;
4381 return false;
4382 return (trigger & editTriggers);
4383}
4384
4386 const QEvent *event) const
4387{
4389 return false;
4390
4391 switch (event->type()) {
4392 case QEvent::KeyPress:
4396 case QEvent::MouseMove:
4397 return true;
4398 default:
4399 break;
4400 };
4401
4402 return false;
4403}
4404
4406{
4407 if (!autoScroll)
4408 return false;
4409 QRect area = static_cast<QAbstractItemView*>(viewport)->d_func()->clipRect(); // access QWidget private by bending C++ rules
4410 return (pos.y() - area.top() < autoScrollMargin)
4411 || (area.bottom() - pos.y() < autoScrollMargin)
4412 || (pos.x() - area.left() < autoScrollMargin)
4413 || (area.right() - pos.x() < autoScrollMargin);
4414}
4415
4417{
4418 if (!delayedPendingLayout) {
4419 delayedPendingLayout = true;
4420 delayedLayout.start(delay, q_func());
4421 }
4422}
4423
4425{
4426 delayedLayout.stop();
4427 delayedPendingLayout = false;
4428}
4429
4431{
4432 Q_Q(QAbstractItemView);
4433 if (sizeAdjustPolicy == QAbstractScrollArea::AdjustIgnored)
4434 return;
4435 if (sizeAdjustPolicy == QAbstractScrollArea::AdjustToContents || !shownOnce)
4436 q->updateGeometry();
4437}
4438
4439/*
4440 Handles selection of content for some editors containing QLineEdit.
4441
4442 ### Qt 7 This should be done by a virtual method in QAbstractItemDelegate.
4443*/
4445{
4446 while (QWidget *fp = editor->focusProxy())
4447 editor = fp;
4448
4449#if QT_CONFIG(lineedit)
4450 if (QLineEdit *le = qobject_cast<QLineEdit*>(editor))
4451 le->selectAll();
4452#endif
4453#if QT_CONFIG(spinbox)
4454 if (QSpinBox *sb = qobject_cast<QSpinBox*>(editor))
4455 sb->selectAll();
4456 else if (QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox*>(editor))
4457 dsb->selectAll();
4458#endif
4459}
4460
4462 const QStyleOptionViewItem &options)
4463{
4464 Q_Q(QAbstractItemView);
4466 if (!w) {
4467 QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
4468 if (!delegate)
4469 return nullptr;
4470 w = delegate->createEditor(viewport, options, index);
4471 if (w) {
4472 w->installEventFilter(delegate);
4474 delegate->updateEditorGeometry(w, options, index);
4475 delegate->setEditorData(w, index);
4476 addEditor(index, w, false);
4477 if (w->parent() == viewport)
4479
4481 }
4482 }
4483
4484 return w;
4485}
4486
4488{
4489 Q_Q(QAbstractItemView);
4490 // we are counting on having relatively few editors
4491 const bool checkIndexes = tl.isValid() && br.isValid();
4492 const QModelIndex parent = tl.parent();
4493 // QTBUG-25370: We need to copy the indexEditorHash, because while we're
4494 // iterating over it, we are calling methods which can allow user code to
4495 // call a method on *this which can modify the member indexEditorHash.
4496 const QIndexEditorHash indexEditorHashCopy = indexEditorHash;
4497 QIndexEditorHash::const_iterator it = indexEditorHashCopy.constBegin();
4498 for (; it != indexEditorHashCopy.constEnd(); ++it) {
4499 QWidget *editor = it.value().widget.data();
4500 const QModelIndex index = it.key();
4501 if (it.value().isStatic || !editor || !index.isValid() ||
4502 (checkIndexes
4503 && (index.row() < tl.row() || index.row() > br.row()
4504 || index.column() < tl.column() || index.column() > br.column()
4505 || index.parent() != parent)))
4506 continue;
4507
4508 QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
4509 if (delegate) {
4510 delegate->setEditorData(editor, index);
4511 }
4512 }
4513}
4514
4525{
4526#if QT_CONFIG(draganddrop)
4529
4530 if (!overwrite) {
4531 for (; it != selection.constEnd(); ++it) {
4532 QModelIndex parent = (*it).parent();
4533 if ((*it).left() != 0)
4534 continue;
4535 if ((*it).right() != (model->columnCount(parent) - 1))
4536 continue;
4537 int count = (*it).bottom() - (*it).top() + 1;
4538 model->removeRows((*it).top(), count, parent);
4539 }
4540 } else {
4541 // we can't remove the rows so reset the items (i.e. the view is like a table)
4543 for (int i=0; i < list.size(); ++i) {
4545 QMap<int, QVariant> roles = model->itemData(index);
4546 for (QMap<int, QVariant>::Iterator it = roles.begin(); it != roles.end(); ++it)
4547 it.value() = QVariant();
4548 model->setItemData(index, roles);
4549 }
4550 }
4551#endif
4552}
4553
4561{
4562 Q_Q(QAbstractItemView);
4564 if (persistent.contains(widget)) {
4565 //a persistent editor has gained the focus
4568 q->setCurrentIndex(index);
4569 }
4570 }
4571}
4572
4573
4575{
4576 static QEditorInfo nullInfo;
4577
4578 // do not try to search to avoid slow implicit cast from QModelIndex to QPersistentModelIndex
4580 return nullInfo;
4581
4583 if (it == indexEditorHash.end())
4584 return nullInfo;
4585
4586 return it.value();
4587}
4588
4590{
4591 // Search's implicit cast (QModelIndex to QPersistentModelIndex) is slow; use cheap pre-test to avoid when we can.
4593}
4594
4596{
4597 // do not try to search to avoid slow implicit cast from QModelIndex to QPersistentModelIndex
4599 return QModelIndex();
4600
4602 if (it == editorIndexHash.end())
4603 return QModelIndex();
4604
4605 return it.value();
4606}
4607
4619
4625
4627{
4628 Q_Q(const QAbstractItemView);
4629 QModelIndex buddy = model->buddy(index);
4630 QStyleOptionViewItem options;
4631 q->initViewItemOption(&options);
4632 options.rect = q->visualRect(buddy);
4633 options.state |= (buddy == q->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
4634 QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
4635 return (event && delegate && delegate->editorEvent(event, model, options, buddy));
4636}
4637
4639{
4640 Q_Q(QAbstractItemView);
4641
4642 QModelIndex buddy = model->buddy(index);
4643 QStyleOptionViewItem options;
4644 q->initViewItemOption(&options);
4645 options.rect = q->visualRect(buddy);
4646 options.state |= (buddy == q->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
4647
4648 QWidget *w = editor(buddy, options);
4649 if (!w)
4650 return false;
4651
4653 w->show();
4654 if (!waitForIMCommit)
4655 w->setFocus();
4656 else
4657 q->updateMicroFocus();
4658
4659 if (event)
4660 QCoreApplication::sendEvent(w->focusProxy() ? w->focusProxy() : w, event);
4661
4662 return true;
4663}
4664
4665/*
4666 \internal
4667
4668 returns the pair QRect/QModelIndex that should be painted on the viewports's rect
4669*/
4670
4672{
4673 Q_ASSERT(r);
4674 Q_Q(const QAbstractItemView);
4675 QRect &rect = *r;
4676 const QRect viewportRect = viewport->rect();
4678 for (const auto &index : indexes) {
4679 const QRect current = q->visualRect(index);
4680 if (current.intersects(viewportRect)) {
4681 ret.append({current, index});
4682 rect |= current;
4683 }
4684 }
4685 QRect clipped = rect & viewportRect;
4686 rect.setLeft(clipped.left());
4687 rect.setRight(clipped.right());
4688 return ret;
4689}
4690
4692{
4693 Q_Q(const QAbstractItemView);
4694 Q_ASSERT(r);
4695 QItemViewPaintPairs paintPairs = draggablePaintPairs(indexes, r);
4696 if (paintPairs.isEmpty())
4697 return QPixmap();
4698
4699 QWindow *window = windowHandle(WindowHandleMode::Closest);
4700 const qreal scale = window ? window->devicePixelRatio() : qreal(1);
4701
4702 QPixmap pixmap(r->size() * scale);
4703 pixmap.setDevicePixelRatio(scale);
4704
4705 pixmap.fill(Qt::transparent);
4707 QStyleOptionViewItem option;
4708 q->initViewItemOption(&option);
4710 for (int j = 0; j < paintPairs.size(); ++j) {
4711 option.rect = paintPairs.at(j).rect.translated(-r->topLeft());
4712 const QModelIndex &current = paintPairs.at(j).index;
4714 q->itemDelegateForIndex(current)->paint(&painter, option, current);
4715 }
4716 return pixmap;
4717}
4718
4719void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
4720{
4721 if (!selectionModel)
4722 return;
4723 if (!model->hasChildren(root))
4724 return;
4725
4727 QModelIndex tl = model->index(0, 0, root);
4729 model->columnCount(root) - 1,
4730 root);
4732 selectionModel->select(selection, command);
4733}
4734
4735#if QT_CONFIG(draganddrop)
4736QModelIndexList QAbstractItemViewPrivate::selectedDraggableIndexes() const
4737{
4738 Q_Q(const QAbstractItemView);
4739 QModelIndexList indexes = q->selectedIndexes();
4740 auto isNotDragEnabled = [this](const QModelIndex &index) {
4741 return !isIndexDragEnabled(index);
4742 };
4743 indexes.removeIf(isNotDragEnabled);
4744 return indexes;
4745}
4746
4747void QAbstractItemViewPrivate::maybeStartDrag(QPoint eventPosition)
4748{
4749 Q_Q(QAbstractItemView);
4750
4751 const QPoint topLeft = pressedPosition - offset();
4752 if ((topLeft - eventPosition).manhattanLength() > QApplication::startDragDistance()) {
4754 q->startDrag(model->supportedDragActions());
4755 q->setState(QAbstractItemView::NoState); // the startDrag will return when the dnd operation
4756 // is done
4757 q->stopAutoScroll();
4758 }
4759}
4760#endif
4761
4767{
4768 Q_D(QAbstractItemView);
4769 if (object == this || object == viewport() || event->type() != QEvent::FocusIn)
4770 return QAbstractScrollArea::eventFilter(object, event);
4772 // If it is not a persistent widget then we did not install
4773 // the event filter on it, so assume a base implementation is
4774 // filtering
4775 if (!widget || !d->persistent.contains(widget))
4776 return QAbstractScrollArea::eventFilter(object, event);
4777 setCurrentIndex(d->indexForEditor(widget));
4778 return false;
4779}
4780
4782
4783#include "moc_qabstractitemview.cpp"
The QAbstractItemDelegate class is used to display and edit data items from a model.
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const =0
This pure abstract function must be reimplemented if you want to provide custom rendering.
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...
void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint=NoHint)
This signal is emitted when the user has finished editing an item using the specified editor.
void commitData(QWidget *editor)
This signal must be emitted when the editor widget has completed editing the data,...
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.
void sizeHintChanged(const QModelIndex &)
virtual bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index)
static QAbstractItemModel * staticEmptyModel()
virtual Qt::DropActions supportedDropActions() const
void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal)
Q_INVOKABLE int const QModelIndex & parent
Returns the parent of the model item with the given index.
void columnsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after columns have been removed from the model.
virtual Q_INVOKABLE Qt::ItemFlags flags(const QModelIndex &index) const
Returns the item flags for the given index.
void modelReset(QPrivateSignal)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >())
This signal is emitted whenever the data in an existing item changes.
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.
void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before columns are removed from the model.
void layoutChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
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}.
void headerDataChanged(Qt::Orientation orientation, int first, int last)
This signal is emitted whenever a header is changed.
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before rows are removed from the model.
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.
void rowsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after rows have been inserted into the model.
void columnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn, QPrivateSignal)
void columnsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after columns have been inserted into the model.
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.
void rowsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after rows have been removed from the model.
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 columnsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart)
virtual void adjustViewOptionsForIndex(QStyleOptionViewItem *, const QModelIndex &) const
void removeEditor(QWidget *editor)
virtual void rowsRemoved(const QModelIndex &parent, int start, int end)
void updateEditorData(const QModelIndex &topLeft, const QModelIndex &bottomRight)
bool hasEditor(const QModelIndex &index) const
QPointer< QAbstractItemDelegate > itemDelegate
void addEditor(const QModelIndex &index, QWidget *editor, bool isStatic)
QMap< int, QPointer< QAbstractItemDelegate > > columnDelegates
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
QMap< int, QPointer< QAbstractItemDelegate > > rowDelegates
void setHoverIndex(const QPersistentModelIndex &index)
virtual void columnsInserted(const QModelIndex &parent, int start, int end)
QAbstractItemView::State state
QPointer< QItemSelectionModel > selectionModel
void delegateSizeHintChanged(const QModelIndex &index)
bool shouldAutoScroll(const QPoint &pos) const
bool shouldForwardEvent(QAbstractItemView::EditTrigger trigger, const QEvent *event) const
QItemSelectionModel::SelectionFlags selectionBehaviorFlags() const
QPersistentModelIndex root
bool droppingOnItself(QDropEvent *event, const QModelIndex &index)
std::array< QMetaObject::Connection, 4 > scrollbarConnections
bool openEditor(const QModelIndex &index, QEvent *event)
virtual QRect visualRect(const QModelIndex &index) const
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
virtual void columnsRemoved(const QModelIndex &parent, int start, int end)
QItemSelectionModel::SelectionFlags extendedSelectionCommand(const QModelIndex &index, const QEvent *event) const
virtual void columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
QPersistentModelIndex enteredIndex
QItemSelectionModel::SelectionFlags multiSelectionCommand(const QModelIndex &index, const QEvent *event) const
virtual void rowsInserted(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
virtual void rowsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart)
std::array< QMetaObject::Connection, 14 > modelConnections
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
void valueChanged(int value)
This signal is emitted when the slider value has changed, with the new slider value as argument.
int pageStep
the page step.
void actionTriggered(int action)
This signal is emitted when the slider action action is triggered.
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.
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:148
Qt::DropAction exec(Qt::DropActions supportedActions=Qt::MoveAction)
Definition qdrag.cpp:201
void setMimeData(QMimeData *data)
Sets the data to be sent to the given MIME data.
Definition qdrag.cpp:101
void setPixmap(const QPixmap &)
Sets pixmap as the pixmap used to represent the data in a drag and drop operation.
Definition qdrag.cpp:125
QObject * target() const
Returns the target of the drag and drop operation.
Definition qdrag.cpp:178
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:470
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:958
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1299
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1291
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:985
iterator erase(const_iterator it)
Definition qhash.h:1233
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
const_iterator cend() const noexcept
Definition qhash.h:1218
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:928
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
The QHeaderView class provides a header row or header column for item views.
Definition qheaderview.h:18
The QHelpEvent class provides an event that is used to request helpful information about a particular...
Definition qevent.h:788
\inmodule QtGui
Definition qevent.h:246
\inmodule QtGui
Definition qevent.h:49
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:625
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
This signal is emitted whenever the selection changes.
void currentChanged(const QModelIndex &current, const QModelIndex &previous)
This signal is emitted whenever the current item changes.
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:424
The QLineEdit widget is a one-line text editor.
Definition qlineedit.h:28
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
const_iterator constBegin() const noexcept
Definition qlist.h:632
qsizetype removeIf(Predicate pred)
Definition qlist.h:604
void append(parameter_type t)
Definition qlist.h:458
const_iterator constEnd() const noexcept
Definition qlist.h:633
@ OmitGroupSeparator
Definition qlocale.h:879
\inmodule QtCore Represents a handle to a signal-slot (or signal-functor) connection.
\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.
constexpr const QAbstractItemModel * model() const noexcept
Returns a pointer to the model containing the item that this index refers to.
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:196
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
static bool disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot)
Definition qobject_p.h:328
\inmodule QtCore
Definition qobject.h:103
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2339
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
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:25
T * data() const noexcept
Definition qpointer.h:73
\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:167
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:1069
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:373
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:415
constexpr void setLeft(int pos) noexcept
Sets the left edge of the rectangle to the given x coordinate.
Definition qrect.h:191
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:548
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
void stateChanged(QScroller::State newstate)
QScroller emits this signal whenever the state changes.
bool remove(const T &value)
Definition qset.h:63
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
iterator erase(const_iterator i)
Definition qset.h:145
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:808
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype count(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4833
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:659
@ SH_ItemView_ScrollMode
Definition qstyle.h:698
@ SH_ItemView_ActivateItemOnSingleClick
Definition qstyle.h:646
@ SH_ItemView_ShowDecorationSelected
Definition qstyle.h:645
@ PM_SmallIconSize
Definition qstyle.h:495
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
Returns the value of the given pixel metric.
The QStyledItemDelegate class provides display and editing facilities for data items from a model.
\inmodule QtCore
Definition qcoreevent.h:366
\inmodule QtCore
Definition qvariant.h:65
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
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:345
static QWidgetPrivate * get(QWidget *w)
Definition qwidget_p.h:212
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:6427
static void setTabOrder(QWidget *, QWidget *)
Puts the second widget after the first widget in the focus order.
Definition qwidget.cpp:6981
void show()
Shows the widget and its child widgets.
Definition qwidget.cpp:7875
\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.
Definition qcompare.h:63
InputMethodQuery
@ ImCursorRectangle
@ AlignVCenter
Definition qnamespace.h:155
@ AlignCenter
Definition qnamespace.h:163
@ AlignLeft
Definition qnamespace.h:144
@ NavigationModeKeypadDirectional
@ NavigationModeKeypadTabOrder
MouseButton
Definition qnamespace.h:56
@ LeftButton
Definition qnamespace.h:58
@ RightButton
Definition qnamespace.h:59
@ NoButton
Definition qnamespace.h:57
@ WA_InputMethodEnabled
Definition qnamespace.h:295
@ NoFocus
Definition qnamespace.h:107
@ Horizontal
Definition qnamespace.h:99
@ Vertical
Definition qnamespace.h:100
@ MouseEventSynthesizedByQt
@ transparent
Definition qnamespace.h:47
@ StatusTipRole
@ DisplayRole
@ Key_Escape
Definition qnamespace.h:663
@ Key_O
Definition qnamespace.h:561
@ Key_Tab
Definition qnamespace.h:664
@ Key_Select
@ Key_Shift
Definition qnamespace.h:683
@ Key_Return
Definition qnamespace.h:667
@ Key_Right
Definition qnamespace.h:679
@ Key_Enter
Definition qnamespace.h:668
@ Key_PageUp
Definition qnamespace.h:681
@ Key_Space
Definition qnamespace.h:513
@ Key_Backspace
Definition qnamespace.h:666
@ Key_Backtab
Definition qnamespace.h:665
@ Key_Left
Definition qnamespace.h:677
@ Key_Control
Definition qnamespace.h:684
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
@ Key_F2
Definition qnamespace.h:691
@ Key_Delete
Definition qnamespace.h:670
@ Key_PageDown
Definition qnamespace.h:682
@ Key_Back
Definition qnamespace.h:846
@ Key_Home
Definition qnamespace.h:675
@ Key_End
Definition qnamespace.h:676
@ ShiftModifier
@ ControlModifier
@ MetaModifier
@ NoModifier
@ AltModifier
DropAction
@ CopyAction
@ IgnoreAction
@ MoveAction
@ QueuedConnection
@ UniqueConnection
TextElideMode
Definition qnamespace.h:188
@ ItemIsEditable
@ ItemIsEnabled
@ ItemIsDropEnabled
@ MouseFocusReason
QList< QItemViewPaintPair > QItemViewPaintPairs
static jboolean copy(JNIEnv *, jobject)
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
DBusConnection * connection
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr auto emptyString
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
static int area(const QSize &s)
Definition qicon.cpp:153
#define qWarning
Definition qlogging.h:166
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
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 GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei width
GLbitfield flags
GLboolean enable
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
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:60
double qreal
Definition qtypes.h:187
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
QSqlQueryModel * model
[16]
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
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]
QHostInfo info
[0]
QScroller * scroller
QPointer< QWidget > widget
bool contains(const AT &t) const noexcept
Definition qlist.h:45
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...