diff options
Diffstat (limited to 'src/widgets/itemviews/qtableview.cpp')
-rw-r--r-- | src/widgets/itemviews/qtableview.cpp | 267 |
1 files changed, 150 insertions, 117 deletions
diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index 1ba0c20361..5726348bc5 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -4,7 +4,7 @@ #include "qtableview.h" #include <qheaderview.h> -#include <qitemdelegate.h> +#include <qabstractitemdelegate.h> #include <qapplication.h> #include <qpainter.h> #include <qstyle.h> @@ -19,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 @@ -170,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 @@ -200,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(); ) { @@ -247,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) { @@ -352,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); @@ -420,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); } @@ -479,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); @@ -499,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); } @@ -592,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 } @@ -882,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); @@ -937,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); @@ -947,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); @@ -957,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); @@ -967,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); @@ -977,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); } @@ -1169,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} */ /*! @@ -1200,6 +1238,8 @@ QTableView::QTableView(QTableViewPrivate &dd, QWidget *parent) */ QTableView::~QTableView() { + Q_D(QTableView); + d->clearConnections(); } /*! @@ -1223,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); @@ -1286,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); @@ -1296,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); } } @@ -1334,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; @@ -1345,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); } @@ -1372,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; @@ -1383,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); }) + }; } /*! @@ -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); @@ -3457,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); @@ -3479,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); |