File indexing completed on 2025-02-16 04:45:51

0001 /*
0002     This file is part of Akonadi Contact.
0003 
0004     SPDX-FileCopyrightText: 2010 KDAB
0005     SPDX-FileContributor: Tobias Koenig <tokoe@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "leafextensionproxymodel_p.h"
0011 
0012 #include <QSet>
0013 
0014 using namespace Akonadi;
0015 
0016 class Akonadi::LeafExtensionProxyModelPrivate
0017 {
0018 public:
0019     explicit LeafExtensionProxyModelPrivate(LeafExtensionProxyModel *qq)
0020         : q(qq)
0021     {
0022     }
0023 
0024     void sourceRowsInserted(const QModelIndex &parentIndex, int start, int end);
0025     void sourceRowsRemoved(const QModelIndex &parentIndex, int start, int end);
0026 
0027     LeafExtensionProxyModel *const q;
0028     QMap<qint64, QModelIndex> mParentIndexes;
0029     QSet<QModelIndex> mOwnIndexes;
0030     qint64 mUniqueKeyCounter = 0;
0031 };
0032 
0033 void LeafExtensionProxyModelPrivate::sourceRowsInserted(const QModelIndex &parentIndex, int start, int end)
0034 {
0035     // iterate over all of our stored parent indexes
0036     QMutableMapIterator<qint64, QModelIndex> it(mParentIndexes);
0037     while (it.hasNext()) {
0038         it.next();
0039         if (it.value().parent() == parentIndex) {
0040             if (it.value().row() >= start) {
0041                 const QModelIndex newIndex = q->QSortFilterProxyModel::index(it.value().row() + (end - start) + 1, it.value().column(), parentIndex);
0042                 it.setValue(newIndex);
0043             }
0044         }
0045     }
0046 }
0047 
0048 void LeafExtensionProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parentIndex, int start, int end)
0049 {
0050     // iterate over all of our stored parent indexes
0051     QMutableMapIterator<qint64, QModelIndex> it(mParentIndexes);
0052     while (it.hasNext()) {
0053         it.next();
0054         if (it.value().parent() == parentIndex) {
0055             if (it.value().row() >= start && it.value().row() <= end) {
0056                 it.remove();
0057             } else if (it.value().row() > end) {
0058                 const QModelIndex newIndex = q->index(it.value().row() - (end - start) - 1, it.value().column(), parentIndex);
0059                 it.setValue(newIndex);
0060             }
0061         }
0062     }
0063 }
0064 
0065 LeafExtensionProxyModel::LeafExtensionProxyModel(QObject *parent)
0066     : QSortFilterProxyModel(parent)
0067     , d(new LeafExtensionProxyModelPrivate(this))
0068 {
0069 }
0070 
0071 LeafExtensionProxyModel::~LeafExtensionProxyModel() = default;
0072 
0073 QModelIndex LeafExtensionProxyModel::index(int row, int column, const QModelIndex &parent) const
0074 {
0075     if (row < 0 || column < 0) {
0076         return {};
0077     }
0078 
0079     if (parent.isValid()) {
0080         const QModelIndex sourceParent = mapToSource(parent);
0081         const QModelIndex sourceIndex = sourceModel()->index(row, column, sourceParent);
0082         if (!sourceIndex.isValid()) {
0083             qint64 key = -1;
0084             QMapIterator<qint64, QModelIndex> it(d->mParentIndexes);
0085             while (it.hasNext()) {
0086                 it.next();
0087                 if (it.value() == parent) {
0088                     key = it.key();
0089                     break;
0090                 }
0091             }
0092 
0093             if (key == -1) {
0094                 key = ++(d->mUniqueKeyCounter);
0095                 d->mParentIndexes.insert(key, parent);
0096             }
0097 
0098             const QModelIndex index = createIndex(row, column, static_cast<quint32>(key));
0099             d->mOwnIndexes.insert(index);
0100 
0101             return index;
0102         }
0103     }
0104 
0105     return QSortFilterProxyModel::index(row, column, parent);
0106 }
0107 
0108 QModelIndex LeafExtensionProxyModel::parent(const QModelIndex &index) const
0109 {
0110     if (d->mOwnIndexes.contains(index)) {
0111         return d->mParentIndexes.value(index.internalId());
0112     }
0113 
0114     return QSortFilterProxyModel::parent(index);
0115 }
0116 
0117 int LeafExtensionProxyModel::rowCount(const QModelIndex &index) const
0118 {
0119     if (d->mOwnIndexes.contains(index)) {
0120         return 0;
0121     }
0122 
0123     const QModelIndex sourceIndex = mapToSource(index);
0124     if (sourceModel()->rowCount(sourceIndex) == 0) {
0125         return leafRowCount(index);
0126     }
0127 
0128     return QSortFilterProxyModel::rowCount(index);
0129 }
0130 
0131 int LeafExtensionProxyModel::columnCount(const QModelIndex &index) const
0132 {
0133     if (d->mOwnIndexes.contains(index)) {
0134         return 1;
0135     }
0136 
0137     return QSortFilterProxyModel::columnCount(index);
0138 }
0139 
0140 QVariant LeafExtensionProxyModel::data(const QModelIndex &index, int role) const
0141 {
0142     if (d->mOwnIndexes.contains(index)) {
0143         return leafData(index.parent(), index.row(), index.column(), role);
0144     }
0145 
0146     return QSortFilterProxyModel::data(index, role);
0147 }
0148 
0149 Qt::ItemFlags LeafExtensionProxyModel::flags(const QModelIndex &index) const
0150 {
0151     if (d->mOwnIndexes.contains(index)) {
0152         return Qt::ItemFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
0153     }
0154 
0155     return QSortFilterProxyModel::flags(index);
0156 }
0157 
0158 bool LeafExtensionProxyModel::setData(const QModelIndex &index, const QVariant &data, int role)
0159 {
0160     if (d->mOwnIndexes.contains(index)) {
0161         return false;
0162     }
0163 
0164     return QSortFilterProxyModel::setData(index, data, role);
0165 }
0166 
0167 bool LeafExtensionProxyModel::hasChildren(const QModelIndex &parent) const
0168 {
0169     if (d->mOwnIndexes.contains(parent)) {
0170         return false; // extensible in the future?
0171     }
0172 
0173     const QModelIndex sourceParent = mapToSource(parent);
0174     if (sourceModel() && sourceModel()->rowCount(sourceParent) == 0) {
0175         return leafRowCount(parent) != 0;
0176     }
0177 
0178     return QSortFilterProxyModel::hasChildren(parent);
0179 }
0180 
0181 QModelIndex LeafExtensionProxyModel::buddy(const QModelIndex &index) const
0182 {
0183     if (d->mOwnIndexes.contains(index)) {
0184         return index;
0185     }
0186 
0187     return QSortFilterProxyModel::buddy(index);
0188 }
0189 
0190 void LeafExtensionProxyModel::fetchMore(const QModelIndex &index)
0191 {
0192     if (d->mOwnIndexes.contains(index)) {
0193         return;
0194     }
0195 
0196     QSortFilterProxyModel::fetchMore(index);
0197 }
0198 
0199 void LeafExtensionProxyModel::setSourceModel(QAbstractItemModel *_sourceModel)
0200 {
0201     if (_sourceModel == sourceModel()) {
0202         return;
0203     }
0204 
0205     beginResetModel();
0206 
0207     disconnect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(sourceRowsInserted(QModelIndex, int, int)));
0208     disconnect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(sourceRowsRemoved(QModelIndex, int, int)));
0209 
0210     QSortFilterProxyModel::setSourceModel(_sourceModel);
0211 
0212     connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(sourceRowsInserted(QModelIndex, int, int)));
0213     connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(sourceRowsRemoved(QModelIndex, int, int)));
0214 
0215     endResetModel();
0216 }
0217 
0218 #include "moc_leafextensionproxymodel_p.cpp"