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 // reimplemented from QAbstractScrollAreaPrivate
276 QPoint contentsOffset() const override {
277 Q_Q(const QAbstractItemView);
278 return QPoint(q->horizontalOffset(), q->verticalOffset());
279 }
280
281 /**
282 * For now, assume that we have few editors, if we need a more efficient implementation
283 * we should add a QMap<QAbstractItemDelegate*, int> member.
284 */
285 int delegateRefCount(const QAbstractItemDelegate *delegate) const
286 {
287 int ref = 0;
288 if (itemDelegate == delegate)
289 ++ref;
290
291 for (int maps = 0; maps < 2; ++maps) {
292 const QMap<int, QPointer<QAbstractItemDelegate> > *delegates = maps ? &columnDelegates : &rowDelegates;
293 for (QMap<int, QPointer<QAbstractItemDelegate> >::const_iterator it = delegates->begin();
294 it != delegates->end(); ++it) {
295 if (it.value() == delegate) {
296 ++ref;
297 // optimization, we are only interested in the ref count values 0, 1 or >=2
298 if (ref >= 2) {
299 return ref;
300 }
301 }
302 }
303 }
304 return ref;
305 }
306
307 /**
308 * return true if the index is registered as a QPersistentModelIndex
309 */
310 inline bool isPersistent(const QModelIndex &index) const
311 {
312 return static_cast<QAbstractItemModelPrivate *>(model->d_ptr.data())->persistent.indexes.contains(index);
313 }
314
315#if QT_CONFIG(draganddrop)
316 QModelIndexList selectedDraggableIndexes() const;
317 void maybeStartDrag(QPoint eventPoint);
318#endif
319
320 void doDelayedReset()
321 {
322 //we delay the reset of the timer because some views (QTableView)
323 //with headers can't handle the fact that the model has been destroyed
324 //all modelDestroyed() slots must have been called
325 if (!delayedReset.isActive())
326 delayedReset.start(0, q_func());
327 }
328
329 QAbstractItemModel *model;
330 QPointer<QAbstractItemDelegate> itemDelegate;
331 QMap<int, QPointer<QAbstractItemDelegate> > rowDelegates;
332 QMap<int, QPointer<QAbstractItemDelegate> > columnDelegates;
333 QPointer<QItemSelectionModel> selectionModel;
334 QItemSelectionModel::SelectionFlag ctrlDragSelectionFlag;
335 bool noSelectionOnMousePress;
336
337 QAbstractItemView::SelectionMode selectionMode;
338 QAbstractItemView::SelectionBehavior selectionBehavior;
339
340 QEditorIndexHash editorIndexHash;
341 QIndexEditorHash indexEditorHash;
342 QSet<QWidget*> persistent;
343 QWidget *currentlyCommittingEditor;
344 QBasicTimer pressClosedEditorWatcher;
345 QPersistentModelIndex lastEditedIndex;
346 bool pressClosedEditor;
347 bool waitForIMCommit;
348
349 QPersistentModelIndex enteredIndex;
350 QPersistentModelIndex pressedIndex;
351 QPersistentModelIndex currentSelectionStartIndex;
352 Qt::KeyboardModifiers pressedModifiers;
353 QPoint pressedPosition;
354 QPoint draggedPosition;
355 QPoint draggedPositionOffset;
356 bool pressedAlreadySelected;
357 bool releaseFromDoubleClick;
358
359 //forces the next mouseMoveEvent to send the viewportEntered signal
360 //if the mouse is over the viewport and not over an item
361 bool viewportEnteredNeeded;
362
363 QAbstractItemView::State state;
364 QAbstractItemView::State stateBeforeAnimation;
365 QAbstractItemView::EditTriggers editTriggers;
366 QAbstractItemView::EditTrigger lastTrigger;
367
368 QPersistentModelIndex root;
369 QPersistentModelIndex hover;
370
371 bool tabKeyNavigation;
372
373#if QT_CONFIG(draganddrop)
374 bool showDropIndicator;
375 QRect dropIndicatorRect;
376 bool dragEnabled;
377 QAbstractItemView::DragDropMode dragDropMode;
378 bool overwrite;
379 bool dropEventMoved;
380 QAbstractItemView::DropIndicatorPosition dropIndicatorPosition;
381 Qt::DropAction defaultDropAction;
382#endif
383
384 QString keyboardInput;
385 QElapsedTimer keyboardInputTime;
386 Qt::MatchFlags keyboardSearchFlags = Qt::MatchStartsWith | Qt::MatchWrap;
387
388 bool autoScroll;
389 QBasicTimer autoScrollTimer;
390 int autoScrollMargin;
391 int autoScrollCount;
392 bool shouldScrollToCurrentOnShow; //used to know if we should scroll to current on show event
393 bool shouldClearStatusTip; //if there is a statustip currently shown that need to be cleared when leaving.
394
395 bool alternatingColors;
396
397 QSize iconSize;
398 Qt::TextElideMode textElideMode;
399
400 QRegion updateRegion; // used for the internal update system
401 QPoint scrollDelayOffset;
402
403 QBasicTimer updateTimer;
404 QBasicTimer delayedEditing;
405 QBasicTimer delayedAutoScroll; //used when an item is clicked
406 QBasicTimer delayedReset;
407
408 QAbstractItemView::ScrollMode verticalScrollMode;
409 QAbstractItemView::ScrollMode horizontalScrollMode;
410
411#ifndef QT_NO_GESTURES
412 // the selection before the last mouse down. In case we have to restore it for scrolling
413 QItemSelection oldSelection;
414 QModelIndex oldCurrent;
415#endif
416
417 bool currentIndexSet;
418
419 bool wrapItemText;
420 mutable bool delayedPendingLayout;
421 bool moveCursorUpdatedView;
422
423 // Whether scroll mode has been explicitly set or its value come from SH_ItemView_ScrollMode
424 bool verticalScrollModeSet;
425 bool horizontalScrollModeSet;
426
427 int updateThreshold;
428
429 virtual QRect visualRect(const QModelIndex &index) const { return q_func()->visualRect(index); }
430
431 std::array<QMetaObject::Connection, 14> modelConnections;
432 std::array<QMetaObject::Connection, 4> scrollbarConnections;
433#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
434 QMetaObject::Connection scollerConnection;
435#endif
436
437private:
438 void connectDelegate(QAbstractItemDelegate *delegate);
439 void disconnectDelegate(QAbstractItemDelegate *delegate);
440 void disconnectAll();
441 inline QAbstractItemDelegate *delegateForIndex(const QModelIndex &index) const {
442 QMap<int, QPointer<QAbstractItemDelegate> >::ConstIterator it;
443
444 it = rowDelegates.find(index.row());
445 if (it != rowDelegates.end())
446 return it.value();
447
448 it = columnDelegates.find(index.column());
449 if (it != columnDelegates.end())
450 return it.value();
451
452 return itemDelegate;
453 }
454
455 mutable QBasicTimer delayedLayout;
456 mutable QBasicTimer fetchMoreTimer;
457};
458
459QT_BEGIN_INCLUDE_NAMESPACE
460#include <qlist.h>
461QT_END_INCLUDE_NAMESPACE
462
463template<typename T>
464inline int qBinarySearch(const QList<T> &vec, const T &item, int start, int end)
465{
466 int i = (start + end + 1) >> 1;
467 while (end - start > 0) {
468 if (vec.at(i) > item)
469 end = i - 1;
470 else
471 start = i;
472 i = (start + end + 1) >> 1;
473 }
474 return i;
475}
476
477QT_END_NAMESPACE
478
479#endif // QABSTRACTITEMVIEW_P_H
QT_REQUIRE_CONFIG(itemviews)
QHash< QPersistentModelIndex, QEditorInfo > QIndexEditorHash
QHash< QWidget *, QPersistentModelIndex > QEditorIndexHash
QList< QItemViewPaintPair > QItemViewPaintPairs