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

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

trunk: Merged in qt 4.6.1 sources.

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