Warning, file /system/plasma-packagekit/src/AbstractModel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     Copyright © 2014-2017 Harald Sitter <sitter@kde.org>
0003     Copyright © 2016 David Rosca <nowrep@gmail.com>
0004 
0005     This library is free software; you can redistribute it and/or
0006     modify it under the terms of the GNU Lesser General Public
0007     License as published by the Free Software Foundation; either
0008     version 2.1 of the License, or (at your option) version 3, or any
0009     later version accepted by the membership of KDE e.V. (or its
0010     successor approved by the membership of KDE e.V.), which shall
0011     act as a proxy defined in Section 6 of version 3 of the license.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Lesser General Public License for more details.
0017 
0018     You should have received a copy of the GNU Lesser General Public
0019     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0020 */
0021 
0022 #include "AbstractModel.h"
0023 
0024 #include <QMetaProperty>
0025 
0026 #include "Debug.h"
0027 
0028 AbstractModel::AbstractModel(QMap<QString, QObject *> *map, QObject *parent)
0029     : QAbstractListModel(parent)
0030     , m_map(map)
0031 {
0032 }
0033 
0034 QHash<int, QByteArray> AbstractModel::roleNames() const
0035 {
0036     if (!m_roles.empty()) {
0037         qCDebug(PLASMAPK) << "returning roles" << m_roles;
0038         return m_roles;
0039     }
0040     Q_UNREACHABLE();
0041     return QHash<int, QByteArray>();
0042 }
0043 
0044 int AbstractModel::rowCount(const QModelIndex &parent) const
0045 {
0046     Q_UNUSED(parent);
0047     return m_map->count();
0048 }
0049 
0050 QVariant AbstractModel::data(const QModelIndex &index, int role) const
0051 {
0052     auto data = m_map->values().at(index.row());
0053     Q_ASSERT(data);
0054     if (role == ObjectRole) {
0055         return QVariant::fromValue(data);
0056     }
0057     int property = m_objectProperties.value(role, -1);
0058     if (property == -1) {
0059         qCDebug(PLASMAPK) << "failed to resolve property " << role;
0060         return QVariant();
0061     }
0062     return data->metaObject()->property(property).read(data);
0063 }
0064 
0065 int AbstractModel::role(const QByteArray &roleName) const
0066 {
0067     qCDebug(PLASMAPK) << roleName << m_roles.key(roleName, -1);
0068     return m_roles.key(roleName, -1);
0069 }
0070 
0071 void AbstractModel::initRoleNames(const QMetaObject &qobjectMetaObject)
0072 {
0073     m_roles[ObjectRole] = QByteArrayLiteral("ModelObject");
0074 
0075     QMetaEnum enumerator;
0076     for (int i = 0; i < metaObject()->enumeratorCount(); ++i) {
0077         if (metaObject()->enumerator(i).name() == QLatin1String("ItemRole")) {
0078             enumerator = metaObject()->enumerator(i);
0079             break;
0080         }
0081     }
0082 
0083     for (int i = 0; i < enumerator.keyCount(); ++i) {
0084         // Clip the Role suffix and glue it in the hash.
0085         const int roleLength = 4;
0086         QByteArray key(enumerator.key(i));
0087         // Enum values must end in Role or the enum is crap
0088         Q_ASSERT(key.right(roleLength) == QByteArrayLiteral("Role"));
0089         key.chop(roleLength);
0090         m_roles[enumerator.value(i)] = key;
0091     }
0092 
0093     int maxEnumValue = -1;
0094     for (auto it = m_roles.constBegin(); it != m_roles.constEnd(); ++it) {
0095         if (it.key() > maxEnumValue) {
0096             maxEnumValue = it.key();
0097         }
0098     }
0099     Q_ASSERT(maxEnumValue != -1);
0100     auto mo = qobjectMetaObject;
0101     for (int i = 0; i < mo.propertyCount(); ++i) {
0102         QMetaProperty property = mo.property(i);
0103         QString name(property.name());
0104         // Coerece first char to be lower case to ensure we are consistent there.
0105         name.replace(0, 1, name.at(0).toLower());
0106         m_roles[++maxEnumValue] = name.toLatin1();
0107         m_objectProperties.insert(maxEnumValue, i);
0108         if (!property.hasNotifySignal()) {
0109             continue;
0110         }
0111         m_signalIndexToProperties.insert(property.notifySignalIndex(), i);
0112     }
0113     qCDebug(PLASMAPK) << m_roles;
0114 
0115     // Connect to property changes also with objects already in model
0116     for (int i = 0; i < m_map->keys().count(); ++i) {
0117         onDataAdded(i);
0118     }
0119 }
0120 
0121 void AbstractModel::propertyChanged()
0122 {
0123     if (!sender() || senderSignalIndex() == -1) {
0124         return;
0125     }
0126     int propertyIndex = m_signalIndexToProperties.value(senderSignalIndex(), -1);
0127     if (propertyIndex == -1) {
0128         return;
0129     }
0130     int role = m_objectProperties.key(propertyIndex, -1);
0131     if (role == -1) {
0132         return;
0133     }
0134     int index = m_map->values().indexOf(sender());
0135     qCDebug(PLASMAPK) << "PROPERTY CHANGED (" << index << ") :: " << role << roleNames().value(role);
0136     emit dataChanged(createIndex(index, 0), createIndex(index, 0), {role});
0137 }
0138 
0139 void AbstractModel::onDataAdded(int index)
0140 {
0141     beginInsertRows(QModelIndex(), index, index);
0142     QObject *data = m_map->values().at(index);
0143     const QMetaObject *mo = data->metaObject();
0144     // We have all the data changed notify signals already stored
0145     auto keys = m_signalIndexToProperties.keys();
0146     foreach (int index, keys) {
0147         QMetaMethod meth = mo->method(index);
0148         connect(data, meth, this, propertyChangedMetaMethod());
0149     }
0150     endInsertRows();
0151 }
0152 
0153 void AbstractModel::onDataRemoved(int index)
0154 {
0155     beginRemoveRows(QModelIndex(), index, index);
0156     endRemoveRows();
0157 }
0158 
0159 QMetaMethod AbstractModel::propertyChangedMetaMethod() const
0160 {
0161     auto mo = metaObject();
0162     int methodIndex = mo->indexOfMethod("propertyChanged()");
0163     if (methodIndex == -1) {
0164         return QMetaMethod();
0165     }
0166     return mo->method(methodIndex);
0167 }