File indexing completed on 2025-01-26 05:09:00
0001 /* 0002 SPDX-FileCopyrightText: 2010 Marco Martin <mart@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef DATAMODEL_H 0008 #define DATAMODEL_H 0009 0010 #include <QAbstractItemModel> 0011 #include <QJSValue> 0012 #include <QList> 0013 #include <QRegularExpression> 0014 #include <QSortFilterProxyModel> 0015 0016 #include <Plasma5Support/DataEngine> 0017 0018 class QTimer; 0019 0020 // All classes here will hopefully be removed in KF6 (along with DataEngines in general) 0021 0022 namespace Plasma5Support 0023 { 0024 class DataSource; 0025 class DataModel; 0026 0027 /** 0028 * @class SortFilterModel 0029 * @short Filter and sort an existing QAbstractItemModel 0030 */ 0031 class SortFilterModel : public QSortFilterProxyModel 0032 { 0033 Q_OBJECT 0034 /** 0035 * The source model of this sorting proxy model. It has to inherit QAbstractItemModel (ListModel is not supported) 0036 */ 0037 Q_PROPERTY(QAbstractItemModel *sourceModel READ sourceModel WRITE setModel NOTIFY sourceModelChanged) 0038 0039 /** 0040 * The regular expression for the filter, only items with their filterRole matching filterRegExp will be displayed 0041 */ 0042 Q_PROPERTY(QString filterRegExp READ filterRegExp WRITE setFilterRegExp NOTIFY filterRegExpChanged) 0043 0044 /** 0045 * The string for the filter, only items with their filterRole matching filterString will be displayed 0046 */ 0047 Q_PROPERTY(QString filterString READ filterString WRITE setFilterString NOTIFY filterStringChanged REVISION 1) 0048 0049 /** 0050 * A JavaScript callable that is passed the source model row index as first argument and the value 0051 * of filterRole as second argument. The callable's return value is evaluated as boolean to determine 0052 * whether the row is accepted (true) or filtered out (false). It overrides the default implementation 0053 * that uses filterRegExp or filterString; while filterCallable is set those two properties are 0054 * ignored. Attempts to write a non-callable to this property are silently ignored, but you can set 0055 * it to null. 0056 */ 0057 Q_PROPERTY(QJSValue filterCallback READ filterCallback WRITE setFilterCallback NOTIFY filterCallbackChanged REVISION 1) 0058 0059 /** 0060 * The role of the sourceModel on which filterRegExp must be applied. 0061 */ 0062 Q_PROPERTY(QString filterRole READ filterRole WRITE setFilterRole) 0063 0064 /** 0065 * The role of the sourceModel that will be used for sorting. if empty the order will be left unaltered 0066 */ 0067 Q_PROPERTY(QString sortRole READ sortRole WRITE setSortRole) 0068 0069 /** 0070 * One of Qt.Ascending or Qt.Descending 0071 */ 0072 Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder) 0073 0074 /** 0075 * Specify which column should be used for sorting 0076 */ 0077 Q_PROPERTY(int sortColumn READ sortColumn WRITE setSortColumn NOTIFY sortColumnChanged) 0078 0079 /** 0080 * How many items are in this model 0081 */ 0082 Q_PROPERTY(int count READ count NOTIFY countChanged) 0083 0084 friend class DataModel; 0085 0086 public: 0087 explicit SortFilterModel(QObject *parent = nullptr); 0088 ~SortFilterModel() override; 0089 0090 void setModel(QAbstractItemModel *source); 0091 0092 void setFilterRegExp(const QString &exp); 0093 QString filterRegExp() const; 0094 0095 void setFilterString(const QString &filterString); 0096 QString filterString() const; 0097 0098 void setFilterCallback(const QJSValue &callback); 0099 QJSValue filterCallback() const; 0100 0101 void setFilterRole(const QString &role); 0102 QString filterRole() const; 0103 0104 void setSortRole(const QString &role); 0105 QString sortRole() const; 0106 0107 void setSortOrder(const Qt::SortOrder order); 0108 0109 void setSortColumn(int column); 0110 0111 int count() const 0112 { 0113 return QSortFilterProxyModel::rowCount(); 0114 } 0115 0116 /** 0117 * Returns the item at index in the list model. 0118 * This allows the item data to be accessed (but not modified) from JavaScript. 0119 * It returns an Object with a property for each role. 0120 * 0121 * @param i the row we want 0122 */ 0123 Q_INVOKABLE QVariantMap get(int i) const; 0124 0125 Q_INVOKABLE int mapRowToSource(int i) const; 0126 0127 Q_INVOKABLE int mapRowFromSource(int i) const; 0128 0129 Q_SIGNALS: 0130 void countChanged(); 0131 void sortColumnChanged(); 0132 void sourceModelChanged(QObject *); 0133 void filterRegExpChanged(const QString &); 0134 Q_REVISION(1) void filterStringChanged(const QString &); 0135 Q_REVISION(1) void filterCallbackChanged(const QJSValue &); 0136 0137 protected: 0138 int roleNameToId(const QString &name) const; 0139 bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; 0140 QHash<int, QByteArray> roleNames() const override; 0141 0142 protected Q_SLOTS: 0143 void syncRoleNames(); 0144 0145 private: 0146 QString m_filterRole; 0147 QString m_sortRole; 0148 QString m_filterString; 0149 QJSValue m_filterCallback; 0150 QHash<QString, int> m_roleIds; 0151 }; 0152 0153 /** 0154 * @class DataModel 0155 * @short DataSource data as a model 0156 */ 0157 class DataModel : public QAbstractItemModel 0158 { 0159 Q_OBJECT 0160 0161 /** 0162 * The instance of DataSource to construct this model on 0163 */ 0164 Q_PROPERTY(QObject *dataSource READ dataSource WRITE setDataSource) 0165 0166 /** 0167 * It's a regular expression. Only data with keys that match this filter 0168 * expression will be inserted in the model 0169 */ 0170 Q_PROPERTY(QString keyRoleFilter READ keyRoleFilter WRITE setKeyRoleFilter) 0171 0172 /** 0173 * It's a regular expression. If the DataSource is connected to more than one source, 0174 * only inserts data from sources matching this filter expression in the model. If we 0175 * want to have a source watch all sources beginning with say "name:", the required 0176 * regexp would be sourceFilter: "name:.*" 0177 */ 0178 Q_PROPERTY(QString sourceFilter READ sourceFilter WRITE setSourceFilter) 0179 0180 /** 0181 * How many items are in this model 0182 */ 0183 Q_PROPERTY(int count READ count NOTIFY countChanged) 0184 0185 public: 0186 DataModel(QObject *parent = nullptr); 0187 ~DataModel() override; 0188 0189 void setDataSource(QObject *source); 0190 QObject *dataSource() const; 0191 0192 /** 0193 * Include only items with a key that matches this regexp in the model 0194 */ 0195 void setKeyRoleFilter(const QString &key); 0196 QString keyRoleFilter() const; 0197 0198 /** 0199 * Include only sources that matches this regexp in the model 0200 */ 0201 void setSourceFilter(const QString &key); 0202 QString sourceFilter() const; 0203 0204 // Reimplemented 0205 QVariant data(const QModelIndex &index, int role) const override; 0206 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 0207 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 0208 QModelIndex parent(const QModelIndex &child) const override; 0209 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0210 int columnCount(const QModelIndex &parent = QModelIndex()) const override; 0211 0212 int count() const 0213 { 0214 return countItems(); 0215 } 0216 0217 /** 0218 * Returns the item at index in the list model. 0219 * This allows the item data to be accessed (but not modified) from JavaScript. 0220 * It returns an Object with a property for each role. 0221 * 0222 * @param i the row we want 0223 */ 0224 Q_INVOKABLE QVariantMap get(int i) const; 0225 0226 protected: 0227 void setItems(const QString &sourceName, const QVariantList &list); 0228 inline int countItems() const; 0229 QHash<int, QByteArray> roleNames() const override; 0230 Q_SIGNALS: 0231 void countChanged(); 0232 void sourceModelChanged(QObject *); 0233 void filterRegExpChanged(const QString &); 0234 0235 private Q_SLOTS: 0236 void dataUpdated(const QString &sourceName, const QVariantMap &data); 0237 void removeSource(const QString &sourceName); 0238 0239 private: 0240 DataSource *m_dataSource; 0241 QString m_keyRoleFilter; 0242 QRegularExpression m_keyRoleFilterRE; 0243 QString m_sourceFilter; 0244 QRegularExpression m_sourceFilterRE; 0245 QMap<QString, QList<QVariant>> m_items; 0246 QHash<int, QByteArray> m_roleNames; 0247 QHash<QString, int> m_roleIds; 0248 int m_maxRoleId; 0249 }; 0250 0251 int DataModel::countItems() const 0252 { 0253 int count = 0; 0254 for (const QList<QVariant> &v : std::as_const(m_items)) { 0255 count += v.count(); 0256 } 0257 return count; 0258 } 0259 0260 } 0261 #endif