3826f3b4e937bf7a8d17d4fb84b5b183479bb2ea
[profile/ivi/qtbase.git] / src / widgets / itemviews / qabstractitemview_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QABSTRACTITEMVIEW_P_H
43 #define QABSTRACTITEMVIEW_P_H
44
45 //
46 //  W A R N I N G
47 //  -------------
48 //
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.
52 //
53 // We mean it.
54 //
55
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"
68
69 #ifndef QT_NO_ITEMVIEWS
70
71 QT_BEGIN_NAMESPACE
72
73 struct QEditorInfo {
74     QEditorInfo(QWidget *e, bool s): widget(QWeakPointer<QWidget>(e)), isStatic(s) {}
75     QEditorInfo(): isStatic(false) {}
76
77     QWeakPointer<QWidget> widget;
78     bool isStatic;
79 };
80
81 //  Fast associativity between Persistent editors and indices.
82 typedef QHash<QWidget *, QPersistentModelIndex> QEditorIndexHash;
83 typedef QHash<QPersistentModelIndex, QEditorInfo> QIndexEditorHash;
84
85 typedef QPair<QRect, QModelIndex> QItemViewPaintPair;
86 typedef QList<QItemViewPaintPair> QItemViewPaintPairs;
87
88 class QEmptyModel : public QAbstractItemModel
89 {
90 public:
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(); }
98 };
99
100 class Q_AUTOTEST_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate
101 {
102     Q_DECLARE_PUBLIC(QAbstractItemView)
103
104 public:
105     QAbstractItemViewPrivate();
106     virtual ~QAbstractItemViewPrivate();
107
108     void init();
109
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);
119
120     void _q_headerDataChanged() { doDelayedItemsLayout(); }
121     void _q_scrollerStateChanged();
122
123     void fetchMore();
124
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;
130
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());
135         autoScrollCount = 0;
136     }
137     void stopAutoScroll() { autoScrollTimer.stop(); autoScrollCount = 0;}
138
139 #ifndef QT_NO_DRAGANDDROP
140     virtual bool dropOn(QDropEvent *event, int *row, int *col, QModelIndex *index);
141 #endif
142     bool droppingOnItself(QDropEvent *event, const QModelIndex &index);
143
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);
148
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);
156
157     void setHoverIndex(const QPersistentModelIndex &index);
158
159     void checkMouseMove(const QPersistentModelIndex &index);
160     inline void checkMouseMove(const QPoint &pos) { checkMouseMove(q_func()->indexAt(pos)); }
161
162     inline QItemSelectionModel::SelectionFlags selectionBehaviorFlags() const
163     {
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;
168         }
169     }
170
171 #ifndef QT_NO_DRAGANDDROP
172     virtual QAbstractItemView::DropIndicatorPosition position(const QPoint &pos, const QRect &rect, const QModelIndex &idx) const;
173
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()))
180                 return true;
181         return false;
182     }
183
184     inline void paintDropIndicator(QPainter *painter)
185     {
186         if (showDropIndicator && state == QAbstractItemView::DraggingState
187 #ifndef QT_NO_CURSOR
188             && viewport->cursor().shape() != Qt::ForbiddenCursor
189 #endif
190             ) {
191             QStyleOption opt;
192             opt.init(q_func());
193             opt.rect = dropIndicatorRect;
194             q_func()->style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, painter, q_func());
195         }
196     }
197
198 #endif
199     virtual QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const;
200     // reimplemented in subclasses
201     virtual void adjustViewOptionsForIndex(QStyleOptionViewItemV4*, const QModelIndex&) const {}
202
203     inline void releaseEditor(QWidget *editor, const QModelIndex &index = QModelIndex()) const {
204         if (editor) {
205             QObject::disconnect(editor, SIGNAL(destroyed(QObject*)),
206                                 q_func(), SLOT(editorDestroyed(QObject*)));
207             editor->removeEventFilter(itemDelegate);
208             editor->hide();
209             QAbstractItemDelegate *delegate = delegateForIndex(index);
210
211             if (delegate)
212                 delegate->destroyEditor(editor, index);
213             else
214                 editor->deleteLater();
215         }
216     }
217
218     inline void executePostedLayout() const {
219         if (delayedPendingLayout && state != QAbstractItemView::CollapsingState) {
220             interruptDelayedItemsLayout();
221             const_cast<QAbstractItemView*>(q_func())->doItemsLayout();
222         }
223     }
224
225     inline void setDirtyRegion(const QRegion &visualRegion) {
226         updateRegion += visualRegion;
227         if (!updateTimer.isActive())
228             updateTimer.start(0, q_func());
229     }
230
231     inline void scrollDirtyRegion(int dx, int dy) {
232         scrollDelayOffset = QPoint(-dx, -dy);
233         updateDirtyRegion();
234         scrollDelayOffset = QPoint(0, 0);
235     }
236
237     inline void scrollContentsBy(int dx, int dy) {
238         scrollDirtyRegion(dx, dy);
239         viewport->scroll(dx, dy);
240     }
241
242     void updateDirtyRegion() {
243         updateTimer.stop();
244         viewport->update(updateRegion);
245         updateRegion = QRegion();
246     }
247
248     void clearOrRemove();
249     void checkPersistentEditorFocus();
250
251     QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r) const;
252
253     inline QPoint offset() const {
254         const Q_Q(QAbstractItemView);
255         return QPoint(q->isRightToLeft() ? -q->horizontalOffset()
256                       : q->horizontalOffset(), q->verticalOffset());
257     }
258
259     const QEditorInfo &editorForIndex(const QModelIndex &index) const;
260     inline bool hasEditor(const QModelIndex &index) const {
261         return indexEditorHash.find(index) != indexEditorHash.constEnd();
262     }
263
264     QModelIndex indexForEditor(QWidget *editor) const;
265     void addEditor(const QModelIndex &index, QWidget *editor, bool isStatic);
266     void removeEditor(QWidget *editor);
267
268     inline bool isAnimating() const {
269         return state == QAbstractItemView::AnimatingState;
270     }
271
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;
276         return itemDelegate;
277     }
278
279     inline bool isIndexValid(const QModelIndex &index) const {
280          return (index.row() >= 0) && (index.column() >= 0) && (index.model() == model);
281     }
282     inline bool isIndexSelectable(const QModelIndex &index) const {
283         return (model->flags(index) & Qt::ItemIsSelectable);
284     }
285     inline bool isIndexEnabled(const QModelIndex &index) const {
286         return (model->flags(index) & Qt::ItemIsEnabled);
287     }
288     inline bool isIndexDropEnabled(const QModelIndex &index) const {
289         return (model->flags(index) & Qt::ItemIsDropEnabled);
290     }
291     inline bool isIndexDragEnabled(const QModelIndex &index) const {
292         return (model->flags(index) & Qt::ItemIsDragEnabled);
293     }
294
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);
298     }
299
300     // reimplemented from QAbstractScrollAreaPrivate
301     virtual QPoint contentsOffset() const {
302         Q_Q(const QAbstractItemView);
303         return QPoint(q->horizontalOffset(), q->verticalOffset());
304     }
305
306     /**
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.
309      */
310     int delegateRefCount(const QAbstractItemDelegate *delegate) const
311     {
312         int ref = 0;
313         if (itemDelegate == delegate)
314             ++ref;
315
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) {
321                         ++ref;
322                         // optimization, we are only interested in the ref count values 0, 1 or >=2
323                         if (ref >= 2) {
324                             return ref;
325                         }
326                     }
327             }
328         }
329         return ref;
330     }
331
332     /**
333      * return true if the index is registered as a QPersistentModelIndex
334      */
335     inline bool isPersistent(const QModelIndex &index) const
336     {
337         return static_cast<QAbstractItemModelPrivate *>(model->d_ptr.data())->persistent.indexes.contains(index);
338     }
339
340     QModelIndexList selectedDraggableIndexes() const;
341
342     QStyleOptionViewItemV4 viewOptionsV4() const;
343
344     void doDelayedReset()
345     {
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());
351     }
352
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;
360
361     QAbstractItemView::SelectionMode selectionMode;
362     QAbstractItemView::SelectionBehavior selectionBehavior;
363
364     QEditorIndexHash editorIndexHash;
365     QIndexEditorHash indexEditorHash;
366     QSet<QWidget*> persistent;
367     QWidget *currentlyCommittingEditor;
368
369     QPersistentModelIndex enteredIndex;
370     QPersistentModelIndex pressedIndex;
371     Qt::KeyboardModifiers pressedModifiers;
372     QPoint pressedPosition;
373     bool pressedAlreadySelected;
374
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;
378
379     QAbstractItemView::State state;
380     QAbstractItemView::State stateBeforeAnimation;
381     QAbstractItemView::EditTriggers editTriggers;
382     QAbstractItemView::EditTrigger lastTrigger;
383
384     QPersistentModelIndex root;
385     QPersistentModelIndex hover;
386
387     bool tabKeyNavigation;
388
389 #ifndef QT_NO_DRAGANDDROP
390     bool showDropIndicator;
391     QRect dropIndicatorRect;
392     bool dragEnabled;
393     QAbstractItemView::DragDropMode dragDropMode;
394     bool overwrite;
395     QAbstractItemView::DropIndicatorPosition dropIndicatorPosition;
396     Qt::DropAction defaultDropAction;
397 #endif
398
399 #ifdef QT_SOFTKEYS_ENABLED
400     QAction *doneSoftKey;
401 #endif
402
403     QString keyboardInput;
404     QElapsedTimer keyboardInputTime;
405
406     bool autoScroll;
407     QBasicTimer autoScrollTimer;
408     int autoScrollMargin;
409     int autoScrollCount;
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.
412
413     bool alternatingColors;
414
415     QSize iconSize;
416     Qt::TextElideMode textElideMode;
417
418     QRegion updateRegion; // used for the internal update system
419     QPoint scrollDelayOffset;
420
421     QBasicTimer updateTimer;
422     QBasicTimer delayedEditing;
423     QBasicTimer delayedAutoScroll; //used when an item is clicked
424     QBasicTimer delayedReset;
425
426     QAbstractItemView::ScrollMode verticalScrollMode;
427     QAbstractItemView::ScrollMode horizontalScrollMode;
428
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;
433 #endif
434
435     bool currentIndexSet;
436
437     bool wrapItemText;
438     mutable bool delayedPendingLayout;
439     bool moveCursorUpdatedView;
440
441 private:
442     mutable QBasicTimer delayedLayout;
443     mutable QBasicTimer fetchMoreTimer;
444 };
445
446 QT_BEGIN_INCLUDE_NAMESPACE
447 #include <qvector.h>
448 QT_END_INCLUDE_NAMESPACE
449
450 template <typename T>
451 inline int qBinarySearch(const QVector<T> &vec, const T &item, int start, int end)
452 {
453     int i = (start + end + 1) >> 1;
454     while (end - start > 0) {
455         if (vec.at(i) > item)
456             end = i - 1;
457         else
458             start = i;
459         i = (start + end + 1) >> 1;
460     }
461     return i;
462 }
463
464 QT_END_NAMESPACE
465
466 #endif // QT_NO_ITEMVIEWS
467
468 #endif // QABSTRACTITEMVIEW_P_H