Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qabstractitemview_p.h
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// Qt-Security score:significant reason:default
4
5#ifndef QABSTRACTITEMVIEW_P_H
6#define QABSTRACTITEMVIEW_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtWidgets/private/qtwidgetsglobal_p.h>
21#include "private/qabstractscrollarea_p.h"
22#include "private/qabstractitemmodel_p.h"
23#include "QtWidgets/qapplication.h"
24#include "QtGui/qevent.h"
25#include "QtCore/qmimedata.h"
26#include "QtGui/qpainter.h"
27#include "QtGui/qregion.h"
28
29#include "QtCore/qbasictimer.h"
30#include "QtCore/qelapsedtimer.h"
31#include <QtCore/qpointer.h>
32
33
34#include <array>
35
37
38QT_BEGIN_NAMESPACE
39
40struct QEditorInfo {
41 QEditorInfo(QWidget *e, bool s): widget(QPointer<QWidget>(e)), isStatic(s) {}
42 QEditorInfo(): isStatic(false) {}
43
44 QPointer<QWidget> widget;
45 bool isStatic;
46};
47
48// Fast associativity between Persistent editors and indices.
51
56template <>
58
60
61class Q_AUTOTEST_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate
62{
63 Q_DECLARE_PUBLIC(QAbstractItemView)
64
65public:
66 QAbstractItemViewPrivate();
67 virtual ~QAbstractItemViewPrivate();
68
69 void init();
70
71 virtual void rowsRemoved(const QModelIndex &parent, int start, int end);
72 virtual void rowsInserted(const QModelIndex &parent, int start, int end);
73 virtual void columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
74 virtual void columnsRemoved(const QModelIndex &parent, int start, int end);
75 virtual void columnsInserted(const QModelIndex &parent, int start, int end);
76 virtual void modelDestroyed();
77 virtual void layoutChanged();
78 virtual void rowsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart);
79 virtual void columnsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart);
80 virtual QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const;
81
82 void headerDataChanged() { doDelayedItemsLayout(); }
83 void scrollerStateChanged();
84 void delegateSizeHintChanged(const QModelIndex &index);
85
86 void fetchMore();
87
88 bool shouldEdit(QAbstractItemView::EditTrigger trigger, const QModelIndex &index) const;
89 bool shouldForwardEvent(QAbstractItemView::EditTrigger trigger, const QEvent *event) const;
90 bool shouldAutoScroll(const QPoint &pos) const;
91 void doDelayedItemsLayout(int delay = 0);
92 void interruptDelayedItemsLayout() const;
93
94 void updateGeometry();
95
96 void startAutoScroll()
97 { // ### it would be nice to make this into a style hint one day
98 int scrollInterval = (verticalScrollMode == QAbstractItemView::ScrollPerItem) ? 150 : 50;
99 autoScrollTimer.start(scrollInterval, q_func());
100 autoScrollCount = 0;
101 }
102 void stopAutoScroll() { autoScrollTimer.stop(); autoScrollCount = 0;}
103
104#if QT_CONFIG(draganddrop)
105 virtual bool dropOn(QDropEvent *event, int *row, int *col, QModelIndex *index);
106#endif
107 bool droppingOnItself(QDropEvent *event, const QModelIndex &index);
108
109 QWidget *editor(const QModelIndex &index, const QStyleOptionViewItem &options);
110 bool sendDelegateEvent(const QModelIndex &index, QEvent *event) const;
111 bool openEditor(const QModelIndex &index, QEvent *event);
112 void updateEditorData(const QModelIndex &topLeft, const QModelIndex &bottomRight);
113 void selectAllInEditor(QWidget *w);
114
115 QItemSelectionModel::SelectionFlags multiSelectionCommand(const QModelIndex &index,
116 const QEvent *event) const;
117 QItemSelectionModel::SelectionFlags extendedSelectionCommand(const QModelIndex &index,
118 const QEvent *event) const;
119 QItemSelectionModel::SelectionFlags contiguousSelectionCommand(const QModelIndex &index,
120 const QEvent *event) const;
121 virtual void selectAll(QItemSelectionModel::SelectionFlags command);
122
123 void setHoverIndex(const QPersistentModelIndex &index);
124
125 void checkMouseMove(const QPersistentModelIndex &index);
126 inline void checkMouseMove(const QPoint &pos) { checkMouseMove(q_func()->indexAt(pos)); }
127
128 inline QItemSelectionModel::SelectionFlags selectionBehaviorFlags() const
129 {
130 switch (selectionBehavior) {
131 case QAbstractItemView::SelectRows: return QItemSelectionModel::Rows;
132 case QAbstractItemView::SelectColumns: return QItemSelectionModel::Columns;
133 case QAbstractItemView::SelectItems: default: return QItemSelectionModel::NoUpdate;
134 }
135 }
136
137#if QT_CONFIG(draganddrop)
138 virtual QAbstractItemView::DropIndicatorPosition position(const QPoint &pos, const QRect &rect, const QModelIndex &idx) const;
139
140 inline bool canDrop(QDropEvent *event) {
141 const QMimeData *mime = event->mimeData();
142
143 // Drag enter event shall always be accepted, if mime type and action match.
144 // Whether the data can actually be dropped will be checked in drag move.
145 if (event->type() == QEvent::DragEnter && (event->dropAction() & model->supportedDropActions())) {
146 const QStringList modelTypes = model->mimeTypes();
147 for (const auto &modelType : modelTypes) {
148 if (mime->hasFormat(modelType))
149 return true;
150 }
151 }
152
153 QModelIndex index;
154 int col = -1;
155 int row = -1;
156 if (dropOn(event, &row, &col, &index)) {
157 return model->canDropMimeData(mime,
158 dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(),
159 row, col, index);
160 }
161 return false;
162 }
163
164 inline void paintDropIndicator(QPainter *painter)
165 {
166 if (showDropIndicator && state == QAbstractItemView::DraggingState
167 && !dropIndicatorRect.isNull()
168#ifndef QT_NO_CURSOR
169 && viewport->cursor().shape() != Qt::ForbiddenCursor
170#endif
171 ) {
172 QStyleOption opt;
173 opt.initFrom(q_func());
174 opt.rect = dropIndicatorRect;
175 q_func()->style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, painter, q_func());
176 }
177 }
178
179#endif
180 virtual QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const;
181 // reimplemented in subclasses
182 virtual void adjustViewOptionsForIndex(QStyleOptionViewItem*, const QModelIndex&) const {}
183
184 inline void releaseEditor(QWidget *editor, const QModelIndex &index = QModelIndex()) const {
185 if (editor) {
186 Q_Q(const QAbstractItemView);
187 QObject::disconnect(editor, &QWidget::destroyed,
188 q, &QAbstractItemView::editorDestroyed);
189 editor->removeEventFilter(itemDelegate);
190 editor->hide();
191 QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
192
193 if (delegate)
194 delegate->destroyEditor(editor, index);
195 else
196 editor->deleteLater();
197 }
198 }
199
200 inline void executePostedLayout() const {
201 if (delayedPendingLayout && state != QAbstractItemView::CollapsingState) {
202 interruptDelayedItemsLayout();
203 const_cast<QAbstractItemView*>(q_func())->doItemsLayout();
204 }
205 }
206
207 inline void setDirtyRegion(const QRegion &visualRegion) {
208 updateRegion += visualRegion;
209 if (!updateTimer.isActive())
210 updateTimer.start(0, q_func());
211 }
212
213 inline void scrollDirtyRegion(int dx, int dy) {
214 scrollDelayOffset = QPoint(-dx, -dy);
215 updateDirtyRegion();
216 scrollDelayOffset = QPoint(0, 0);
217 }
218
219 inline void scrollContentsBy(int dx, int dy) {
220 scrollDirtyRegion(dx, dy);
221 viewport->scroll(dx, dy);
222 }
223
224 void updateDirtyRegion() {
225 updateTimer.stop();
226 viewport->update(updateRegion);
227 updateRegion = QRegion();
228 }
229
230 void clearOrRemove();
231 void checkPersistentEditorFocus();
232
233 QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r) const;
234
235 inline QPoint offset() const {
236 const Q_Q(QAbstractItemView);
237 return QPoint(q->isRightToLeft() ? -q->horizontalOffset()
238 : q->horizontalOffset(), q->verticalOffset());
239 }
240
241 const QEditorInfo &editorForIndex(const QModelIndex &index) const;
242 bool hasEditor(const QModelIndex &index) const;
243
244 QModelIndex indexForEditor(QWidget *editor) const;
245 void addEditor(const QModelIndex &index, QWidget *editor, bool isStatic);
246 void removeEditor(QWidget *editor);
247
248 inline bool isAnimating() const {
249 return state == QAbstractItemView::AnimatingState;
250 }
251
252 inline bool isIndexValid(const QModelIndex &index) const {
253 return (index.row() >= 0) && (index.column() >= 0) && (index.model() == model);
254 }
255 inline bool isIndexSelectable(const QModelIndex &index) const {
256 return (model->flags(index) & Qt::ItemIsSelectable);
257 }
258 inline bool isIndexEnabled(const QModelIndex &index) const {
259 return (model->flags(index) & Qt::ItemIsEnabled);
260 }
261#if QT_CONFIG(draganddrop)
262 inline bool isIndexDropEnabled(const QModelIndex &index) const {
263 return (model->flags(index) & Qt::ItemIsDropEnabled);
264 }
265 inline bool isIndexDragEnabled(const QModelIndex &index) const {
266 return (model->flags(index) & Qt::ItemIsDragEnabled);
267 }
268#endif
269
270 virtual bool selectionAllowed(const QModelIndex &index) const {
271 // in some views we want to go ahead with selections, even if the index is invalid
272 return isIndexValid(index) && isIndexSelectable(index);
273 }
274
275#if QT_CONFIG(accessibility)
276 virtual int accessibleChildIndex(const QModelIndex &index) const
277 {
278 Q_UNUSED(index);
279 return -1;
280 }
281#endif
282
283#if QT_CONFIG(accessibility)
284 void updateItemAccessibility(const QModelIndex &index, const QList<int> &roles);
285#endif
286
287 // reimplemented from QAbstractScrollAreaPrivate
288 QPoint contentsOffset() const override {
289 Q_Q(const QAbstractItemView);
290 return QPoint(q->horizontalOffset(), q->verticalOffset());
291 }
292
293 /**
294 * For now, assume that we have few editors, if we need a more efficient implementation
295 * we should add a QMap<QAbstractItemDelegate*, int> member.
296 */
297 int delegateRefCount(const QAbstractItemDelegate *delegate) const
298 {
299 int ref = 0;
300 if (itemDelegate == delegate)
301 ++ref;
302
303 for (int maps = 0; maps < 2; ++maps) {
304 const QMap<int, QPointer<QAbstractItemDelegate> > *delegates = maps ? &columnDelegates : &rowDelegates;
305 for (QMap<int, QPointer<QAbstractItemDelegate> >::const_iterator it = delegates->begin();
306 it != delegates->end(); ++it) {
307 if (it.value() == delegate) {
308 ++ref;
309 // optimization, we are only interested in the ref count values 0, 1 or >=2
310 if (ref >= 2) {
311 return ref;
312 }
313 }
314 }
315 }
316 return ref;
317 }
318
319 /**
320 * return true if the index is registered as a QPersistentModelIndex
321 */
322 inline bool isPersistent(const QModelIndex &index) const
323 {
324 return static_cast<QAbstractItemModelPrivate *>(model->d_ptr.data())->persistent.indexes.contains(index);
325 }
326
327#if QT_CONFIG(draganddrop)
328 QModelIndexList selectedDraggableIndexes() const;
329 void maybeStartDrag(QPoint eventPoint);
330#endif
331
332 void doDelayedReset()
333 {
334 //we delay the reset of the timer because some views (QTableView)
335 //with headers can't handle the fact that the model has been destroyed
336 //all modelDestroyed() slots must have been called
337 if (!delayedReset.isActive())
338 delayedReset.start(0, q_func());
339 }
340
341 QAbstractItemModel *model;
342 QPointer<QAbstractItemDelegate> itemDelegate;
343 QMap<int, QPointer<QAbstractItemDelegate> > rowDelegates;
344 QMap<int, QPointer<QAbstractItemDelegate> > columnDelegates;
345 QPointer<QItemSelectionModel> selectionModel;
346 QItemSelectionModel::SelectionFlag ctrlDragSelectionFlag;
347 bool noSelectionOnMousePress;
348
349 QAbstractItemView::SelectionMode selectionMode;
350 QAbstractItemView::SelectionBehavior selectionBehavior;
351
352 QEditorIndexHash editorIndexHash;
353 QIndexEditorHash indexEditorHash;
354 QSet<QWidget*> persistent;
355 QWidget *currentlyCommittingEditor;
356 QBasicTimer pressClosedEditorWatcher;
357 QPersistentModelIndex lastEditedIndex;
358 bool pressClosedEditor;
359 bool waitForIMCommit;
360
361 QPersistentModelIndex enteredIndex;
362 QPersistentModelIndex pressedIndex;
363 QPersistentModelIndex currentSelectionStartIndex;
364 Qt::KeyboardModifiers pressedModifiers;
365 QPoint pressedPosition;
366 QPoint draggedPosition;
367 bool pressedAlreadySelected;
368 bool releaseFromDoubleClick;
369
370 //forces the next mouseMoveEvent to send the viewportEntered signal
371 //if the mouse is over the viewport and not over an item
372 bool viewportEnteredNeeded;
373
374 QAbstractItemView::State state;
375 QAbstractItemView::State stateBeforeAnimation;
376 QAbstractItemView::EditTriggers editTriggers;
377 QAbstractItemView::EditTrigger lastTrigger;
378
379 QPersistentModelIndex root;
380 QPersistentModelIndex hover;
381
382 bool tabKeyNavigation;
383
384#if QT_CONFIG(draganddrop)
385 bool showDropIndicator;
386 QRect dropIndicatorRect;
387 bool dragEnabled;
388 QAbstractItemView::DragDropMode dragDropMode;
389 bool overwrite;
390 bool dropEventMoved;
391 QAbstractItemView::DropIndicatorPosition dropIndicatorPosition;
392 Qt::DropAction defaultDropAction;
393#endif
394
395 QString keyboardInput;
396 QElapsedTimer keyboardInputTime;
397 Qt::MatchFlags keyboardSearchFlags = Qt::MatchStartsWith | Qt::MatchWrap;
398
399 bool autoScroll;
400 QBasicTimer autoScrollTimer;
401 int autoScrollMargin;
402 int autoScrollCount;
403 bool shouldScrollToCurrentOnShow; //used to know if we should scroll to current on show event
404 bool shouldClearStatusTip; //if there is a statustip currently shown that need to be cleared when leaving.
405
406 bool alternatingColors;
407
408 QSize iconSize;
409 Qt::TextElideMode textElideMode;
410
411 QRegion updateRegion; // used for the internal update system
412 QPoint scrollDelayOffset;
413
414 QBasicTimer updateTimer;
415 QBasicTimer delayedEditing;
416 QBasicTimer delayedAutoScroll; //used when an item is clicked
417 QBasicTimer delayedReset;
418
419 QAbstractItemView::ScrollMode verticalScrollMode;
420 QAbstractItemView::ScrollMode horizontalScrollMode;
421
422#ifndef QT_NO_GESTURES
423 // the selection before the last mouse down. In case we have to restore it for scrolling
424 QItemSelection oldSelection;
425 QModelIndex oldCurrent;
426#endif
427
428 bool currentIndexSet;
429
430 bool wrapItemText;
431 mutable bool delayedPendingLayout;
432 bool moveCursorUpdatedView;
433
434 // Whether scroll mode has been explicitly set or its value come from SH_ItemView_ScrollMode
435 bool verticalScrollModeSet;
436 bool horizontalScrollModeSet;
437
438 int updateThreshold;
439
440 virtual QRect visualRect(const QModelIndex &index) const { return q_func()->visualRect(index); }
441
442 std::array<QMetaObject::Connection, 14> modelConnections;
443 std::array<QMetaObject::Connection, 4> scrollbarConnections;
444#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
445 QMetaObject::Connection scollerConnection;
446#endif
447
448private:
449 void connectDelegate(QAbstractItemDelegate *delegate);
450 void disconnectDelegate(QAbstractItemDelegate *delegate);
451 void disconnectAll();
452 inline QAbstractItemDelegate *delegateForIndex(const QModelIndex &index) const {
453 QMap<int, QPointer<QAbstractItemDelegate> >::ConstIterator it;
454
455 it = rowDelegates.find(index.row());
456 if (it != rowDelegates.end())
457 return it.value();
458
459 it = columnDelegates.find(index.column());
460 if (it != columnDelegates.end())
461 return it.value();
462
463 return itemDelegate;
464 }
465
466 mutable QBasicTimer delayedLayout;
467 mutable QBasicTimer fetchMoreTimer;
468};
469
470QT_BEGIN_INCLUDE_NAMESPACE
471#include <qlist.h>
472QT_END_INCLUDE_NAMESPACE
473
474template<typename T>
475inline int qBinarySearch(const QList<T> &vec, const T &item, int start, int end)
476{
477 int i = (start + end + 1) >> 1;
478 while (end - start > 0) {
479 if (vec.at(i) > item)
480 end = i - 1;
481 else
482 start = i;
483 i = (start + end + 1) >> 1;
484 }
485 return i;
486}
487
488QT_END_NAMESPACE
489
490#endif // QABSTRACTITEMVIEW_P_H
QT_REQUIRE_CONFIG(itemviews)
QHash< QPersistentModelIndex, QEditorInfo > QIndexEditorHash
QHash< QWidget *, QPersistentModelIndex > QEditorIndexHash
QList< QItemViewPaintPair > QItemViewPaintPairs