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

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

trunk: Merged in qt 4.6.2 sources.

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