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>
This commit is contained in:
parent
e43638c8a8
commit
52cbcd947d
|
@ -25,7 +25,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickSelectable
|
||||||
public:
|
public:
|
||||||
virtual QQuickItem *selectionPointerHandlerTarget() const = 0;
|
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 setSelectionStartPos(const QPointF &pos) = 0;
|
||||||
virtual void setSelectionEndPos(const QPointF &pos) = 0;
|
virtual void setSelectionEndPos(const QPointF &pos) = 0;
|
||||||
virtual void clearSelection() = 0;
|
virtual void clearSelection() = 0;
|
||||||
|
|
|
@ -1517,11 +1517,18 @@ QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget() const
|
||||||
return const_cast<QQuickTableView *>(q_func())->contentItem();
|
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);
|
Q_UNUSED(pos);
|
||||||
// Only allow a selection if it doesn't conflict with resizing
|
// 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)
|
void QQuickTableViewPrivate::setSelectionStartPos(const QPointF &pos)
|
||||||
|
@ -4633,12 +4640,12 @@ void QQuickTableViewPrivate::init()
|
||||||
positionYAnimation.stop();
|
positionYAnimation.stop();
|
||||||
|
|
||||||
if (!q->isInteractive())
|
if (!q->isInteractive())
|
||||||
handleTap(tapHandler->point().pressPosition());
|
handleTap(tapHandler->point());
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, [this, q, tapHandler] {
|
QObject::connect(tapHandler, &QQuickTapHandler::singleTapped, [this, q, tapHandler] {
|
||||||
if (q->isInteractive())
|
if (q->isInteractive())
|
||||||
handleTap(tapHandler->point().pressPosition());
|
handleTap(tapHandler->point());
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(tapHandler, &QQuickTapHandler::doubleTapped, [this, q, tapHandler] {
|
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);
|
Q_Q(QQuickTableView);
|
||||||
|
|
||||||
if (keyNavigationEnabled)
|
if (keyNavigationEnabled)
|
||||||
q->forceActiveFocus(Qt::MouseFocusReason);
|
q->forceActiveFocus(Qt::MouseFocusReason);
|
||||||
|
|
||||||
|
if (point.modifiers() != Qt::NoModifier)
|
||||||
|
return;
|
||||||
if (resizableRows && hoverHandler->m_row != -1)
|
if (resizableRows && hoverHandler->m_row != -1)
|
||||||
return;
|
return;
|
||||||
if (resizableColumns && hoverHandler->m_column != -1)
|
if (resizableColumns && hoverHandler->m_column != -1)
|
||||||
|
@ -4679,14 +4688,14 @@ void QQuickTableViewPrivate::handleTap(const QPointF &pos)
|
||||||
prevIndex = selectionModel->currentIndex();
|
prevIndex = selectionModel->currentIndex();
|
||||||
if (pointerNavigationEnabled) {
|
if (pointerNavigationEnabled) {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
setCurrentIndexFromTap(pos);
|
setCurrentIndexFromTap(point.position());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editTriggers != QQuickTableView::NoEditTriggers)
|
if (editTriggers != QQuickTableView::NoEditTriggers)
|
||||||
q->closeEditor();
|
q->closeEditor();
|
||||||
|
|
||||||
const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(pos));
|
const QModelIndex tappedIndex = q->modelIndex(q->cellAtPosition(point.position()));
|
||||||
if (canEdit(tappedIndex, false)) {
|
if (canEdit(tappedIndex, false)) {
|
||||||
if (editTriggers & QQuickTableView::SingleTapped)
|
if (editTriggers & QQuickTableView::SingleTapped)
|
||||||
q->edit(tappedIndex);
|
q->edit(tappedIndex);
|
||||||
|
|
|
@ -548,7 +548,7 @@ public:
|
||||||
int serializedModelIndex,
|
int serializedModelIndex,
|
||||||
QObject *object, bool init);
|
QObject *object, bool init);
|
||||||
|
|
||||||
void handleTap(const QPointF &pos);
|
void handleTap(const QQuickHandlerPoint &point);
|
||||||
void setCurrentIndexFromTap(const QPointF &pos);
|
void setCurrentIndexFromTap(const QPointF &pos);
|
||||||
void setCurrentIndex(const QPoint &cell);
|
void setCurrentIndex(const QPoint &cell);
|
||||||
bool setCurrentIndexFromKeyEvent(QKeyEvent *e);
|
bool setCurrentIndexFromKeyEvent(QKeyEvent *e);
|
||||||
|
@ -557,7 +557,7 @@ public:
|
||||||
|
|
||||||
// QQuickSelectable
|
// QQuickSelectable
|
||||||
QQuickItem *selectionPointerHandlerTarget() const override;
|
QQuickItem *selectionPointerHandlerTarget() const override;
|
||||||
bool canStartSelection(const QPointF &pos) override;
|
bool startSelection(const QPointF &pos) override;
|
||||||
void setSelectionStartPos(const QPointF &pos) override;
|
void setSelectionStartPos(const QPointF &pos) override;
|
||||||
void setSelectionEndPos(const QPointF &pos) override;
|
void setSelectionEndPos(const QPointF &pos) override;
|
||||||
void clearSelection() override;
|
void clearSelection() override;
|
||||||
|
|
|
@ -182,7 +182,9 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
|
||||||
|
|
||||||
QObject::connect(m_tapHandler, &QQuickTapHandler::longPressed, [this]() {
|
QObject::connect(m_tapHandler, &QQuickTapHandler::longPressed, [this]() {
|
||||||
const QPointF pos = m_tapHandler->point().pressPosition();
|
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;
|
return;
|
||||||
if (handleUnderPos(pos) != nullptr) {
|
if (handleUnderPos(pos) != nullptr) {
|
||||||
// Don't allow press'n'hold to start a new
|
// Don't allow press'n'hold to start a new
|
||||||
|
@ -199,6 +201,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!modifiers.testFlag(Qt::ShiftModifier))
|
||||||
m_selectable->clearSelection();
|
m_selectable->clearSelection();
|
||||||
m_selectable->setSelectionStartPos(pos);
|
m_selectable->setSelectionStartPos(pos);
|
||||||
m_selectable->setSelectionEndPos(pos);
|
m_selectable->setSelectionEndPos(pos);
|
||||||
|
@ -209,10 +212,12 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
|
||||||
QObject::connect(m_dragHandler, &QQuickDragHandler::activeChanged, [this]() {
|
QObject::connect(m_dragHandler, &QQuickDragHandler::activeChanged, [this]() {
|
||||||
const QPointF startPos = m_dragHandler->centroid().pressPosition();
|
const QPointF startPos = m_dragHandler->centroid().pressPosition();
|
||||||
const QPointF dragPos = m_dragHandler->centroid().position();
|
const QPointF dragPos = m_dragHandler->centroid().position();
|
||||||
|
const auto modifiers = m_dragHandler->centroid().modifiers();
|
||||||
|
|
||||||
if (m_dragHandler->active()) {
|
if (m_dragHandler->active()) {
|
||||||
if (!m_selectable->canStartSelection(startPos))
|
if (!m_selectable->startSelection(startPos))
|
||||||
return;
|
return;
|
||||||
|
if (!modifiers.testFlag(Qt::ShiftModifier))
|
||||||
m_selectable->clearSelection();
|
m_selectable->clearSelection();
|
||||||
m_selectable->setSelectionStartPos(startPos);
|
m_selectable->setSelectionStartPos(startPos);
|
||||||
m_selectable->setSelectionEndPos(dragPos);
|
m_selectable->setSelectionEndPos(dragPos);
|
||||||
|
|
|
@ -198,8 +198,36 @@ TestCase {
|
||||||
mousePress(tableView, 1, 1, Qt.LeftButton)
|
mousePress(tableView, 1, 1, Qt.LeftButton)
|
||||||
mousePress(tableView, 1, 1, Qt.LeftButton, Qt.NoModifier, 1000)
|
mousePress(tableView, 1, 1, Qt.LeftButton, Qt.NoModifier, 1000)
|
||||||
verify(!tableView.selectionModel.hasSelection)
|
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() {
|
function test_pressAndHold_data() {
|
||||||
return [
|
return [
|
||||||
{ tag: "resize enabled", resizeEnabled: true },
|
{ tag: "resize enabled", resizeEnabled: true },
|
||||||
|
|
Loading…
Reference in New Issue