Update KDescendantsProxyModel code from KF5 kitemmodels, tag v5.24.0-rc3

parent 05250753
......@@ -31,979 +31,950 @@ typedef KHash2Map<QPersistentModelIndex, int> Mapping;
class KDescendantsProxyModelPrivate
{
KDescendantsProxyModelPrivate(KDescendantsProxyModel * qq)
: q_ptr(qq),
m_rowCount(0),
m_ignoreNextLayoutAboutToBeChanged(false),
m_ignoreNextLayoutChanged(false),
m_relayouting(false),
m_displayAncestorData( false ),
m_ancestorSeparator( QLatin1String( " / " ) )
{
}
Q_DECLARE_PUBLIC(KDescendantsProxyModel)
KDescendantsProxyModel * const q_ptr;
mutable QVector<QPersistentModelIndex> m_pendingParents;
void scheduleProcessPendingParents() const;
void processPendingParents();
void synchronousMappingRefresh();
void updateInternalIndexes(int start, int offset);
void resetInternalData();
void sourceRowsAboutToBeInserted(const QModelIndex &, int, int);
void sourceRowsInserted(const QModelIndex &, int, int);
void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
void sourceRowsRemoved(const QModelIndex &, int, int);
void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceModelAboutToBeReset();
void sourceModelReset();
void sourceLayoutAboutToBeChanged();
void sourceLayoutChanged();
void sourceDataChanged(const QModelIndex &, const QModelIndex &);
void sourceModelDestroyed();
Mapping m_mapping;
int m_rowCount;
QPair<int, int> m_removePair;
QPair<int, int> m_insertPair;
bool m_ignoreNextLayoutAboutToBeChanged;
bool m_ignoreNextLayoutChanged;
bool m_relayouting;
bool m_displayAncestorData;
QString m_ancestorSeparator;
QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
QModelIndexList m_proxyIndexes;
KDescendantsProxyModelPrivate(KDescendantsProxyModel *qq)
: q_ptr(qq),
m_rowCount(0),
m_ignoreNextLayoutAboutToBeChanged(false),
m_ignoreNextLayoutChanged(false),
m_relayouting(false),
m_displayAncestorData(false),
m_ancestorSeparator(QStringLiteral(" / "))
{
}
Q_DECLARE_PUBLIC(KDescendantsProxyModel)
KDescendantsProxyModel *const q_ptr;
mutable QVector<QPersistentModelIndex> m_pendingParents;
void scheduleProcessPendingParents() const;
void processPendingParents();
void synchronousMappingRefresh();
void updateInternalIndexes(int start, int offset);
void resetInternalData();
void sourceRowsAboutToBeInserted(const QModelIndex &, int, int);
void sourceRowsInserted(const QModelIndex &, int, int);
void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
void sourceRowsRemoved(const QModelIndex &, int, int);
void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceModelAboutToBeReset();
void sourceModelReset();
void sourceLayoutAboutToBeChanged();
void sourceLayoutChanged();
void sourceDataChanged(const QModelIndex &, const QModelIndex &);
void sourceModelDestroyed();
Mapping m_mapping;
int m_rowCount;
QPair<int, int> m_removePair;
QPair<int, int> m_insertPair;
bool m_ignoreNextLayoutAboutToBeChanged;
bool m_ignoreNextLayoutChanged;
bool m_relayouting;
bool m_displayAncestorData;
QString m_ancestorSeparator;
QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
QModelIndexList m_proxyIndexes;
};
void KDescendantsProxyModelPrivate::resetInternalData()
{
m_rowCount = 0;
m_mapping.clear();
m_layoutChangePersistentIndexes.clear();
m_proxyIndexes.clear();
m_rowCount = 0;
m_mapping.clear();
m_layoutChangePersistentIndexes.clear();
m_proxyIndexes.clear();
}
void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
{
m_rowCount = 0;
m_mapping.clear();
m_pendingParents.clear();
m_rowCount = 0;
m_mapping.clear();
m_pendingParents.clear();
m_pendingParents.append(QModelIndex());
m_pendingParents.append(QModelIndex());
m_relayouting = true;
while (!m_pendingParents.isEmpty())
{
processPendingParents();
}
m_relayouting = false;
m_relayouting = true;
while (!m_pendingParents.isEmpty()) {
processPendingParents();
}
m_relayouting = false;
}
void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const
{
// Q_Q(const KDescendantsProxyModel);
const_cast<KDescendantsProxyModelPrivate*>(this)->processPendingParents();
const_cast<KDescendantsProxyModelPrivate *>(this)->processPendingParents();
}
void KDescendantsProxyModelPrivate::processPendingParents()
{
Q_Q(KDescendantsProxyModel);
const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin();
QVector<QPersistentModelIndex>::iterator it = begin;
Q_Q(KDescendantsProxyModel);
const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin();
QVector<QPersistentModelIndex>::iterator it = begin;
// Process chunkSize elements per invocation.
// static const int chunkSize = 30;
const QVector<QPersistentModelIndex>::iterator end = m_pendingParents.end();
const QVector<QPersistentModelIndex>::iterator end =
/* (m_pendingParents.size() > chunkSize) ? begin + chunkSize : */ m_pendingParents.end();
QVector<QPersistentModelIndex> newPendingParents;
QVector<QPersistentModelIndex> newPendingParents;
while (it != end && it != m_pendingParents.end()) {
const QModelIndex sourceParent = *it;
if (!sourceParent.isValid() && m_rowCount > 0)
{
// It was removed from the source model before it was inserted.
it = m_pendingParents.erase(it);
continue;
}
const int rowCount = q->sourceModel()->rowCount(sourceParent);
while (it != end && it != m_pendingParents.end()) {
const QModelIndex sourceParent = *it;
if (!sourceParent.isValid() && m_rowCount > 0) {
// It was removed from the source model before it was inserted.
it = m_pendingParents.erase(it);
continue;
}
const int rowCount = q->sourceModel()->rowCount(sourceParent);
Q_ASSERT(rowCount > 0);
const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent);
Q_ASSERT(rowCount > 0);
const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent);
Q_ASSERT(sourceIndex.isValid());
Q_ASSERT(sourceIndex.isValid());
const QModelIndex proxyParent = q->mapFromSource(sourceParent);
const QModelIndex proxyParent = q->mapFromSource(sourceParent);
Q_ASSERT(sourceParent.isValid() == proxyParent.isValid());
const int proxyEndRow = proxyParent.row() + rowCount;
const int proxyStartRow = proxyEndRow - rowCount + 1;
Q_ASSERT(sourceParent.isValid() == proxyParent.isValid());
const int proxyEndRow = proxyParent.row() + rowCount;
const int proxyStartRow = proxyEndRow - rowCount + 1;
if (!m_relayouting)
q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow);
if (!m_relayouting) {
q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow);
}
updateInternalIndexes(proxyStartRow, rowCount);
m_mapping.insert(sourceIndex, proxyEndRow);
it = m_pendingParents.erase(it);
m_rowCount += rowCount;
updateInternalIndexes(proxyStartRow, rowCount);
m_mapping.insert(sourceIndex, proxyEndRow);
it = m_pendingParents.erase(it);
m_rowCount += rowCount;
if (!m_relayouting)
q->endInsertRows();
if (!m_relayouting) {
q->endInsertRows();
}
for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow ) {
static const int column = 0;
const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
Q_ASSERT(child.isValid());
for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow) {
static const int column = 0;
const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
Q_ASSERT(child.isValid());
if (q->sourceModel()->hasChildren(child))
{
Q_ASSERT(q->sourceModel()->rowCount(child) > 0);
newPendingParents.append(child);
}
if (q->sourceModel()->hasChildren(child)) {
Q_ASSERT(q->sourceModel()->rowCount(child) > 0);
newPendingParents.append(child);
}
}
}
m_pendingParents += newPendingParents;
if (!m_pendingParents.isEmpty()) {
processPendingParents();
}
}
m_pendingParents += newPendingParents;
if (!m_pendingParents.isEmpty())
processPendingParents();
// scheduleProcessPendingParents();
}
void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset)
{
// TODO: Make KHash2Map support key updates and do this backwards.
QHash<int, QPersistentModelIndex> updates;
{
Mapping::right_iterator it = m_mapping.rightLowerBound(start);
const Mapping::right_iterator end = m_mapping.rightEnd();
while (it != end)
// TODO: Make KHash2Map support key updates and do this backwards.
QHash<int, QPersistentModelIndex> updates;
{
updates.insert(it.key() + offset, *it);
++it;
}
}
Mapping::right_iterator it = m_mapping.rightLowerBound(start);
const Mapping::right_iterator end = m_mapping.rightEnd();
{
QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin();
const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd();
while (it != end) {
updates.insert(it.key() + offset, *it);
++it;
}
}
for ( ; it != end; ++it)
{
m_mapping.insert(it.value(), it.key());
QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin();
const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd();
for (; it != end; ++it) {
m_mapping.insert(it.value(), it.key());
}
}
}
}
KDescendantsProxyModel::KDescendantsProxyModel(QObject *parent)
: QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this))
: QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this))
{
}
KDescendantsProxyModel::~KDescendantsProxyModel()
{
delete d_ptr;
delete d_ptr;
}
#if 0
void KDescendantsProxyModel::setRootIndex(const QModelIndex &index)
{
Q_UNUSED(index)
}
#endif
QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
{
return QAbstractProxyModel::match(start, role, value, hits, flags);
return QAbstractProxyModel::match(start, role, value, hits, flags);
}
void KDescendantsProxyModel::setDisplayAncestorData( bool display )
void KDescendantsProxyModel::setDisplayAncestorData(bool display)
{
Q_D(KDescendantsProxyModel);
d->m_displayAncestorData = display;
Q_D(KDescendantsProxyModel);
d->m_displayAncestorData = display;
}
bool KDescendantsProxyModel::displayAncestorData() const
{
Q_D(const KDescendantsProxyModel );
return d->m_displayAncestorData;
Q_D(const KDescendantsProxyModel);
return d->m_displayAncestorData;
}
void KDescendantsProxyModel::setAncestorSeparator( const QString &separator )
void KDescendantsProxyModel::setAncestorSeparator(const QString &separator)
{
Q_D(KDescendantsProxyModel);
d->m_ancestorSeparator = separator;
Q_D(KDescendantsProxyModel);
d->m_ancestorSeparator = separator;
}
QString KDescendantsProxyModel::ancestorSeparator() const
{
Q_D(const KDescendantsProxyModel );
return d->m_ancestorSeparator;
Q_D(const KDescendantsProxyModel);
return d->m_ancestorSeparator;
}
void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel)
{
Q_D(const KDescendantsProxyModel );
beginResetModel();
if (sourceModel()) {
disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
// disconnect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
// this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
// disconnect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
// this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
disconnect(sourceModel(), SIGNAL(modelAboutToBeReset()),
this, SLOT(sourceModelAboutToBeReset()));
disconnect(sourceModel(), SIGNAL(modelReset()),
this, SLOT(sourceModelReset()));
disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged()),
this, SLOT(sourceLayoutAboutToBeChanged()));
disconnect(sourceModel(), SIGNAL(layoutChanged()),
this, SLOT(sourceLayoutChanged()));
disconnect(sourceModel(), SIGNAL(destroyed()),
this, SLOT(sourceModelDestroyed()));
}
QAbstractProxyModel::setSourceModel(_sourceModel);
if ( sourceModel()->hasChildren() )
{
Q_ASSERT( sourceModel()->rowCount() > 0 );
const_cast<KDescendantsProxyModelPrivate*>(d)->synchronousMappingRefresh();
}
if (_sourceModel) {
connect(_sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)));
connect(_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
SLOT(sourceRowsInserted(QModelIndex,int,int)));
connect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
connect(_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
SLOT(sourceRowsRemoved(QModelIndex,int,int)));
// connect(_sourceModel, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
// SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
// connect(_sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
// SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
connect(_sourceModel, SIGNAL(modelAboutToBeReset()),
SLOT(sourceModelAboutToBeReset()));
connect(_sourceModel, SIGNAL(modelReset()),
SLOT(sourceModelReset()));
connect(_sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
connect(_sourceModel, SIGNAL(layoutAboutToBeChanged()),
SLOT(sourceLayoutAboutToBeChanged()));
connect(_sourceModel, SIGNAL(layoutChanged()),
SLOT(sourceLayoutChanged()));
connect(_sourceModel, SIGNAL(destroyed()),
SLOT(sourceModelDestroyed()));
}
endResetModel();
beginResetModel();
static const char *modelSignals[] = {
SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
SIGNAL(rowsInserted(QModelIndex,int,int)),
SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
SIGNAL(rowsRemoved(QModelIndex,int,int)),
SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
SIGNAL(modelAboutToBeReset()),
SIGNAL(modelReset()),
SIGNAL(dataChanged(QModelIndex,QModelIndex)),
SIGNAL(layoutAboutToBeChanged()),
SIGNAL(layoutChanged()),
SIGNAL(destroyed())
};
static const char *proxySlots[] = {
SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)),
SLOT(sourceRowsInserted(QModelIndex,int,int)),
SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)),
SLOT(sourceRowsRemoved(QModelIndex,int,int)),
SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)),
SLOT(sourceModelAboutToBeReset()),
SLOT(sourceModelReset()),
SLOT(sourceDataChanged(QModelIndex,QModelIndex)),
SLOT(sourceLayoutAboutToBeChanged()),
SLOT(sourceLayoutChanged()),
SLOT(sourceModelDestroyed())
};
if (sourceModel()) {
for (int i = 0; i < int(sizeof modelSignals / sizeof * modelSignals); ++i) {
disconnect(sourceModel(), modelSignals[i], this, proxySlots[i]);
}
}
QAbstractProxyModel::setSourceModel(_sourceModel);
if (_sourceModel) {
for (int i = 0; i < int(sizeof modelSignals / sizeof * modelSignals); ++i) {
connect(_sourceModel, modelSignals[i], this, proxySlots[i]);
}
}
endResetModel();
}
QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const
{
Q_UNUSED(index)
return QModelIndex();
Q_UNUSED(index)
return QModelIndex();
}
bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const
{
Q_D(const KDescendantsProxyModel);
return !(d->m_mapping.isEmpty() || parent.isValid());
Q_D(const KDescendantsProxyModel);
return !(d->m_mapping.isEmpty() || parent.isValid());
}
int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const
{
Q_D(const KDescendantsProxyModel);
if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel())
return 0;
Q_D(const KDescendantsProxyModel);
if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) {
return 0;
}
if (d->m_mapping.isEmpty() && sourceModel()->hasChildren())
{
Q_ASSERT(sourceModel()->rowCount() > 0);
const_cast<KDescendantsProxyModelPrivate*>(d)->synchronousMappingRefresh();
}
return d->m_rowCount;
if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) {
Q_ASSERT(sourceModel()->rowCount() > 0);
const_cast<KDescendantsProxyModelPrivate *>(d)->synchronousMappingRefresh();
}
return d->m_rowCount;
}
QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid())
return QModelIndex();
if (parent.isValid()) {
return QModelIndex();
}
if (!hasIndex(row, column, parent))
return QModelIndex();
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}
return createIndex(row, column);
return createIndex(row, column);
}
QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
Q_D(const KDescendantsProxyModel);
if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel())
return QModelIndex();
Q_D(const KDescendantsProxyModel);
if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) {
return QModelIndex();
}
const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row());
Q_ASSERT(result != d->m_mapping.rightEnd());
const int proxyLastRow = result.key();
const QModelIndex sourceLastChild = result.value();
Q_ASSERT(sourceLastChild.isValid());
// proxyLastRow is greater than proxyIndex.row().
// sourceLastChild is vertically below the result we're looking for
// and not necessarily in the correct parent.
// We travel up through its parent hierarchy until we are in the
// right parent, then return the correct sibling.
// Source: Proxy: Row
// - A - A - 0
// - B - B - 1
// - C - C - 2
// - D - D - 3
// - - E - E - 4
// - - F - F - 5
// - - G - G - 6
// - - H - H - 7
// - - I - I - 8
// - - - J - J - 9
// - - - K - K - 10
// - - - L - L - 11
// - - M - M - 12
// - - N - N - 13
// - O - O - 14
// Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we
// are trying to map G from the proxy to the source, We at this point have an iterator
// pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the
// sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row().
// In this case the verticalDistance is 5.
int verticalDistance = proxyLastRow - proxyIndex.row();
// We traverse the ancestors of L, until we can index the desired row in the source.
QModelIndex ancestor = sourceLastChild;
while (ancestor.isValid())
{
const int ancestorRow = ancestor.row();
if (verticalDistance <= ancestorRow)
{
return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column());
const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row());
Q_ASSERT(result != d->m_mapping.rightEnd());
const int proxyLastRow = result.key();
const QModelIndex sourceLastChild = result.value();
Q_ASSERT(sourceLastChild.isValid());
// proxyLastRow is greater than proxyIndex.row().
// sourceLastChild is vertically below the result we're looking for
// and not necessarily in the correct parent.
// We travel up through its parent hierarchy until we are in the
// right parent, then return the correct sibling.
// Source: Proxy: Row
// - A - A - 0
// - B - B - 1
// - C - C - 2
// - D - D - 3
// - - E - E - 4
// - - F - F - 5
// - - G - G - 6
// - - H - H - 7
// - - I - I - 8
// - - - J - J - 9
// - - - K - K - 10