1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qabstractitemview.h"
43 
44 #ifndef QT_NO_ITEMVIEWS
45 #include <qpointer.h>
46 #include <qapplication.h>
47 #include <qclipboard.h>
48 #include <qpainter.h>
49 #include <qstyle.h>
50 #include <qdrag.h>
51 #include <qevent.h>
52 #include <qscrollbar.h>
53 #include <qwhatsthis.h>
54 #include <qtooltip.h>
55 #include <qdatetime.h>
56 #include <qlineedit.h>
57 #include <qspinbox.h>
58 #include <qstyleditemdelegate.h>
59 #include <private/qabstractitemview_p.h>
60 #include <private/qabstractitemmodel_p.h>
61 #ifndef QT_NO_ACCESSIBILITY
62 #include <qaccessible.h>
63 #include <qaccessible2.h>
64 #endif
65 #include <private/qsoftkeymanager_p.h>
66 
67 QT_BEGIN_NAMESPACE
68 
QAbstractItemViewPrivate()69 QAbstractItemViewPrivate::QAbstractItemViewPrivate()
70     :   model(QAbstractItemModelPrivate::staticEmptyModel()),
71         itemDelegate(0),
72         selectionModel(0),
73         ctrlDragSelectionFlag(QItemSelectionModel::NoUpdate),
74         noSelectionOnMousePress(false),
75         selectionMode(QAbstractItemView::ExtendedSelection),
76         selectionBehavior(QAbstractItemView::SelectItems),
77         currentlyCommittingEditor(0),
78         pressedModifiers(Qt::NoModifier),
79         pressedPosition(QPoint(-1, -1)),
80         pressedAlreadySelected(false),
81         viewportEnteredNeeded(false),
82         state(QAbstractItemView::NoState),
83         stateBeforeAnimation(QAbstractItemView::NoState),
84         editTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed),
85         lastTrigger(QAbstractItemView::NoEditTriggers),
86         tabKeyNavigation(false),
87 #ifndef QT_NO_DRAGANDDROP
88         showDropIndicator(true),
89         dragEnabled(false),
90         dragDropMode(QAbstractItemView::NoDragDrop),
91         overwrite(false),
92         dropIndicatorPosition(QAbstractItemView::OnItem),
93         defaultDropAction(Qt::IgnoreAction),
94 #endif
95 #ifdef QT_SOFTKEYS_ENABLED
96         doneSoftKey(0),
97 #endif
98         autoScroll(true),
99         autoScrollMargin(16),
100         autoScrollCount(0),
101         shouldScrollToCurrentOnShow(false),
102         shouldClearStatusTip(false),
103         alternatingColors(false),
104         textElideMode(Qt::ElideRight),
105         verticalScrollMode(QAbstractItemView::ScrollPerItem),
106         horizontalScrollMode(QAbstractItemView::ScrollPerItem),
107         currentIndexSet(false),
108         wrapItemText(false),
109         delayedPendingLayout(true),
110         moveCursorUpdatedView(false)
111 {
112     keyboardInputTime.invalidate();
113 }
114 
~QAbstractItemViewPrivate()115 QAbstractItemViewPrivate::~QAbstractItemViewPrivate()
116 {
117 }
118 
init()119 void QAbstractItemViewPrivate::init()
120 {
121     Q_Q(QAbstractItemView);
122     q->setItemDelegate(new QStyledItemDelegate(q));
123 
124     vbar->setRange(0, 0);
125     hbar->setRange(0, 0);
126 
127     QObject::connect(vbar, SIGNAL(actionTriggered(int)),
128                      q, SLOT(verticalScrollbarAction(int)));
129     QObject::connect(hbar, SIGNAL(actionTriggered(int)),
130                      q, SLOT(horizontalScrollbarAction(int)));
131     QObject::connect(vbar, SIGNAL(valueChanged(int)),
132                      q, SLOT(verticalScrollbarValueChanged(int)));
133     QObject::connect(hbar, SIGNAL(valueChanged(int)),
134                      q, SLOT(horizontalScrollbarValueChanged(int)));
135 
136     viewport->setBackgroundRole(QPalette::Base);
137 
138     q->setAttribute(Qt::WA_InputMethodEnabled);
139 
140 #ifdef QT_SOFTKEYS_ENABLED
141     doneSoftKey = QSoftKeyManager::createKeyedAction(QSoftKeyManager::DoneSoftKey, Qt::Key_Back, q);
142 #endif
143 }
144 
setHoverIndex(const QPersistentModelIndex & index)145 void QAbstractItemViewPrivate::setHoverIndex(const QPersistentModelIndex &index)
146 {
147     Q_Q(QAbstractItemView);
148     if (hover == index)
149         return;
150 
151     if (selectionBehavior != QAbstractItemView::SelectRows) {
152         q->update(hover); //update the old one
153         q->update(index); //update the new one
154     } else {
155         QRect oldHoverRect = q->visualRect(hover);
156         QRect newHoverRect = q->visualRect(index);
157         viewport->update(QRect(0, newHoverRect.y(), viewport->width(), newHoverRect.height()));
158         viewport->update(QRect(0, oldHoverRect.y(), viewport->width(), oldHoverRect.height()));
159     }
160     hover = index;
161 }
162 
checkMouseMove(const QPersistentModelIndex & index)163 void QAbstractItemViewPrivate::checkMouseMove(const QPersistentModelIndex &index)
164 {
165     //we take a persistent model index because the model might change by emitting signals
166     Q_Q(QAbstractItemView);
167     setHoverIndex(index);
168     if (viewportEnteredNeeded || enteredIndex != index) {
169         viewportEnteredNeeded = false;
170 
171         if (index.isValid()) {
172             emit q->entered(index);
173 #ifndef QT_NO_STATUSTIP
174             QString statustip = model->data(index, Qt::StatusTipRole).toString();
175             if (parent && (shouldClearStatusTip || !statustip.isEmpty())) {
176                 QStatusTipEvent tip(statustip);
177                 QApplication::sendEvent(parent, &tip);
178                 shouldClearStatusTip = !statustip.isEmpty();
179             }
180 #endif
181         } else {
182 #ifndef QT_NO_STATUSTIP
183             if (parent && shouldClearStatusTip) {
184                 QString emptyString;
185                 QStatusTipEvent tip( emptyString );
186                 QApplication::sendEvent(parent, &tip);
187             }
188 #endif
189             emit q->viewportEntered();
190         }
191         enteredIndex = index;
192     }
193 }
194 
195 
196 /*!
197     \class QAbstractItemView
198 
199     \brief The QAbstractItemView class provides the basic functionality for
200     item view classes.
201 
202     \ingroup model-view
203 
204 
205     QAbstractItemView class is the base class for every standard view
206     that uses a QAbstractItemModel. QAbstractItemView is an abstract
207     class and cannot itself be instantiated. It provides a standard
208     interface for interoperating with models through the signals and
209     slots mechanism, enabling subclasses to be kept up-to-date with
210     changes to their models.  This class provides standard support for
211     keyboard and mouse navigation, viewport scrolling, item editing,
212     and selections. The keyboard navigation implements this
213     functionality:
214 
215     \table
216         \header
217             \o Keys
218             \o Functionality
219         \row
220             \o Arrow keys
221             \o Changes the current item and selects it.
222         \row
223             \o Ctrl+Arrow keys
224             \o Changes the current item but does not select it.
225         \row
226             \o Shift+Arrow keys
227             \o Changes the current item and selects it. The previously
228                selected item(s) is not deselected.
229         \row
230             \o Ctr+Space
231             \o Toggles selection of the current item.
232         \row
233             \o Tab/Backtab
234             \o Changes the current item to the next/previous item.
235         \row
236             \o Home/End
237             \o Selects the first/last item in the model.
238         \row
239             \o Page up/Page down
240             \o Scrolls the rows shown up/down by the number of
241                visible rows in the view.
242         \row
243             \o Ctrl+A
244             \o Selects all items in the model.
245     \endtable
246 
247     Note that the above table assumes that the
248     \l{selectionMode}{selection mode} allows the operations. For
249     instance, you cannot select items if the selection mode is
250     QAbstractItemView::NoSelection.
251 
252     The QAbstractItemView class is one of the \l{Model/View Classes}
253     and is part of Qt's \l{Model/View Programming}{model/view framework}.
254 
255     The view classes that inherit QAbstractItemView only need
256     to implement their own view-specific functionality, such as
257     drawing items, returning the geometry of items, finding items,
258     etc.
259 
260     QAbstractItemView provides common slots such as edit() and
261     setCurrentIndex(). Many protected slots are also provided, including
262     dataChanged(), rowsInserted(), rowsAboutToBeRemoved(), selectionChanged(),
263     and currentChanged().
264 
265     The root item is returned by rootIndex(), and the current item by
266     currentIndex(). To make sure that an item is visible use
267     scrollTo().
268 
269     Some of QAbstractItemView's functions are concerned with
270     scrolling, for example setHorizontalScrollMode() and
271     setVerticalScrollMode(). To set the range of the scroll bars, you
272     can, for example, reimplement the view's resizeEvent() function:
273 
274     \snippet doc/src/snippets/code/src_gui_itemviews_qabstractitemview.cpp 0
275 
276     Note that the range is not updated until the widget is shown.
277 
278     Several other functions are concerned with selection control; for
279     example setSelectionMode(), and setSelectionBehavior(). This class
280     provides a default selection model to work with
281     (selectionModel()), but this can be replaced by using
282     setSelectionModel() with an instance of QItemSelectionModel.
283 
284     For complete control over the display and editing of items you can
285     specify a delegate with setItemDelegate().
286 
287     QAbstractItemView provides a lot of protected functions. Some are
288     concerned with editing, for example, edit(), and commitData(),
289     whilst others are keyboard and mouse event handlers.
290 
291     \note If you inherit QAbstractItemView and intend to update the contents
292     of the viewport, you should use viewport->update() instead of
293     \l{QWidget::update()}{update()} as all painting operations take place on the
294     viewport.
295 
296     \sa {View Classes}, {Model/View Programming}, QAbstractItemModel, {Chart Example}
297 */
298 
299 /*!
300     \enum QAbstractItemView::SelectionMode
301 
302     This enum indicates how the view responds to user selections:
303 
304     \value SingleSelection  When the user selects an item, any already-selected
305     item becomes unselected, and the user cannot unselect the selected item by
306     clicking on it.
307 
308     \value ContiguousSelection When the user selects an item in the usual way,
309     the selection is cleared and the new item selected. However, if the user
310     presses the Shift key while clicking on an item, all items between the
311     current item and the clicked item are selected or unselected, depending on
312     the state of the clicked item.
313 
314     \value ExtendedSelection When the user selects an item in the usual way,
315     the selection is cleared and the new item selected. However, if the user
316     presses the Ctrl key when clicking on an item, the clicked item gets
317     toggled and all other items are left untouched. If the user presses the
318     Shift key while clicking on an item, all items between the current item
319     and the clicked item are selected or unselected, depending on the state of
320     the clicked item. Multiple items can be selected by dragging the mouse over
321     them.
322 
323     \value MultiSelection When the user selects an item in the usual way, the
324     selection status of that item is toggled and the other items are left
325     alone. Multiple items can be toggled by dragging the mouse over them.
326 
327     \value NoSelection Items cannot be selected.
328 
329     The most commonly used modes are SingleSelection and ExtendedSelection.
330 */
331 
332 /*!
333     \enum QAbstractItemView::SelectionBehavior
334 
335     \value SelectItems   Selecting single items.
336     \value SelectRows    Selecting only rows.
337     \value SelectColumns Selecting only columns.
338 */
339 
340 /*!
341     \enum QAbstractItemView::ScrollHint
342 
343     \value EnsureVisible  Scroll to ensure that the item is visible.
344     \value PositionAtTop  Scroll to position the item at the top of the
345            viewport.
346     \value PositionAtBottom  Scroll to position the item at the bottom of the
347            viewport.
348     \value PositionAtCenter  Scroll to position the item at the center of the
349            viewport.
350 */
351 
352 
353 /*!
354     \enum QAbstractItemView::EditTrigger
355 
356     This enum describes actions which will initiate item editing.
357 
358     \value NoEditTriggers  No editing possible.
359     \value CurrentChanged  Editing start whenever current item changes.
360     \value DoubleClicked   Editing starts when an item is double clicked.
361     \value SelectedClicked Editing starts when clicking on an already selected
362            item.
363     \value EditKeyPressed  Editing starts when the platform edit key has been
364            pressed over an item.
365     \value AnyKeyPressed   Editing starts when any key is pressed over an item.
366     \value AllEditTriggers Editing starts for all above actions.
367 */
368 
369 /*!
370     \enum QAbstractItemView::CursorAction
371 
372     This enum describes the different ways to navigate between items,
373     \sa moveCursor()
374 
375     \value MoveUp       Move to the item above the current item.
376     \value MoveDown     Move to the item below the current item.
377     \value MoveLeft     Move to the item left of the current item.
378     \value MoveRight    Move to the item right of the current item.
379     \value MoveHome     Move to the top-left corner item.
380     \value MoveEnd      Move to the bottom-right corner item.
381     \value MovePageUp   Move one page up above the current item.
382     \value MovePageDown Move one page down below the current item.
383     \value MoveNext     Move to the item after the current item.
384     \value MovePrevious Move to the item before the current item.
385 */
386 
387 /*!
388     \enum QAbstractItemView::State
389 
390     Describes the different states the view can be in. This is usually
391     only interesting when reimplementing your own view.
392 
393     \value NoState        The is the default state.
394     \value DraggingState  The user is dragging items.
395     \value DragSelectingState The user is selecting items.
396     \value EditingState   The user is editing an item in a widget editor.
397     \value ExpandingState   The user is opening a branch of items.
398     \value CollapsingState   The user is closing a branch of items.
399     \value AnimatingState The item view is performing an animation.
400 */
401 
402 /*!
403     \since 4.2
404     \enum QAbstractItemView::ScrollMode
405 
406     \value ScrollPerItem    The view will scroll the contents one item at a time.
407     \value ScrollPerPixel   The view will scroll the contents one pixel at a time.
408 */
409 
410 /*!
411     \fn QRect QAbstractItemView::visualRect(const QModelIndex &index) const = 0
412     Returns the rectangle on the viewport occupied by the item at \a index.
413 
414     If your item is displayed in several areas then visualRect should return
415     the primary area that contains index and not the complete area that index
416     might encompasses, touch or cause drawing.
417 
418     In the base class this is a pure virtual function.
419 
420     \sa indexAt(), visualRegionForSelection()
421 */
422 
423 /*!
424     \fn void QAbstractItemView::scrollTo(const QModelIndex &index, ScrollHint hint) = 0
425 
426     Scrolls the view if necessary to ensure that the item at \a index
427     is visible. The view will try to position the item according to the given \a hint.
428 
429     In the base class this is a pure virtual function.
430 */
431 
432 /*!
433     \fn QModelIndex QAbstractItemView::indexAt(const QPoint &point) const = 0
434 
435     Returns the model index of the item at the viewport coordinates \a point.
436 
437     In the base class this is a pure virtual function.
438 
439     \sa visualRect()
440 */
441 
442 /*!
443     \fn void QAbstractItemView::activated(const QModelIndex &index)
444 
445     This signal is emitted when the item specified by \a index is
446     activated by the user. How to activate items depends on the
447     platform; e.g., by single- or double-clicking the item, or by
448     pressing the Return or Enter key when the item is current.
449 
450     \sa clicked(), doubleClicked(), entered(), pressed()
451 */
452 
453 /*!
454     \fn void QAbstractItemView::entered(const QModelIndex &index)
455 
456     This signal is emitted when the mouse cursor enters the item
457     specified by \a index.
458     Mouse tracking needs to be enabled for this feature to work.
459 
460     \sa viewportEntered(), activated(), clicked(), doubleClicked(), pressed()
461 */
462 
463 /*!
464     \fn void QAbstractItemView::viewportEntered()
465 
466     This signal is emitted when the mouse cursor enters the viewport.
467     Mouse tracking needs to be enabled for this feature to work.
468 
469     \sa entered()
470 */
471 
472 /*!
473     \fn void QAbstractItemView::pressed(const QModelIndex &index)
474 
475     This signal is emitted when a mouse button is pressed. The item
476     the mouse was pressed on is specified by \a index. The signal is
477     only emitted when the index is valid.
478 
479     Use the QApplication::mouseButtons() function to get the state
480     of the mouse buttons.
481 
482     \sa activated(), clicked(), doubleClicked(), entered()
483 */
484 
485 /*!
486     \fn void QAbstractItemView::clicked(const QModelIndex &index)
487 
488     This signal is emitted when a mouse button is clicked. The item
489     the mouse was clicked on is specified by \a index. The signal is
490     only emitted when the index is valid.
491 
492     \sa activated(), doubleClicked(), entered(), pressed()
493 */
494 
495 /*!
496     \fn void QAbstractItemView::doubleClicked(const QModelIndex &index)
497 
498     This signal is emitted when a mouse button is double-clicked. The
499     item the mouse was double-clicked on is specified by \a index.
500     The signal is only emitted when the index is valid.
501 
502     \sa clicked(), activated()
503 */
504 
505 /*!
506     \fn QModelIndex QAbstractItemView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) = 0
507 
508     Returns a QModelIndex object pointing to the next object in the view,
509     based on the given \a cursorAction and keyboard modifiers specified
510     by \a modifiers.
511 
512     In the base class this is a pure virtual function.
513 */
514 
515 /*!
516     \fn int QAbstractItemView::horizontalOffset() const = 0
517 
518     Returns the horizontal offset of the view.
519 
520     In the base class this is a pure virtual function.
521 
522     \sa verticalOffset()
523 */
524 
525 /*!
526     \fn int QAbstractItemView::verticalOffset() const = 0
527 
528     Returns the vertical offset of the view.
529 
530     In the base class this is a pure virtual function.
531 
532     \sa horizontalOffset()
533 */
534 
535 /*!
536     \fn bool QAbstractItemView::isIndexHidden(const QModelIndex &index) const
537 
538     Returns true if the item referred to by the given \a index is hidden in the view,
539     otherwise returns false.
540 
541     Hiding is a view specific feature.  For example in TableView a column can be marked
542     as hidden or a row in the TreeView.
543 
544     In the base class this is a pure virtual function.
545 */
546 
547 /*!
548     \fn void QAbstractItemView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags)
549 
550     Applies the selection \a flags to the items in or touched by the
551     rectangle, \a rect.
552 
553     When implementing your own itemview setSelection should call
554     selectionModel()->select(selection, flags) where selection
555     is either an empty QModelIndex or a QItemSelection that contains
556     all items that are contained in \a rect.
557 
558     \sa selectionCommand(), selectedIndexes()
559 */
560 
561 /*!
562     \fn QRegion QAbstractItemView::visualRegionForSelection(const QItemSelection &selection) const = 0
563 
564     Returns the region from the viewport of the items in the given
565     \a selection.
566 
567     In the base class this is a pure virtual function.
568 
569     \sa visualRect(), selectedIndexes()
570 */
571 
572 /*!
573     \fn void QAbstractItemView::update()
574     \internal
575 */
576 
577 /*!
578     Constructs an abstract item view with the given \a parent.
579 */
QAbstractItemView(QWidget * parent)580 QAbstractItemView::QAbstractItemView(QWidget *parent)
581     : QAbstractScrollArea(*(new QAbstractItemViewPrivate), parent)
582 {
583     d_func()->init();
584 }
585 
586 /*!
587     \internal
588 */
QAbstractItemView(QAbstractItemViewPrivate & dd,QWidget * parent)589 QAbstractItemView::QAbstractItemView(QAbstractItemViewPrivate &dd, QWidget *parent)
590     : QAbstractScrollArea(dd, parent)
591 {
592     d_func()->init();
593 }
594 
595 /*!
596     Destroys the view.
597 */
~QAbstractItemView()598 QAbstractItemView::~QAbstractItemView()
599 {
600     Q_D(QAbstractItemView);
601     // stop these timers here before ~QObject
602     d->delayedReset.stop();
603     d->updateTimer.stop();
604     d->delayedEditing.stop();
605     d->delayedAutoScroll.stop();
606     d->autoScrollTimer.stop();
607     d->delayedLayout.stop();
608     d->fetchMoreTimer.stop();
609 }
610 
611 /*!
612     Sets the \a model for the view to present.
613 
614     This function will create and set a new selection model, replacing any
615     model that was previously set with setSelectionModel(). However, the old
616     selection model will not be deleted as it may be shared between several
617     views. We recommend that you delete the old selection model if it is no
618     longer required. This is done with the following code:
619 
620     \snippet doc/src/snippets/code/src_gui_itemviews_qabstractitemview.cpp 2
621 
622     If both the old model and the old selection model do not have parents, or
623     if their parents are long-lived objects, it may be preferable to call their
624     deleteLater() functions to explicitly delete them.
625 
626     The view \e{does not} take ownership of the model unless it is the model's
627     parent object because the model may be shared between many different views.
628 
629     \sa selectionModel(), setSelectionModel()
630 */
setModel(QAbstractItemModel * model)631 void QAbstractItemView::setModel(QAbstractItemModel *model)
632 {
633     Q_D(QAbstractItemView);
634     if (model == d->model)
635         return;
636     if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
637         disconnect(d->model, SIGNAL(destroyed()),
638                    this, SLOT(_q_modelDestroyed()));
639         disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
640                    this, SLOT(dataChanged(QModelIndex,QModelIndex)));
641         disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
642                    this, SLOT(_q_headerDataChanged()));
643         disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
644                    this, SLOT(rowsInserted(QModelIndex,int,int)));
645         disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
646                    this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
647         disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
648                    this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
649         disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
650                    this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
651         disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
652                    this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
653         disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
654                    this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
655         disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
656                    this, SLOT(_q_columnsInserted(QModelIndex,int,int)));
657 
658         disconnect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
659         disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
660     }
661     d->model = (model ? model : QAbstractItemModelPrivate::staticEmptyModel());
662 
663     // These asserts do basic sanity checking of the model
664     Q_ASSERT_X(d->model->index(0,0) == d->model->index(0,0),
665                "QAbstractItemView::setModel",
666                "A model should return the exact same index "
667                "(including its internal id/pointer) when asked for it twice in a row.");
668     Q_ASSERT_X(!d->model->index(0,0).parent().isValid(),
669                "QAbstractItemView::setModel",
670                "The parent of a top level index should be invalid");
671 
672     if (d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
673         connect(d->model, SIGNAL(destroyed()),
674                 this, SLOT(_q_modelDestroyed()));
675         connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
676                 this, SLOT(dataChanged(QModelIndex,QModelIndex)));
677         connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
678                 this, SLOT(_q_headerDataChanged()));
679         connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
680                 this, SLOT(rowsInserted(QModelIndex,int,int)));
681         connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
682                 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
683         connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
684                 this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
685         connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
686                 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
687         connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
688                 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
689         connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
690                 this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
691         connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
692                 this, SLOT(_q_columnsInserted(QModelIndex,int,int)));
693 
694         connect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
695         connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
696     }
697 
698     QItemSelectionModel *selection_model = new QItemSelectionModel(d->model, this);
699     connect(d->model, SIGNAL(destroyed()), selection_model, SLOT(deleteLater()));
700     setSelectionModel(selection_model);
701 
702     reset(); // kill editors, set new root and do layout
703 }
704 
705 /*!
706     Returns the model that this view is presenting.
707 */
model() const708 QAbstractItemModel *QAbstractItemView::model() const
709 {
710     Q_D(const QAbstractItemView);
711     return (d->model == QAbstractItemModelPrivate::staticEmptyModel() ? 0 : d->model);
712 }
713 
714 /*!
715     Sets the current selection model to the given \a selectionModel.
716 
717     Note that, if you call setModel() after this function, the given \a selectionModel
718     will be replaced by one created by the view.
719 
720     \note It is up to the application to delete the old selection model if it is no
721     longer needed; i.e., if it is not being used by other views. This will happen
722     automatically when its parent object is deleted. However, if it does not have a
723     parent, or if the parent is a long-lived object, it may be preferable to call its
724     deleteLater() function to explicitly delete it.
725 
726     \sa selectionModel(), setModel(), clearSelection()
727 */
setSelectionModel(QItemSelectionModel * selectionModel)728 void QAbstractItemView::setSelectionModel(QItemSelectionModel *selectionModel)
729 {
730     // ### if the given model is null, we should use the original selection model
731     Q_ASSERT(selectionModel);
732     Q_D(QAbstractItemView);
733 
734     if (selectionModel->model() != d->model) {
735         qWarning("QAbstractItemView::setSelectionModel() failed: "
736                  "Trying to set a selection model, which works on "
737                  "a different model than the view.");
738         return;
739     }
740 
741     if (d->selectionModel) {
742         disconnect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
743                    this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
744         disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
745                    this, SLOT(currentChanged(QModelIndex,QModelIndex)));
746     }
747 
748     d->selectionModel = selectionModel;
749 
750     if (d->selectionModel) {
751         connect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
752                 this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
753         connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
754                 this, SLOT(currentChanged(QModelIndex,QModelIndex)));
755     }
756 }
757 
758 /*!
759     Returns the current selection model.
760 
761     \sa setSelectionModel(), selectedIndexes()
762 */
selectionModel() const763 QItemSelectionModel* QAbstractItemView::selectionModel() const
764 {
765     Q_D(const QAbstractItemView);
766     return d->selectionModel;
767 }
768 
769 /*!
770     Sets the item delegate for this view and its model to \a delegate.
771     This is useful if you want complete control over the editing and
772     display of items.
773 
774     Any existing delegate will be removed, but not deleted. QAbstractItemView
775     does not take ownership of \a delegate.
776 
777     \warning You should not share the same instance of a delegate between views.
778     Doing so can cause incorrect or unintuitive editing behavior since each
779     view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
780     signal, and attempt to access, modify or close an editor that has already been closed.
781 
782     \sa itemDelegate()
783 */
setItemDelegate(QAbstractItemDelegate * delegate)784 void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *delegate)
785 {
786     Q_D(QAbstractItemView);
787     if (delegate == d->itemDelegate)
788         return;
789 
790     if (d->itemDelegate) {
791         if (d->delegateRefCount(d->itemDelegate) == 1) {
792             disconnect(d->itemDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
793                        this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
794             disconnect(d->itemDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
795             disconnect(d->itemDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()));
796         }
797     }
798 
799     if (delegate) {
800         if (d->delegateRefCount(delegate) == 0) {
801             connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
802                     this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
803             connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
804             qRegisterMetaType<QModelIndex>("QModelIndex");
805             connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()), Qt::QueuedConnection);
806         }
807     }
808     d->itemDelegate = delegate;
809     viewport()->update();
810 }
811 
812 /*!
813     Returns the item delegate used by this view and model. This is
814     either one set with setItemDelegate(), or the default one.
815 
816     \sa setItemDelegate()
817 */
itemDelegate() const818 QAbstractItemDelegate *QAbstractItemView::itemDelegate() const
819 {
820     return d_func()->itemDelegate;
821 }
822 
823 /*!
824     \reimp
825 */
inputMethodQuery(Qt::InputMethodQuery query) const826 QVariant QAbstractItemView::inputMethodQuery(Qt::InputMethodQuery query) const
827 {
828     const QModelIndex current = currentIndex();
829     if (!current.isValid() || query != Qt::ImMicroFocus)
830         return QAbstractScrollArea::inputMethodQuery(query);
831     return visualRect(current);
832 }
833 
834 /*!
835     \since 4.2
836 
837     Sets the given item \a delegate used by this view and model for the given
838     \a row. All items on \a row will be drawn and managed by \a delegate
839     instead of using the default delegate (i.e., itemDelegate()).
840 
841     Any existing row delegate for \a row will be removed, but not
842     deleted. QAbstractItemView does not take ownership of \a delegate.
843 
844     \note If a delegate has been assigned to both a row and a column, the row
845     delegate (i.e., this delegate) will take precedence and manage the
846     intersecting cell index.
847 
848     \warning You should not share the same instance of a delegate between views.
849     Doing so can cause incorrect or unintuitive editing behavior since each
850     view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
851     signal, and attempt to access, modify or close an editor that has already been closed.
852 
853     \sa itemDelegateForRow(), setItemDelegateForColumn(), itemDelegate()
854 */
setItemDelegateForRow(int row,QAbstractItemDelegate * delegate)855 void QAbstractItemView::setItemDelegateForRow(int row, QAbstractItemDelegate *delegate)
856 {
857     Q_D(QAbstractItemView);
858     if (QAbstractItemDelegate *rowDelegate = d->rowDelegates.value(row, 0)) {
859         if (d->delegateRefCount(rowDelegate) == 1) {
860             disconnect(rowDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
861                        this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
862             disconnect(rowDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
863         }
864         d->rowDelegates.remove(row);
865     }
866     if (delegate) {
867         if (d->delegateRefCount(delegate) == 0) {
868             connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
869                     this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
870             connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
871         }
872         d->rowDelegates.insert(row, delegate);
873     }
874     viewport()->update();
875 }
876 
877 /*!
878    \since 4.2
879 
880    Returns the item delegate used by this view and model for the given \a row,
881    or 0 if no delegate has been assigned. You can call itemDelegate() to get a
882    pointer to the current delegate for a given index.
883 
884    \sa setItemDelegateForRow(), itemDelegateForColumn(), setItemDelegate()
885 */
itemDelegateForRow(int row) const886 QAbstractItemDelegate *QAbstractItemView::itemDelegateForRow(int row) const
887 {
888     Q_D(const QAbstractItemView);
889     return d->rowDelegates.value(row, 0);
890 }
891 
892 /*!
893     \since 4.2
894 
895     Sets the given item \a delegate used by this view and model for the given
896     \a column. All items on \a column will be drawn and managed by \a delegate
897     instead of using the default delegate (i.e., itemDelegate()).
898 
899     Any existing column delegate for \a column will be removed, but not
900     deleted. QAbstractItemView does not take ownership of \a delegate.
901 
902     \note If a delegate has been assigned to both a row and a column, the row
903     delegate will take precedence and manage the intersecting cell index.
904 
905     \warning You should not share the same instance of a delegate between views.
906     Doing so can cause incorrect or unintuitive editing behavior since each
907     view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
908     signal, and attempt to access, modify or close an editor that has already been closed.
909 
910     \sa itemDelegateForColumn(), setItemDelegateForRow(), itemDelegate()
911 */
setItemDelegateForColumn(int column,QAbstractItemDelegate * delegate)912 void QAbstractItemView::setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate)
913 {
914     Q_D(QAbstractItemView);
915     if (QAbstractItemDelegate *columnDelegate = d->columnDelegates.value(column, 0)) {
916         if (d->delegateRefCount(columnDelegate) == 1) {
917             disconnect(columnDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
918                        this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
919             disconnect(columnDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
920         }
921         d->columnDelegates.remove(column);
922     }
923     if (delegate) {
924         if (d->delegateRefCount(delegate) == 0) {
925             connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
926                     this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
927             connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
928         }
929         d->columnDelegates.insert(column, delegate);
930     }
931     viewport()->update();
932 }
933 
934 /*!
935     \since 4.2
936 
937     Returns the item delegate used by this view and model for the given \a
938     column.  You can call itemDelegate() to get a pointer to the current delegate
939     for a given index.
940 
941     \sa setItemDelegateForColumn(), itemDelegateForRow(), itemDelegate()
942 */
itemDelegateForColumn(int column) const943 QAbstractItemDelegate *QAbstractItemView::itemDelegateForColumn(int column) const
944 {
945     Q_D(const QAbstractItemView);
946     return d->columnDelegates.value(column, 0);
947 }
948 
949 /*!
950     Returns the item delegate used by this view and model for
951     the given \a index.
952 */
itemDelegate(const QModelIndex & index) const953 QAbstractItemDelegate *QAbstractItemView::itemDelegate(const QModelIndex &index) const
954 {
955     Q_D(const QAbstractItemView);
956     return d->delegateForIndex(index);
957 }
958 
959 /*!
960     \property QAbstractItemView::selectionMode
961     \brief which selection mode the view operates in
962 
963     This property controls whether the user can select one or many items
964     and, in many-item selections, whether the selection must be a
965     continuous range of items.
966 
967     \sa SelectionMode SelectionBehavior
968 */
setSelectionMode(SelectionMode mode)969 void QAbstractItemView::setSelectionMode(SelectionMode mode)
970 {
971     Q_D(QAbstractItemView);
972     d->selectionMode = mode;
973 }
974 
selectionMode() const975 QAbstractItemView::SelectionMode QAbstractItemView::selectionMode() const
976 {
977     Q_D(const QAbstractItemView);
978     return d->selectionMode;
979 }
980 
981 /*!
982     \property QAbstractItemView::selectionBehavior
983     \brief which selection behavior the view uses
984 
985     This property holds whether selections are done
986     in terms of single items, rows or columns.
987 
988     \sa SelectionMode SelectionBehavior
989 */
990 
setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)991 void QAbstractItemView::setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
992 {
993     Q_D(QAbstractItemView);
994     d->selectionBehavior = behavior;
995 }
996 
selectionBehavior() const997 QAbstractItemView::SelectionBehavior QAbstractItemView::selectionBehavior() const
998 {
999     Q_D(const QAbstractItemView);
1000     return d->selectionBehavior;
1001 }
1002 
1003 /*!
1004     Sets the current item to be the item at \a index.
1005 
1006     Unless the current selection mode is
1007     \l{QAbstractItemView::}{NoSelection}, the item is also be selected.
1008     Note that this function also updates the starting position for any
1009     new selections the user performs.
1010 
1011     To set an item as the current item without selecting it, call
1012 
1013     \c{selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);}
1014 
1015     \sa currentIndex(), currentChanged(), selectionMode
1016 */
setCurrentIndex(const QModelIndex & index)1017 void QAbstractItemView::setCurrentIndex(const QModelIndex &index)
1018 {
1019     Q_D(QAbstractItemView);
1020     if (d->selectionModel && (!index.isValid() || d->isIndexEnabled(index))) {
1021         QItemSelectionModel::SelectionFlags command = selectionCommand(index, 0);
1022         d->selectionModel->setCurrentIndex(index, command);
1023         d->currentIndexSet = true;
1024         if ((command & QItemSelectionModel::Current) == 0)
1025             d->pressedPosition = visualRect(currentIndex()).center() + d->offset();
1026     }
1027 }
1028 
1029 /*!
1030     Returns the model index of the current item.
1031 
1032     \sa setCurrentIndex()
1033 */
currentIndex() const1034 QModelIndex QAbstractItemView::currentIndex() const
1035 {
1036     Q_D(const QAbstractItemView);
1037     return d->selectionModel ? d->selectionModel->currentIndex() : QModelIndex();
1038 }
1039 
1040 
1041 /*!
1042     Reset the internal state of the view.
1043 
1044     \warning This function will reset open editors, scroll bar positions,
1045     selections, etc. Existing changes will not be committed. If you would like
1046     to save your changes when resetting the view, you can reimplement this
1047     function, commit your changes, and then call the superclass'
1048     implementation.
1049 */
reset()1050 void QAbstractItemView::reset()
1051 {
1052     Q_D(QAbstractItemView);
1053     d->delayedReset.stop(); //make sure we stop the timer
1054     foreach (const QEditorInfo &info, d->indexEditorHash) {
1055         if (info.widget)
1056             d->releaseEditor(info.widget.data());
1057     }
1058     d->editorIndexHash.clear();
1059     d->indexEditorHash.clear();
1060     d->persistent.clear();
1061     d->currentIndexSet = false;
1062     setState(NoState);
1063     setRootIndex(QModelIndex());
1064     if (d->selectionModel)
1065         d->selectionModel->reset();
1066 #ifndef QT_NO_ACCESSIBILITY
1067 #ifdef Q_WS_X11
1068     if (QAccessible::isActive()) {
1069         QAccessible::queryAccessibleInterface(this)->table2Interface()->modelReset();
1070         QAccessible::updateAccessibility(this, 0, QAccessible::TableModelChanged);
1071     }
1072 #endif
1073 #endif
1074 }
1075 
1076 /*!
1077     Sets the root item to the item at the given \a index.
1078 
1079     \sa rootIndex()
1080 */
setRootIndex(const QModelIndex & index)1081 void QAbstractItemView::setRootIndex(const QModelIndex &index)
1082 {
1083     Q_D(QAbstractItemView);
1084     if (index.isValid() && index.model() != d->model) {
1085         qWarning("QAbstractItemView::setRootIndex failed : index must be from the currently set model");
1086         return;
1087     }
1088     d->root = index;
1089     d->doDelayedItemsLayout();
1090 }
1091 
1092 /*!
1093     Returns the model index of the model's root item. The root item is
1094     the parent item to the view's toplevel items. The root can be invalid.
1095 
1096     \sa setRootIndex()
1097 */
rootIndex() const1098 QModelIndex QAbstractItemView::rootIndex() const
1099 {
1100     return QModelIndex(d_func()->root);
1101 }
1102 
1103 /*!
1104     Selects all items in the view.
1105     This function will use the selection behavior
1106     set on the view when selecting.
1107 
1108     \sa setSelection(), selectedIndexes(), clearSelection()
1109 */
selectAll()1110 void QAbstractItemView::selectAll()
1111 {
1112     Q_D(QAbstractItemView);
1113     SelectionMode mode = d->selectionMode;
1114     if (mode == MultiSelection || mode == ExtendedSelection)
1115         d->selectAll(QItemSelectionModel::ClearAndSelect
1116                      |d->selectionBehaviorFlags());
1117     else if (mode != SingleSelection)
1118         d->selectAll(selectionCommand(d->model->index(0, 0, d->root)));
1119 }
1120 
1121 /*!
1122     Starts editing the item corresponding to the given \a index if it is
1123     editable.
1124 
1125     Note that this function does not change the current index. Since the current
1126     index defines the next and previous items to edit, users may find that
1127     keyboard navigation does not work as expected. To provide consistent navigation
1128     behavior, call setCurrentIndex() before this function with the same model
1129     index.
1130 
1131     \sa QModelIndex::flags()
1132 */
edit(const QModelIndex & index)1133 void QAbstractItemView::edit(const QModelIndex &index)
1134 {
1135     Q_D(QAbstractItemView);
1136     if (!d->isIndexValid(index))
1137         qWarning("edit: index was invalid");
1138     if (!edit(index, AllEditTriggers, 0))
1139         qWarning("edit: editing failed");
1140 }
1141 
1142 /*!
1143     Deselects all selected items. The current index will not be changed.
1144 
1145     \sa setSelection(), selectAll()
1146 */
clearSelection()1147 void QAbstractItemView::clearSelection()
1148 {
1149     Q_D(QAbstractItemView);
1150     if (d->selectionModel)
1151         d->selectionModel->clearSelection();
1152 }
1153 
1154 /*!
1155     \internal
1156 
1157     This function is intended to lay out the items in the view.
1158     The default implementation just calls updateGeometries() and updates the viewport.
1159 */
doItemsLayout()1160 void QAbstractItemView::doItemsLayout()
1161 {
1162     Q_D(QAbstractItemView);
1163     d->interruptDelayedItemsLayout();
1164     updateGeometries();
1165     d->viewport->update();
1166 }
1167 
1168 /*!
1169     \property QAbstractItemView::editTriggers
1170     \brief which actions will initiate item editing
1171 
1172     This property is a selection of flags defined by
1173     \l{EditTrigger}, combined using the OR
1174     operator. The view will only initiate the editing of an item if the
1175     action performed is set in this property.
1176 */
setEditTriggers(EditTriggers actions)1177 void QAbstractItemView::setEditTriggers(EditTriggers actions)
1178 {
1179     Q_D(QAbstractItemView);
1180     d->editTriggers = actions;
1181 }
1182 
editTriggers() const1183 QAbstractItemView::EditTriggers QAbstractItemView::editTriggers() const
1184 {
1185     Q_D(const QAbstractItemView);
1186     return d->editTriggers;
1187 }
1188 
1189 /*!
1190     \since 4.2
1191     \property QAbstractItemView::verticalScrollMode
1192     \brief how the view scrolls its contents in the vertical direction
1193 
1194     This property controls how the view scroll its contents vertically.
1195     Scrolling can be done either per pixel or per item.
1196 */
1197 
setVerticalScrollMode(ScrollMode mode)1198 void QAbstractItemView::setVerticalScrollMode(ScrollMode mode)
1199 {
1200     Q_D(QAbstractItemView);
1201     if (mode == d->verticalScrollMode)
1202         return;
1203     QModelIndex topLeft = indexAt(QPoint(0, 0));
1204     d->verticalScrollMode = mode;
1205     updateGeometries(); // update the scroll bars
1206     scrollTo(topLeft, QAbstractItemView::PositionAtTop);
1207 }
1208 
verticalScrollMode() const1209 QAbstractItemView::ScrollMode QAbstractItemView::verticalScrollMode() const
1210 {
1211     Q_D(const QAbstractItemView);
1212     return d->verticalScrollMode;
1213 }
1214 
1215 /*!
1216     \since 4.2
1217     \property QAbstractItemView::horizontalScrollMode
1218     \brief how the view scrolls its contents in the horizontal direction
1219 
1220     This property controls how the view scroll its contents horizontally.
1221     Scrolling can be done either per pixel or per item.
1222 */
1223 
setHorizontalScrollMode(ScrollMode mode)1224 void QAbstractItemView::setHorizontalScrollMode(ScrollMode mode)
1225 {
1226     Q_D(QAbstractItemView);
1227     d->horizontalScrollMode = mode;
1228     updateGeometries(); // update the scroll bars
1229 }
1230 
horizontalScrollMode() const1231 QAbstractItemView::ScrollMode QAbstractItemView::horizontalScrollMode() const
1232 {
1233     Q_D(const QAbstractItemView);
1234     return d->horizontalScrollMode;
1235 }
1236 
1237 #ifndef QT_NO_DRAGANDDROP
1238 /*!
1239     \since 4.2
1240     \property QAbstractItemView::dragDropOverwriteMode
1241     \brief the view's drag and drop behavior
1242 
1243     If its value is \c true, the selected data will overwrite the
1244     existing item data when dropped, while moving the data will clear
1245     the item. If its value is \c false, the selected data will be
1246     inserted as a new item when the data is dropped. When the data is
1247     moved, the item is removed as well.
1248 
1249     The default value is \c false, as in the QListView and QTreeView
1250     subclasses. In the QTableView subclass, on the other hand, the
1251     property has been set to \c true.
1252 
1253     Note: This is not intended to prevent overwriting of items.
1254     The model's implementation of flags() should do that by not
1255     returning Qt::ItemIsDropEnabled.
1256 
1257     \sa dragDropMode
1258 */
setDragDropOverwriteMode(bool overwrite)1259 void QAbstractItemView::setDragDropOverwriteMode(bool overwrite)
1260 {
1261     Q_D(QAbstractItemView);
1262     d->overwrite = overwrite;
1263 }
1264 
dragDropOverwriteMode() const1265 bool QAbstractItemView::dragDropOverwriteMode() const
1266 {
1267     Q_D(const QAbstractItemView);
1268     return d->overwrite;
1269 }
1270 #endif
1271 
1272 /*!
1273     \property QAbstractItemView::autoScroll
1274     \brief whether autoscrolling in drag move events is enabled
1275 
1276     If this property is set to true (the default), the
1277     QAbstractItemView automatically scrolls the contents of the view
1278     if the user drags within 16 pixels of the viewport edge. If the current
1279     item changes, then the view will scroll automatically to ensure that the
1280     current item is fully visible.
1281 
1282     This property only works if the viewport accepts drops. Autoscroll is
1283     switched off by setting this property to false.
1284 */
1285 
setAutoScroll(bool enable)1286 void QAbstractItemView::setAutoScroll(bool enable)
1287 {
1288     Q_D(QAbstractItemView);
1289     d->autoScroll = enable;
1290 }
1291 
hasAutoScroll() const1292 bool QAbstractItemView::hasAutoScroll() const
1293 {
1294     Q_D(const QAbstractItemView);
1295     return d->autoScroll;
1296 }
1297 
1298 /*!
1299     \since 4.4
1300     \property QAbstractItemView::autoScrollMargin
1301     \brief the size of the area when auto scrolling is triggered
1302 
1303     This property controls the size of the area at the edge of the viewport that
1304     triggers autoscrolling. The default value is 16 pixels.
1305 */
setAutoScrollMargin(int margin)1306 void QAbstractItemView::setAutoScrollMargin(int margin)
1307 {
1308     Q_D(QAbstractItemView);
1309     d->autoScrollMargin = margin;
1310 }
1311 
autoScrollMargin() const1312 int QAbstractItemView::autoScrollMargin() const
1313 {
1314     Q_D(const QAbstractItemView);
1315     return d->autoScrollMargin;
1316 }
1317 
1318 /*!
1319   \property QAbstractItemView::tabKeyNavigation
1320   \brief whether item navigation with tab and backtab is enabled.
1321 */
1322 
setTabKeyNavigation(bool enable)1323 void QAbstractItemView::setTabKeyNavigation(bool enable)
1324 {
1325     Q_D(QAbstractItemView);
1326     d->tabKeyNavigation = enable;
1327 }
1328 
tabKeyNavigation() const1329 bool QAbstractItemView::tabKeyNavigation() const
1330 {
1331     Q_D(const QAbstractItemView);
1332     return d->tabKeyNavigation;
1333 }
1334 
1335 #ifndef QT_NO_DRAGANDDROP
1336 /*!
1337     \property QAbstractItemView::showDropIndicator
1338     \brief whether the drop indicator is shown when dragging items and dropping.
1339 
1340     \sa dragEnabled DragDropMode dragDropOverwriteMode acceptDrops
1341 */
1342 
setDropIndicatorShown(bool enable)1343 void QAbstractItemView::setDropIndicatorShown(bool enable)
1344 {
1345     Q_D(QAbstractItemView);
1346     d->showDropIndicator = enable;
1347 }
1348 
showDropIndicator() const1349 bool QAbstractItemView::showDropIndicator() const
1350 {
1351     Q_D(const QAbstractItemView);
1352     return d->showDropIndicator;
1353 }
1354 
1355 /*!
1356     \property QAbstractItemView::dragEnabled
1357     \brief whether the view supports dragging of its own items
1358 
1359     \sa showDropIndicator DragDropMode dragDropOverwriteMode acceptDrops
1360 */
1361 
setDragEnabled(bool enable)1362 void QAbstractItemView::setDragEnabled(bool enable)
1363 {
1364     Q_D(QAbstractItemView);
1365     d->dragEnabled = enable;
1366 }
1367 
dragEnabled() const1368 bool QAbstractItemView::dragEnabled() const
1369 {
1370     Q_D(const QAbstractItemView);
1371     return d->dragEnabled;
1372 }
1373 
1374 /*!
1375     \since 4.2
1376     \enum QAbstractItemView::DragDropMode
1377 
1378     Describes the various drag and drop events the view can act upon.
1379     By default the view does not support dragging or dropping (\c
1380     NoDragDrop).
1381 
1382     \value NoDragDrop Does not support dragging or dropping.
1383     \value DragOnly The view supports dragging of its own items
1384     \value DropOnly The view accepts drops
1385     \value DragDrop The view supports both dragging and dropping
1386     \value InternalMove The view accepts move (\bold{not copy}) operations only
1387            from itself.
1388 
1389     Note that the model used needs to provide support for drag and drop operations.
1390 
1391     \sa setDragDropMode() {Using drag and drop with item views}
1392 */
1393 
1394 /*!
1395     \property QAbstractItemView::dragDropMode
1396     \brief the drag and drop event the view will act upon
1397 
1398     \since 4.2
1399     \sa showDropIndicator dragDropOverwriteMode
1400 */
setDragDropMode(DragDropMode behavior)1401 void QAbstractItemView::setDragDropMode(DragDropMode behavior)
1402 {
1403     Q_D(QAbstractItemView);
1404     d->dragDropMode = behavior;
1405     setDragEnabled(behavior == DragOnly || behavior == DragDrop || behavior == InternalMove);
1406     setAcceptDrops(behavior == DropOnly || behavior == DragDrop || behavior == InternalMove);
1407 }
1408 
dragDropMode() const1409 QAbstractItemView::DragDropMode QAbstractItemView::dragDropMode() const
1410 {
1411     Q_D(const QAbstractItemView);
1412     DragDropMode setBehavior = d->dragDropMode;
1413     if (!dragEnabled() && !acceptDrops())
1414         return NoDragDrop;
1415 
1416     if (dragEnabled() && !acceptDrops())
1417         return DragOnly;
1418 
1419     if (!dragEnabled() && acceptDrops())
1420         return DropOnly;
1421 
1422     if (dragEnabled() && acceptDrops()) {
1423         if (setBehavior == InternalMove)
1424             return setBehavior;
1425         else
1426             return DragDrop;
1427     }
1428 
1429     return NoDragDrop;
1430 }
1431 
1432 /*!
1433     \property QAbstractItemView::defaultDropAction
1434     \brief the drop action that will be used by default in QAbstractItemView::drag()
1435 
1436     If the property is not set, the drop action is CopyAction when the supported
1437     actions support CopyAction.
1438 
1439     \since 4.6
1440     \sa showDropIndicator dragDropOverwriteMode
1441 */
setDefaultDropAction(Qt::DropAction dropAction)1442 void QAbstractItemView::setDefaultDropAction(Qt::DropAction dropAction)
1443 {
1444     Q_D(QAbstractItemView);
1445     d->defaultDropAction = dropAction;
1446 }
1447 
defaultDropAction() const1448 Qt::DropAction QAbstractItemView::defaultDropAction() const
1449 {
1450     Q_D(const QAbstractItemView);
1451     return d->defaultDropAction;
1452 }
1453 
1454 #endif // QT_NO_DRAGANDDROP
1455 
1456 /*!
1457     \property QAbstractItemView::alternatingRowColors
1458     \brief whether to draw the background using alternating colors
1459 
1460     If this property is true, the item background will be drawn using
1461     QPalette::Base and QPalette::AlternateBase; otherwise the background
1462     will be drawn using the QPalette::Base color.
1463 
1464     By default, this property is false.
1465 */
setAlternatingRowColors(bool enable)1466 void QAbstractItemView::setAlternatingRowColors(bool enable)
1467 {
1468     Q_D(QAbstractItemView);
1469     d->alternatingColors = enable;
1470     if (isVisible())
1471         d->viewport->update();
1472 }
1473 
alternatingRowColors() const1474 bool QAbstractItemView::alternatingRowColors() const
1475 {
1476     Q_D(const QAbstractItemView);
1477     return d->alternatingColors;
1478 }
1479 
1480 /*!
1481     \property QAbstractItemView::iconSize
1482     \brief the size of items' icons
1483 
1484     Setting this property when the view is visible will cause the
1485     items to be laid out again.
1486 */
setIconSize(const QSize & size)1487 void QAbstractItemView::setIconSize(const QSize &size)
1488 {
1489     Q_D(QAbstractItemView);
1490     if (size == d->iconSize)
1491         return;
1492     d->iconSize = size;
1493     d->doDelayedItemsLayout();
1494 }
1495 
iconSize() const1496 QSize QAbstractItemView::iconSize() const
1497 {
1498     Q_D(const QAbstractItemView);
1499     return d->iconSize;
1500 }
1501 
1502 /*!
1503     \property QAbstractItemView::textElideMode
1504 
1505     \brief the position of the "..." in elided text.
1506 
1507     The default value for all item views is Qt::ElideRight.
1508 */
setTextElideMode(Qt::TextElideMode mode)1509 void QAbstractItemView::setTextElideMode(Qt::TextElideMode mode)
1510 {
1511     Q_D(QAbstractItemView);
1512     d->textElideMode = mode;
1513 }
1514 
textElideMode() const1515 Qt::TextElideMode QAbstractItemView::textElideMode() const
1516 {
1517     return d_func()->textElideMode;
1518 }
1519 
1520 /*!
1521   \reimp
1522 */
focusNextPrevChild(bool next)1523 bool QAbstractItemView::focusNextPrevChild(bool next)
1524 {
1525     Q_D(QAbstractItemView);
1526     if (d->tabKeyNavigation && isEnabled() && d->viewport->isEnabled()) {
1527         QKeyEvent event(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
1528         keyPressEvent(&event);
1529         if (event.isAccepted())
1530             return true;
1531     }
1532     return QAbstractScrollArea::focusNextPrevChild(next);
1533 }
1534 
1535 /*!
1536   \reimp
1537 */
event(QEvent * event)1538 bool QAbstractItemView::event(QEvent *event)
1539 {
1540     Q_D(QAbstractItemView);
1541     switch (event->type()) {
1542     case QEvent::Paint:
1543         //we call this here because the scrollbars' visibility might be altered
1544         //so this can't be done in the paintEvent method
1545         d->executePostedLayout(); //make sure we set the layout properly
1546         break;
1547     case QEvent::Show:
1548         d->executePostedLayout(); //make sure we set the layout properly
1549         if (d->shouldScrollToCurrentOnShow) {
1550             d->shouldScrollToCurrentOnShow = false;
1551             const QModelIndex current = currentIndex();
1552             if (current.isValid() && (d->state == QAbstractItemView::EditingState || d->autoScroll))
1553                 scrollTo(current);
1554         }
1555         break;
1556     case QEvent::LocaleChange:
1557         viewport()->update();
1558         break;
1559     case QEvent::LayoutDirectionChange:
1560     case QEvent::ApplicationLayoutDirectionChange:
1561         updateGeometries();
1562         break;
1563     case QEvent::StyleChange:
1564         doItemsLayout();
1565         break;
1566     case QEvent::FocusOut:
1567         d->checkPersistentEditorFocus();
1568         break;
1569     case QEvent::FontChange:
1570         d->doDelayedItemsLayout(); // the size of the items will change
1571         break;
1572 #ifdef QT_SOFTKEYS_ENABLED
1573     case QEvent::LanguageChange:
1574         d->doneSoftKey->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::DoneSoftKey));
1575         break;
1576 #endif
1577     default:
1578         break;
1579     }
1580     return QAbstractScrollArea::event(event);
1581 }
1582 
1583 /*!
1584     \fn bool QAbstractItemView::viewportEvent(QEvent *event)
1585 
1586     This function is used to handle tool tips, and What's
1587     This? mode, if the given \a event is a QEvent::ToolTip,or a
1588     QEvent::WhatsThis. It passes all other
1589     events on to its base class viewportEvent() handler.
1590 */
viewportEvent(QEvent * event)1591 bool QAbstractItemView::viewportEvent(QEvent *event)
1592 {
1593     Q_D(QAbstractItemView);
1594     switch (event->type()) {
1595     case QEvent::HoverMove:
1596     case QEvent::HoverEnter:
1597         d->setHoverIndex(indexAt(static_cast<QHoverEvent*>(event)->pos()));
1598         break;
1599     case QEvent::HoverLeave:
1600         d->setHoverIndex(QModelIndex());
1601         break;
1602     case QEvent::Enter:
1603         d->viewportEnteredNeeded = true;
1604         break;
1605     case QEvent::Leave:
1606     #ifndef QT_NO_STATUSTIP
1607         if (d->shouldClearStatusTip && d->parent) {
1608             QString empty;
1609             QStatusTipEvent tip(empty);
1610             QApplication::sendEvent(d->parent, &tip);
1611             d->shouldClearStatusTip = false;
1612         }
1613     #endif
1614         d->enteredIndex = QModelIndex();
1615         break;
1616     case QEvent::ToolTip:
1617     case QEvent::QueryWhatsThis:
1618     case QEvent::WhatsThis: {
1619         QHelpEvent *he = static_cast<QHelpEvent*>(event);
1620         const QModelIndex index = indexAt(he->pos());
1621         QStyleOptionViewItemV4 option = d->viewOptionsV4();
1622         option.rect = visualRect(index);
1623         option.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
1624         bool retval = false;
1625         // ### Qt 5: make this a normal function call to a virtual function
1626         QMetaObject::invokeMethod(d->delegateForIndex(index), "helpEvent",
1627                                   Q_RETURN_ARG(bool, retval),
1628                                   Q_ARG(QHelpEvent *, he),
1629                                   Q_ARG(QAbstractItemView *, this),
1630                                   Q_ARG(QStyleOptionViewItem, option),
1631                                   Q_ARG(QModelIndex, index));
1632         return retval;
1633     }
1634     case QEvent::FontChange:
1635         d->doDelayedItemsLayout(); // the size of the items will change
1636         break;
1637     case QEvent::WindowActivate:
1638     case QEvent::WindowDeactivate:
1639         d->viewport->update();
1640         break;
1641     default:
1642         break;
1643     }
1644     return QAbstractScrollArea::viewportEvent(event);
1645 }
1646 
1647 /*!
1648     This function is called with the given \a event when a mouse button is pressed
1649     while the cursor is inside the widget. If a valid item is pressed on it is made
1650     into the current item. This function emits the pressed() signal.
1651 */
mousePressEvent(QMouseEvent * event)1652 void QAbstractItemView::mousePressEvent(QMouseEvent *event)
1653 {
1654     Q_D(QAbstractItemView);
1655     d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
1656     QPoint pos = event->pos();
1657     QPersistentModelIndex index = indexAt(pos);
1658 
1659     if (!d->selectionModel
1660         || (d->state == EditingState && d->hasEditor(index)))
1661         return;
1662 
1663     d->pressedAlreadySelected = d->selectionModel->isSelected(index);
1664     d->pressedIndex = index;
1665     d->pressedModifiers = event->modifiers();
1666     QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1667     d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid();
1668     QPoint offset = d->offset();
1669     if ((command & QItemSelectionModel::Current) == 0)
1670         d->pressedPosition = pos + offset;
1671     else if (!indexAt(d->pressedPosition - offset).isValid())
1672         d->pressedPosition = visualRect(currentIndex()).center() + offset;
1673 
1674     if (edit(index, NoEditTriggers, event))
1675         return;
1676 
1677     if (index.isValid() && d->isIndexEnabled(index)) {
1678         // we disable scrollTo for mouse press so the item doesn't change position
1679         // when the user is interacting with it (ie. clicking on it)
1680         bool autoScroll = d->autoScroll;
1681         d->autoScroll = false;
1682         d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1683         d->autoScroll = autoScroll;
1684         QRect rect(d->pressedPosition - offset, pos);
1685         if (command.testFlag(QItemSelectionModel::Toggle)) {
1686             command &= ~QItemSelectionModel::Toggle;
1687             d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
1688             command |= d->ctrlDragSelectionFlag;
1689         }
1690         setSelection(rect, command);
1691 
1692         // signal handlers may change the model
1693         emit pressed(index);
1694         if (d->autoScroll) {
1695             //we delay the autoscrolling to filter out double click event
1696             //100 is to be sure that there won't be a double-click misinterpreted as a 2 single clicks
1697             d->delayedAutoScroll.start(QApplication::doubleClickInterval()+100, this);
1698         }
1699 
1700     } else {
1701         // Forces a finalize() even if mouse is pressed, but not on a item
1702         d->selectionModel->select(QModelIndex(), QItemSelectionModel::Select);
1703     }
1704 }
1705 
1706 /*!
1707     This function is called with the given \a event when a mouse move event is
1708     sent to the widget. If a selection is in progress and new items are moved
1709     over the selection is extended; if a drag is in progress it is continued.
1710 */
mouseMoveEvent(QMouseEvent * event)1711 void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
1712 {
1713     Q_D(QAbstractItemView);
1714     QPoint topLeft;
1715     QPoint bottomRight = event->pos();
1716 
1717     if (state() == ExpandingState || state() == CollapsingState)
1718         return;
1719 
1720 #ifndef QT_NO_DRAGANDDROP
1721     if (state() == DraggingState) {
1722         topLeft = d->pressedPosition - d->offset();
1723         if ((topLeft - bottomRight).manhattanLength() > QApplication::startDragDistance()) {
1724             d->pressedIndex = QModelIndex();
1725             startDrag(d->model->supportedDragActions());
1726             setState(NoState); // the startDrag will return when the dnd operation is done
1727             stopAutoScroll();
1728         }
1729         return;
1730     }
1731 #endif // QT_NO_DRAGANDDROP
1732 
1733     QPersistentModelIndex index = indexAt(bottomRight);
1734     QModelIndex buddy = d->model->buddy(d->pressedIndex);
1735     if ((state() == EditingState && d->hasEditor(buddy))
1736         || edit(index, NoEditTriggers, event))
1737         return;
1738 
1739     if (d->selectionMode != SingleSelection)
1740         topLeft = d->pressedPosition - d->offset();
1741     else
1742         topLeft = bottomRight;
1743 
1744     d->checkMouseMove(index);
1745 
1746 #ifndef QT_NO_DRAGANDDROP
1747     if (d->pressedIndex.isValid()
1748         && d->dragEnabled
1749         && (state() != DragSelectingState)
1750         && (event->buttons() != Qt::NoButton)
1751         && !d->selectedDraggableIndexes().isEmpty()) {
1752             setState(DraggingState);
1753             return;
1754     }
1755 #endif
1756 
1757     if ((event->buttons() & Qt::LeftButton) && d->selectionAllowed(index) && d->selectionModel) {
1758         setState(DragSelectingState);
1759         QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1760         if (d->ctrlDragSelectionFlag != QItemSelectionModel::NoUpdate && command.testFlag(QItemSelectionModel::Toggle)) {
1761             command &= ~QItemSelectionModel::Toggle;
1762             command |= d->ctrlDragSelectionFlag;
1763         }
1764 
1765         // Do the normalize ourselves, since QRect::normalized() is flawed
1766         QRect selectionRect = QRect(topLeft, bottomRight);
1767         setSelection(selectionRect, command);
1768 
1769         // set at the end because it might scroll the view
1770         if (index.isValid()
1771             && (index != d->selectionModel->currentIndex())
1772             && d->isIndexEnabled(index))
1773             d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1774     }
1775 }
1776 
1777 /*!
1778     This function is called with the given \a event when a mouse button is released,
1779     after a mouse press event on the widget. If a user presses the mouse inside your
1780     widget and then drags the mouse to another location before releasing the mouse button,
1781     your widget receives the release event. The function will emit the clicked() signal if an
1782     item was being pressed.
1783 */
mouseReleaseEvent(QMouseEvent * event)1784 void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
1785 {
1786     Q_D(QAbstractItemView);
1787 
1788     QPoint pos = event->pos();
1789     QPersistentModelIndex index = indexAt(pos);
1790 
1791     if (state() == EditingState) {
1792         if (d->isIndexValid(index)
1793             && d->isIndexEnabled(index)
1794             && d->sendDelegateEvent(index, event))
1795             update(index);
1796         return;
1797     }
1798 
1799     bool click = (index == d->pressedIndex && index.isValid());
1800     bool selectedClicked = click && (event->button() & Qt::LeftButton) && d->pressedAlreadySelected;
1801     EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
1802     bool edited = edit(index, trigger, event);
1803 
1804     d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
1805 
1806     if (d->selectionModel && d->noSelectionOnMousePress) {
1807         d->noSelectionOnMousePress = false;
1808         d->selectionModel->select(index, selectionCommand(index, event));
1809     }
1810 
1811     setState(NoState);
1812 
1813     if (click) {
1814         emit clicked(index);
1815         if (edited)
1816             return;
1817         QStyleOptionViewItemV4 option = d->viewOptionsV4();
1818         if (d->pressedAlreadySelected)
1819             option.state |= QStyle::State_Selected;
1820         if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
1821             emit activated(index);
1822     }
1823 }
1824 
1825 /*!
1826     This function is called with the given \a event when a mouse button is
1827     double clicked inside the widget. If the double-click is on a valid item it
1828     emits the doubleClicked() signal and calls edit() on the item.
1829 */
mouseDoubleClickEvent(QMouseEvent * event)1830 void QAbstractItemView::mouseDoubleClickEvent(QMouseEvent *event)
1831 {
1832     Q_D(QAbstractItemView);
1833 
1834     QModelIndex index = indexAt(event->pos());
1835     if (!index.isValid()
1836         || !d->isIndexEnabled(index)
1837         || (d->pressedIndex != index)) {
1838         QMouseEvent me(QEvent::MouseButtonPress,
1839                        event->pos(), event->button(),
1840                        event->buttons(), event->modifiers());
1841         mousePressEvent(&me);
1842         return;
1843     }
1844     // signal handlers may change the model
1845     QPersistentModelIndex persistent = index;
1846     emit doubleClicked(persistent);
1847     if ((event->button() & Qt::LeftButton) && !edit(persistent, DoubleClicked, event)
1848         && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this))
1849         emit activated(persistent);
1850 }
1851 
1852 #ifndef QT_NO_DRAGANDDROP
1853 
1854 /*!
1855     This function is called with the given \a event when a drag and drop operation enters
1856     the widget. If the drag is over a valid dropping place (e.g. over an item that
1857     accepts drops), the event is accepted; otherwise it is ignored.
1858 
1859     \sa dropEvent() startDrag()
1860 */
dragEnterEvent(QDragEnterEvent * event)1861 void QAbstractItemView::dragEnterEvent(QDragEnterEvent *event)
1862 {
1863     if (dragDropMode() == InternalMove
1864         && (event->source() != this|| !(event->possibleActions() & Qt::MoveAction)))
1865         return;
1866 
1867     if (d_func()->canDecode(event)) {
1868         event->accept();
1869         setState(DraggingState);
1870     } else {
1871         event->ignore();
1872     }
1873 }
1874 
1875 /*!
1876     This function is called continuously with the given \a event during a drag and
1877     drop operation over the widget. It can cause the view to scroll if, for example,
1878     the user drags a selection to view's right or bottom edge. In this case, the
1879     event will be accepted; otherwise it will be ignored.
1880 
1881     \sa dropEvent() startDrag()
1882 */
dragMoveEvent(QDragMoveEvent * event)1883 void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event)
1884 {
1885     Q_D(QAbstractItemView);
1886     if (dragDropMode() == InternalMove
1887         && (event->source() != this || !(event->possibleActions() & Qt::MoveAction)))
1888         return;
1889 
1890     // ignore by default
1891     event->ignore();
1892 
1893     QModelIndex index = indexAt(event->pos());
1894     d->hover = index;
1895     if (!d->droppingOnItself(event, index)
1896         && d->canDecode(event)) {
1897 
1898         if (index.isValid() && d->showDropIndicator) {
1899             QRect rect = visualRect(index);
1900             d->dropIndicatorPosition = d->position(event->pos(), rect, index);
1901             switch (d->dropIndicatorPosition) {
1902             case AboveItem:
1903                 if (d->isIndexDropEnabled(index.parent())) {
1904                     d->dropIndicatorRect = QRect(rect.left(), rect.top(), rect.width(), 0);
1905                     event->accept();
1906                 } else {
1907                     d->dropIndicatorRect = QRect();
1908                 }
1909                 break;
1910             case BelowItem:
1911                 if (d->isIndexDropEnabled(index.parent())) {
1912                     d->dropIndicatorRect = QRect(rect.left(), rect.bottom(), rect.width(), 0);
1913                     event->accept();
1914                 } else {
1915                     d->dropIndicatorRect = QRect();
1916                 }
1917                 break;
1918             case OnItem:
1919                 if (d->isIndexDropEnabled(index)) {
1920                     d->dropIndicatorRect = rect;
1921                     event->accept();
1922                 } else {
1923                     d->dropIndicatorRect = QRect();
1924                 }
1925                 break;
1926             case OnViewport:
1927                 d->dropIndicatorRect = QRect();
1928                 if (d->isIndexDropEnabled(rootIndex())) {
1929                     event->accept(); // allow dropping in empty areas
1930                 }
1931                 break;
1932             }
1933         } else {
1934             d->dropIndicatorRect = QRect();
1935             d->dropIndicatorPosition = OnViewport;
1936             if (d->isIndexDropEnabled(rootIndex())) {
1937                 event->accept(); // allow dropping in empty areas
1938             }
1939         }
1940         d->viewport->update();
1941     } // can decode
1942 
1943     if (d->shouldAutoScroll(event->pos()))
1944         startAutoScroll();
1945 }
1946 
1947 /*!
1948     \internal
1949     Return true if this is a move from ourself and \a index is a child of the selection that
1950     is being moved.
1951  */
droppingOnItself(QDropEvent * event,const QModelIndex & index)1952 bool QAbstractItemViewPrivate::droppingOnItself(QDropEvent *event, const QModelIndex &index)
1953 {
1954     Q_Q(QAbstractItemView);
1955     Qt::DropAction dropAction = event->dropAction();
1956     if (q->dragDropMode() == QAbstractItemView::InternalMove)
1957         dropAction = Qt::MoveAction;
1958     if (event->source() == q
1959         && event->possibleActions() & Qt::MoveAction
1960         && dropAction == Qt::MoveAction) {
1961         QModelIndexList selectedIndexes = q->selectedIndexes();
1962         QModelIndex child = index;
1963         while (child.isValid() && child != root) {
1964             if (selectedIndexes.contains(child))
1965                 return true;
1966             child = child.parent();
1967         }
1968     }
1969     return false;
1970 }
1971 
1972 /*!
1973     \fn void QAbstractItemView::dragLeaveEvent(QDragLeaveEvent *event)
1974 
1975     This function is called when the item being dragged leaves the view.
1976     The \a event describes the state of the drag and drop operation.
1977 */
dragLeaveEvent(QDragLeaveEvent *)1978 void QAbstractItemView::dragLeaveEvent(QDragLeaveEvent *)
1979 {
1980     Q_D(QAbstractItemView);
1981     stopAutoScroll();
1982     setState(NoState);
1983     d->hover = QModelIndex();
1984     d->viewport->update();
1985 }
1986 
1987 /*!
1988     This function is called with the given \a event when a drop event occurs over
1989     the widget. If the model accepts the even position the drop event is accepted;
1990     otherwise it is ignored.
1991 
1992     \sa startDrag()
1993 */
dropEvent(QDropEvent * event)1994 void QAbstractItemView::dropEvent(QDropEvent *event)
1995 {
1996     Q_D(QAbstractItemView);
1997     if (dragDropMode() == InternalMove) {
1998         if (event->source() != this || !(event->possibleActions() & Qt::MoveAction))
1999             return;
2000     }
2001 
2002     QModelIndex index;
2003     int col = -1;
2004     int row = -1;
2005     if (d->dropOn(event, &row, &col, &index)) {
2006         if (d->model->dropMimeData(event->mimeData(),
2007             dragDropMode() == InternalMove ? Qt::MoveAction : event->dropAction(), row, col, index)) {
2008                 if (dragDropMode() == InternalMove)
2009                     event->setDropAction(Qt::MoveAction);
2010                 event->accept();
2011         }
2012     }
2013     stopAutoScroll();
2014     setState(NoState);
2015     d->viewport->update();
2016 }
2017 
2018 /*!
2019     If the event hasn't already been accepted, determines the index to drop on.
2020 
2021     if (row == -1 && col == -1)
2022         // append to this drop index
2023     else
2024         // place at row, col in drop index
2025 
2026     If it returns true a drop can be done, and dropRow, dropCol and dropIndex reflects the position of the drop.
2027     \internal
2028   */
dropOn(QDropEvent * event,int * dropRow,int * dropCol,QModelIndex * dropIndex)2029 bool QAbstractItemViewPrivate::dropOn(QDropEvent *event, int *dropRow, int *dropCol, QModelIndex *dropIndex)
2030 {
2031     Q_Q(QAbstractItemView);
2032     if (event->isAccepted())
2033         return false;
2034 
2035     QModelIndex index;
2036     // rootIndex() (i.e. the viewport) might be a valid index
2037     if (viewport->rect().contains(event->pos())) {
2038         index = q->indexAt(event->pos());
2039         if (!index.isValid() || !q->visualRect(index).contains(event->pos()))
2040             index = root;
2041     }
2042 
2043     // If we are allowed to do the drop
2044     if (model->supportedDropActions() & event->dropAction()) {
2045         int row = -1;
2046         int col = -1;
2047         if (index != root) {
2048             dropIndicatorPosition = position(event->pos(), q->visualRect(index), index);
2049             switch (dropIndicatorPosition) {
2050             case QAbstractItemView::AboveItem:
2051                 row = index.row();
2052                 col = index.column();
2053                 index = index.parent();
2054                 break;
2055             case QAbstractItemView::BelowItem:
2056                 row = index.row() + 1;
2057                 col = index.column();
2058                 index = index.parent();
2059                 break;
2060             case QAbstractItemView::OnItem:
2061             case QAbstractItemView::OnViewport:
2062                 break;
2063             }
2064         } else {
2065             dropIndicatorPosition = QAbstractItemView::OnViewport;
2066         }
2067         *dropIndex = index;
2068         *dropRow = row;
2069         *dropCol = col;
2070         if (!droppingOnItself(event, index))
2071             return true;
2072     }
2073     return false;
2074 }
2075 
2076 QAbstractItemView::DropIndicatorPosition
position(const QPoint & pos,const QRect & rect,const QModelIndex & index) const2077 QAbstractItemViewPrivate::position(const QPoint &pos, const QRect &rect, const QModelIndex &index) const
2078 {
2079     QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2080     if (!overwrite) {
2081         const int margin = 2;
2082         if (pos.y() - rect.top() < margin) {
2083             r = QAbstractItemView::AboveItem;
2084         } else if (rect.bottom() - pos.y() < margin) {
2085             r = QAbstractItemView::BelowItem;
2086         } else if (rect.contains(pos, true)) {
2087             r = QAbstractItemView::OnItem;
2088         }
2089     } else {
2090         QRect touchingRect = rect;
2091         touchingRect.adjust(-1, -1, 1, 1);
2092         if (touchingRect.contains(pos, false)) {
2093             r = QAbstractItemView::OnItem;
2094         }
2095     }
2096 
2097     if (r == QAbstractItemView::OnItem && (!(model->flags(index) & Qt::ItemIsDropEnabled)))
2098         r = pos.y() < rect.center().y() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2099 
2100     return r;
2101 }
2102 
2103 #endif // QT_NO_DRAGANDDROP
2104 
2105 /*!
2106     This function is called with the given \a event when the widget obtains the focus.
2107     By default, the event is ignored.
2108 
2109     \sa setFocus(), focusOutEvent()
2110 */
focusInEvent(QFocusEvent * event)2111 void QAbstractItemView::focusInEvent(QFocusEvent *event)
2112 {
2113     Q_D(QAbstractItemView);
2114     QAbstractScrollArea::focusInEvent(event);
2115 
2116     const QItemSelectionModel* model = selectionModel();
2117     const bool currentIndexValid = currentIndex().isValid();
2118 
2119     if (model
2120         && !d->currentIndexSet
2121         && !currentIndexValid) {
2122         bool autoScroll = d->autoScroll;
2123         d->autoScroll = false;
2124         QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index
2125         if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason)
2126             selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
2127         d->autoScroll = autoScroll;
2128     }
2129 
2130     if (model && currentIndexValid) {
2131         if (currentIndex().flags() != Qt::ItemIsEditable)
2132             setAttribute(Qt::WA_InputMethodEnabled, false);
2133         else
2134             setAttribute(Qt::WA_InputMethodEnabled);
2135     }
2136 
2137     if (!currentIndexValid)
2138         setAttribute(Qt::WA_InputMethodEnabled, false);
2139 
2140     d->viewport->update();
2141 }
2142 
2143 /*!
2144     This function is called with the given \a event when the widget
2145     looses the focus. By default, the event is ignored.
2146 
2147     \sa clearFocus(), focusInEvent()
2148 */
focusOutEvent(QFocusEvent * event)2149 void QAbstractItemView::focusOutEvent(QFocusEvent *event)
2150 {
2151     Q_D(QAbstractItemView);
2152     QAbstractScrollArea::focusOutEvent(event);
2153     d->viewport->update();
2154 
2155 #ifdef QT_SOFTKEYS_ENABLED
2156     if(!hasEditFocus())
2157         removeAction(d->doneSoftKey);
2158 #endif
2159 }
2160 
2161 /*!
2162     This function is called with the given \a event when a key event is sent to
2163     the widget. The default implementation handles basic cursor movement, e.g. Up,
2164     Down, Left, Right, Home, PageUp, and PageDown; the activated() signal is
2165     emitted if the current index is valid and the activation key is pressed
2166     (e.g. Enter or Return, depending on the platform).
2167     This function is where editing is initiated by key press, e.g. if F2 is
2168     pressed.
2169 
2170     \sa edit(), moveCursor(), keyboardSearch(), tabKeyNavigation
2171 */
keyPressEvent(QKeyEvent * event)2172 void QAbstractItemView::keyPressEvent(QKeyEvent *event)
2173 {
2174     Q_D(QAbstractItemView);
2175     d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
2176 
2177 #ifdef QT_KEYPAD_NAVIGATION
2178     switch (event->key()) {
2179     case Qt::Key_Select:
2180         if (QApplication::keypadNavigationEnabled()) {
2181             if (!hasEditFocus()) {
2182                 setEditFocus(true);
2183 #ifdef QT_SOFTKEYS_ENABLED
2184                 // If we can't keypad navigate to any direction, there is no sense to add
2185                 // "Done" softkey, since it basically does nothing when there is
2186                 // only one widget in screen
2187                 if(QWidgetPrivate::canKeypadNavigate(Qt::Horizontal)
2188                         || QWidgetPrivate::canKeypadNavigate(Qt::Vertical))
2189                     addAction(d->doneSoftKey);
2190 #endif
2191                 return;
2192             }
2193         }
2194         break;
2195     case Qt::Key_Back:
2196         if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
2197 #ifdef QT_SOFTKEYS_ENABLED
2198             removeAction(d->doneSoftKey);
2199 #endif
2200             setEditFocus(false);
2201         } else {
2202             event->ignore();
2203         }
2204         return;
2205     case Qt::Key_Down:
2206     case Qt::Key_Up:
2207         // Let's ignore vertical navigation events, only if there is no other widget
2208         // what can take the focus in vertical direction. This means widget can handle navigation events
2209         // even the widget don't have edit focus, and there is no other widget in requested direction.
2210         if(QApplication::keypadNavigationEnabled() && !hasEditFocus()
2211                 && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2212             event->ignore();
2213             return;
2214         }
2215         break;
2216     case Qt::Key_Left:
2217     case Qt::Key_Right:
2218         // Similar logic as in up and down events
2219         if(QApplication::keypadNavigationEnabled() && !hasEditFocus()
2220                 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this))) {
2221             event->ignore();
2222             return;
2223         }
2224         break;
2225     default:
2226         if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
2227             event->ignore();
2228             return;
2229         }
2230     }
2231 #endif
2232 
2233 #if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
2234     if (event == QKeySequence::Copy) {
2235         QVariant variant;
2236         if (d->model)
2237             variant = d->model->data(currentIndex(), Qt::DisplayRole);
2238         if (variant.type() == QVariant::String)
2239             QApplication::clipboard()->setText(variant.toString());
2240         event->accept();
2241     }
2242 #endif
2243 
2244     QPersistentModelIndex newCurrent;
2245     d->moveCursorUpdatedView = false;
2246     switch (event->key()) {
2247     case Qt::Key_Down:
2248         newCurrent = moveCursor(MoveDown, event->modifiers());
2249         break;
2250     case Qt::Key_Up:
2251         newCurrent = moveCursor(MoveUp, event->modifiers());
2252         break;
2253     case Qt::Key_Left:
2254         newCurrent = moveCursor(MoveLeft, event->modifiers());
2255         break;
2256     case Qt::Key_Right:
2257         newCurrent = moveCursor(MoveRight, event->modifiers());
2258         break;
2259     case Qt::Key_Home:
2260         newCurrent = moveCursor(MoveHome, event->modifiers());
2261         break;
2262     case Qt::Key_End:
2263         newCurrent = moveCursor(MoveEnd, event->modifiers());
2264         break;
2265     case Qt::Key_PageUp:
2266         newCurrent = moveCursor(MovePageUp, event->modifiers());
2267         break;
2268     case Qt::Key_PageDown:
2269         newCurrent = moveCursor(MovePageDown, event->modifiers());
2270         break;
2271     case Qt::Key_Tab:
2272         if (d->tabKeyNavigation)
2273             newCurrent = moveCursor(MoveNext, event->modifiers());
2274         break;
2275     case Qt::Key_Backtab:
2276         if (d->tabKeyNavigation)
2277             newCurrent = moveCursor(MovePrevious, event->modifiers());
2278         break;
2279     }
2280 
2281     QPersistentModelIndex oldCurrent = currentIndex();
2282     if (newCurrent != oldCurrent && newCurrent.isValid() && d->isIndexEnabled(newCurrent)) {
2283         if (!hasFocus() && QApplication::focusWidget() == indexWidget(oldCurrent))
2284             setFocus();
2285         QItemSelectionModel::SelectionFlags command = selectionCommand(newCurrent, event);
2286         if (command != QItemSelectionModel::NoUpdate
2287              || style()->styleHint(QStyle::SH_ItemView_MovementWithoutUpdatingSelection, 0, this)) {
2288             // note that we don't check if the new current index is enabled because moveCursor() makes sure it is
2289             if (command & QItemSelectionModel::Current) {
2290                 d->selectionModel->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
2291                 if (!indexAt(d->pressedPosition - d->offset()).isValid())
2292                     d->pressedPosition = visualRect(oldCurrent).center() + d->offset();
2293                 QRect rect(d->pressedPosition - d->offset(), visualRect(newCurrent).center());
2294                 setSelection(rect, command);
2295             } else {
2296                 d->selectionModel->setCurrentIndex(newCurrent, command);
2297                 d->pressedPosition = visualRect(newCurrent).center() + d->offset();
2298                 if (newCurrent.isValid()) {
2299                     // We copy the same behaviour as for mousePressEvent().
2300                     QRect rect(d->pressedPosition - d->offset(), QSize(1, 1));
2301                     setSelection(rect, command);
2302                 }
2303             }
2304             event->accept();
2305             return;
2306         }
2307     }
2308 
2309     switch (event->key()) {
2310     // ignored keys
2311     case Qt::Key_Down:
2312     case Qt::Key_Up:
2313 #ifdef QT_KEYPAD_NAVIGATION
2314         if (QApplication::keypadNavigationEnabled() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2315             event->accept(); // don't change focus
2316             break;
2317         }
2318 #endif
2319     case Qt::Key_Left:
2320     case Qt::Key_Right:
2321 #ifdef QT_KEYPAD_NAVIGATION
2322         if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
2323                 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal)
2324                 || (QWidgetPrivate::inTabWidget(this) && d->model->columnCount(d->root) > 1))) {
2325             event->accept(); // don't change focus
2326             break;
2327         }
2328 #endif // QT_KEYPAD_NAVIGATION
2329     case Qt::Key_Home:
2330     case Qt::Key_End:
2331     case Qt::Key_PageUp:
2332     case Qt::Key_PageDown:
2333     case Qt::Key_Escape:
2334     case Qt::Key_Shift:
2335     case Qt::Key_Control:
2336     case Qt::Key_Delete:
2337     case Qt::Key_Backspace:
2338         event->ignore();
2339         break;
2340     case Qt::Key_Space:
2341     case Qt::Key_Select:
2342         if (!edit(currentIndex(), AnyKeyPressed, event) && d->selectionModel)
2343             d->selectionModel->select(currentIndex(), selectionCommand(currentIndex(), event));
2344 #ifdef QT_KEYPAD_NAVIGATION
2345         if ( event->key()==Qt::Key_Select ) {
2346             // Also do Key_Enter action.
2347             if (currentIndex().isValid()) {
2348                 if (state() != EditingState)
2349                     emit activated(currentIndex());
2350             } else {
2351                 event->ignore();
2352             }
2353         }
2354 #endif
2355         break;
2356 #ifdef Q_WS_MAC
2357     case Qt::Key_Enter:
2358     case Qt::Key_Return:
2359         // Propagate the enter if you couldn't edit the item and there are no
2360         // current editors (if there are editors, the event was most likely propagated from it).
2361         if (!edit(currentIndex(), EditKeyPressed, event) && d->editorIndexHash.isEmpty())
2362             event->ignore();
2363         break;
2364 #else
2365     case Qt::Key_F2:
2366         if (!edit(currentIndex(), EditKeyPressed, event))
2367             event->ignore();
2368         break;
2369     case Qt::Key_Enter:
2370     case Qt::Key_Return:
2371         // ### we can't open the editor on enter, becuse
2372         // some widgets will forward the enter event back
2373         // to the viewport, starting an endless loop
2374         if (state() != EditingState || hasFocus()) {
2375             if (currentIndex().isValid())
2376                 emit activated(currentIndex());
2377             event->ignore();
2378         }
2379         break;
2380 #endif
2381     case Qt::Key_A:
2382         if (event->modifiers() & Qt::ControlModifier) {
2383             selectAll();
2384             break;
2385         }
2386     default: {
2387 #ifdef Q_WS_MAC
2388         if (event->key() == Qt::Key_O && event->modifiers() & Qt::ControlModifier && currentIndex().isValid()) {
2389             emit activated(currentIndex());
2390             break;
2391         }
2392 #endif
2393         bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier));
2394         if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) {
2395             keyboardSearch(event->text());
2396             event->accept();
2397         } else {
2398             event->ignore();
2399         }
2400         break; }
2401     }
2402     if (d->moveCursorUpdatedView)
2403         event->accept();
2404 }
2405 
2406 /*!
2407     This function is called with the given \a event when a resize event is sent to
2408     the widget.
2409 
2410     \sa QWidget::resizeEvent()
2411 */
resizeEvent(QResizeEvent * event)2412 void QAbstractItemView::resizeEvent(QResizeEvent *event)
2413 {
2414     QAbstractScrollArea::resizeEvent(event);
2415     updateGeometries();
2416 }
2417 
2418 /*!
2419   This function is called with the given \a event when a timer event is sent
2420   to the widget.
2421 
2422   \sa QObject::timerEvent()
2423 */
timerEvent(QTimerEvent * event)2424 void QAbstractItemView::timerEvent(QTimerEvent *event)
2425 {
2426     Q_D(QAbstractItemView);
2427     if (event->timerId() == d->fetchMoreTimer.timerId())
2428         d->fetchMore();
2429     else if (event->timerId() == d->delayedReset.timerId())
2430         reset();
2431     else if (event->timerId() == d->autoScrollTimer.timerId())
2432         doAutoScroll();
2433     else if (event->timerId() == d->updateTimer.timerId())
2434         d->updateDirtyRegion();
2435     else if (event->timerId() == d->delayedEditing.timerId()) {
2436         d->delayedEditing.stop();
2437         edit(currentIndex());
2438     } else if (event->timerId() == d->delayedLayout.timerId()) {
2439         d->delayedLayout.stop();
2440         if (isVisible()) {
2441             d->interruptDelayedItemsLayout();
2442             doItemsLayout();
2443             const QModelIndex current = currentIndex();
2444             if (current.isValid() && d->state == QAbstractItemView::EditingState)
2445                 scrollTo(current);
2446         }
2447     } else if (event->timerId() == d->delayedAutoScroll.timerId()) {
2448         d->delayedAutoScroll.stop();
2449         //end of the timer: if the current item is still the same as the one when the mouse press occurred
2450         //we only get here if there was no double click
2451         if (d->pressedIndex.isValid() && d->pressedIndex == currentIndex())
2452             scrollTo(d->pressedIndex);
2453     }
2454 }
2455 
2456 /*!
2457     \reimp
2458 */
inputMethodEvent(QInputMethodEvent * event)2459 void QAbstractItemView::inputMethodEvent(QInputMethodEvent *event)
2460 {
2461     if (event->commitString().isEmpty() && event->preeditString().isEmpty()) {
2462         event->ignore();
2463         return;
2464     }
2465     if (!edit(currentIndex(), AnyKeyPressed, event)) {
2466         if (!event->commitString().isEmpty())
2467             keyboardSearch(event->commitString());
2468         event->ignore();
2469     }
2470 }
2471 
2472 #ifndef QT_NO_DRAGANDDROP
2473 /*!
2474     \enum QAbstractItemView::DropIndicatorPosition
2475 
2476     This enum indicates the position of the drop indicator in
2477     relation to the index at the current mouse position:
2478 
2479     \value OnItem  The item will be dropped on the index.
2480 
2481     \value AboveItem  The item will be dropped above the index.
2482 
2483     \value BelowItem  The item will be dropped below the index.
2484 
2485     \value OnViewport  The item will be dropped onto a region of the viewport with
2486     no items. The way each view handles items dropped onto the viewport depends on
2487     the behavior of the underlying model in use.
2488 */
2489 
2490 
2491 /*!
2492     \since 4.1
2493 
2494     Returns the position of the drop indicator in relation to the closest item.
2495 */
dropIndicatorPosition() const2496 QAbstractItemView::DropIndicatorPosition QAbstractItemView::dropIndicatorPosition() const
2497 {
2498     Q_D(const QAbstractItemView);
2499     return d->dropIndicatorPosition;
2500 }
2501 #endif
2502 
2503 /*!
2504     This convenience function returns a list of all selected and
2505     non-hidden item indexes in the view. The list contains no
2506     duplicates, and is not sorted.
2507 
2508     \sa QItemSelectionModel::selectedIndexes()
2509 */
selectedIndexes() const2510 QModelIndexList QAbstractItemView::selectedIndexes() const
2511 {
2512     Q_D(const QAbstractItemView);
2513     QModelIndexList indexes;
2514     if (d->selectionModel) {
2515         indexes = d->selectionModel->selectedIndexes();
2516         QList<QModelIndex>::iterator it = indexes.begin();
2517         while (it != indexes.end())
2518             if (isIndexHidden(*it))
2519                 it = indexes.erase(it);
2520             else
2521                 ++it;
2522     }
2523     return indexes;
2524 }
2525 
2526 /*!
2527     Starts editing the item at \a index, creating an editor if
2528     necessary, and returns true if the view's \l{State} is now
2529     EditingState; otherwise returns false.
2530 
2531     The action that caused the editing process is described by
2532     \a trigger, and the associated event is specified by \a event.
2533 
2534     Editing can be forced by specifying the \a trigger to be
2535     QAbstractItemView::AllEditTriggers.
2536 
2537     \sa closeEditor()
2538 */
edit(const QModelIndex & index,EditTrigger trigger,QEvent * event)2539 bool QAbstractItemView::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
2540 {
2541     Q_D(QAbstractItemView);
2542 
2543     if (!d->isIndexValid(index))
2544         return false;
2545 
2546     if (QWidget *w = (d->persistent.isEmpty() ? static_cast<QWidget*>(0) : d->editorForIndex(index).widget.data())) {
2547         if (w->focusPolicy() == Qt::NoFocus)
2548             return false;
2549         w->setFocus();
2550         return true;
2551     }
2552 
2553     if (trigger == DoubleClicked) {
2554         d->delayedEditing.stop();
2555         d->delayedAutoScroll.stop();
2556     } else if (trigger == CurrentChanged) {
2557         d->delayedEditing.stop();
2558     }
2559 
2560     if (d->sendDelegateEvent(index, event)) {
2561         update(index);
2562         return true;
2563     }
2564 
2565     // save the previous trigger before updating
2566     EditTriggers lastTrigger = d->lastTrigger;
2567     d->lastTrigger = trigger;
2568 
2569     if (!d->shouldEdit(trigger, d->model->buddy(index)))
2570         return false;
2571 
2572     if (d->delayedEditing.isActive())
2573         return false;
2574 
2575     // we will receive a mouseButtonReleaseEvent after a
2576     // mouseDoubleClickEvent, so we need to check the previous trigger
2577     if (lastTrigger == DoubleClicked && trigger == SelectedClicked)
2578         return false;
2579 
2580     // we may get a double click event later
2581     if (trigger == SelectedClicked)
2582         d->delayedEditing.start(QApplication::doubleClickInterval(), this);
2583     else
2584         d->openEditor(index, d->shouldForwardEvent(trigger, event) ? event : 0);
2585 
2586     return true;
2587 }
2588 
2589 /*!
2590     \internal
2591     Updates the data shown in the open editor widgets in the view.
2592 */
updateEditorData()2593 void QAbstractItemView::updateEditorData()
2594 {
2595     Q_D(QAbstractItemView);
2596     d->updateEditorData(QModelIndex(), QModelIndex());
2597 }
2598 
2599 /*!
2600     \internal
2601     Updates the geometry of the open editor widgets in the view.
2602 */
updateEditorGeometries()2603 void QAbstractItemView::updateEditorGeometries()
2604 {
2605     Q_D(QAbstractItemView);
2606     if(d->editorIndexHash.isEmpty())
2607         return;
2608     QStyleOptionViewItemV4 option = d->viewOptionsV4();
2609     QEditorIndexHash::iterator it = d->editorIndexHash.begin();
2610     QWidgetList editorsToRelease;
2611     QWidgetList editorsToHide;
2612     while (it != d->editorIndexHash.end()) {
2613         QModelIndex index = it.value();
2614         QWidget *editor = it.key();
2615         if (index.isValid() && editor) {
2616             option.rect = visualRect(index);
2617             if (option.rect.isValid()) {
2618                 editor->show();
2619                 QAbstractItemDelegate *delegate = d->delegateForIndex(index);
2620                 if (delegate)
2621                     delegate->updateEditorGeometry(editor, option, index);
2622             } else {
2623                 editorsToHide << editor;
2624             }
2625             ++it;
2626         } else {
2627             d->indexEditorHash.remove(it.value());
2628             it = d->editorIndexHash.erase(it);
2629             editorsToRelease << editor;
2630         }
2631     }
2632 
2633     //we hide and release the editor outside of the loop because it might change the focus and try
2634     //to change the editors hashes.
2635     for (int i = 0; i < editorsToHide.count(); ++i) {
2636         editorsToHide.at(i)->hide();
2637     }
2638     for (int i = 0; i < editorsToRelease.count(); ++i) {
2639         d->releaseEditor(editorsToRelease.at(i));
2640     }
2641 }
2642 
2643 /*!
2644     \since 4.4
2645 
2646     Updates the geometry of the child widgets of the view.
2647 */
updateGeometries()2648 void QAbstractItemView::updateGeometries()
2649 {
2650     updateEditorGeometries();
2651     d_func()->fetchMoreTimer.start(0, this); //fetch more later
2652 }
2653 
2654 /*!
2655     \internal
2656 */
verticalScrollbarValueChanged(int value)2657 void QAbstractItemView::verticalScrollbarValueChanged(int value)
2658 {
2659     Q_D(QAbstractItemView);
2660     if (verticalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2661         d->model->fetchMore(d->root);
2662     QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2663     if (viewport()->rect().contains(posInVp))
2664         d->checkMouseMove(posInVp);
2665 }
2666 
2667 /*!
2668     \internal
2669 */
horizontalScrollbarValueChanged(int value)2670 void QAbstractItemView::horizontalScrollbarValueChanged(int value)
2671 {
2672     Q_D(QAbstractItemView);
2673     if (horizontalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2674         d->model->fetchMore(d->root);
2675     QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2676     if (viewport()->rect().contains(posInVp))
2677         d->checkMouseMove(posInVp);
2678 }
2679 
2680 /*!
2681     \internal
2682 */
verticalScrollbarAction(int)2683 void QAbstractItemView::verticalScrollbarAction(int)
2684 {
2685     //do nothing
2686 }
2687 
2688 /*!
2689     \internal
2690 */
horizontalScrollbarAction(int)2691 void QAbstractItemView::horizontalScrollbarAction(int)
2692 {
2693     //do nothing
2694 }
2695 
2696 /*!
2697     Closes the given \a editor, and releases it. The \a hint is
2698     used to specify how the view should respond to the end of the editing
2699     operation. For example, the hint may indicate that the next item in
2700     the view should be opened for editing.
2701 
2702     \sa edit(), commitData()
2703 */
2704 
closeEditor(QWidget * editor,QAbstractItemDelegate::EndEditHint hint)2705 void QAbstractItemView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
2706 {
2707     Q_D(QAbstractItemView);
2708 
2709     // Close the editor
2710     if (editor) {
2711         bool isPersistent = d->persistent.contains(editor);
2712         bool hadFocus = editor->hasFocus();
2713         QModelIndex index = d->indexForEditor(editor);
2714         if (!index.isValid())
2715             return; // the editor was not registered
2716 
2717         if (!isPersistent) {
2718             setState(NoState);
2719             QModelIndex index = d->indexForEditor(editor);
2720             editor->removeEventFilter(d->delegateForIndex(index));
2721             d->removeEditor(editor);
2722         }
2723         if (hadFocus)
2724             setFocus(); // this will send a focusLost event to the editor
2725         else
2726             d->checkPersistentEditorFocus();
2727 
2728         QPointer<QWidget> ed = editor;
2729         QApplication::sendPostedEvents(editor, 0);
2730         editor = ed;
2731 
2732         if (!isPersistent && editor)
2733             d->releaseEditor(editor);
2734     }
2735 
2736     // The EndEditHint part
2737     QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect
2738                                                 | d->selectionBehaviorFlags();
2739     switch (hint) {
2740     case QAbstractItemDelegate::EditNextItem: {
2741         QModelIndex index = moveCursor(MoveNext, Qt::NoModifier);
2742         if (index.isValid()) {
2743             QPersistentModelIndex persistent(index);
2744             d->selectionModel->setCurrentIndex(persistent, flags);
2745             // currentChanged signal would have already started editing
2746             if (index.flags() & Qt::ItemIsEditable
2747                 && (!(editTriggers() & QAbstractItemView::CurrentChanged)))
2748                 edit(persistent);
2749         } break; }
2750     case QAbstractItemDelegate::EditPreviousItem: {
2751         QModelIndex index = moveCursor(MovePrevious, Qt::NoModifier);
2752         if (index.isValid()) {
2753             QPersistentModelIndex persistent(index);
2754             d->selectionModel->setCurrentIndex(persistent, flags);
2755             // currentChanged signal would have already started editing
2756             if (index.flags() & Qt::ItemIsEditable
2757                 && (!(editTriggers() & QAbstractItemView::CurrentChanged)))
2758                 edit(persistent);
2759         } break; }
2760     case QAbstractItemDelegate::SubmitModelCache:
2761         d->model->submit();
2762         break;
2763     case QAbstractItemDelegate::RevertModelCache:
2764         d->model->revert();
2765         break;
2766     default:
2767         break;
2768     }
2769 }
2770 
2771 /*!
2772     Commit the data in the \a editor to the model.
2773 
2774     \sa closeEditor()
2775 */
commitData(QWidget * editor)2776 void QAbstractItemView::commitData(QWidget *editor)
2777 {
2778     Q_D(QAbstractItemView);
2779     if (!editor || !d->itemDelegate || d->currentlyCommittingEditor)
2780         return;
2781     QModelIndex index = d->indexForEditor(editor);
2782     if (!index.isValid())
2783         return;
2784     d->currentlyCommittingEditor = editor;
2785     QAbstractItemDelegate *delegate = d->delegateForIndex(index);
2786     editor->removeEventFilter(delegate);
2787     delegate->setModelData(editor, d->model, index);
2788     editor->installEventFilter(delegate);
2789     d->currentlyCommittingEditor = 0;
2790 }
2791 
2792 /*!
2793     This function is called when the given \a editor has been destroyed.
2794 
2795     \sa closeEditor()
2796 */
editorDestroyed(QObject * editor)2797 void QAbstractItemView::editorDestroyed(QObject *editor)
2798 {
2799     Q_D(QAbstractItemView);
2800     QWidget *w = qobject_cast<QWidget*>(editor);
2801     d->removeEditor(w);
2802     d->persistent.remove(w);
2803     if (state() == EditingState)
2804         setState(NoState);
2805 }
2806 
2807 /*!
2808     \obsolete
2809     Sets the horizontal scroll bar's steps per item to \a steps.
2810 
2811     This is the number of steps used by the horizontal scroll bar to
2812     represent the width of an item.
2813 
2814     Note that if the view has a horizontal header, the item steps
2815     will be ignored and the header section size will be used instead.
2816 
2817     \sa horizontalStepsPerItem() setVerticalStepsPerItem()
2818 */
setHorizontalStepsPerItem(int steps)2819 void QAbstractItemView::setHorizontalStepsPerItem(int steps)
2820 {
2821     Q_UNUSED(steps)
2822     // do nothing
2823 }
2824 
2825 /*!
2826     \obsolete
2827     Returns the horizontal scroll bar's steps per item.
2828 
2829     \sa setHorizontalStepsPerItem() verticalStepsPerItem()
2830 */
horizontalStepsPerItem() const2831 int QAbstractItemView::horizontalStepsPerItem() const
2832 {
2833     return 1;
2834 }
2835 
2836 /*!
2837     \obsolete
2838     Sets the vertical scroll bar's steps per item to \a steps.
2839 
2840     This is the number of steps used by the vertical scroll bar to
2841     represent the height of an item.
2842 
2843     Note that if the view has a vertical header, the item steps
2844     will be ignored and the header section size will be used instead.
2845 
2846     \sa verticalStepsPerItem() setHorizontalStepsPerItem()
2847 */
setVerticalStepsPerItem(int steps)2848 void QAbstractItemView::setVerticalStepsPerItem(int steps)
2849 {
2850     Q_UNUSED(steps)
2851     // do nothing
2852 }
2853 
2854 /*!
2855     \obsolete
2856     Returns the vertical scroll bar's steps per item.
2857 
2858     \sa setVerticalStepsPerItem() horizontalStepsPerItem()
2859 */
verticalStepsPerItem() const2860 int QAbstractItemView::verticalStepsPerItem() const
2861 {
2862     return 1;
2863 }
2864 
2865 /*!
2866     Moves to and selects the item best matching the string \a search.
2867     If no item is found nothing happens.
2868 
2869     In the default implementation, the search is reset if \a search is empty, or
2870     the time interval since the last search has exceeded
2871     QApplication::keyboardInputInterval().
2872 */
keyboardSearch(const QString & search)2873 void QAbstractItemView::keyboardSearch(const QString &search)
2874 {
2875     Q_D(QAbstractItemView);
2876     if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
2877         return;
2878 
2879     QModelIndex start = currentIndex().isValid() ? currentIndex()
2880                         : d->model->index(0, 0, d->root);
2881     bool skipRow = false;
2882     bool keyboardTimeWasValid = d->keyboardInputTime.isValid();
2883     qint64 keyboardInputTimeElapsed = d->keyboardInputTime.restart();
2884     if (search.isEmpty() || !keyboardTimeWasValid
2885         || keyboardInputTimeElapsed > QApplication::keyboardInputInterval()) {
2886         d->keyboardInput = search;
2887         skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0)
2888     } else {
2889         d->keyboardInput += search;
2890     }
2891 
2892     // special case for searches with same key like 'aaaaa'
2893     bool sameKey = false;
2894     if (d->keyboardInput.length() > 1) {
2895         int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1));
2896         sameKey = (c == d->keyboardInput.length());
2897         if (sameKey)
2898             skipRow = true;
2899     }
2900 
2901     // skip if we are searching for the same key or a new search started
2902     if (skipRow) {
2903         QModelIndex parent = start.parent();
2904         int newRow = (start.row() < d->model->rowCount(parent) - 1) ? start.row() + 1 : 0;
2905         start = d->model->index(newRow, start.column(), parent);
2906     }
2907 
2908     // search from start with wraparound
2909     const QString searchString = sameKey ? QString(d->keyboardInput.at(0)) : d->keyboardInput;
2910     QModelIndex current = start;
2911     QModelIndexList match;
2912     QModelIndex firstMatch;
2913     QModelIndex startMatch;
2914     QModelIndexList previous;
2915     do {
2916         match = d->model->match(current, Qt::DisplayRole, searchString);
2917         if (match == previous)
2918             break;
2919         firstMatch = match.value(0);
2920         previous = match;
2921         if (firstMatch.isValid()) {
2922             if (d->isIndexEnabled(firstMatch)) {
2923                 setCurrentIndex(firstMatch);
2924                 break;
2925             }
2926             int row = firstMatch.row() + 1;
2927             if (row >= d->model->rowCount(firstMatch.parent()))
2928                 row = 0;
2929             current = firstMatch.sibling(row, firstMatch.column());
2930 
2931             //avoid infinite loop if all the matching items are disabled.
2932             if (!startMatch.isValid())
2933                 startMatch = firstMatch;
2934             else if (startMatch == firstMatch)
2935                 break;
2936         }
2937     } while (current != start && firstMatch.isValid());
2938 }
2939 
2940 /*!
2941     Returns the size hint for the item with the specified \a index or
2942     an invalid size for invalid indexes.
2943 
2944     \sa sizeHintForRow(), sizeHintForColumn()
2945 */
sizeHintForIndex(const QModelIndex & index) const2946 QSize QAbstractItemView::sizeHintForIndex(const QModelIndex &index) const
2947 {
2948     Q_D(const QAbstractItemView);
2949     if (!d->isIndexValid(index) || !d->itemDelegate)
2950         return QSize();
2951     return d->delegateForIndex(index)->sizeHint(d->viewOptionsV4(), index);
2952 }
2953 
2954 /*!
2955     Returns the height size hint for the specified \a row or -1 if
2956     there is no model.
2957 
2958     The returned height is calculated using the size hints of the
2959     given \a row's items, i.e. the returned value is the maximum
2960     height among the items. Note that to control the height of a row,
2961     you must reimplement the QAbstractItemDelegate::sizeHint()
2962     function.
2963 
2964     This function is used in views with a vertical header to find the
2965     size hint for a header section based on the contents of the given
2966     \a row.
2967 
2968     \sa sizeHintForColumn()
2969 */
sizeHintForRow(int row) const2970 int QAbstractItemView::sizeHintForRow(int row) const
2971 {
2972     Q_D(const QAbstractItemView);
2973 
2974     if (row < 0 || row >= d->model->rowCount(d->root))
2975         return -1;
2976 
2977     ensurePolished();
2978 
2979     QStyleOptionViewItemV4 option = d->viewOptionsV4();
2980     int height = 0;
2981     int colCount = d->model->columnCount(d->root);
2982     QModelIndex index;
2983     for (int c = 0; c < colCount; ++c) {
2984         index = d->model->index(row, c, d->root);
2985         if (QWidget *editor = d->editorForIndex(index).widget.data())
2986             height = qMax(height, editor->height());
2987         int hint = d->delegateForIndex(index)->sizeHint(option, index).height();
2988         height = qMax(height, hint);
2989     }
2990     return height;
2991 }
2992 
2993 /*!
2994     Returns the width size hint for the specified \a column or -1 if there is no model.
2995 
2996     This function is used in views with a horizontal header to find the size hint for
2997     a header section based on the contents of the given \a column.
2998 
2999     \sa sizeHintForRow()
3000 */
sizeHintForColumn(int column) const3001 int QAbstractItemView::sizeHintForColumn(int column) const
3002 {
3003     Q_D(const QAbstractItemView);
3004 
3005     if (column < 0 || column >= d->model->columnCount(d->root))
3006         return -1;
3007 
3008     ensurePolished();
3009 
3010     QStyleOptionViewItemV4 option = d->viewOptionsV4();
3011     int width = 0;
3012     int rows = d->model->rowCount(d->root);
3013     QModelIndex index;
3014     for (int r = 0; r < rows; ++r) {
3015         index = d->model->index(r, column, d->root);
3016         if (QWidget *editor = d->editorForIndex(index).widget.data())
3017             width = qMax(width, editor->sizeHint().width());
3018         int hint = d->delegateForIndex(index)->sizeHint(option, index).width();
3019         width = qMax(width, hint);
3020     }
3021     return width;
3022 }
3023 
3024 /*!
3025     Opens a persistent editor on the item at the given \a index.
3026     If no editor exists, the delegate will create a new editor.
3027 
3028     \sa closePersistentEditor()
3029 */
openPersistentEditor(const QModelIndex & index)3030 void QAbstractItemView::openPersistentEditor(const QModelIndex &index)
3031 {
3032     Q_D(QAbstractItemView);
3033     QStyleOptionViewItemV4 options = d->viewOptionsV4();
3034     options.rect = visualRect(index);
3035     options.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
3036 
3037     QWidget *editor = d->editor(index, options);
3038     if (editor) {
3039         editor->show();
3040         d->persistent.insert(editor);
3041     }
3042 }
3043 
3044 /*!
3045     Closes the persistent editor for the item at the given \a index.
3046 
3047     \sa openPersistentEditor()
3048 */
closePersistentEditor(const QModelIndex & index)3049 void QAbstractItemView::closePersistentEditor(const QModelIndex &index)
3050 {
3051     Q_D(QAbstractItemView);
3052     if (QWidget *editor = d->editorForIndex(index).widget.data()) {
3053         if (index == selectionModel()->currentIndex())
3054             closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
3055         d->persistent.remove(editor);
3056         d->removeEditor(editor);
3057         d->releaseEditor(editor);
3058     }
3059 }
3060 
3061 /*!
3062     \since 4.1
3063 
3064     Sets the given \a widget on the item at the given \a index, passing the
3065     ownership of the widget to the viewport.
3066 
3067     If \a index is invalid (e.g., if you pass the root index), this function
3068     will do nothing.
3069 
3070     The given \a widget's \l{QWidget}{autoFillBackground} property must be set
3071     to true, otherwise the widget's background will be transparent, showing
3072     both the model data and the item at the given \a index.
3073 
3074     If index widget A is replaced with index widget B, index widget A will be
3075     deleted. For example, in the code snippet below, the QLineEdit object will
3076     be deleted.
3077 
3078     \snippet doc/src/snippets/code/src_gui_itemviews_qabstractitemview.cpp 1
3079 
3080     This function should only be used to display static content within the
3081     visible area corresponding to an item of data. If you want to display
3082     custom dynamic content or implement a custom editor widget, subclass
3083     QItemDelegate instead.
3084 
3085     \sa {Delegate Classes}
3086 */
setIndexWidget(const QModelIndex & index,QWidget * widget)3087 void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget)
3088 {
3089     Q_D(QAbstractItemView);
3090     if (!d->isIndexValid(index))
3091         return;
3092     if (QWidget *oldWidget = indexWidget(index)) {
3093         d->persistent.remove(oldWidget);
3094         d->removeEditor(oldWidget);
3095         oldWidget->deleteLater();
3096     }
3097     if (widget) {
3098         widget->setParent(viewport());
3099         d->persistent.insert(widget);
3100         d->addEditor(index, widget, true);
3101         widget->show();
3102         dataChanged(index, index); // update the geometry
3103         if (!d->delayedPendingLayout)
3104             widget->setGeometry(visualRect(index));
3105     }
3106 }
3107 
3108 /*!
3109     \since 4.1
3110 
3111     Returns the widget for the item at the given \a index.
3112 */
indexWidget(const QModelIndex & index) const3113 QWidget* QAbstractItemView::indexWidget(const QModelIndex &index) const
3114 {
3115     Q_D(const QAbstractItemView);
3116     if (d->isIndexValid(index))
3117         if (QWidget *editor = d->editorForIndex(index).widget.data())
3118             return editor;
3119 
3120     return 0;
3121 }
3122 
3123 /*!
3124     \since 4.1
3125 
3126     Scrolls the view to the top.
3127 
3128     \sa scrollTo(), scrollToBottom()
3129 */
scrollToTop()3130 void QAbstractItemView::scrollToTop()
3131 {
3132     verticalScrollBar()->setValue(verticalScrollBar()->minimum());
3133 }
3134 
3135 /*!
3136     \since 4.1
3137 
3138     Scrolls the view to the bottom.
3139 
3140     \sa scrollTo(), scrollToTop()
3141 */
scrollToBottom()3142 void QAbstractItemView::scrollToBottom()
3143 {
3144     Q_D(QAbstractItemView);
3145     if (d->delayedPendingLayout) {
3146         d->executePostedLayout();
3147         updateGeometries();
3148     }
3149     verticalScrollBar()->setValue(verticalScrollBar()->maximum());
3150 }
3151 
3152 /*!
3153     \since 4.3
3154 
3155     Updates the area occupied by the given \a index.
3156 
3157 */
update(const QModelIndex & index)3158 void QAbstractItemView::update(const QModelIndex &index)
3159 {
3160     Q_D(QAbstractItemView);
3161     if (index.isValid()) {
3162         const QRect rect = visualRect(index);
3163         //this test is important for peformance reason
3164         //For example in dataChanged we simply update all the cells without checking
3165         //it can be a major bottleneck to update rects that aren't even part of the viewport
3166         if (d->viewport->rect().intersects(rect))
3167             d->viewport->update(rect);
3168     }
3169 }
3170 
3171 /*!
3172     This slot is called when items are changed in the model. The
3173     changed items are those from \a topLeft to \a bottomRight
3174     inclusive. If just one item is changed \a topLeft == \a
3175     bottomRight.
3176 */
dataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)3177 void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
3178 {
3179     // Single item changed
3180     Q_D(QAbstractItemView);
3181     if (topLeft == bottomRight && topLeft.isValid()) {
3182         const QEditorInfo &editorInfo = d->editorForIndex(topLeft);
3183         //we don't update the edit data if it is static
3184         if (!editorInfo.isStatic && editorInfo.widget) {
3185             QAbstractItemDelegate *delegate = d->delegateForIndex(topLeft);
3186             if (delegate) {
3187                 delegate->setEditorData(editorInfo.widget.data(), topLeft);
3188             }
3189         }
3190         if (isVisible() && !d->delayedPendingLayout) {
3191             // otherwise the items will be update later anyway
3192             update(topLeft);
3193         }
3194         return;
3195     }
3196     d->updateEditorData(topLeft, bottomRight);
3197     if (!isVisible() || d->delayedPendingLayout)
3198         return; // no need to update
3199     d->viewport->update();
3200 }
3201 
3202 /*!
3203     This slot is called when rows are inserted. The new rows are those
3204     under the given \a parent from \a start to \a end inclusive. The
3205     base class implementation calls fetchMore() on the model to check
3206     for more data.
3207 
3208     \sa rowsAboutToBeRemoved()
3209 */
rowsInserted(const QModelIndex &,int,int)3210 void QAbstractItemView::rowsInserted(const QModelIndex &, int, int)
3211 {
3212     if (!isVisible())
3213         d_func()->fetchMoreTimer.start(0, this); //fetch more later
3214     else
3215         updateEditorGeometries();
3216 }
3217 
3218 /*!
3219     This slot is called when rows are about to be removed. The deleted rows are
3220     those under the given \a parent from \a start to \a end inclusive.
3221 
3222     \sa rowsInserted()
3223 */
rowsAboutToBeRemoved(const QModelIndex & parent,int start,int end)3224 void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
3225 {
3226     Q_D(QAbstractItemView);
3227 
3228     setState(CollapsingState);
3229 
3230     // Ensure one selected item in single selection mode.
3231     QModelIndex current = currentIndex();
3232     if (d->selectionMode == SingleSelection
3233         && current.isValid()
3234         && current.row() >= start
3235         && current.row() <= end
3236         && current.parent() == parent) {
3237         int totalToRemove = end - start + 1;
3238         if (d->model->rowCount(parent) <= totalToRemove) { // no more children
3239             QModelIndex index = parent;
3240             while (index != d->root && !d->isIndexEnabled(index))
3241                 index = index.parent();
3242             if (index != d->root)
3243                 setCurrentIndex(index);
3244         } else {
3245             int row = end + 1;
3246             QModelIndex next;
3247             do { // find the next visible and enabled item
3248                 next = d->model->index(row++, current.column(), current.parent());
3249             } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next)));
3250             if (row > d->model->rowCount(parent)) {
3251                 row = start - 1;
3252                 do { // find the previous visible and enabled item
3253                     next = d->model->index(row--, current.column(), current.parent());
3254                 } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next)));
3255             }
3256             setCurrentIndex(next);
3257         }
3258     }
3259 
3260     // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
3261     QEditorIndexHash::iterator i = d->editorIndexHash.begin();
3262     while (i != d->editorIndexHash.end()) {
3263         const QModelIndex index = i.value();
3264         if (index.row() >= start && index.row() <= end && d->model->parent(index) == parent) {
3265             QWidget *editor = i.key();
3266             QEditorInfo info = d->indexEditorHash.take(index);
3267             i = d->editorIndexHash.erase(i);
3268             if (info.widget)
3269                 d->releaseEditor(editor);
3270         } else {
3271             ++i;
3272         }
3273     }
3274 }
3275 
3276 /*!
3277     \internal
3278 
3279     This slot is called when rows have been removed. The deleted
3280     rows are those under the given \a parent from \a start to \a end
3281     inclusive.
3282 */
_q_rowsRemoved(const QModelIndex & index,int start,int end)3283 void QAbstractItemViewPrivate::_q_rowsRemoved(const QModelIndex &index, int start, int end)
3284 {
3285     Q_UNUSED(index)
3286     Q_UNUSED(start)
3287     Q_UNUSED(end)
3288 
3289     Q_Q(QAbstractItemView);
3290     if (q->isVisible())
3291         q->updateEditorGeometries();
3292     q->setState(QAbstractItemView::NoState);
3293 #ifndef QT_NO_ACCESSIBILITY
3294 #ifdef Q_WS_X11
3295     if (QAccessible::isActive()) {
3296         QAccessible::queryAccessibleInterface(q)->table2Interface()->rowsRemoved(index, start, end);
3297         QAccessible::updateAccessibility(q, 0, QAccessible::TableModelChanged);
3298     }
3299 #endif
3300 #endif
3301 }
3302 
3303 /*!
3304     \internal
3305 
3306     This slot is called when columns are about to be removed. The deleted
3307     columns are those under the given \a parent from \a start to \a end
3308     inclusive.
3309 */
_q_columnsAboutToBeRemoved(const QModelIndex & parent,int start,int end)3310 void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
3311 {
3312     Q_Q(QAbstractItemView);
3313 
3314     q->setState(QAbstractItemView::CollapsingState);
3315 
3316     // Ensure one selected item in single selection mode.
3317     QModelIndex current = q->currentIndex();
3318     if (current.isValid()
3319         && selectionMode == QAbstractItemView::SingleSelection
3320         && current.column() >= start
3321         && current.column() <= end) {
3322         int totalToRemove = end - start + 1;
3323         if (model->columnCount(parent) < totalToRemove) { // no more columns
3324             QModelIndex index = parent;
3325             while (index.isValid() && !isIndexEnabled(index))
3326                 index = index.parent();
3327             if (index.isValid())
3328                 q->setCurrentIndex(index);
3329         } else {
3330             int column = end;
3331             QModelIndex next;
3332             do { // find the next visible and enabled item
3333                 next = model->index(current.row(), column++, current.parent());
3334             } while (next.isValid() && (q->isIndexHidden(next) || !isIndexEnabled(next)));
3335             q->setCurrentIndex(next);
3336         }
3337     }
3338 
3339     // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
3340     QEditorIndexHash::iterator it = editorIndexHash.begin();
3341     while (it != editorIndexHash.end()) {
3342         QModelIndex index = it.value();
3343         if (index.column() <= start && index.column() >= end && model->parent(index) == parent) {
3344             QWidget *editor = it.key();
3345             QEditorInfo info = indexEditorHash.take(it.value());
3346             it = editorIndexHash.erase(it);
3347             if (info.widget)
3348                 releaseEditor(editor);
3349         } else {
3350             ++it;
3351         }
3352     }
3353 
3354 }
3355 
3356 /*!
3357     \internal
3358 
3359     This slot is called when columns have been removed. The deleted
3360     rows are those under the given \a parent from \a start to \a end
3361     inclusive.
3362 */
_q_columnsRemoved(const QModelIndex & index,int start,int end)3363 void QAbstractItemViewPrivate::_q_columnsRemoved(const QModelIndex &index, int start, int end)
3364 {
3365     Q_UNUSED(index)
3366     Q_UNUSED(start)
3367     Q_UNUSED(end)
3368 
3369     Q_Q(QAbstractItemView);
3370     if (q->isVisible())
3371         q->updateEditorGeometries();
3372     q->setState(QAbstractItemView::NoState);
3373 #ifndef QT_NO_ACCESSIBILITY
3374 #ifdef Q_WS_X11
3375     if (QAccessible::isActive()) {
3376         QAccessible::queryAccessibleInterface(q)->table2Interface()->columnsRemoved(index, start, end);
3377         QAccessible::updateAccessibility(q, 0, QAccessible::TableModelChanged);
3378     }
3379 #endif
3380 #endif
3381 }
3382 
3383 
3384 /*!
3385     \internal
3386 
3387     This slot is called when rows have been inserted.
3388 */
_q_rowsInserted(const QModelIndex & index,int start,int end)3389 void QAbstractItemViewPrivate::_q_rowsInserted(const QModelIndex &index, int start, int end)
3390 {
3391     Q_UNUSED(index)
3392     Q_UNUSED(start)
3393     Q_UNUSED(end)
3394 
3395 #ifndef QT_NO_ACCESSIBILITY
3396 #ifdef Q_WS_X11
3397     Q_Q(QAbstractItemView);
3398     if (QAccessible::isActive()) {
3399         QAccessible::queryAccessibleInterface(q)->table2Interface()->rowsInserted(index, start, end);
3400         QAccessible::updateAccessibility(q, 0, QAccessible::TableModelChanged);
3401     }
3402 #endif
3403 #endif
3404 }
3405 
3406 /*!
3407     \internal
3408 
3409     This slot is called when columns have been inserted.
3410 */
_q_columnsInserted(const QModelIndex & index,int start,int end)3411 void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &index, int start, int end)
3412 {
3413     Q_UNUSED(index)
3414     Q_UNUSED(start)
3415     Q_UNUSED(end)
3416 
3417     Q_Q(QAbstractItemView);
3418     if (q->isVisible())
3419         q->updateEditorGeometries();
3420 #ifndef QT_NO_ACCESSIBILITY
3421 #ifdef Q_WS_X11
3422     if (QAccessible::isActive()) {
3423         QAccessible::queryAccessibleInterface(q)->table2Interface()->columnsInserted(index, start, end);
3424         QAccessible::updateAccessibility(q, 0, QAccessible::TableModelChanged);
3425     }
3426 #endif
3427 #endif
3428 }
3429 
3430 /*!
3431     \internal
3432 */
_q_modelDestroyed()3433 void QAbstractItemViewPrivate::_q_modelDestroyed()
3434 {
3435     model = QAbstractItemModelPrivate::staticEmptyModel();
3436     doDelayedReset();
3437 }
3438 
3439 /*!
3440     \internal
3441 
3442     This slot is called when the layout is changed.
3443 */
_q_layoutChanged()3444 void QAbstractItemViewPrivate::_q_layoutChanged()
3445 {
3446     doDelayedItemsLayout();
3447 #ifndef QT_NO_ACCESSIBILITY
3448 #ifdef Q_WS_X11
3449     Q_Q(QAbstractItemView);
3450     if (QAccessible::isActive()) {
3451         QAccessible::queryAccessibleInterface(q)->table2Interface()->modelReset();
3452         QAccessible::updateAccessibility(q, 0, QAccessible::TableModelChanged);
3453     }
3454 #endif
3455 #endif
3456 }
3457 
3458 /*!
3459     This slot is called when the selection is changed. The previous
3460     selection (which may be empty), is specified by \a deselected, and the
3461     new selection by \a selected.
3462 
3463     \sa setSelection()
3464 */
selectionChanged(const QItemSelection & selected,const QItemSelection & deselected)3465 void QAbstractItemView::selectionChanged(const QItemSelection &selected,
3466                                          const QItemSelection &deselected)
3467 {
3468     Q_D(QAbstractItemView);
3469     if (isVisible() && updatesEnabled()) {
3470         d->viewport->update(visualRegionForSelection(deselected) | visualRegionForSelection(selected));
3471     }
3472 }
3473 
3474 /*!
3475     This slot is called when a new item becomes the current item.
3476     The previous current item is specified by the \a previous index, and the new
3477     item by the \a current index.
3478 
3479     If you want to know about changes to items see the
3480     dataChanged() signal.
3481 */
currentChanged(const QModelIndex & current,const QModelIndex & previous)3482 void QAbstractItemView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
3483 {
3484     Q_D(QAbstractItemView);
3485     Q_ASSERT(d->model);
3486 
3487     if (previous.isValid()) {
3488         QModelIndex buddy = d->model->buddy(previous);
3489         QWidget *editor = d->editorForIndex(buddy).widget.data();
3490         if (editor && !d->persistent.contains(editor)) {
3491             commitData(editor);
3492             if (current.row() != previous.row())
3493                 closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
3494             else
3495                 closeEditor(editor, QAbstractItemDelegate::NoHint);
3496         }
3497         if (isVisible()) {
3498             update(previous);
3499         }
3500     }
3501 
3502     if (current.isValid() && !d->autoScrollTimer.isActive()) {
3503         if (isVisible()) {
3504             if (d->autoScroll)
3505                 scrollTo(current);
3506             update(current);
3507             edit(current, CurrentChanged, 0);
3508             if (current.row() == (d->model->rowCount(d->root) - 1))
3509                 d->fetchMore();
3510         } else {
3511             d->shouldScrollToCurrentOnShow = d->autoScroll;
3512         }
3513     }
3514 }
3515 
3516 #ifndef QT_NO_DRAGANDDROP
3517 /*!
3518     Starts a drag by calling drag->exec() using the given \a supportedActions.
3519 */
startDrag(Qt::DropActions supportedActions)3520 void QAbstractItemView::startDrag(Qt::DropActions supportedActions)
3521 {
3522     Q_D(QAbstractItemView);
3523     QModelIndexList indexes = d->selectedDraggableIndexes();
3524     if (indexes.count() > 0) {
3525         QMimeData *data = d->model->mimeData(indexes);
3526         if (!data)
3527             return;
3528         QRect rect;
3529         QPixmap pixmap = d->renderToPixmap(indexes, &rect);
3530         rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
3531         QDrag *drag = new QDrag(this);
3532         drag->setPixmap(pixmap);
3533         drag->setMimeData(data);
3534         drag->setHotSpot(d->pressedPosition - rect.topLeft());
3535         Qt::DropAction defaultDropAction = Qt::IgnoreAction;
3536         if (d->defaultDropAction != Qt::IgnoreAction && (supportedActions & d->defaultDropAction))
3537             defaultDropAction = d->defaultDropAction;
3538         else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
3539             defaultDropAction = Qt::CopyAction;
3540         if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
3541             d->clearOrRemove();
3542     }
3543 }
3544 #endif // QT_NO_DRAGANDDROP
3545 
3546 /*!
3547     Returns a QStyleOptionViewItem structure populated with the view's
3548     palette, font, state, alignments etc.
3549 */
viewOptions() const3550 QStyleOptionViewItem QAbstractItemView::viewOptions() const
3551 {
3552     Q_D(const QAbstractItemView);
3553     QStyleOptionViewItem option;
3554     option.init(this);
3555     option.state &= ~QStyle::State_MouseOver;
3556     option.font = font();
3557 
3558 #ifndef Q_WS_MAC
3559     // On mac the focus appearance follows window activation
3560     // not widget activation
3561     if (!hasFocus())
3562         option.state &= ~QStyle::State_Active;
3563 #endif
3564 
3565     option.state &= ~QStyle::State_HasFocus;
3566     if (d->iconSize.isValid()) {
3567         option.decorationSize = d->iconSize;
3568     } else {
3569         int pm = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
3570         option.decorationSize = QSize(pm, pm);
3571     }
3572     option.decorationPosition = QStyleOptionViewItem::Left;
3573     option.decorationAlignment = Qt::AlignCenter;
3574     option.displayAlignment = Qt::AlignLeft|Qt::AlignVCenter;
3575     option.textElideMode = d->textElideMode;
3576     option.rect = QRect();
3577     option.showDecorationSelected = style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, 0, this);
3578     return option;
3579 }
3580 
viewOptionsV4() const3581 QStyleOptionViewItemV4 QAbstractItemViewPrivate::viewOptionsV4() const
3582 {
3583     Q_Q(const QAbstractItemView);
3584     QStyleOptionViewItemV4 option = q->viewOptions();
3585     if (wrapItemText)
3586         option.features = QStyleOptionViewItemV2::WrapText;
3587     option.locale = q->locale();
3588     option.locale.setNumberOptions(QLocale::OmitGroupSeparator);
3589     option.widget = q;
3590     return option;
3591 }
3592 
3593 /*!
3594     Returns the item view's state.
3595 
3596     \sa setState()
3597 */
state() const3598 QAbstractItemView::State QAbstractItemView::state() const
3599 {
3600     Q_D(const QAbstractItemView);
3601     return d->state;
3602 }
3603 
3604 /*!
3605     Sets the item view's state to the given \a state.
3606 
3607     \sa state()
3608 */
setState(State state)3609 void QAbstractItemView::setState(State state)
3610 {
3611     Q_D(QAbstractItemView);
3612     d->state = state;
3613 }
3614 
3615 /*!
3616   Schedules a layout of the items in the view to be executed when the
3617   event processing starts.
3618 
3619   Even if scheduleDelayedItemsLayout() is called multiple times before
3620   events are processed, the view will only do the layout once.
3621 
3622   \sa executeDelayedItemsLayout()
3623 */
scheduleDelayedItemsLayout()3624 void QAbstractItemView::scheduleDelayedItemsLayout()
3625 {
3626     Q_D(QAbstractItemView);
3627     d->doDelayedItemsLayout();
3628 }
3629 
3630 /*!
3631   Executes the scheduled layouts without waiting for the event processing
3632   to begin.
3633 
3634   \sa scheduleDelayedItemsLayout()
3635 */
executeDelayedItemsLayout()3636 void QAbstractItemView::executeDelayedItemsLayout()
3637 {
3638     Q_D(QAbstractItemView);
3639     d->executePostedLayout();
3640 }
3641 
3642 /*!
3643     \since 4.1
3644 
3645     Marks the given \a region as dirty and schedules it to be updated.
3646     You only need to call this function if you are implementing
3647     your own view subclass.
3648 
3649     \sa scrollDirtyRegion(), dirtyRegionOffset()
3650 */
3651 
setDirtyRegion(const QRegion & region)3652 void QAbstractItemView::setDirtyRegion(const QRegion &region)
3653 {
3654     Q_D(QAbstractItemView);
3655     d->setDirtyRegion(region);
3656 }
3657 
3658 /*!
3659     Prepares the view for scrolling by (\a{dx},\a{dy}) pixels by moving the dirty regions in the
3660     opposite direction. You only need to call this function if you are implementing a scrolling
3661     viewport in your view subclass.
3662 
3663     If you implement scrollContentsBy() in a subclass of QAbstractItemView, call this function
3664     before you call QWidget::scroll() on the viewport. Alternatively, just call update().
3665 
3666     \sa scrollContentsBy(), dirtyRegionOffset(), setDirtyRegion()
3667 */
scrollDirtyRegion(int dx,int dy)3668 void QAbstractItemView::scrollDirtyRegion(int dx, int dy)
3669 {
3670     Q_D(QAbstractItemView);
3671     d->scrollDirtyRegion(dx, dy);
3672 }
3673 
3674 /*!
3675     Returns the offset of the dirty regions in the view.
3676 
3677     If you use scrollDirtyRegion() and implement a paintEvent() in a subclass of
3678     QAbstractItemView, you should translate the area given by the paint event with
3679     the offset returned from this function.
3680 
3681     \sa scrollDirtyRegion(), setDirtyRegion()
3682 */
dirtyRegionOffset() const3683 QPoint QAbstractItemView::dirtyRegionOffset() const
3684 {
3685     Q_D(const QAbstractItemView);
3686     return d->scrollDelayOffset;
3687 }
3688 
3689 /*!
3690   \internal
3691 */
startAutoScroll()3692 void QAbstractItemView::startAutoScroll()
3693 {
3694     d_func()->startAutoScroll();
3695 }
3696 
3697 /*!
3698   \internal
3699 */
stopAutoScroll()3700 void QAbstractItemView::stopAutoScroll()
3701 {
3702     d_func()->stopAutoScroll();
3703 }
3704 
3705 /*!
3706   \internal
3707 */
doAutoScroll()3708 void QAbstractItemView::doAutoScroll()
3709 {
3710     // find how much we should scroll with
3711     Q_D(QAbstractItemView);
3712     int verticalStep = verticalScrollBar()->pageStep();
3713     int horizontalStep = horizontalScrollBar()->pageStep();
3714     if (d->autoScrollCount < qMax(verticalStep, horizontalStep))
3715         ++d->autoScrollCount;
3716 
3717     int margin = d->autoScrollMargin;
3718     int verticalValue = verticalScrollBar()->value();
3719     int horizontalValue = horizontalScrollBar()->value();
3720 
3721     QPoint pos = d->viewport->mapFromGlobal(QCursor::pos());
3722     QRect area = static_cast<QAbstractItemView*>(d->viewport)->d_func()->clipRect(); // access QWidget private by bending C++ rules
3723 
3724     // do the scrolling if we are in the scroll margins
3725     if (pos.y() - area.top() < margin)
3726         verticalScrollBar()->setValue(verticalValue - d->autoScrollCount);
3727     else if (area.bottom() - pos.y() < margin)
3728         verticalScrollBar()->setValue(verticalValue + d->autoScrollCount);
3729     if (pos.x() - area.left() < margin)
3730         horizontalScrollBar()->setValue(horizontalValue - d->autoScrollCount);
3731     else if (area.right() - pos.x() < margin)
3732         horizontalScrollBar()->setValue(horizontalValue + d->autoScrollCount);
3733     // if nothing changed, stop scrolling
3734     bool verticalUnchanged = (verticalValue == verticalScrollBar()->value());
3735     bool horizontalUnchanged = (horizontalValue == horizontalScrollBar()->value());
3736     if (verticalUnchanged && horizontalUnchanged) {
3737         stopAutoScroll();
3738     } else {
3739 #ifndef QT_NO_DRAGANDDROP
3740         d->dropIndicatorRect = QRect();
3741         d->dropIndicatorPosition = QAbstractItemView::OnViewport;
3742 #endif
3743         d->viewport->update();
3744     }
3745 }
3746 
3747 /*!
3748     Returns the SelectionFlags to be used when updating a selection with
3749     to include the \a index specified. The \a event is a user input event,
3750     such as a mouse or keyboard event.
3751 
3752     Reimplement this function to define your own selection behavior.
3753 
3754     \sa setSelection()
3755 */
selectionCommand(const QModelIndex & index,const QEvent * event) const3756 QItemSelectionModel::SelectionFlags QAbstractItemView::selectionCommand(const QModelIndex &index,
3757                                                                         const QEvent *event) const
3758 {
3759     Q_D(const QAbstractItemView);
3760     switch (d->selectionMode) {
3761         case NoSelection: // Never update selection model
3762             return QItemSelectionModel::NoUpdate;
3763         case SingleSelection: // ClearAndSelect on valid index otherwise NoUpdate
3764             if (event && event->type() == QEvent::MouseButtonRelease)
3765                 return QItemSelectionModel::NoUpdate;
3766             return QItemSelectionModel::ClearAndSelect|d->selectionBehaviorFlags();
3767         case MultiSelection:
3768             return d->multiSelectionCommand(index, event);
3769         case ExtendedSelection:
3770             return d->extendedSelectionCommand(index, event);
3771         case ContiguousSelection:
3772             return d->contiguousSelectionCommand(index, event);
3773     }
3774     return QItemSelectionModel::NoUpdate;
3775 }
3776 
multiSelectionCommand(const QModelIndex & index,const QEvent * event) const3777 QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::multiSelectionCommand(
3778     const QModelIndex &index, const QEvent *event) const
3779 {
3780     Q_UNUSED(index)
3781 
3782     if (event) {
3783         switch (event->type()) {
3784         case QEvent::KeyPress:
3785             if (static_cast<const QKeyEvent*>(event)->key() == Qt::Key_Space
3786              || static_cast<const QKeyEvent*>(event)->key() == Qt::Key_Select)
3787                 return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3788             break;
3789         case QEvent::MouseButtonPress:
3790             if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton)
3791                 return QItemSelectionModel::Toggle|selectionBehaviorFlags(); // toggle
3792             break;
3793         case QEvent::MouseButtonRelease:
3794             if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton)
3795                 return QItemSelectionModel::NoUpdate|selectionBehaviorFlags(); // finalize
3796             break;
3797         case QEvent::MouseMove:
3798             if (static_cast<const QMouseEvent*>(event)->buttons() & Qt::LeftButton)
3799                 return QItemSelectionModel::ToggleCurrent|selectionBehaviorFlags(); // toggle drag select
3800         default:
3801             break;
3802         }
3803         return QItemSelectionModel::NoUpdate;
3804     }
3805 
3806     return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3807 }
3808 
extendedSelectionCommand(const QModelIndex & index,const QEvent * event) const3809 QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionCommand(
3810     const QModelIndex &index, const QEvent *event) const
3811 {
3812     Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
3813     if (event) {
3814         switch (event->type()) {
3815         case QEvent::MouseMove: {
3816             // Toggle on MouseMove
3817             modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
3818             if (modifiers & Qt::ControlModifier)
3819                 return QItemSelectionModel::ToggleCurrent|selectionBehaviorFlags();
3820             break;
3821         }
3822         case QEvent::MouseButtonPress: {
3823             modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
3824             const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
3825             const bool rightButtonPressed = button & Qt::RightButton;
3826             const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
3827             const bool controlKeyPressed = modifiers & Qt::ControlModifier;
3828             const bool indexIsSelected = selectionModel->isSelected(index);
3829             if ((shiftKeyPressed || controlKeyPressed) && rightButtonPressed)
3830                 return QItemSelectionModel::NoUpdate;
3831             if (!shiftKeyPressed && !controlKeyPressed && indexIsSelected)
3832                 return QItemSelectionModel::NoUpdate;
3833             if (!index.isValid() && !rightButtonPressed && !shiftKeyPressed && !controlKeyPressed)
3834                 return QItemSelectionModel::Clear;
3835             if (!index.isValid())
3836                 return QItemSelectionModel::NoUpdate;
3837             break;
3838         }
3839         case QEvent::MouseButtonRelease: {
3840             // ClearAndSelect on MouseButtonRelease if MouseButtonPress on selected item or empty area
3841             modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
3842             const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
3843             const bool rightButtonPressed = button & Qt::RightButton;
3844             const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
3845             const bool controlKeyPressed = modifiers & Qt::ControlModifier;
3846             if (((index == pressedIndex && selectionModel->isSelected(index))
3847                 || !index.isValid()) && state != QAbstractItemView::DragSelectingState
3848                 && !shiftKeyPressed && !controlKeyPressed && (!rightButtonPressed || !index.isValid()))
3849                 return QItemSelectionModel::ClearAndSelect|selectionBehaviorFlags();
3850             return QItemSelectionModel::NoUpdate;
3851         }
3852         case QEvent::KeyPress: {
3853             // NoUpdate on Key movement and Ctrl
3854             modifiers = static_cast<const QKeyEvent*>(event)->modifiers();
3855             switch (static_cast<const QKeyEvent*>(event)->key()) {
3856             case Qt::Key_Backtab:
3857                 modifiers = modifiers & ~Qt::ShiftModifier; // special case for backtab
3858             case Qt::Key_Down:
3859             case Qt::Key_Up:
3860             case Qt::Key_Left:
3861             case Qt::Key_Right:
3862             case Qt::Key_Home:
3863             case Qt::Key_End:
3864             case Qt::Key_PageUp:
3865             case Qt::Key_PageDown:
3866             case Qt::Key_Tab:
3867                 if (modifiers & Qt::ControlModifier
3868 #ifdef QT_KEYPAD_NAVIGATION
3869                     // Preserve historical tab order navigation behavior
3870                     || QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
3871 #endif
3872                     )
3873                     return QItemSelectionModel::NoUpdate;
3874                 break;
3875             case Qt::Key_Select:
3876                 return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3877             case Qt::Key_Space:// Toggle on Ctrl-Qt::Key_Space, Select on Space
3878                 if (modifiers & Qt::ControlModifier)
3879                     return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3880                 return QItemSelectionModel::Select|selectionBehaviorFlags();
3881             default:
3882                 break;
3883             }
3884         }
3885         default:
3886             break;
3887         }
3888     }
3889 
3890     if (modifiers & Qt::ShiftModifier)
3891         return QItemSelectionModel::SelectCurrent|selectionBehaviorFlags();
3892     if (modifiers & Qt::ControlModifier)
3893         return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3894     if (state == QAbstractItemView::DragSelectingState) {
3895         //when drag-selecting we need to clear any previous selection and select the current one
3896         return QItemSelectionModel::Clear|QItemSelectionModel::SelectCurrent|selectionBehaviorFlags();
3897     }
3898 
3899     return QItemSelectionModel::ClearAndSelect|selectionBehaviorFlags();
3900 }
3901 
3902 QItemSelectionModel::SelectionFlags
contiguousSelectionCommand(const QModelIndex & index,const QEvent * event) const3903 QAbstractItemViewPrivate::contiguousSelectionCommand(const QModelIndex &index,
3904                                                      const QEvent *event) const
3905 {
3906     QItemSelectionModel::SelectionFlags flags = extendedSelectionCommand(index, event);
3907     const int Mask = QItemSelectionModel::Clear | QItemSelectionModel::Select
3908                      | QItemSelectionModel::Deselect | QItemSelectionModel::Toggle
3909                      | QItemSelectionModel::Current;
3910 
3911     switch (flags & Mask) {
3912     case QItemSelectionModel::Clear:
3913     case QItemSelectionModel::ClearAndSelect:
3914     case QItemSelectionModel::SelectCurrent:
3915         return flags;
3916     case QItemSelectionModel::NoUpdate:
3917         if (event &&
3918             (event->type() == QEvent::MouseButtonPress
3919              || event->type() == QEvent::MouseButtonRelease))
3920             return flags;
3921         return QItemSelectionModel::ClearAndSelect|selectionBehaviorFlags();
3922     default:
3923         return QItemSelectionModel::SelectCurrent|selectionBehaviorFlags();
3924     }
3925 }
3926 
fetchMore()3927 void QAbstractItemViewPrivate::fetchMore()
3928 {
3929     fetchMoreTimer.stop();
3930     if (!model->canFetchMore(root))
3931         return;
3932     int last = model->rowCount(root) - 1;
3933     if (last < 0) {
3934         model->fetchMore(root);
3935         return;
3936     }
3937 
3938     QModelIndex index = model->index(last, 0, root);
3939     QRect rect = q_func()->visualRect(index);
3940     if (viewport->rect().intersects(rect))
3941         model->fetchMore(root);
3942 }
3943 
shouldEdit(QAbstractItemView::EditTrigger trigger,const QModelIndex & index) const3944 bool QAbstractItemViewPrivate::shouldEdit(QAbstractItemView::EditTrigger trigger,
3945                                           const QModelIndex &index) const
3946 {
3947     if (!index.isValid())
3948         return false;
3949     Qt::ItemFlags flags = model->flags(index);
3950     if (((flags & Qt::ItemIsEditable) == 0) || ((flags & Qt::ItemIsEnabled) == 0))
3951         return false;
3952     if (state == QAbstractItemView::EditingState)
3953         return false;
3954     if (hasEditor(index))
3955         return false;
3956     if (trigger == QAbstractItemView::AllEditTriggers) // force editing
3957         return true;
3958     if ((trigger & editTriggers) == QAbstractItemView::SelectedClicked
3959         && !selectionModel->isSelected(index))
3960         return false;
3961     return (trigger & editTriggers);
3962 }
3963 
shouldForwardEvent(QAbstractItemView::EditTrigger trigger,const QEvent * event) const3964 bool QAbstractItemViewPrivate::shouldForwardEvent(QAbstractItemView::EditTrigger trigger,
3965                                                   const QEvent *event) const
3966 {
3967     if (!event || (trigger & editTriggers) != QAbstractItemView::AnyKeyPressed)
3968         return false;
3969 
3970     switch (event->type()) {
3971         case QEvent::KeyPress:
3972         case QEvent::MouseButtonDblClick:
3973         case QEvent::MouseButtonPress:
3974         case QEvent::MouseButtonRelease:
3975         case QEvent::MouseMove:
3976             return true;
3977         default:
3978             break;
3979     };
3980 
3981     return false;
3982 }
3983 
shouldAutoScroll(const QPoint & pos) const3984 bool QAbstractItemViewPrivate::shouldAutoScroll(const QPoint &pos) const
3985 {
3986     if (!autoScroll)
3987         return false;
3988     QRect area = static_cast<QAbstractItemView*>(viewport)->d_func()->clipRect(); // access QWidget private by bending C++ rules
3989     return (pos.y() - area.top() < autoScrollMargin)
3990         || (area.bottom() - pos.y() < autoScrollMargin)
3991         || (pos.x() - area.left() < autoScrollMargin)
3992         || (area.right() - pos.x() < autoScrollMargin);
3993 }
3994 
doDelayedItemsLayout(int delay)3995 void QAbstractItemViewPrivate::doDelayedItemsLayout(int delay)
3996 {
3997     if (!delayedPendingLayout) {
3998         delayedPendingLayout = true;
3999         delayedLayout.start(delay, q_func());
4000     }
4001 }
4002 
interruptDelayedItemsLayout() const4003 void QAbstractItemViewPrivate::interruptDelayedItemsLayout() const
4004 {
4005     delayedLayout.stop();
4006     delayedPendingLayout = false;
4007 }
4008 
4009 
4010 
editor(const QModelIndex & index,const QStyleOptionViewItem & options)4011 QWidget *QAbstractItemViewPrivate::editor(const QModelIndex &index,
4012                                           const QStyleOptionViewItem &options)
4013 {
4014     Q_Q(QAbstractItemView);
4015     QWidget *w = editorForIndex(index).widget.data();
4016     if (!w) {
4017         QAbstractItemDelegate *delegate = delegateForIndex(index);
4018         if (!delegate)
4019             return 0;
4020         w = delegate->createEditor(viewport, options, index);
4021         if (w) {
4022             w->installEventFilter(delegate);
4023             QObject::connect(w, SIGNAL(destroyed(QObject*)), q, SLOT(editorDestroyed(QObject*)));
4024             delegate->updateEditorGeometry(w, options, index);
4025             delegate->setEditorData(w, index);
4026             addEditor(index, w, false);
4027             if (w->parent() == viewport)
4028                 QWidget::setTabOrder(q, w);
4029 
4030             // Special cases for some editors containing QLineEdit
4031             QWidget *focusWidget = w;
4032             while (QWidget *fp = focusWidget->focusProxy())
4033                 focusWidget = fp;
4034 #ifndef QT_NO_LINEEDIT
4035             if (QLineEdit *le = qobject_cast<QLineEdit*>(focusWidget))
4036                 le->selectAll();
4037 #endif
4038 #ifndef QT_NO_SPINBOX
4039             if (QSpinBox *sb = qobject_cast<QSpinBox*>(focusWidget))
4040                 sb->selectAll();
4041             else if (QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox*>(focusWidget))
4042                 dsb->selectAll();
4043 #endif
4044         }
4045     }
4046 
4047     return w;
4048 }
4049 
updateEditorData(const QModelIndex & tl,const QModelIndex & br)4050 void QAbstractItemViewPrivate::updateEditorData(const QModelIndex &tl, const QModelIndex &br)
4051 {
4052     // we are counting on having relatively few editors
4053     const bool checkIndexes = tl.isValid() && br.isValid();
4054     const QModelIndex parent = tl.parent();
4055     QIndexEditorHash::const_iterator it = indexEditorHash.constBegin();
4056     for (; it != indexEditorHash.constEnd(); ++it) {
4057         QWidget *editor = it.value().widget.data();
4058         const QModelIndex index = it.key();
4059         if (it.value().isStatic || !editor || !index.isValid() ||
4060             (checkIndexes
4061                 && (index.row() < tl.row() || index.row() > br.row()
4062                     || index.column() < tl.column() || index.column() > br.column()
4063                     || index.parent() != parent)))
4064             continue;
4065 
4066         QAbstractItemDelegate *delegate = delegateForIndex(index);
4067         if (delegate) {
4068             delegate->setEditorData(editor, index);
4069         }
4070     }
4071 }
4072 
4073 /*!
4074     \internal
4075 
4076     In DND if something has been moved then this is called.
4077     Typically this means you should "remove" the selected item or row,
4078     but the behavior is view dependant (table just clears the selected indexes for example).
4079 
4080     Either remove the selected rows or clear them
4081 */
clearOrRemove()4082 void QAbstractItemViewPrivate::clearOrRemove()
4083 {
4084 #ifndef QT_NO_DRAGANDDROP
4085     const QItemSelection selection = selectionModel->selection();
4086     QList<QItemSelectionRange>::const_iterator it = selection.constBegin();
4087 
4088     if (!overwrite) {
4089         for (; it != selection.constEnd(); ++it) {
4090             QModelIndex parent = (*it).parent();
4091             if ((*it).left() != 0)
4092                 continue;
4093             if ((*it).right() != (model->columnCount(parent) - 1))
4094                 continue;
4095             int count = (*it).bottom() - (*it).top() + 1;
4096             model->removeRows((*it).top(), count, parent);
4097         }
4098     } else {
4099         // we can't remove the rows so reset the items (i.e. the view is like a table)
4100         QModelIndexList list = selection.indexes();
4101         for (int i=0; i < list.size(); ++i) {
4102             QModelIndex index = list.at(i);
4103             QMap<int, QVariant> roles = model->itemData(index);
4104             for (QMap<int, QVariant>::Iterator it = roles.begin(); it != roles.end(); ++it)
4105                 it.value() = QVariant();
4106             model->setItemData(index, roles);
4107         }
4108     }
4109 #endif
4110 }
4111 
4112 /*!
4113     \internal
4114 
4115     When persistent aeditor gets/loses focus, we need to check
4116     and setcorrectly the current index.
4117 */
checkPersistentEditorFocus()4118 void QAbstractItemViewPrivate::checkPersistentEditorFocus()
4119 {
4120     Q_Q(QAbstractItemView);
4121     if (QWidget *widget = QApplication::focusWidget()) {
4122         if (persistent.contains(widget)) {
4123             //a persistent editor has gained the focus
4124             QModelIndex index = indexForEditor(widget);
4125             if (selectionModel->currentIndex() != index)
4126                 q->setCurrentIndex(index);
4127         }
4128     }
4129 }
4130 
4131 
editorForIndex(const QModelIndex & index) const4132 const QEditorInfo & QAbstractItemViewPrivate::editorForIndex(const QModelIndex &index) const
4133 {
4134     static QEditorInfo nullInfo;
4135 
4136     // do not try to search to avoid slow implicit cast from QModelIndex to QPersistentModelIndex
4137     if (indexEditorHash.isEmpty())
4138         return nullInfo;
4139 
4140     QIndexEditorHash::const_iterator it = indexEditorHash.find(index);
4141     if (it == indexEditorHash.end())
4142         return nullInfo;
4143 
4144     return it.value();
4145 }
4146 
indexForEditor(QWidget * editor) const4147 QModelIndex QAbstractItemViewPrivate::indexForEditor(QWidget *editor) const
4148 {
4149     // do not try to search to avoid slow implicit cast from QModelIndex to QPersistentModelIndex
4150     if (indexEditorHash.isEmpty())
4151         return QModelIndex();
4152 
4153     QEditorIndexHash::const_iterator it = editorIndexHash.find(editor);
4154     if (it == editorIndexHash.end())
4155         return QModelIndex();
4156 
4157     return it.value();
4158 }
4159 
removeEditor(QWidget * editor)4160 void QAbstractItemViewPrivate::removeEditor(QWidget *editor)
4161 {
4162    QEditorIndexHash::iterator it = editorIndexHash.find(editor);
4163     if (it != editorIndexHash.end())
4164     {
4165         indexEditorHash.remove(it.value());
4166         editorIndexHash.erase(it);
4167     }
4168 }
4169 
addEditor(const QModelIndex & index,QWidget * editor,bool isStatic)4170 void QAbstractItemViewPrivate::addEditor(const QModelIndex &index, QWidget *editor, bool isStatic)
4171 {
4172     editorIndexHash.insert(editor, index);
4173     indexEditorHash.insert(index, QEditorInfo(editor, isStatic));
4174 }
4175 
sendDelegateEvent(const QModelIndex & index,QEvent * event) const4176 bool QAbstractItemViewPrivate::sendDelegateEvent(const QModelIndex &index, QEvent *event) const
4177 {
4178     Q_Q(const QAbstractItemView);
4179     QModelIndex buddy = model->buddy(index);
4180     QStyleOptionViewItemV4 options = viewOptionsV4();
4181     options.rect = q->visualRect(buddy);
4182     options.state |= (buddy == q->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
4183     QAbstractItemDelegate *delegate = delegateForIndex(index);
4184     return (event && delegate && delegate->editorEvent(event, model, options, buddy));
4185 }
4186 
openEditor(const QModelIndex & index,QEvent * event)4187 bool QAbstractItemViewPrivate::openEditor(const QModelIndex &index, QEvent *event)
4188 {
4189     Q_Q(QAbstractItemView);
4190 
4191     QModelIndex buddy = model->buddy(index);
4192     QStyleOptionViewItemV4 options = viewOptionsV4();
4193     options.rect = q->visualRect(buddy);
4194     options.state |= (buddy == q->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
4195 
4196     QWidget *w = editor(buddy, options);
4197     if (!w)
4198         return false;
4199 
4200     q->setState(QAbstractItemView::EditingState);
4201     w->show();
4202     w->setFocus();
4203 
4204     if (event)
4205         QApplication::sendEvent(w->focusProxy() ? w->focusProxy() : w, event);
4206 
4207     return true;
4208 }
4209 
4210 /*
4211     \internal
4212 
4213     returns the pair QRect/QModelIndex that should be painted on the viewports's rect
4214 */
4215 
draggablePaintPairs(const QModelIndexList & indexes,QRect * r) const4216 QItemViewPaintPairs QAbstractItemViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
4217 {
4218     Q_ASSERT(r);
4219     Q_Q(const QAbstractItemView);
4220     QRect &rect = *r;
4221     const QRect viewportRect = viewport->rect();
4222     QItemViewPaintPairs ret;
4223     for (int i = 0; i < indexes.count(); ++i) {
4224         const QModelIndex &index = indexes.at(i);
4225         const QRect current = q->visualRect(index);
4226         if (current.intersects(viewportRect)) {
4227             ret += qMakePair(current, index);
4228             rect |= current;
4229         }
4230     }
4231     rect &= viewportRect;
4232     return ret;
4233 }
4234 
renderToPixmap(const QModelIndexList & indexes,QRect * r) const4235 QPixmap QAbstractItemViewPrivate::renderToPixmap(const QModelIndexList &indexes, QRect *r) const
4236 {
4237     Q_ASSERT(r);
4238     QItemViewPaintPairs paintPairs = draggablePaintPairs(indexes, r);
4239     if (paintPairs.isEmpty())
4240         return QPixmap();
4241     QPixmap pixmap(r->size());
4242     pixmap.fill(Qt::transparent);
4243     QPainter painter(&pixmap);
4244     QStyleOptionViewItemV4 option = viewOptionsV4();
4245     option.state |= QStyle::State_Selected;
4246     for (int j = 0; j < paintPairs.count(); ++j) {
4247         option.rect = paintPairs.at(j).first.translated(-r->topLeft());
4248         const QModelIndex &current = paintPairs.at(j).second;
4249         adjustViewOptionsForIndex(&option, current);
4250         delegateForIndex(current)->paint(&painter, option, current);
4251     }
4252     return pixmap;
4253 }
4254 
selectAll(QItemSelectionModel::SelectionFlags command)4255 void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
4256 {
4257     if (!selectionModel)
4258         return;
4259 
4260     QItemSelection selection;
4261     QModelIndex tl = model->index(0, 0, root);
4262     QModelIndex br = model->index(model->rowCount(root) - 1,
4263                                   model->columnCount(root) - 1,
4264                                   root);
4265     selection.append(QItemSelectionRange(tl, br));
4266     selectionModel->select(selection, command);
4267 }
4268 
selectedDraggableIndexes() const4269 QModelIndexList QAbstractItemViewPrivate::selectedDraggableIndexes() const
4270 {
4271     Q_Q(const QAbstractItemView);
4272     QModelIndexList indexes = q->selectedIndexes();
4273     for(int i = indexes.count() - 1 ; i >= 0; --i) {
4274         if (!isIndexDragEnabled(indexes.at(i)))
4275             indexes.removeAt(i);
4276     }
4277     return indexes;
4278 }
4279 
4280 
4281 QT_END_NAMESPACE
4282 
4283 #include "moc_qabstractitemview.cpp"
4284 
4285 #endif // QT_NO_ITEMVIEWS
4286