diff options
Diffstat (limited to 'src/widgets/itemviews/qabstractitemview.cpp')
-rw-r--r-- | src/widgets/itemviews/qabstractitemview.cpp | 660 |
1 files changed, 392 insertions, 268 deletions
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 43919a2efb..85e478a71e 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qabstractitemview.h" @@ -66,7 +30,7 @@ #include <private/qapplication_p.h> #include <private/qguiapplication_p.h> #include <private/qscrollbar_p.h> -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) #include <qaccessible.h> #endif #if QT_CONFIG(gestures) && QT_CONFIG(scroller) @@ -138,15 +102,16 @@ void QAbstractItemViewPrivate::init() vbar->setRange(0, 0); hbar->setRange(0, 0); - QObject::connect(vbar, SIGNAL(actionTriggered(int)), - q, SLOT(verticalScrollbarAction(int))); - QObject::connect(hbar, SIGNAL(actionTriggered(int)), - q, SLOT(horizontalScrollbarAction(int))); - QObject::connect(vbar, SIGNAL(valueChanged(int)), - q, SLOT(verticalScrollbarValueChanged(int))); - QObject::connect(hbar, SIGNAL(valueChanged(int)), - q, SLOT(horizontalScrollbarValueChanged(int))); - + scrollbarConnections = { + QObject::connect(vbar, &QScrollBar::actionTriggered, + q, &QAbstractItemView::verticalScrollbarAction), + QObject::connect(hbar, &QScrollBar::actionTriggered, + q, &QAbstractItemView::horizontalScrollbarAction), + QObject::connect(vbar, &QScrollBar::valueChanged, + q, &QAbstractItemView::verticalScrollbarValueChanged), + QObject::connect(hbar, &QScrollBar::valueChanged, + q, &QAbstractItemView::horizontalScrollbarValueChanged) + }; viewport->setBackgroundRole(QPalette::Base); q->setAttribute(Qt::WA_InputMethodEnabled); @@ -165,8 +130,8 @@ void QAbstractItemViewPrivate::setHoverIndex(const QPersistentModelIndex &index) q->update(hover); //update the old one q->update(index); //update the new one } else { - QRect oldHoverRect = q->visualRect(hover); - QRect newHoverRect = q->visualRect(index); + const QRect oldHoverRect = visualRect(hover); + const QRect newHoverRect = visualRect(index); viewport->update(QRect(0, newHoverRect.y(), viewport->width(), newHoverRect.height())); viewport->update(QRect(0, oldHoverRect.y(), viewport->width(), oldHoverRect.height())); } @@ -208,7 +173,7 @@ void QAbstractItemViewPrivate::checkMouseMove(const QPersistentModelIndex &index #if QT_CONFIG(gestures) && QT_CONFIG(scroller) // stores and restores the selection and current item when flicking -void QAbstractItemViewPrivate::_q_scrollerStateChanged() +void QAbstractItemViewPrivate::scrollerStateChanged() { Q_Q(QAbstractItemView); @@ -244,6 +209,73 @@ void QAbstractItemViewPrivate::_q_scrollerStateChanged() #endif // QT_NO_GESTURES +void QAbstractItemViewPrivate::delegateSizeHintChanged(const QModelIndex &index) +{ + Q_Q(QAbstractItemView); + if (model) { + if (!model->checkIndex(index)) + qWarning("Delegate size hint changed for a model index that does not belong to this view"); + } + QMetaObject::invokeMethod(q, &QAbstractItemView::doItemsLayout, Qt::QueuedConnection); +} + +void QAbstractItemViewPrivate::connectDelegate(QAbstractItemDelegate *delegate) +{ + if (!delegate) + return; + Q_Q(QAbstractItemView); + QObject::connect(delegate, &QAbstractItemDelegate::closeEditor, + q, &QAbstractItemView::closeEditor); + QObject::connect(delegate, &QAbstractItemDelegate::commitData, + q, &QAbstractItemView::commitData); + QObjectPrivate::connect(delegate, &QAbstractItemDelegate::sizeHintChanged, + this, &QAbstractItemViewPrivate::delegateSizeHintChanged); +} + +void QAbstractItemViewPrivate::disconnectDelegate(QAbstractItemDelegate *delegate) +{ + if (!delegate) + return; + Q_Q(QAbstractItemView); + QObject::disconnect(delegate, &QAbstractItemDelegate::closeEditor, + q, &QAbstractItemView::closeEditor); + QObject::disconnect(delegate, &QAbstractItemDelegate::commitData, + q, &QAbstractItemView::commitData); + QObjectPrivate::disconnect(delegate, &QAbstractItemDelegate::sizeHintChanged, + this, &QAbstractItemViewPrivate::delegateSizeHintChanged); +} + +void QAbstractItemViewPrivate::disconnectAll() +{ + Q_Q(QAbstractItemView); + for (const QMetaObject::Connection &connection : modelConnections) + QObject::disconnect(connection); + for (const QMetaObject::Connection &connection : scrollbarConnections) + QObject::disconnect(connection); + disconnectDelegate(itemDelegate); + for (QAbstractItemDelegate *delegate : std::as_const(rowDelegates)) + disconnectDelegate(delegate); + for (QAbstractItemDelegate *delegate : std::as_const(columnDelegates)) + disconnectDelegate(delegate); + if (model && selectionModel) { + QObject::disconnect(model, &QAbstractItemModel::destroyed, + selectionModel, &QItemSelectionModel::deleteLater); + } + if (selectionModel) { + QObject::disconnect(selectionModel, &QItemSelectionModel::selectionChanged, + q, &QAbstractItemView::selectionChanged); + QObject::disconnect(selectionModel, &QItemSelectionModel::currentChanged, + q, &QAbstractItemView::currentChanged); + } + for (const auto &info : std::as_const(indexEditorHash)) { + if (!info.isStatic && info.widget) + QObject::disconnect(info.widget, &QWidget::destroyed, q, &QAbstractItemView::editorDestroyed); + } +#if QT_CONFIG(gestures) && QT_CONFIG(scroller) + QObject::disconnect(scollerConnection); +#endif +} + /*! \class QAbstractItemView @@ -344,7 +376,7 @@ void QAbstractItemViewPrivate::_q_scrollerStateChanged() \l{QWidget::update()}{update()} as all painting operations take place on the viewport. - \sa {View Classes}, {Model/View Programming}, QAbstractItemModel, {Chart Example} + \sa {View Classes}, {Model/View Programming}, QAbstractItemModel */ /*! @@ -657,6 +689,7 @@ QAbstractItemView::~QAbstractItemView() d->autoScrollTimer.stop(); d->delayedLayout.stop(); d->fetchMoreTimer.stop(); + d->disconnectAll(); } /*! @@ -685,68 +718,47 @@ void QAbstractItemView::setModel(QAbstractItemModel *model) if (model == d->model) return; if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) { - disconnect(d->model, SIGNAL(destroyed()), - this, SLOT(_q_modelDestroyed())); - disconnect(d->model, SIGNAL(dataChanged(QModelIndex, QModelIndex, QList<int>)), this, - SLOT(dataChanged(QModelIndex, QModelIndex, QList<int>))); - disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), - this, SLOT(_q_headerDataChanged())); - disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(rowsInserted(QModelIndex,int,int))); - disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); - disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); - disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); - disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(_q_rowsInserted(QModelIndex,int,int))); - disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int))); - disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)), - this, SLOT(_q_columnsRemoved(QModelIndex,int,int))); - disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)), - this, SLOT(_q_columnsInserted(QModelIndex,int,int))); - disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int))); - - disconnect(d->model, SIGNAL(modelReset()), this, SLOT(reset())); - disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged())); + for (const QMetaObject::Connection &connection : d->modelConnections) + disconnect(connection); } d->model = (model ? model : QAbstractItemModelPrivate::staticEmptyModel()); if (d->model != QAbstractItemModelPrivate::staticEmptyModel()) { - connect(d->model, SIGNAL(destroyed()), - this, SLOT(_q_modelDestroyed())); - connect(d->model, SIGNAL(dataChanged(QModelIndex, QModelIndex, QList<int>)), this, - SLOT(dataChanged(QModelIndex, QModelIndex, QList<int>))); - connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), - this, SLOT(_q_headerDataChanged())); - connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(rowsInserted(QModelIndex,int,int))); - connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(_q_rowsInserted(QModelIndex,int,int))); - connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); - connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)), - this, SLOT(_q_columnsRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)), - this, SLOT(_q_columnsInserted(QModelIndex,int,int))); - connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int))); - - connect(d->model, SIGNAL(modelReset()), this, SLOT(reset())); - connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged())); + d->modelConnections = { + QObjectPrivate::connect(d->model, &QAbstractItemModel::destroyed, + d, &QAbstractItemViewPrivate::modelDestroyed), + QObject::connect(d->model, &QAbstractItemModel::dataChanged, + this, &QAbstractItemView::dataChanged), + QObjectPrivate::connect(d->model, &QAbstractItemModel::headerDataChanged, + d, &QAbstractItemViewPrivate::headerDataChanged), + QObject::connect(d->model, &QAbstractItemModel::rowsInserted, + this, &QAbstractItemView::rowsInserted), + QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsInserted, + d, &QAbstractItemViewPrivate::rowsInserted), + QObject::connect(d->model, &QAbstractItemModel::rowsAboutToBeRemoved, + this, &QAbstractItemView::rowsAboutToBeRemoved), + QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsRemoved, + d, &QAbstractItemViewPrivate::rowsRemoved), + QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsMoved, + d, &QAbstractItemViewPrivate::rowsMoved), + QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeRemoved, + d, &QAbstractItemViewPrivate::columnsAboutToBeRemoved), + QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsRemoved, + d, &QAbstractItemViewPrivate::columnsRemoved), + QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsInserted, + d, &QAbstractItemViewPrivate::columnsInserted), + QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsMoved, + d, &QAbstractItemViewPrivate::columnsMoved), + QObject::connect(d->model, &QAbstractItemModel::modelReset, + this, &QAbstractItemView::reset), + QObjectPrivate::connect(d->model, &QAbstractItemModel::layoutChanged, + d, &QAbstractItemViewPrivate::layoutChanged), + }; } QItemSelectionModel *selection_model = new QItemSelectionModel(d->model, this); - connect(d->model, SIGNAL(destroyed()), selection_model, SLOT(deleteLater())); + connect(d->model, &QAbstractItemModel::destroyed, + selection_model, &QItemSelectionModel::deleteLater); setSelectionModel(selection_model); reset(); // kill editors, set new root and do layout @@ -796,20 +808,19 @@ void QAbstractItemView::setSelectionModel(QItemSelectionModel *selectionModel) oldSelection = d->selectionModel->selection(); oldCurrentIndex = d->selectionModel->currentIndex(); } - - disconnect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(selectionChanged(QItemSelection,QItemSelection))); - disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(currentChanged(QModelIndex,QModelIndex))); + disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged, + this, &QAbstractItemView::selectionChanged); + disconnect(d->selectionModel, &QItemSelectionModel::currentChanged, + this, &QAbstractItemView::currentChanged); } d->selectionModel = selectionModel; if (d->selectionModel) { - connect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(selectionChanged(QItemSelection,QItemSelection))); - connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(currentChanged(QModelIndex,QModelIndex))); + connect(d->selectionModel, &QItemSelectionModel::selectionChanged, + this, &QAbstractItemView::selectionChanged); + connect(d->selectionModel, &QItemSelectionModel::currentChanged, + this, &QAbstractItemView::currentChanged); selectionChanged(d->selectionModel->selection(), oldSelection); currentChanged(d->selectionModel->currentIndex(), oldCurrentIndex); @@ -849,21 +860,13 @@ void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *delegate) return; if (d->itemDelegate) { - if (d->delegateRefCount(d->itemDelegate) == 1) { - disconnect(d->itemDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), - this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); - disconnect(d->itemDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*))); - disconnect(d->itemDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout())); - } + if (d->delegateRefCount(d->itemDelegate) == 1) + d->disconnectDelegate(delegate); } if (delegate) { - if (d->delegateRefCount(delegate) == 0) { - connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), - this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); - connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*))); - connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()), Qt::QueuedConnection); - } + if (d->delegateRefCount(delegate) == 0) + d->connectDelegate(delegate); } d->itemDelegate = delegate; viewport()->update(); @@ -933,21 +936,13 @@ void QAbstractItemView::setItemDelegateForRow(int row, QAbstractItemDelegate *de { Q_D(QAbstractItemView); if (QAbstractItemDelegate *rowDelegate = d->rowDelegates.value(row, nullptr)) { - if (d->delegateRefCount(rowDelegate) == 1) { - disconnect(rowDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), - this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); - disconnect(rowDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*))); - disconnect(rowDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout())); - } + if (d->delegateRefCount(rowDelegate) == 1) + d->disconnectDelegate(rowDelegate); d->rowDelegates.remove(row); } if (delegate) { - if (d->delegateRefCount(delegate) == 0) { - connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), - this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); - connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*))); - connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()), Qt::QueuedConnection); - } + if (d->delegateRefCount(delegate) == 0) + d->connectDelegate(delegate); d->rowDelegates.insert(row, delegate); } viewport()->update(); @@ -993,21 +988,13 @@ void QAbstractItemView::setItemDelegateForColumn(int column, QAbstractItemDelega { Q_D(QAbstractItemView); if (QAbstractItemDelegate *columnDelegate = d->columnDelegates.value(column, nullptr)) { - if (d->delegateRefCount(columnDelegate) == 1) { - disconnect(columnDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), - this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); - disconnect(columnDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*))); - disconnect(columnDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout())); - } + if (d->delegateRefCount(columnDelegate) == 1) + d->disconnectDelegate(columnDelegate); d->columnDelegates.remove(column); } if (delegate) { - if (d->delegateRefCount(delegate) == 0) { - connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), - this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); - connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*))); - connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(doItemsLayout()), Qt::QueuedConnection); - } + if (d->delegateRefCount(delegate) == 0) + d->connectDelegate(delegate); d->columnDelegates.insert(column, delegate); } viewport()->update(); @@ -1145,7 +1132,11 @@ void QAbstractItemView::reset() { Q_D(QAbstractItemView); d->delayedReset.stop(); //make sure we stop the timer - foreach (const QEditorInfo &info, d->indexEditorHash) { + // Taking a copy because releaseEditor() eventurally calls deleteLater() on the + // editor, which calls QCoreApplication::postEvent(), the latter may invoke unknown + // code that may modify d->indexEditorHash. + const auto copy = d->indexEditorHash; + for (const auto &[index, info] : copy.asKeyValueRange()) { if (info.widget) d->releaseEditor(info.widget.data(), d->indexForEditor(info.widget.data())); } @@ -1157,7 +1148,7 @@ void QAbstractItemView::reset() setRootIndex(QModelIndex()); if (d->selectionModel) d->selectionModel->reset(); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) if (QAccessible::isActive()) { QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::ModelReset); QAccessible::updateAccessibility(&accessibleEvent); @@ -1179,6 +1170,12 @@ void QAbstractItemView::setRootIndex(const QModelIndex &index) return; } d->root = index; +#if QT_CONFIG(accessibility) + if (QAccessible::isActive()) { + QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::ModelReset); + QAccessible::updateAccessibility(&accessibleEvent); + } +#endif d->doDelayedItemsLayout(); d->updateGeometry(); } @@ -1204,12 +1201,21 @@ QModelIndex QAbstractItemView::rootIndex() const void QAbstractItemView::selectAll() { Q_D(QAbstractItemView); - SelectionMode mode = d->selectionMode; - if (mode == MultiSelection || mode == ExtendedSelection) + const SelectionMode mode = d->selectionMode; + switch (mode) { + case MultiSelection: + case ExtendedSelection: d->selectAll(QItemSelectionModel::ClearAndSelect - |d->selectionBehaviorFlags()); - else if (mode != SingleSelection) - d->selectAll(selectionCommand(d->model->index(0, 0, d->root))); + | d->selectionBehaviorFlags()); + break; + case NoSelection: + case ContiguousSelection: + if (d->model->hasChildren(d->root)) + d->selectAll(selectionCommand(d->model->index(0, 0, d->root))); + break; + case SingleSelection: + break; + } } /*! @@ -1562,7 +1568,7 @@ QAbstractItemView::DragDropMode QAbstractItemView::dragDropMode() const /*! \property QAbstractItemView::defaultDropAction - \brief the drop action that will be used by default in QAbstractItemView::drag() + \brief the drop action that will be used by default in QAbstractItemView::drag(). If the property is not set, the drop action is CopyAction when the supported actions support CopyAction. @@ -1655,7 +1661,7 @@ Qt::TextElideMode QAbstractItemView::textElideMode() const bool QAbstractItemView::focusNextPrevChild(bool next) { Q_D(QAbstractItemView); - if (d->tabKeyNavigation && isEnabled() && d->viewport->isEnabled()) { + if (d->tabKeyNavigation && isVisible() && isEnabled() && d->viewport->isEnabled()) { QKeyEvent event(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier); keyPressEvent(&event); if (event.isAccepted()) @@ -1726,6 +1732,12 @@ bool QAbstractItemView::viewportEvent(QEvent *event) { Q_D(QAbstractItemView); switch (event->type()) { + case QEvent::Paint: + // Similar to pre-painting in QAbstractItemView::event to update scrollbar + // visibility, make sure that all pending layout requests have been executed + // so that the view's data structures are up-to-date before rendering. + d->executePostedLayout(); + break; case QEvent::HoverMove: case QEvent::HoverEnter: d->setHoverIndex(indexAt(static_cast<QHoverEvent*>(event)->position().toPoint())); @@ -1773,7 +1785,10 @@ bool QAbstractItemView::viewportEvent(QEvent *event) case QEvent::ScrollPrepare: executeDelayedItemsLayout(); #if QT_CONFIG(gestures) && QT_CONFIG(scroller) - connect(QScroller::scroller(d->viewport), SIGNAL(stateChanged(QScroller::State)), this, SLOT(_q_scrollerStateChanged()), Qt::UniqueConnection); + d->scollerConnection = QObjectPrivate::connect( + QScroller::scroller(d->viewport), &QScroller::stateChanged, + d, &QAbstractItemViewPrivate::scrollerStateChanged, + Qt::UniqueConnection); #endif break; @@ -1808,9 +1823,18 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid(); QPoint offset = d->offset(); - d->pressedPosition = d->draggedPosition = pos + offset; - if (!(command & QItemSelectionModel::Current)) + d->draggedPosition = pos + offset; + +#if QT_CONFIG(draganddrop) + // update the pressed position when drag was enable + if (d->dragEnabled) + d->pressedPosition = d->draggedPosition; +#endif + + if (!(command & QItemSelectionModel::Current)) { + d->pressedPosition = pos + offset; d->currentSelectionStartIndex = index; + } else if (!d->currentSelectionStartIndex.isValid()) d->currentSelectionStartIndex = currentIndex(); @@ -1830,7 +1854,7 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) command |= d->ctrlDragSelectionFlag; } - if ((command & QItemSelectionModel::Current) == 0) { + if (!(command & QItemSelectionModel::Current)) { setSelection(QRect(pos, QSize(1, 1)), command); } else { QRect rect(visualRect(d->currentSelectionStartIndex).center(), pos); @@ -1859,7 +1883,6 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) { Q_D(QAbstractItemView); - QPoint topLeft; QPoint bottomRight = event->position().toPoint(); d->draggedPosition = bottomRight + d->offset(); @@ -1869,13 +1892,7 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) #if QT_CONFIG(draganddrop) if (state() == DraggingState) { - topLeft = d->pressedPosition - d->offset(); - if ((topLeft - bottomRight).manhattanLength() > QApplication::startDragDistance()) { - d->pressedIndex = QModelIndex(); - startDrag(d->model->supportedDragActions()); - setState(NoState); // the startDrag will return when the dnd operation is done - stopAutoScroll(); - } + d->maybeStartDrag(bottomRight); return; } #endif // QT_CONFIG(draganddrop) @@ -1886,16 +1903,8 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) || edit(index, NoEditTriggers, event)) return; - if (d->selectionMode != SingleSelection) { - // Use the current selection start index if it is valid as this will be based on the - // start of the selection and not the last item being pressed which can be different - // when in extended selection - topLeft = d->currentSelectionStartIndex.isValid() - ? visualRect(d->currentSelectionStartIndex).center() - : d->pressedPosition - d->offset(); - } else { - topLeft = bottomRight; - } + const QPoint topLeft = + d->selectionMode != SingleSelection ? d->pressedPosition - d->offset() : bottomRight; d->checkMouseMove(index); @@ -1906,6 +1915,7 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) && (event->buttons() != Qt::NoButton) && !d->selectedDraggableIndexes().isEmpty()) { setState(DraggingState); + d->maybeStartDrag(bottomRight); return; } #endif @@ -1955,7 +1965,9 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) } bool click = (index == d->pressedIndex && index.isValid() && !releaseFromDoubleClick); - bool selectedClicked = click && (event->button() == Qt::LeftButton) && d->pressedAlreadySelected; + bool selectedClicked = click && d->pressedAlreadySelected + && (event->button() == Qt::LeftButton) + && (event->modifiers() == Qt::NoModifier); EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers); const bool edited = click && !d->pressClosedEditor ? edit(index, trigger, event) : false; @@ -1963,7 +1975,7 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) if (d->selectionModel && d->noSelectionOnMousePress) { d->noSelectionOnMousePress = false; - if (!edited && !d->pressClosedEditor) + if (!d->pressClosedEditor) d->selectionModel->select(index, selectionCommand(index, event)); } @@ -2382,11 +2394,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) #if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT) if (event == QKeySequence::Copy) { - QVariant variant; - if (d->model) - variant = d->model->data(currentIndex(), Qt::DisplayRole); - if (variant.canConvert<QString>()) - QGuiApplication::clipboard()->setText(variant.toString()); + const QModelIndex index = currentIndex(); + if (index.isValid() && d->model) { + const QVariant variant = d->model->data(index, Qt::DisplayRole); + if (variant.canConvert<QString>()) + QGuiApplication::clipboard()->setText(variant.toString()); + } event->accept(); } #endif @@ -2845,10 +2858,10 @@ void QAbstractItemView::updateEditorGeometries() //we hide and release the editor outside of the loop because it might change the focus and try //to change the editors hashes. - for (int i = 0; i < editorsToHide.count(); ++i) { + for (int i = 0; i < editorsToHide.size(); ++i) { editorsToHide.at(i)->hide(); } - for (int i = 0; i < editorsToRelease.count(); ++i) { + for (int i = 0; i < editorsToRelease.size(); ++i) { d->releaseEditor(editorsToRelease.at(i)); } } @@ -2923,39 +2936,50 @@ void QAbstractItemView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndE // Close the editor if (editor) { - bool isPersistent = d->persistent.contains(editor); - bool hadFocus = editor->hasFocus(); - QModelIndex index = d->indexForEditor(editor); - if (!index.isValid()) - return; // the editor was not registered - - // start a timer that expires immediately when we return to the event loop - // to identify whether this close was triggered by a mousepress-initiated - // focus event - d->pressClosedEditorWatcher.start(0, this); - d->lastEditedIndex = index; - - if (!isPersistent) { - setState(NoState); - QModelIndex index = d->indexForEditor(editor); - editor->removeEventFilter(itemDelegateForIndex(index)); - d->removeEditor(editor); - } - if (hadFocus) { - if (focusPolicy() != Qt::NoFocus) - setFocus(); // this will send a focusLost event to the editor - else - editor->clearFocus(); + const bool isPersistent = d->persistent.contains(editor); + const QModelIndex index = d->indexForEditor(editor); + if (!index.isValid()) { + if (!editor->isVisible()) { + // The commit might have removed the index (e.g. it might get filtered), in + // which case the editor is already hidden and scheduled for deletion. We + // don't have to do anything, except reset the state, and continue with + // EndEditHint processing. + if (!isPersistent) + setState(NoState); + } else { + qWarning("QAbstractItemView::closeEditor called with an editor that does not belong to this view"); + return; + } } else { - d->checkPersistentEditorFocus(); - } + const bool hadFocus = editor->hasFocus(); + // start a timer that expires immediately when we return to the event loop + // to identify whether this close was triggered by a mousepress-initiated + // focus event + d->pressClosedEditorWatcher.start(0, this); + d->lastEditedIndex = index; + + if (!isPersistent) { + setState(NoState); + QModelIndex index = d->indexForEditor(editor); + editor->removeEventFilter(itemDelegateForIndex(index)); + d->removeEditor(editor); + } + if (hadFocus) { + if (focusPolicy() != Qt::NoFocus) + setFocus(); // this will send a focusLost event to the editor + else + editor->clearFocus(); + } else { + d->checkPersistentEditorFocus(); + } - QPointer<QWidget> ed = editor; - QCoreApplication::sendPostedEvents(editor, 0); - editor = ed; + QPointer<QWidget> ed = editor; + QCoreApplication::sendPostedEvents(editor, 0); + editor = ed; - if (!isPersistent && editor) - d->releaseEditor(editor, index); + if (!isPersistent && editor) + d->releaseEditor(editor, index); + } } // The EndEditHint part @@ -3005,8 +3029,10 @@ void QAbstractItemView::commitData(QWidget *editor) if (!editor || !d->itemDelegate || d->currentlyCommittingEditor) return; QModelIndex index = d->indexForEditor(editor); - if (!index.isValid()) + if (!index.isValid()) { + qWarning("QAbstractItemView::commitData called with an editor that does not belong to this view"); return; + } d->currentlyCommittingEditor = editor; QAbstractItemDelegate *delegate = itemDelegateForIndex(index); editor->removeEventFilter(delegate); @@ -3065,9 +3091,9 @@ void QAbstractItemView::keyboardSearch(const QString &search) // special case for searches with same key like 'aaaaa' bool sameKey = false; - if (d->keyboardInput.length() > 1) { - int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1)); - sameKey = (c == d->keyboardInput.length()); + if (d->keyboardInput.size() > 1) { + int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.size() - 1)); + sameKey = (c == d->keyboardInput.size()); if (sameKey) skipRow = true; } @@ -3355,7 +3381,7 @@ void QAbstractItemView::update(const QModelIndex &index) { Q_D(QAbstractItemView); if (index.isValid()) { - const QRect rect = visualRect(index); + const QRect rect = d->visualRect(index); //this test is important for performance reason //For example in dataChanged we simply update all the cells without checking //it can be a major bottleneck to update rects that aren't even part of the viewport @@ -3410,7 +3436,7 @@ void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelInde } } -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) if (QAccessible::isActive()) { QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::DataChanged); accessibleEvent.setFirstRow(topLeft.row()); @@ -3468,24 +3494,59 @@ void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int star } else { int row = end + 1; QModelIndex next; - do { // find the next visible and enabled item + const int rowCount = d->model->rowCount(parent); + bool found = false; + // find the next visible and enabled item + while (row < rowCount && !found) { next = d->model->index(row++, current.column(), current.parent()); - } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next))); - if (row > d->model->rowCount(parent)) { +#ifdef QT_DEBUG + if (!next.isValid()) { + qWarning("Model unexpectedly returned an invalid index"); + break; + } +#endif + if (!isIndexHidden(next) && d->isIndexEnabled(next)) { + found = true; + break; + } + } + + if (!found) { row = start - 1; - do { // find the previous visible and enabled item + // find the previous visible and enabled item + while (row >= 0) { next = d->model->index(row--, current.column(), current.parent()); - } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next))); +#ifdef QT_DEBUG + if (!next.isValid()) { + qWarning("Model unexpectedly returned an invalid index"); + break; + } +#endif + if (!isIndexHidden(next) && d->isIndexEnabled(next)) + break; + } } + setCurrentIndex(next); } } // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes + const auto findDirectChildOf = [](const QModelIndex &parent, QModelIndex child) + { + while (child.isValid()) { + const auto parentIndex = child.parent(); + if (parentIndex == parent) + return child; + child = parentIndex; + } + return QModelIndex(); + }; QEditorIndexHash::iterator i = d->editorIndexHash.begin(); while (i != d->editorIndexHash.end()) { const QModelIndex index = i.value(); - if (index.row() >= start && index.row() <= end && d->model->parent(index) == parent) { + const QModelIndex directChild = findDirectChildOf(parent, index); + if (directChild.isValid() && directChild.row() >= start && directChild.row() <= end) { QWidget *editor = i.key(); QEditorInfo info = d->indexEditorHash.take(index); i = d->editorIndexHash.erase(i); @@ -3504,7 +3565,7 @@ void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int star rows are those under the given \a parent from \a start to \a end inclusive. */ -void QAbstractItemViewPrivate::_q_rowsRemoved(const QModelIndex &index, int start, int end) +void QAbstractItemViewPrivate::rowsRemoved(const QModelIndex &index, int start, int end) { Q_UNUSED(index); Q_UNUSED(start); @@ -3514,7 +3575,7 @@ void QAbstractItemViewPrivate::_q_rowsRemoved(const QModelIndex &index, int star if (q->isVisible()) q->updateEditorGeometries(); q->setState(QAbstractItemView::NoState); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) if (QAccessible::isActive()) { QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::RowsRemoved); accessibleEvent.setFirstRow(start); @@ -3532,7 +3593,7 @@ void QAbstractItemViewPrivate::_q_rowsRemoved(const QModelIndex &index, int star columns are those under the given \a parent from \a start to \a end inclusive. */ -void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +void QAbstractItemViewPrivate::columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { Q_Q(QAbstractItemView); @@ -3554,9 +3615,19 @@ void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &par } else { int column = end; QModelIndex next; - do { // find the next visible and enabled item + const int columnCount = model->columnCount(current.parent()); + // find the next visible and enabled item + while (column < columnCount) { next = model->index(current.row(), column++, current.parent()); - } while (next.isValid() && (q->isIndexHidden(next) || !isIndexEnabled(next))); +#ifdef QT_DEBUG + if (!next.isValid()) { + qWarning("Model unexpectedly returned an invalid index"); + break; + } +#endif + if (!q->isIndexHidden(next) && isIndexEnabled(next)) + break; + } q->setCurrentIndex(next); } } @@ -3585,7 +3656,7 @@ void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &par rows are those under the given \a parent from \a start to \a end inclusive. */ -void QAbstractItemViewPrivate::_q_columnsRemoved(const QModelIndex &index, int start, int end) +void QAbstractItemViewPrivate::columnsRemoved(const QModelIndex &index, int start, int end) { Q_UNUSED(index); Q_UNUSED(start); @@ -3595,7 +3666,7 @@ void QAbstractItemViewPrivate::_q_columnsRemoved(const QModelIndex &index, int s if (q->isVisible()) q->updateEditorGeometries(); q->setState(QAbstractItemView::NoState); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) if (QAccessible::isActive()) { QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ColumnsRemoved); accessibleEvent.setFirstColumn(start); @@ -3612,13 +3683,13 @@ void QAbstractItemViewPrivate::_q_columnsRemoved(const QModelIndex &index, int s This slot is called when rows have been inserted. */ -void QAbstractItemViewPrivate::_q_rowsInserted(const QModelIndex &index, int start, int end) +void QAbstractItemViewPrivate::rowsInserted(const QModelIndex &index, int start, int end) { Q_UNUSED(index); Q_UNUSED(start); Q_UNUSED(end); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) Q_Q(QAbstractItemView); if (QAccessible::isActive()) { QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::RowsInserted); @@ -3635,7 +3706,7 @@ void QAbstractItemViewPrivate::_q_rowsInserted(const QModelIndex &index, int sta This slot is called when columns have been inserted. */ -void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &index, int start, int end) +void QAbstractItemViewPrivate::columnsInserted(const QModelIndex &index, int start, int end) { Q_UNUSED(index); Q_UNUSED(start); @@ -3644,7 +3715,7 @@ void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &index, int Q_Q(QAbstractItemView); if (q->isVisible()) q->updateEditorGeometries(); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) if (QAccessible::isActive()) { QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ColumnsInserted); accessibleEvent.setFirstColumn(start); @@ -3658,7 +3729,7 @@ void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &index, int /*! \internal */ -void QAbstractItemViewPrivate::_q_modelDestroyed() +void QAbstractItemViewPrivate::modelDestroyed() { model = QAbstractItemModelPrivate::staticEmptyModel(); doDelayedReset(); @@ -3669,10 +3740,10 @@ void QAbstractItemViewPrivate::_q_modelDestroyed() This slot is called when the layout is changed. */ -void QAbstractItemViewPrivate::_q_layoutChanged() +void QAbstractItemViewPrivate::layoutChanged() { doDelayedItemsLayout(); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) Q_Q(QAbstractItemView); if (QAccessible::isActive()) { QAccessibleTableModelChangeEvent accessibleEvent(q, QAccessibleTableModelChangeEvent::ModelReset); @@ -3681,14 +3752,14 @@ void QAbstractItemViewPrivate::_q_layoutChanged() #endif } -void QAbstractItemViewPrivate::_q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int) +void QAbstractItemViewPrivate::rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int) { - _q_layoutChanged(); + layoutChanged(); } -void QAbstractItemViewPrivate::_q_columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int) +void QAbstractItemViewPrivate::columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int) { - _q_layoutChanged(); + layoutChanged(); } QRect QAbstractItemViewPrivate::intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const @@ -3771,7 +3842,7 @@ void QAbstractItemView::startDrag(Qt::DropActions supportedActions) { Q_D(QAbstractItemView); QModelIndexList indexes = d->selectedDraggableIndexes(); - if (indexes.count() > 0) { + if (indexes.size() > 0) { QMimeData *data = d->model->mimeData(indexes); if (!data) return; @@ -4042,9 +4113,10 @@ void QAbstractItemView::doAutoScroll() } /*! - Returns the SelectionFlags to be used when updating a selection with - to include the \a index specified. The \a event is a user input event, - such as a mouse or keyboard event. + Returns the SelectionFlags to be used when updating a selection model + for the specified \a index. The result depends on the current + selectionMode(), and on the user input event \a event, which can be + \nullptr. Reimplement this function to define your own selection behavior. @@ -4061,12 +4133,28 @@ QItemSelectionModel::SelectionFlags QAbstractItemView::selectionCommand(const QM case NoSelection: // Never update selection model return QItemSelectionModel::NoUpdate; case SingleSelection: // ClearAndSelect on valid index otherwise NoUpdate - if (event && event->type() == QEvent::MouseButtonRelease) - return QItemSelectionModel::NoUpdate; - if ((keyModifiers & Qt::ControlModifier) && d->selectionModel->isSelected(index) && event->type() != QEvent::MouseMove) - return QItemSelectionModel::Deselect | d->selectionBehaviorFlags(); - else - return QItemSelectionModel::ClearAndSelect | d->selectionBehaviorFlags(); + if (event) { + switch (event->type()) { + case QEvent::MouseButtonPress: + // press with any modifiers on a selected item does nothing + if (d->pressedAlreadySelected) + return QItemSelectionModel::NoUpdate; + break; + case QEvent::MouseButtonRelease: + // clicking into area with no items does nothing + if (!index.isValid()) + return QItemSelectionModel::NoUpdate; + Q_FALLTHROUGH(); + case QEvent::KeyPress: + // ctrl-release on selected item deselects + if ((keyModifiers & Qt::ControlModifier) && d->selectionModel->isSelected(index)) + return QItemSelectionModel::Deselect | d->selectionBehaviorFlags(); + break; + default: + break; + } + } + return QItemSelectionModel::ClearAndSelect | d->selectionBehaviorFlags(); case MultiSelection: return d->multiSelectionCommand(index, event); case ExtendedSelection: @@ -4092,13 +4180,21 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::multiSelectionComm case QEvent::MouseButtonPress: if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton) { // since the press might start a drag, deselect only on release - if (!pressedAlreadySelected || !dragEnabled || !isIndexDragEnabled(index)) + if (!pressedAlreadySelected +#if QT_CONFIG(draganddrop) + || !dragEnabled || !isIndexDragEnabled(index) +#endif + ) return QItemSelectionModel::Toggle|selectionBehaviorFlags(); // toggle } break; case QEvent::MouseButtonRelease: if (static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton) { - if (pressedAlreadySelected && dragEnabled && isIndexDragEnabled(index) && index == pressedIndex) + if (pressedAlreadySelected +#if QT_CONFIG(draganddrop) + && dragEnabled && isIndexDragEnabled(index) +#endif + && index == pressedIndex) return QItemSelectionModel::Toggle|selectionBehaviorFlags(); return QItemSelectionModel::NoUpdate|selectionBehaviorFlags(); // finalize } @@ -4146,7 +4242,10 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC return QItemSelectionModel::NoUpdate; // since the press might start a drag, deselect only on release if (controlKeyPressed && !rightButtonPressed && pressedAlreadySelected - && dragEnabled && isIndexDragEnabled(index)) { +#if QT_CONFIG(draganddrop) + && dragEnabled && isIndexDragEnabled(index) +#endif + ) { return QItemSelectionModel::NoUpdate; } break; @@ -4162,7 +4261,10 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC && !shiftKeyPressed && !controlKeyPressed && (!rightButtonPressed || !index.isValid())) return QItemSelectionModel::ClearAndSelect|selectionBehaviorFlags(); if (index == pressedIndex && controlKeyPressed && !rightButtonPressed - && dragEnabled && isIndexDragEnabled(index)) { +#if QT_CONFIG(draganddrop) + && dragEnabled && isIndexDragEnabled(index) +#endif + ) { break; } return QItemSelectionModel::NoUpdate; @@ -4199,6 +4301,7 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC default: break; } + break; } default: break; @@ -4367,7 +4470,7 @@ QWidget *QAbstractItemViewPrivate::editor(const QModelIndex &index, w = delegate->createEditor(viewport, options, index); if (w) { w->installEventFilter(delegate); - QObject::connect(w, SIGNAL(destroyed(QObject*)), q, SLOT(editorDestroyed(QObject*))); + QObject::connect(w, &QWidget::destroyed, q, &QAbstractItemView::editorDestroyed); delegate->updateEditorGeometry(w, options, index); delegate->setEditorData(w, index); addEditor(index, w, false); @@ -4504,6 +4607,9 @@ QModelIndex QAbstractItemViewPrivate::indexForEditor(QWidget *editor) const void QAbstractItemViewPrivate::removeEditor(QWidget *editor) { + Q_Q(QAbstractItemView); + if (editor) + QObject::disconnect(editor, &QWidget::destroyed, q, &QAbstractItemView::editorDestroyed); const auto it = editorIndexHash.constFind(editor); if (it != editorIndexHash.cend()) { indexEditorHash.remove(it.value()); @@ -4601,7 +4707,7 @@ QPixmap QAbstractItemViewPrivate::renderToPixmap(const QModelIndexList &indexes, QStyleOptionViewItem option; q->initViewItemOption(&option); option.state |= QStyle::State_Selected; - for (int j = 0; j < paintPairs.count(); ++j) { + for (int j = 0; j < paintPairs.size(); ++j) { option.rect = paintPairs.at(j).rect.translated(-r->topLeft()); const QModelIndex ¤t = paintPairs.at(j).index; adjustViewOptionsForIndex(&option, current); @@ -4614,6 +4720,8 @@ void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags com { if (!selectionModel) return; + if (!model->hasChildren(root)) + return; QItemSelection selection; QModelIndex tl = model->index(0, 0, root); @@ -4624,6 +4732,7 @@ void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags com selectionModel->select(selection, command); } +#if QT_CONFIG(draganddrop) QModelIndexList QAbstractItemViewPrivate::selectedDraggableIndexes() const { Q_Q(const QAbstractItemView); @@ -4635,6 +4744,21 @@ QModelIndexList QAbstractItemViewPrivate::selectedDraggableIndexes() const return indexes; } +void QAbstractItemViewPrivate::maybeStartDrag(QPoint eventPosition) +{ + Q_Q(QAbstractItemView); + + const QPoint topLeft = pressedPosition - offset(); + if ((topLeft - eventPosition).manhattanLength() > QApplication::startDragDistance()) { + pressedIndex = QModelIndex(); + q->startDrag(model->supportedDragActions()); + q->setState(QAbstractItemView::NoState); // the startDrag will return when the dnd operation + // is done + q->stopAutoScroll(); + } +} +#endif + /*! \reimp */ |