File indexing completed on 2024-05-05 04:38:47

0001 /*
0002     SPDX-FileCopyrightText: 2013 Kevin Funk <kfunk@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "placeholderitemproxymodel.h"
0008 
0009 #include <KColorScheme>
0010 
0011 using namespace KDevelop;
0012 
0013 class KDevelop::PlaceholderItemProxyModelPrivate
0014 {
0015 public:
0016     explicit PlaceholderItemProxyModelPrivate(PlaceholderItemProxyModel* qq)
0017         : q(qq)
0018     {}
0019 
0020     inline int sourceRowCount()
0021     {
0022         return q->sourceModel() ? q->sourceModel()->rowCount() : 0;
0023     }
0024 
0025     inline bool isPlaceholderRow(const QModelIndex& index) const
0026     {
0027         if (!q->sourceModel()) {
0028             return false;
0029         }
0030         return index.row() == q->sourceModel()->rowCount();
0031     }
0032 
0033     PlaceholderItemProxyModel* const q;
0034 
0035     /// column -> hint mapping
0036     QMap<int, QVariant> m_columnHints;
0037 };
0038 
0039 PlaceholderItemProxyModel::PlaceholderItemProxyModel(QObject* parent)
0040     : QIdentityProxyModel(parent)
0041     , d_ptr(new PlaceholderItemProxyModelPrivate(this))
0042 {}
0043 
0044 PlaceholderItemProxyModel::~PlaceholderItemProxyModel()
0045 {
0046 }
0047 
0048 QVariant PlaceholderItemProxyModel::columnHint(int column) const
0049 {
0050     Q_D(const PlaceholderItemProxyModel);
0051 
0052     return d->m_columnHints.value(column);
0053 }
0054 
0055 void PlaceholderItemProxyModel::setColumnHint(int column, const QVariant& hint)
0056 {
0057     Q_D(PlaceholderItemProxyModel);
0058 
0059     if (column < 0) {
0060         return;
0061     }
0062 
0063     d->m_columnHints[column] = hint;
0064 
0065     const int row = d->sourceRowCount();
0066     emit dataChanged(index(row, 0), index(row, columnCount()));
0067 }
0068 
0069 Qt::ItemFlags PlaceholderItemProxyModel::flags(const QModelIndex& index) const
0070 {
0071     Q_D(const PlaceholderItemProxyModel);
0072 
0073     if (d->isPlaceholderRow(index)) {
0074         Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
0075         const int column = index.column();
0076         // if the column doesn't provide a hint we assume that we can't edit this field
0077         if (d->m_columnHints.contains(column)) {
0078             flags |= Qt::ItemIsEditable;
0079         }
0080         return flags;
0081     }
0082 
0083     return QIdentityProxyModel::flags(index);
0084 }
0085 
0086 void PlaceholderItemProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
0087 {
0088     QIdentityProxyModel::setSourceModel(sourceModel);
0089     // TODO: Listen to layoutDataChanged signals?
0090 }
0091 
0092 int PlaceholderItemProxyModel::rowCount(const QModelIndex& parent) const
0093 {
0094     if (!sourceModel())
0095         return 0;
0096 
0097     // only flat models supported for now, assert early in case that's not true
0098     Q_ASSERT(!parent.isValid());
0099     Q_UNUSED(parent);
0100     return sourceModel()->rowCount() + 1;
0101 }
0102 
0103 bool KDevelop::PlaceholderItemProxyModel::hasChildren(const QModelIndex& parent) const
0104 {
0105     if (!parent.isValid()) {
0106         return true;
0107     }
0108     return QIdentityProxyModel::hasChildren(parent);
0109 }
0110 
0111 QVariant PlaceholderItemProxyModel::data(const QModelIndex& proxyIndex, int role) const
0112 {
0113     Q_D(const PlaceholderItemProxyModel);
0114 
0115     const int column = proxyIndex.column();
0116     if (d->isPlaceholderRow(proxyIndex)) {
0117         switch (role) {
0118         case Qt::DisplayRole:
0119             return columnHint(column);
0120         case Qt::ForegroundRole: {
0121             const KColorScheme scheme(QPalette::Normal);
0122             return scheme.foreground(KColorScheme::InactiveText);
0123         }
0124         default:
0125             return QVariant();
0126         }
0127     }
0128     return QIdentityProxyModel::data(proxyIndex, role);
0129 }
0130 
0131 QModelIndex PlaceholderItemProxyModel::parent(const QModelIndex& child) const
0132 {
0133     Q_D(const PlaceholderItemProxyModel);
0134 
0135     if (d->isPlaceholderRow(child)) {
0136         return QModelIndex();
0137     }
0138 
0139     return QIdentityProxyModel::parent(child);
0140 }
0141 
0142 QModelIndex PlaceholderItemProxyModel::buddy(const QModelIndex& index) const
0143 {
0144     Q_D(const PlaceholderItemProxyModel);
0145 
0146     if (d->isPlaceholderRow(index)) {
0147         return index;
0148     }
0149     return QIdentityProxyModel::buddy(index);
0150 }
0151 
0152 QModelIndex PlaceholderItemProxyModel::sibling(int row, int column, const QModelIndex& idx) const
0153 {
0154     const bool isPlaceHolderRow = (sourceModel() ? row == sourceModel()->rowCount() : false);
0155     if (isPlaceHolderRow) {
0156         return index(row, column, QModelIndex());
0157     }
0158     return QIdentityProxyModel::sibling(row, column, idx);
0159 }
0160 
0161 QModelIndex PlaceholderItemProxyModel::mapToSource(const QModelIndex& proxyIndex) const
0162 {
0163     Q_D(const PlaceholderItemProxyModel);
0164 
0165     if (d->isPlaceholderRow(proxyIndex)) {
0166         return QModelIndex();
0167     }
0168     return QIdentityProxyModel::mapToSource(proxyIndex);
0169 }
0170 
0171 bool PlaceholderItemProxyModel::setData(const QModelIndex& index, const QVariant& value, int role)
0172 {
0173     Q_D(PlaceholderItemProxyModel);
0174 
0175     const int column = index.column();
0176     if (d->isPlaceholderRow(index) && role == Qt::EditRole && d->m_columnHints.contains(column)) {
0177         const bool accept = validateRow(index, value);
0178         // if validation fails, clear the complete line
0179         if (!accept) {
0180             emit dataChanged(index, index);
0181             return false;
0182         }
0183 
0184         // update view
0185         emit dataChanged(index, index);
0186 
0187         // notify observers
0188         emit dataInserted(column, value);
0189         return true;
0190     }
0191     return QIdentityProxyModel::setData(index, value, role);
0192 }
0193 
0194 QModelIndex PlaceholderItemProxyModel::index(int row, int column, const QModelIndex& parent) const
0195 {
0196     Q_ASSERT(!parent.isValid());
0197     Q_UNUSED(parent);
0198 
0199     const bool isPlaceHolderRow = (sourceModel() ? row == sourceModel()->rowCount() : false);
0200     if (isPlaceHolderRow) {
0201         return createIndex(row, column);
0202     }
0203     return QIdentityProxyModel::index(row, column, parent);
0204 }
0205 
0206 bool PlaceholderItemProxyModel::validateRow(const QModelIndex& index, const QVariant& value) const
0207 {
0208     Q_UNUSED(index);
0209     return !value.toString().isEmpty();
0210 }
0211 
0212 #include "moc_placeholderitemproxymodel.cpp"