1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWidgets 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 https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qabstractitemview.h"
41
42#include <qpointer.h>
43#include <qapplication.h>
44#include <qclipboard.h>
45#include <qpainter.h>
46#include <qstyle.h>
47#if QT_CONFIG(draganddrop)
48#include <qdrag.h>
49#endif
50#include <qevent.h>
51#include <qscrollbar.h>
52#include <qtooltip.h>
53#include <qdatetime.h>
54#if QT_CONFIG(lineedit)
55#include <qlineedit.h>
56#endif
57#if QT_CONFIG(spinbox)
58#include <qspinbox.h>
59#endif
60#include <qheaderview.h>
61#include <qstyleditemdelegate.h>
62#include <private/qabstractitemview_p.h>
63#include <private/qabstractitemmodel_p.h>
64#include <private/qguiapplication_p.h>
65#include <private/qscrollbar_p.h>
66#ifndef QT_NO_ACCESSIBILITY
67#include <qaccessible.h>
68#endif
69#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
70# include <qscroller.h>
71#endif
72
73#include <algorithm>
74
75QT_BEGIN_NAMESPACE
76
77QAbstractItemViewPrivate::QAbstractItemViewPrivate()
78 : model(QAbstractItemModelPrivate::staticEmptyModel()),
79 itemDelegate(0),
80 selectionModel(0),
81 ctrlDragSelectionFlag(QItemSelectionModel::NoUpdate),
82 noSelectionOnMousePress(false),
83 selectionMode(QAbstractItemView::ExtendedSelection),
84 selectionBehavior(QAbstractItemView::SelectItems),
85 currentlyCommittingEditor(0),
86 pressedModifiers(Qt::NoModifier),
87 pressedPosition(QPoint(-1, -1)),
88 pressedAlreadySelected(false),
89 viewportEnteredNeeded(false),
90 state(QAbstractItemView::NoState),
91 stateBeforeAnimation(QAbstractItemView::NoState),
92 editTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed),
93 lastTrigger(QAbstractItemView::NoEditTriggers),
94 tabKeyNavigation(false),
95#if QT_CONFIG(draganddrop)
96 showDropIndicator(true),
97 dragEnabled(false),
98 dragDropMode(QAbstractItemView::NoDragDrop),
99 overwrite(false),
100 dropIndicatorPosition(QAbstractItemView::OnItem),
101 defaultDropAction(Qt::IgnoreAction),
102#endif
103 autoScroll(true),
104 autoScrollMargin(16),
105 autoScrollCount(0),
106 shouldScrollToCurrentOnShow(false),
107 shouldClearStatusTip(false),
108 alternatingColors(false),
109 textElideMode(Qt::ElideRight),
110 verticalScrollMode(QAbstractItemView::ScrollPerItem),
111 horizontalScrollMode(QAbstractItemView::ScrollPerItem),
112 currentIndexSet(false),
113 wrapItemText(false),
114 delayedPendingLayout(true),
115 moveCursorUpdatedView(false),
116 verticalScrollModeSet(false),
117 horizontalScrollModeSet(false)
118{
119 keyboardInputTime.invalidate();
120}
121
122QAbstractItemViewPrivate::~QAbstractItemViewPrivate()
123{
124}
125
126void QAbstractItemViewPrivate::init()
127{
128 Q_Q(QAbstractItemView);
129 q->setItemDelegate(new QStyledItemDelegate(q));
130
131 vbar->setRange(0, 0);
132 hbar->setRange(0, 0);
133
134 QObject::connect(vbar, SIGNAL(actionTriggered(int)),
135 q, SLOT(verticalScrollbarAction(int)));
136 QObject::connect(hbar, SIGNAL(actionTriggered(int)),
137 q, SLOT(horizontalScrollbarAction(int)));
138 QObject::connect(vbar, SIGNAL(valueChanged(int)),
139 q, SLOT(verticalScrollbarValueChanged(int)));
140 QObject::connect(hbar, SIGNAL(valueChanged(int)),
141 q, SLOT(horizontalScrollbarValueChanged(int)));
142
143 viewport->setBackgroundRole(QPalette::Base);
144
145 q->setAttribute(Qt::WA_InputMethodEnabled);
146
147 verticalScrollMode = static_cast<QAbstractItemView::ScrollMode>(q->style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, q, 0));
148 horizontalScrollMode = static_cast<QAbstractItemView::ScrollMode>(q->style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, q, 0));
149}
150
151void QAbstractItemViewPrivate::setHoverIndex(const QPersistentModelIndex &index)
152{
153 Q_Q(QAbstractItemView);
154 if (hover == index)
155 return;
156
157 if (selectionBehavior != QAbstractItemView::SelectRows) {
158 q->update(hover); //update the old one
159 q->update(index); //update the new one
160 } else {
161 QRect oldHoverRect = q->visualRect(hover);
162 QRect newHoverRect = q->visualRect(index);
163 viewport->update(QRect(0, newHoverRect.y(), viewport->width(), newHoverRect.height()));
164 viewport->update(QRect(0, oldHoverRect.y(), viewport->width(), oldHoverRect.height()));
165 }
166 hover = index;
167}
168
169void QAbstractItemViewPrivate::checkMouseMove(const QPersistentModelIndex &index)
170{
171 //we take a persistent model index because the model might change by emitting signals
172 Q_Q(QAbstractItemView);
173 setHoverIndex(index);
174 if (viewportEnteredNeeded || enteredIndex != index) {
175 viewportEnteredNeeded = false;
176
177 if (index.isValid()) {
178 emit q->entered(index);
179#if QT_CONFIG(statustip)
180 QString statustip = model->data(index, Qt::StatusTipRole).toString();
181 if (parent && (shouldClearStatusTip || !statustip.isEmpty())) {
182 QStatusTipEvent tip(statustip);
183 QApplication::sendEvent(parent, &tip);
184 shouldClearStatusTip = !statustip.isEmpty();
185 }
186#endif
187 } else {
188#if QT_CONFIG(statustip)
189 if (parent && shouldClearStatusTip) {
190 QString emptyString;
191 QStatusTipEvent tip( emptyString );
192 QApplication::sendEvent(parent, &tip);
193 }
194#endif
195 emit q->viewportEntered();
196 }
197 enteredIndex = index;
198 }
199}
200
201#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
202
203// stores and restores the selection and current item when flicking
204void QAbstractItemViewPrivate::_q_scrollerStateChanged()
205{
206 Q_Q(QAbstractItemView);
207
208 if (QScroller *scroller = QScroller::scroller(viewport)) {
209 switch (scroller->state()) {
210 case QScroller::Pressed:
211 // store the current selection in case we start scrolling
212 if (q->selectionModel()) {
213 oldSelection = q->selectionModel()->selection();
214 oldCurrent = q->selectionModel()->currentIndex();
215 }
216 break;
217
218 case QScroller::Dragging:
219 // restore the old selection if we really start scrolling
220 if (q->selectionModel()) {
221 q->selectionModel()->select(oldSelection, QItemSelectionModel::ClearAndSelect);
222 q->selectionModel()->setCurrentIndex(oldCurrent, QItemSelectionModel::NoUpdate);
223 }
224 Q_FALLTHROUGH();
225
226 default:
227 oldSelection = QItemSelection();
228 oldCurrent = QModelIndex();
229 break;
230 }
231 }
232}
233
234#endif // QT_NO_GESTURES
235
236/*!
237 \class QAbstractItemView
238
239 \brief The QAbstractItemView class provides the basic functionality for
240 item view classes.
241
242 \ingroup model-view
243 \inmodule QtWidgets
244
245 QAbstractItemView class is the base class for every standard view
246 that uses a QAbstractItemModel. QAbstractItemView is an abstract
247 class and cannot itself be instantiated. It provides a standard
248 interface for interoperating with models through the signals and
249 slots mechanism, enabling subclasses to be kept up-to-date with
250 changes to their models. This class provides standard support for
251 keyboard and mouse navigation, viewport scrolling, item editing,
252 and selections. The keyboard navigation implements this
253 functionality:
254
255 \table
256 \header
257 \li Keys
258 \li Functionality
259 \row
260 \li Arrow keys
261 \li Changes the current item and selects it.
262 \row
263 \li Ctrl+Arrow keys
264 \li Changes the current item but does not select it.
265 \row
266 \li Shift+Arrow keys
267 \li Changes the current item and selects it. The previously
268 selected item(s) is not deselected.
269 \row
270 \li Ctr+Space
271 \li Toggles selection of the current item.
272 \row
273 \li Tab/Backtab
274 \li Changes the current item to the next/previous item.
275 \row
276 \li Home/End
277 \li Selects the first/last item in the model.
278 \row
279 \li Page up/Page down
280 \li Scrolls the rows shown up/down by the number of
281 visible rows in the view.
282 \row
283 \li Ctrl+A
284 \li Selects all items in the model.
285 \endtable
286
287 Note that the above table assumes that the
288 \l{selectionMode}{selection mode} allows the operations. For
289 instance, you cannot select items if the selection mode is
290 QAbstractItemView::NoSelection.
291
292 The QAbstractItemView class is one of the \l{Model/View Classes}
293 and is part of Qt's \l{Model/View Programming}{model/view framework}.
294
295 The view classes that inherit QAbstractItemView only need
296 to implement their own view-specific functionality, such as
297 drawing items, returning the geometry of items, finding items,
298 etc.
299
300 QAbstractItemView provides common slots such as edit() and
301 setCurrentIndex(). Many protected slots are also provided, including
302 dataChanged(), rowsInserted(), rowsAboutToBeRemoved(), selectionChanged(),
303 and currentChanged().
304
305 The root item is returned by rootIndex(), and the current item by
306 currentIndex(). To make sure that an item is visible use
307 scrollTo().
308
309 Some of QAbstractItemView's functions are concerned with
310 scrolling, for example setHorizontalScrollMode() and
311 setVerticalScrollMode(). To set the range of the scroll bars, you
312 can, for example, reimplement the view's resizeEvent() function:
313
314 \snippet code/src_gui_itemviews_qabstractitemview.cpp 0
315
316 Note that the range is not updated until the widget is shown.
317
318 Several other functions are concerned with selection control; for
319 example setSelectionMode(), and setSelectionBehavior(). This class
320 provides a default selection model to work with
321 (selectionModel()), but this can be replaced by using
322 setSelectionModel() with an instance of QItemSelectionModel.
323
324 For complete control over the display and editing of items you can
325 specify a delegate with setItemDelegate().
326
327 QAbstractItemView provides a lot of protected functions. Some are
328 concerned with editing, for example, edit(), and commitData(),
329 whilst others are keyboard and mouse event handlers.
330
331 \note If you inherit QAbstractItemView and intend to update the contents
332 of the viewport, you should use viewport->update() instead of
333 \l{QWidget::update()}{update()} as all painting operations take place on the
334 viewport.
335
336 \sa {View Classes}, {Model/View Programming}, QAbstractItemModel, {Chart Example}
337*/
338
339/*!
340 \enum QAbstractItemView::SelectionMode
341
342 This enum indicates how the view responds to user selections:
343
344 \value SingleSelection When the user selects an item, any already-selected
345 item becomes unselected. It is possible for the user to deselect the selected
346 item.
347
348 \value ContiguousSelection When the user selects an item in the usual way,
349 the selection is cleared and the new item selected. However, if the user
350 presses the Shift key while clicking on an item, all items between the
351 current item and the clicked item are selected or unselected, depending on
352 the state of the clicked item.
353
354 \value ExtendedSelection When the user selects an item in the usual way,
355 the selection is cleared and the new item selected. However, if the user
356 presses the Ctrl key when clicking on an item, the clicked item gets
357 toggled and all other items are left untouched. If the user presses the
358 Shift key while clicking on an item, all items between the current item
359 and the clicked item are selected or unselected, depending on the state of
360 the clicked item. Multiple items can be selected by dragging the mouse over
361 them.
362
363 \value MultiSelection When the user selects an item in the usual way, the
364 selection status of that item is toggled and the other items are left
365 alone. Multiple items can be toggled by dragging the mouse over them.
366
367 \value NoSelection Items cannot be selected.
368
369 The most commonly used modes are SingleSelection and ExtendedSelection.
370*/
371
372/*!
373 \enum QAbstractItemView::SelectionBehavior
374
375 \value SelectItems Selecting single items.
376 \value SelectRows Selecting only rows.
377 \value SelectColumns Selecting only columns.
378*/
379
380/*!
381 \enum QAbstractItemView::ScrollHint
382
383 \value EnsureVisible Scroll to ensure that the item is visible.
384 \value PositionAtTop Scroll to position the item at the top of the
385 viewport.
386 \value PositionAtBottom Scroll to position the item at the bottom of the
387 viewport.
388 \value PositionAtCenter Scroll to position the item at the center of the
389 viewport.
390*/
391
392
393/*!
394 \enum QAbstractItemView::EditTrigger
395
396 This enum describes actions which will initiate item editing.
397
398 \value NoEditTriggers No editing possible.
399 \value CurrentChanged Editing start whenever current item changes.
400 \value DoubleClicked Editing starts when an item is double clicked.
401 \value SelectedClicked Editing starts when clicking on an already selected
402 item.
403 \value EditKeyPressed Editing starts when the platform edit key has been
404 pressed over an item.
405 \value AnyKeyPressed Editing starts when any key is pressed over an item.
406 \value AllEditTriggers Editing starts for all above actions.
407*/
408
409/*!
410 \enum QAbstractItemView::CursorAction
411
412 This enum describes the different ways to navigate between items,
413 \sa moveCursor()
414
415 \value MoveUp Move to the item above the current item.
416 \value MoveDown Move to the item below the current item.
417 \value MoveLeft Move to the item left of the current item.
418 \value MoveRight Move to the item right of the current item.
419 \value MoveHome Move to the top-left corner item.
420 \value MoveEnd Move to the bottom-right corner item.
421 \value MovePageUp Move one page up above the current item.
422 \value MovePageDown Move one page down below the current item.
423 \value MoveNext Move to the item after the current item.
424 \value MovePrevious Move to the item before the current item.
425*/
426
427/*!
428 \enum QAbstractItemView::State
429
430 Describes the different states the view can be in. This is usually
431 only interesting when reimplementing your own view.
432
433 \value NoState The is the default state.
434 \value DraggingState The user is dragging items.
435 \value DragSelectingState The user is selecting items.
436 \value EditingState The user is editing an item in a widget editor.
437 \value ExpandingState The user is opening a branch of items.
438 \value CollapsingState The user is closing a branch of items.
439 \value AnimatingState The item view is performing an animation.
440*/
441
442/*!
443 \since 4.2
444 \enum QAbstractItemView::ScrollMode
445
446 Describes how the scrollbar should behave. When setting the scroll mode
447 to ScrollPerPixel the single step size will adjust automatically unless
448 it was set explicitly using \l{QAbstractSlider::}{setSingleStep()}.
449 The automatic adjustment can be restored by setting the single step size to -1.
450
451 \value ScrollPerItem The view will scroll the contents one item at a time.
452 \value ScrollPerPixel The view will scroll the contents one pixel at a time.
453*/
454
455/*!
456 \fn QRect QAbstractItemView::visualRect(const QModelIndex &index) const = 0
457 Returns the rectangle on the viewport occupied by the item at \a index.
458
459 If your item is displayed in several areas then visualRect should return
460 the primary area that contains index and not the complete area that index
461 might encompasses, touch or cause drawing.
462
463 In the base class this is a pure virtual function.
464
465 \sa indexAt(), visualRegionForSelection()
466*/
467
468/*!
469 \fn void QAbstractItemView::scrollTo(const QModelIndex &index, ScrollHint hint) = 0
470
471 Scrolls the view if necessary to ensure that the item at \a index
472 is visible. The view will try to position the item according to the given \a hint.
473
474 In the base class this is a pure virtual function.
475*/
476
477/*!
478 \fn QModelIndex QAbstractItemView::indexAt(const QPoint &point) const = 0
479
480 Returns the model index of the item at the viewport coordinates \a point.
481
482 In the base class this is a pure virtual function.
483
484 \sa visualRect()
485*/
486
487/*!
488 \fn void QAbstractItemView::activated(const QModelIndex &index)
489
490 This signal is emitted when the item specified by \a index is
491 activated by the user. How to activate items depends on the
492 platform; e.g., by single- or double-clicking the item, or by
493 pressing the Return or Enter key when the item is current.
494
495 \sa clicked(), doubleClicked(), entered(), pressed()
496*/
497
498/*!
499 \fn void QAbstractItemView::entered(const QModelIndex &index)
500
501 This signal is emitted when the mouse cursor enters the item
502 specified by \a index.
503 Mouse tracking needs to be enabled for this feature to work.
504
505 \sa viewportEntered(), activated(), clicked(), doubleClicked(), pressed()
506*/
507
508/*!
509 \fn void QAbstractItemView::viewportEntered()
510
511 This signal is emitted when the mouse cursor enters the viewport.
512 Mouse tracking needs to be enabled for this feature to work.
513
514 \sa entered()
515*/
516
517/*!
518 \fn void QAbstractItemView::pressed(const QModelIndex &index)
519
520 This signal is emitted when a mouse button is pressed. The item
521 the mouse was pressed on is specified by \a index. The signal is
522 only emitted when the index is valid.
523
524 Use the QApplication::mouseButtons() function to get the state
525 of the mouse buttons.
526
527 \sa activated(), clicked(), doubleClicked(), entered()
528*/
529
530/*!
531 \fn void QAbstractItemView::clicked(const QModelIndex &index)
532
533 This signal is emitted when a mouse button is left-clicked. The item
534 the mouse was clicked on is specified by \a index. The signal is
535 only emitted when the index is valid.
536
537 \sa activated(), doubleClicked(), entered(), pressed()
538*/
539
540/*!
541 \fn void QAbstractItemView::doubleClicked(const QModelIndex &index)
542
543 This signal is emitted when a mouse button is double-clicked. The
544 item the mouse was double-clicked on is specified by \a index.
545 The signal is only emitted when the index is valid.
546
547 \sa clicked(), activated()
548*/
549
550/*!
551 \fn QModelIndex QAbstractItemView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) = 0
552
553 Returns a QModelIndex object pointing to the next object in the view,
554 based on the given \a cursorAction and keyboard modifiers specified
555 by \a modifiers.
556
557 In the base class this is a pure virtual function.
558*/
559
560/*!
561 \fn int QAbstractItemView::horizontalOffset() const = 0
562
563 Returns the horizontal offset of the view.
564
565 In the base class this is a pure virtual function.
566
567 \sa verticalOffset()
568*/
569
570/*!
571 \fn int QAbstractItemView::verticalOffset() const = 0
572
573 Returns the vertical offset of the view.
574
575 In the base class this is a pure virtual function.
576
577 \sa horizontalOffset()
578*/
579
580/*!
581 \fn bool QAbstractItemView::isIndexHidden(const QModelIndex &index) const
582
583 Returns \c true if the item referred to by the given \a index is hidden in the view,
584 otherwise returns \c false.
585
586 Hiding is a view specific feature. For example in TableView a column can be marked
587 as hidden or a row in the TreeView.
588
589 In the base class this is a pure virtual function.
590*/
591
592/*!
593 \fn void QAbstractItemView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags)
594
595 Applies the selection \a flags to the items in or touched by the
596 rectangle, \a rect.
597
598 When implementing your own itemview setSelection should call
599 selectionModel()->select(selection, flags) where selection
600 is either an empty QModelIndex or a QItemSelection that contains
601 all items that are contained in \a rect.
602
603 \sa selectionCommand(), selectedIndexes()
604*/
605
606/*!
607 \fn QRegion QAbstractItemView::visualRegionForSelection(const QItemSelection &selection) const = 0
608
609 Returns the region from the viewport of the items in the given
610 \a selection.
611
612 In the base class this is a pure virtual function.
613
614 \sa visualRect(), selectedIndexes()
615*/
616
617/*!
618 Constructs an abstract item view with the given \a parent.
619*/
620QAbstractItemView::QAbstractItemView(QWidget *parent)
621 : QAbstractScrollArea(*(new QAbstractItemViewPrivate), parent)
622{
623 d_func()->init();
624}
625
626/*!
627 \internal
628*/
629QAbstractItemView::QAbstractItemView(QAbstractItemViewPrivate &dd, QWidget *parent)
630 : QAbstractScrollArea(dd, parent)
631{
632 d_func()->init();
633}
634
635/*!
636 Destroys the view.
637*/
638QAbstractItemView::~QAbstractItemView()
639{
640 Q_D(QAbstractItemView);
641 // stop these timers here before ~QObject
642 d->delayedReset.stop();
643 d->updateTimer.stop();
644 d->delayedEditing.stop();
645 d->delayedAutoScroll.stop();
646 d->autoScrollTimer.stop();
647 d->delayedLayout.stop();
648 d->fetchMoreTimer.stop();
649}
650
651/*!
652 Sets the \a model for the view to present.
653
654 This function will create and set a new selection model, replacing any
655 model that was previously set with setSelectionModel(). However, the old
656 selection model will not be deleted as it may be shared between several
657 views. We recommend that you delete the old selection model if it is no
658 longer required. This is done with the following code:
659
660 \snippet code/src_gui_itemviews_qabstractitemview.cpp 2
661
662 If both the old model and the old selection model do not have parents, or
663 if their parents are long-lived objects, it may be preferable to call their
664 deleteLater() functions to explicitly delete them.
665
666 The view \e{does not} take ownership of the model unless it is the model's
667 parent object because the model may be shared between many different views.
668
669 \sa selectionModel(), setSelectionModel()
670*/
671void QAbstractItemView::setModel(QAbstractItemModel *model)
672{
673 Q_D(QAbstractItemView);
674 if (model == d->model)
675 return;
676 if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
677 disconnect(d->model, SIGNAL(destroyed()),
678 this, SLOT(_q_modelDestroyed()));
679 disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
680 this, SLOT(dataChanged(QModelIndex,QModelIndex,QVector<int>)));
681 disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
682 this, SLOT(_q_headerDataChanged()));
683 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
684 this, SLOT(rowsInserted(QModelIndex,int,int)));
685 disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
686 this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
687 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
688 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
689 disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
690 this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
691 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
692 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
693 disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
694 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
695 disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
696 this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
697 disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
698 this, SLOT(_q_columnsInserted(QModelIndex,int,int)));
699 disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
700 this, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
701
702 disconnect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
703 disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
704 }
705 d->model = (model ? model : QAbstractItemModelPrivate::staticEmptyModel());
706
707 // These asserts do basic sanity checking of the model
708 Q_ASSERT_X(d->model->index(0,0) == d->model->index(0,0),
709 "QAbstractItemView::setModel",
710 "A model should return the exact same index "
711 "(including its internal id/pointer) when asked for it twice in a row.");
712 Q_ASSERT_X(!d->model->index(0,0).parent().isValid(),
713 "QAbstractItemView::setModel",
714 "The parent of a top level index should be invalid");
715
716 if (d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
717 connect(d->model, SIGNAL(destroyed()),
718 this, SLOT(_q_modelDestroyed()));
719 connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
720 this, SLOT(dataChanged(QModelIndex,QModelIndex,QVector<int>)));
721 connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
722 this, SLOT(_q_headerDataChanged()));
723 connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
724 this, SLOT(rowsInserted(QModelIndex,int,int)));
725 connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
726 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
727 connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
728 this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
729 connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
730 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
731 connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
732 this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
733 connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
734 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
735 connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
736 this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
737 connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
738 this, SLOT(_q_columnsInserted(QModelIndex,int,int)));
739 connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
740 this, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
741
742 connect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
743 connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
744 }
745
746 QItemSelectionModel *selection_model = new QItemSelectionModel(d->model, this);
747 connect(d->model, SIGNAL(destroyed()), selection_model, SLOT(deleteLater()));
748 setSelectionModel(selection_model);
749
750 reset(); // kill editors, set new root and do layout
751}
752
753/*!
754 Returns the model that this view is presenting.
755*/
756QAbstractItemModel *QAbstractItemView::model() const
757{
758 Q_D(const QAbstractItemView);
759 return (d->model == QAbstractItemModelPrivate::staticEmptyModel() ? 0 : d->model);
760}
761
762/*!
763 Sets the current selection model to the given \a selectionModel.
764
765 Note that, if you call setModel() after this function, the given \a selectionModel
766 will be replaced by one created by the view.
767
768 \note It is up to the application to delete the old selection model if it is no
769 longer needed; i.e., if it is not being used by other views. This will happen
770 automatically when its parent object is deleted. However, if it does not have a
771 parent, or if the parent is a long-lived object, it may be preferable to call its
772 deleteLater() function to explicitly delete it.
773
774 \sa selectionModel(), setModel(), clearSelection()
775*/
776void QAbstractItemView::setSelectionModel(QItemSelectionModel *selectionModel)
777{
778 // ### if the given model is null, we should use the original selection model
779 Q_ASSERT(selectionModel);
780 Q_D(QAbstractItemView);
781
782 if (Q_UNLIKELY(selectionModel->model() != d->model)) {
783 qWarning("QAbstractItemView::setSelectionModel() failed: "
784 "Trying to set a selection model, which works on "
785 "a different model than the view.");
786 return;
787 }
788
789 QItemSelection oldSelection;
790 QModelIndex oldCurrentIndex;
791
792 if (d->selectionModel) {
793 if (d->selectionModel->model() == selectionModel->model()) {
794 oldSelection = d->selectionModel->selection();
795 oldCurrentIndex = d->selectionModel->currentIndex();
796 }
797
798 disconnect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
799 this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
800 disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
801 this, SLOT(currentChanged(QModelIndex,QModelIndex)));
802 }
803
804 d->selectionModel = selectionModel;
805
806 if (d->selectionModel) {
807 connect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
808 this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
809 connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
810 this, SLOT(currentChanged(QModelIndex,QModelIndex)));
811
812 selectionChanged(d->selectionModel->selection(), oldSelection);
813 currentChanged(d->selectionModel->currentIndex(), oldCurrentIndex);
814 }
815}
816
817/*!
818 Returns the current selection model.
819
820 \sa setSelectionModel(), selectedIndexes()
821*/
822QItemSelectionModel* QAbstractItemView::selectionModel() const
823{
824 Q_D(const QAbstractItemView);
825 return d->selectionModel;
826}
827
828/*!
829 Sets the item delegate for this view and its model to \a delegate.
830 This is useful if you want complete control over the editing and
831 display of items.
832
833 Any existing delegate will be removed, but not deleted. QAbstractItemView
834 does not take ownership of \a delegate.
835
836 \warning You should not share the same instance of a delegate between views.
837 Doing so can cause incorrect or unintuitive editing behavior since each
838 view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
839 signal, and attempt to access, modify or close an editor that has already been closed.
840
841 \sa itemDelegate()
842*/
843void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *delegate)
844{
845 Q_D(QAbstractItemView);
846 if (delegate == d->itemDelegate)
847 return;
848
849 if (d->itemDelegate) {
850 if (d->delegateRefCount(d->itemDelegate) == 1) {
851 disconnect(d->itemDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
852 this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
853 disconnect(d->itemDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
854 disconnect(d->itemDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()));
855 }
856 }
857
858 if (delegate) {
859 if (d->delegateRefCount(delegate) == 0) {
860 connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
861 this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
862 connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
863 connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()), Qt::QueuedConnection);
864 }
865 }
866 d->itemDelegate = delegate;
867 viewport()->update();
868 d->doDelayedItemsLayout();
869}
870
871/*!
872 Returns the item delegate used by this view and model. This is
873 either one set with setItemDelegate(), or the default one.
874
875 \sa setItemDelegate()
876*/
877QAbstractItemDelegate *QAbstractItemView::itemDelegate() const
878{
879 return d_func()->itemDelegate;
880}
881
882/*!
883 \reimp
884*/
885QVariant QAbstractItemView::inputMethodQuery(Qt::InputMethodQuery query) const
886{
887 const QModelIndex current = currentIndex();
888 if (!current.isValid() || query != Qt::ImCursorRectangle)
889 return QAbstractScrollArea::inputMethodQuery(query);
890 return visualRect(current);
891}
892
893/*!
894 \since 4.2
895
896 Sets the given item \a delegate used by this view and model for the given
897 \a row. All items on \a row will be drawn and managed by \a delegate
898 instead of using the default delegate (i.e., itemDelegate()).
899
900 Any existing row delegate for \a row will be removed, but not
901 deleted. QAbstractItemView does not take ownership of \a delegate.
902
903 \note If a delegate has been assigned to both a row and a column, the row
904 delegate (i.e., this delegate) will take precedence and manage the
905 intersecting cell index.
906
907 \warning You should not share the same instance of a delegate between views.
908 Doing so can cause incorrect or unintuitive editing behavior since each
909 view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
910 signal, and attempt to access, modify or close an editor that has already been closed.
911
912 \sa itemDelegateForRow(), setItemDelegateForColumn(), itemDelegate()
913*/
914void QAbstractItemView::setItemDelegateForRow(int row, QAbstractItemDelegate *delegate)
915{
916 Q_D(QAbstractItemView);
917 if (QAbstractItemDelegate *rowDelegate = d->rowDelegates.value(row, 0)) {
918 if (d->delegateRefCount(rowDelegate) == 1) {
919 disconnect(rowDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
920 this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
921 disconnect(rowDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
922 disconnect(rowDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()));
923 }
924 d->rowDelegates.remove(row);
925 }
926 if (delegate) {
927 if (d->delegateRefCount(delegate) == 0) {
928 connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
929 this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
930 connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
931 connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()), Qt::QueuedConnection);
932 }
933 d->rowDelegates.insert(row, delegate);
934 }
935 viewport()->update();
936 d->doDelayedItemsLayout();
937}
938
939/*!
940 \since 4.2
941
942 Returns the item delegate used by this view and model for the given \a row,
943 or \nullptr if no delegate has been assigned. You can call itemDelegate()
944 to get a pointer to the current delegate for a given index.
945
946 \sa setItemDelegateForRow(), itemDelegateForColumn(), setItemDelegate()
947*/
948QAbstractItemDelegate *QAbstractItemView::itemDelegateForRow(int row) const
949{
950 Q_D(const QAbstractItemView);
951 return d->rowDelegates.value(row, 0);
952}
953
954/*!
955 \since 4.2
956
957 Sets the given item \a delegate used by this view and model for the given
958 \a column. All items on \a column will be drawn and managed by \a delegate
959 instead of using the default delegate (i.e., itemDelegate()).
960
961 Any existing column delegate for \a column will be removed, but not
962 deleted. QAbstractItemView does not take ownership of \a delegate.
963
964 \note If a delegate has been assigned to both a row and a column, the row
965 delegate will take precedence and manage the intersecting cell index.
966
967 \warning You should not share the same instance of a delegate between views.
968 Doing so can cause incorrect or unintuitive editing behavior since each
969 view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
970 signal, and attempt to access, modify or close an editor that has already been closed.
971
972 \sa itemDelegateForColumn(), setItemDelegateForRow(), itemDelegate()
973*/
974void QAbstractItemView::setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate)
975{
976 Q_D(QAbstractItemView);
977 if (QAbstractItemDelegate *columnDelegate = d->columnDelegates.value(column, 0)) {
978 if (d->delegateRefCount(columnDelegate) == 1) {
979 disconnect(columnDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
980 this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
981 disconnect(columnDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
982 disconnect(columnDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()));
983 }
984 d->columnDelegates.remove(column);
985 }
986 if (delegate) {
987 if (d->delegateRefCount(delegate) == 0) {
988 connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
989 this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
990 connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
991 connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()), Qt::QueuedConnection);
992 }
993 d->columnDelegates.insert(column, delegate);
994 }
995 viewport()->update();
996 d->doDelayedItemsLayout();
997}
998
999/*!
1000 \since 4.2
1001
1002 Returns the item delegate used by this view and model for the given \a
1003 column. You can call itemDelegate() to get a pointer to the current delegate
1004 for a given index.
1005
1006 \sa setItemDelegateForColumn(), itemDelegateForRow(), itemDelegate()
1007*/
1008QAbstractItemDelegate *QAbstractItemView::itemDelegateForColumn(int column) const
1009{
1010 Q_D(const QAbstractItemView);
1011 return d->columnDelegates.value(column, 0);
1012}
1013
1014/*!
1015 Returns the item delegate used by this view and model for
1016 the given \a index.
1017*/
1018QAbstractItemDelegate *QAbstractItemView::itemDelegate(const QModelIndex &index) const
1019{
1020 Q_D(const QAbstractItemView);
1021 return d->delegateForIndex(index);
1022}
1023
1024/*!
1025 \property QAbstractItemView::selectionMode
1026 \brief which selection mode the view operates in
1027
1028 This property controls whether the user can select one or many items
1029 and, in many-item selections, whether the selection must be a
1030 continuous range of items.
1031
1032 \sa SelectionMode, SelectionBehavior
1033*/
1034void QAbstractItemView::setSelectionMode(SelectionMode mode)
1035{
1036 Q_D(QAbstractItemView);
1037 d->selectionMode = mode;
1038}
1039
1040QAbstractItemView::SelectionMode QAbstractItemView::selectionMode() const
1041{
1042 Q_D(const QAbstractItemView);
1043 return d->selectionMode;
1044}
1045
1046/*!
1047 \property QAbstractItemView::selectionBehavior
1048 \brief which selection behavior the view uses
1049
1050 This property holds whether selections are done
1051 in terms of single items, rows or columns.
1052
1053 \sa SelectionMode, SelectionBehavior
1054*/
1055
1056void QAbstractItemView::setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
1057{
1058 Q_D(QAbstractItemView);
1059 d->selectionBehavior = behavior;
1060}
1061
1062QAbstractItemView::SelectionBehavior QAbstractItemView::selectionBehavior() const
1063{
1064 Q_D(const QAbstractItemView);
1065 return d->selectionBehavior;
1066}
1067
1068/*!
1069 Sets the current item to be the item at \a index.
1070
1071 Unless the current selection mode is
1072 \l{QAbstractItemView::}{NoSelection}, the item is also selected.
1073 Note that this function also updates the starting position for any
1074 new selections the user performs.
1075
1076 To set an item as the current item without selecting it, call
1077
1078 \c{selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);}
1079
1080 \sa currentIndex(), currentChanged(), selectionMode
1081*/
1082void QAbstractItemView::setCurrentIndex(const QModelIndex &index)
1083{
1084 Q_D(QAbstractItemView);
1085 if (d->selectionModel && (!index.isValid() || d->isIndexEnabled(index))) {
1086 QItemSelectionModel::SelectionFlags command = selectionCommand(index, 0);
1087 d->selectionModel->setCurrentIndex(index, command);
1088 d->currentIndexSet = true;
1089 if ((command & QItemSelectionModel::Current) == 0)
1090 d->currentSelectionStartIndex = index;
1091 }
1092}
1093
1094/*!
1095 Returns the model index of the current item.
1096
1097 \sa setCurrentIndex()
1098*/
1099QModelIndex QAbstractItemView::currentIndex() const
1100{
1101 Q_D(const QAbstractItemView);
1102 return d->selectionModel ? d->selectionModel->currentIndex() : QModelIndex();
1103}
1104
1105
1106/*!
1107 Reset the internal state of the view.
1108
1109 \warning This function will reset open editors, scroll bar positions,
1110 selections, etc. Existing changes will not be committed. If you would like
1111 to save your changes when resetting the view, you can reimplement this
1112 function, commit your changes, and then call the superclass'
1113 implementation.
1114*/
1115void QAbstractItemView::reset()
1116{
1117 Q_D(QAbstractItemView);
1118 d->delayedReset.stop(); //make sure we stop the timer
1119 foreach (const QEditorInfo &info, d->indexEditorHash) {
1120 if (info.widget)
1121 d->releaseEditor(info.widget.data(), d->indexForEditor(info.widget.data()));
1122 }
1123 d->editorIndexHash.clear();
1124 d->indexEditorHash.clear();
1125 d->persistent.clear();
1126 d->currentIndexSet = false;
1127 setState(NoState);
1128 setRootIndex(QModelIndex());
1129 if (d->selectionModel)
1130 d->selectionModel->reset();
1131#ifndef QT_NO_ACCESSIBILITY
1132 if (QAccessible::isActive()) {
1133 QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::ModelReset);
1134 QAccessible::updateAccessibility(&accessibleEvent);
1135 }
1136#endif
1137 d->updateGeometry();
1138}
1139
1140/*!
1141 Sets the root item to the item at the given \a index.
1142
1143 \sa rootIndex()
1144*/
1145void QAbstractItemView::setRootIndex(const QModelIndex &index)
1146{
1147 Q_D(QAbstractItemView);
1148 if (Q_UNLIKELY(index.isValid() && index.model() != d->model)) {
1149 qWarning("QAbstractItemView::setRootIndex failed : index must be from the currently set model");
1150 return;
1151 }
1152 d->root = index;
1153 d->doDelayedItemsLayout();
1154 d->updateGeometry();
1155}
1156
1157/*!
1158 Returns the model index of the model's root item. The root item is
1159 the parent item to the view's toplevel items. The root can be invalid.
1160
1161 \sa setRootIndex()
1162*/
1163QModelIndex QAbstractItemView::rootIndex() const
1164{
1165 return QModelIndex(d_func()->root);
1166}
1167
1168/*!
1169 Selects all items in the view.
1170 This function will use the selection behavior
1171 set on the view when selecting.
1172
1173 \sa setSelection(), selectedIndexes(), clearSelection()
1174*/
1175void QAbstractItemView::selectAll()
1176{
1177 Q_D(QAbstractItemView);
1178 SelectionMode mode = d->selectionMode;
1179 if (mode == MultiSelection || mode == ExtendedSelection)
1180 d->selectAll(QItemSelectionModel::ClearAndSelect
1181 |d->selectionBehaviorFlags());
1182 else if (mode != SingleSelection)
1183 d->selectAll(selectionCommand(d->model->index(0, 0, d->root)));
1184}
1185
1186/*!
1187 Starts editing the item corresponding to the given \a index if it is
1188 editable.
1189
1190 Note that this function does not change the current index. Since the current
1191 index defines the next and previous items to edit, users may find that
1192 keyboard navigation does not work as expected. To provide consistent navigation
1193 behavior, call setCurrentIndex() before this function with the same model
1194 index.
1195
1196 \sa QModelIndex::flags()
1197*/
1198void QAbstractItemView::edit(const QModelIndex &index)
1199{
1200 Q_D(QAbstractItemView);
1201 if (Q_UNLIKELY(!d->isIndexValid(index)))
1202 qWarning("edit: index was invalid");
1203 if (Q_UNLIKELY(!edit(index, AllEditTriggers, 0)))
1204 qWarning("edit: editing failed");
1205}
1206
1207/*!
1208 Deselects all selected items. The current index will not be changed.
1209
1210 \sa setSelection(), selectAll()
1211*/
1212void QAbstractItemView::clearSelection()
1213{
1214 Q_D(QAbstractItemView);
1215 if (d->selectionModel)
1216 d->selectionModel->clearSelection();
1217}
1218
1219/*!
1220 \internal
1221
1222 This function is intended to lay out the items in the view.
1223 The default implementation just calls updateGeometries() and updates the viewport.
1224*/
1225void QAbstractItemView::doItemsLayout()
1226{
1227 Q_D(QAbstractItemView);
1228 d->interruptDelayedItemsLayout();
1229 updateGeometries();
1230 d->viewport->update();
1231}
1232
1233/*!
1234 \property QAbstractItemView::editTriggers
1235 \brief which actions will initiate item editing
1236
1237 This property is a selection of flags defined by
1238 \l{EditTrigger}, combined using the OR
1239 operator. The view will only initiate the editing of an item if the
1240 action performed is set in this property.
1241*/
1242void QAbstractItemView::setEditTriggers(EditTriggers actions)
1243{
1244 Q_D(QAbstractItemView);
1245 d->editTriggers = actions;
1246}
1247
1248QAbstractItemView::EditTriggers QAbstractItemView::editTriggers() const
1249{
1250 Q_D(const QAbstractItemView);
1251 return d->editTriggers;
1252}
1253
1254/*!
1255 \since 4.2
1256 \property QAbstractItemView::verticalScrollMode
1257 \brief how the view scrolls its contents in the vertical direction
1258
1259 This property controls how the view scroll its contents vertically.
1260 Scrolling can be done either per pixel or per item. Its default value
1261 comes from the style via the QStyle::SH_ItemView_ScrollMode style hint.
1262*/
1263
1264void QAbstractItemView::setVerticalScrollMode(ScrollMode mode)
1265{
1266 Q_D(QAbstractItemView);
1267 d->verticalScrollModeSet = true;
1268 if (mode == d->verticalScrollMode)
1269 return;
1270 QModelIndex topLeft = indexAt(QPoint(0, 0));
1271 d->verticalScrollMode = mode;
1272 if (mode == ScrollPerItem)
1273 verticalScrollBar()->d_func()->itemviewChangeSingleStep(1); // setSingleStep(-1) => step with 1
1274 else
1275 verticalScrollBar()->setSingleStep(-1); // Ensure that the view can update single step
1276 updateGeometries(); // update the scroll bars
1277 scrollTo(topLeft, QAbstractItemView::PositionAtTop);
1278}
1279
1280QAbstractItemView::ScrollMode QAbstractItemView::verticalScrollMode() const
1281{
1282 Q_D(const QAbstractItemView);
1283 return d->verticalScrollMode;
1284}
1285
1286void QAbstractItemView::resetVerticalScrollMode()
1287{
1288 auto sm = static_cast<ScrollMode>(style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, this, 0));
1289 setVerticalScrollMode(sm);
1290 d_func()->verticalScrollModeSet = false;
1291}
1292
1293/*!
1294 \since 4.2
1295 \property QAbstractItemView::horizontalScrollMode
1296 \brief how the view scrolls its contents in the horizontal direction
1297
1298 This property controls how the view scroll its contents horizontally.
1299 Scrolling can be done either per pixel or per item. Its default value
1300 comes from the style via the QStyle::SH_ItemView_ScrollMode style hint.
1301*/
1302
1303void QAbstractItemView::setHorizontalScrollMode(ScrollMode mode)
1304{
1305 Q_D(QAbstractItemView);
1306 d->horizontalScrollModeSet = true;
1307 if (mode == d->horizontalScrollMode)
1308 return;
1309 d->horizontalScrollMode = mode;
1310 if (mode == ScrollPerItem)
1311 horizontalScrollBar()->d_func()->itemviewChangeSingleStep(1); // setSingleStep(-1) => step with 1
1312 else
1313 horizontalScrollBar()->setSingleStep(-1); // Ensure that the view can update single step
1314 updateGeometries(); // update the scroll bars
1315}
1316
1317QAbstractItemView::ScrollMode QAbstractItemView::horizontalScrollMode() const
1318{
1319 Q_D(const QAbstractItemView);
1320 return d->horizontalScrollMode;
1321}
1322
1323void QAbstractItemView::resetHorizontalScrollMode()
1324{
1325 auto sm = static_cast<ScrollMode>(style()->styleHint(QStyle::SH_ItemView_ScrollMode, 0, this, 0));
1326 setHorizontalScrollMode(sm);
1327 d_func()->horizontalScrollModeSet = false;
1328}
1329
1330#if QT_CONFIG(draganddrop)
1331/*!
1332 \since 4.2
1333 \property QAbstractItemView::dragDropOverwriteMode
1334 \brief the view's drag and drop behavior
1335
1336 If its value is \c true, the selected data will overwrite the
1337 existing item data when dropped, while moving the data will clear
1338 the item. If its value is \c false, the selected data will be
1339 inserted as a new item when the data is dropped. When the data is
1340 moved, the item is removed as well.
1341
1342 The default value is \c false, as in the QListView and QTreeView
1343 subclasses. In the QTableView subclass, on the other hand, the
1344 property has been set to \c true.
1345
1346 Note: This is not intended to prevent overwriting of items.
1347 The model's implementation of flags() should do that by not
1348 returning Qt::ItemIsDropEnabled.
1349
1350 \sa dragDropMode
1351*/
1352void QAbstractItemView::setDragDropOverwriteMode(bool overwrite)
1353{
1354 Q_D(QAbstractItemView);
1355 d->overwrite = overwrite;
1356}
1357
1358bool QAbstractItemView::dragDropOverwriteMode() const
1359{
1360 Q_D(const QAbstractItemView);
1361 return d->overwrite;
1362}
1363#endif
1364
1365/*!
1366 \property QAbstractItemView::autoScroll
1367 \brief whether autoscrolling in drag move events is enabled
1368
1369 If this property is set to true (the default), the
1370 QAbstractItemView automatically scrolls the contents of the view
1371 if the user drags within 16 pixels of the viewport edge. If the current
1372 item changes, then the view will scroll automatically to ensure that the
1373 current item is fully visible.
1374
1375 This property only works if the viewport accepts drops. Autoscroll is
1376 switched off by setting this property to false.
1377*/
1378
1379void QAbstractItemView::setAutoScroll(bool enable)
1380{
1381 Q_D(QAbstractItemView);
1382 d->autoScroll = enable;
1383}
1384
1385bool QAbstractItemView::hasAutoScroll() const
1386{
1387 Q_D(const QAbstractItemView);
1388 return d->autoScroll;
1389}
1390
1391/*!
1392 \since 4.4
1393 \property QAbstractItemView::autoScrollMargin
1394 \brief the size of the area when auto scrolling is triggered
1395
1396 This property controls the size of the area at the edge of the viewport that
1397 triggers autoscrolling. The default value is 16 pixels.
1398*/
1399void QAbstractItemView::setAutoScrollMargin(int margin)
1400{
1401 Q_D(QAbstractItemView);
1402 d->autoScrollMargin = margin;
1403}
1404
1405int QAbstractItemView::autoScrollMargin() const
1406{
1407 Q_D(const QAbstractItemView);
1408 return d->autoScrollMargin;
1409}
1410
1411/*!
1412 \property QAbstractItemView::tabKeyNavigation
1413 \brief whether item navigation with tab and backtab is enabled.
1414*/
1415
1416void QAbstractItemView::setTabKeyNavigation(bool enable)
1417{
1418 Q_D(QAbstractItemView);
1419 d->tabKeyNavigation = enable;
1420}
1421
1422bool QAbstractItemView::tabKeyNavigation() const
1423{
1424 Q_D(const QAbstractItemView);
1425 return d->tabKeyNavigation;
1426}
1427
1428/*!
1429 \since 5.2
1430 \reimp
1431*/
1432QSize QAbstractItemView::viewportSizeHint() const
1433{
1434 return QAbstractScrollArea::viewportSizeHint();
1435}
1436
1437#if QT_CONFIG(draganddrop)
1438/*!
1439 \property QAbstractItemView::showDropIndicator
1440 \brief whether the drop indicator is shown when dragging items and dropping.
1441
1442 \sa dragEnabled, DragDropMode, dragDropOverwriteMode, acceptDrops
1443*/
1444
1445void QAbstractItemView::setDropIndicatorShown(bool enable)
1446{
1447 Q_D(QAbstractItemView);
1448 d->showDropIndicator = enable;
1449}
1450
1451bool QAbstractItemView::showDropIndicator() const
1452{
1453 Q_D(const QAbstractItemView);
1454 return d->showDropIndicator;
1455}
1456
1457/*!
1458 \property QAbstractItemView::dragEnabled
1459 \brief whether the view supports dragging of its own items
1460
1461 \sa showDropIndicator, DragDropMode, dragDropOverwriteMode, acceptDrops
1462*/
1463
1464void QAbstractItemView::setDragEnabled(bool enable)
1465{
1466 Q_D(QAbstractItemView);
1467 d->dragEnabled = enable;
1468}
1469
1470bool QAbstractItemView::dragEnabled() const
1471{
1472 Q_D(const QAbstractItemView);
1473 return d->dragEnabled;
1474}
1475
1476/*!
1477 \since 4.2
1478 \enum QAbstractItemView::DragDropMode
1479
1480 Describes the various drag and drop events the view can act upon.
1481 By default the view does not support dragging or dropping (\c
1482 NoDragDrop).
1483
1484 \value NoDragDrop Does not support dragging or dropping.
1485 \value DragOnly The view supports dragging of its own items
1486 \value DropOnly The view accepts drops
1487 \value DragDrop The view supports both dragging and dropping
1488 \value InternalMove The view accepts move (\b{not copy}) operations only
1489 from itself.
1490
1491 Note that the model used needs to provide support for drag and drop operations.
1492
1493 \sa setDragDropMode(), {Using drag and drop with item views}
1494*/
1495
1496/*!
1497 \property QAbstractItemView::dragDropMode
1498 \brief the drag and drop event the view will act upon
1499
1500 \since 4.2
1501 \sa showDropIndicator, dragDropOverwriteMode
1502*/
1503void QAbstractItemView::setDragDropMode(DragDropMode behavior)
1504{
1505 Q_D(QAbstractItemView);
1506 d->dragDropMode = behavior;
1507 setDragEnabled(behavior == DragOnly || behavior == DragDrop || behavior == InternalMove);
1508 setAcceptDrops(behavior == DropOnly || behavior == DragDrop || behavior == InternalMove);
1509}
1510
1511QAbstractItemView::DragDropMode QAbstractItemView::dragDropMode() const
1512{
1513 Q_D(const QAbstractItemView);
1514 DragDropMode setBehavior = d->dragDropMode;
1515 if (!dragEnabled() && !acceptDrops())
1516 return NoDragDrop;
1517
1518 if (dragEnabled() && !acceptDrops())
1519 return DragOnly;
1520
1521 if (!dragEnabled() && acceptDrops())
1522 return DropOnly;
1523
1524 if (dragEnabled() && acceptDrops()) {
1525 if (setBehavior == InternalMove)
1526 return setBehavior;
1527 else
1528 return DragDrop;
1529 }
1530
1531 return NoDragDrop;
1532}
1533
1534/*!
1535 \property QAbstractItemView::defaultDropAction
1536 \brief the drop action that will be used by default in QAbstractItemView::drag()
1537
1538 If the property is not set, the drop action is CopyAction when the supported
1539 actions support CopyAction.
1540
1541 \since 4.6
1542 \sa showDropIndicator, dragDropOverwriteMode
1543*/
1544void QAbstractItemView::setDefaultDropAction(Qt::DropAction dropAction)
1545{
1546 Q_D(QAbstractItemView);
1547 d->defaultDropAction = dropAction;
1548}
1549
1550Qt::DropAction QAbstractItemView::defaultDropAction() const
1551{
1552 Q_D(const QAbstractItemView);
1553 return d->defaultDropAction;
1554}
1555
1556#endif // QT_CONFIG(draganddrop)
1557
1558/*!
1559 \property QAbstractItemView::alternatingRowColors
1560 \brief whether to draw the background using alternating colors
1561
1562 If this property is \c true, the item background will be drawn using
1563 QPalette::Base and QPalette::AlternateBase; otherwise the background
1564 will be drawn using the QPalette::Base color.
1565
1566 By default, this property is \c false.
1567*/
1568void QAbstractItemView::setAlternatingRowColors(bool enable)
1569{
1570 Q_D(QAbstractItemView);
1571 d->alternatingColors = enable;
1572 if (isVisible())
1573 d->viewport->update();
1574}
1575
1576bool QAbstractItemView::alternatingRowColors() const
1577{
1578 Q_D(const QAbstractItemView);
1579 return d->alternatingColors;
1580}
1581
1582/*!
1583 \property QAbstractItemView::iconSize
1584 \brief the size of items' icons
1585
1586 Setting this property when the view is visible will cause the
1587 items to be laid out again.
1588*/
1589void QAbstractItemView::setIconSize(const QSize &size)
1590{
1591 Q_D(QAbstractItemView);
1592 if (size == d->iconSize)
1593 return;
1594 d->iconSize = size;
1595 d->doDelayedItemsLayout();
1596 emit iconSizeChanged(size);
1597}
1598
1599QSize QAbstractItemView::iconSize() const
1600{
1601 Q_D(const QAbstractItemView);
1602 return d->iconSize;
1603}
1604
1605/*!
1606 \property QAbstractItemView::textElideMode
1607
1608 \brief the position of the "..." in elided text.
1609
1610 The default value for all item views is Qt::ElideRight.
1611*/
1612void QAbstractItemView::setTextElideMode(Qt::TextElideMode mode)
1613{
1614 Q_D(QAbstractItemView);
1615 d->textElideMode = mode;
1616}
1617
1618Qt::TextElideMode QAbstractItemView::textElideMode() const
1619{
1620 return d_func()->textElideMode;
1621}
1622
1623/*!
1624 \reimp
1625*/
1626bool QAbstractItemView::focusNextPrevChild(bool next)
1627{
1628 Q_D(QAbstractItemView);
1629 if (d->tabKeyNavigation && isEnabled() && d->viewport->isEnabled()) {
1630 QKeyEvent event(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
1631 keyPressEvent(&event);
1632 if (event.isAccepted())
1633 return true;
1634 }
1635 return QAbstractScrollArea::focusNextPrevChild(next);
1636}
1637
1638/*!
1639 \reimp
1640*/
1641bool QAbstractItemView::event(QEvent *event)
1642{
1643 Q_D(QAbstractItemView);
1644 switch (event->type()) {
1645 case QEvent::Paint:
1646 //we call this here because the scrollbars' visibility might be altered
1647 //so this can't be done in the paintEvent method
1648 d->executePostedLayout(); //make sure we set the layout properly
1649 break;
1650 case QEvent::Show:
1651 d->executePostedLayout(); //make sure we set the layout properly
1652 if (d->shouldScrollToCurrentOnShow) {
1653 d->shouldScrollToCurrentOnShow = false;
1654 const QModelIndex current = currentIndex();
1655 if (current.isValid() && (d->state == QAbstractItemView::EditingState || d->autoScroll))
1656 scrollTo(current);
1657 }
1658 break;
1659 case QEvent::LocaleChange:
1660 viewport()->update();
1661 break;
1662 case QEvent::LayoutDirectionChange:
1663 case QEvent::ApplicationLayoutDirectionChange:
1664 updateGeometries();
1665 break;
1666 case QEvent::StyleChange:
1667 doItemsLayout();
1668 if (!d->verticalScrollModeSet)
1669 resetVerticalScrollMode();
1670 if (!d->horizontalScrollModeSet)
1671 resetHorizontalScrollMode();
1672 break;
1673 case QEvent::FocusOut:
1674 d->checkPersistentEditorFocus();
1675 break;
1676 case QEvent::FontChange:
1677 d->doDelayedItemsLayout(); // the size of the items will change
1678 break;
1679 default:
1680 break;
1681 }
1682 return QAbstractScrollArea::event(event);
1683}
1684
1685/*!
1686 \fn bool QAbstractItemView::viewportEvent(QEvent *event)
1687
1688 This function is used to handle tool tips, and What's
1689 This? mode, if the given \a event is a QEvent::ToolTip,or a
1690 QEvent::WhatsThis. It passes all other
1691 events on to its base class viewportEvent() handler.
1692
1693 Returns \c true if \a event has been recognized and processed; otherwise,
1694 returns \c false.
1695*/
1696bool QAbstractItemView::viewportEvent(QEvent *event)
1697{
1698 Q_D(QAbstractItemView);
1699 switch (event->type()) {
1700 case QEvent::HoverMove:
1701 case QEvent::HoverEnter:
1702 d->setHoverIndex(indexAt(static_cast<QHoverEvent*>(event)->pos()));
1703 break;
1704 case QEvent::HoverLeave:
1705 d->setHoverIndex(QModelIndex());
1706 break;
1707 case QEvent::Enter:
1708 d->viewportEnteredNeeded = true;
1709 break;
1710 case QEvent::Leave:
1711 d->setHoverIndex(QModelIndex()); // If we've left, no hover should be needed anymore
1712 #if QT_CONFIG(statustip)
1713 if (d->shouldClearStatusTip && d->parent) {
1714 QString empty;
1715 QStatusTipEvent tip(empty);
1716 QApplication::sendEvent(d->parent, &tip);
1717 d->shouldClearStatusTip = false;
1718 }
1719 #endif
1720 d->enteredIndex = QModelIndex();
1721 break;
1722 case QEvent::ToolTip:
1723 case QEvent::QueryWhatsThis:
1724 case QEvent::WhatsThis: {
1725 QHelpEvent *he = static_cast<QHelpEvent*>(event);
1726 const QModelIndex index = indexAt(he->pos());
1727 QStyleOptionViewItem option = d->viewOptionsV1();
1728 option.rect = visualRect(index);
1729 option.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
1730
1731 QAbstractItemDelegate *delegate = d->delegateForIndex(index);
1732 if (!delegate)
1733 return false;
1734 return delegate->helpEvent(he, this, option, index);
1735 }
1736 case QEvent::FontChange:
1737 d->doDelayedItemsLayout(); // the size of the items will change
1738 break;
1739 case QEvent::WindowActivate:
1740 case QEvent::WindowDeactivate:
1741 d->viewport->update();
1742 break;
1743 case QEvent::ScrollPrepare:
1744 executeDelayedItemsLayout();
1745#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
1746 connect(QScroller::scroller(d->viewport), SIGNAL(stateChanged(QScroller::State)), this, SLOT(_q_scrollerStateChanged()), Qt::UniqueConnection);
1747#endif
1748 break;
1749
1750 default:
1751 break;
1752 }
1753 return QAbstractScrollArea::viewportEvent(event);
1754}
1755
1756/*!
1757 This function is called with the given \a event when a mouse button is pressed
1758 while the cursor is inside the widget. If a valid item is pressed on it is made
1759 into the current item. This function emits the pressed() signal.
1760*/
1761void QAbstractItemView::mousePressEvent(QMouseEvent *event)
1762{
1763 Q_D(QAbstractItemView);
1764 d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
1765 QPoint pos = event->pos();
1766 QPersistentModelIndex index = indexAt(pos);
1767
1768 if (!d->selectionModel
1769 || (d->state == EditingState && d->hasEditor(index)))
1770 return;
1771
1772 d->pressedAlreadySelected = d->selectionModel->isSelected(index);
1773 d->pressedIndex = index;
1774 d->pressedModifiers = event->modifiers();
1775 QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1776 d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid();
1777 QPoint offset = d->offset();
1778 if ((command & QItemSelectionModel::Current) == 0) {
1779 d->pressedPosition = pos + offset;
1780 d->currentSelectionStartIndex = index;
1781 }
1782 else if (!d->currentSelectionStartIndex.isValid())
1783 d->currentSelectionStartIndex = currentIndex();
1784
1785 if (edit(index, NoEditTriggers, event))
1786 return;
1787
1788 if (index.isValid() && d->isIndexEnabled(index)) {
1789 // we disable scrollTo for mouse press so the item doesn't change position
1790 // when the user is interacting with it (ie. clicking on it)
1791 bool autoScroll = d->autoScroll;
1792 d->autoScroll = false;
1793 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1794 d->autoScroll = autoScroll;
1795 if (command.testFlag(QItemSelectionModel::Toggle)) {
1796 command &= ~QItemSelectionModel::Toggle;
1797 d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
1798 command |= d->ctrlDragSelectionFlag;
1799 }
1800
1801 if ((command & QItemSelectionModel::Current) == 0) {
1802 setSelection(QRect(pos, QSize(1, 1)), command);
1803 } else {
1804 QRect rect(visualRect(d->currentSelectionStartIndex).center(), pos);
1805 setSelection(rect, command);
1806 }
1807
1808 // signal handlers may change the model
1809 emit pressed(index);
1810 if (d->autoScroll) {
1811 //we delay the autoscrolling to filter out double click event
1812 //100 is to be sure that there won't be a double-click misinterpreted as a 2 single clicks
1813 d->delayedAutoScroll.start(QApplication::doubleClickInterval()+100, this);
1814 }
1815
1816 } else {
1817 // Forces a finalize() even if mouse is pressed, but not on a item
1818 d->selectionModel->select(QModelIndex(), QItemSelectionModel::Select);
1819 }
1820}
1821
1822/*!
1823 This function is called with the given \a event when a mouse move event is
1824 sent to the widget. If a selection is in progress and new items are moved
1825 over the selection is extended; if a drag is in progress it is continued.
1826*/
1827void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
1828{
1829 Q_D(QAbstractItemView);
1830 QPoint topLeft;
1831 QPoint bottomRight = event->pos();
1832
1833 if (state() == ExpandingState || state() == CollapsingState)
1834 return;
1835
1836#if QT_CONFIG(draganddrop)
1837 if (state() == DraggingState) {
1838 topLeft = d->pressedPosition - d->offset();
1839 if ((topLeft - bottomRight).manhattanLength() > QApplication::startDragDistance()) {
1840 d->pressedIndex = QModelIndex();
1841 startDrag(d->model->supportedDragActions());
1842 setState(NoState); // the startDrag will return when the dnd operation is done
1843 stopAutoScroll();
1844 }
1845 return;
1846 }
1847#endif // QT_CONFIG(draganddrop)
1848
1849 QPersistentModelIndex index = indexAt(bottomRight);
1850 QModelIndex buddy = d->model->buddy(d->pressedIndex);
1851 if ((state() == EditingState && d->hasEditor(buddy))
1852 || edit(index, NoEditTriggers, event))
1853 return;
1854
1855 if (d->selectionMode != SingleSelection)
1856 topLeft = d->pressedPosition - d->offset();
1857 else
1858 topLeft = bottomRight;
1859
1860 d->checkMouseMove(index);
1861
1862#if QT_CONFIG(draganddrop)
1863 if (d->pressedIndex.isValid()
1864 && d->dragEnabled
1865 && (state() != DragSelectingState)
1866 && (event->buttons() != Qt::NoButton)
1867 && !d->selectedDraggableIndexes().isEmpty()) {
1868 setState(DraggingState);
1869 return;
1870 }
1871#endif
1872
1873 if ((event->buttons() & Qt::LeftButton) && d->selectionAllowed(index) && d->selectionModel) {
1874 setState(DragSelectingState);
1875 QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1876 if (d->ctrlDragSelectionFlag != QItemSelectionModel::NoUpdate && command.testFlag(QItemSelectionModel::Toggle)) {
1877 command &= ~QItemSelectionModel::Toggle;
1878 command |= d->ctrlDragSelectionFlag;
1879 }
1880
1881 // Do the normalize ourselves, since QRect::normalized() is flawed
1882 QRect selectionRect = QRect(topLeft, bottomRight);
1883 setSelection(selectionRect, command);
1884
1885 // set at the end because it might scroll the view
1886 if (index.isValid()
1887 && (index != d->selectionModel->currentIndex())
1888 && d->isIndexEnabled(index))
1889 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1890 }
1891}
1892
1893/*!
1894 This function is called with the given \a event when a mouse button is released,
1895 after a mouse press event on the widget. If a user presses the mouse inside your
1896 widget and then drags the mouse to another location before releasing the mouse button,
1897 your widget receives the release event. The function will emit the clicked() signal if an
1898 item was being pressed.
1899*/
1900void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
1901{
1902 Q_D(QAbstractItemView);
1903
1904 QPoint pos = event->pos();
1905 QPersistentModelIndex index = indexAt(pos);
1906
1907 if (state() == EditingState) {
1908 if (d->isIndexValid(index)
1909 && d->isIndexEnabled(index)
1910 && d->sendDelegateEvent(index, event))
1911 update(index);
1912 return;
1913 }
1914
1915 bool click = (index == d->pressedIndex && index.isValid());
1916 bool selectedClicked = click && (event->button() == Qt::LeftButton) && d->pressedAlreadySelected;
1917 EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
1918 const bool edited = click ? edit(index, trigger, event) : false;
1919
1920 d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
1921
1922 if (d->selectionModel && d->noSelectionOnMousePress) {
1923 d->noSelectionOnMousePress = false;
1924 d->selectionModel->select(index, selectionCommand(index, event));
1925 }
1926
1927 setState(NoState);
1928
1929 if (click) {
1930 if (event->button() == Qt::LeftButton)
1931 emit clicked(index);
1932 if (edited)
1933 return;
1934 QStyleOptionViewItem option = d->viewOptionsV1();
1935 if (d->pressedAlreadySelected)
1936 option.state |= QStyle::State_Selected;
1937 if ((d->model->flags(index) & Qt::ItemIsEnabled)
1938 && style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
1939 emit activated(index);
1940 }
1941}
1942
1943/*!
1944 This function is called with the given \a event when a mouse button is
1945 double clicked inside the widget. If the double-click is on a valid item it
1946 emits the doubleClicked() signal and calls edit() on the item.
1947*/
1948void QAbstractItemView::mouseDoubleClickEvent(QMouseEvent *event)
1949{
1950 Q_D(QAbstractItemView);
1951
1952 QModelIndex index = indexAt(event->pos());
1953 if (!index.isValid()
1954 || !d->isIndexEnabled(index)
1955 || (d->pressedIndex != index)) {
1956 QMouseEvent me(QEvent::MouseButtonPress,
1957 event->localPos(), event->windowPos(), event->screenPos(),
1958 event->button(), event->buttons(), event->modifiers(), event->source());
1959 mousePressEvent(&me);
1960 return;
1961 }
1962 // signal handlers may change the model
1963 QPersistentModelIndex persistent = index;
1964 emit doubleClicked(persistent);
1965 if ((event->button() == Qt::LeftButton) && !edit(persistent, DoubleClicked, event)
1966 && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this))
1967 emit activated(persistent);
1968}
1969
1970#if QT_CONFIG(draganddrop)
1971
1972/*!
1973 This function is called with the given \a event when a drag and drop operation enters
1974 the widget. If the drag is over a valid dropping place (e.g. over an item that
1975 accepts drops), the event is accepted; otherwise it is ignored.
1976
1977 \sa dropEvent(), startDrag()
1978*/
1979void QAbstractItemView::dragEnterEvent(QDragEnterEvent *event)
1980{
1981 if (dragDropMode() == InternalMove
1982 && (event->source() != this|| !(event->possibleActions() & Qt::MoveAction)))
1983 return;
1984
1985 if (d_func()->canDrop(event)) {
1986 event->accept();
1987 setState(DraggingState);
1988 } else {
1989 event->ignore();
1990 }
1991}
1992
1993/*!
1994 This function is called continuously with the given \a event during a drag and
1995 drop operation over the widget. It can cause the view to scroll if, for example,
1996 the user drags a selection to view's right or bottom edge. In this case, the
1997 event will be accepted; otherwise it will be ignored.
1998
1999 \sa dropEvent(), startDrag()
2000*/
2001void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event)
2002{
2003 Q_D(QAbstractItemView);
2004 if (dragDropMode() == InternalMove
2005 && (event->source() != this || !(event->possibleActions() & Qt::MoveAction)))
2006 return;
2007
2008 // ignore by default
2009 event->ignore();
2010
2011 QModelIndex index = indexAt(event->pos());
2012 d->hover = index;
2013 if (!d->droppingOnItself(event, index)
2014 && d->canDrop(event)) {
2015
2016 if (index.isValid() && d->showDropIndicator) {
2017 QRect rect = visualRect(index);
2018 d->dropIndicatorPosition = d->position(event->pos(), rect, index);
2019 switch (d->dropIndicatorPosition) {
2020 case AboveItem:
2021 if (d->isIndexDropEnabled(index.parent())) {
2022 d->dropIndicatorRect = QRect(rect.left(), rect.top(), rect.width(), 0);
2023 event->acceptProposedAction();
2024 } else {
2025 d->dropIndicatorRect = QRect();
2026 }
2027 break;
2028 case BelowItem:
2029 if (d->isIndexDropEnabled(index.parent())) {
2030 d->dropIndicatorRect = QRect(rect.left(), rect.bottom(), rect.width(), 0);
2031 event->acceptProposedAction();
2032 } else {
2033 d->dropIndicatorRect = QRect();
2034 }
2035 break;
2036 case OnItem:
2037 if (d->isIndexDropEnabled(index)) {
2038 d->dropIndicatorRect = rect;
2039 event->acceptProposedAction();
2040 } else {
2041 d->dropIndicatorRect = QRect();
2042 }
2043 break;
2044 case OnViewport:
2045 d->dropIndicatorRect = QRect();
2046 if (d->isIndexDropEnabled(rootIndex())) {
2047 event->acceptProposedAction(); // allow dropping in empty areas
2048 }
2049 break;
2050 }
2051 } else {
2052 d->dropIndicatorRect = QRect();
2053 d->dropIndicatorPosition = OnViewport;
2054 if (d->isIndexDropEnabled(rootIndex())) {
2055 event->acceptProposedAction(); // allow dropping in empty areas
2056 }
2057 }
2058 d->viewport->update();
2059 } // can drop
2060
2061 if (d->shouldAutoScroll(event->pos()))
2062 startAutoScroll();
2063}
2064
2065/*!
2066 \internal
2067 Return true if this is a move from ourself and \a index is a child of the selection that
2068 is being moved.
2069 */
2070bool QAbstractItemViewPrivate::droppingOnItself(QDropEvent *event, const QModelIndex &index)
2071{
2072 Q_Q(QAbstractItemView);
2073 Qt::DropAction dropAction = event->dropAction();
2074 if (q->dragDropMode() == QAbstractItemView::InternalMove)
2075 dropAction = Qt::MoveAction;
2076 if (event->source() == q
2077 && event->possibleActions() & Qt::MoveAction
2078 && dropAction == Qt::MoveAction) {
2079 QModelIndexList selectedIndexes = q->selectedIndexes();
2080 QModelIndex child = index;
2081 while (child.isValid() && child != root) {
2082 if (selectedIndexes.contains(child))
2083 return true;
2084 child = child.parent();
2085 }
2086 }
2087 return false;
2088}
2089
2090/*!
2091 \fn void QAbstractItemView::dragLeaveEvent(QDragLeaveEvent *event)
2092
2093 This function is called when the item being dragged leaves the view.
2094 The \a event describes the state of the drag and drop operation.
2095*/
2096void QAbstractItemView::dragLeaveEvent(QDragLeaveEvent *)
2097{
2098 Q_D(QAbstractItemView);
2099 stopAutoScroll();
2100 setState(NoState);
2101 d->hover = QModelIndex();
2102 d->viewport->update();
2103}
2104
2105/*!
2106 This function is called with the given \a event when a drop event occurs over
2107 the widget. If the model accepts the even position the drop event is accepted;
2108 otherwise it is ignored.
2109
2110 \sa startDrag()
2111*/
2112void QAbstractItemView::dropEvent(QDropEvent *event)
2113{
2114 Q_D(QAbstractItemView);
2115 if (dragDropMode() == InternalMove) {
2116 if (event->source() != this || !(event->possibleActions() & Qt::MoveAction))
2117 return;
2118 }
2119
2120 QModelIndex index;
2121 int col = -1;
2122 int row = -1;
2123 if (d->dropOn(event, &row, &col, &index)) {
2124 const Qt::DropAction action = dragDropMode() == InternalMove ? Qt::MoveAction : event->dropAction();
2125 if (d->model->dropMimeData(event->mimeData(), action, row, col, index)) {
2126 if (action != event->dropAction()) {
2127 event->setDropAction(action);
2128 event->accept();
2129 } else {
2130 event->acceptProposedAction();
2131 }
2132 }
2133 }
2134 stopAutoScroll();
2135 setState(NoState);
2136 d->viewport->update();
2137}
2138
2139/*!
2140 If the event hasn't already been accepted, determines the index to drop on.
2141
2142 if (row == -1 && col == -1)
2143 // append to this drop index
2144 else
2145 // place at row, col in drop index
2146
2147 If it returns \c true a drop can be done, and dropRow, dropCol and dropIndex reflects the position of the drop.
2148 \internal
2149 */
2150bool QAbstractItemViewPrivate::dropOn(QDropEvent *event, int *dropRow, int *dropCol, QModelIndex *dropIndex)
2151{
2152 Q_Q(QAbstractItemView);
2153 if (event->isAccepted())
2154 return false;
2155
2156 QModelIndex index;
2157 // rootIndex() (i.e. the viewport) might be a valid index
2158 if (viewport->rect().contains(event->pos())) {
2159 index = q->indexAt(event->pos());
2160 if (!index.isValid() || !q->visualRect(index).contains(event->pos()))
2161 index = root;
2162 }
2163
2164 // If we are allowed to do the drop
2165 if (model->supportedDropActions() & event->dropAction()) {
2166 int row = -1;
2167 int col = -1;
2168 if (index != root) {
2169 dropIndicatorPosition = position(event->pos(), q->visualRect(index), index);
2170 switch (dropIndicatorPosition) {
2171 case QAbstractItemView::AboveItem:
2172 row = index.row();
2173 col = index.column();
2174 index = index.parent();
2175 break;
2176 case QAbstractItemView::BelowItem:
2177 row = index.row() + 1;
2178 col = index.column();
2179 index = index.parent();
2180 break;
2181 case QAbstractItemView::OnItem:
2182 case QAbstractItemView::OnViewport:
2183 break;
2184 }
2185 } else {
2186 dropIndicatorPosition = QAbstractItemView::OnViewport;
2187 }
2188 *dropIndex = index;
2189 *dropRow = row;
2190 *dropCol = col;
2191 if (!droppingOnItself(event, index))
2192 return true;
2193 }
2194 return false;
2195}
2196
2197QAbstractItemView::DropIndicatorPosition
2198QAbstractItemViewPrivate::position(const QPoint &pos, const QRect &rect, const QModelIndex &index) const
2199{
2200 QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2201 if (!overwrite) {
2202 const int margin = qBound(2, qRound(qreal(rect.height()) / 5.5), 12);
2203 if (pos.y() - rect.top() < margin) {
2204 r = QAbstractItemView::AboveItem;
2205 } else if (rect.bottom() - pos.y() < margin) {
2206 r = QAbstractItemView::BelowItem;
2207 } else if (rect.contains(pos, true)) {
2208 r = QAbstractItemView::OnItem;
2209 }
2210 } else {
2211 QRect touchingRect = rect;
2212 touchingRect.adjust(-1, -1, 1, 1);
2213 if (touchingRect.contains(pos, false)) {
2214 r = QAbstractItemView::OnItem;
2215 }
2216 }
2217
2218 if (r == QAbstractItemView::OnItem && (!(model->flags(index) & Qt::ItemIsDropEnabled)))
2219 r = pos.y() < rect.center().y() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2220
2221 return r;
2222}
2223
2224#endif // QT_CONFIG(draganddrop)
2225
2226/*!
2227 This function is called with the given \a event when the widget obtains the focus.
2228 By default, the event is ignored.
2229
2230 \sa setFocus(), focusOutEvent()
2231*/
2232void QAbstractItemView::focusInEvent(QFocusEvent *event)
2233{
2234 Q_D(QAbstractItemView);
2235 QAbstractScrollArea::focusInEvent(event);
2236
2237 const QItemSelectionModel* model = selectionModel();
2238 bool currentIndexValid = currentIndex().isValid();
2239
2240 if (model
2241 && !d->currentIndexSet
2242 && !currentIndexValid) {
2243 bool autoScroll = d->autoScroll;
2244 d->autoScroll = false;
2245 QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index
2246 if (index.isValid() && d->isIndexEnabled(index) && event->reason() != Qt::MouseFocusReason) {
2247 selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
2248 currentIndexValid = true;
2249 }
2250 d->autoScroll = autoScroll;
2251 }
2252
2253 if (model && currentIndexValid)
2254 setAttribute(Qt::WA_InputMethodEnabled, (currentIndex().flags() & Qt::ItemIsEditable));
2255 else if (!currentIndexValid)
2256 setAttribute(Qt::WA_InputMethodEnabled, false);
2257
2258 d->viewport->update();
2259}
2260
2261/*!
2262 This function is called with the given \a event when the widget
2263 loses the focus. By default, the event is ignored.
2264
2265 \sa clearFocus(), focusInEvent()
2266*/
2267void QAbstractItemView::focusOutEvent(QFocusEvent *event)
2268{
2269 Q_D(QAbstractItemView);
2270 QAbstractScrollArea::focusOutEvent(event);
2271 d->viewport->update();
2272}
2273
2274/*!
2275 This function is called with the given \a event when a key event is sent to
2276 the widget. The default implementation handles basic cursor movement, e.g. Up,
2277 Down, Left, Right, Home, PageUp, and PageDown; the activated() signal is
2278 emitted if the current index is valid and the activation key is pressed
2279 (e.g. Enter or Return, depending on the platform).
2280 This function is where editing is initiated by key press, e.g. if F2 is
2281 pressed.
2282
2283 \sa edit(), moveCursor(), keyboardSearch(), tabKeyNavigation
2284*/
2285void QAbstractItemView::keyPressEvent(QKeyEvent *event)
2286{
2287 Q_D(QAbstractItemView);
2288 d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
2289
2290#ifdef QT_KEYPAD_NAVIGATION
2291 switch (event->key()) {
2292 case Qt::Key_Select:
2293 if (QApplication::keypadNavigationEnabled()) {
2294 if (!hasEditFocus()) {
2295 setEditFocus(true);
2296 return;
2297 }
2298 }
2299 break;
2300 case Qt::Key_Back:
2301 if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
2302 setEditFocus(false);
2303 } else {
2304 event->ignore();
2305 }
2306 return;
2307 case Qt::Key_Down:
2308 case Qt::Key_Up:
2309 // Let's ignore vertical navigation events, only if there is no other widget
2310 // what can take the focus in vertical direction. This means widget can handle navigation events
2311 // even the widget don't have edit focus, and there is no other widget in requested direction.
2312 if(QApplication::keypadNavigationEnabled() && !hasEditFocus()
2313 && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2314 event->ignore();
2315 return;
2316 }
2317 break;
2318 case Qt::Key_Left:
2319 case Qt::Key_Right:
2320 // Similar logic as in up and down events
2321 if(QApplication::keypadNavigationEnabled() && !hasEditFocus()
2322 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this))) {
2323 event->ignore();
2324 return;
2325 }
2326 break;
2327 default:
2328 if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
2329 event->ignore();
2330 return;
2331 }
2332 }
2333#endif
2334
2335#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
2336 if (event == QKeySequence::Copy) {
2337 QVariant variant;
2338 if (d->model)
2339 variant = d->model->data(currentIndex(), Qt::DisplayRole);
2340 if (variant.type() == QVariant::String)
2341 QApplication::clipboard()->setText(variant.toString());
2342 event->accept();
2343 }
2344#endif
2345
2346 QPersistentModelIndex newCurrent;
2347 d->moveCursorUpdatedView = false;
2348 switch (event->key()) {
2349 case Qt::Key_Down:
2350 newCurrent = moveCursor(MoveDown, event->modifiers());
2351 break;
2352 case Qt::Key_Up:
2353 newCurrent = moveCursor(MoveUp, event->modifiers());
2354 break;
2355 case Qt::Key_Left:
2356 newCurrent = moveCursor(MoveLeft, event->modifiers());
2357 break;
2358 case Qt::Key_Right:
2359 newCurrent = moveCursor(MoveRight, event->modifiers());
2360 break;
2361 case Qt::Key_Home:
2362 newCurrent = moveCursor(MoveHome, event->modifiers());
2363 break;
2364 case Qt::Key_End:
2365 newCurrent = moveCursor(MoveEnd, event->modifiers());
2366 break;
2367 case Qt::Key_PageUp:
2368 newCurrent = moveCursor(MovePageUp, event->modifiers());
2369 break;
2370 case Qt::Key_PageDown:
2371 newCurrent = moveCursor(MovePageDown, event->modifiers());
2372 break;
2373 case Qt::Key_Tab:
2374 if (d->tabKeyNavigation)
2375 newCurrent = moveCursor(MoveNext, event->modifiers());
2376 break;
2377 case Qt::Key_Backtab:
2378 if (d->tabKeyNavigation)
2379 newCurrent = moveCursor(MovePrevious, event->modifiers());
2380 break;
2381 }
2382
2383 QPersistentModelIndex oldCurrent = currentIndex();
2384 if (newCurrent != oldCurrent && newCurrent.isValid() && d->isIndexEnabled(newCurrent)) {
2385 if (!hasFocus() && QApplication::focusWidget() == indexWidget(oldCurrent))
2386 setFocus();
2387 QItemSelectionModel::SelectionFlags command = selectionCommand(newCurrent, event);
2388 if (command != QItemSelectionModel::NoUpdate
2389 || style()->styleHint(QStyle::SH_ItemView_MovementWithoutUpdatingSelection, 0, this)) {
2390 // note that we don't check if the new current index is enabled because moveCursor() makes sure it is
2391 if (command & QItemSelectionModel::Current) {
2392 d->selectionModel->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
2393 if (!d->currentSelectionStartIndex.isValid())
2394 d->currentSelectionStartIndex = oldCurrent;
2395 QRect rect(visualRect(d->currentSelectionStartIndex).center(), visualRect(newCurrent).center());
2396 setSelection(rect, command);
2397 } else {
2398 d->selectionModel->setCurrentIndex(newCurrent, command);
2399 d->currentSelectionStartIndex = newCurrent;
2400 if (newCurrent.isValid()) {
2401 // We copy the same behaviour as for mousePressEvent().
2402 QRect rect(visualRect(newCurrent).center(), QSize(1, 1));
2403 setSelection(rect, command);
2404 }
2405 }
2406 event->accept();
2407 return;
2408 }
2409 }
2410
2411 switch (event->key()) {
2412 // ignored keys
2413 case Qt::Key_Down:
2414 case Qt::Key_Up:
2415#ifdef QT_KEYPAD_NAVIGATION
2416 if (QApplication::keypadNavigationEnabled() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2417 event->accept(); // don't change focus
2418 break;
2419 }
2420#endif
2421 case Qt::Key_Left:
2422 case Qt::Key_Right:
2423#ifdef QT_KEYPAD_NAVIGATION
2424 if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
2425 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal)
2426 || (QWidgetPrivate::inTabWidget(this) && d->model->columnCount(d->root) > 1))) {
2427 event->accept(); // don't change focus
2428 break;
2429 }
2430#endif // QT_KEYPAD_NAVIGATION
2431 case Qt::Key_Home:
2432 case Qt::Key_End:
2433 case Qt::Key_PageUp:
2434 case Qt::Key_PageDown:
2435 case Qt::Key_Escape:
2436 case Qt::Key_Shift:
2437 case Qt::Key_Control:
2438 case Qt::Key_Delete:
2439 case Qt::Key_Backspace:
2440 event->ignore();
2441 break;
2442 case Qt::Key_Space:
2443 case Qt::Key_Select:
2444 if (!edit(currentIndex(), AnyKeyPressed, event)) {
2445 if (d->selectionModel)
2446 d->selectionModel->select(currentIndex(), selectionCommand(currentIndex(), event));
2447 if (event->key() == Qt::Key_Space) {
2448 keyboardSearch(event->text());
2449 event->accept();
2450 }
2451 }
2452#ifdef QT_KEYPAD_NAVIGATION
2453 if ( event->key()==Qt::Key_Select ) {
2454 // Also do Key_Enter action.
2455 if (currentIndex().isValid()) {
2456 if (state() != EditingState)
2457 emit activated(currentIndex());
2458 } else {
2459 event->ignore();
2460 }
2461 }
2462#endif
2463 break;
2464#ifdef Q_OS_OSX
2465 case Qt::Key_Enter:
2466 case Qt::Key_Return:
2467 // Propagate the enter if you couldn't edit the item and there are no
2468 // current editors (if there are editors, the event was most likely propagated from it).
2469 if (!edit(currentIndex(), EditKeyPressed, event) && d->editorIndexHash.isEmpty())
2470 event->ignore();
2471 break;
2472#else
2473 case Qt::Key_F2:
2474 if (!edit(currentIndex(), EditKeyPressed, event))
2475 event->ignore();
2476 break;
2477 case Qt::Key_Enter:
2478 case Qt::Key_Return:
2479 // ### we can't open the editor on enter, becuse
2480 // some widgets will forward the enter event back
2481 // to the viewport, starting an endless loop
2482 if (state() != EditingState || hasFocus()) {
2483 if (currentIndex().isValid())
2484 emit activated(currentIndex());
2485 event->ignore();
2486 }
2487 break;
2488#endif
2489 default: {
2490#ifndef QT_NO_SHORTCUT
2491 if (event == QKeySequence::SelectAll && selectionMode() != NoSelection) {
2492 selectAll();
2493 break;
2494 }
2495#endif
2496#ifdef Q_OS_OSX
2497 if (event->key() == Qt::Key_O && event->modifiers() & Qt::ControlModifier && currentIndex().isValid()) {
2498 emit activated(currentIndex());
2499 break;
2500 }
2501#endif
2502 bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier));
2503 if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) {
2504 keyboardSearch(event->text());
2505 event->accept();
2506 } else {
2507 event->ignore();
2508 }
2509 break; }
2510 }
2511 if (d->moveCursorUpdatedView)
2512 event->accept();
2513}
2514
2515/*!
2516 This function is called with the given \a event when a resize event is sent to
2517 the widget.
2518
2519 \sa QWidget::resizeEvent()
2520*/
2521void QAbstractItemView::resizeEvent(QResizeEvent *event)
2522{
2523 QAbstractScrollArea::resizeEvent(event);
2524 updateGeometries();
2525}
2526
2527/*!
2528 This function is called with the given \a event when a timer event is sent
2529 to the widget.
2530
2531 \sa QObject::timerEvent()
2532*/
2533void QAbstractItemView::timerEvent(QTimerEvent *event)
2534{
2535 Q_D(QAbstractItemView);
2536 if (event->timerId() == d->fetchMoreTimer.timerId())
2537 d->fetchMore();
2538 else if (event->timerId() == d->delayedReset.timerId())
2539 reset();
2540 else if (event->timerId() == d->autoScrollTimer.timerId())
2541 doAutoScroll();
2542 else if (event->timerId() == d->updateTimer.timerId())
2543 d->updateDirtyRegion();
2544 else if (event->timerId() == d->delayedEditing.timerId()) {
2545 d->delayedEditing.stop();
2546 edit(currentIndex());
2547 } else if (event->timerId() == d->delayedLayout.timerId()) {
2548 d->delayedLayout.stop();
2549 if (isVisible()) {
2550 d->interruptDelayedItemsLayout();
2551 doItemsLayout();
2552 const QModelIndex current = currentIndex();
2553 if (current.isValid() && d->state == QAbstractItemView::EditingState)
2554 scrollTo(current);
2555 }
2556 } else if (event->timerId() == d->delayedAutoScroll.timerId()) {
2557 d->delayedAutoScroll.stop();
2558 //end of the timer: if the current item is still the same as the one when the mouse press occurred
2559 //we only get here if there was no double click
2560 if (d->pressedIndex.isValid() && d->pressedIndex == currentIndex())
2561 scrollTo(d->pressedIndex);
2562 }
2563}
2564
2565/*!
2566 \reimp
2567*/
2568void QAbstractItemView::inputMethodEvent(QInputMethodEvent *event)
2569{
2570 if (event->commitString().isEmpty() && event->preeditString().isEmpty()) {
2571 event->ignore();
2572 return;
2573 }
2574 if (!edit(currentIndex(), AnyKeyPressed, event)) {
2575 if (!event->commitString().isEmpty())
2576 keyboardSearch(event->commitString());
2577 event->ignore();
2578 }
2579}
2580
2581#if QT_CONFIG(draganddrop)
2582/*!
2583 \enum QAbstractItemView::DropIndicatorPosition
2584
2585 This enum indicates the position of the drop indicator in
2586 relation to the index at the current mouse position:
2587
2588 \value OnItem The item will be dropped on the index.
2589
2590 \value AboveItem The item will be dropped above the index.
2591
2592 \value BelowItem The item will be dropped below the index.
2593
2594 \value OnViewport The item will be dropped onto a region of the viewport with
2595 no items. The way each view handles items dropped onto the viewport depends on
2596 the behavior of the underlying model in use.
2597*/
2598
2599
2600/*!
2601 \since 4.1
2602
2603 Returns the position of the drop indicator in relation to the closest item.
2604*/
2605QAbstractItemView::DropIndicatorPosition QAbstractItemView::dropIndicatorPosition() const
2606{
2607 Q_D(const QAbstractItemView);
2608 return d->dropIndicatorPosition;
2609}
2610#endif
2611
2612/*!
2613 This convenience function returns a list of all selected and
2614 non-hidden item indexes in the view. The list contains no
2615 duplicates, and is not sorted.
2616
2617 \sa QItemSelectionModel::selectedIndexes()
2618*/
2619QModelIndexList QAbstractItemView::selectedIndexes() const
2620{
2621 Q_D(const QAbstractItemView);
2622 QModelIndexList indexes;
2623 if (d->selectionModel) {
2624 indexes = d->selectionModel->selectedIndexes();
2625 auto isHidden = [this](const QModelIndex &idx) {
2626 return isIndexHidden(idx);
2627 };
2628 const auto end = indexes.end();
2629 indexes.erase(std::remove_if(indexes.begin(), end, isHidden), end);
2630 }
2631 return indexes;
2632}
2633
2634/*!
2635 Starts editing the item at \a index, creating an editor if
2636 necessary, and returns \c true if the view's \l{State} is now
2637 EditingState; otherwise returns \c false.
2638
2639 The action that caused the editing process is described by
2640 \a trigger, and the associated event is specified by \a event.
2641
2642 Editing can be forced by specifying the \a trigger to be
2643 QAbstractItemView::AllEditTriggers.
2644
2645 \sa closeEditor()
2646*/
2647bool QAbstractItemView::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
2648{
2649 Q_D(QAbstractItemView);
2650
2651 if (!d->isIndexValid(index))
2652 return false;
2653
2654 if (QWidget *w = (d->persistent.isEmpty() ? static_cast<QWidget*>(0) : d->editorForIndex(index).widget.data())) {
2655 if (w->focusPolicy() == Qt::NoFocus)
2656 return false;
2657 w->setFocus();
2658 return true;
2659 }
2660
2661 if (trigger == DoubleClicked) {
2662 d->delayedEditing.stop();
2663 d->delayedAutoScroll.stop();
2664 } else if (trigger == CurrentChanged) {
2665 d->delayedEditing.stop();
2666 }
2667
2668 if (d->sendDelegateEvent(index, event)) {
2669 update(index);
2670 return true;
2671 }
2672
2673 // save the previous trigger before updating
2674 EditTriggers lastTrigger = d->lastTrigger;
2675 d->lastTrigger = trigger;
2676
2677 if (!d->shouldEdit(trigger, d->model->buddy(index)))
2678 return false;
2679
2680 if (d->delayedEditing.isActive())
2681 return false;
2682
2683 // we will receive a mouseButtonReleaseEvent after a
2684 // mouseDoubleClickEvent, so we need to check the previous trigger
2685 if (lastTrigger == DoubleClicked && trigger == SelectedClicked)
2686 return false;
2687
2688 // we may get a double click event later
2689 if (trigger == SelectedClicked)
2690 d->delayedEditing.start(QApplication::doubleClickInterval(), this);
2691 else
2692 d->openEditor(index, d->shouldForwardEvent(trigger, event) ? event : 0);
2693
2694 return true;
2695}
2696
2697/*!
2698 \internal
2699 Updates the data shown in the open editor widgets in the view.
2700*/
2701void QAbstractItemView::updateEditorData()
2702{
2703 Q_D(QAbstractItemView);
2704 d->updateEditorData(QModelIndex(), QModelIndex());
2705}
2706
2707/*!
2708 \internal
2709 Updates the geometry of the open editor widgets in the view.
2710*/
2711void QAbstractItemView::updateEditorGeometries()
2712{
2713 Q_D(QAbstractItemView);
2714 if(d->editorIndexHash.isEmpty())
2715 return;
2716 if (d->delayedPendingLayout) {
2717 // doItemsLayout() will end up calling this function again
2718 d->executePostedLayout();
2719 return;
2720 }
2721 QStyleOptionViewItem option = d->viewOptionsV1();
2722 QEditorIndexHash::iterator it = d->editorIndexHash.begin();
2723 QWidgetList editorsToRelease;
2724 QWidgetList editorsToHide;
2725 while (it != d->editorIndexHash.end()) {
2726 QModelIndex index = it.value();
2727 QWidget *editor = it.key();
2728 if (index.isValid() && editor) {
2729 option.rect = visualRect(index);
2730 if (option.rect.isValid()) {
2731 editor->show();
2732 QAbstractItemDelegate *delegate = d->delegateForIndex(index);
2733 if (delegate)
2734 delegate->updateEditorGeometry(editor, option, index);
2735 } else {
2736 editorsToHide << editor;
2737 }
2738 ++it;
2739 } else {
2740 d->indexEditorHash.remove(it.value());
2741 it = d->editorIndexHash.erase(it);
2742 editorsToRelease << editor;
2743 }
2744 }
2745
2746 //we hide and release the editor outside of the loop because it might change the focus and try
2747 //to change the editors hashes.
2748 for (int i = 0; i < editorsToHide.count(); ++i) {
2749 editorsToHide.at(i)->hide();
2750 }
2751 for (int i = 0; i < editorsToRelease.count(); ++i) {
2752 d->releaseEditor(editorsToRelease.at(i));
2753 }
2754}
2755
2756/*!
2757 \since 4.4
2758
2759 Updates the geometry of the child widgets of the view.
2760*/
2761void QAbstractItemView::updateGeometries()
2762{
2763 Q_D(QAbstractItemView);
2764 updateEditorGeometries();
2765 d->fetchMoreTimer.start(0, this); //fetch more later
2766 d->updateGeometry();
2767}
2768
2769/*!
2770 \internal
2771*/
2772void QAbstractItemView::verticalScrollbarValueChanged(int value)
2773{
2774 Q_D(QAbstractItemView);
2775 if (verticalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2776 d->model->fetchMore(d->root);
2777 QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2778 if (viewport()->rect().contains(posInVp))
2779 d->checkMouseMove(posInVp);
2780}
2781
2782/*!
2783 \internal
2784*/
2785void QAbstractItemView::horizontalScrollbarValueChanged(int value)
2786{
2787 Q_D(QAbstractItemView);
2788 if (horizontalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2789 d->model->fetchMore(d->root);
2790 QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2791 if (viewport()->rect().contains(posInVp))
2792 d->checkMouseMove(posInVp);
2793}
2794
2795/*!
2796 \internal
2797*/
2798void QAbstractItemView::verticalScrollbarAction(int)
2799{
2800 //do nothing
2801}
2802
2803/*!
2804 \internal
2805*/
2806void QAbstractItemView::horizontalScrollbarAction(int)
2807{
2808 //do nothing
2809}
2810
2811/*!
2812 Closes the given \a editor, and releases it. The \a hint is
2813 used to specify how the view should respond to the end of the editing
2814 operation. For example, the hint may indicate that the next item in
2815 the view should be opened for editing.
2816
2817 \sa edit(), commitData()
2818*/
2819
2820void QAbstractItemView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
2821{
2822 Q_D(QAbstractItemView);
2823
2824 // Close the editor
2825 if (editor) {
2826 bool isPersistent = d->persistent.contains(editor);
2827 bool hadFocus = editor->hasFocus();
2828 QModelIndex index = d->indexForEditor(editor);
2829 if (!index.isValid())
2830 return; // the editor was not registered
2831
2832 if (!isPersistent) {
2833 setState(NoState);
2834 QModelIndex index = d->indexForEditor(editor);
2835 editor->removeEventFilter(d->delegateForIndex(index));
2836 d->removeEditor(editor);
2837 }
2838 if (hadFocus) {
2839 if (focusPolicy() != Qt::NoFocus)
2840 setFocus(); // this will send a focusLost event to the editor
2841 else
2842 editor->clearFocus();
2843 } else {
2844 d->checkPersistentEditorFocus();
2845 }
2846
2847 QPointer<QWidget> ed = editor;
2848 QApplication::sendPostedEvents(editor, 0);
2849 editor = ed;
2850
2851 if (!isPersistent && editor)
2852 d->releaseEditor(editor, index);
2853 }
2854
2855 // The EndEditHint part
2856 QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::NoUpdate;
2857 if (d->selectionMode != NoSelection)
2858 flags = QItemSelectionModel::ClearAndSelect | d->selectionBehaviorFlags();
2859 switch (hint) {
2860 case QAbstractItemDelegate::EditNextItem: {
2861 QModelIndex index = moveCursor(MoveNext, Qt::NoModifier);
2862 if (index.isValid()) {
2863 QPersistentModelIndex persistent(index);
2864 d->selectionModel->setCurrentIndex(persistent, flags);
2865 // currentChanged signal would have already started editing
2866 if (index.flags() & Qt::ItemIsEditable
2867 && (!(editTriggers() & QAbstractItemView::CurrentChanged)))
2868 edit(persistent);
2869 } break; }
2870 case QAbstractItemDelegate::EditPreviousItem: {
2871 QModelIndex index = moveCursor(MovePrevious, Qt::NoModifier);
2872 if (index.isValid()) {
2873 QPersistentModelIndex persistent(index);
2874 d->selectionModel->setCurrentIndex(persistent, flags);
2875 // currentChanged signal would have already started editing
2876 if (index.flags() & Qt::ItemIsEditable
2877 && (!(editTriggers() & QAbstractItemView::CurrentChanged)))
2878 edit(persistent);
2879 } break; }
2880 case QAbstractItemDelegate::SubmitModelCache:
2881 d->model->submit();
2882 break;
2883 case QAbstractItemDelegate::RevertModelCache:
2884 d->model->revert();
2885 break;
2886 default:
2887 break;
2888 }
2889}
2890
2891/*!
2892 Commit the data in the \a editor to the model.
2893
2894 \sa closeEditor()
2895*/
2896void QAbstractItemView::commitData(QWidget *editor)
2897{
2898 Q_D(QAbstractItemView);
2899 if (!editor || !d->itemDelegate || d->currentlyCommittingEditor)
2900 return;
2901 QModelIndex index = d->indexForEditor(editor);
2902 if (!index.isValid())
2903 return;
2904 d->currentlyCommittingEditor = editor;
2905 QAbstractItemDelegate *delegate = d->delegateForIndex(index);
2906 editor->removeEventFilter(delegate);
2907 delegate->setModelData(editor, d->model, index);
2908 editor->installEventFilter(delegate);
2909 d->currentlyCommittingEditor = 0;
2910}
2911
2912/*!
2913 This function is called when the given \a editor has been destroyed.
2914
2915 \sa closeEditor()
2916*/
2917void QAbstractItemView::editorDestroyed(QObject *editor)
2918{
2919 Q_D(QAbstractItemView);
2920 QWidget *w = qobject_cast<QWidget*>(editor);
2921 d->removeEditor(w);
2922 d->persistent.remove(w);
2923 if (state() == EditingState)
2924 setState(NoState);
2925}
2926
2927#if QT_DEPRECATED_SINCE(5, 13)
2928/*!
2929 \obsolete
2930 Sets the horizontal scroll bar's steps per item to \a steps.
2931
2932 This is the number of steps used by the horizontal scroll bar to
2933 represent the width of an item.
2934
2935 Note that if the view has a horizontal header, the item steps
2936 will be ignored and the header section size will be used instead.
2937
2938 \sa horizontalStepsPerItem(), setVerticalStepsPerItem()
2939*/
2940void QAbstractItemView::setHorizontalStepsPerItem(int steps)
2941{
2942 Q_UNUSED(steps)
2943 // do nothing
2944}
2945
2946/*!
2947 \obsolete
2948 Returns the horizontal scroll bar's steps per item.
2949
2950 \sa setHorizontalStepsPerItem(), verticalStepsPerItem()
2951*/
2952int QAbstractItemView::horizontalStepsPerItem() const
2953{
2954 return 1;
2955}
2956
2957/*!
2958 \obsolete
2959 Sets the vertical scroll bar's steps per item to \a steps.
2960
2961 This is the number of steps used by the vertical scroll bar to
2962 represent the height of an item.
2963
2964 Note that if the view has a vertical header, the item steps
2965 will be ignored and the header section size will be used instead.
2966
2967 \sa verticalStepsPerItem(), setHorizontalStepsPerItem()
2968*/
2969void QAbstractItemView::setVerticalStepsPerItem(int steps)
2970{
2971 Q_UNUSED(steps)
2972 // do nothing
2973}
2974
2975/*!
2976 \obsolete
2977 Returns the vertical scroll bar's steps per item.
2978
2979 \sa setVerticalStepsPerItem(), horizontalStepsPerItem()
2980*/
2981int QAbstractItemView::verticalStepsPerItem() const
2982{
2983 return 1;
2984}
2985#endif
2986
2987/*!
2988 Moves to and selects the item best matching the string \a search.
2989 If no item is found nothing happens.
2990
2991 In the default implementation, the search is reset if \a search is empty, or
2992 the time interval since the last search has exceeded
2993 QApplication::keyboardInputInterval().
2994*/
2995void QAbstractItemView::keyboardSearch(const QString &search)
2996{
2997 Q_D(QAbstractItemView);
2998 if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
2999 return;
3000
3001 QModelIndex start = currentIndex().isValid() ? currentIndex()
3002 : d->model->index(0, 0, d->root);
3003 bool skipRow = false;
3004 bool keyboardTimeWasValid = d->keyboardInputTime.isValid();
3005 qint64 keyboardInputTimeElapsed;
3006 if (keyboardTimeWasValid)
3007 keyboardInputTimeElapsed = d->keyboardInputTime.restart();
3008 else
3009 d->keyboardInputTime.start();
3010 if (search.isEmpty() || !keyboardTimeWasValid
3011 || keyboardInputTimeElapsed > QApplication::keyboardInputInterval()) {
3012 d->keyboardInput = search;
3013 skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0)
3014 } else {
3015 d->keyboardInput += search;
3016 }
3017
3018 // special case for searches with same key like 'aaaaa'
3019 bool sameKey = false;
3020 if (d->keyboardInput.length() > 1) {
3021 int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1));
3022 sameKey = (c == d->keyboardInput.length());
3023 if (sameKey)
3024 skipRow = true;
3025 }
3026
3027 // skip if we are searching for the same key or a new search started
3028 if (skipRow) {
3029 QModelIndex parent = start.parent();
3030 int newRow = (start.row() < d->model->rowCount(parent) - 1) ? start.row() + 1 : 0;
3031 start = d->model->index(newRow, start.column(), parent);
3032 }
3033
3034 // search from start with wraparound
3035 QModelIndex current = start;
3036 QModelIndexList match;
3037 QModelIndex firstMatch;
3038 QModelIndex startMatch;
3039 QModelIndexList previous;
3040 do {
3041 match =