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