1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef QABSTRACTITEMVIEW_P_H
43 #define QABSTRACTITEMVIEW_P_H
49 // This file is not part of the Qt API. It exists purely as an
50 // implementation detail. This header file may change from version to
51 // version without notice, or even be removed.
56 #include "private/qabstractscrollarea_p.h"
57 #include "private/qabstractitemmodel_p.h"
58 #include "QtWidgets/qapplication.h"
59 #include "QtGui/qevent.h"
60 #include "QtCore/qmimedata.h"
61 #include "QtGui/qpainter.h"
62 #include "QtCore/qpair.h"
63 #include "QtGui/qregion.h"
64 #include "QtCore/qdebug.h"
65 #include "QtGui/qpainter.h"
66 #include "QtCore/qbasictimer.h"
67 #include "QtCore/qelapsedtimer.h"
69 #ifndef QT_NO_ITEMVIEWS
74 QEditorInfo(QWidget *e, bool s): widget(QWeakPointer<QWidget>(e)), isStatic(s) {}
75 QEditorInfo(): isStatic(false) {}
77 QWeakPointer<QWidget> widget;
81 // Fast associativity between Persistent editors and indices.
82 typedef QHash<QWidget *, QPersistentModelIndex> QEditorIndexHash;
83 typedef QHash<QPersistentModelIndex, QEditorInfo> QIndexEditorHash;
85 typedef QPair<QRect, QModelIndex> QItemViewPaintPair;
86 typedef QList<QItemViewPaintPair> QItemViewPaintPairs;
88 class QEmptyModel : public QAbstractItemModel
91 explicit QEmptyModel(QObject *parent = 0) : QAbstractItemModel(parent) {}
92 QModelIndex index(int, int, const QModelIndex &) const { return QModelIndex(); }
93 QModelIndex parent(const QModelIndex &) const { return QModelIndex(); }
94 int rowCount(const QModelIndex &) const { return 0; }
95 int columnCount(const QModelIndex &) const { return 0; }
96 bool hasChildren(const QModelIndex &) const { return false; }
97 QVariant data(const QModelIndex &, int) const { return QVariant(); }
100 class Q_AUTOTEST_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate
102 Q_DECLARE_PUBLIC(QAbstractItemView)
105 QAbstractItemViewPrivate();
106 virtual ~QAbstractItemViewPrivate();
110 virtual void _q_rowsRemoved(const QModelIndex &parent, int start, int end);
111 virtual void _q_rowsInserted(const QModelIndex &parent, int start, int end);
112 virtual void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
113 virtual void _q_columnsRemoved(const QModelIndex &parent, int start, int end);
114 virtual void _q_columnsInserted(const QModelIndex &parent, int start, int end);
115 virtual void _q_modelDestroyed();
116 virtual void _q_layoutChanged();
117 virtual void _q_rowsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart);
118 virtual void _q_columnsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart);
120 void _q_headerDataChanged() { doDelayedItemsLayout(); }
121 void _q_scrollerStateChanged();
125 bool shouldEdit(QAbstractItemView::EditTrigger trigger, const QModelIndex &index) const;
126 bool shouldForwardEvent(QAbstractItemView::EditTrigger trigger, const QEvent *event) const;
127 bool shouldAutoScroll(const QPoint &pos) const;
128 void doDelayedItemsLayout(int delay = 0);
129 void interruptDelayedItemsLayout() const;
131 void startAutoScroll()
132 { // ### it would be nice to make this into a style hint one day
133 int scrollInterval = (verticalScrollMode == QAbstractItemView::ScrollPerItem) ? 150 : 50;
134 autoScrollTimer.start(scrollInterval, q_func());
137 void stopAutoScroll() { autoScrollTimer.stop(); autoScrollCount = 0;}
139 #ifndef QT_NO_DRAGANDDROP
140 virtual bool dropOn(QDropEvent *event, int *row, int *col, QModelIndex *index);
142 bool droppingOnItself(QDropEvent *event, const QModelIndex &index);
144 QWidget *editor(const QModelIndex &index, const QStyleOptionViewItem &options);
145 bool sendDelegateEvent(const QModelIndex &index, QEvent *event) const;
146 bool openEditor(const QModelIndex &index, QEvent *event);
147 void updateEditorData(const QModelIndex &topLeft, const QModelIndex &bottomRight);
149 QItemSelectionModel::SelectionFlags multiSelectionCommand(const QModelIndex &index,
150 const QEvent *event) const;
151 QItemSelectionModel::SelectionFlags extendedSelectionCommand(const QModelIndex &index,
152 const QEvent *event) const;
153 QItemSelectionModel::SelectionFlags contiguousSelectionCommand(const QModelIndex &index,
154 const QEvent *event) const;
155 virtual void selectAll(QItemSelectionModel::SelectionFlags command);
157 void setHoverIndex(const QPersistentModelIndex &index);
159 void checkMouseMove(const QPersistentModelIndex &index);
160 inline void checkMouseMove(const QPoint &pos) { checkMouseMove(q_func()->indexAt(pos)); }
162 inline QItemSelectionModel::SelectionFlags selectionBehaviorFlags() const
164 switch (selectionBehavior) {
165 case QAbstractItemView::SelectRows: return QItemSelectionModel::Rows;
166 case QAbstractItemView::SelectColumns: return QItemSelectionModel::Columns;
167 case QAbstractItemView::SelectItems: default: return QItemSelectionModel::NoUpdate;
171 #ifndef QT_NO_DRAGANDDROP
172 virtual QAbstractItemView::DropIndicatorPosition position(const QPoint &pos, const QRect &rect, const QModelIndex &idx) const;
174 inline bool canDecode(QDropEvent *e) const {
175 QStringList modelTypes = model->mimeTypes();
176 const QMimeData *mime = e->mimeData();
177 for (int i = 0; i < modelTypes.count(); ++i)
178 if (mime->hasFormat(modelTypes.at(i))
179 && (e->dropAction() & model->supportedDropActions()))
184 inline void paintDropIndicator(QPainter *painter)
186 if (showDropIndicator && state == QAbstractItemView::DraggingState
188 && viewport->cursor().shape() != Qt::ForbiddenCursor
193 opt.rect = dropIndicatorRect;
194 q_func()->style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, painter, q_func());
199 virtual QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const;
200 // reimplemented in subclasses
201 virtual void adjustViewOptionsForIndex(QStyleOptionViewItemV4*, const QModelIndex&) const {}
203 inline void releaseEditor(QWidget *editor, const QModelIndex &index = QModelIndex()) const {
205 QObject::disconnect(editor, SIGNAL(destroyed(QObject*)),
206 q_func(), SLOT(editorDestroyed(QObject*)));
207 editor->removeEventFilter(itemDelegate);
209 QAbstractItemDelegate *delegate = delegateForIndex(index);
212 delegate->destroyEditor(editor, index);
214 editor->deleteLater();
218 inline void executePostedLayout() const {
219 if (delayedPendingLayout && state != QAbstractItemView::CollapsingState) {
220 interruptDelayedItemsLayout();
221 const_cast<QAbstractItemView*>(q_func())->doItemsLayout();
225 inline void setDirtyRegion(const QRegion &visualRegion) {
226 updateRegion += visualRegion;
227 if (!updateTimer.isActive())
228 updateTimer.start(0, q_func());
231 inline void scrollDirtyRegion(int dx, int dy) {
232 scrollDelayOffset = QPoint(-dx, -dy);
234 scrollDelayOffset = QPoint(0, 0);
237 inline void scrollContentsBy(int dx, int dy) {
238 scrollDirtyRegion(dx, dy);
239 viewport->scroll(dx, dy);
242 void updateDirtyRegion() {
244 viewport->update(updateRegion);
245 updateRegion = QRegion();
248 void clearOrRemove();
249 void checkPersistentEditorFocus();
251 QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r) const;
253 inline QPoint offset() const {
254 const Q_Q(QAbstractItemView);
255 return QPoint(q->isRightToLeft() ? -q->horizontalOffset()
256 : q->horizontalOffset(), q->verticalOffset());
259 const QEditorInfo &editorForIndex(const QModelIndex &index) const;
260 inline bool hasEditor(const QModelIndex &index) const {
261 return indexEditorHash.find(index) != indexEditorHash.constEnd();
264 QModelIndex indexForEditor(QWidget *editor) const;
265 void addEditor(const QModelIndex &index, QWidget *editor, bool isStatic);
266 void removeEditor(QWidget *editor);
268 inline bool isAnimating() const {
269 return state == QAbstractItemView::AnimatingState;
272 inline QAbstractItemDelegate *delegateForIndex(const QModelIndex &index) const {
273 QAbstractItemDelegate *del;
274 if ((del = rowDelegates.value(index.row(), 0))) return del;
275 if ((del = columnDelegates.value(index.column(), 0))) return del;
279 inline bool isIndexValid(const QModelIndex &index) const {
280 return (index.row() >= 0) && (index.column() >= 0) && (index.model() == model);
282 inline bool isIndexSelectable(const QModelIndex &index) const {
283 return (model->flags(index) & Qt::ItemIsSelectable);
285 inline bool isIndexEnabled(const QModelIndex &index) const {
286 return (model->flags(index) & Qt::ItemIsEnabled);
288 inline bool isIndexDropEnabled(const QModelIndex &index) const {
289 return (model->flags(index) & Qt::ItemIsDropEnabled);
291 inline bool isIndexDragEnabled(const QModelIndex &index) const {
292 return (model->flags(index) & Qt::ItemIsDragEnabled);
295 virtual bool selectionAllowed(const QModelIndex &index) const {
296 // in some views we want to go ahead with selections, even if the index is invalid
297 return isIndexValid(index) && isIndexSelectable(index);
300 // reimplemented from QAbstractScrollAreaPrivate
301 virtual QPoint contentsOffset() const {
302 Q_Q(const QAbstractItemView);
303 return QPoint(q->horizontalOffset(), q->verticalOffset());
307 * For now, assume that we have few editors, if we need a more efficient implementation
308 * we should add a QMap<QAbstractItemDelegate*, int> member.
310 int delegateRefCount(const QAbstractItemDelegate *delegate) const
313 if (itemDelegate == delegate)
316 for (int maps = 0; maps < 2; ++maps) {
317 const QMap<int, QPointer<QAbstractItemDelegate> > *delegates = maps ? &columnDelegates : &rowDelegates;
318 for (QMap<int, QPointer<QAbstractItemDelegate> >::const_iterator it = delegates->begin();
319 it != delegates->end(); ++it) {
320 if (it.value() == delegate) {
322 // optimization, we are only interested in the ref count values 0, 1 or >=2
333 * return true if the index is registered as a QPersistentModelIndex
335 inline bool isPersistent(const QModelIndex &index) const
337 return static_cast<QAbstractItemModelPrivate *>(model->d_ptr.data())->persistent.indexes.contains(index);
340 QModelIndexList selectedDraggableIndexes() const;
342 QStyleOptionViewItemV4 viewOptionsV4() const;
344 void doDelayedReset()
346 //we delay the reset of the timer because some views (QTableView)
347 //with headers can't handle the fact that the model has been destroyed
348 //all _q_modelDestroyed slots must have been called
349 if (!delayedReset.isActive())
350 delayedReset.start(0, q_func());
353 QAbstractItemModel *model;
354 QPointer<QAbstractItemDelegate> itemDelegate;
355 QMap<int, QPointer<QAbstractItemDelegate> > rowDelegates;
356 QMap<int, QPointer<QAbstractItemDelegate> > columnDelegates;
357 QPointer<QItemSelectionModel> selectionModel;
358 QItemSelectionModel::SelectionFlag ctrlDragSelectionFlag;
359 bool noSelectionOnMousePress;
361 QAbstractItemView::SelectionMode selectionMode;
362 QAbstractItemView::SelectionBehavior selectionBehavior;
364 QEditorIndexHash editorIndexHash;
365 QIndexEditorHash indexEditorHash;
366 QSet<QWidget*> persistent;
367 QWidget *currentlyCommittingEditor;
369 QPersistentModelIndex enteredIndex;
370 QPersistentModelIndex pressedIndex;
371 Qt::KeyboardModifiers pressedModifiers;
372 QPoint pressedPosition;
373 bool pressedAlreadySelected;
375 //forces the next mouseMoveEvent to send the viewportEntered signal
376 //if the mouse is over the viewport and not over an item
377 bool viewportEnteredNeeded;
379 QAbstractItemView::State state;
380 QAbstractItemView::State stateBeforeAnimation;
381 QAbstractItemView::EditTriggers editTriggers;
382 QAbstractItemView::EditTrigger lastTrigger;
384 QPersistentModelIndex root;
385 QPersistentModelIndex hover;
387 bool tabKeyNavigation;
389 #ifndef QT_NO_DRAGANDDROP
390 bool showDropIndicator;
391 QRect dropIndicatorRect;
393 QAbstractItemView::DragDropMode dragDropMode;
395 QAbstractItemView::DropIndicatorPosition dropIndicatorPosition;
396 Qt::DropAction defaultDropAction;
399 #ifdef QT_SOFTKEYS_ENABLED
400 QAction *doneSoftKey;
403 QString keyboardInput;
404 QElapsedTimer keyboardInputTime;
407 QBasicTimer autoScrollTimer;
408 int autoScrollMargin;
410 bool shouldScrollToCurrentOnShow; //used to know if we should scroll to current on show event
411 bool shouldClearStatusTip; //if there is a statustip currently shown that need to be cleared when leaving.
413 bool alternatingColors;
416 Qt::TextElideMode textElideMode;
418 QRegion updateRegion; // used for the internal update system
419 QPoint scrollDelayOffset;
421 QBasicTimer updateTimer;
422 QBasicTimer delayedEditing;
423 QBasicTimer delayedAutoScroll; //used when an item is clicked
424 QBasicTimer delayedReset;
426 QAbstractItemView::ScrollMode verticalScrollMode;
427 QAbstractItemView::ScrollMode horizontalScrollMode;
429 #ifndef QT_NO_GESTURES
430 // the selection before the last mouse down. In case we have to restore it for scrolling
431 QItemSelection oldSelection;
432 QModelIndex oldCurrent;
435 bool currentIndexSet;
438 mutable bool delayedPendingLayout;
439 bool moveCursorUpdatedView;
442 mutable QBasicTimer delayedLayout;
443 mutable QBasicTimer fetchMoreTimer;
446 QT_BEGIN_INCLUDE_NAMESPACE
448 QT_END_INCLUDE_NAMESPACE
450 template <typename T>
451 inline int qBinarySearch(const QVector<T> &vec, const T &item, int start, int end)
453 int i = (start + end + 1) >> 1;
454 while (end - start > 0) {
455 if (vec.at(i) > item)
459 i = (start + end + 1) >> 1;
466 #endif // QT_NO_ITEMVIEWS
468 #endif // QABSTRACTITEMVIEW_P_H