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