123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 | // Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qidentityproxymodel.h"#include"qidentityproxymodel_p.h"#include"qitemselectionmodel.h"#include <private/qabstractproxymodel_p.h> QT_BEGIN_NAMESPACE QIdentityProxyModelPrivate::~QIdentityProxyModelPrivate()=default;/*! \since 4.8 \class QIdentityProxyModel \inmodule QtCore \brief The QIdentityProxyModel class proxies its source model unmodified. \ingroup model-view QIdentityProxyModel can be used to forward the structure of a source model exactly, with no sorting, filtering or other transformation. This is similar in concept to an identity matrix where A.I = A. Because it does no sorting or filtering, this class is most suitable to proxy models which transform the data() of the source model. For example, a proxy model could be created to define the font used, or the background colour, or the tooltip etc. This removes the need to implement all data handling in the same class that creates the structure of the model, and can also be used to create re-usable components. This also provides a way to change the data in the case where a source model is supplied by a third party which cannot be modified. \snippet code/src_gui_itemviews_qidentityproxymodel.cpp 0 \sa QAbstractProxyModel, {Model/View Programming}, QAbstractItemModel*//*! Constructs an identity model with the given \a parent.*/QIdentityProxyModel::QIdentityProxyModel(QObject* parent):QAbstractProxyModel(*new QIdentityProxyModelPrivate, parent){}/*! \internal */QIdentityProxyModel::QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent):QAbstractProxyModel(dd, parent){}/*! Destroys this identity model.*/QIdentityProxyModel::~QIdentityProxyModel(){}/*! \reimp */intQIdentityProxyModel::columnCount(const QModelIndex& parent)const{Q_ASSERT(parent.isValid() ? parent.model() ==this:true);Q_D(const QIdentityProxyModel);return d->model->columnCount(mapToSource(parent));}/*! \reimp */boolQIdentityProxyModel::dropMimeData(const QMimeData* data,Qt::DropAction action,int row,int column,const QModelIndex& parent){Q_ASSERT(parent.isValid() ? parent.model() ==this:true);Q_D(QIdentityProxyModel);return d->model->dropMimeData(data, action, row, column,mapToSource(parent));}/*! \reimp */ QModelIndex QIdentityProxyModel::index(int row,int column,const QModelIndex& parent)const{Q_ASSERT(parent.isValid() ? parent.model() ==this:true);Q_D(const QIdentityProxyModel);const QModelIndex sourceParent =mapToSource(parent);const QModelIndex sourceIndex = d->model->index(row, column, sourceParent);returnmapFromSource(sourceIndex);}/*! \reimp */ QModelIndex QIdentityProxyModel::sibling(int row,int column,const QModelIndex &idx)const{Q_D(const QIdentityProxyModel);returnmapFromSource(d->model->sibling(row, column,mapToSource(idx)));}/*! \reimp */boolQIdentityProxyModel::insertColumns(int column,int count,const QModelIndex& parent){Q_ASSERT(parent.isValid() ? parent.model() ==this:true);Q_D(QIdentityProxyModel);return d->model->insertColumns(column, count,mapToSource(parent));}/*! \reimp */boolQIdentityProxyModel::insertRows(int row,int count,const QModelIndex& parent){Q_ASSERT(parent.isValid() ? parent.model() ==this:true);Q_D(QIdentityProxyModel);return d->model->insertRows(row, count,mapToSource(parent));}/*! \reimp */ QModelIndex QIdentityProxyModel::mapFromSource(const QModelIndex& sourceIndex)const{Q_D(const QIdentityProxyModel);if(!d->model || !sourceIndex.isValid())returnQModelIndex();Q_ASSERT(sourceIndex.model() == d->model);returncreateIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer());}/*! \reimp */ QItemSelection QIdentityProxyModel::mapSelectionFromSource(const QItemSelection& selection)const{Q_D(const QIdentityProxyModel); QItemSelection proxySelection;if(!d->model)return proxySelection;QItemSelection::const_iterator it = selection.constBegin();constQItemSelection::const_iterator end = selection.constEnd(); proxySelection.reserve(selection.size());for( ; it != end; ++it) {Q_ASSERT(it->model() == d->model);const QItemSelectionRange range(mapFromSource(it->topLeft()),mapFromSource(it->bottomRight())); proxySelection.append(range);}return proxySelection;}/*! \reimp */ QItemSelection QIdentityProxyModel::mapSelectionToSource(const QItemSelection& selection)const{Q_D(const QIdentityProxyModel); QItemSelection sourceSelection;if(!d->model)return sourceSelection;QItemSelection::const_iterator it = selection.constBegin();constQItemSelection::const_iterator end = selection.constEnd(); sourceSelection.reserve(selection.size());for( ; it != end; ++it) {Q_ASSERT(it->model() ==this);const QItemSelectionRange range(mapToSource(it->topLeft()),mapToSource(it->bottomRight())); sourceSelection.append(range);}return sourceSelection;}/*! \reimp */ QModelIndex QIdentityProxyModel::mapToSource(const QModelIndex& proxyIndex)const{Q_D(const QIdentityProxyModel);if(!d->model || !proxyIndex.isValid())returnQModelIndex();Q_ASSERT(proxyIndex.model() ==this);returncreateSourceIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer());}/*! \reimp */ QModelIndexList QIdentityProxyModel::match(const QModelIndex& start,int role,const QVariant& value,int hits,Qt::MatchFlags flags)const{Q_D(const QIdentityProxyModel);Q_ASSERT(start.isValid() ? start.model() ==this:true);if(!d->model)returnQModelIndexList();const QModelIndexList sourceList = d->model->match(mapToSource(start), role, value, hits, flags);QModelIndexList::const_iterator it = sourceList.constBegin();constQModelIndexList::const_iterator end = sourceList.constEnd(); QModelIndexList proxyList; proxyList.reserve(sourceList.size());for( ; it != end; ++it) proxyList.append(mapFromSource(*it));return proxyList;}/*! \reimp */ QModelIndex QIdentityProxyModel::parent(const QModelIndex& child)const{Q_ASSERT(child.isValid() ? child.model() ==this:true);const QModelIndex sourceIndex =mapToSource(child);const QModelIndex sourceParent = sourceIndex.parent();returnmapFromSource(sourceParent);}/*! \reimp */boolQIdentityProxyModel::removeColumns(int column,int count,const QModelIndex& parent){Q_ASSERT(parent.isValid() ? parent.model() ==this:true);Q_D(QIdentityProxyModel);return d->model->removeColumns(column, count,mapToSource(parent));}/*! \reimp */boolQIdentityProxyModel::removeRows(int row,int count,const QModelIndex& parent){Q_ASSERT(parent.isValid() ? parent.model() ==this:true);Q_D(QIdentityProxyModel);return d->model->removeRows(row, count,mapToSource(parent));}/*! \reimp \since 5.15 */boolQIdentityProxyModel::moveRows(const QModelIndex &sourceParent,int sourceRow,int count,const QModelIndex &destinationParent,int destinationChild){Q_ASSERT(sourceParent.isValid() ? sourceParent.model() ==this:true);Q_ASSERT(destinationParent.isValid() ? destinationParent.model() ==this:true);Q_D(QIdentityProxyModel);return d->model->moveRows(mapToSource(sourceParent), sourceRow, count,mapToSource(destinationParent), destinationChild);}/*! \reimp \since 5.15 */boolQIdentityProxyModel::moveColumns(const QModelIndex &sourceParent,int sourceColumn,int count,const QModelIndex &destinationParent,int destinationChild){Q_ASSERT(sourceParent.isValid() ? sourceParent.model() ==this:true);Q_ASSERT(destinationParent.isValid() ? destinationParent.model() ==this:true);Q_D(QIdentityProxyModel);return d->model->moveColumns(mapToSource(sourceParent), sourceColumn, count,mapToSource(destinationParent), destinationChild);}/*! \reimp */intQIdentityProxyModel::rowCount(const QModelIndex& parent)const{Q_ASSERT(parent.isValid() ? parent.model() ==this:true);Q_D(const QIdentityProxyModel);return d->model->rowCount(mapToSource(parent));}/*! \reimp */ QVariant QIdentityProxyModel::headerData(int section,Qt::Orientation orientation,int role)const{Q_D(const QIdentityProxyModel);return d->model->headerData(section, orientation, role);}/*! \reimp */voidQIdentityProxyModel::setSourceModel(QAbstractItemModel* newSourceModel){beginResetModel();Q_D(QIdentityProxyModel);// Call QObject::disconnect() unconditionally, if there is an existing source// model, it's disconnected, and if there isn't, then calling disconnect() on// a default-constructed Connection does nothingfor(constauto&c : d->m_sourceModelConnections)QObject::disconnect(c);QAbstractProxyModel::setSourceModel(newSourceModel);if(sourceModel()) {auto*m =sourceModel(); d->m_sourceModelConnections = {QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeInserted, d,&QIdentityProxyModelPrivate::sourceRowsAboutToBeInserted),QObjectPrivate::connect(m, &QAbstractItemModel::rowsInserted, d,&QIdentityProxyModelPrivate::sourceRowsInserted),QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeRemoved, d,&QIdentityProxyModelPrivate::sourceRowsAboutToBeRemoved),QObjectPrivate::connect(m, &QAbstractItemModel::rowsRemoved, d,&QIdentityProxyModelPrivate::sourceRowsRemoved),QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeMoved, d,&QIdentityProxyModelPrivate::sourceRowsAboutToBeMoved),QObjectPrivate::connect(m, &QAbstractItemModel::rowsMoved, d,&QIdentityProxyModelPrivate::sourceRowsMoved),QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeInserted, d,&QIdentityProxyModelPrivate::sourceColumnsAboutToBeInserted),QObjectPrivate::connect(m, &QAbstractItemModel::columnsInserted, d,&QIdentityProxyModelPrivate::sourceColumnsInserted),QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeRemoved, d,&QIdentityProxyModelPrivate::sourceColumnsAboutToBeRemoved),QObjectPrivate::connect(m, &QAbstractItemModel::columnsRemoved, d,&QIdentityProxyModelPrivate::sourceColumnsRemoved),QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeMoved, d,&QIdentityProxyModelPrivate::sourceColumnsAboutToBeMoved),QObjectPrivate::connect(m, &QAbstractItemModel::columnsMoved, d,&QIdentityProxyModelPrivate::sourceColumnsMoved),QObjectPrivate::connect(m, &QAbstractItemModel::modelAboutToBeReset, d,&QIdentityProxyModelPrivate::sourceModelAboutToBeReset),QObjectPrivate::connect(m, &QAbstractItemModel::modelReset, d,&QIdentityProxyModelPrivate::sourceModelReset),QObjectPrivate::connect(m, &QAbstractItemModel::headerDataChanged, d,&QIdentityProxyModelPrivate::sourceHeaderDataChanged),};if(d->m_handleDataChanges) { d->m_sourceModelConnections.emplace_back(QObjectPrivate::connect(m, &QAbstractItemModel::dataChanged, d,&QIdentityProxyModelPrivate::sourceDataChanged));}if(d->m_handleLayoutChanges) { d->m_sourceModelConnections.emplace_back(QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged, d,&QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged)); d->m_sourceModelConnections.emplace_back(QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged, d,&QIdentityProxyModelPrivate::sourceLayoutChanged));}}endResetModel();}/*! \since 6.8 If \a b is \c true, this proxy model will handle the source model layout changes (by connecting to \c QAbstractItemModel::layoutAboutToBeChanged and \c QAbstractItemModel::layoutChanged signals). The default is for this proxy model to handle the source model layout changes. In sub-classes of QIdentityProxyModel, it may be useful to set this to \c false if you need to specially handle the source model layout changes. \note Calling this method will only have an effect after calling setSourceModel().*/voidQIdentityProxyModel::setHandleSourceLayoutChanges(bool b){d_func()->m_handleLayoutChanges = b;}/*! \since 6.8 Returns \c true if this proxy model handles the source model layout changes, otherwise returns \c false.*/boolQIdentityProxyModel::handleSourceLayoutChanges()const{returnd_func()->m_handleLayoutChanges;}/*! \since 6.8 If \a b is \c true, this proxy model will handle the source model data changes (by connecting to \c QAbstractItemModel::dataChanged signal). The default is for this proxy model to handle the source model data changes. In sub-classes of QIdentityProxyModel, it may be useful to set this to \c false if you need to specially handle the source model data changes. \note Calling this method will only have an effect after calling setSourceModel().*/voidQIdentityProxyModel::setHandleSourceDataChanges(bool b){d_func()->m_handleDataChanges = b;}/*! \since 6.8 Returns \c true if this proxy model handles the source model data changes, otherwise returns \c false.*/boolQIdentityProxyModel::handleSourceDataChanges()const{returnd_func()->m_handleDataChanges;}voidQIdentityProxyModelPrivate::sourceColumnsAboutToBeInserted(const QModelIndex &parent,int start,int end){Q_ASSERT(parent.isValid() ? parent.model() == model :true);Q_Q(QIdentityProxyModel); q->beginInsertColumns(q->mapFromSource(parent), start, end);}voidQIdentityProxyModelPrivate::sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent,int sourceStart,int sourceEnd,const QModelIndex &destParent,int dest){Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model :true);Q_ASSERT(destParent.isValid() ? destParent.model() == model :true);Q_Q(QIdentityProxyModel); q->beginMoveColumns(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest);}voidQIdentityProxyModelPrivate::sourceColumnsAboutToBeRemoved(const QModelIndex &parent,int start,int end){Q_ASSERT(parent.isValid() ? parent.model() == model :true);Q_Q(QIdentityProxyModel); q->beginRemoveColumns(q->mapFromSource(parent), start, end);}voidQIdentityProxyModelPrivate::sourceColumnsInserted(const QModelIndex &parent,int start,int end){Q_ASSERT(parent.isValid() ? parent.model() == model :true);Q_Q(QIdentityProxyModel);Q_UNUSED(parent);Q_UNUSED(start);Q_UNUSED(end); q->endInsertColumns();}voidQIdentityProxyModelPrivate::sourceColumnsMoved(const QModelIndex &sourceParent,int sourceStart,int sourceEnd,const QModelIndex &destParent,int dest){Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model :true);Q_ASSERT(destParent.isValid() ? destParent.model() == model :true);Q_Q(QIdentityProxyModel);Q_UNUSED(sourceParent);Q_UNUSED(sourceStart);Q_UNUSED(sourceEnd);Q_UNUSED(destParent);Q_UNUSED(dest); q->endMoveColumns();}voidQIdentityProxyModelPrivate::sourceColumnsRemoved(const QModelIndex &parent,int start,int end){Q_ASSERT(parent.isValid() ? parent.model() == model :true);Q_Q(QIdentityProxyModel);Q_UNUSED(parent);Q_UNUSED(start);Q_UNUSED(end); q->endRemoveColumns();}voidQIdentityProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft,const QModelIndex &bottomRight,const QList<int> &roles){Q_ASSERT(topLeft.isValid() ? topLeft.model() == model :true);Q_ASSERT(bottomRight.isValid() ? bottomRight.model() == model :true);Q_Q(QIdentityProxyModel); emit q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight), roles);}voidQIdentityProxyModelPrivate::sourceHeaderDataChanged(Qt::Orientation orientation,int first,int last){Q_Q(QIdentityProxyModel); emit q->headerDataChanged(orientation, first, last);}voidQIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents,QAbstractItemModel::LayoutChangeHint hint){Q_Q(QIdentityProxyModel); QList<QPersistentModelIndex> parents; parents.reserve(sourceParents.size());for(const QPersistentModelIndex &parent : sourceParents) {if(!parent.isValid()) { parents <<QPersistentModelIndex();continue;}const QModelIndex mappedParent = q->mapFromSource(parent);Q_ASSERT(mappedParent.isValid()); parents << mappedParent;} emit q->layoutAboutToBeChanged(parents, hint);constauto proxyPersistentIndexes = q->persistentIndexList();for(const QModelIndex &proxyPersistentIndex : proxyPersistentIndexes) { proxyIndexes << proxyPersistentIndex;Q_ASSERT(proxyPersistentIndex.isValid());const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex);Q_ASSERT(srcPersistentIndex.isValid()); layoutChangePersistentIndexes << srcPersistentIndex;}}voidQIdentityProxyModelPrivate::sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents,QAbstractItemModel::LayoutChangeHint hint){Q_Q(QIdentityProxyModel);for(int i =0; i < proxyIndexes.size(); ++i) { q->changePersistentIndex(proxyIndexes.at(i), q->mapFromSource(layoutChangePersistentIndexes.at(i)));} layoutChangePersistentIndexes.clear(); proxyIndexes.clear(); QList<QPersistentModelIndex> parents; parents.reserve(sourceParents.size());for(const QPersistentModelIndex &parent : sourceParents) {if(!parent.isValid()) { parents <<QPersistentModelIndex();continue;}const QModelIndex mappedParent = q->mapFromSource(parent);Q_ASSERT(mappedParent.isValid()); parents << mappedParent;} emit q->layoutChanged(parents, hint);}voidQIdentityProxyModelPrivate::sourceModelAboutToBeReset(){Q_Q(QIdentityProxyModel); q->beginResetModel();}voidQIdentityProxyModelPrivate::sourceModelReset(){Q_Q(QIdentityProxyModel); q->endResetModel();}voidQIdentityProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent,int start,int end){Q_ASSERT(parent.isValid() ? parent.model() == model :true);Q_Q(QIdentityProxyModel); q->beginInsertRows(q->mapFromSource(parent), start, end);}voidQIdentityProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &sourceParent,int sourceStart,int sourceEnd,const QModelIndex &destParent,int dest){Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model :true);Q_ASSERT(destParent.isValid() ? destParent.model() == model :true);Q_Q(QIdentityProxyModel); q->beginMoveRows(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest);}voidQIdentityProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent,int start,int end){Q_ASSERT(parent.isValid() ? parent.model() == model :true);Q_Q(QIdentityProxyModel); q->beginRemoveRows(q->mapFromSource(parent), start, end);}voidQIdentityProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent,int start,int end){Q_ASSERT(parent.isValid() ? parent.model() == model :true);Q_Q(QIdentityProxyModel);Q_UNUSED(parent);Q_UNUSED(start);Q_UNUSED(end); q->endInsertRows();}voidQIdentityProxyModelPrivate::sourceRowsMoved(const QModelIndex &sourceParent,int sourceStart,int sourceEnd,const QModelIndex &destParent,int dest){Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model :true);Q_ASSERT(destParent.isValid() ? destParent.model() == model :true);Q_Q(QIdentityProxyModel);Q_UNUSED(sourceParent);Q_UNUSED(sourceStart);Q_UNUSED(sourceEnd);Q_UNUSED(destParent);Q_UNUSED(dest); q->endMoveRows();}voidQIdentityProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent,int start,int end){Q_ASSERT(parent.isValid() ? parent.model() == model :true);Q_Q(QIdentityProxyModel);Q_UNUSED(parent);Q_UNUSED(start);Q_UNUSED(end); q->endRemoveRows();} QT_END_NAMESPACE #include"moc_qidentityproxymodel.cpp"
|