KQuickCharts

ModelSource.cpp
1/*
2 * This file is part of KQuickCharts
3 * SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7
8#include "ModelSource.h"
9
10#include <QMetaProperty>
11
12#include "charts_datasource_logging.h"
13
14ModelSource::ModelSource(QObject *parent)
15 : ChartDataSource(parent)
16{
17 connect(this, &ModelSource::modelChanged, this, &ModelSource::dataChanged);
18 connect(this, &ModelSource::columnChanged, this, &ModelSource::dataChanged);
19 connect(this, &ModelSource::roleChanged, this, &ModelSource::dataChanged);
20 connect(this, &ModelSource::indexColumnsChanged, this, &ModelSource::dataChanged);
21}
22
23int ModelSource::role() const
24{
25 if (!m_model) {
26 return -1;
27 }
28
29 if (m_role < 0 && !m_roleName.isEmpty()) {
30 m_role = m_model->roleNames().key(m_roleName.toLatin1(), -1);
31 }
32
33 return m_role;
34}
35
36QString ModelSource::roleName() const
37{
38 return m_roleName;
39}
40
41int ModelSource::column() const
42{
43 return m_column;
44}
45
46QAbstractItemModel *ModelSource::model() const
47{
48 return m_model;
49}
50
51bool ModelSource::indexColumns() const
52{
53 return m_indexColumns;
54}
55
56int ModelSource::itemCount() const
57{
58 if (!m_model) {
59 return 0;
60 }
61
62 return m_indexColumns ? m_model->columnCount() : m_model->rowCount();
63}
64
65QVariant ModelSource::item(int index) const
66{
67 if (!m_model) {
68 return {};
69 }
70
71 // For certain model (QML ListModel for example), the roleNames() are more
72 // dynamic and may only be valid when this method gets called. So try and
73 // lookup the role first before anything else.
74 if (m_role < 0) {
75 if (m_roleName.isEmpty()) {
76 return QVariant{};
77 }
78
79 m_role = m_model->roleNames().key(m_roleName.toLatin1(), -1);
80 if (m_role < 0) {
81 qCWarning(DATASOURCE) << "ModelSource: Invalid role " << m_role << m_roleName;
82 return QVariant{};
83 }
84 }
85
86 if (!m_indexColumns && (m_column < 0 || m_column > m_model->columnCount())) {
87 qCDebug(DATASOURCE) << "ModelSource: Invalid column" << m_column;
88 return QVariant{};
89 }
90
91 auto modelIndex = m_indexColumns ? m_model->index(0, index) : m_model->index(index, m_column);
92 if (modelIndex.isValid()) {
93 return m_model->data(modelIndex, m_role);
94 }
95
96 return QVariant{};
97}
98
99QVariant ModelSource::minimum() const
100{
101 if (!m_model || itemCount() <= 0) {
102 return {};
103 }
104
105 if (m_minimum.isValid()) {
106 return m_minimum;
107 }
108
109 auto minProperty = m_model->property("minimum");
110 auto maxProperty = m_model->property("maximum");
111 if (minProperty.isValid() && minProperty != maxProperty) {
112 return minProperty;
113 }
114
115 QVariant result = std::numeric_limits<float>::max();
116 for (int i = 0; i < itemCount(); ++i) {
117 result = std::min(result, item(i), variantCompare);
118 }
119 return result;
120}
121
122QVariant ModelSource::maximum() const
123{
124 if (!m_model || itemCount() <= 0) {
125 return {};
126 }
127
128 if (m_maximum.isValid()) {
129 return m_maximum;
130 }
131
132 auto minProperty = m_model->property("minimum");
133 auto maxProperty = m_model->property("maximum");
134 if (maxProperty.isValid() && maxProperty != minProperty) {
135 return maxProperty;
136 }
137
138 QVariant result = std::numeric_limits<float>::min();
139 for (int i = 0; i < itemCount(); ++i) {
140 result = std::max(result, item(i), variantCompare);
141 }
142 return result;
143}
144
145void ModelSource::setRole(int role)
146{
147 if (role == m_role) {
148 return;
149 }
150
151 m_role = role;
152 if (m_model) {
153 m_roleName = QString::fromLatin1(m_model->roleNames().value(role));
154 Q_EMIT roleNameChanged();
155 }
156 Q_EMIT roleChanged();
157}
158
159void ModelSource::setRoleName(const QString &name)
160{
161 if (name == m_roleName) {
162 return;
163 }
164
165 m_roleName = name;
166 if (m_model) {
167 m_role = m_model->roleNames().key(m_roleName.toLatin1(), -1);
168 Q_EMIT roleChanged();
169 }
170 Q_EMIT roleNameChanged();
171}
172
173void ModelSource::setColumn(int column)
174{
175 if (column == m_column) {
176 return;
177 }
178
179 m_column = column;
180 Q_EMIT columnChanged();
181}
182
183void ModelSource::setIndexColumns(bool index)
184{
185 if (index == m_indexColumns) {
186 return;
187 }
188
189 m_indexColumns = index;
190 Q_EMIT indexColumnsChanged();
191}
192
193void ModelSource::setModel(QAbstractItemModel *model)
194{
195 if (m_model == model) {
196 return;
197 }
198
199 if (m_model) {
200 m_model->disconnect(this);
201 m_minimum = QVariant{};
202 m_maximum = QVariant{};
203 }
204
205 m_model = model;
206 if (m_model) {
207 connect(m_model, &QAbstractItemModel::rowsInserted, this, &ModelSource::dataChanged);
208 connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ModelSource::dataChanged);
209 connect(m_model, &QAbstractItemModel::rowsMoved, this, &ModelSource::dataChanged);
210 connect(m_model, &QAbstractItemModel::modelReset, this, &ModelSource::dataChanged);
211 connect(m_model, &QAbstractItemModel::dataChanged, this, &ModelSource::dataChanged);
212 connect(m_model, &QAbstractItemModel::layoutChanged, this, &ModelSource::dataChanged);
213
214 connect(m_model, &QAbstractItemModel::destroyed, this, [this]() {
215 m_minimum = QVariant{};
216 m_maximum = QVariant{};
217 m_model = nullptr;
218 });
219
220 auto minimumIndex = m_model->metaObject()->indexOfProperty("minimum");
221 if (minimumIndex != -1) {
222 auto minimum = m_model->metaObject()->property(minimumIndex);
223 if (minimum.hasNotifySignal()) {
224 auto slot = metaObject()->method(metaObject()->indexOfSlot("onMinimumChanged()"));
225 connect(m_model, minimum.notifySignal(), this, slot);
226 m_minimum = minimum.read(m_model);
227 }
228 }
229
230 auto maximumIndex = m_model->metaObject()->indexOfProperty("maximum");
231 if (maximumIndex != -1) {
232 auto maximum = m_model->metaObject()->property(maximumIndex);
233 if (maximum.hasNotifySignal()) {
234 auto slot = metaObject()->method(metaObject()->indexOfSlot("onMaximumChanged()"));
235 connect(m_model, maximum.notifySignal(), this, slot);
236 m_maximum = maximum.read(m_model);
237 }
238 }
239 }
240
241 Q_EMIT modelChanged();
242}
243
244void ModelSource::onMinimumChanged()
245{
246 auto newMinimum = m_model->property("minimum");
247 if (newMinimum.isValid() && newMinimum != m_minimum) {
248 m_minimum = newMinimum;
249 }
250}
251
252void ModelSource::onMaximumChanged()
253{
254 auto newMaximum = m_model->property("maximum");
255 if (newMaximum.isValid() && newMaximum != m_maximum) {
256 m_maximum = newMaximum;
257 }
258}
259
260#include "moc_ModelSource.cpp"
Abstract base class for data sources.
QString name(StandardShortcut id)
virtual int columnCount(const QModelIndex &parent) const const=0
virtual QVariant data(const QModelIndex &index, int role) const const=0
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
void layoutChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
virtual QHash< int, QByteArray > roleNames() const const
virtual int rowCount(const QModelIndex &parent) const const=0
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
void rowsRemoved(const QModelIndex &parent, int first, int last)
int indexOfProperty(const char *name) const const
QMetaMethod method(int index) const const
QMetaProperty property(int index) const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
bool disconnect(const QMetaObject::Connection &connection)
virtual const QMetaObject * metaObject() const const
QVariant property(const char *name) const const
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QByteArray toLatin1() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isValid() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:57 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.