Select a single range of cells in QTableView, away from merged cells
- when there is no intersection between the current selection and the spans collection, get ranges for all cells, just as if no span exists - when there is an intersection between the current selection and the spans collection, get separate ranges for each cell (as before) This fixes the regular case of selecting multiple non-spanned cells after some cells are merged (get a single range for all cells instead of separate range for each cell). However, when selecting together a group of spanned and non-spanned cells, you still get a separate range for each cell. But this is normal behavior in similar applications; for example in LibreOffice, you cannot select and merge spanned and non-spanned cells: an error dialog tells you that it's not allowed. Done-with: Christos Kokkinidis Pick-to: 6.2 Fixes: QTBUG-255 Change-Id: Ic38f9a064a1f499825e7f750668013fc2dc564ba Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
9a77230685
commit
826765f654
@ -2004,6 +2004,9 @@ void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF
|
||||
|
||||
if (d->hasSpans()) {
|
||||
bool expanded;
|
||||
// when the current selection does not intersect with any spans of merged cells,
|
||||
// the range of selected cells must be the same as if there were no merged cells
|
||||
bool intersectsSpan = false;
|
||||
int top = qMin(d->visualRow(tl.row()), d->visualRow(br.row()));
|
||||
int left = qMin(d->visualColumn(tl.column()), d->visualColumn(br.column()));
|
||||
int bottom = qMax(d->visualRow(tl.row()), d->visualRow(br.row()));
|
||||
@ -2018,6 +2021,7 @@ void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF
|
||||
int r = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
|
||||
if ((t > bottom) || (l > right) || (top > b) || (left > r))
|
||||
continue; // no intersect
|
||||
intersectsSpan = true;
|
||||
if (t < top) {
|
||||
top = t;
|
||||
expanded = true;
|
||||
@ -2038,14 +2042,20 @@ void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF
|
||||
break;
|
||||
}
|
||||
} while (expanded);
|
||||
selection.reserve((right - left + 1) * (bottom - top + 1));
|
||||
for (int horizontal = left; horizontal <= right; ++horizontal) {
|
||||
int column = d->logicalColumn(horizontal);
|
||||
for (int vertical = top; vertical <= bottom; ++vertical) {
|
||||
int row = d->logicalRow(vertical);
|
||||
QModelIndex index = d->model->index(row, column, d->root);
|
||||
selection.append(QItemSelectionRange(index));
|
||||
if (intersectsSpan) {
|
||||
selection.reserve((right - left + 1) * (bottom - top + 1));
|
||||
for (int horizontal = left; horizontal <= right; ++horizontal) {
|
||||
int column = d->logicalColumn(horizontal);
|
||||
for (int vertical = top; vertical <= bottom; ++vertical) {
|
||||
int row = d->logicalRow(vertical);
|
||||
QModelIndex index = d->model->index(row, column, d->root);
|
||||
selection.append(QItemSelectionRange(index));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QItemSelectionRange range(tl, br);
|
||||
if (!range.isEmpty())
|
||||
selection.append(range);
|
||||
}
|
||||
} else if (verticalMoved && horizontalMoved) {
|
||||
int top = d->visualRow(tl.row());
|
||||
|
@ -61,6 +61,8 @@ private slots:
|
||||
void takeItem();
|
||||
void selectedItems_data();
|
||||
void selectedItems();
|
||||
void selectedSpannedCells_data();
|
||||
void selectedSpannedCells();
|
||||
void removeRow_data();
|
||||
void removeRow();
|
||||
void removeColumn_data();
|
||||
@ -585,6 +587,75 @@ void tst_QTableWidget::selectedItems()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QTableWidget::selectedSpannedCells_data()
|
||||
{
|
||||
QTest::addColumn<QRect>("spannedCells"); // in cells, not pixels
|
||||
QTest::addColumn<QPoint>("selectionStartCell");
|
||||
QTest::addColumn<QPoint>("selectionEndCell");
|
||||
QTest::addColumn<int>("expectedSelectionRangeCount");
|
||||
QTest::addColumn<QTableWidgetSelectionRange>("expectedFirstSelectionRange");
|
||||
|
||||
QTest::newRow("merge 2 cells in column, select adjacent left")
|
||||
<< QRect(1, 2, 1, 2) << QPoint(0, 1) << QPoint(0, 3)
|
||||
<< 1 << QTableWidgetSelectionRange(1, 0, 3, 0);
|
||||
|
||||
QTest::newRow("merge 2 cells in column, select those and one more")
|
||||
<< QRect(1, 2, 1, 2) << QPoint(1, 1) << QPoint(1, 3)
|
||||
<< 3 << QTableWidgetSelectionRange(1, 1, 1, 1);
|
||||
|
||||
QTest::newRow("merge 2 cells in column, select rows above")
|
||||
<< QRect(1, 2, 1, 2) << QPoint(0, 0) << QPoint(3, 1)
|
||||
<< 1 << QTableWidgetSelectionRange(0, 0, 1, 3);
|
||||
|
||||
QTest::newRow("merge 4 cells in column, select adjacent right")
|
||||
<< QRect(1, 0, 1, 4) << QPoint(2, 0) << QPoint(3, 3)
|
||||
<< 1 << QTableWidgetSelectionRange(0, 2, 3, 3);
|
||||
|
||||
QTest::newRow("merge 3 cells in row, select those and one more")
|
||||
<< QRect(0, 1, 3, 1) << QPoint(0, 1) << QPoint(3, 1)
|
||||
<< 4 << QTableWidgetSelectionRange(1, 0, 1, 0);
|
||||
|
||||
QTest::newRow("merge 3 cells in row, select adjacent to right")
|
||||
<< QRect(0, 1, 3, 1) << QPoint(3, 0) << QPoint(3, 2)
|
||||
<< 1 << QTableWidgetSelectionRange(0, 3, 2, 3);
|
||||
|
||||
QTest::newRow("merge 3 cells in row, select adjacent above")
|
||||
<< QRect(0, 2, 3, 2) << QPoint(0, 1) << QPoint(2, 1)
|
||||
<< 1 << QTableWidgetSelectionRange(1, 0, 1, 2);
|
||||
}
|
||||
|
||||
void tst_QTableWidget::selectedSpannedCells() // QTBUG-255
|
||||
{
|
||||
QFETCH(QRect, spannedCells);
|
||||
QFETCH(QPoint, selectionStartCell);
|
||||
QFETCH(QPoint, selectionEndCell);
|
||||
QFETCH(int, expectedSelectionRangeCount);
|
||||
QFETCH(const QTableWidgetSelectionRange, expectedFirstSelectionRange);
|
||||
|
||||
QTableWidget testWidget(4, 4);
|
||||
testWidget.resize(600, 200);
|
||||
testWidget.show();
|
||||
|
||||
// create and set items
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
for (int r = 0; r < 4; ++r)
|
||||
testWidget.setItem(r, c, new QTableWidgetItem(QString("Item %1 %2").arg(c).arg(r)));
|
||||
}
|
||||
|
||||
// merge some cells
|
||||
testWidget.setSpan(spannedCells.top(), spannedCells.left(), spannedCells.height(), spannedCells.width());
|
||||
|
||||
// click one cell and shift-click another, to select a range
|
||||
QTest::mouseClick(testWidget.viewport(), Qt::LeftButton, Qt::NoModifier,
|
||||
testWidget.visualRect(testWidget.model()->index(selectionStartCell.y(), selectionStartCell.x())).center());
|
||||
QTest::mouseClick(testWidget.viewport(), Qt::LeftButton, Qt::ShiftModifier,
|
||||
testWidget.visualRect(testWidget.model()->index(selectionEndCell.y(), selectionEndCell.x())).center());
|
||||
|
||||
auto ranges = testWidget.selectedRanges();
|
||||
QCOMPARE(ranges.count(), expectedSelectionRangeCount);
|
||||
QCOMPARE(ranges.first(), expectedFirstSelectionRange);
|
||||
}
|
||||
|
||||
void tst_QTableWidget::removeRow_data()
|
||||
{
|
||||
QTest::addColumn<int>("rowCount");
|
||||
|
Loading…
Reference in New Issue
Block a user