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#ifndef QABSTRACTITEMVIEW_P_H
5#define QABSTRACTITEMVIEW_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtWidgets/private/qtwidgetsglobal_p.h>
19#include "qabstractitemview.h"
20#include "private/qabstractscrollarea_p.h"
21#include "private/qabstractitemmodel_p.h"
22#include "QtWidgets/qapplication.h"
23#include "QtGui/qevent.h"
24#include "QtCore/qmimedata.h"
25#include "QtGui/qpainter.h"
26#include "QtGui/qregion.h"
27
28#include "QtCore/qdebug.h"
29#include "QtCore/qbasictimer.h"
30#include "QtCore/qelapsedtimer.h"
31#include <QtCore/qpointer.h>
32
33
34#include <array>
35
36QT_REQUIRE_CONFIG(itemviews);
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.
49typedef QHash<QWidget *, QPersistentModelIndex> QEditorIndexHash;
50typedef QHash<QPersistentModelIndex, QEditorInfo> QIndexEditorHash;
51
52struct QItemViewPaintPair {
53 QRect rect;
54 QModelIndex index;
55};
56template <>
57class QTypeInfo<QItemViewPaintPair> : public QTypeInfoMerger<QItemViewPaintPair, QRect, QModelIndex> {};
58
59typedef QList<QItemViewPaintPair> QItemViewPaintPairs;
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(msec: scrollInterval, obj: 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(index: q_func()->indexAt(point: 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(mimetype: modelType))
149 return true;
150 }
151 }
152
153 QModelIndex index;
154 int col = -1;
155 int row = -1;
156 if (dropOn(event, row: &row, col: &col, index: &index)) {
157 return model->canDropMimeData(data: mime,
158 action: dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(),
159 row, column: col, parent: 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(w: q_func());
174 opt.rect = dropIndicatorRect;
175 q_func()->style()->drawPrimitive(pe: QStyle::PE_IndicatorItemViewItemDrop, opt: &opt, p: painter, w: 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(sender: editor, signal: &QWidget::destroyed,
188 receiver: q, slot: &QAbstractItemView::editorDestroyed);
189 editor->removeEventFilter(obj: 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(msec: 0, obj: 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(key: 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(msec: 0, obj: 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 bool pressedAlreadySelected;
356 bool releaseFromDoubleClick;
357
358 //forces the next mouseMoveEvent to send the viewportEntered signal
359 //if the mouse is over the viewport and not over an item
360 bool viewportEnteredNeeded;
361
362 QAbstractItemView::State state;
363 QAbstractItemView::State stateBeforeAnimation;
364 QAbstractItemView::EditTriggers editTriggers;
365 QAbstractItemView::EditTrigger lastTrigger;
366
367 QPersistentModelIndex root;
368 QPersistentModelIndex hover;
369
370 bool tabKeyNavigation;
371
372#if QT_CONFIG(draganddrop)
373 bool showDropIndicator;
374 QRect dropIndicatorRect;
375 bool dragEnabled;
376 QAbstractItemView::DragDropMode dragDropMode;
377 bool overwrite;
378 bool dropEventMoved;
379 QAbstractItemView::DropIndicatorPosition dropIndicatorPosition;
380 Qt::DropAction defaultDropAction;
381#endif
382
383 QString keyboardInput;
384 QElapsedTimer keyboardInputTime;
385
386 bool autoScroll;
387 QBasicTimer autoScrollTimer;
388 int autoScrollMargin;
389 int autoScrollCount;
390 bool shouldScrollToCurrentOnShow; //used to know if we should scroll to current on show event
391 bool shouldClearStatusTip; //if there is a statustip currently shown that need to be cleared when leaving.
392
393 bool alternatingColors;
394
395 QSize iconSize;
396 Qt::TextElideMode textElideMode;
397
398 QRegion updateRegion; // used for the internal update system
399 QPoint scrollDelayOffset;
400
401 QBasicTimer updateTimer;
402 QBasicTimer delayedEditing;
403 QBasicTimer delayedAutoScroll; //used when an item is clicked
404 QBasicTimer delayedReset;
405
406 QAbstractItemView::ScrollMode verticalScrollMode;
407 QAbstractItemView::ScrollMode horizontalScrollMode;
408
409#ifndef QT_NO_GESTURES
410 // the selection before the last mouse down. In case we have to restore it for scrolling
411 QItemSelection oldSelection;
412 QModelIndex oldCurrent;
413#endif
414
415 bool currentIndexSet;
416
417 bool wrapItemText;
418 mutable bool delayedPendingLayout;
419 bool moveCursorUpdatedView;
420
421 // Whether scroll mode has been explicitly set or its value come from SH_ItemView_ScrollMode
422 bool verticalScrollModeSet;
423 bool horizontalScrollModeSet;
424
425 virtual QRect visualRect(const QModelIndex &index) const { return q_func()->visualRect(index); }
426
427 std::array<QMetaObject::Connection, 14> modelConnections;
428 std::array<QMetaObject::Connection, 4> scrollbarConnections;
429#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
430 QMetaObject::Connection scollerConnection;
431#endif
432
433private:
434 void connectDelegate(QAbstractItemDelegate *delegate);
435 void disconnectDelegate(QAbstractItemDelegate *delegate);
436 void disconnectAll();
437 inline QAbstractItemDelegate *delegateForIndex(const QModelIndex &index) const {
438 QMap<int, QPointer<QAbstractItemDelegate> >::ConstIterator it;
439
440 it = rowDelegates.find(key: index.row());
441 if (it != rowDelegates.end())
442 return it.value();
443
444 it = columnDelegates.find(key: index.column());
445 if (it != columnDelegates.end())
446 return it.value();
447
448 return itemDelegate;
449 }
450
451 mutable QBasicTimer delayedLayout;
452 mutable QBasicTimer fetchMoreTimer;
453};
454
455QT_BEGIN_INCLUDE_NAMESPACE
456#include <qlist.h>
457QT_END_INCLUDE_NAMESPACE
458
459template<typename T>
460inline int qBinarySearch(const QList<T> &vec, const T &item, int start, int end)
461{
462 int i = (start + end + 1) >> 1;
463 while (end - start > 0) {
464 if (vec.at(i) > item)
465 end = i - 1;
466 else
467 start = i;
468 i = (start + end + 1) >> 1;
469 }
470 return i;
471}
472
473QT_END_NAMESPACE
474
475#endif // QABSTRACTITEMVIEW_P_H
476

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/widgets/itemviews/qabstractitemview_p.h