diff options
Diffstat (limited to 'src/widgets/itemviews/qabstractitemview.cpp')
-rw-r--r-- | src/widgets/itemviews/qabstractitemview.cpp | 475 |
1 files changed, 281 insertions, 194 deletions
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 57139cce61..85e478a71e 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -102,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); @@ -129,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())); } @@ -172,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); @@ -208,7 +209,7 @@ void QAbstractItemViewPrivate::_q_scrollerStateChanged() #endif // QT_NO_GESTURES -void QAbstractItemViewPrivate::_q_delegateSizeHintChanged(const QModelIndex &index) +void QAbstractItemViewPrivate::delegateSizeHintChanged(const QModelIndex &index) { Q_Q(QAbstractItemView); if (model) { @@ -218,6 +219,63 @@ void QAbstractItemViewPrivate::_q_delegateSizeHintChanged(const QModelIndex &ind 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 @@ -318,7 +376,7 @@ void QAbstractItemViewPrivate::_q_delegateSizeHintChanged(const QModelIndex &ind \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 */ /*! @@ -631,6 +689,7 @@ QAbstractItemView::~QAbstractItemView() d->autoScrollTimer.stop(); d->delayedLayout.stop(); d->fetchMoreTimer.stop(); + d->disconnectAll(); } /*! @@ -659,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 @@ -770,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); @@ -823,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(_q_delegateSizeHintChanged(QModelIndex))); - } + 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(_q_delegateSizeHintChanged(QModelIndex))); - } + if (d->delegateRefCount(delegate) == 0) + d->connectDelegate(delegate); } d->itemDelegate = delegate; viewport()->update(); @@ -907,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(_q_delegateSizeHintChanged(QModelIndex))); - } + 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(_q_delegateSizeHintChanged(QModelIndex))); - } + if (d->delegateRefCount(delegate) == 0) + d->connectDelegate(delegate); d->rowDelegates.insert(row, delegate); } viewport()->update(); @@ -967,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(_q_delegateSizeHintChanged(QModelIndex))); - } + 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(_q_delegateSizeHintChanged(QModelIndex))); - } + if (d->delegateRefCount(delegate) == 0) + d->connectDelegate(delegate); d->columnDelegates.insert(column, delegate); } viewport()->update(); @@ -1119,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())); } @@ -1153,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(); } @@ -1545,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. @@ -1638,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()) @@ -1709,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())); @@ -1756,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; @@ -1793,9 +1825,11 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) QPoint offset = d->offset(); 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; @@ -1849,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(); @@ -1859,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) @@ -1876,10 +1903,8 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) || edit(index, NoEditTriggers, event)) return; - if (d->selectionMode != SingleSelection) - topLeft = d->pressedPosition - d->offset(); - else - topLeft = bottomRight; + const QPoint topLeft = + d->selectionMode != SingleSelection ? d->pressedPosition - d->offset() : bottomRight; d->checkMouseMove(index); @@ -1890,6 +1915,7 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) && (event->buttons() != Qt::NoButton) && !d->selectedDraggableIndexes().isEmpty()) { setState(DraggingState); + d->maybeStartDrag(bottomRight); return; } #endif @@ -1939,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; @@ -1947,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)); } @@ -2366,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 @@ -2829,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)); } } @@ -2907,41 +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); + const bool isPersistent = d->persistent.contains(editor); + const QModelIndex index = d->indexForEditor(editor); if (!index.isValid()) { - qWarning("QAbstractItemView::closeEditor called with an editor that does not belong to this view"); - 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(); + 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 @@ -3053,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; } @@ -3343,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 @@ -3494,10 +3532,21 @@ void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int star } // 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); @@ -3516,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); @@ -3544,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); @@ -3607,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); @@ -3634,7 +3683,7 @@ 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); @@ -3657,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); @@ -3680,7 +3729,7 @@ void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &index, int /*! \internal */ -void QAbstractItemViewPrivate::_q_modelDestroyed() +void QAbstractItemViewPrivate::modelDestroyed() { model = QAbstractItemModelPrivate::staticEmptyModel(); doDelayedReset(); @@ -3691,7 +3740,7 @@ void QAbstractItemViewPrivate::_q_modelDestroyed() This slot is called when the layout is changed. */ -void QAbstractItemViewPrivate::_q_layoutChanged() +void QAbstractItemViewPrivate::layoutChanged() { doDelayedItemsLayout(); #if QT_CONFIG(accessibility) @@ -3703,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 @@ -3793,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; @@ -4091,8 +4140,12 @@ QItemSelectionModel::SelectionFlags QAbstractItemView::selectionCommand(const QM if (d->pressedAlreadySelected) return QItemSelectionModel::NoUpdate; break; - case QEvent::KeyPress: 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(); @@ -4127,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 } @@ -4181,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; @@ -4197,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; @@ -4234,6 +4301,7 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC default: break; } + break; } default: break; @@ -4402,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); @@ -4539,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()); @@ -4636,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); @@ -4661,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); @@ -4672,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 */ |