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

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

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

File size: 137.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#ifdef QT_SOFTKEYS_ENABLED
1544 case QEvent::LanguageChange:
1545 d->doneSoftKey->setText(QSoftKeyManager::standardSoftKeyText(QSoftKeyManager::DoneSoftKey));
1546 break;
1547#endif
1548 default:
1549 break;
1550 }
1551 return QAbstractScrollArea::event(event);
1552}
1553
1554/*!
1555 \fn bool QAbstractItemView::viewportEvent(QEvent *event)
1556
1557 This function is used to handle tool tips, and What's
1558 This? mode, if the given \a event is a QEvent::ToolTip,or a
1559 QEvent::WhatsThis. It passes all other
1560 events on to its base class viewportEvent() handler.
1561*/
1562bool QAbstractItemView::viewportEvent(QEvent *event)
1563{
1564 Q_D(QAbstractItemView);
1565 switch (event->type()) {
1566 case QEvent::HoverMove:
1567 case QEvent::HoverEnter:
1568 d->setHoverIndex(indexAt(static_cast<QHoverEvent*>(event)->pos()));
1569 break;
1570 case QEvent::HoverLeave:
1571 d->setHoverIndex(QModelIndex());
1572 break;
1573 case QEvent::Enter:
1574 d->viewportEnteredNeeded = true;
1575 break;
1576 case QEvent::Leave:
1577 #ifndef QT_NO_STATUSTIP
1578 if (d->shouldClearStatusTip && d->parent) {
1579 QString empty;
1580 QStatusTipEvent tip(empty);
1581 QApplication::sendEvent(d->parent, &tip);
1582 d->shouldClearStatusTip = false;
1583 }
1584 #endif
1585 d->enteredIndex = QModelIndex();
1586 break;
1587 case QEvent::ToolTip:
1588 case QEvent::QueryWhatsThis:
1589 case QEvent::WhatsThis: {
1590 QHelpEvent *he = static_cast<QHelpEvent*>(event);
1591 const QModelIndex index = indexAt(he->pos());
1592 QStyleOptionViewItemV4 option = d->viewOptionsV4();
1593 option.rect = visualRect(index);
1594 option.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
1595 bool retval = false;
1596 // ### Qt 5: make this a normal function call to a virtual function
1597 QMetaObject::invokeMethod(d->delegateForIndex(index), "helpEvent",
1598 Q_RETURN_ARG(bool, retval),
1599 Q_ARG(QHelpEvent *, he),
1600 Q_ARG(QAbstractItemView *, this),
1601 Q_ARG(QStyleOptionViewItem, option),
1602 Q_ARG(QModelIndex, index));
1603 return retval;
1604 }
1605 case QEvent::FontChange:
1606 d->doDelayedItemsLayout(); // the size of the items will change
1607 break;
1608 case QEvent::WindowActivate:
1609 case QEvent::WindowDeactivate:
1610 d->viewport->update();
1611 break;
1612 default:
1613 break;
1614 }
1615 return QAbstractScrollArea::viewportEvent(event);
1616}
1617
1618/*!
1619 This function is called with the given \a event when a mouse button is pressed
1620 while the cursor is inside the widget. If a valid item is pressed on it is made
1621 into the current item. This function emits the pressed() signal.
1622*/
1623void QAbstractItemView::mousePressEvent(QMouseEvent *event)
1624{
1625 Q_D(QAbstractItemView);
1626 d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
1627 QPoint pos = event->pos();
1628 QPersistentModelIndex index = indexAt(pos);
1629
1630 if (!d->selectionModel
1631 || (d->state == EditingState && d->hasEditor(index)))
1632 return;
1633
1634 d->pressedAlreadySelected = d->selectionModel->isSelected(index);
1635 d->pressedIndex = index;
1636 d->pressedModifiers = event->modifiers();
1637 QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1638 d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid();
1639 QPoint offset = d->offset();
1640 if ((command & QItemSelectionModel::Current) == 0)
1641 d->pressedPosition = pos + offset;
1642 else if (!indexAt(d->pressedPosition - offset).isValid())
1643 d->pressedPosition = visualRect(currentIndex()).center() + offset;
1644
1645 if (edit(index, NoEditTriggers, event))
1646 return;
1647
1648 if (index.isValid() && d->isIndexEnabled(index)) {
1649 // we disable scrollTo for mouse press so the item doesn't change position
1650 // when the user is interacting with it (ie. clicking on it)
1651 bool autoScroll = d->autoScroll;
1652 d->autoScroll = false;
1653 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1654 d->autoScroll = autoScroll;
1655 QRect rect(d->pressedPosition - offset, pos);
1656 if (command.testFlag(QItemSelectionModel::Toggle)) {
1657 command &= ~QItemSelectionModel::Toggle;
1658 d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
1659 command |= d->ctrlDragSelectionFlag;
1660 }
1661 setSelection(rect, command);
1662
1663 // signal handlers may change the model
1664 emit pressed(index);
1665 if (d->autoScroll) {
1666 //we delay the autoscrolling to filter out double click event
1667 //100 is to be sure that there won't be a double-click misinterpreted as a 2 single clicks
1668 d->delayedAutoScroll.start(QApplication::doubleClickInterval()+100, this);
1669 }
1670
1671 } else {
1672 // Forces a finalize() even if mouse is pressed, but not on a item
1673 d->selectionModel->select(QModelIndex(), QItemSelectionModel::Select);
1674 }
1675}
1676
1677/*!
1678 This function is called with the given \a event when a mouse move event is
1679 sent to the widget. If a selection is in progress and new items are moved
1680 over the selection is extended; if a drag is in progress it is continued.
1681*/
1682void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
1683{
1684 Q_D(QAbstractItemView);
1685 QPoint topLeft;
1686 QPoint bottomRight = event->pos();
1687
1688 if (state() == ExpandingState || state() == CollapsingState)
1689 return;
1690
1691#ifndef QT_NO_DRAGANDDROP
1692 if (state() == DraggingState) {
1693 topLeft = d->pressedPosition - d->offset();
1694 if ((topLeft - bottomRight).manhattanLength() > QApplication::startDragDistance()) {
1695 d->pressedIndex = QModelIndex();
1696 startDrag(d->model->supportedDragActions());
1697 setState(NoState); // the startDrag will return when the dnd operation is done
1698 stopAutoScroll();
1699 }
1700 return;
1701 }
1702#endif // QT_NO_DRAGANDDROP
1703
1704 QPersistentModelIndex index = indexAt(bottomRight);
1705 QModelIndex buddy = d->model->buddy(d->pressedIndex);
1706 if ((state() == EditingState && d->hasEditor(buddy))
1707 || edit(index, NoEditTriggers, event))
1708 return;
1709
1710 if (d->selectionMode != SingleSelection)
1711 topLeft = d->pressedPosition - d->offset();
1712 else
1713 topLeft = bottomRight;
1714
1715 d->checkMouseMove(index);
1716
1717#ifndef QT_NO_DRAGANDDROP
1718 if (d->pressedIndex.isValid()
1719 && d->dragEnabled
1720 && (state() != DragSelectingState)
1721 && (event->buttons() != Qt::NoButton)
1722 && !d->selectedDraggableIndexes().isEmpty()) {
1723 setState(DraggingState);
1724 return;
1725 }
1726#endif
1727
1728 if ((event->buttons() & Qt::LeftButton) && d->selectionAllowed(index) && d->selectionModel) {
1729 setState(DragSelectingState);
1730 QItemSelectionModel::SelectionFlags command = selectionCommand(index, event);
1731 if (d->ctrlDragSelectionFlag != QItemSelectionModel::NoUpdate && command.testFlag(QItemSelectionModel::Toggle)) {
1732 command &= ~QItemSelectionModel::Toggle;
1733 command |= d->ctrlDragSelectionFlag;
1734 }
1735
1736 // Do the normalize ourselves, since QRect::normalized() is flawed
1737 QRect selectionRect = QRect(topLeft, bottomRight);
1738 setSelection(selectionRect, command);
1739
1740 // set at the end because it might scroll the view
1741 if (index.isValid()
1742 && (index != d->selectionModel->currentIndex())
1743 && d->isIndexEnabled(index))
1744 d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1745 }
1746}
1747
1748/*!
1749 This function is called with the given \a event when a mouse button is released,
1750 after a mouse press event on the widget. If a user presses the mouse inside your
1751 widget and then drags the mouse to another location before releasing the mouse button,
1752 your widget receives the release event. The function will emit the clicked() signal if an
1753 item was being pressed.
1754*/
1755void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
1756{
1757 Q_D(QAbstractItemView);
1758
1759 QPoint pos = event->pos();
1760 QPersistentModelIndex index = indexAt(pos);
1761
1762 if (state() == EditingState) {
1763 if (d->isIndexValid(index)
1764 && d->isIndexEnabled(index)
1765 && d->sendDelegateEvent(index, event))
1766 update(index);
1767 return;
1768 }
1769
1770 bool click = (index == d->pressedIndex && index.isValid());
1771 bool selectedClicked = click && (event->button() & Qt::LeftButton) && d->pressedAlreadySelected;
1772 EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
1773 bool edited = edit(index, trigger, event);
1774
1775 d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
1776
1777 if (d->selectionModel && d->noSelectionOnMousePress) {
1778 d->noSelectionOnMousePress = false;
1779 d->selectionModel->select(index, selectionCommand(index, event));
1780 }
1781
1782 setState(NoState);
1783
1784 if (click) {
1785 emit clicked(index);
1786 if (edited)
1787 return;
1788 QStyleOptionViewItemV4 option = d->viewOptionsV4();
1789 if (d->pressedAlreadySelected)
1790 option.state |= QStyle::State_Selected;
1791 if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
1792 emit activated(index);
1793 }
1794}
1795
1796/*!
1797 This function is called with the given \a event when a mouse button is
1798 double clicked inside the widget. If the double-click is on a valid item it
1799 emits the doubleClicked() signal and calls edit() on the item.
1800*/
1801void QAbstractItemView::mouseDoubleClickEvent(QMouseEvent *event)
1802{
1803 Q_D(QAbstractItemView);
1804
1805 QModelIndex index = indexAt(event->pos());
1806 if (!index.isValid()
1807 || !d->isIndexEnabled(index)
1808 || (d->pressedIndex != index)) {
1809 QMouseEvent me(QEvent::MouseButtonPress,
1810 event->pos(), event->button(),
1811 event->buttons(), event->modifiers());
1812 mousePressEvent(&me);
1813 return;
1814 }
1815 // signal handlers may change the model
1816 QPersistentModelIndex persistent = index;
1817 emit doubleClicked(persistent);
1818 if ((event->button() & Qt::LeftButton) && !edit(persistent, DoubleClicked, event)
1819 && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this))
1820 emit activated(persistent);
1821}
1822
1823#ifndef QT_NO_DRAGANDDROP
1824
1825/*!
1826 This function is called with the given \a event when a drag and drop operation enters
1827 the widget. If the drag is over a valid dropping place (e.g. over an item that
1828 accepts drops), the event is accepted; otherwise it is ignored.
1829
1830 \sa dropEvent() startDrag()
1831*/
1832void QAbstractItemView::dragEnterEvent(QDragEnterEvent *event)
1833{
1834 if (dragDropMode() == InternalMove
1835 && (event->source() != this|| !(event->possibleActions() & Qt::MoveAction)))
1836 return;
1837
1838 if (d_func()->canDecode(event)) {
1839 event->accept();
1840 setState(DraggingState);
1841 } else {
1842 event->ignore();
1843 }
1844}
1845
1846/*!
1847 This function is called continuously with the given \a event during a drag and
1848 drop operation over the widget. It can cause the view to scroll if, for example,
1849 the user drags a selection to view's right or bottom edge. In this case, the
1850 event will be accepted; otherwise it will be ignored.
1851
1852 \sa dropEvent() startDrag()
1853*/
1854void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event)
1855{
1856 Q_D(QAbstractItemView);
1857 if (dragDropMode() == InternalMove
1858 && (event->source() != this || !(event->possibleActions() & Qt::MoveAction)))
1859 return;
1860
1861 // ignore by default
1862 event->ignore();
1863
1864 QModelIndex index = indexAt(event->pos());
1865 d->hover = index;
1866 if (!d->droppingOnItself(event, index)
1867 && d->canDecode(event)) {
1868
1869 if (index.isValid() && d->showDropIndicator) {
1870 QRect rect = visualRect(index);
1871 d->dropIndicatorPosition = d->position(event->pos(), rect, index);
1872 switch (d->dropIndicatorPosition) {
1873 case AboveItem:
1874 if (d->isIndexDropEnabled(index.parent())) {
1875 d->dropIndicatorRect = QRect(rect.left(), rect.top(), rect.width(), 0);
1876 event->accept();
1877 } else {
1878 d->dropIndicatorRect = QRect();
1879 }
1880 break;
1881 case BelowItem:
1882 if (d->isIndexDropEnabled(index.parent())) {
1883 d->dropIndicatorRect = QRect(rect.left(), rect.bottom(), rect.width(), 0);
1884 event->accept();
1885 } else {
1886 d->dropIndicatorRect = QRect();
1887 }
1888 break;
1889 case OnItem:
1890 if (d->isIndexDropEnabled(index)) {
1891 d->dropIndicatorRect = rect;
1892 event->accept();
1893 } else {
1894 d->dropIndicatorRect = QRect();
1895 }
1896 break;
1897 case OnViewport:
1898 d->dropIndicatorRect = QRect();
1899 if (d->isIndexDropEnabled(rootIndex())) {
1900 event->accept(); // allow dropping in empty areas
1901 }
1902 break;
1903 }
1904 } else {
1905 d->dropIndicatorRect = QRect();
1906 d->dropIndicatorPosition = OnViewport;
1907 if (d->isIndexDropEnabled(rootIndex())) {
1908 event->accept(); // allow dropping in empty areas
1909 }
1910 }
1911 d->viewport->update();
1912 } // can decode
1913
1914 if (d->shouldAutoScroll(event->pos()))
1915 startAutoScroll();
1916}
1917
1918/*!
1919 \internal
1920 Return true if this is a move from ourself and \a index is a child of the selection that
1921 is being moved.
1922 */
1923bool QAbstractItemViewPrivate::droppingOnItself(QDropEvent *event, const QModelIndex &index)
1924{
1925 Q_Q(QAbstractItemView);
1926 Qt::DropAction dropAction = event->dropAction();
1927 if (q->dragDropMode() == QAbstractItemView::InternalMove)
1928 dropAction = Qt::MoveAction;
1929 if (event->source() == q
1930 && event->possibleActions() & Qt::MoveAction
1931 && dropAction == Qt::MoveAction) {
1932 QModelIndexList selectedIndexes = q->selectedIndexes();
1933 QModelIndex child = index;
1934 while (child.isValid() && child != root) {
1935 if (selectedIndexes.contains(child))
1936 return true;
1937 child = child.parent();
1938 }
1939 }
1940 return false;
1941}
1942
1943/*!
1944 \fn void QAbstractItemView::dragLeaveEvent(QDragLeaveEvent *event)
1945
1946 This function is called when the item being dragged leaves the view.
1947 The \a event describes the state of the drag and drop operation.
1948*/
1949void QAbstractItemView::dragLeaveEvent(QDragLeaveEvent *)
1950{
1951 Q_D(QAbstractItemView);
1952 stopAutoScroll();
1953 setState(NoState);
1954 d->hover = QModelIndex();
1955 d->viewport->update();
1956}
1957
1958/*!
1959 This function is called with the given \a event when a drop event occurs over
1960 the widget. If the model accepts the even position the drop event is accepted;
1961 otherwise it is ignored.
1962
1963 \sa startDrag()
1964*/
1965void QAbstractItemView::dropEvent(QDropEvent *event)
1966{
1967 Q_D(QAbstractItemView);
1968 if (dragDropMode() == InternalMove) {
1969 if (event->source() != this || !(event->possibleActions() & Qt::MoveAction))
1970 return;
1971 }
1972
1973 QModelIndex index;
1974 int col = -1;
1975 int row = -1;
1976 if (d->dropOn(event, &row, &col, &index)) {
1977 if (d->model->dropMimeData(event->mimeData(),
1978 dragDropMode() == InternalMove ? Qt::MoveAction : event->dropAction(), row, col, index)) {
1979 if (dragDropMode() == InternalMove)
1980 event->setDropAction(Qt::MoveAction);
1981 event->accept();
1982 }
1983 }
1984 stopAutoScroll();
1985 setState(NoState);
1986 d->viewport->update();
1987}
1988
1989/*!
1990 If the event hasn't already been accepted, determines the index to drop on.
1991
1992 if (row == -1 && col == -1)
1993 // append to this drop index
1994 else
1995 // place at row, col in drop index
1996
1997 If it returns true a drop can be done, and dropRow, dropCol and dropIndex reflects the position of the drop.
1998 \internal
1999 */
2000bool QAbstractItemViewPrivate::dropOn(QDropEvent *event, int *dropRow, int *dropCol, QModelIndex *dropIndex)
2001{
2002 Q_Q(QAbstractItemView);
2003 if (event->isAccepted())
2004 return false;
2005
2006 QModelIndex index;
2007 // rootIndex() (i.e. the viewport) might be a valid index
2008 if (viewport->rect().contains(event->pos())) {
2009 index = q->indexAt(event->pos());
2010 if (!index.isValid() || !q->visualRect(index).contains(event->pos()))
2011 index = root;
2012 }
2013
2014 // If we are allowed to do the drop
2015 if (model->supportedDropActions() & event->dropAction()) {
2016 int row = -1;
2017 int col = -1;
2018 if (index != root) {
2019 dropIndicatorPosition = position(event->pos(), q->visualRect(index), index);
2020 switch (dropIndicatorPosition) {
2021 case QAbstractItemView::AboveItem:
2022 row = index.row();
2023 col = index.column();
2024 index = index.parent();
2025 break;
2026 case QAbstractItemView::BelowItem:
2027 row = index.row() + 1;
2028 col = index.column();
2029 index = index.parent();
2030 break;
2031 case QAbstractItemView::OnItem:
2032 case QAbstractItemView::OnViewport:
2033 break;
2034 }
2035 } else {
2036 dropIndicatorPosition = QAbstractItemView::OnViewport;
2037 }
2038 *dropIndex = index;
2039 *dropRow = row;
2040 *dropCol = col;
2041 if (!droppingOnItself(event, index))
2042 return true;
2043 }
2044 return false;
2045}
2046
2047QAbstractItemView::DropIndicatorPosition
2048QAbstractItemViewPrivate::position(const QPoint &pos, const QRect &rect, const QModelIndex &index) const
2049{
2050 QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
2051 if (!overwrite) {
2052 const int margin = 2;
2053 if (pos.y() - rect.top() < margin) {
2054 r = QAbstractItemView::AboveItem;
2055 } else if (rect.bottom() - pos.y() < margin) {
2056 r = QAbstractItemView::BelowItem;
2057 } else if (rect.contains(pos, true)) {
2058 r = QAbstractItemView::OnItem;
2059 }
2060 } else {
2061 QRect touchingRect = rect;
2062 touchingRect.adjust(-1, -1, 1, 1);
2063 if (touchingRect.contains(pos, false)) {
2064 r = QAbstractItemView::OnItem;
2065 }
2066 }
2067
2068 if (r == QAbstractItemView::OnItem && (!(model->flags(index) & Qt::ItemIsDropEnabled)))
2069 r = pos.y() < rect.center().y() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
2070
2071 return r;
2072}
2073
2074#endif // QT_NO_DRAGANDDROP
2075
2076/*!
2077 This function is called with the given \a event when the widget obtains the focus.
2078 By default, the event is ignored.
2079
2080 \sa setFocus(), focusOutEvent()
2081*/
2082void QAbstractItemView::focusInEvent(QFocusEvent *event)
2083{
2084 Q_D(QAbstractItemView);
2085 QAbstractScrollArea::focusInEvent(event);
2086
2087 const QItemSelectionModel* model = selectionModel();
2088 const bool currentIndexValid = currentIndex().isValid();
2089
2090 if (model
2091 && !d->currentIndexSet
2092 && !currentIndexValid) {
2093 bool autoScroll = d->autoScroll;
2094 d->autoScroll = false;
2095 QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index
2096 if (index.isValid() && d->isIndexEnabled(index))
2097 selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
2098 d->autoScroll = autoScroll;
2099 }
2100
2101 if (model && currentIndexValid) {
2102 if (currentIndex().flags() != Qt::ItemIsEditable)
2103 setAttribute(Qt::WA_InputMethodEnabled, false);
2104 else
2105 setAttribute(Qt::WA_InputMethodEnabled);
2106 }
2107
2108 if (!currentIndexValid)
2109 setAttribute(Qt::WA_InputMethodEnabled, false);
2110
2111 d->viewport->update();
2112}
2113
2114/*!
2115 This function is called with the given \a event when the widget
2116 looses the focus. By default, the event is ignored.
2117
2118 \sa clearFocus(), focusInEvent()
2119*/
2120void QAbstractItemView::focusOutEvent(QFocusEvent *event)
2121{
2122 Q_D(QAbstractItemView);
2123 QAbstractScrollArea::focusOutEvent(event);
2124 d->viewport->update();
2125
2126#ifdef QT_SOFTKEYS_ENABLED
2127 if(!hasEditFocus())
2128 removeAction(d->doneSoftKey);
2129#endif
2130}
2131
2132/*!
2133 This function is called with the given \a event when a key event is sent to
2134 the widget. The default implementation handles basic cursor movement, e.g. Up,
2135 Down, Left, Right, Home, PageUp, and PageDown; the activated() signal is
2136 emitted if the current index is valid and the activation key is pressed
2137 (e.g. Enter or Return, depending on the platform).
2138 This function is where editing is initiated by key press, e.g. if F2 is
2139 pressed.
2140
2141 \sa edit(), moveCursor(), keyboardSearch(), tabKeyNavigation
2142*/
2143void QAbstractItemView::keyPressEvent(QKeyEvent *event)
2144{
2145 Q_D(QAbstractItemView);
2146 d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling
2147
2148#ifdef QT_KEYPAD_NAVIGATION
2149 switch (event->key()) {
2150 case Qt::Key_Select:
2151 if (QApplication::keypadNavigationEnabled()) {
2152 if (!hasEditFocus()) {
2153 setEditFocus(true);
2154#ifdef QT_SOFTKEYS_ENABLED
2155 // If we can't keypad navigate to any direction, there is no sense to add
2156 // "Done" softkey, since it basically does nothing when there is
2157 // only one widget in screen
2158 if(QWidgetPrivate::canKeypadNavigate(Qt::Horizontal)
2159 || QWidgetPrivate::canKeypadNavigate(Qt::Vertical))
2160 addAction(d->doneSoftKey);
2161#endif
2162 return;
2163 }
2164 }
2165 break;
2166 case Qt::Key_Back:
2167 if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
2168#ifdef QT_SOFTKEYS_ENABLED
2169 removeAction(d->doneSoftKey);
2170#endif
2171 setEditFocus(false);
2172 } else {
2173 event->ignore();
2174 }
2175 return;
2176 case Qt::Key_Down:
2177 case Qt::Key_Up:
2178 // Let's ignore vertical navigation events, only if there is no other widget
2179 // what can take the focus in vertical direction. This means widget can handle navigation events
2180 // even the widget don't have edit focus, and there is no other widget in requested direction.
2181 if(QApplication::keypadNavigationEnabled() && !hasEditFocus()
2182 && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2183 event->ignore();
2184 return;
2185 }
2186 break;
2187 case Qt::Key_Left:
2188 case Qt::Key_Right:
2189 // Similar logic as in up and down events
2190 if(QApplication::keypadNavigationEnabled() && !hasEditFocus()
2191 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this))) {
2192 event->ignore();
2193 return;
2194 }
2195 break;
2196 default:
2197 if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
2198 event->ignore();
2199 return;
2200 }
2201 }
2202#endif
2203
2204#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
2205 if (event == QKeySequence::Copy) {
2206 QVariant variant;
2207 if (d->model)
2208 variant = d->model->data(currentIndex(), Qt::DisplayRole);
2209 if (variant.type() == QVariant::String)
2210 QApplication::clipboard()->setText(variant.toString());
2211 event->accept();
2212 }
2213#endif
2214
2215 QPersistentModelIndex newCurrent;
2216 switch (event->key()) {
2217 case Qt::Key_Down:
2218 newCurrent = moveCursor(MoveDown, event->modifiers());
2219 break;
2220 case Qt::Key_Up:
2221 newCurrent = moveCursor(MoveUp, event->modifiers());
2222 break;
2223 case Qt::Key_Left:
2224 newCurrent = moveCursor(MoveLeft, event->modifiers());
2225 break;
2226 case Qt::Key_Right:
2227 newCurrent = moveCursor(MoveRight, event->modifiers());
2228 break;
2229 case Qt::Key_Home:
2230 newCurrent = moveCursor(MoveHome, event->modifiers());
2231 break;
2232 case Qt::Key_End:
2233 newCurrent = moveCursor(MoveEnd, event->modifiers());
2234 break;
2235 case Qt::Key_PageUp:
2236 newCurrent = moveCursor(MovePageUp, event->modifiers());
2237 break;
2238 case Qt::Key_PageDown:
2239 newCurrent = moveCursor(MovePageDown, event->modifiers());
2240 break;
2241 case Qt::Key_Tab:
2242 if (d->tabKeyNavigation)
2243 newCurrent = moveCursor(MoveNext, event->modifiers());
2244 break;
2245 case Qt::Key_Backtab:
2246 if (d->tabKeyNavigation)
2247 newCurrent = moveCursor(MovePrevious, event->modifiers());
2248 break;
2249 }
2250
2251 QPersistentModelIndex oldCurrent = currentIndex();
2252 if (newCurrent != oldCurrent && newCurrent.isValid() && d->isIndexEnabled(newCurrent)) {
2253 if (!hasFocus() && QApplication::focusWidget() == indexWidget(oldCurrent))
2254 setFocus();
2255 QItemSelectionModel::SelectionFlags command = selectionCommand(newCurrent, event);
2256 if (command != QItemSelectionModel::NoUpdate
2257 || style()->styleHint(QStyle::SH_ItemView_MovementWithoutUpdatingSelection, 0, this)) {
2258 // note that we don't check if the new current index is enabled because moveCursor() makes sure it is
2259 if (command & QItemSelectionModel::Current) {
2260 d->selectionModel->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
2261 if (!indexAt(d->pressedPosition - d->offset()).isValid())
2262 d->pressedPosition = visualRect(oldCurrent).center() + d->offset();
2263 QRect rect(d->pressedPosition - d->offset(), visualRect(newCurrent).center());
2264 setSelection(rect, command);
2265 } else {
2266 d->selectionModel->setCurrentIndex(newCurrent, command);
2267 d->pressedPosition = visualRect(newCurrent).center() + d->offset();
2268 // We copy the same behaviour as for mousePressEvent().
2269 QRect rect(d->pressedPosition - d->offset(), QSize(1, 1));
2270 setSelection(rect, command);
2271 }
2272 return;
2273 }
2274 }
2275
2276 switch (event->key()) {
2277 // ignored keys
2278 case Qt::Key_Down:
2279 case Qt::Key_Up:
2280#ifdef QT_KEYPAD_NAVIGATION
2281 if (QApplication::keypadNavigationEnabled() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical)) {
2282 event->accept(); // don't change focus
2283 break;
2284 }
2285#endif
2286 case Qt::Key_Left:
2287 case Qt::Key_Right:
2288#ifdef QT_KEYPAD_NAVIGATION
2289 if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
2290 && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal)
2291 || (QWidgetPrivate::inTabWidget(this) && d->model->columnCount(d->root) > 1))) {
2292 event->accept(); // don't change focus
2293 break;
2294 }
2295#endif // QT_KEYPAD_NAVIGATION
2296 case Qt::Key_Home:
2297 case Qt::Key_End:
2298 case Qt::Key_PageUp:
2299 case Qt::Key_PageDown:
2300 case Qt::Key_Escape:
2301 case Qt::Key_Shift:
2302 case Qt::Key_Control:
2303 event->ignore();
2304 break;
2305 case Qt::Key_Space:
2306 case Qt::Key_Select:
2307 if (!edit(currentIndex(), AnyKeyPressed, event) && d->selectionModel)
2308 d->selectionModel->select(currentIndex(), selectionCommand(currentIndex(), event));
2309#ifdef QT_KEYPAD_NAVIGATION
2310 if ( event->key()==Qt::Key_Select ) {
2311 // Also do Key_Enter action.
2312 if (currentIndex().isValid()) {
2313 if (state() != EditingState)
2314 emit activated(currentIndex());
2315 } else {
2316 event->ignore();
2317 }
2318 }
2319#endif
2320 break;
2321#ifdef Q_WS_MAC
2322 case Qt::Key_Enter:
2323 case Qt::Key_Return:
2324 // Propagate the enter if you couldn't edit the item and there are no
2325 // current editors (if there are editors, the event was most likely propagated from it).
2326 if (!edit(currentIndex(), EditKeyPressed, event) && d->editors.isEmpty())
2327 event->ignore();
2328 break;
2329#else
2330 case Qt::Key_F2:
2331 if (!edit(currentIndex(), EditKeyPressed, event))
2332 event->ignore();
2333 break;
2334 case Qt::Key_Enter:
2335 case Qt::Key_Return:
2336 // ### we can't open the editor on enter, becuse
2337 // some widgets will forward the enter event back
2338 // to the viewport, starting an endless loop
2339 if (state() != EditingState || hasFocus()) {
2340 if (currentIndex().isValid())
2341 emit activated(currentIndex());
2342 event->ignore();
2343 }
2344 break;
2345#endif
2346 case Qt::Key_A:
2347 if (event->modifiers() & Qt::ControlModifier) {
2348 selectAll();
2349 break;
2350 }
2351 default: {
2352#ifdef Q_WS_MAC
2353 if (event->key() == Qt::Key_O && event->modifiers() & Qt::ControlModifier && currentIndex().isValid()) {
2354 emit activated(currentIndex());
2355 break;
2356 }
2357#endif
2358 bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier));
2359 if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) {
2360 keyboardSearch(event->text());
2361 event->accept();
2362 } else {
2363 event->ignore();
2364 }
2365 break; }
2366 }
2367}
2368
2369/*!
2370 This function is called with the given \a event when a resize event is sent to
2371 the widget.
2372
2373 \sa QWidget::resizeEvent()
2374*/
2375void QAbstractItemView::resizeEvent(QResizeEvent *event)
2376{
2377 QAbstractScrollArea::resizeEvent(event);
2378 updateGeometries();
2379}
2380
2381/*!
2382 This function is called with the given \a event when a timer event is sent
2383 to the widget.
2384
2385 \sa QObject::timerEvent()
2386*/
2387void QAbstractItemView::timerEvent(QTimerEvent *event)
2388{
2389 Q_D(QAbstractItemView);
2390 if (event->timerId() == d->fetchMoreTimer.timerId())
2391 d->fetchMore();
2392 else if (event->timerId() == d->delayedReset.timerId())
2393 reset();
2394 else if (event->timerId() == d->autoScrollTimer.timerId())
2395 doAutoScroll();
2396 else if (event->timerId() == d->updateTimer.timerId())
2397 d->updateDirtyRegion();
2398 else if (event->timerId() == d->delayedEditing.timerId()) {
2399 d->delayedEditing.stop();
2400 edit(currentIndex());
2401 } else if (event->timerId() == d->delayedLayout.timerId()) {
2402 d->delayedLayout.stop();
2403 if (isVisible()) {
2404 d->interruptDelayedItemsLayout();
2405 doItemsLayout();
2406 const QModelIndex current = currentIndex();
2407 if (current.isValid() && d->state == QAbstractItemView::EditingState)
2408 scrollTo(current);
2409 }
2410 } else if (event->timerId() == d->delayedAutoScroll.timerId()) {
2411 d->delayedAutoScroll.stop();
2412 //end of the timer: if the current item is still the same as the one when the mouse press occurred
2413 //we only get here if there was no double click
2414 if (d->pressedIndex.isValid() && d->pressedIndex == currentIndex())
2415 scrollTo(d->pressedIndex);
2416 }
2417}
2418
2419/*!
2420 \reimp
2421*/
2422void QAbstractItemView::inputMethodEvent(QInputMethodEvent *event)
2423{
2424 if (event->commitString().isEmpty() && event->preeditString().isEmpty()) {
2425 event->ignore();
2426 return;
2427 }
2428 if (!edit(currentIndex(), AnyKeyPressed, event)) {
2429 if (!event->commitString().isEmpty())
2430 keyboardSearch(event->commitString());
2431 event->ignore();
2432 }
2433}
2434
2435#ifndef QT_NO_DRAGANDDROP
2436/*!
2437 \enum QAbstractItemView::DropIndicatorPosition
2438
2439 This enum indicates the position of the drop indicator in
2440 relation to the index at the current mouse position:
2441
2442 \value OnItem The item will be dropped on the index.
2443
2444 \value AboveItem The item will be dropped above the index.
2445
2446 \value BelowItem The item will be dropped below the index.
2447
2448 \value OnViewport The item will be dropped onto a region of the viewport with
2449 no items. The way each view handles items dropped onto the viewport depends on
2450 the behavior of the underlying model in use.
2451*/
2452
2453
2454/*!
2455 \since 4.1
2456
2457 Returns the position of the drop indicator in relation to the closest item.
2458*/
2459QAbstractItemView::DropIndicatorPosition QAbstractItemView::dropIndicatorPosition() const
2460{
2461 Q_D(const QAbstractItemView);
2462 return d->dropIndicatorPosition;
2463}
2464#endif
2465
2466/*!
2467 This convenience function returns a list of all selected and
2468 non-hidden item indexes in the view. The list contains no
2469 duplicates, and is not sorted.
2470
2471 \sa QItemSelectionModel::selectedIndexes()
2472*/
2473QModelIndexList QAbstractItemView::selectedIndexes() const
2474{
2475 Q_D(const QAbstractItemView);
2476 QModelIndexList indexes;
2477 if (d->selectionModel) {
2478 indexes = d->selectionModel->selectedIndexes();
2479 QList<QModelIndex>::iterator it = indexes.begin();
2480 while (it != indexes.end())
2481 if (isIndexHidden(*it))
2482 it = indexes.erase(it);
2483 else
2484 ++it;
2485 }
2486 return indexes;
2487}
2488
2489/*!
2490 Starts editing the item at \a index, creating an editor if
2491 necessary, and returns true if the view's \l{State} is now
2492 EditingState; otherwise returns false.
2493
2494 The action that caused the editing process is described by
2495 \a trigger, and the associated event is specified by \a event.
2496
2497 Editing can be forced by specifying the \a trigger to be
2498 QAbstractItemView::AllEditTriggers.
2499
2500 \sa closeEditor()
2501*/
2502bool QAbstractItemView::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
2503{
2504 Q_D(QAbstractItemView);
2505
2506 if (!d->isIndexValid(index))
2507 return false;
2508
2509 if (QWidget *w = (d->persistent.isEmpty() ? static_cast<QWidget*>(0) : d->editorForIndex(index).editor.data())) {
2510 if (w->focusPolicy() == Qt::NoFocus)
2511 return false;
2512 w->setFocus();
2513 return true;
2514 }
2515
2516 if (trigger == DoubleClicked) {
2517 d->delayedEditing.stop();
2518 d->delayedAutoScroll.stop();
2519 } else if (trigger == CurrentChanged) {
2520 d->delayedEditing.stop();
2521 }
2522
2523 if (d->sendDelegateEvent(index, event)) {
2524 update(index);
2525 return true;
2526 }
2527
2528 // save the previous trigger before updating
2529 EditTriggers lastTrigger = d->lastTrigger;
2530 d->lastTrigger = trigger;
2531
2532 if (!d->shouldEdit(trigger, d->model->buddy(index)))
2533 return false;
2534
2535 if (d->delayedEditing.isActive())
2536 return false;
2537
2538 // we will receive a mouseButtonReleaseEvent after a
2539 // mouseDoubleClickEvent, so we need to check the previous trigger
2540 if (lastTrigger == DoubleClicked && trigger == SelectedClicked)
2541 return false;
2542
2543 // we may get a double click event later
2544 if (trigger == SelectedClicked)
2545 d->delayedEditing.start(QApplication::doubleClickInterval(), this);
2546 else
2547 d->openEditor(index, d->shouldForwardEvent(trigger, event) ? event : 0);
2548
2549 return true;
2550}
2551
2552/*!
2553 \internal
2554 Updates the data shown in the open editor widgets in the view.
2555*/
2556void QAbstractItemView::updateEditorData()
2557{
2558 Q_D(QAbstractItemView);
2559 d->updateEditorData(QModelIndex(), QModelIndex());
2560}
2561
2562/*!
2563 \internal
2564 Updates the geometry of the open editor widgets in the view.
2565*/
2566void QAbstractItemView::updateEditorGeometries()
2567{
2568 Q_D(QAbstractItemView);
2569 if(d->editors.isEmpty())
2570 return;
2571 QStyleOptionViewItemV4 option = d->viewOptionsV4();
2572 QList<QEditorInfo>::iterator it = d->editors.begin();
2573 QWidgetList editorsToRelease;
2574 QWidgetList editorsToHide;
2575 while (it != d->editors.end()) {
2576 QModelIndex index = it->index;
2577 QWidget *editor = it->editor;
2578 if (index.isValid() && editor) {
2579 option.rect = visualRect(index);
2580 if (option.rect.isValid()) {
2581 editor->show();
2582 QAbstractItemDelegate *delegate = d->delegateForIndex(index);
2583 if (delegate)
2584 delegate->updateEditorGeometry(editor, option, index);
2585 } else {
2586 editorsToHide << editor;
2587 }
2588 ++it;
2589 } else {
2590 it = d->editors.erase(it);
2591 editorsToRelease << editor;
2592 }
2593 }
2594
2595 //we hide and release the editor outside of the loop because it might change the focus and try
2596 //to change the d->editors list.
2597 for (int i = 0; i < editorsToHide.count(); ++i) {
2598 editorsToHide.at(i)->hide();
2599 }
2600 for (int i = 0; i < editorsToRelease.count(); ++i) {
2601 d->releaseEditor(editorsToRelease.at(i));
2602 }
2603}
2604
2605/*!
2606 \since 4.4
2607
2608 Updates the geometry of the child widgets of the view.
2609*/
2610void QAbstractItemView::updateGeometries()
2611{
2612 updateEditorGeometries();
2613 d_func()->fetchMoreTimer.start(0, this); //fetch more later
2614}
2615
2616/*!
2617 \internal
2618*/
2619void QAbstractItemView::verticalScrollbarValueChanged(int value)
2620{
2621 Q_D(QAbstractItemView);
2622 if (verticalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2623 d->model->fetchMore(d->root);
2624 QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2625 if (viewport()->rect().contains(posInVp))
2626 d->checkMouseMove(posInVp);
2627}
2628
2629/*!
2630 \internal
2631*/
2632void QAbstractItemView::horizontalScrollbarValueChanged(int value)
2633{
2634 Q_D(QAbstractItemView);
2635 if (horizontalScrollBar()->maximum() == value && d->model->canFetchMore(d->root))
2636 d->model->fetchMore(d->root);
2637 QPoint posInVp = viewport()->mapFromGlobal(QCursor::pos());
2638 if (viewport()->rect().contains(posInVp))
2639 d->checkMouseMove(posInVp);
2640}
2641
2642/*!
2643 \internal
2644*/
2645void QAbstractItemView::verticalScrollbarAction(int)
2646{
2647 //do nothing
2648}
2649
2650/*!
2651 \internal
2652*/
2653void QAbstractItemView::horizontalScrollbarAction(int)
2654{
2655 //do nothing
2656}
2657
2658/*!
2659 Closes the given \a editor, and releases it. The \a hint is
2660 used to specify how the view should respond to the end of the editing
2661 operation. For example, the hint may indicate that the next item in
2662 the view should be opened for editing.
2663
2664 \sa edit(), commitData()
2665*/
2666
2667void QAbstractItemView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
2668{
2669 Q_D(QAbstractItemView);
2670
2671 // Close the editor
2672 if (editor) {
2673 bool isPersistent = d->persistent.contains(editor);
2674 bool hadFocus = editor->hasFocus();
2675 QModelIndex index = d->indexForEditor(editor);
2676 if (!index.isValid())
2677 return; // the editor was not registered
2678
2679 if (!isPersistent) {
2680 setState(NoState);
2681 QModelIndex index = d->indexForEditor(editor);
2682 editor->removeEventFilter(d->delegateForIndex(index));
2683 d->removeEditor(editor);
2684 }
2685 if (hadFocus)
2686 setFocus(); // this will send a focusLost event to the editor
2687 else
2688 d->checkPersistentEditorFocus();
2689
2690 QPointer<QWidget> ed = editor;
2691 QApplication::sendPostedEvents(editor, 0);
2692 editor = ed;
2693
2694 if (!isPersistent && editor)
2695 d->releaseEditor(editor);
2696 }
2697
2698 // The EndEditHint part
2699 QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect
2700 | d->selectionBehaviorFlags();
2701 switch (hint) {
2702 case QAbstractItemDelegate::EditNextItem: {
2703 QModelIndex index = moveCursor(MoveNext, Qt::NoModifier);
2704 if (index.isValid()) {
2705 QPersistentModelIndex persistent(index);
2706 d->selectionModel->setCurrentIndex(persistent, flags);
2707 // currentChanged signal would have already started editing
2708 if (index.flags() & Qt::ItemIsEditable
2709 && (!(editTriggers() & QAbstractItemView::CurrentChanged)))
2710 edit(persistent);
2711 } break; }
2712 case QAbstractItemDelegate::EditPreviousItem: {
2713 QModelIndex index = moveCursor(MovePrevious, Qt::NoModifier);
2714 if (index.isValid()) {
2715 QPersistentModelIndex persistent(index);
2716 d->selectionModel->setCurrentIndex(persistent, flags);
2717 // currentChanged signal would have already started editing
2718 if (index.flags() & Qt::ItemIsEditable
2719 && (!(editTriggers() & QAbstractItemView::CurrentChanged)))
2720 edit(persistent);
2721 } break; }
2722 case QAbstractItemDelegate::SubmitModelCache:
2723 d->model->submit();
2724 break;
2725 case QAbstractItemDelegate::RevertModelCache:
2726 d->model->revert();
2727 break;
2728 default:
2729 break;
2730 }
2731}
2732
2733/*!
2734 Commit the data in the \a editor to the model.
2735
2736 \sa closeEditor()
2737*/
2738void QAbstractItemView::commitData(QWidget *editor)
2739{
2740 Q_D(QAbstractItemView);
2741 if (!editor || !d->itemDelegate || d->currentlyCommittingEditor)
2742 return;
2743 QModelIndex index = d->indexForEditor(editor);
2744 if (!index.isValid())
2745 return;
2746 d->currentlyCommittingEditor = editor;
2747 QAbstractItemDelegate *delegate = d->delegateForIndex(index);
2748 editor->removeEventFilter(delegate);
2749 delegate->setModelData(editor, d->model, index);
2750 editor->installEventFilter(delegate);
2751 d->currentlyCommittingEditor = 0;
2752}
2753
2754/*!
2755 This function is called when the given \a editor has been destroyed.
2756
2757 \sa closeEditor()
2758*/
2759void QAbstractItemView::editorDestroyed(QObject *editor)
2760{
2761 Q_D(QAbstractItemView);
2762 QWidget *w = qobject_cast<QWidget*>(editor);
2763 d->removeEditor(w);
2764 d->persistent.remove(w);
2765 if (state() == EditingState)
2766 setState(NoState);
2767}
2768
2769/*!
2770 \obsolete
2771 Sets the horizontal scroll bar's steps per item to \a steps.
2772
2773 This is the number of steps used by the horizontal scroll bar to
2774 represent the width of an item.
2775
2776 Note that if the view has a horizontal header, the item steps
2777 will be ignored and the header section size will be used instead.
2778
2779 \sa horizontalStepsPerItem() setVerticalStepsPerItem()
2780*/
2781void QAbstractItemView::setHorizontalStepsPerItem(int steps)
2782{
2783 Q_UNUSED(steps);
2784 // do nothing
2785}
2786
2787/*!
2788 \obsolete
2789 Returns the horizontal scroll bar's steps per item.
2790
2791 \sa setHorizontalStepsPerItem() verticalStepsPerItem()
2792*/
2793int QAbstractItemView::horizontalStepsPerItem() const
2794{
2795 return 1;
2796}
2797
2798/*!
2799 \obsolete
2800 Sets the vertical scroll bar's steps per item to \a steps.
2801
2802 This is the number of steps used by the vertical scroll bar to
2803 represent the height of an item.
2804
2805 Note that if the view has a vertical header, the item steps
2806 will be ignored and the header section size will be used instead.
2807
2808 \sa verticalStepsPerItem() setHorizontalStepsPerItem()
2809*/
2810void QAbstractItemView::setVerticalStepsPerItem(int steps)
2811{
2812 Q_UNUSED(steps);
2813 // do nothing
2814}
2815
2816/*!
2817 \obsolete
2818 Returns the vertical scroll bar's steps per item.
2819
2820 \sa setVerticalStepsPerItem() horizontalStepsPerItem()
2821*/
2822int QAbstractItemView::verticalStepsPerItem() const
2823{
2824 return 1;
2825}
2826
2827/*!
2828 Moves to and selects the item best matching the string \a search.
2829 If no item is found nothing happens.
2830
2831 In the default implementation, the search is reset if \a search is empty, or
2832 the time interval since the last search has exceeded
2833 QApplication::keyboardInputInterval().
2834*/
2835void QAbstractItemView::keyboardSearch(const QString &search)
2836{
2837 Q_D(QAbstractItemView);
2838 if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
2839 return;
2840
2841 QModelIndex start = currentIndex().isValid() ? currentIndex()
2842 : d->model->index(0, 0, d->root);
2843 QTime now(QTime::currentTime());
2844 bool skipRow = false;
2845 if (search.isEmpty()
2846 || (d->keyboardInputTime.msecsTo(now) > QApplication::keyboardInputInterval())) {
2847 d->keyboardInput = search;
2848 skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0)
2849 } else {
2850 d->keyboardInput += search;
2851 }
2852 d->keyboardInputTime = now;
2853
2854 // special case for searches with same key like 'aaaaa'
2855 bool sameKey = false;
2856 if (d->keyboardInput.length() > 1) {
2857 int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1));
2858 sameKey = (c == d->keyboardInput.length());
2859 if (sameKey)
2860 skipRow = true;
2861 }
2862
2863 // skip if we are searching for the same key or a new search started
2864 if (skipRow) {
2865 QModelIndex parent = start.parent();
2866 int newRow = (start.row() < d->model->rowCount(parent) - 1) ? start.row() + 1 : 0;
2867 start = d->model->index(newRow, start.column(), parent);
2868 }
2869
2870 // search from start with wraparound
2871 const QString searchString = sameKey ? QString(d->keyboardInput.at(0)) : d->keyboardInput;
2872 QModelIndex current = start;
2873 QModelIndexList match;
2874 QModelIndex firstMatch;
2875 QModelIndex startMatch;
2876 QModelIndexList previous;
2877 do {
2878 match = d->model->match(current, Qt::DisplayRole, searchString);
2879 if (match == previous)
2880 break;
2881 firstMatch = match.value(0);
2882 previous = match;
2883 if (firstMatch.isValid()) {
2884 if (d->isIndexEnabled(firstMatch)) {
2885 setCurrentIndex(firstMatch);
2886 break;
2887 }
2888 int row = firstMatch.row() + 1;
2889 if (row >= d->model->rowCount(firstMatch.parent()))
2890 row = 0;
2891 current = firstMatch.sibling(row, firstMatch.column());
2892
2893 //avoid infinite loop if all the matching items are disabled.
2894 if (!startMatch.isValid())
2895 startMatch = firstMatch;
2896 else if (startMatch == firstMatch)
2897 break;
2898 }
2899 } while (current != start && firstMatch.isValid());
2900}
2901
2902/*!
2903 Returns the size hint for the item with the specified \a index or
2904 an invalid size for invalid indexes.
2905
2906 \sa sizeHintForRow(), sizeHintForColumn()
2907*/
2908QSize QAbstractItemView::sizeHintForIndex(const QModelIndex &index) const
2909{
2910 Q_D(const QAbstractItemView);
2911 if (!d->isIndexValid(index) || !d->itemDelegate)
2912 return QSize();
2913 return d->delegateForIndex(index)->sizeHint(d->viewOptionsV4(), index);
2914}
2915
2916/*!
2917 Returns the height size hint for the specified \a row or -1 if
2918 there is no model.
2919
2920 The returned height is calculated using the size hints of the
2921 given \a row's items, i.e. the returned value is the maximum
2922 height among the items. Note that to control the height of a row,
2923 you must reimplement the QAbstractItemDelegate::sizeHint()
2924 function.
2925
2926 This function is used in views with a vertical header to find the
2927 size hint for a header section based on the contents of the given
2928 \a row.
2929
2930 \sa sizeHintForColumn()
2931*/
2932int QAbstractItemView::sizeHintForRow(int row) const
2933{
2934 Q_D(const QAbstractItemView);
2935
2936 if (row < 0 || row >= d->model->rowCount() || !model())
2937 return -1;
2938
2939 ensurePolished();
2940
2941 QStyleOptionViewItemV4 option = d->viewOptionsV4();
2942 int height = 0;
2943 int colCount = d->model->columnCount(d->root);
2944 QModelIndex index;
2945 for (int c = 0; c < colCount; ++c) {
2946 index = d->model->index(row, c, d->root);
2947 if (QWidget *editor = d->editorForIndex(index).editor)
2948 height = qMax(height, editor->size().height());
2949 int hint = d->delegateForIndex(index)->sizeHint(option, index).height();
2950 height = qMax(height, hint);
2951 }
2952 return height;
2953}
2954
2955/*!
2956 Returns the width size hint for the specified \a column or -1 if there is no model.
2957
2958 This function is used in views with a horizontal header to find the size hint for
2959 a header section based on the contents of the given \a column.
2960
2961 \sa sizeHintForRow()
2962*/
2963int QAbstractItemView::sizeHintForColumn(int column) const
2964{
2965 Q_D(const QAbstractItemView);
2966
2967 if (column < 0 || column >= d->model->columnCount() || !model())
2968 return -1;
2969
2970 ensurePolished();
2971
2972 QStyleOptionViewItemV4 option = d->viewOptionsV4();
2973 int width = 0;
2974 int rows = d->model->rowCount(d->root);
2975 QModelIndex index;
2976 for (int r = 0; r < rows; ++r) {
2977 index = d->model->index(r, column, d->root);
2978 if (QWidget *editor = d->editorForIndex(index).editor)
2979 width = qMax(width, editor->sizeHint().width());
2980 int hint = d->delegateForIndex(index)->sizeHint(option, index).width();
2981 width = qMax(width, hint);
2982 }
2983 return width;
2984}
2985
2986/*!
2987 Opens a persistent editor on the item at the given \a index.
2988 If no editor exists, the delegate will create a new editor.
2989
2990 \sa closePersistentEditor()
2991*/
2992void QAbstractItemView::openPersistentEditor(const QModelIndex &index)
2993{
2994 Q_D(QAbstractItemView);
2995 QStyleOptionViewItemV4 options = d->viewOptionsV4();
2996 options.rect = visualRect(index);
2997 options.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
2998
2999 QWidget *editor = d->editor(index, options);
3000 if (editor) {
3001 editor->show();
3002 d->persistent.insert(editor);
3003 }
3004}
3005
3006/*!
3007 Closes the persistent editor for the item at the given \a index.
3008
3009 \sa openPersistentEditor()
3010*/
3011void QAbstractItemView::closePersistentEditor(const QModelIndex &index)
3012{
3013 Q_D(QAbstractItemView);
3014 QWidget *editor = d->editorForIndex(index).editor;
3015 if (editor) {
3016 if (index == selectionModel()->currentIndex())
3017 closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
3018 d->persistent.remove(editor);
3019 d->removeEditor(editor);
3020 d->releaseEditor(editor);
3021 }
3022}
3023
3024/*!
3025 \since 4.1
3026
3027 Sets the given \a widget on the item at the given \a index, passing the
3028 ownership of the widget to the viewport.
3029
3030 If \a index is invalid (e.g., if you pass the root index), this function
3031 will do nothing.
3032
3033 The given \a widget's \l{QWidget}{autoFillBackground} property must be set
3034 to true, otherwise the widget's background will be transparent, showing
3035 both the model data and the item at the given \a index.
3036
3037 If index widget A is replaced with index widget B, index widget A will be
3038 deleted. For example, in the code snippet below, the QLineEdit object will
3039 be deleted.
3040
3041 \snippet doc/src/snippets/code/src_gui_itemviews_qabstractitemview.cpp 1
3042
3043 This function should only be used to display static content within the
3044 visible area corresponding to an item of data. If you want to display
3045 custom dynamic content or implement a custom editor widget, subclass
3046 QItemDelegate instead.
3047
3048 \sa {Delegate Classes}
3049*/
3050void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget)
3051{
3052 Q_D(QAbstractItemView);
3053 if (!d->isIndexValid(index))
3054 return;
3055 if (QWidget *oldWidget = indexWidget(index)) {
3056 d->persistent.remove(oldWidget);
3057 d->removeEditor(oldWidget);
3058 oldWidget->deleteLater();
3059 }
3060 if (widget) {
3061 widget->setParent(viewport());
3062 d->persistent.insert(widget);
3063 d->addEditor(index, widget, true);
3064 widget->show();
3065 dataChanged(index, index); // update the geometry
3066 if (!d->delayedPendingLayout)
3067 widget->setGeometry(visualRect(index));
3068 }
3069}
3070
3071/*!
3072 \since 4.1
3073
3074 Returns the widget for the item at the given \a index.
3075*/
3076QWidget* QAbstractItemView::indexWidget(const QModelIndex &index) const
3077{
3078 Q_D(const QAbstractItemView);
3079 if (!d->isIndexValid(index))
3080 return 0;
3081 return d->editorForIndex(index).editor;
3082}
3083
3084/*!
3085 \since 4.1
3086
3087 Scrolls the view to the top.
3088
3089 \sa scrollTo(), scrollToBottom()
3090*/
3091void QAbstractItemView::scrollToTop()
3092{
3093 verticalScrollBar()->setValue(verticalScrollBar()->minimum());
3094}
3095
3096/*!
3097 \since 4.1
3098
3099 Scrolls the view to the bottom.
3100
3101 \sa scrollTo(), scrollToTop()
3102*/
3103void QAbstractItemView::scrollToBottom()
3104{
3105 Q_D(QAbstractItemView);
3106 if (d->delayedPendingLayout) {
3107 d->executePostedLayout();
3108 updateGeometries();
3109 }
3110 verticalScrollBar()->setValue(verticalScrollBar()->maximum());
3111}
3112
3113/*!
3114 \since 4.3
3115
3116 Updates the area occupied by the given \a index.
3117
3118*/
3119void QAbstractItemView::update(const QModelIndex &index)
3120{
3121 Q_D(QAbstractItemView);
3122 if (index.isValid()) {
3123 const QRect rect = visualRect(index);
3124 //this test is important for peformance reason
3125 //For example in dataChanged we simply update all the cells without checking
3126 //it can be a major bottleneck to update rects that aren't even part of the viewport
3127 if (d->viewport->rect().intersects(rect))
3128 d->viewport->update(rect);
3129 }
3130}
3131
3132/*!
3133 This slot is called when items are changed in the model. The
3134 changed items are those from \a topLeft to \a bottomRight
3135 inclusive. If just one item is changed \a topLeft == \a
3136 bottomRight.
3137*/
3138void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
3139{
3140 // Single item changed
3141 Q_D(QAbstractItemView);
3142 if (topLeft == bottomRight && topLeft.isValid()) {
3143 const QEditorInfo editorInfo = d->editorForIndex(topLeft);
3144 //we don't update the edit data if it is static
3145 if (!editorInfo.isStatic && editorInfo.editor) {
3146 QAbstractItemDelegate *delegate = d->delegateForIndex(topLeft);
3147 if (delegate) {
3148 delegate->setEditorData(editorInfo.editor, topLeft);
3149 }
3150 }
3151 if (isVisible() && !d->delayedPendingLayout) {
3152 // otherwise the items will be update later anyway
3153 update(topLeft);
3154 }
3155 return;
3156 }
3157 d->updateEditorData(topLeft, bottomRight);
3158 if (!isVisible() || d->delayedPendingLayout)
3159 return; // no need to update
3160 d->viewport->update();
3161}
3162
3163/*!
3164 This slot is called when rows are inserted. The new rows are those
3165 under the given \a parent from \a start to \a end inclusive. The
3166 base class implementation calls fetchMore() on the model to check
3167 for more data.
3168
3169 \sa rowsAboutToBeRemoved()
3170*/
3171void QAbstractItemView::rowsInserted(const QModelIndex &, int, int)
3172{
3173 if (!isVisible())
3174 d_func()->fetchMoreTimer.start(0, this); //fetch more later
3175 else
3176 updateEditorGeometries();
3177}
3178
3179/*!
3180 This slot is called when rows are about to be removed. The deleted rows are
3181 those under the given \a parent from \a start to \a end inclusive.
3182
3183 \sa rowsInserted()
3184*/
3185void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
3186{
3187 Q_D(QAbstractItemView);
3188
3189 setState(CollapsingState);
3190
3191 // Ensure one selected item in single selection mode.
3192 QModelIndex current = currentIndex();
3193 if (d->selectionMode == SingleSelection
3194 && current.isValid()
3195 && current.row() >= start
3196 && current.row() <= end
3197 && current.parent() == parent) {
3198 int totalToRemove = end - start + 1;
3199 if (d->model->rowCount(parent) <= totalToRemove) { // no more children
3200 QModelIndex index = parent;
3201 while (index != d->root && !d->isIndexEnabled(index))
3202 index = index.parent();
3203 if (index != d->root)
3204 setCurrentIndex(index);
3205 } else {
3206 int row = end + 1;
3207 QModelIndex next;
3208 do { // find the next visible and enabled item
3209 next = d->model->index(row++, current.column(), current.parent());
3210 } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next)));
3211 if (row > d->model->rowCount(parent)) {
3212 row = start - 1;
3213 do { // find the previous visible and enabled item
3214 next = d->model->index(row--, current.column(), current.parent());
3215 } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next)));
3216 }
3217 setCurrentIndex(next);
3218 }
3219 }
3220
3221 // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
3222 for (int i = d->editors.size() - 1; i >= 0; --i) {
3223 const QModelIndex index = d->editors.at(i).index;
3224 QWidget *editor = d->editors.at(i).editor;
3225 if (index.row() >= start && index.row() <= end && d->model->parent(index) == parent) {
3226 d->editors.removeAt(i);
3227 d->releaseEditor(editor);
3228 }
3229 }
3230}
3231
3232/*!
3233 \internal
3234
3235 This slot is called when rows have been removed. The deleted
3236 rows are those under the given \a parent from \a start to \a end
3237 inclusive.
3238*/
3239void QAbstractItemViewPrivate::_q_rowsRemoved(const QModelIndex &, int, int)
3240{
3241 Q_Q(QAbstractItemView);
3242 if (q->isVisible())
3243 q->updateEditorGeometries();
3244 q->setState(QAbstractItemView::NoState);
3245}
3246
3247/*!
3248 \internal
3249
3250 This slot is called when columns are about to be removed. The deleted
3251 columns are those under the given \a parent from \a start to \a end
3252 inclusive.
3253*/
3254void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
3255{
3256 Q_Q(QAbstractItemView);
3257
3258 q->setState(QAbstractItemView::CollapsingState);
3259
3260 // Ensure one selected item in single selection mode.
3261 QModelIndex current = q->currentIndex();
3262 if (current.isValid()
3263 && selectionMode == QAbstractItemView::SingleSelection
3264 && current.column() >= start
3265 && current.column() <= end) {
3266 int totalToRemove = end - start + 1;
3267 if (model->columnCount(parent) < totalToRemove) { // no more columns
3268 QModelIndex index = parent;
3269 while (index.isValid() && !isIndexEnabled(index))
3270 index = index.parent();
3271 if (index.isValid())
3272 q->setCurrentIndex(index);
3273 } else {
3274 int column = end;
3275 QModelIndex next;
3276 do { // find the next visible and enabled item
3277 next = model->index(current.row(), column++, current.parent());
3278 } while (next.isValid() && (q->isIndexHidden(next) || !isIndexEnabled(next)));
3279 q->setCurrentIndex(next);
3280 }
3281 }
3282
3283 // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
3284 QList<QEditorInfo>::iterator it = editors.begin();
3285 while (it != editors.end()) {
3286 QModelIndex index = it->index;
3287 if (index.column() <= start && index.column() >= end && model->parent(index) == parent) {
3288 QWidget *editor = it->editor;
3289 it = editors.erase(it);
3290 releaseEditor(editor);
3291 } else {
3292 ++it;
3293 }
3294 }
3295}
3296
3297/*!
3298 \internal
3299
3300 This slot is called when columns have been removed. The deleted
3301 rows are those under the given \a parent from \a start to \a end
3302 inclusive.
3303*/
3304void QAbstractItemViewPrivate::_q_columnsRemoved(const QModelIndex &, int, int)
3305{
3306 Q_Q(QAbstractItemView);
3307 if (q->isVisible())
3308 q->updateEditorGeometries();
3309 q->setState(QAbstractItemView::NoState);
3310}
3311
3312/*!
3313 \internal
3314
3315 This slot is called when rows have been inserted.
3316*/
3317void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &, int, int)
3318{
3319 Q_Q(QAbstractItemView);
3320 if (q->isVisible())
3321 q->updateEditorGeometries();
3322}
3323
3324
3325
3326/*!
3327 \internal
3328*/
3329void QAbstractItemViewPrivate::_q_modelDestroyed()
3330{
3331 model = QAbstractItemModelPrivate::staticEmptyModel();
3332 doDelayedReset();
3333}
3334
3335/*!
3336 \internal
3337
3338 This slot is called when the layout is changed.
3339*/
3340void QAbstractItemViewPrivate::_q_layoutChanged()
3341{
3342 doDelayedItemsLayout();
3343}
3344
3345/*!
3346 This slot is called when the selection is changed. The previous
3347 selection (which may be empty), is specified by \a deselected, and the
3348 new selection by \a selected.
3349
3350 \sa setSelection()
3351*/
3352void QAbstractItemView::selectionChanged(const QItemSelection &selected,
3353 const QItemSelection &deselected)
3354{
3355 Q_D(QAbstractItemView);
3356 if (isVisible() && updatesEnabled()) {
3357 d->viewport->update(visualRegionForSelection(deselected) | visualRegionForSelection(selected));
3358 }
3359}
3360
3361/*!
3362 This slot is called when a new item becomes the current item.
3363 The previous current item is specified by the \a previous index, and the new
3364 item by the \a current index.
3365
3366 If you want to know about changes to items see the
3367 dataChanged() signal.
3368*/
3369void QAbstractItemView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
3370{
3371 Q_D(QAbstractItemView);
3372 Q_ASSERT(d->model);
3373
3374 if (previous.isValid()) {
3375 QModelIndex buddy = d->model->buddy(previous);
3376 QWidget *editor = d->editorForIndex(buddy).editor;
3377 if (editor && !d->persistent.contains(editor)) {
3378 commitData(editor);
3379 if (current.row() != previous.row())
3380 closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
3381 else
3382 closeEditor(editor, QAbstractItemDelegate::NoHint);
3383 }
3384 if (isVisible()) {
3385 update(previous);
3386 }
3387 }
3388
3389 if (current.isValid() && !d->autoScrollTimer.isActive()) {
3390 if (isVisible()) {
3391 if (d->autoScroll)
3392 scrollTo(current);
3393 update(current);
3394 edit(current, CurrentChanged, 0);
3395 if (current.row() == (d->model->rowCount(d->root) - 1))
3396 d->fetchMore();
3397 } else {
3398 d->shouldScrollToCurrentOnShow = d->autoScroll;
3399 }
3400 }
3401}
3402
3403#ifndef QT_NO_DRAGANDDROP
3404/*!
3405 Starts a drag by calling drag->exec() using the given \a supportedActions.
3406*/
3407void QAbstractItemView::startDrag(Qt::DropActions supportedActions)
3408{
3409 Q_D(QAbstractItemView);
3410 QModelIndexList indexes = d->selectedDraggableIndexes();
3411 if (indexes.count() > 0) {
3412 QMimeData *data = d->model->mimeData(indexes);
3413 if (!data)
3414 return;
3415 QRect rect;
3416 QPixmap pixmap = d->renderToPixmap(indexes, &rect);
3417 rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
3418 QDrag *drag = new QDrag(this);
3419 drag->setPixmap(pixmap);
3420 drag->setMimeData(data);
3421 drag->setHotSpot(d->pressedPosition - rect.topLeft());
3422 Qt::DropAction defaultDropAction = Qt::IgnoreAction;
3423 if (d->defaultDropAction != Qt::IgnoreAction && (supportedActions & d->defaultDropAction))
3424 defaultDropAction = d->defaultDropAction;
3425 else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
3426 defaultDropAction = Qt::CopyAction;
3427 if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
3428 d->clearOrRemove();
3429 }
3430}
3431#endif // QT_NO_DRAGANDDROP
3432
3433/*!
3434 Returns a QStyleOptionViewItem structure populated with the view's
3435 palette, font, state, alignments etc.
3436*/
3437QStyleOptionViewItem QAbstractItemView::viewOptions() const
3438{
3439 Q_D(const QAbstractItemView);
3440 QStyleOptionViewItem option;
3441 option.init(this);
3442 option.state &= ~QStyle::State_MouseOver;
3443 option.font = font();
3444
3445#ifndef Q_WS_MAC
3446 // On mac the focus appearance follows window activation
3447 // not widget activation
3448 if (!hasFocus())
3449 option.state &= ~QStyle::State_Active;
3450#endif
3451
3452 option.state &= ~QStyle::State_HasFocus;
3453 if (d->iconSize.isValid()) {
3454 option.decorationSize = d->iconSize;
3455 } else {
3456 int pm = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
3457 option.decorationSize = QSize(pm, pm);
3458 }
3459 option.decorationPosition = QStyleOptionViewItem::Left;
3460 option.decorationAlignment = Qt::AlignCenter;
3461 option.displayAlignment = Qt::AlignLeft|Qt::AlignVCenter;
3462 option.textElideMode = d->textElideMode;
3463 option.rect = QRect();
3464 option.showDecorationSelected = style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, 0, this);
3465 return option;
3466}
3467
3468QStyleOptionViewItemV4 QAbstractItemViewPrivate::viewOptionsV4() const
3469{
3470 Q_Q(const QAbstractItemView);
3471 QStyleOptionViewItemV4 option = q->viewOptions();
3472 if (wrapItemText)
3473 option.features = QStyleOptionViewItemV2::WrapText;
3474 option.locale = q->locale();
3475 option.locale.setNumberOptions(QLocale::OmitGroupSeparator);
3476 option.widget = q;
3477 return option;
3478}
3479
3480/*!
3481 Returns the item view's state.
3482
3483 \sa setState()
3484*/
3485QAbstractItemView::State QAbstractItemView::state() const
3486{
3487 Q_D(const QAbstractItemView);
3488 return d->state;
3489}
3490
3491/*!
3492 Sets the item view's state to the given \a state.
3493
3494 \sa state()
3495*/
3496void QAbstractItemView::setState(State state)
3497{
3498 Q_D(QAbstractItemView);
3499 d->state = state;
3500}
3501
3502/*!
3503 Schedules a layout of the items in the view to be executed when the
3504 event processing starts.
3505
3506 Even if scheduleDelayedItemsLayout() is called multiple times before
3507 events are processed, the view will only do the layout once.
3508
3509 \sa executeDelayedItemsLayout()
3510*/
3511void QAbstractItemView::scheduleDelayedItemsLayout()
3512{
3513 Q_D(QAbstractItemView);
3514 d->doDelayedItemsLayout();
3515}
3516
3517/*!
3518 Executes the scheduled layouts without waiting for the event processing
3519 to begin.
3520
3521 \sa scheduleDelayedItemsLayout()
3522*/
3523void QAbstractItemView::executeDelayedItemsLayout()
3524{
3525 Q_D(QAbstractItemView);
3526 d->executePostedLayout();
3527}
3528
3529/*!
3530 \since 4.1
3531
3532 Marks the given \a region as dirty and schedules it to be updated.
3533 You only need to call this function if you are implementing
3534 your own view subclass.
3535
3536 \sa scrollDirtyRegion(), dirtyRegionOffset()
3537*/
3538
3539void QAbstractItemView::setDirtyRegion(const QRegion &region)
3540{
3541 Q_D(QAbstractItemView);
3542 d->setDirtyRegion(region);
3543}
3544
3545/*!
3546 Prepares the view for scrolling by (\a{dx},\a{dy}) pixels by moving the dirty regions in the
3547 opposite direction. You only need to call this function if you are implementing a scrolling
3548 viewport in your view subclass.
3549
3550 If you implement scrollContentsBy() in a subclass of QAbstractItemView, call this function
3551 before you call QWidget::scroll() on the viewport. Alternatively, just call update().
3552
3553 \sa scrollContentsBy(), dirtyRegionOffset(), setDirtyRegion()
3554*/
3555void QAbstractItemView::scrollDirtyRegion(int dx, int dy)
3556{
3557 Q_D(QAbstractItemView);
3558 d->scrollDirtyRegion(dx, dy);
3559}
3560
3561/*!
3562 Returns the offset of the dirty regions in the view.
3563
3564 If you use scrollDirtyRegion() and implement a paintEvent() in a subclass of
3565 QAbstractItemView, you should translate the area given by the paint event with
3566 the offset returned from this function.
3567
3568 \sa scrollDirtyRegion(), setDirtyRegion()
3569*/
3570QPoint QAbstractItemView::dirtyRegionOffset() const
3571{
3572 Q_D(const QAbstractItemView);
3573 return d->scrollDelayOffset;
3574}
3575
3576/*!
3577 \internal
3578*/
3579void QAbstractItemView::startAutoScroll()
3580{
3581 d_func()->startAutoScroll();
3582}
3583
3584/*!
3585 \internal
3586*/
3587void QAbstractItemView::stopAutoScroll()
3588{
3589 d_func()->stopAutoScroll();
3590}
3591
3592/*!
3593 \internal
3594*/
3595void QAbstractItemView::doAutoScroll()
3596{
3597 // find how much we should scroll with
3598 Q_D(QAbstractItemView);
3599 int verticalStep = verticalScrollBar()->pageStep();
3600 int horizontalStep = horizontalScrollBar()->pageStep();
3601 if (d->autoScrollCount < qMax(verticalStep, horizontalStep))
3602 ++d->autoScrollCount;
3603
3604 int margin = d->autoScrollMargin;
3605 int verticalValue = verticalScrollBar()->value();
3606 int horizontalValue = horizontalScrollBar()->value();
3607
3608 QPoint pos = d->viewport->mapFromGlobal(QCursor::pos());
3609 QRect area = static_cast<QAbstractItemView*>(d->viewport)->d_func()->clipRect(); // access QWidget private by bending C++ rules
3610
3611 // do the scrolling if we are in the scroll margins
3612 if (pos.y() - area.top() < margin)
3613 verticalScrollBar()->setValue(verticalValue - d->autoScrollCount);
3614 else if (area.bottom() - pos.y() < margin)
3615 verticalScrollBar()->setValue(verticalValue + d->autoScrollCount);
3616 if (pos.x() - area.left() < margin)
3617 horizontalScrollBar()->setValue(horizontalValue - d->autoScrollCount);
3618 else if (area.right() - pos.x() < margin)
3619 horizontalScrollBar()->setValue(horizontalValue + d->autoScrollCount);
3620 // if nothing changed, stop scrolling
3621 bool verticalUnchanged = (verticalValue == verticalScrollBar()->value());
3622 bool horizontalUnchanged = (horizontalValue == horizontalScrollBar()->value());
3623 if (verticalUnchanged && horizontalUnchanged) {
3624 stopAutoScroll();
3625 } else {
3626#ifndef QT_NO_DRAGANDDROP
3627 d->dropIndicatorRect = QRect();
3628 d->dropIndicatorPosition = QAbstractItemView::OnViewport;
3629#endif
3630 d->viewport->update();
3631 }
3632}
3633
3634/*!
3635 Returns the SelectionFlags to be used when updating a selection with
3636 to include the \a index specified. The \a event is a user input event,
3637 such as a mouse or keyboard event.
3638
3639 Reimplement this function to define your own selection behavior.
3640
3641 \sa setSelection()
3642*/
3643QItemSelectionModel::SelectionFlags QAbstractItemView::selectionCommand(const QModelIndex &index,
3644 const QEvent *event) const
3645{
3646 Q_D(const QAbstractItemView);
3647 switch (d->selectionMode) {
3648 case NoSelection: // Never update selection model
3649 return QItemSelectionModel::NoUpdate;
3650 case SingleSelection: // ClearAndSelect on valid index otherwise NoUpdate
3651 if (event && event->type() == QEvent::MouseButtonRelease)
3652 return QItemSelectionModel::NoUpdate;
3653 return QItemSelectionModel::ClearAndSelect|d->selectionBehaviorFlags();
3654 case MultiSelection:
3655 return d->multiSelectionCommand(index, event);
3656 case ExtendedSelection:
3657 return d->extendedSelectionCommand(index, event);
3658 case ContiguousSelection:
3659 return d->contiguousSelectionCommand(index, event);
3660 }
3661 return QItemSelectionModel::NoUpdate;
3662}
3663
3664QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::multiSelectionCommand(
3665 const QModelIndex &index, const QEvent *event) const
3666{
3667 Q_UNUSED(index);
3668
3669 if (event) {
3670 switch (event->type()) {
3671 case QEvent::KeyPress:
3672 if (static_cast<const QKeyEvent*>(event)->key() == Qt::Key_Space
3673 || static_cast<const QKeyEvent*>(event)->key() == Qt::Key_Select)
3674 return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3675 break;
3676 case QEvent::MouseButtonPress:
3677 if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton)
3678 return QItemSelectionModel::Toggle|selectionBehaviorFlags(); // toggle
3679 break;
3680 case QEvent::MouseButtonRelease:
3681 if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton)
3682 return QItemSelectionModel::NoUpdate|selectionBehaviorFlags(); // finalize
3683 break;
3684 case QEvent::MouseMove:
3685 if (static_cast<const QMouseEvent*>(event)->buttons() & Qt::LeftButton)
3686 return QItemSelectionModel::ToggleCurrent|selectionBehaviorFlags(); // toggle drag select
3687 default:
3688 break;
3689 }
3690 return QItemSelectionModel::NoUpdate;
3691 }
3692
3693 return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3694}
3695
3696QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionCommand(
3697 const QModelIndex &index, const QEvent *event) const
3698{
3699 Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
3700 if (event) {
3701 switch (event->type()) {
3702 case QEvent::MouseMove: {
3703 // Toggle on MouseMove
3704 modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
3705 if (modifiers & Qt::ControlModifier)
3706 return QItemSelectionModel::ToggleCurrent|selectionBehaviorFlags();
3707 break;
3708 }
3709 case QEvent::MouseButtonPress: {
3710 modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
3711 const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
3712 const bool rightButtonPressed = button & Qt::RightButton;
3713 const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
3714 const bool controlKeyPressed = modifiers & Qt::ControlModifier;
3715 const bool indexIsSelected = selectionModel->isSelected(index);
3716 if ((shiftKeyPressed || controlKeyPressed) && rightButtonPressed)
3717 return QItemSelectionModel::NoUpdate;
3718 if (!shiftKeyPressed && !controlKeyPressed && indexIsSelected)
3719 return QItemSelectionModel::NoUpdate;
3720 if (!index.isValid() && !rightButtonPressed && !shiftKeyPressed && !controlKeyPressed)
3721 return QItemSelectionModel::Clear;
3722 if (!index.isValid())
3723 return QItemSelectionModel::NoUpdate;
3724 break;
3725 }
3726 case QEvent::MouseButtonRelease: {
3727 // ClearAndSelect on MouseButtonRelease if MouseButtonPress on selected item or empty area
3728 modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
3729 const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
3730 const bool rightButtonPressed = button & Qt::RightButton;
3731 const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
3732 const bool controlKeyPressed = modifiers & Qt::ControlModifier;
3733 if (((index == pressedIndex && selectionModel->isSelected(index))
3734 || !index.isValid()) && state != QAbstractItemView::DragSelectingState
3735 && !shiftKeyPressed && !controlKeyPressed && (!rightButtonPressed || !index.isValid()))
3736 return QItemSelectionModel::ClearAndSelect|selectionBehaviorFlags();
3737 return QItemSelectionModel::NoUpdate;
3738 }
3739 case QEvent::KeyPress: {
3740 // NoUpdate on Key movement and Ctrl
3741 modifiers = static_cast<const QKeyEvent*>(event)->modifiers();
3742 switch (static_cast<const QKeyEvent*>(event)->key()) {
3743 case Qt::Key_Backtab:
3744 modifiers = modifiers & ~Qt::ShiftModifier; // special case for backtab
3745 case Qt::Key_Down:
3746 case Qt::Key_Up:
3747 case Qt::Key_Left:
3748 case Qt::Key_Right:
3749 case Qt::Key_Home:
3750 case Qt::Key_End:
3751 case Qt::Key_PageUp:
3752 case Qt::Key_PageDown:
3753 case Qt::Key_Tab:
3754 if (modifiers & Qt::ControlModifier
3755#ifdef QT_KEYPAD_NAVIGATION
3756 // Preserve historical tab order navigation behavior
3757 || QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
3758#endif
3759 )
3760 return QItemSelectionModel::NoUpdate;
3761 break;
3762 case Qt::Key_Select:
3763 return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3764 case Qt::Key_Space:// Toggle on Ctrl-Qt::Key_Space, Select on Space
3765 if (modifiers & Qt::ControlModifier)
3766 return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3767 return QItemSelectionModel::Select|selectionBehaviorFlags();
3768 default:
3769 break;
3770 }
3771 }
3772 default:
3773 break;
3774 }
3775 }
3776
3777 if (modifiers & Qt::ShiftModifier)
3778 return QItemSelectionModel::SelectCurrent|selectionBehaviorFlags();
3779 if (modifiers & Qt::ControlModifier)
3780 return QItemSelectionModel::Toggle|selectionBehaviorFlags();
3781 if (state == QAbstractItemView::DragSelectingState) {
3782 //when drag-selecting we need to clear any previous selection and select the current one
3783 return QItemSelectionModel::Clear|QItemSelectionModel::SelectCurrent|selectionBehaviorFlags();
3784 }
3785
3786 return QItemSelectionModel::ClearAndSelect|selectionBehaviorFlags();
3787}
3788
3789QItemSelectionModel::SelectionFlags
3790QAbstractItemViewPrivate::contiguousSelectionCommand(const QModelIndex &index,
3791 const QEvent *event) const
3792{
3793 QItemSelectionModel::SelectionFlags flags = extendedSelectionCommand(index, event);
3794 const int Mask = QItemSelectionModel::Clear | QItemSelectionModel::Select
3795 | QItemSelectionModel::Deselect | QItemSelectionModel::Toggle
3796 | QItemSelectionModel::Current;
3797
3798 switch (flags & Mask) {
3799 case QItemSelectionModel::Clear:
3800 case QItemSelectionModel::ClearAndSelect:
3801 case QItemSelectionModel::SelectCurrent:
3802 return flags;
3803 case QItemSelectionModel::NoUpdate:
3804 if (event &&
3805 (event->type() == QEvent::MouseButtonPress
3806 || event->type() == QEvent::MouseButtonRelease))
3807 return flags;
3808 return QItemSelectionModel::ClearAndSelect|selectionBehaviorFlags();
3809 default:
3810 return QItemSelectionModel::SelectCurrent|selectionBehaviorFlags();
3811 }
3812}
3813
3814void QAbstractItemViewPrivate::fetchMore()
3815{
3816 fetchMoreTimer.stop();
3817 if (!model->canFetchMore(root))
3818 return;
3819 int last = model->rowCount(root) - 1;
3820 if (last < 0) {
3821 model->fetchMore(root);
3822 return;
3823 }
3824
3825 QModelIndex index = model->index(last, 0, root);
3826 QRect rect = q_func()->visualRect(index);
3827 if (viewport->rect().intersects(rect))
3828 model->fetchMore(root);
3829}
3830
3831bool QAbstractItemViewPrivate::shouldEdit(QAbstractItemView::EditTrigger trigger,
3832 const QModelIndex &index) const
3833{
3834 if (!index.isValid())
3835 return false;
3836 Qt::ItemFlags flags = model->flags(index);
3837 if (((flags & Qt::ItemIsEditable) == 0) || ((flags & Qt::ItemIsEnabled) == 0))
3838 return false;
3839 if (state == QAbstractItemView::EditingState)
3840 return false;
3841 if (hasEditor(index))
3842 return false;
3843 if (trigger == QAbstractItemView::AllEditTriggers) // force editing
3844 return true;
3845 if ((trigger & editTriggers) == QAbstractItemView::SelectedClicked
3846 && !selectionModel->isSelected(index))
3847 return false;
3848 return (trigger & editTriggers);
3849}
3850
3851bool QAbstractItemViewPrivate::shouldForwardEvent(QAbstractItemView::EditTrigger trigger,
3852 const QEvent *event) const
3853{
3854 if (!event || (trigger & editTriggers) != QAbstractItemView::AnyKeyPressed)
3855 return false;
3856
3857 switch (event->type()) {
3858 case QEvent::KeyPress:
3859 case QEvent::MouseButtonDblClick:
3860 case QEvent::MouseButtonPress:
3861 case QEvent::MouseButtonRelease:
3862 case QEvent::MouseMove:
3863 return true;
3864 default:
3865 break;
3866 };
3867
3868 return false;
3869}
3870
3871bool QAbstractItemViewPrivate::shouldAutoScroll(const QPoint &pos) const
3872{
3873 if (!autoScroll)
3874 return false;
3875 QRect area = static_cast<QAbstractItemView*>(viewport)->d_func()->clipRect(); // access QWidget private by bending C++ rules
3876 return (pos.y() - area.top() < autoScrollMargin)
3877 || (area.bottom() - pos.y() < autoScrollMargin)
3878 || (pos.x() - area.left() < autoScrollMargin)
3879 || (area.right() - pos.x() < autoScrollMargin);
3880}
3881
3882void QAbstractItemViewPrivate::doDelayedItemsLayout(int delay)
3883{
3884 if (!delayedPendingLayout) {
3885 delayedPendingLayout = true;
3886 delayedLayout.start(delay, q_func());
3887 }
3888}
3889
3890void QAbstractItemViewPrivate::interruptDelayedItemsLayout() const
3891{
3892 delayedLayout.stop();
3893 delayedPendingLayout = false;
3894}
3895
3896
3897
3898QWidget *QAbstractItemViewPrivate::editor(const QModelIndex &index,
3899 const QStyleOptionViewItem &options)
3900{
3901 Q_Q(QAbstractItemView);
3902 QWidget *w = editorForIndex(index).editor;
3903 if (!w) {
3904 QAbstractItemDelegate *delegate = delegateForIndex(index);
3905 if (!delegate)
3906 return 0;
3907 w = delegate->createEditor(viewport, options, index);
3908 if (w) {
3909 w->installEventFilter(delegate);
3910 QObject::connect(w, SIGNAL(destroyed(QObject*)), q, SLOT(editorDestroyed(QObject*)));
3911 delegate->updateEditorGeometry(w, options, index);
3912 delegate->setEditorData(w, index);
3913 addEditor(index, w, false);
3914 if (w->parent() == viewport)
3915 QWidget::setTabOrder(q, w);
3916
3917 // Special cases for some editors containing QLineEdit
3918 QWidget *focusWidget = w;
3919 while (QWidget *fp = focusWidget->focusProxy())
3920 focusWidget = fp;
3921#ifndef QT_NO_LINEEDIT
3922 if (QLineEdit *le = qobject_cast<QLineEdit*>(focusWidget))
3923 le->selectAll();
3924#endif
3925#ifndef QT_NO_SPINBOX
3926 if (QSpinBox *sb = qobject_cast<QSpinBox*>(focusWidget))
3927 sb->selectAll();
3928 else if (QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox*>(focusWidget))
3929 dsb->selectAll();
3930#endif
3931 }
3932 }
3933 return w;
3934}
3935
3936void QAbstractItemViewPrivate::updateEditorData(const QModelIndex &tl, const QModelIndex &br)
3937{
3938 // we are counting on having relatively few editors
3939 const bool checkIndexes = tl.isValid() && br.isValid();
3940 const QModelIndex parent = tl.parent();
3941 QList<QEditorInfo>::const_iterator it = editors.constBegin();
3942 for (; it != editors.constEnd(); ++it) {
3943 QWidget *editor = it->editor;
3944 const QModelIndex index = it->index;
3945 if (it->isStatic || editor == 0 || !index.isValid() ||
3946 (checkIndexes
3947 && (index.row() < tl.row() || index.row() > br.row()
3948 || index.column() < tl.column() || index.column() > br.column()
3949 || index.parent() != parent)))
3950 continue;
3951
3952 QAbstractItemDelegate *delegate = delegateForIndex(index);
3953 if (delegate) {
3954 delegate->setEditorData(editor, index);
3955 }
3956 }
3957}
3958
3959/*!
3960 \internal
3961
3962 In DND if something has been moved then this is called.
3963 Typically this means you should "remove" the selected item or row,
3964 but the behavior is view dependant (table just clears the selected indexes for example).
3965
3966 Either remove the selected rows or clear them
3967*/
3968void QAbstractItemViewPrivate::clearOrRemove()
3969{
3970#ifndef QT_NO_DRAGANDDROP
3971 const QItemSelection selection = selectionModel->selection();
3972 QList<QItemSelectionRange>::const_iterator it = selection.constBegin();
3973
3974 if (!overwrite) {
3975 for (; it != selection.constEnd(); ++it) {
3976 QModelIndex parent = (*it).parent();
3977 if ((*it).left() != 0)
3978 continue;
3979 if ((*it).right() != (model->columnCount(parent) - 1))
3980 continue;
3981 int count = (*it).bottom() - (*it).top() + 1;
3982 model->removeRows((*it).top(), count, parent);
3983 }
3984 } else {
3985 // we can't remove the rows so reset the items (i.e. the view is like a table)
3986 QModelIndexList list = selection.indexes();
3987 for (int i=0; i < list.size(); ++i) {
3988 QModelIndex index = list.at(i);
3989 QMap<int, QVariant> roles = model->itemData(index);
3990 for (QMap<int, QVariant>::Iterator it = roles.begin(); it != roles.end(); ++it)
3991 it.value() = QVariant();
3992 model->setItemData(index, roles);
3993 }
3994 }
3995#endif
3996}
3997
3998/*!
3999 \internal
4000
4001 When persistent aeditor gets/loses focus, we need to check
4002 and setcorrectly the current index.
4003*/
4004void QAbstractItemViewPrivate::checkPersistentEditorFocus()
4005{
4006 Q_Q(QAbstractItemView);
4007 if (QWidget *widget = QApplication::focusWidget()) {
4008 if (persistent.contains(widget)) {
4009 //a persistent editor has gained the focus
4010 QModelIndex index = indexForEditor(widget);
4011 if (selectionModel->currentIndex() != index)
4012 q->setCurrentIndex(index);
4013 }
4014 }
4015}
4016
4017
4018QEditorInfo QAbstractItemViewPrivate::editorForIndex(const QModelIndex &index) const
4019{
4020 QList<QEditorInfo>::const_iterator it = editors.constBegin();
4021 for (; it != editors.constEnd(); ++it) {
4022 if (it->index == index)
4023 return *it;
4024 }
4025
4026 return QEditorInfo();
4027}
4028
4029QModelIndex QAbstractItemViewPrivate::indexForEditor(QWidget *editor) const
4030{
4031 QList<QEditorInfo>::const_iterator it = editors.constBegin();
4032 for (; it != editors.constEnd(); ++it) {
4033 if (it->editor == editor)
4034 return it->index;
4035 }
4036 return QModelIndex();
4037}
4038
4039void QAbstractItemViewPrivate::removeEditor(QWidget *editor)
4040{
4041 QList<QEditorInfo>::iterator it = editors.begin();
4042 for (; it != editors.end(); ) {
4043 if (it->editor == editor)
4044 it = editors.erase(it);
4045 else
4046 ++it;
4047 }
4048}
4049
4050void QAbstractItemViewPrivate::addEditor(const QModelIndex &index, QWidget *editor, bool isStatic)
4051{
4052 editors.append(QEditorInfo(index, editor, isStatic));
4053}
4054
4055bool QAbstractItemViewPrivate::sendDelegateEvent(const QModelIndex &index, QEvent *event) const
4056{
4057 Q_Q(const QAbstractItemView);
4058 QModelIndex buddy = model->buddy(index);
4059 QStyleOptionViewItemV4 options = viewOptionsV4();
4060 options.rect = q->visualRect(buddy);
4061 options.state |= (buddy == q->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
4062 QAbstractItemDelegate *delegate = delegateForIndex(index);
4063 return (event && delegate && delegate->editorEvent(event, model, options, buddy));
4064}
4065
4066bool QAbstractItemViewPrivate::openEditor(const QModelIndex &index, QEvent *event)
4067{
4068 Q_Q(QAbstractItemView);
4069
4070 QModelIndex buddy = model->buddy(index);
4071 QStyleOptionViewItemV4 options = viewOptionsV4();
4072 options.rect = q->visualRect(buddy);
4073 options.state |= (buddy == q->currentIndex() ? QStyle::State_HasFocus : QStyle::State_None);
4074
4075 QWidget *w = editor(buddy, options);
4076 if (!w)
4077 return false;
4078
4079 if (event)
4080 QApplication::sendEvent(w->focusProxy() ? w->focusProxy() : w, event);
4081
4082 q->setState(QAbstractItemView::EditingState);
4083 w->show();
4084 w->setFocus();
4085
4086 return true;
4087}
4088
4089/*
4090 \internal
4091
4092 returns the pair QRect/QModelIndex that should be painted on the viewports's rect
4093*/
4094
4095QItemViewPaintPairs QAbstractItemViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
4096{
4097 Q_ASSERT(r);
4098 Q_Q(const QAbstractItemView);
4099 QRect &rect = *r;
4100 const QRect viewportRect = viewport->rect();
4101 QItemViewPaintPairs ret;
4102 for (int i = 0; i < indexes.count(); ++i) {
4103 const QModelIndex &index = indexes.at(i);
4104 const QRect current = q->visualRect(index);
4105 if (current.intersects(viewportRect)) {
4106 ret += qMakePair(current, index);
4107 rect |= current;
4108 }
4109 }
4110 rect &= viewportRect;
4111 return ret;
4112}
4113
4114QPixmap QAbstractItemViewPrivate::renderToPixmap(const QModelIndexList &indexes, QRect *r) const
4115{
4116 Q_ASSERT(r);
4117 QItemViewPaintPairs paintPairs = draggablePaintPairs(indexes, r);
4118 if (paintPairs.isEmpty())
4119 return QPixmap();
4120 QPixmap pixmap(r->size());
4121 pixmap.fill(Qt::transparent);
4122 QPainter painter(&pixmap);
4123 QStyleOptionViewItemV4 option = viewOptionsV4();
4124 option.state |= QStyle::State_Selected;
4125 for (int j = 0; j < paintPairs.count(); ++j) {
4126 option.rect = paintPairs.at(j).first.translated(-r->topLeft());
4127 const QModelIndex &current = paintPairs.at(j).second;
4128 delegateForIndex(current)->paint(&painter, option, current);
4129 }
4130 return pixmap;
4131}
4132
4133void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
4134{
4135 if (!selectionModel)
4136 return;
4137
4138 QItemSelection selection;
4139 QModelIndex tl = model->index(0, 0, root);
4140 QModelIndex br = model->index(model->rowCount(root) - 1,
4141 model->columnCount(root) - 1,
4142 root);
4143 selection.append(QItemSelectionRange(tl, br));
4144 selectionModel->select(selection, command);
4145}
4146
4147QModelIndexList QAbstractItemViewPrivate::selectedDraggableIndexes() const
4148{
4149 Q_Q(const QAbstractItemView);
4150 QModelIndexList indexes = q->selectedIndexes();
4151 for(int i = indexes.count() - 1 ; i >= 0; --i) {
4152 if (!isIndexDragEnabled(indexes.at(i)))
4153 indexes.removeAt(i);
4154 }
4155 return indexes;
4156}
4157
4158
4159QT_END_NAMESPACE
4160
4161#include "moc_qabstractitemview.cpp"
4162
4163#endif // QT_NO_ITEMVIEWS
Note: See TracBrowser for help on using the repository browser.