From 0644e3dce532b1df00a77d3a30c61d6b75d3ff30 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 17 Sep 2009 13:07:30 +0200 Subject: Control-drag header selection behaved wierdly. The QItemSelectionModel::Current was not set in QTableViewPrivate::selectColumn(). However, Control-drag selection in QTableView behaved differently than other software such as OpenOffice's spreadsheet. Now the behaviour when Control-dragging is that the selection will be set to the opposite of the selection state of the first cell. If that cell is selected, we will deselected the cells while dragging, and conversely, if it isn't selected, the cells will be selected. Reviewed-by: Olivier Task-number: QT-1435 Task-number: 191545 --- src/gui/itemviews/qabstractitemview.cpp | 12 ++++ src/gui/itemviews/qabstractitemview_p.h | 1 + src/gui/itemviews/qtableview.cpp | 28 +++++++- tests/auto/qtableview/tst_qtableview.cpp | 114 +++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 2 deletions(-) diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 9d977a5..757ded9 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -69,6 +69,7 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate() : model(QAbstractItemModelPrivate::staticEmptyModel()), itemDelegate(0), selectionModel(0), + ctrlDragSelectionFlag(QItemSelectionModel::NoUpdate), selectionMode(QAbstractItemView::ExtendedSelection), selectionBehavior(QAbstractItemView::SelectItems), currentlyCommittingEditor(0), @@ -1589,6 +1590,11 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); d->autoScroll = autoScroll; QRect rect(d->pressedPosition - offset, pos); + if (command.testFlag(QItemSelectionModel::Toggle)) { + command &= ~QItemSelectionModel::Toggle; + d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select; + command |= d->ctrlDragSelectionFlag; + } setSelection(rect, command); // signal handlers may change the model @@ -1659,6 +1665,10 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) if ((event->buttons() & Qt::LeftButton) && d->selectionAllowed(index) && d->selectionModel) { setState(DragSelectingState); QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); + if (command.testFlag(QItemSelectionModel::Toggle)) { + command &= ~QItemSelectionModel::Toggle; + command |= d->ctrlDragSelectionFlag; + } // Do the normalize ourselves, since QRect::normalized() is flawed QRect selectionRect = QRect(topLeft, bottomRight); @@ -1699,6 +1709,8 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers); bool edited = edit(index, trigger, event); + d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate; + //in the case the user presses on no item we might decide to clear the selection if (d->selectionModel && !index.isValid()) d->selectionModel->select(QModelIndex(), selectionCommand(index, event)); diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h index 725d0a9..6b1ec8e 100644 --- a/src/gui/itemviews/qabstractitemview_p.h +++ b/src/gui/itemviews/qabstractitemview_p.h @@ -342,6 +342,7 @@ public: QMap > rowDelegates; QMap > columnDelegates; QPointer selectionModel; + QItemSelectionModel::SelectionFlag ctrlDragSelectionFlag; QAbstractItemView::SelectionMode selectionMode; QAbstractItemView::SelectionBehavior selectionBehavior; diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index 684da3f..f1ffaa6 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -2519,9 +2519,21 @@ void QTableViewPrivate::selectRow(int row, bool anchor) QModelIndex index = model->index(row, column, root); QItemSelectionModel::SelectionFlags command = q->selectionCommand(index); selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); - if ((!(command & QItemSelectionModel::Current) && anchor) + if ((anchor && !(command & QItemSelectionModel::Current)) || (q->selectionMode() == QTableView::SingleSelection)) rowSectionAnchor = row; + + if (q->selectionMode() != QTableView::SingleSelection + && command.testFlag(QItemSelectionModel::Toggle)) { + if (anchor) + ctrlDragSelectionFlag = verticalHeader->selectionModel()->selectedRows().contains(index) + ? QItemSelectionModel::Deselect : QItemSelectionModel::Select; + command &= ~QItemSelectionModel::Toggle; + command |= ctrlDragSelectionFlag; + if (!anchor) + command |= QItemSelectionModel::Current; + } + QModelIndex tl = model->index(qMin(rowSectionAnchor, row), 0, root); QModelIndex br = model->index(qMax(rowSectionAnchor, row), model->columnCount(root) - 1, root); if (verticalHeader->sectionsMoved() && tl.row() != br.row()) @@ -2545,9 +2557,21 @@ void QTableViewPrivate::selectColumn(int column, bool anchor) QModelIndex index = model->index(row, column, root); QItemSelectionModel::SelectionFlags command = q->selectionCommand(index); selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); - if ((!(command & QItemSelectionModel::Current) && anchor) + if ((anchor && !(command & QItemSelectionModel::Current)) || (q->selectionMode() == QTableView::SingleSelection)) columnSectionAnchor = column; + + if (q->selectionMode() != QTableView::SingleSelection + && command.testFlag(QItemSelectionModel::Toggle)) { + if (anchor) + ctrlDragSelectionFlag = horizontalHeader->selectionModel()->selectedColumns().contains(index) + ? QItemSelectionModel::Deselect : QItemSelectionModel::Select; + command &= ~QItemSelectionModel::Toggle; + command |= ctrlDragSelectionFlag; + if (!anchor) + command |= QItemSelectionModel::Current; + } + QModelIndex tl = model->index(0, qMin(columnSectionAnchor, column), root); QModelIndex br = model->index(model->rowCount(root) - 1, qMax(columnSectionAnchor, column), root); diff --git a/tests/auto/qtableview/tst_qtableview.cpp b/tests/auto/qtableview/tst_qtableview.cpp index 8d9a50c..48fcb3e 100644 --- a/tests/auto/qtableview/tst_qtableview.cpp +++ b/tests/auto/qtableview/tst_qtableview.cpp @@ -43,6 +43,7 @@ #include #include #include "../../shared/util.h" +#include "private/qapplication_p.h" //TESTED_CLASS= //TESTED_FILES= @@ -179,6 +180,7 @@ private slots: void task240266_veryBigColumn(); void task248688_autoScrollNavigation(); void task259308_scrollVerticalHeaderSwappedSections(); + void task191545_dragSelectRows(); void mouseWheel_data(); void mouseWheel(); @@ -3300,5 +3302,117 @@ void tst_QTableView::task259308_scrollVerticalHeaderSwappedSections() QTRY_COMPARE(tv.rowAt(tv.viewport()->height() - 1), tv.verticalHeader()->logicalIndex(model.rowCount() - 1)); } +template +struct ValueSaver { + T &var, value; + ValueSaver(T &v) : var(v), value(v) { } + ~ValueSaver() { var = value; } +}; + +void tst_QTableView::task191545_dragSelectRows() +{ + QStandardItemModel model(10, 10); + QTableView table; + table.setModel(&model); + table.setSelectionBehavior(QAbstractItemView::SelectItems); + table.setSelectionMode(QAbstractItemView::ExtendedSelection); + table.setMinimumSize(1000, 400); + table.show(); + QTest::qWait(200); + + ValueSaver saver(QApplicationPrivate::modifier_buttons); + QApplicationPrivate::modifier_buttons = Qt::ControlModifier; + + { + QRect cellRect = table.visualRect(model.index(3, 0)); + QHeaderView *vHeader = table.verticalHeader(); + QWidget *vHeaderVp = vHeader->viewport(); + QPoint rowPos(5, (cellRect.top() + cellRect.bottom()) / 2); + QMouseEvent rowPressEvent(QEvent::MouseButtonPress, rowPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); + qApp->sendEvent(vHeaderVp, &rowPressEvent); + + for (int i = 0; i < 4; ++i) { + rowPos.setY(rowPos.y() + cellRect.height()); + QMouseEvent moveEvent(QEvent::MouseMove, rowPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier); + qApp->sendEvent(vHeaderVp, &moveEvent); + } + QMouseEvent rowReleaseEvent(QEvent::MouseButtonRelease, rowPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); + qApp->sendEvent(vHeaderVp, &rowReleaseEvent); + + for (int i = 0; i < 4; ++i) { + QModelIndex index = model.index(3 + i, 0, table.rootIndex()); + QVERIFY(vHeader->selectionModel()->selectedRows().contains(index)); + } + } + + { + QRect cellRect = table.visualRect(model.index(0, 3)); + QHeaderView *hHeader = table.horizontalHeader(); + QWidget *hHeaderVp = hHeader->viewport(); + QPoint colPos((cellRect.left() + cellRect.right()) / 2, 5); + QMouseEvent colPressEvent(QEvent::MouseButtonPress, colPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); + qApp->sendEvent(hHeaderVp, &colPressEvent); + + for (int i = 0; i < 4; ++i) { + colPos.setX(colPos.x() + cellRect.width()); + QMouseEvent moveEvent(QEvent::MouseMove, colPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier); + qApp->sendEvent(hHeaderVp, &moveEvent); + } + QMouseEvent colReleaseEvent(QEvent::MouseButtonRelease, colPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); + qApp->sendEvent(hHeaderVp, &colReleaseEvent); + + for (int i = 0; i < 4; ++i) { + QModelIndex index = model.index(0, 3 + i, table.rootIndex()); + QVERIFY(hHeader->selectionModel()->selectedColumns().contains(index)); + } + } + + { + QRect cellRect = table.visualRect(model.index(2, 2)); + QWidget *tableVp = table.viewport(); + QPoint cellPos = cellRect.center(); + QMouseEvent cellPressEvent(QEvent::MouseButtonPress, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); + qApp->sendEvent(tableVp, &cellPressEvent); + + for (int i = 0; i < 6; ++i) { + cellPos.setX(cellPos.x() + cellRect.width()); + cellPos.setY(cellPos.y() + cellRect.height()); + QMouseEvent moveEvent(QEvent::MouseMove, cellPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier); + qApp->sendEvent(tableVp, &moveEvent); + } + QMouseEvent cellReleaseEvent(QEvent::MouseButtonRelease, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); + qApp->sendEvent(tableVp, &cellReleaseEvent); + + for (int i = 0; i < 6; ++i) + for (int j = 0; j < 6; ++j) { + QModelIndex index = model.index(2 + i, 2 + j, table.rootIndex()); + QVERIFY(table.selectionModel()->isSelected(index)); + } + } + + { + QRect cellRect = table.visualRect(model.index(3, 3)); + QWidget *tableVp = table.viewport(); + QPoint cellPos = cellRect.center(); + QMouseEvent cellPressEvent(QEvent::MouseButtonPress, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); + qApp->sendEvent(tableVp, &cellPressEvent); + + for (int i = 0; i < 6; ++i) { + cellPos.setX(cellPos.x() + cellRect.width()); + cellPos.setY(cellPos.y() + cellRect.height()); + QMouseEvent moveEvent(QEvent::MouseMove, cellPos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier); + qApp->sendEvent(tableVp, &moveEvent); + } + QMouseEvent cellReleaseEvent(QEvent::MouseButtonRelease, cellPos, Qt::LeftButton, Qt::NoButton, Qt::ControlModifier); + qApp->sendEvent(tableVp, &cellReleaseEvent); + + for (int i = 0; i < 6; ++i) + for (int j = 0; j < 6; ++j) { + QModelIndex index = model.index(3 + i, 3 + j, table.rootIndex()); + QVERIFY(!table.selectionModel()->isSelected(index)); + } + } +} + QTEST_MAIN(tst_QTableView) #include "tst_qtableview.moc" -- cgit v0.12