summaryrefslogtreecommitdiffstats
path: root/src/widgets/itemviews/qtableview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/itemviews/qtableview.cpp')
-rw-r--r--src/widgets/itemviews/qtableview.cpp371
1 files changed, 203 insertions, 168 deletions
diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp
index b261ee837d..5726348bc5 100644
--- a/src/widgets/itemviews/qtableview.cpp
+++ b/src/widgets/itemviews/qtableview.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtableview.h"
#include <qheaderview.h>
-#include <qitemdelegate.h>
+#include <qabstractitemdelegate.h>
#include <qapplication.h>
#include <qpainter.h>
#include <qstyle.h>
@@ -55,7 +19,7 @@
#include <private/qtableview_p.h>
#include <private/qheaderview_p.h>
#include <private/qscrollbar_p.h>
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
#include <qaccessible.h>
#endif
@@ -206,6 +170,13 @@ QDebug operator<<(QDebug str, const QSpanCollection::Span &span)
str << '(' << span.top() << ',' << span.left() << ',' << span.bottom() << ',' << span.right() << ')';
return str;
}
+
+QDebug operator<<(QDebug debug, const QSpanCollection::SpanList &spans)
+{
+ for (const auto *span : spans)
+ debug << span << *span;
+ return debug;
+}
#endif
/** \internal
@@ -236,8 +207,7 @@ void QSpanCollection::updateInsertedRows(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug("After");
- foreach (QSpanCollection::Span *span, spans)
- qDebug() << span << *span;
+ qDebug() << spans;
#endif
for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
@@ -283,8 +253,7 @@ void QSpanCollection::updateInsertedColumns(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug("After");
- foreach (QSpanCollection::Span *span, spans)
- qDebug() << span << *span;
+ qDebug() << spans;
#endif
for (Index::iterator it_y = index.begin(); it_y != index.end(); ++it_y) {
@@ -388,8 +357,7 @@ void QSpanCollection::updateRemovedRows(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug("After");
- foreach (QSpanCollection::Span *span, spans)
- qDebug() << span << *span;
+ qDebug() << spans;
#endif
if (spans.empty()) {
qDeleteAll(spansToBeDeleted);
@@ -456,8 +424,7 @@ void QSpanCollection::updateRemovedRows(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug() << index;
qDebug("Deleted");
- foreach (QSpanCollection::Span *span, spansToBeDeleted)
- qDebug() << span << *span;
+ qDebug() << spansToBeDeleted;
#endif
qDeleteAll(spansToBeDeleted);
}
@@ -515,8 +482,7 @@ void QSpanCollection::updateRemovedColumns(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug("After");
- foreach (QSpanCollection::Span *span, spans)
- qDebug() << span << *span;
+ qDebug() << spans;
#endif
if (spans.empty()) {
qDeleteAll(toBeDeleted);
@@ -535,8 +501,7 @@ void QSpanCollection::updateRemovedColumns(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug() << index;
qDebug("Deleted");
- foreach (QSpanCollection::Span *span, toBeDeleted)
- qDebug() << span << *span;
+ qDebug() << toBeDeleted;
#endif
qDeleteAll(toBeDeleted);
}
@@ -628,7 +593,25 @@ void QTableViewPrivate::init()
#if QT_CONFIG(abstractbutton)
cornerWidget = new QTableCornerButton(q);
cornerWidget->setFocusPolicy(Qt::NoFocus);
- QObject::connect(cornerWidget, SIGNAL(clicked()), q, SLOT(selectAll()));
+ cornerWidgetConnection = QObject::connect(
+ cornerWidget, &QTableCornerButton::clicked,
+ q, &QTableView::selectAll);
+#endif
+}
+
+void QTableViewPrivate::clearConnections()
+{
+ for (const QMetaObject::Connection &connection : modelConnections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : verHeaderConnections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : horHeaderConnections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : dynHorHeaderConnections)
+ QObject::disconnect(connection);
+ QObject::disconnect(selectionmodelConnection);
+#if QT_CONFIG(abstractbutton)
+ QObject::disconnect(cornerWidgetConnection);
#endif
}
@@ -918,13 +901,32 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter,
visibleSpans = spans.spansInRect(logicalColumn(firstVisualColumn), logicalRow(firstVisualRow),
lastVisualColumn - firstVisualColumn + 1, lastVisualRow - firstVisualRow + 1);
} else {
- for(int x = firstVisualColumn; x <= lastVisualColumn; x++)
- for(int y = firstVisualRow; y <= lastVisualRow; y++)
- visibleSpans.insert(spans.spanAt(x,y));
- visibleSpans.remove(nullptr);
- }
-
- for (QSpanCollection::Span *span : qAsConst(visibleSpans)) {
+ // Any cell outside the viewport, on the top or left, can still end up visible inside the
+ // viewport if is has a span. Calculating if a spanned cell overlaps with the viewport is
+ // "easy" enough when the columns (or rows) in the view are aligned with the columns
+ // in the model; In that case you know that if a column is outside the viewport on the
+ // right, it cannot affect the drawing of the cells inside the viewport, even with a span.
+ // And under that assumption, the spansInRect() function can be used (which is optimized
+ // to only iterate the spans that are close to the viewport).
+ // But when the view has rearranged the columns (or rows), this is no longer true. In that
+ // case, even if a column, according to the model, is outside the viewport on the right, it
+ // can still overlap with the viewport. This can happen if it was moved to the left of the
+ // viewport and one of its cells has a span. In that case we need to take the theoretically
+ // slower route and iterate through all the spans, and check if any of them overlaps with
+ // the viewport.
+ const auto spanList = spans.spans;
+ for (QSpanCollection::Span *span : spanList) {
+ const int spanVisualLeft = visualColumn(span->left());
+ const int spanVisualTop = visualRow(span->top());
+ const int spanVisualRight = spanVisualLeft + span->width() - 1;
+ const int spanVisualBottom = spanVisualTop + span->height() - 1;
+ if ((spanVisualLeft <= lastVisualColumn && spanVisualRight >= firstVisualColumn)
+ && (spanVisualTop <= lastVisualRow && spanVisualBottom >= firstVisualRow))
+ visibleSpans.insert(span);
+ }
+ }
+
+ for (QSpanCollection::Span *span : std::as_const(visibleSpans)) {
int row = span->top();
int col = span->left();
QModelIndex index = model->index(row, col, root);
@@ -973,7 +975,7 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter,
\internal
Updates spans after row insertion.
*/
-void QTableViewPrivate::_q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end)
+void QTableViewPrivate::updateSpanInsertedRows(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent);
spans.updateInsertedRows(start, end);
@@ -983,7 +985,7 @@ void QTableViewPrivate::_q_updateSpanInsertedRows(const QModelIndex &parent, int
\internal
Updates spans after column insertion.
*/
-void QTableViewPrivate::_q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end)
+void QTableViewPrivate::updateSpanInsertedColumns(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent);
spans.updateInsertedColumns(start, end);
@@ -993,7 +995,7 @@ void QTableViewPrivate::_q_updateSpanInsertedColumns(const QModelIndex &parent,
\internal
Updates spans after row removal.
*/
-void QTableViewPrivate::_q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end)
+void QTableViewPrivate::updateSpanRemovedRows(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent);
spans.updateRemovedRows(start, end);
@@ -1003,7 +1005,7 @@ void QTableViewPrivate::_q_updateSpanRemovedRows(const QModelIndex &parent, int
\internal
Updates spans after column removal.
*/
-void QTableViewPrivate::_q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end)
+void QTableViewPrivate::updateSpanRemovedColumns(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent);
spans.updateRemovedColumns(start, end);
@@ -1013,7 +1015,7 @@ void QTableViewPrivate::_q_updateSpanRemovedColumns(const QModelIndex &parent, i
\internal
Sort the model when the header sort indicator changed
*/
-void QTableViewPrivate::_q_sortIndicatorChanged(int column, Qt::SortOrder order)
+void QTableViewPrivate::sortIndicatorChanged(int column, Qt::SortOrder order)
{
model->sort(column, order);
}
@@ -1165,6 +1167,8 @@ int QTableViewPrivate::heightHintForIndex(const QModelIndex &index, int hint, QS
table can be found by using rowHeight(); similarly, the width of
columns can be found using columnWidth(). Since both of these are plain
widgets, you can hide either of them using their hide() functions.
+ Each header is configured with its \l{QHeaderView::}{highlightSections}
+ and \l{QHeaderView::}{sectionsClickable} properties set to \c true.
Rows and columns can be hidden and shown with hideRow(), hideColumn(),
showRow(), and showColumn(). They can be selected with selectRow()
@@ -1203,7 +1207,7 @@ int QTableViewPrivate::heightHintForIndex(const QModelIndex &index, int hint, QS
operations between x-coordinates and column indexes.
\sa QTableWidget, {View Classes}, QAbstractItemModel, QAbstractItemView,
- {Chart Example}, {Pixelator Example}, {Table Model Example}
+ {Table Model Example}
*/
/*!
@@ -1234,6 +1238,8 @@ QTableView::QTableView(QTableViewPrivate &dd, QWidget *parent)
*/
QTableView::~QTableView()
{
+ Q_D(QTableView);
+ d->clearConnections();
}
/*!
@@ -1257,28 +1263,23 @@ void QTableView::setModel(QAbstractItemModel *model)
return;
//let's disconnect from the old model
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
- disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
+ for (const QMetaObject::Connection &connection : d->modelConnections)
+ disconnect(connection);
}
if (d->selectionModel) { // support row editing
- disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
+ disconnect(d->selectionmodelConnection);
}
if (model) { //and connect to the new one
- connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
- connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
- connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
- connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
+ d->modelConnections = {
+ QObjectPrivate::connect(model, &QAbstractItemModel::rowsInserted,
+ d, &QTableViewPrivate::updateSpanInsertedRows),
+ QObjectPrivate::connect(model, &QAbstractItemModel::columnsInserted,
+ d, &QTableViewPrivate::updateSpanInsertedColumns),
+ QObjectPrivate::connect(model, &QAbstractItemModel::rowsRemoved,
+ d, &QTableViewPrivate::updateSpanRemovedRows),
+ QObjectPrivate::connect(model, &QAbstractItemModel::columnsRemoved,
+ d, &QTableViewPrivate::updateSpanRemovedColumns)
+ };
}
d->verticalHeader->setModel(model);
d->horizontalHeader->setModel(model);
@@ -1320,8 +1321,7 @@ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
Q_ASSERT(selectionModel);
if (d->selectionModel) {
// support row editing
- disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
+ disconnect(d->selectionmodelConnection);
}
d->verticalHeader->setSelectionModel(selectionModel);
@@ -1330,8 +1330,9 @@ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
if (d->selectionModel) {
// support row editing
- connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
+ d->selectionmodelConnection =
+ connect(d->selectionModel, &QItemSelectionModel::currentRowChanged,
+ d->model, &QAbstractItemModel::submit);
}
}
@@ -1368,6 +1369,8 @@ void QTableView::setHorizontalHeader(QHeaderView *header)
if (!header || header == d->horizontalHeader)
return;
+ for (const QMetaObject::Connection &connection : d->horHeaderConnections)
+ disconnect(connection);
if (d->horizontalHeader && d->horizontalHeader->parent() == this)
delete d->horizontalHeader;
d->horizontalHeader = header;
@@ -1379,18 +1382,18 @@ void QTableView::setHorizontalHeader(QHeaderView *header)
d->horizontalHeader->setSelectionModel(d->selectionModel);
}
- connect(d->horizontalHeader,SIGNAL(sectionResized(int,int,int)),
- this, SLOT(columnResized(int,int,int)));
- connect(d->horizontalHeader, SIGNAL(sectionMoved(int,int,int)),
- this, SLOT(columnMoved(int,int,int)));
- connect(d->horizontalHeader, SIGNAL(sectionCountChanged(int,int)),
- this, SLOT(columnCountChanged(int,int)));
- connect(d->horizontalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int)));
- connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectColumn(int)));
- connect(d->horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
- this, SLOT(resizeColumnToContents(int)));
- connect(d->horizontalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
-
+ d->horHeaderConnections = {
+ connect(d->horizontalHeader,&QHeaderView::sectionResized,
+ this, &QTableView::columnResized),
+ connect(d->horizontalHeader, &QHeaderView::sectionMoved,
+ this, &QTableView::columnMoved),
+ connect(d->horizontalHeader, &QHeaderView::sectionCountChanged,
+ this, &QTableView::columnCountChanged),
+ connect(d->horizontalHeader, &QHeaderView::sectionHandleDoubleClicked,
+ this, &QTableView::resizeColumnToContents),
+ connect(d->horizontalHeader, &QHeaderView::geometriesChanged,
+ this, &QTableView::updateGeometries),
+ };
//update the sorting enabled states on the new header
setSortingEnabled(d->sortingEnabled);
}
@@ -1406,6 +1409,8 @@ void QTableView::setVerticalHeader(QHeaderView *header)
if (!header || header == d->verticalHeader)
return;
+ for (const QMetaObject::Connection &connection : d->verHeaderConnections)
+ disconnect(connection);
if (d->verticalHeader && d->verticalHeader->parent() == this)
delete d->verticalHeader;
d->verticalHeader = header;
@@ -1417,17 +1422,22 @@ void QTableView::setVerticalHeader(QHeaderView *header)
d->verticalHeader->setSelectionModel(d->selectionModel);
}
- connect(d->verticalHeader, SIGNAL(sectionResized(int,int,int)),
- this, SLOT(rowResized(int,int,int)));
- connect(d->verticalHeader, SIGNAL(sectionMoved(int,int,int)),
- this, SLOT(rowMoved(int,int,int)));
- connect(d->verticalHeader, SIGNAL(sectionCountChanged(int,int)),
- this, SLOT(rowCountChanged(int,int)));
- connect(d->verticalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectRow(int)));
- connect(d->verticalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectRow(int)));
- connect(d->verticalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
- this, SLOT(resizeRowToContents(int)));
- connect(d->verticalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
+ d->verHeaderConnections = {
+ connect(d->verticalHeader, &QHeaderView::sectionResized,
+ this, &QTableView::rowResized),
+ connect(d->verticalHeader, &QHeaderView::sectionMoved,
+ this, &QTableView::rowMoved),
+ connect(d->verticalHeader, &QHeaderView::sectionCountChanged,
+ this, &QTableView::rowCountChanged),
+ connect(d->verticalHeader, &QHeaderView::sectionPressed,
+ this, &QTableView::selectRow),
+ connect(d->verticalHeader, &QHeaderView::sectionHandleDoubleClicked,
+ this, &QTableView::resizeRowToContents),
+ connect(d->verticalHeader, &QHeaderView::geometriesChanged,
+ this, &QTableView::updateGeometries),
+ connect(d->verticalHeader, &QHeaderView::sectionEntered,
+ this, [d](int row) { d->selectRow(row, false); })
+ };
}
/*!
@@ -1496,7 +1506,7 @@ void QTableView::paintEvent(QPaintEvent *event)
const int gridSize = showGrid ? 1 : 0;
const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);
const QColor gridColor = QColor::fromRgba(static_cast<QRgb>(gridHint));
- const QPen gridPen = QPen(gridColor, 0, d->gridStyle);
+ const QPen gridPen = QPen(gridColor, 1, d->gridStyle);
const QHeaderView *verticalHeader = d->verticalHeader;
const QHeaderView *horizontalHeader = d->horizontalHeader;
const bool alternate = d->alternatingColors;
@@ -1630,7 +1640,8 @@ void QTableView::paintEvent(QPaintEvent *event)
int rowY = rowViewportPosition(row);
rowY += offset.y();
int rowh = rowHeight(row) - gridSize;
- painter.drawLine(dirtyArea.left(), rowY + rowh, dirtyArea.right(), rowY + rowh);
+ QLineF line(dirtyArea.left(), rowY + rowh, dirtyArea.right(), rowY + rowh);
+ painter.drawLine(line.translated(0.5, 0.5));
}
// Paint each column
@@ -1642,7 +1653,30 @@ void QTableView::paintEvent(QPaintEvent *event)
colp += offset.x();
if (!rightToLeft)
colp += columnWidth(col) - gridSize;
- painter.drawLine(colp, dirtyArea.top(), colp, dirtyArea.bottom());
+ QLineF line(colp, dirtyArea.top(), colp, dirtyArea.bottom());
+ painter.drawLine(line.translated(0.5, 0.5));
+ }
+ const bool drawWhenHidden = style()->styleHint(QStyle::SH_Table_AlwaysDrawLeftTopGridLines,
+ &option, this);
+ if (drawWhenHidden && horizontalHeader->isHidden()) {
+ const int row = verticalHeader->logicalIndex(top);
+ if (!verticalHeader->isSectionHidden(row)) {
+ const int rowY = rowViewportPosition(row) + offset.y();
+ if (rowY == dirtyArea.top())
+ painter.drawLine(dirtyArea.left(), rowY, dirtyArea.right(), rowY);
+ }
+ }
+ if (drawWhenHidden && verticalHeader->isHidden()) {
+ const int col = horizontalHeader->logicalIndex(left);
+ if (!horizontalHeader->isSectionHidden(col)) {
+ int colX = columnViewportPosition(col) + offset.x();
+ if (!isLeftToRight())
+ colX += columnWidth(left) - 1;
+ if (isLeftToRight() && colX == dirtyArea.left())
+ painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom());
+ if (!isLeftToRight() && colX == dirtyArea.right())
+ painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom());
+ }
}
painter.setPen(old);
}
@@ -1982,6 +2016,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()));
@@ -1996,6 +2033,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;
@@ -2016,14 +2054,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());
@@ -2178,7 +2222,7 @@ QModelIndexList QTableView::selectedIndexes() const
QModelIndexList modelSelected;
if (d->selectionModel)
modelSelected = d->selectionModel->selectedIndexes();
- for (int i = 0; i < modelSelected.count(); ++i) {
+ for (int i = 0; i < modelSelected.size(); ++i) {
QModelIndex index = modelSelected.at(i);
if (!isIndexHidden(index) && index.parent() == d->root)
viewSelected.append(index);
@@ -2388,12 +2432,12 @@ int QTableView::sizeHintForRow(int row) const
break;
}
- int actualRight = d->model->columnCount(d->root) - 1;
+ const int actualRight = d->model->columnCount(d->root) - 1;
int idxLeft = left;
int idxRight = column - 1;
- if (maximumProcessCols == 0)
- columnsProcessed = 0; // skip the while loop
+ if (maximumProcessCols == 0 || actualRight < idxLeft)
+ columnsProcessed = maximumProcessCols; // skip the while loop
while (columnsProcessed != maximumProcessCols && (idxLeft > 0 || idxRight < actualRight)) {
int logicalIdx = -1;
@@ -2417,11 +2461,10 @@ int QTableView::sizeHintForRow(int row) const
break;
}
}
- if (logicalIdx < 0)
- continue;
-
- index = d->model->index(row, logicalIdx, d->root);
- hint = d->heightHintForIndex(index, hint, option);
+ if (logicalIdx >= 0) {
+ index = d->model->index(row, logicalIdx, d->root);
+ hint = d->heightHintForIndex(index, hint, option);
+ }
++columnsProcessed;
}
@@ -2477,12 +2520,12 @@ int QTableView::sizeHintForColumn(int column) const
break;
}
- int actualBottom = d->model->rowCount(d->root) - 1;
+ const int actualBottom = d->model->rowCount(d->root) - 1;
int idxTop = top;
int idxBottom = row - 1;
- if (maximumProcessRows == 0)
- rowsProcessed = 0; // skip the while loop
+ if (maximumProcessRows == 0 || actualBottom < idxTop)
+ rowsProcessed = maximumProcessRows; // skip the while loop
while (rowsProcessed != maximumProcessRows && (idxTop > 0 || idxBottom < actualBottom)) {
int logicalIdx = -1;
@@ -2506,11 +2549,10 @@ int QTableView::sizeHintForColumn(int column) const
break;
}
}
- if (logicalIdx < 0)
- continue;
-
- index = d->model->index(logicalIdx, column, d->root);
- hint = d->widthHintForIndex(index, hint, option);
+ if (logicalIdx >= 0) {
+ index = d->model->index(logicalIdx, column, d->root);
+ hint = d->widthHintForIndex(index, hint, option);
+ }
++rowsProcessed;
}
@@ -2685,24 +2727,25 @@ void QTableView::setSortingEnabled(bool enable)
{
Q_D(QTableView);
horizontalHeader()->setSortIndicatorShown(enable);
+ for (const QMetaObject::Connection &connection : d->dynHorHeaderConnections)
+ disconnect(connection);
+ d->dynHorHeaderConnections.clear();
if (enable) {
- disconnect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
- this, SLOT(_q_selectColumn(int)));
- disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)),
- this, SLOT(selectColumn(int)));
//sortByColumn has to be called before we connect or set the sortingEnabled flag
// because otherwise it will not call sort on the model.
- sortByColumn(horizontalHeader()->sortIndicatorSection(),
- horizontalHeader()->sortIndicatorOrder());
- connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
- this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)), Qt::UniqueConnection);
+ sortByColumn(d->horizontalHeader->sortIndicatorSection(),
+ d->horizontalHeader->sortIndicatorOrder());
+ d->dynHorHeaderConnections = {
+ QObjectPrivate::connect(d->horizontalHeader, &QHeaderView::sortIndicatorChanged,
+ d, &QTableViewPrivate::sortIndicatorChanged)
+ };
} else {
- connect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
- this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection);
- connect(horizontalHeader(), SIGNAL(sectionPressed(int)),
- this, SLOT(selectColumn(int)), Qt::UniqueConnection);
- disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
- this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)));
+ d->dynHorHeaderConnections = {
+ connect(d->horizontalHeader, &QHeaderView::sectionPressed,
+ this, &QTableView::selectColumn),
+ connect(d->horizontalHeader, &QHeaderView::sectionEntered,
+ this, [d](int column) {d->selectColumn(column, false); })
+ };
}
d->sortingEnabled = enable;
}
@@ -3362,16 +3405,6 @@ void QTableView::clearSpans()
d->viewport->update();
}
-void QTableViewPrivate::_q_selectRow(int row)
-{
- selectRow(row, false);
-}
-
-void QTableViewPrivate::_q_selectColumn(int column)
-{
- selectColumn(column, false);
-}
-
void QTableViewPrivate::selectRow(int row, bool anchor)
{
Q_Q(QTableView);
@@ -3388,7 +3421,7 @@ void QTableViewPrivate::selectRow(int row, bool anchor)
selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
if ((anchor && !(command & QItemSelectionModel::Current))
|| (q->selectionMode() == QTableView::SingleSelection))
- rowSectionAnchor = row;
+ currentSelectionStartIndex = model->index(row, column, root);
if (q->selectionMode() != QTableView::SingleSelection
&& command.testFlag(QItemSelectionModel::Toggle)) {
@@ -3401,6 +3434,7 @@ void QTableViewPrivate::selectRow(int row, bool anchor)
command |= QItemSelectionModel::Current;
}
+ const auto rowSectionAnchor = currentSelectionStartIndex.row();
QModelIndex upper = model->index(qMin(rowSectionAnchor, row), column, root);
QModelIndex lower = model->index(qMax(rowSectionAnchor, row), column, root);
if ((verticalHeader->sectionsMoved() && upper.row() != lower.row())) {
@@ -3427,12 +3461,12 @@ void QTableViewPrivate::selectColumn(int column, bool anchor)
selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
if ((anchor && !(command & QItemSelectionModel::Current))
|| (q->selectionMode() == QTableView::SingleSelection))
- columnSectionAnchor = column;
+ currentSelectionStartIndex = model->index(row, column, root);
if (q->selectionMode() != QTableView::SingleSelection
&& command.testFlag(QItemSelectionModel::Toggle)) {
if (anchor)
- ctrlDragSelectionFlag = horizontalHeader->selectionModel()->selectedColumns().contains(index)
+ ctrlDragSelectionFlag = horizontalHeader->selectionModel()->selectedColumns(row).contains(index)
? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
command &= ~QItemSelectionModel::Toggle;
command |= ctrlDragSelectionFlag;
@@ -3440,6 +3474,7 @@ void QTableViewPrivate::selectColumn(int column, bool anchor)
command |= QItemSelectionModel::Current;
}
+ const auto columnSectionAnchor = currentSelectionStartIndex.column();
QModelIndex left = model->index(row, qMin(columnSectionAnchor, column), root);
QModelIndex right = model->index(row, qMax(columnSectionAnchor, column), root);
if ((horizontalHeader->sectionsMoved() && left.column() != right.column())) {
@@ -3455,9 +3490,9 @@ void QTableViewPrivate::selectColumn(int column, bool anchor)
*/
void QTableView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
if (QAccessible::isActive()) {
- if (current.isValid()) {
+ if (current.isValid() && hasFocus()) {
Q_D(QTableView);
int entry = d->accessibleTable2Index(current);
QAccessibleEvent event(this, QAccessible::Focus);
@@ -3477,7 +3512,7 @@ void QTableView::selectionChanged(const QItemSelection &selected,
{
Q_D(QTableView);
Q_UNUSED(d);
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
if (QAccessible::isActive()) {
// ### does not work properly for selection ranges.
QModelIndex sel = selected.indexes().value(0);