diff options
Diffstat (limited to 'src/widgets/itemviews/qtableview.cpp')
-rw-r--r-- | src/widgets/itemviews/qtableview.cpp | 381 |
1 files changed, 208 insertions, 173 deletions
diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index 05d8807e10..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,21 +1422,26 @@ 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); }) + }; } /*! - \internal + \reimp Scroll the contents of the table view by (\a dx, \a dy). */ @@ -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()); @@ -2069,7 +2113,7 @@ void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF } /*! - \internal + \reimp Returns the rectangle from the viewport of the items in the given \a selection. @@ -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; } @@ -2812,7 +2855,7 @@ bool QTableView::isCornerButtonEnabled() const #endif /*! - \internal + \reimp Returns the rectangle on the viewport occupied by the given \a index. @@ -2842,9 +2885,9 @@ QRect QTableView::visualRect(const QModelIndex &index) const } /*! - \internal + \reimp - Makes sure that the given \a item is visible in the table view, + Makes sure that the given \a index is visible in the table view, scrolling if necessary. */ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint) @@ -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 ¤t, 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); |