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

Last change on this file since 123 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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