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

parent 05250753
...@@ -31,979 +31,950 @@ typedef KHash2Map<QPersistentModelIndex, int> Mapping; ...@@ -31,979 +31,950 @@ typedef KHash2Map<QPersistentModelIndex, int> Mapping;
class KDescendantsProxyModelPrivate class KDescendantsProxyModelPrivate
{ {
KDescendantsProxyModelPrivate(KDescendantsProxyModel * qq) KDescendantsProxyModelPrivate(KDescendantsProxyModel *qq)
: q_ptr(qq), : q_ptr(qq),
m_rowCount(0), m_rowCount(0),
m_ignoreNextLayoutAboutToBeChanged(false), m_ignoreNextLayoutAboutToBeChanged(false),
m_ignoreNextLayoutChanged(false), m_ignoreNextLayoutChanged(false),
m_relayouting(false), m_relayouting(false),
m_displayAncestorData( false ), m_displayAncestorData(false),
m_ancestorSeparator( QLatin1String( " / " ) ) m_ancestorSeparator(QStringLiteral(" / "))
{ {
} }
Q_DECLARE_PUBLIC(KDescendantsProxyModel) Q_DECLARE_PUBLIC(KDescendantsProxyModel)
KDescendantsProxyModel * const q_ptr; KDescendantsProxyModel *const q_ptr;
mutable QVector<QPersistentModelIndex> m_pendingParents; mutable QVector<QPersistentModelIndex> m_pendingParents;
void scheduleProcessPendingParents() const; void scheduleProcessPendingParents() const;
void processPendingParents(); void processPendingParents();
void synchronousMappingRefresh(); void synchronousMappingRefresh();
void updateInternalIndexes(int start, int offset); void updateInternalIndexes(int start, int offset);
void resetInternalData(); void resetInternalData();
void sourceRowsAboutToBeInserted(const QModelIndex &, int, int); void sourceRowsAboutToBeInserted(const QModelIndex &, int, int);
void sourceRowsInserted(const QModelIndex &, int, int); void sourceRowsInserted(const QModelIndex &, int, int);
void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int); void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
void sourceRowsRemoved(const QModelIndex &, int, int); void sourceRowsRemoved(const QModelIndex &, int, int);
void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int); void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int); void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void sourceModelAboutToBeReset(); void sourceModelAboutToBeReset();
void sourceModelReset(); void sourceModelReset();
void sourceLayoutAboutToBeChanged(); void sourceLayoutAboutToBeChanged();
void sourceLayoutChanged(); void sourceLayoutChanged();
void sourceDataChanged(const QModelIndex &, const QModelIndex &); void sourceDataChanged(const QModelIndex &, const QModelIndex &);
void sourceModelDestroyed(); void sourceModelDestroyed();
Mapping m_mapping; Mapping m_mapping;
int m_rowCount; int m_rowCount;
QPair<int, int> m_removePair; QPair<int, int> m_removePair;
QPair<int, int> m_insertPair; QPair<int, int> m_insertPair;
bool m_ignoreNextLayoutAboutToBeChanged; bool m_ignoreNextLayoutAboutToBeChanged;
bool m_ignoreNextLayoutChanged; bool m_ignoreNextLayoutChanged;
bool m_relayouting; bool m_relayouting;
bool m_displayAncestorData; bool m_displayAncestorData;
QString m_ancestorSeparator; QString m_ancestorSeparator;
QList<QPersistentModelIndex> m_layoutChangePersistentIndexes; QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
QModelIndexList m_proxyIndexes; QModelIndexList m_proxyIndexes;
}; };
void KDescendantsProxyModelPrivate::resetInternalData() void KDescendantsProxyModelPrivate::resetInternalData()
{ {
m_rowCount = 0; m_rowCount = 0;
m_mapping.clear(); m_mapping.clear();
m_layoutChangePersistentIndexes.clear(); m_layoutChangePersistentIndexes.clear();
m_proxyIndexes.clear(); m_proxyIndexes.clear();
} }
void KDescendantsProxyModelPrivate::synchronousMappingRefresh() void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
{ {
m_rowCount = 0; m_rowCount = 0;
m_mapping.clear(); m_mapping.clear();
m_pendingParents.clear(); m_pendingParents.clear();
m_pendingParents.append(QModelIndex()); m_pendingParents.append(QModelIndex());
m_relayouting = true; m_relayouting = true;
while (!m_pendingParents.isEmpty()) while (!m_pendingParents.isEmpty()) {
{ processPendingParents();
processPendingParents(); }
} m_relayouting = false;
m_relayouting = false;
} }
void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const
{ {
// Q_Q(const KDescendantsProxyModel); const_cast<KDescendantsProxyModelPrivate *>(this)->processPendingParents();
const_cast<KDescendantsProxyModelPrivate*>(this)->processPendingParents();
} }
void KDescendantsProxyModelPrivate::processPendingParents() void KDescendantsProxyModelPrivate::processPendingParents()
{ {
Q_Q(KDescendantsProxyModel); Q_Q(KDescendantsProxyModel);
const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin(); const QVector<QPersistentModelIndex>::iterator begin = m_pendingParents.begin();
QVector<QPersistentModelIndex>::iterator it = begin; QVector<QPersistentModelIndex>::iterator it = begin;
// Process chunkSize elements per invocation. const QVector<QPersistentModelIndex>::iterator end = m_pendingParents.end();
// static const int chunkSize = 30;
const QVector<QPersistentModelIndex>::iterator end = QVector<QPersistentModelIndex> newPendingParents;
/* (m_pendingParents.size() > chunkSize) ? begin + chunkSize : */ m_pendingParents.end();
QVector<QPersistentModelIndex> newPendingParents; while (it != end && it != m_pendingParents.end()) {
const QModelIndex sourceParent = *it;
while (it != end && it != m_pendingParents.end()) { if (!sourceParent.isValid() && m_rowCount > 0) {
const QModelIndex sourceParent = *it; // It was removed from the source model before it was inserted.
if (!sourceParent.isValid() && m_rowCount > 0) it = m_pendingParents.erase(it);
{ continue;
// It was removed from the source model before it was inserted. }
it = m_pendingParents.erase(it); const int rowCount = q->sourceModel()->rowCount(sourceParent);
continue;
}
const int rowCount = q->sourceModel()->rowCount(sourceParent);
Q_ASSERT(rowCount > 0); Q_ASSERT(rowCount > 0);
const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent); 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()); Q_ASSERT(sourceParent.isValid() == proxyParent.isValid());
const int proxyEndRow = proxyParent.row() + rowCount; const int proxyEndRow = proxyParent.row() + rowCount;
const int proxyStartRow = proxyEndRow - rowCount + 1; const int proxyStartRow = proxyEndRow - rowCount + 1;
if (!m_relayouting) if (!m_relayouting) {
q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow); q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow);
}
updateInternalIndexes(proxyStartRow, rowCount); updateInternalIndexes(proxyStartRow, rowCount);
m_mapping.insert(sourceIndex, proxyEndRow); m_mapping.insert(sourceIndex, proxyEndRow);
it = m_pendingParents.erase(it); it = m_pendingParents.erase(it);
m_rowCount += rowCount; m_rowCount += rowCount;
if (!m_relayouting) if (!m_relayouting) {
q->endInsertRows(); q->endInsertRows();
}
for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow ) { for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow) {
static const int column = 0; static const int column = 0;
const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent); const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
Q_ASSERT(child.isValid()); Q_ASSERT(child.isValid());
if (q->sourceModel()->hasChildren(child)) if (q->sourceModel()->hasChildren(child)) {
{ Q_ASSERT(q->sourceModel()->rowCount(child) > 0);
Q_ASSERT(q->sourceModel()->rowCount(child) > 0); newPendingParents.append(child);
newPendingParents.append(child); }
} }
}
m_pendingParents += newPendingParents;
if (!m_pendingParents.isEmpty()) {
processPendingParents();
} }
}
m_pendingParents += newPendingParents;
if (!m_pendingParents.isEmpty())
processPendingParents();
// scheduleProcessPendingParents(); // scheduleProcessPendingParents();
} }
void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset) void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset)
{ {
// TODO: Make KHash2Map support key updates and do this backwards. // TODO: Make KHash2Map support key updates and do this backwards.
QHash<int, QPersistentModelIndex> updates; QHash<int, QPersistentModelIndex> updates;
{
Mapping::right_iterator it = m_mapping.rightLowerBound(start);
const Mapping::right_iterator end = m_mapping.rightEnd();
while (it != end)
{ {
updates.insert(it.key() + offset, *it); Mapping::right_iterator it = m_mapping.rightLowerBound(start);
++it; const Mapping::right_iterator end = m_mapping.rightEnd();
}
}
{ while (it != end) {
QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin(); updates.insert(it.key() + offset, *it);
const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd(); ++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) KDescendantsProxyModel::KDescendantsProxyModel(QObject *parent)
: QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this)) : QAbstractProxyModel(parent), d_ptr(new KDescendantsProxyModelPrivate(this))
{ {
} }
KDescendantsProxyModel::~KDescendantsProxyModel() 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 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); Q_D(KDescendantsProxyModel);
d->m_displayAncestorData = display; d->m_displayAncestorData = display;
} }
bool KDescendantsProxyModel::displayAncestorData() const bool KDescendantsProxyModel::displayAncestorData() const
{ {
Q_D(const KDescendantsProxyModel ); Q_D(const KDescendantsProxyModel);
return d->m_displayAncestorData; return d->m_displayAncestorData;
} }
void KDescendantsProxyModel::setAncestorSeparator( const QString &separator ) void KDescendantsProxyModel::setAncestorSeparator(const QString &separator)
{ {
Q_D(KDescendantsProxyModel); Q_D(KDescendantsProxyModel);
d->m_ancestorSeparator = separator; d->m_ancestorSeparator = separator;
} }
QString KDescendantsProxyModel::ancestorSeparator() const QString KDescendantsProxyModel::ancestorSeparator() const
{ {
Q_D(const KDescendantsProxyModel ); Q_D(const KDescendantsProxyModel);
return d->m_ancestorSeparator; return d->m_ancestorSeparator;
} }
void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel) void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel)
{ {
Q_D(const KDescendantsProxyModel ); beginResetModel();
beginResetModel();
static const char *modelSignals[] = {
if (sourceModel()) { SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(sourceRowsInserted(QModelIndex,int,int))); SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); SIGNAL(modelAboutToBeReset()),
disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(modelReset()),
this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); SIGNAL(dataChanged(QModelIndex,QModelIndex)),
// disconnect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), SIGNAL(layoutAboutToBeChanged()),
// this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); SIGNAL(layoutChanged()),
// disconnect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SIGNAL(destroyed())
// this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))); };
disconnect(sourceModel(), SIGNAL(modelAboutToBeReset()), static const char *proxySlots[] = {
this, SLOT(sourceModelAboutToBeReset())); SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int)),
disconnect(sourceModel(), SIGNAL(modelReset()), SLOT(sourceRowsInserted(QModelIndex,int,int)),
this, SLOT(sourceModelReset())); SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int)),
disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(sourceRowsRemoved(QModelIndex,int,int)),
this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged()), SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)),
this, SLOT(sourceLayoutAboutToBeChanged())); SLOT(sourceModelAboutToBeReset()),
disconnect(sourceModel(), SIGNAL(layoutChanged()), SLOT(sourceModelReset()),
this, SLOT(sourceLayoutChanged())); SLOT(sourceDataChanged(QModelIndex,QModelIndex)),
disconnect(sourceModel(), SIGNAL(destroyed()), SLOT(sourceLayoutAboutToBeChanged()),
this, SLOT(sourceModelDestroyed())); SLOT(sourceLayoutChanged()),
} SLOT(sourceModelDestroyed())
};
QAbstractProxyModel::setSourceModel(_sourceModel);
if ( sourceModel()->hasChildren() ) if (sourceModel()) {
{ for (int i = 0; i < int(sizeof modelSignals / sizeof * modelSignals); ++i) {
Q_ASSERT( sourceModel()->rowCount() > 0 ); disconnect(sourceModel(), modelSignals[i], this, proxySlots[i]);
const_cast<KDescendantsProxyModelPrivate*>(d)->synchronousMappingRefresh(); }
} }
if (_sourceModel) { QAbstractProxyModel::setSourceModel(_sourceModel);
connect(_sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); if (_sourceModel) {
connect(_sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)), for (int i = 0; i < int(sizeof modelSignals / sizeof * modelSignals); ++i) {
SLOT(sourceRowsInserted(QModelIndex,int,int))); connect(_sourceModel, modelSignals[i], this, proxySlots[i]);
connect(_sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), }
SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); }
connect(_sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
SLOT(sourceRowsRemoved(QModelIndex,int,int))); endResetModel();
// 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();
} }
QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const
{ {
Q_UNUSED(index) Q_UNUSED(index)
return QModelIndex(); return QModelIndex();
} }
bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const
{ {
Q_D(const KDescendantsProxyModel); Q_D(const KDescendantsProxyModel);
return !(d->m_mapping.isEmpty() || parent.isValid()); return !(d->m_mapping.isEmpty() || parent.isValid());
} }
int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const
{ {
Q_D(const KDescendantsProxyModel); Q_D(const KDescendantsProxyModel);
if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) {
return 0; return 0;
}
if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) {
{ Q_ASSERT(sourceModel()->rowCount() > 0);
Q_ASSERT(sourceModel()->rowCount() > 0); const_cast<KDescendantsProxyModelPrivate *>(d)->synchronousMappingRefresh();
const_cast<KDescendantsProxyModelPrivate*>(d)->synchronousMappingRefresh(); }
} return d->m_rowCount;
return d->m_rowCount;
} }
QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const
{ {
if (parent.isValid()) if (parent.isValid()) {
return QModelIndex(); return QModelIndex();
}
if (!hasIndex(row, column, parent)) if (!hasIndex(row, column, parent)) {
return QModelIndex(); return QModelIndex();
}
return createIndex(row, column); return createIndex(row, column);
} }
QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{ {
Q_D(const KDescendantsProxyModel); Q_D(const KDescendantsProxyModel);
if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) {
return QModelIndex(); return QModelIndex();
}
const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row()); const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row());
Q_ASSERT(result != d->m_mapping.rightEnd()); Q_ASSERT(result != d->m_mapping.rightEnd());
const int proxyLastRow = result.key(); const int proxyLastRow = result.key();
const QModelIndex sourceLastChild = result.value(); const QModelIndex sourceLastChild = result.value();
Q_ASSERT(sourceLastChild.isValid()); Q_ASSERT(sourceLastChild.isValid());
// proxyLastRow is greater than proxyIndex.row(). // proxyLastRow is greater than proxyIndex.row().
// sourceLastChild is vertically below the result we're looking for // sourceLastChild is vertically below the result we're looking for
// and not necessarily in the correct parent. // and not necessarily in the correct parent.
// We travel up through its parent hierarchy until we are in the // We travel up through its parent hierarchy until we are in the
// right parent, then return the correct sibling. // right parent, then return the correct sibling.
// Source: Proxy: Row // Source: Proxy: Row
// - A - A - 0 // - A - A - 0
// - B - B - 1