diff options
author | Richard Moe Gustavsen <richard.gustavsen@qt.io> | 2022-10-31 16:10:03 +0100 |
---|---|---|
committer | Richard Moe Gustavsen <richard.gustavsen@qt.io> | 2022-12-08 23:25:20 +0100 |
commit | 52cbcd947db2219aecb2f6cb59bc6676a7c61e48 (patch) | |
tree | 09835ffc85ef313dfafbdb29305cf4cc83e3d290 | |
parent | e43638c8a830b9ade737b361fa471381b3afdb11 (diff) |
QQuickTableView: support multi-selection
Implement support for doing multiple selections in
TableView by holding down the shift modifier while
dragging.
[ChangeLog][Quick][TableView] Added multi-selection support
if using a SelectionRectangle and holding down the shift-modifier.
Change-Id: Ife622aeea2ed60a5741df01f3aac2fb647108aa9
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
-rw-r--r-- | src/quick/items/qquickselectable_p.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquicktableview.cpp | 23 | ||||
-rw-r--r-- | src/quick/items/qquicktableview_p_p.h | 4 | ||||
-rw-r--r-- | src/quicktemplates/qquickselectionrectangle.cpp | 13 | ||||
-rw-r--r-- | tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml | 28 |
5 files changed, 56 insertions, 14 deletions
diff --git a/src/quick/items/qquickselectable_p.h b/src/quick/items/qquickselectable_p.h index 0381b73f69..726352719f 100644 --- a/src/quick/items/qquickselectable_p.h +++ b/src/quick/items/qquickselectable_p.h @@ -25,7 +25,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickSelectable public: virtual QQuickItem *selectionPointerHandlerTarget() const = 0; - virtual bool canStartSelection(const QPointF &pos) = 0; + virtual bool startSelection(const QPointF &pos) = 0; virtual void setSelectionStartPos(const QPointF &pos) = 0; virtual void setSelectionEndPos(const QPointF &pos) = 0; virtual void clearSelection() = 0; diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index b52922fbee..d4e4305fb3 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -1517,11 +1517,18 @@ QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget() const return const_cast<QQuickTableView *>(q_func())->contentItem(); } -bool QQuickTableViewPrivate::canStartSelection(const QPointF &pos) +bool QQuickTableViewPrivate::startSelection(const QPointF &pos) { + Q_Q(QQuickTableView); Q_UNUSED(pos); // Only allow a selection if it doesn't conflict with resizing - return resizeHandler->state() == QQuickTableViewResizeHandler::Listening; + const bool canStartSelection = resizeHandler->state() == QQuickTableViewResizeHandler::Listening; + if (canStartSelection) { + selectionStartCell = QPoint(-1, -1); + selectionEndCell = QPoint(-1, -1); + q->closeEditor(); + } + return canStartSelection; } void QQuickTableViewPrivate::setSelectionStartPos(const QPointF &pos) @@ -4633,12 +4640,12 @@ void QQuickTableViewPrivate::init() positionYAnimation.stop(); if (!q->isInteractive()) - handleTap(tapHandler->point().pressPosition()); + handleTap(tapHandler->point()); }); QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, [this, q, tapHandler] { if (q->isInteractive()) - handleTap(tapHandler->point().pressPosition()); + handleTap(tapHandler->point()); }); QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, [this, q, tapHandler] { @@ -4660,13 +4667,15 @@ void QQuickTableViewPrivate::init() }); } -void QQuickTableViewPrivate::handleTap(const QPointF &pos) +void QQuickTableViewPrivate::handleTap(const QQuickHandlerPoint &point) { Q_Q(QQuickTableView); if (keyNavigationEnabled) q->forceActiveFocus(Qt::MouseFocusReason); + if (point.modifiers() != Qt::NoModifier) + return; if (resizableRows && hoverHandler->m_row != -1) return; if (resizableColumns && hoverHandler->m_column != -1) @@ -4679,14 +4688,14 @@ void QQuickTableViewPrivate::handleTap(const QPointF &pos) prevIndex = selectionModel->currentIndex(); if (pointerNavigationEnabled) { clearSelection(); - setCurrentIndexFromTap(pos); + setCurrentIndexFromTap(point.position()); } } if (editTriggers != QQuickTableView::NoEditTriggers) q->closeEditor(); - const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(pos)); + const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position())); if (canEdit(tappedIndex, false)) { if (editTriggers & QQuickTableView::SingleTapped) q->edit(tappedIndex); diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h index 54730fbc64..40763b340e 100644 --- a/src/quick/items/qquicktableview_p_p.h +++ b/src/quick/items/qquicktableview_p_p.h @@ -548,7 +548,7 @@ public: int serializedModelIndex, QObject *object, bool init); - void handleTap(const QPointF &pos); + void handleTap(const QQuickHandlerPoint &point); void setCurrentIndexFromTap(const QPointF &pos); void setCurrentIndex(const QPoint &cell); bool setCurrentIndexFromKeyEvent(QKeyEvent *e); @@ -557,7 +557,7 @@ public: // QQuickSelectable QQuickItem *selectionPointerHandlerTarget() const override; - bool canStartSelection(const QPointF &pos) override; + bool startSelection(const QPointF &pos) override; void setSelectionStartPos(const QPointF &pos) override; void setSelectionEndPos(const QPointF &pos) override; void clearSelection() override; diff --git a/src/quicktemplates/qquickselectionrectangle.cpp b/src/quicktemplates/qquickselectionrectangle.cpp index 9e9fa60710..28f495d525 100644 --- a/src/quicktemplates/qquickselectionrectangle.cpp +++ b/src/quicktemplates/qquickselectionrectangle.cpp @@ -182,7 +182,9 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate() QObject::connect(m_tapHandler, &QQuickTapHandler::longPressed, [this]() { const QPointF pos = m_tapHandler->point().pressPosition(); - if (!m_selectable->canStartSelection(pos)) + const auto modifiers = m_tapHandler->point().modifiers(); + + if (!m_selectable->startSelection(pos)) return; if (handleUnderPos(pos) != nullptr) { // Don't allow press'n'hold to start a new @@ -199,7 +201,8 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate() } } - m_selectable->clearSelection(); + if (!modifiers.testFlag(Qt::ShiftModifier)) + m_selectable->clearSelection(); m_selectable->setSelectionStartPos(pos); m_selectable->setSelectionEndPos(pos); updateHandles(); @@ -209,11 +212,13 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate() QObject::connect(m_dragHandler, &QQuickDragHandler::activeChanged, [this]() { const QPointF startPos = m_dragHandler->centroid().pressPosition(); const QPointF dragPos = m_dragHandler->centroid().position(); + const auto modifiers = m_dragHandler->centroid().modifiers(); if (m_dragHandler->active()) { - if (!m_selectable->canStartSelection(startPos)) + if (!m_selectable->startSelection(startPos)) return; - m_selectable->clearSelection(); + if (!modifiers.testFlag(Qt::ShiftModifier)) + m_selectable->clearSelection(); m_selectable->setSelectionStartPos(startPos); m_selectable->setSelectionEndPos(dragPos); m_draggedHandle = nullptr; diff --git a/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml b/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml index 9203528d07..4a1e08f478 100644 --- a/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml +++ b/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml @@ -198,8 +198,36 @@ TestCase { mousePress(tableView, 1, 1, Qt.LeftButton) mousePress(tableView, 1, 1, Qt.LeftButton, Qt.NoModifier, 1000) verify(!tableView.selectionModel.hasSelection) + } +// TODO: enable this test when mouseDrag sends modifiers for all mouse events +// (including mouseMove) +// function test_multi_selection() { +// let tableView = createTemporaryObject(tableviewComp, testCase) +// verify(tableView) +// let selectionRectangle = tableView.selectionRectangle +// verify(selectionRectangle) +// verify(!tableView.selectionModel.hasSelection) + +// selectionRectangle.selectionMode = SelectionRectangle.Drag + +// mouseDrag(tableView, 1, 1, (cellWidth * 2) - 2, 1, Qt.LeftButton) +// verify(tableView.selectionModel.hasSelection) +// compare(tableView.selectionModel.selectedIndexes.length, 2) +// verify(tableView.selectionModel.isSelected(tableView.model.index(0, 0))) +// verify(tableView.selectionModel.isSelected(tableView.model.index(0, 1))) + +// // Hold down shift, and drag again to do a multi-selection +// mouseDrag(tableView, 1, cellHeight + 5, (cellWidth * 2) - 2, 1, Qt.LeftButton, Qt.ShiftModifier) +// verify(tableView.selectionModel.hasSelection) +// compare(tableView.selectionModel.selectedIndexes.length, 4) +// verify(tableView.selectionModel.isSelected(tableView.model.index(0, 0))) +// verify(tableView.selectionModel.isSelected(tableView.model.index(0, 1))) +// verify(tableView.selectionModel.isSelected(tableView.model.index(1, 0))) +// verify(tableView.selectionModel.isSelected(tableView.model.index(1, 1))) +// } + function test_pressAndHold_data() { return [ { tag: "resize enabled", resizeEnabled: true }, |