/**************************************************************************** ** ** Copyright (C) 2018 Luca Beldi ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtransposeproxymodel.h" #include #include #include #include QT_BEGIN_NAMESPACE QModelIndex QTransposeProxyModelPrivate::uncheckedMapToSource(const QModelIndex &proxyIndex) const { if (!model || !proxyIndex.isValid()) return QModelIndex(); if (proxyIndex.internalPointer()) return model->createIndex(proxyIndex.column(), proxyIndex.row(), proxyIndex.internalPointer()); return model->index(proxyIndex.column(), proxyIndex.row()); } QModelIndex QTransposeProxyModelPrivate::uncheckedMapFromSource(const QModelIndex &sourceIndex) const { if (!model || !sourceIndex.isValid()) return QModelIndex(); Q_Q(const QTransposeProxyModel); return q->createIndex(sourceIndex.column(), sourceIndex.row(), sourceIndex.internalPointer()); } void QTransposeProxyModelPrivate::onLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint) { Q_Q(QTransposeProxyModel); QModelIndexList toList; toList.reserve(layoutChangePersistentIndexes.size()); for (const QPersistentModelIndex &persistIdx : qAsConst(layoutChangePersistentIndexes)) toList << q->mapFromSource(persistIdx); q->changePersistentIndexList(layoutChangeProxyIndexes, toList); layoutChangeProxyIndexes.clear(); layoutChangePersistentIndexes.clear(); QList proxyParents; proxyParents.reserve(parents.size()); for (const QPersistentModelIndex &srcParent : parents) proxyParents << q->mapFromSource(srcParent); QAbstractItemModel::LayoutChangeHint proxyHint = QAbstractItemModel::NoLayoutChangeHint; if (hint == QAbstractItemModel::VerticalSortHint) proxyHint = QAbstractItemModel::HorizontalSortHint; else if (hint == QAbstractItemModel::HorizontalSortHint) proxyHint = QAbstractItemModel::VerticalSortHint; emit q->layoutChanged(proxyParents, proxyHint); } void QTransposeProxyModelPrivate::onLayoutAboutToBeChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint) { Q_Q(QTransposeProxyModel); const QModelIndexList proxyPersistentIndexes = q->persistentIndexList(); layoutChangeProxyIndexes.clear(); layoutChangePersistentIndexes.clear(); layoutChangeProxyIndexes.reserve(proxyPersistentIndexes.size()); layoutChangePersistentIndexes.reserve(proxyPersistentIndexes.size()); for (const QPersistentModelIndex &proxyPersistentIndex : proxyPersistentIndexes) { layoutChangeProxyIndexes << proxyPersistentIndex; Q_ASSERT(proxyPersistentIndex.isValid()); const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex); Q_ASSERT(srcPersistentIndex.isValid()); layoutChangePersistentIndexes << srcPersistentIndex; } QList proxyParents; proxyParents.reserve(parents.size()); for (auto& srcParent : parents) proxyParents << q->mapFromSource(srcParent); QAbstractItemModel::LayoutChangeHint proxyHint = QAbstractItemModel::NoLayoutChangeHint; if (hint == QAbstractItemModel::VerticalSortHint) proxyHint = QAbstractItemModel::HorizontalSortHint; else if (hint == QAbstractItemModel::HorizontalSortHint) proxyHint = QAbstractItemModel::VerticalSortHint; emit q->layoutAboutToBeChanged(proxyParents, proxyHint); } void QTransposeProxyModelPrivate::onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector& roles) { Q_Q(QTransposeProxyModel); emit q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight), roles); } void QTransposeProxyModelPrivate::onHeaderDataChanged(Qt::Orientation orientation, int first, int last) { Q_Q(QTransposeProxyModel); emit q->headerDataChanged(orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal, first, last); } void QTransposeProxyModelPrivate::onColumnsAboutToBeInserted(const QModelIndex &parent, int first, int last) { Q_Q(QTransposeProxyModel); q->beginInsertRows(q->mapFromSource(parent), first, last); } void QTransposeProxyModelPrivate::onColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last) { Q_Q(QTransposeProxyModel); q->beginRemoveRows(q->mapFromSource(parent), first, last); } void QTransposeProxyModelPrivate::onColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn) { Q_Q(QTransposeProxyModel); q->beginMoveRows(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destinationParent), destinationColumn); } void QTransposeProxyModelPrivate::onRowsAboutToBeInserted(const QModelIndex &parent, int first, int last) { Q_Q(QTransposeProxyModel); q->beginInsertColumns(q->mapFromSource(parent), first, last); } void QTransposeProxyModelPrivate::onRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last) { Q_Q(QTransposeProxyModel); q->beginRemoveColumns(q->mapFromSource(parent), first, last); } void QTransposeProxyModelPrivate::onRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) { Q_Q(QTransposeProxyModel); q->beginMoveColumns(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destinationParent), destinationRow); } /*! \since 5.13 \class QTransposeProxyModel \brief This proxy transposes the source model. This model will make the rows of the source model become columns of the proxy model and vice-versa. If the model is a tree, the parents will be transposed as well. For example, if an index in the source model had parent `index(2,0)`, it will have parent `index(0,2)` in the proxy. */ /*! Constructs a new proxy model with the given \a parent. */ QTransposeProxyModel::QTransposeProxyModel(QObject* parent) : QAbstractProxyModel(*new QTransposeProxyModelPrivate, parent) {} /*! Destructs the proxy model. */ QTransposeProxyModel::~QTransposeProxyModel() = default; /*! \internal */ QTransposeProxyModel::QTransposeProxyModel(QTransposeProxyModelPrivate &dd, QObject *parent) : QAbstractProxyModel(dd, parent) {} /*! \reimp */ void QTransposeProxyModel::setSourceModel(QAbstractItemModel* newSourceModel) { Q_D(QTransposeProxyModel); if (newSourceModel == d->model) return; beginResetModel(); if (d->model) { for (const QMetaObject::Connection& discIter : qAsConst(d->sourceConnections)) disconnect(discIter); } d->sourceConnections.clear(); QAbstractProxyModel::setSourceModel(newSourceModel); if (d->model) { using namespace std::placeholders; d->sourceConnections = QVector{ connect(d->model, &QAbstractItemModel::modelAboutToBeReset, this, &QTransposeProxyModel::beginResetModel), connect(d->model, &QAbstractItemModel::modelReset, this, &QTransposeProxyModel::endResetModel), connect(d->model, &QAbstractItemModel::dataChanged, this, std::bind(&QTransposeProxyModelPrivate::onDataChanged, d, _1, _2, _3)), connect(d->model, &QAbstractItemModel::headerDataChanged, this, std::bind(&QTransposeProxyModelPrivate::onHeaderDataChanged, d, _1, _2, _3)), connect(d->model, &QAbstractItemModel::columnsAboutToBeInserted, this, std::bind(&QTransposeProxyModelPrivate::onColumnsAboutToBeInserted, d, _1, _2, _3)), connect(d->model, &QAbstractItemModel::columnsAboutToBeMoved, this, std::bind(&QTransposeProxyModelPrivate::onColumnsAboutToBeMoved, d, _1, _2, _3, _4, _5)), connect(d->model, &QAbstractItemModel::columnsAboutToBeRemoved, this, std::bind(&QTransposeProxyModelPrivate::onColumnsAboutToBeRemoved, d, _1, _2, _3)), connect(d->model, &QAbstractItemModel::columnsInserted, this, &QTransposeProxyModel::endInsertRows), connect(d->model, &QAbstractItemModel::columnsRemoved, this, &QTransposeProxyModel::endRemoveRows), connect(d->model, &QAbstractItemModel::columnsMoved, this, &QTransposeProxyModel::endMoveRows), connect(d->model, &QAbstractItemModel::rowsAboutToBeInserted, this, std::bind(&QTransposeProxyModelPrivate::onRowsAboutToBeInserted, d, _1, _2, _3)), connect(d->model, &QAbstractItemModel::rowsAboutToBeMoved, this, std::bind(&QTransposeProxyModelPrivate::onRowsAboutToBeMoved, d, _1, _2, _3, _4, _5)), connect(d->model, &QAbstractItemModel::rowsAboutToBeRemoved, this, std::bind(&QTransposeProxyModelPrivate::onRowsAboutToBeRemoved, d, _1, _2, _3)), connect(d->model, &QAbstractItemModel::rowsInserted, this, &QTransposeProxyModel::endInsertColumns), connect(d->model, &QAbstractItemModel::rowsRemoved, this, &QTransposeProxyModel::endRemoveColumns), connect(d->model, &QAbstractItemModel::rowsMoved, this, &QTransposeProxyModel::endMoveColumns), connect(d->model, &QAbstractItemModel::layoutAboutToBeChanged, this, std::bind(&QTransposeProxyModelPrivate::onLayoutAboutToBeChanged, d, _1, _2)), connect(d->model, &QAbstractItemModel::layoutChanged, this, std::bind(&QTransposeProxyModelPrivate::onLayoutChanged, d, _1, _2)) }; } endResetModel(); } /*! \reimp */ int QTransposeProxyModel::rowCount(const QModelIndex &parent) const { Q_D(const QTransposeProxyModel); if (!d->model) return 0; Q_ASSERT(checkIndex(parent)); return d->model->columnCount(mapToSource(parent)); } /*! \reimp */ int QTransposeProxyModel::columnCount(const QModelIndex &parent) const { Q_D(const QTransposeProxyModel); if (!d->model) return 0; Q_ASSERT(checkIndex(parent)); return d->model->rowCount(mapToSource(parent)); } /*! \reimp */ QVariant QTransposeProxyModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_D(const QTransposeProxyModel); if (!d->model) return QVariant(); return d->model->headerData(section, orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal, role); } /*! \reimp */ bool QTransposeProxyModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { Q_D(QTransposeProxyModel); if (!d->model) return false; return d->model->setHeaderData(section, orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal, value, role); } /*! \reimp */ bool QTransposeProxyModel::setItemData(const QModelIndex &index, const QMap &roles) { Q_D(QTransposeProxyModel); Q_ASSERT(checkIndex(index)); if (!d->model || !index.isValid()) return false; return d->model->setItemData(mapToSource(index), roles); } /*! \reimp */ QSize QTransposeProxyModel::span(const QModelIndex &index) const { Q_D(const QTransposeProxyModel); Q_ASSERT(checkIndex(index)); if (!d->model || !index.isValid()) return QSize(); return d->model->span(mapToSource(index)).transposed(); } /*! \reimp */ QMap QTransposeProxyModel::itemData(const QModelIndex &index) const { Q_D(const QTransposeProxyModel); if (!d->model) return QMap(); Q_ASSERT(checkIndex(index)); return d->model->itemData(mapToSource(index)); } /*! \reimp */ QModelIndex QTransposeProxyModel::mapFromSource(const QModelIndex &sourceIndex) const { Q_D(const QTransposeProxyModel); if (!d->model || !sourceIndex.isValid()) return QModelIndex(); Q_ASSERT(d->model->checkIndex(sourceIndex)); return d->uncheckedMapFromSource(sourceIndex); } /*! \reimp */ QModelIndex QTransposeProxyModel::mapToSource(const QModelIndex &proxyIndex) const { Q_D(const QTransposeProxyModel); Q_ASSERT(checkIndex(proxyIndex)); if (!d->model || !proxyIndex.isValid()) return QModelIndex(); return d->uncheckedMapToSource(proxyIndex); } /*! \reimp */ QModelIndex QTransposeProxyModel::parent(const QModelIndex &index) const { Q_D(const QTransposeProxyModel); Q_ASSERT(checkIndex(index, CheckIndexOption::DoNotUseParent)); if (!d->model || !index.isValid()) return QModelIndex(); return d->uncheckedMapFromSource(d->uncheckedMapToSource(index).parent()); } /*! \reimp */ QModelIndex QTransposeProxyModel::index(int row, int column, const QModelIndex &parent) const { Q_D(const QTransposeProxyModel); Q_ASSERT(checkIndex(parent)); if (!d->model) return QModelIndex(); return mapFromSource(d->model->index(column, row, mapToSource(parent))); } /*! \reimp */ bool QTransposeProxyModel::insertRows(int row, int count, const QModelIndex &parent) { Q_D(QTransposeProxyModel); Q_ASSERT(checkIndex(parent)); if (!d->model) return false; return d->model->insertColumns(row, count, mapToSource(parent)); } /*! \reimp */ bool QTransposeProxyModel::removeRows(int row, int count, const QModelIndex &parent) { Q_D(QTransposeProxyModel); Q_ASSERT(checkIndex(parent)); if (!d->model) return false; return d->model->removeColumns(row, count, mapToSource(parent)); } /*! \reimp */ bool QTransposeProxyModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) { Q_D(QTransposeProxyModel); Q_ASSERT(checkIndex(sourceParent)); Q_ASSERT(checkIndex(destinationParent)); if (!d->model) return false; return d->model->moveColumns(mapToSource(sourceParent), sourceRow, count, mapToSource(destinationParent), destinationChild); } /*! \reimp */ bool QTransposeProxyModel::insertColumns(int column, int count, const QModelIndex &parent) { Q_D(QTransposeProxyModel); Q_ASSERT(checkIndex(parent)); if (!d->model) return false; return d->model->insertRows(column, count, mapToSource(parent)); } /*! \reimp */ bool QTransposeProxyModel::removeColumns(int column, int count, const QModelIndex &parent) { Q_D(QTransposeProxyModel); Q_ASSERT(checkIndex(parent)); if (!d->model) return false; return d->model->removeRows(column, count, mapToSource(parent)); } /*! \reimp */ bool QTransposeProxyModel::moveColumns(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) { Q_D(QTransposeProxyModel); Q_ASSERT(checkIndex(sourceParent)); Q_ASSERT(checkIndex(destinationParent)); if (!d->model) return false; return d->model->moveRows(mapToSource(sourceParent), sourceRow, count, mapToSource(destinationParent), destinationChild); } /*! \reimp This method will perform no action. Use a QSortFilterProxyModel on top of this one if you require sorting. */ void QTransposeProxyModel::sort(int column, Qt::SortOrder order) { Q_UNUSED(column) Q_UNUSED(order) return; } QT_END_NAMESPACE #include "moc_qtransposeproxymodel.cpp"