source: trunk/src/gui/itemviews/qabstractitemview.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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