QItemSelectionModel: cache calls to QPersistentModelIndex functions
Try to avoid the expensive calls to QPMI functions (they are not inlined) by caching its results. This is done through a helper class which does a lazy initialization of the members. Fixes: QTBUG-113137 Change-Id: I8e4d79e393fbc219f1ff8bb2207ed479521c0847 Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
parent
c38e58dcb0
commit
a76ce7b191
@ -18,6 +18,48 @@ QT_BEGIN_NAMESPACE
|
|||||||
QT_IMPL_METATYPE_EXTERN(QItemSelectionRange)
|
QT_IMPL_METATYPE_EXTERN(QItemSelectionRange)
|
||||||
QT_IMPL_METATYPE_EXTERN(QItemSelection)
|
QT_IMPL_METATYPE_EXTERN(QItemSelection)
|
||||||
|
|
||||||
|
// a small helper to cache calls to QPMI functions as they are expensive
|
||||||
|
struct QItemSelectionRangeRefCache
|
||||||
|
{
|
||||||
|
QItemSelectionRangeRefCache(const QItemSelectionRange &range)
|
||||||
|
: m_range(range)
|
||||||
|
{}
|
||||||
|
inline void invalidate() { m_top = m_left = m_bottom = m_right = -1; }
|
||||||
|
inline bool contains(int row, int column, const QModelIndex &parentIndex)
|
||||||
|
{
|
||||||
|
populate();
|
||||||
|
return (m_bottom >= row && m_right >= column &&
|
||||||
|
m_top <= row && m_left <= column &&
|
||||||
|
parent() == parentIndex);
|
||||||
|
}
|
||||||
|
inline void populate()
|
||||||
|
{
|
||||||
|
if (m_top > -2)
|
||||||
|
return;
|
||||||
|
m_top = m_range.top();
|
||||||
|
m_left = m_range.left();
|
||||||
|
m_bottom = m_range.bottom();
|
||||||
|
m_right = m_range.right();
|
||||||
|
}
|
||||||
|
inline const QModelIndex &parent()
|
||||||
|
{
|
||||||
|
if (!m_parent.has_value())
|
||||||
|
m_parent = m_range.parent();
|
||||||
|
return m_parent.value();
|
||||||
|
}
|
||||||
|
// we assume we're initialized for the next functions
|
||||||
|
inline int bottom() const { return m_bottom; }
|
||||||
|
inline int right() const { return m_right; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_top = -2;
|
||||||
|
int m_left = 0;
|
||||||
|
int m_bottom = 0;
|
||||||
|
int m_right = 0;
|
||||||
|
std::optional<QModelIndex> m_parent;
|
||||||
|
const QItemSelectionRange &m_range;
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QItemSelectionRange
|
\class QItemSelectionRange
|
||||||
\inmodule QtCore
|
\inmodule QtCore
|
||||||
@ -1504,28 +1546,32 @@ bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) cons
|
|||||||
|
|
||||||
const int colCount = d->model->columnCount(parent);
|
const int colCount = d->model->columnCount(parent);
|
||||||
int unselectable = 0;
|
int unselectable = 0;
|
||||||
|
std::vector<QItemSelectionRangeRefCache> cache;
|
||||||
|
cache.reserve(d->currentSelection.size() + d->ranges.size());
|
||||||
|
std::copy(d->currentSelection.begin(), d->currentSelection.end(), std::back_inserter(cache));
|
||||||
|
std::copy(d->ranges.begin(), d->ranges.end(), std::back_inserter(cache));
|
||||||
|
|
||||||
// check ranges and currentSelection
|
// check ranges and currentSelection
|
||||||
for (int column = 0; column < colCount; ++column) {
|
for (int column = 0; column < colCount; ++column) {
|
||||||
if (!isSelectable(row, column)) {
|
if (!isSelectable(row, column)) {
|
||||||
++unselectable;
|
++unselectable;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto doCheck = [&](const auto &listToCheck)
|
bool foundSelection = false;
|
||||||
{
|
for (auto &curSel : cache) {
|
||||||
for (const auto &curSel : listToCheck) {
|
if (curSel.contains(row, column, parent)) {
|
||||||
if (curSel.contains(row, column, parent)) {
|
const auto right = curSel.right();
|
||||||
const auto right = curSel.right();
|
for (int i = column + 1; i <= right; ++i) {
|
||||||
for (int i = column + 1; i <= right; ++i) {
|
if (!isSelectable(row, i))
|
||||||
if (!isSelectable(row, i))
|
++unselectable;
|
||||||
++unselectable;
|
|
||||||
}
|
|
||||||
column = qMax(column, right);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
column = right;
|
||||||
|
foundSelection = true;
|
||||||
|
curSel.invalidate();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
};
|
if (!foundSelection)
|
||||||
if (!doCheck(d->ranges) && !doCheck(d->currentSelection))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return unselectable < colCount;
|
return unselectable < colCount;
|
||||||
@ -1584,28 +1630,32 @@ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent
|
|||||||
|
|
||||||
const int rowCount = d->model->rowCount(parent);
|
const int rowCount = d->model->rowCount(parent);
|
||||||
int unselectable = 0;
|
int unselectable = 0;
|
||||||
|
std::vector<QItemSelectionRangeRefCache> cache;
|
||||||
|
cache.reserve(d->currentSelection.size() + d->ranges.size());
|
||||||
|
std::copy(d->currentSelection.begin(), d->currentSelection.end(), std::back_inserter(cache));
|
||||||
|
std::copy(d->ranges.begin(), d->ranges.end(), std::back_inserter(cache));
|
||||||
|
|
||||||
// check ranges and currentSelection
|
// check ranges and currentSelection
|
||||||
for (int row = 0; row < rowCount; ++row) {
|
for (int row = 0; row < rowCount; ++row) {
|
||||||
if (!isSelectable(row, column)) {
|
if (!isSelectable(row, column)) {
|
||||||
++unselectable;
|
++unselectable;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto doCheck = [&](const auto &listToCheck)
|
bool foundSelection = false;
|
||||||
{
|
for (auto &curSel : cache) {
|
||||||
for (const auto &curSel : listToCheck) {
|
if (curSel.contains(row, column, parent)) {
|
||||||
if (curSel.contains(row, column, parent)) {
|
const auto bottom = curSel.bottom();
|
||||||
const auto bottom = curSel.bottom();
|
for (int i = row + 1; i <= bottom; ++i) {
|
||||||
for (int i = row + 1; i <= bottom; ++i) {
|
if (!isSelectable(i, column))
|
||||||
if (!isSelectable(i, column))
|
++unselectable;
|
||||||
++unselectable;
|
|
||||||
}
|
|
||||||
row = qMax(row, bottom);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
row = bottom;
|
||||||
|
foundSelection = true;
|
||||||
|
curSel.invalidate();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
};
|
if (!foundSelection)
|
||||||
if (!doCheck(d->ranges) && !doCheck(d->currentSelection))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return unselectable < rowCount;
|
return unselectable < rowCount;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user