aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2024-03-22 13:31:37 +0100
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2024-04-17 12:27:35 +0200
commitbf0f4bab47c25a21c54be8eb1170ed2af092c84e (patch)
treeb7755a1f32e25d356f09f70fdbb2331345a131e8
parente089ee317cce3908dd390210671ac048fa2ca1db (diff)
QQuickTableView: support unselecting cells
As it stood, SelectionRectangle and TableView didn't support unselecting cells by ctrl-dragging or ctrl-clicking a selected cell. This is considered a bug. This patch will therefore make sure that we support doing that. In order to implement this, we need to provide the held keyboard modifiers to startSelection(), so that TableView can choose if the selected cells should become selected or unselected in the selection model. By making this change, it also became clear that some of the auto tests didn't call startSelection() before setSelectionStartPos(). We therefore now also assert that we always do this, and fix up the failing auto tests that violated this rule. Fixes: QTBUG-121143 Pick-to: 6.7 6.6 6.5 Change-Id: Icd58b551234f3c6145165771de599e46b62014dc Reviewed-by: Santhosh Kumar <santhosh.kumar.selvaraj@qt.io>
-rw-r--r--src/quick/items/qquickselectable_p.h2
-rw-r--r--src/quick/items/qquicktableview.cpp64
-rw-r--r--src/quick/items/qquicktableview_p_p.h3
-rw-r--r--src/quick/items/qquicktreeview.cpp11
-rw-r--r--src/quicktemplates/qquickselectionrectangle.cpp16
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp39
-rw-r--r--tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp14
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml58
8 files changed, 162 insertions, 45 deletions
diff --git a/src/quick/items/qquickselectable_p.h b/src/quick/items/qquickselectable_p.h
index 475660ab2d..dbee64c49e 100644
--- a/src/quick/items/qquickselectable_p.h
+++ b/src/quick/items/qquickselectable_p.h
@@ -30,7 +30,7 @@ public:
virtual QQuickItem *selectionPointerHandlerTarget() const = 0;
- virtual bool startSelection(const QPointF &pos) = 0;
+ virtual bool startSelection(const QPointF &pos, Qt::KeyboardModifiers modifiers) = 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 4d971525d4..6203f6f3c1 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -1663,10 +1663,15 @@ QQuickItem *QQuickTableViewPrivate::selectionPointerHandlerTarget() const
return const_cast<QQuickTableView *>(q_func())->contentItem();
}
-bool QQuickTableViewPrivate::startSelection(const QPointF &pos)
+bool QQuickTableViewPrivate::startSelection(const QPointF &pos, Qt::KeyboardModifiers modifiers)
{
Q_Q(QQuickTableView);
- Q_UNUSED(pos);
+ if (!selectionModel) {
+ if (warnNoSelectionModel)
+ qmlWarning(q_func()) << "Cannot start selection: no SelectionModel assigned!";
+ warnNoSelectionModel = false;
+ return false;
+ }
if (selectionBehavior == QQuickTableView::SelectionDisabled) {
qmlWarning(q) << "Cannot start selection: TableView.selectionBehavior == TableView.SelectionDisabled";
@@ -1684,6 +1689,18 @@ bool QQuickTableViewPrivate::startSelection(const QPointF &pos)
else if (selectionModel)
existingSelection = selectionModel->selection();
+ // If pos is on top of an unselected cell, we start a session where the user selects which
+ // cells to become selected. Otherwise, if pos is on top of an already selected cell and
+ // ctrl is being held, we start a session where the user selects which selected cells to
+ // become unselected.
+ selectionFlag = QItemSelectionModel::Select;
+ if (modifiers & Qt::ControlModifier) {
+ QPoint startCell = clampedCellAtPos(pos);
+ const QModelIndex startIndex = q->index(startCell.y(), startCell.x());
+ if (selectionModel->isSelected(startIndex))
+ selectionFlag = QItemSelectionModel::Deselect;
+ }
+
selectionStartCell = QPoint(-1, -1);
selectionEndCell = QPoint(-1, -1);
q->closeEditor();
@@ -1693,6 +1710,7 @@ bool QQuickTableViewPrivate::startSelection(const QPointF &pos)
void QQuickTableViewPrivate::setSelectionStartPos(const QPointF &pos)
{
Q_Q(QQuickTableView);
+ Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
if (loadedItems.isEmpty())
return;
if (!selectionModel) {
@@ -1749,6 +1767,7 @@ void QQuickTableViewPrivate::setSelectionStartPos(const QPointF &pos)
void QQuickTableViewPrivate::setSelectionEndPos(const QPointF &pos)
{
+ Q_ASSERT(selectionFlag != QItemSelectionModel::NoUpdate);
if (loadedItems.isEmpty())
return;
if (!selectionModel) {
@@ -1854,11 +1873,19 @@ void QQuickTableViewPrivate::updateSelection(const QRect &oldSelection, const QR
deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
}
- // Don't clear the selection that existed before the user started a new selection block
- deselect.merge(existingSelection, QItemSelectionModel::Deselect);
-
- selectionModel->select(deselect, QItemSelectionModel::Deselect);
- selectionModel->select(select, QItemSelectionModel::Select);
+ if (selectionFlag == QItemSelectionModel::Select) {
+ // Don't clear the selection that existed before the user started a new selection block
+ deselect.merge(existingSelection, QItemSelectionModel::Deselect);
+ selectionModel->select(deselect, QItemSelectionModel::Deselect);
+ selectionModel->select(select, QItemSelectionModel::Select);
+ } else if (selectionFlag == QItemSelectionModel::Deselect){
+ QItemSelection oldSelection = existingSelection;
+ oldSelection.merge(select, QItemSelectionModel::Deselect);
+ selectionModel->select(oldSelection, QItemSelectionModel::Select);
+ selectionModel->select(select, QItemSelectionModel::Deselect);
+ } else {
+ Q_UNREACHABLE();
+ }
}
void QQuickTableViewPrivate::cancelSelectionTracking()
@@ -1867,6 +1894,7 @@ void QQuickTableViewPrivate::cancelSelectionTracking()
selectionStartCell = QPoint(-1, -1);
selectionEndCell = QPoint(-1, -1);
existingSelection.clear();
+ selectionFlag = QItemSelectionModel::NoUpdate;
if (selectableCallbackFunction)
selectableCallbackFunction(QQuickSelectable::CallBackFlag::CancelSelection);
}
@@ -5053,7 +5081,6 @@ bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
const QModelIndex currentIndex = selectionModel->currentIndex();
const QPoint currentCell = q->cellAtIndex(currentIndex);
- const bool select = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
if (!q->activeFocusOnTab()) {
switch (e->key()) {
@@ -5085,21 +5112,30 @@ bool QQuickTableViewPrivate::setCurrentIndexFromKeyEvent(QKeyEvent *e)
}
auto beginMoveCurrentIndex = [&](){
- if (!select) {
+ const bool shouldSelect = (e->modifiers() & Qt::ShiftModifier) && (e->key() != Qt::Key_Backtab);
+ const bool startNewSelection = selectionRectangle().isEmpty();
+ if (!shouldSelect) {
clearSelection();
- } else if (selectionRectangle().isEmpty()) {
+ cancelSelectionTracking();
+ } else if (startNewSelection) {
+ // Try to start a new selection if no selection exists from before.
+ // The startSelection() call is theoretically allowed to refuse, although this
+ // is less likely when starting a selection using the keyboard.
const int serializedStartIndex = modelIndexToCellIndex(selectionModel->currentIndex());
if (loadedItems.contains(serializedStartIndex)) {
const QRectF startGeometry = loadedItems.value(serializedStartIndex)->geometry();
- setSelectionStartPos(startGeometry.center());
- if (selectableCallbackFunction)
- selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
+ if (startSelection(startGeometry.center(), Qt::ShiftModifier)) {
+ setSelectionStartPos(startGeometry.center());
+ if (selectableCallbackFunction)
+ selectableCallbackFunction(QQuickSelectable::CallBackFlag::SelectionRectangleChanged);
+ }
}
}
};
auto endMoveCurrentIndex = [&](const QPoint &cell){
- if (select) {
+ const bool isSelecting = selectionFlag != QItemSelectionModel::NoUpdate;
+ if (isSelecting) {
if (polishScheduled)
forceLayout(true);
const int serializedEndIndex = modelIndexAtCell(cell);
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 1f0c8549a5..867e03485a 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -360,6 +360,7 @@ public:
QPointer<QItemSelectionModel> selectionModel;
QQuickTableView::SelectionBehavior selectionBehavior = QQuickTableView::SelectCells;
QQuickTableView::SelectionMode selectionMode = QQuickTableView::ExtendedSelection;
+ QItemSelectionModel::SelectionFlag selectionFlag = QItemSelectionModel::NoUpdate;
std::function<void(CallBackFlag)> selectableCallbackFunction;
bool inSelectionModelUpdate = false;
@@ -582,7 +583,7 @@ public:
// QQuickSelectable
QQuickItem *selectionPointerHandlerTarget() const override;
- bool startSelection(const QPointF &pos) override;
+ bool startSelection(const QPointF &pos, Qt::KeyboardModifiers modifiers) override;
void setSelectionStartPos(const QPointF &pos) override;
void setSelectionEndPos(const QPointF &pos) override;
void clearSelection() override;
diff --git a/src/quick/items/qquicktreeview.cpp b/src/quick/items/qquicktreeview.cpp
index f2613b4f48..033884d58d 100644
--- a/src/quick/items/qquicktreeview.cpp
+++ b/src/quick/items/qquicktreeview.cpp
@@ -369,8 +369,15 @@ void QQuickTreeViewPrivate::updateSelection(const QRect &oldSelection, const QRe
deselect.merge(QItemSelection(index, index), QItemSelectionModel::Select);
}
- selectionModel->select(deselect, QItemSelectionModel::Deselect);
- selectionModel->select(select, QItemSelectionModel::Select);
+ if (selectionFlag == QItemSelectionModel::Select) {
+ selectionModel->select(deselect, QItemSelectionModel::Deselect);
+ selectionModel->select(select, QItemSelectionModel::Select);
+ } else {
+ QItemSelection oldSelection = existingSelection;
+ oldSelection.merge(select, QItemSelectionModel::Deselect);
+ selectionModel->select(oldSelection, QItemSelectionModel::Select);
+ selectionModel->select(select, QItemSelectionModel::Deselect);
+ }
}
QQuickTreeView::QQuickTreeView(QQuickItem *parent)
diff --git a/src/quicktemplates/qquickselectionrectangle.cpp b/src/quicktemplates/qquickselectionrectangle.cpp
index fb737d017a..435b12819b 100644
--- a/src/quicktemplates/qquickselectionrectangle.cpp
+++ b/src/quicktemplates/qquickselectionrectangle.cpp
@@ -192,7 +192,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
// existing selection, start a new selection from the current item
// to the pressed item.
if (!m_active) {
- if (!m_selectable->startSelection(pos))
+ if (!m_selectable->startSelection(pos, modifiers))
return;
m_selectable->setSelectionStartPos(QPoint{-1, -1});
}
@@ -201,7 +201,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
updateActiveState(true);
} else if (modifiers & Qt::ControlModifier) {
// Select a single cell, but keep the old selection (unless
- // m_selectable->startSelection(pos) returns false, which
+ // m_selectable->startSelection(pos. modifiers) returns false, which
// it will if selectionMode only allows a single selection).
if (handleUnderPos(pos) != nullptr) {
// Don't allow press'n'hold to start a new
@@ -209,7 +209,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
return;
}
- if (!m_selectable->startSelection(pos))
+ if (!m_selectable->startSelection(pos, modifiers))
return;
m_selectable->setSelectionStartPos(pos);
m_selectable->setSelectionEndPos(pos);
@@ -235,7 +235,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
// existing selection, start a new selection from the current item
// to the pressed item.
if (!m_active) {
- if (!m_selectable->startSelection(pos))
+ if (!m_selectable->startSelection(pos, modifiers))
return;
m_selectable->setSelectionStartPos(QPoint{-1, -1});
}
@@ -244,9 +244,9 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
updateActiveState(true);
} else if (modifiers == Qt::ControlModifier) {
// Select a single cell, but keep the old selection (unless
- // m_selectable->startSelection(pos) returns false, which
+ // m_selectable->startSelection(pos, modifiers) returns false, which
// it will if selectionMode only allows a single selection).
- if (!m_selectable->startSelection(pos))
+ if (!m_selectable->startSelection(pos, modifiers))
return;
m_selectable->setSelectionStartPos(pos);
m_selectable->setSelectionEndPos(pos);
@@ -255,7 +255,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
} else if (modifiers == Qt::NoModifier) {
// Select a single cell
m_selectable->clearSelection();
- if (!m_selectable->startSelection(pos))
+ if (!m_selectable->startSelection(pos, modifiers))
return;
m_selectable->setSelectionStartPos(pos);
m_selectable->setSelectionEndPos(pos);
@@ -278,7 +278,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
// In that case we continue to extend the active selection instead.
const bool modifiersHeld = modifiers & (Qt::ControlModifier | Qt::ShiftModifier);
if (!m_active || !modifiersHeld) {
- if (!m_selectable->startSelection(startPos))
+ if (!m_selectable->startSelection(startPos, modifiers))
return;
m_selectable->setSelectionStartPos(startPos);
}
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 7fb5cc21e5..bb425b5a6f 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -4582,9 +4582,10 @@ void tst_QQuickTableView::selectionBehaviorCells_data()
void tst_QQuickTableView::selectionBehaviorCells()
{
- // Check that the TableView implement QQuickSelectableInterface setSelectionStartPos, setSelectionEndPos
- // and clearSelection correctly. Do this by calling setSelectionStartPos/setSelectionEndPos on top of
- // different cells, and see that we end up with the expected selections.
+ // Check that the TableView implement QQuickSelectableInterface startSelection,
+ // setSelectionStartPos, setSelectionEndPos and clearSelection correctly. Do this by
+ // calling setSelectionStartPos/setSelectionEndPos on top of different cells, and see
+ // that we end up with the expected selections.
QFETCH(QPoint, endCellDist);
LOAD_TABLEVIEW("tableviewwithselected1.qml");
@@ -4614,6 +4615,7 @@ void tst_QQuickTableView::selectionBehaviorCells()
const QPointF endPos(endItem->x(), endItem->y());
const QPointF endPosWrapped(endItemWrapped->x(), endItemWrapped->y());
+ QVERIFY(tableViewPrivate->startSelection(startPos, Qt::NoModifier));
tableViewPrivate->setSelectionStartPos(startPos);
tableViewPrivate->setSelectionEndPos(endPos);
@@ -4654,8 +4656,9 @@ void tst_QQuickTableView::selectionBehaviorCells()
void tst_QQuickTableView::selectionBehaviorRows()
{
- // Check that the TableView implement QQuickSelectableInterface setSelectionStartPos, setSelectionEndPos
- // and clearSelection correctly for QQuickTableView::SelectRows.
+ // Check that the TableView implement QQuickSelectableInterface startSelection,
+ // setSelectionStartPos, setSelectionEndPos and clearSelection correctly for
+ // QQuickTableView::SelectRows.
LOAD_TABLEVIEW("tableviewwithselected1.qml");
TestModel model(10, 10);
@@ -4670,6 +4673,7 @@ void tst_QQuickTableView::selectionBehaviorRows()
QCOMPARE(selectionModel.hasSelection(), false);
// Drag from row 0 to row 3
+ QVERIFY(tableViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
tableViewPrivate->setSelectionStartPos(QPointF(0, 0));
tableViewPrivate->setSelectionEndPos(QPointF(60, 60));
@@ -4690,6 +4694,7 @@ void tst_QQuickTableView::selectionBehaviorRows()
QCOMPARE(selectionModel.hasSelection(), false);
// Drag from row 3 to row 0 (and overshoot mouse)
+ QVERIFY(tableViewPrivate->startSelection(QPointF(60, 60), Qt::NoModifier));
tableViewPrivate->setSelectionStartPos(QPointF(60, 60));
tableViewPrivate->setSelectionEndPos(QPointF(-10, -10));
@@ -4708,8 +4713,9 @@ void tst_QQuickTableView::selectionBehaviorRows()
void tst_QQuickTableView::selectionBehaviorColumns()
{
- // Check that the TableView implement QQuickSelectableInterface setSelectionStartPos, setSelectionEndPos
- // and clearSelection correctly for QQuickTableView::SelectColumns.
+ // Check that the TableView implement QQuickSelectableInterface startSelection,
+ // setSelectionStartPos, setSelectionEndPos and clearSelection correctly for
+ // QQuickTableView::SelectColumns.
LOAD_TABLEVIEW("tableviewwithselected1.qml");
TestModel model(10, 10);
@@ -4724,6 +4730,7 @@ void tst_QQuickTableView::selectionBehaviorColumns()
QCOMPARE(selectionModel.hasSelection(), false);
// Drag from column 0 to column 3
+ QVERIFY(tableViewPrivate->startSelection(QPointF(60, 60), Qt::NoModifier));
tableViewPrivate->setSelectionStartPos(QPointF(0, 0));
tableViewPrivate->setSelectionEndPos(QPointF(60, 60));
@@ -4744,6 +4751,7 @@ void tst_QQuickTableView::selectionBehaviorColumns()
QCOMPARE(selectionModel.hasSelection(), false);
// Drag from column 3 to column 0 (and overshoot mouse)
+ QVERIFY(tableViewPrivate->startSelection(QPointF(60, 60), Qt::NoModifier));
tableViewPrivate->setSelectionStartPos(QPointF(60, 60));
tableViewPrivate->setSelectionEndPos(QPointF(-10, -10));
@@ -4762,8 +4770,8 @@ void tst_QQuickTableView::selectionBehaviorColumns()
void tst_QQuickTableView::selectionBehaviorDisabled()
{
- // Check that the TableView implement QQuickSelectableInterface setSelectionStartPos, setSelectionEndPos
- // and clearSelection correctly for QQuickTableView::SelectionDisabled.
+ // Check that the TableView implement QQuickSelectableInterface startSelection
+ // correctly for QQuickTableView::SelectionDisabled.
LOAD_TABLEVIEW("tableviewwithselected1.qml");
TestModel model(10, 10);
@@ -4777,18 +4785,18 @@ void tst_QQuickTableView::selectionBehaviorDisabled()
QCOMPARE(selectionModel.hasSelection(), false);
- // Drag from column 0 to column 3
- tableViewPrivate->setSelectionStartPos(QPointF(0, 0));
- tableViewPrivate->setSelectionEndPos(QPointF(60, 60));
+ // Try to start a selection
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*TableView.SelectionDisabled"));
+ QVERIFY(!tableViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
QCOMPARE(selectionModel.hasSelection(), false);
}
void tst_QQuickTableView::testSelectableStartPosEndPosOutsideView()
{
- // Call setSelectionStartPos and setSelectionEndPos with positions outside the view.
- // This should first of all not crash, but instead just clamp the selection to the
- // cells that are visible inside the view.
+ // Call startSelection, setSelectionStartPos and setSelectionEndPos with positions
+ // outside the view. This should first of all not crash, but instead just clamp the
+ // selection to the cells that are visible inside the view.
LOAD_TABLEVIEW("tableviewwithselected1.qml");
TestModel model(10, 10);
@@ -4809,6 +4817,7 @@ void tst_QQuickTableView::testSelectableStartPosEndPosOutsideView()
const QPointF outsideTop(centerPos.x(), -100);
const QPointF outsideBottom(centerPos.x(), tableView->height() + 100);
+ QVERIFY(tableViewPrivate->startSelection(centerPos, Qt::NoModifier));
tableViewPrivate->setSelectionStartPos(centerPos);
tableViewPrivate->setSelectionEndPos(outsideLeft);
diff --git a/tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp b/tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp
index d414cf8a1a..d41d811496 100644
--- a/tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp
+++ b/tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp
@@ -921,6 +921,7 @@ void tst_qquicktreeview::selectionBehaviorCells()
const QPointF endPos(endItem->x(), endItem->y());
const QPointF endPosWrapped(endItemWrapped->x(), endItemWrapped->y());
+ QVERIFY(treeViewPrivate->startSelection(startPos, Qt::NoModifier));
treeViewPrivate->setSelectionStartPos(startPos);
treeViewPrivate->setSelectionEndPos(endPos);
@@ -975,6 +976,7 @@ void tst_qquicktreeview::selectionBehaviorRows()
QCOMPARE(selectionModel->hasSelection(), false);
// Drag from row 0 to row 3
+ QVERIFY(treeViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
treeViewPrivate->setSelectionStartPos(QPointF(0, 0));
treeViewPrivate->setSelectionEndPos(QPointF(80, 60));
@@ -995,6 +997,7 @@ void tst_qquicktreeview::selectionBehaviorRows()
QCOMPARE(selectionModel->hasSelection(), false);
// Drag from row 3 to row 0 (and overshoot mouse)
+ QVERIFY(treeViewPrivate->startSelection(QPointF(80, 60), Qt::NoModifier));
treeViewPrivate->setSelectionStartPos(QPointF(80, 60));
treeViewPrivate->setSelectionEndPos(QPointF(-10, -10));
@@ -1026,6 +1029,7 @@ void tst_qquicktreeview::selectionBehaviorColumns()
QCOMPARE(selectionModel->hasSelection(), false);
// Drag from column 0 to column 3
+ QVERIFY(treeViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
treeViewPrivate->setSelectionStartPos(QPointF(0, 0));
treeViewPrivate->setSelectionEndPos(QPointF(225, 90));
@@ -1046,6 +1050,7 @@ void tst_qquicktreeview::selectionBehaviorColumns()
QCOMPARE(selectionModel->hasSelection(), false);
// Drag from column 3 to column 0 (and overshoot mouse)
+ QVERIFY(treeViewPrivate->startSelection(QPointF(225, 90), Qt::NoModifier));
treeViewPrivate->setSelectionStartPos(QPointF(225, 90));
treeViewPrivate->setSelectionEndPos(QPointF(-10, -10));
@@ -1075,10 +1080,11 @@ void tst_qquicktreeview::selectionBehaviorDisabled()
QCOMPARE(selectionModel->hasSelection(), false);
- // Drag from column 0 to column 3
- treeViewPrivate->setSelectionStartPos(QPointF(0, 0));
- treeViewPrivate->setSelectionEndPos(QPointF(60, 60));
-
+ // Try to start a selection. treeViewPrivate->startSelection() should
+ // reject that, and and return false. The selectionFlag will there stay as
+ // QItemSelectionModel::NoUpdate, meaning no active selection is ongoing.
+ QVERIFY(!treeViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
+ QCOMPARE(treeViewPrivate->selectionFlag, QItemSelectionModel::NoUpdate);
QCOMPARE(selectionModel->hasSelection(), false);
}
diff --git a/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml b/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml
index 302851db4a..879e8c68d4 100644
--- a/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml
@@ -436,6 +436,64 @@ TestCase {
verify(tableView.selectionModel.isSelected(tableView.model.index(r, c)))
}
+ function test_unselect_click() {
+ // Check at a ctrl click on top a selected cell
+ // will cause the cell to be unselected.
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ selectionRectangle.selectionMode = SelectionRectangle.Drag
+
+ // Select some cells
+ tableView.selectionModel.select(tableView.index(0, 0), ItemSelectionModel.Select)
+ tableView.selectionModel.select(tableView.index(0, 1), ItemSelectionModel.Select)
+ tableView.selectionModel.select(tableView.index(0, 3), ItemSelectionModel.Select)
+ tableView.selectionModel.select(tableView.index(1, 0), ItemSelectionModel.Select)
+ compare(tableView.selectionModel.selectedIndexes.length, 4)
+
+ // Do a ctrl-click on top of a selected cell. This
+ // should cause the cell to be unselected.
+ mouseClick(tableView, cellWidth / 2, cellHeight / 2, Qt.LeftButton, Qt.ControlModifier)
+ compare(tableView.selectionModel.selectedIndexes.length, 3)
+ 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(0, 3)))
+ verify(tableView.selectionModel.isSelected(tableView.model.index(1, 0)))
+ }
+
+ function test_unselect_drag() {
+ // Check at a ctrl drag on top a selected cell
+ // will cause the dragged-over cells to be unselected.
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ selectionRectangle.selectionMode = SelectionRectangle.Drag
+
+ // Select some cells
+ tableView.selectionModel.select(tableView.index(0, 0), ItemSelectionModel.Select)
+ tableView.selectionModel.select(tableView.index(0, 1), ItemSelectionModel.Select)
+ tableView.selectionModel.select(tableView.index(0, 3), ItemSelectionModel.Select)
+ tableView.selectionModel.select(tableView.index(1, 0), ItemSelectionModel.Select)
+ compare(tableView.selectionModel.selectedIndexes.length, 4)
+
+ // Do a ctrl-drag on top of the selected cells. This
+ // should cause all the cells to be unselected.
+ mousePress(tableView.contentItem, cellWidth / 2, cellHeight / 2, Qt.LeftButton, Qt.ControlModifier)
+ mouseMove(tableView.contentItem, cellWidth * 4, cellHeight * 2, 0, Qt.LeftButton, Qt.ControlModifier)
+ compare(tableView.selectionModel.selectedIndexes.length, 0)
+
+ // Move the mouse back to cell 2, and release the mouse. Only
+ // the top left cells will then be unselected
+ mouseMove(tableView.contentItem, (cellWidth * 2) - 1, (cellHeight * 2) - 1, 0, Qt.LeftButton, Qt.ControlModifier)
+ mouseRelease(tableView.contentItem, (cellWidth * 2) - 1, (cellHeight * 2) - 1, Qt.LeftButton, Qt.ControlModifier)
+ compare(tableView.selectionModel.selectedIndexes.length, 1)
+ verify(tableView.selectionModel.isSelected(tableView.model.index(0, 3)))
+ }
+
function test_handle_position() {
// Check that the handles end up at the corner of the selection
// even if if we resize some rows and column while they have