SensorDataModel.cpp 10.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
    Copyright (c) 2019 Eike Hein <hein@kde.org>
    Copyright (C) 2020 Arjen Hiemstra <ahiemstra@heimr.nl>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

21
22
23
24
#include "SensorDataModel.h"

#include <optional>

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <QMetaEnum>

#include "Formatter.h"
#include "SensorDaemonInterface_p.h"
#include "SensorInfo_p.h"
#include "sensors_logging.h"

using namespace KSysGuard;

class Q_DECL_HIDDEN SensorDataModel::Private
{
public:
    Private(SensorDataModel *qq)
        : q(qq)
    {
    }

    void sensorsChanged();
    void addSensor(const QString &id);
    void removeSensor(const QString &id);

    QStringList requestedSensors;

    QStringList sensors;
    QStringList objects;

    QHash<QString, SensorInfo> sensorInfos;
    QHash<QString, QVariant> sensorData;
53
    QVariantMap sensorColors;
54
55
56
57

    bool usedByQml = false;
    bool componentComplete = false;
    bool loaded = false;
58
    bool enabled = true;
59

60
61
62
    std::optional<qreal> minimum;
    std::optional<qreal> maximum;

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
private:
    SensorDataModel *q;
};

SensorDataModel::SensorDataModel(const QStringList &sensorIds, QObject *parent)
    : QAbstractTableModel(parent)
    , d(new Private(this))
{
    connect(SensorDaemonInterface::instance(), &SensorDaemonInterface::sensorAdded, this, &SensorDataModel::onSensorAdded);
    connect(SensorDaemonInterface::instance(), &SensorDaemonInterface::sensorRemoved, this, &SensorDataModel::onSensorRemoved);
    connect(SensorDaemonInterface::instance(), &SensorDaemonInterface::metaDataChanged, this, &SensorDataModel::onMetaDataChanged);
    connect(SensorDaemonInterface::instance(), &SensorDaemonInterface::valueChanged, this, &SensorDataModel::onValueChanged);

    // Empty string is used for entries that do not specify a wildcard object
    d->objects << QStringLiteral("");

    setSensors(sensorIds);
}

SensorDataModel::~SensorDataModel()
{
}

QHash<int, QByteArray> SensorDataModel::roleNames() const
{
    QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();

    QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles"));

    for (int i = 0; i < e.keyCount(); ++i) {
        roles.insert(e.value(i), e.key(i));
    }

    return roles;
}

QVariant SensorDataModel::data(const QModelIndex &index, int role) const
{
    const bool check = checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::DoNotUseParent);
    if (!check) {
        return QVariant();
    }

    auto sensor = d->sensors.at(index.column());
    auto info = d->sensorInfos.value(sensor);
    auto data = d->sensorData.value(sensor);

    switch (role) {
    case Qt::DisplayRole:
    case FormattedValue:
        return Formatter::formatValue(data, info.unit);
    case Value:
        return data;
    case Unit:
        return info.unit;
    case Name:
        return info.name;
    case ShortName:
        if (info.shortName.isEmpty()) {
            return info.name;
        }
        return info.shortName;
    case Description:
        return info.description;
    case Minimum:
        return info.min;
    case Maximum:
        return info.max;
    case Type:
        return info.variantType;
    case SensorId:
        return sensor;
135
136
137
138
    case Color:
        if (!d->sensorColors.empty()) {
            return d->sensorColors.value(sensor);
        }
139
        break;
140
141
142
    case UpdateInterval:
        //TODO: Make this dynamic once the backend supports it.
        return BackendUpdateInterval;
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
    default:
        break;
    }

    return QVariant();
}

QVariant SensorDataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Vertical) {
        return QVariant();
    }

    if (section < 0 || section >= d->sensors.size()) {
        return QVariant();
    }

    auto sensor = d->sensors.at(section);
    auto info = d->sensorInfos.value(sensor);

    switch (role) {
    case Qt::DisplayRole:
    case ShortName:
        if (info.shortName.isEmpty()) {
            return info.name;
        }
        return info.shortName;
    case Name:
        return info.name;
    case SensorId:
        return sensor;
    case Unit:
        return info.unit;
    case Description:
        return info.description;
    case Minimum:
        return info.min;
    case Maximum:
        return info.max;
    case Type:
        return info.variantType;
184
185
186
    case UpdateInterval:
        //TODO: Make this dynamic once the backend supports it.
        return BackendUpdateInterval;
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
    default:
        break;
    }

    return QVariant();
}

int SensorDataModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }

    return d->objects.count();
}

int SensorDataModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }

209
    return d->sensorInfos.count();
210
211
212
213
214
215
216
217
}

qreal SensorDataModel::minimum() const
{
    if (d->sensors.isEmpty()) {
        return 0;
    }

218
219
220
221
    if (d->minimum.has_value()) {
        return d->minimum.value();
    }

222
    auto result = std::min_element(d->sensorInfos.cbegin(), d->sensorInfos.cend(), [](const SensorInfo &first, const SensorInfo &second) { return first.min < second.min; });
223
224
    d->minimum = (*result).min;
    return d->minimum.value();
225
226
227
228
229
230
231
232
}

qreal SensorDataModel::maximum() const
{
    if (d->sensors.isEmpty()) {
        return 0;
    }

233
234
235
236
    if (d->maximum.has_value()) {
        return d->maximum.value();
    }

237
    auto result = std::max_element(d->sensorInfos.cbegin(), d->sensorInfos.cend(), [](const SensorInfo &first, const SensorInfo &second) { return first.max < second.max; });
238
239
    d->maximum = (*result).max;
    return d->maximum.value();
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
}

QStringList SensorDataModel::sensors() const
{
    return d->requestedSensors;
}

void SensorDataModel::setSensors(const QStringList &sensorIds)
{
    if (d->requestedSensors == sensorIds) {
        return;
    }

    d->requestedSensors = sensorIds;

    if (!d->usedByQml || d->componentComplete) {
        d->sensorsChanged();
    }
258
    Q_EMIT readyChanged();
259
260
261
    Q_EMIT sensorsChanged();
}

262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
bool SensorDataModel::enabled() const
{
    return d->enabled;
}

void SensorDataModel::setEnabled(bool newEnabled)
{
    if (newEnabled == d->enabled) {
        return;
    }

    d->enabled = newEnabled;
    if (d->enabled) {
        SensorDaemonInterface::instance()->subscribe(d->sensorInfos.keys());
        SensorDaemonInterface::instance()->requestMetaData(d->sensorInfos.keys());
    } else {
        SensorDaemonInterface::instance()->unsubscribe(d->sensorInfos.keys());
    }

    Q_EMIT enabledChanged();
}

284
285
286
287
288
289
290
291
292
293
294
295
296
QVariantMap SensorDataModel::sensorColors() const
{
    return d->sensorColors;
}

void SensorDataModel::setSensorColors(const QVariantMap &sensorColors)
{
    if (sensorColors == d->sensorColors) {
        return;
    }
    d->sensorColors = sensorColors;
    Q_EMIT sensorColorsChanged();
}
297

298
299
bool KSysGuard::SensorDataModel::isReady() const
{
300
    return d->sensors.size() == d->sensorInfos.size();
301
302
}

303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
void SensorDataModel::addSensor(const QString &sensorId)
{
    d->addSensor(sensorId);
}

void SensorDataModel::removeSensor(const QString &sensorId)
{
    d->removeSensor(sensorId);
}

int KSysGuard::SensorDataModel::column(const QString &sensorId) const
{
    return d->sensors.indexOf(sensorId);
}

void KSysGuard::SensorDataModel::classBegin()
{
    d->usedByQml = true;
}

void KSysGuard::SensorDataModel::componentComplete()
{
    d->componentComplete = true;

    d->sensorsChanged();

    emit sensorsChanged();
}

void SensorDataModel::Private::addSensor(const QString &id)
{
334
    if (!requestedSensors.contains(id)) {
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
        return;
    }

    qCDebug(LIBKSYSGUARD_SENSORS) << "Add Sensor" << id;

    sensors.append(id);
    SensorDaemonInterface::instance()->subscribe(id);
    SensorDaemonInterface::instance()->requestMetaData(id);
}

void SensorDataModel::Private::removeSensor(const QString &id)
{
    const int col = sensors.indexOf(id);
    if (col == -1) {
        return;
    }

    q->beginRemoveColumns(QModelIndex(), col, col);

    sensors.removeAt(col);
    sensorInfos.remove(id);
    sensorData.remove(id);

    q->endRemoveColumns();
}

void SensorDataModel::onSensorAdded(const QString &sensorId)
{
363
364
365
366
    if (!d->enabled) {
        return;
    }

367
368
369
370
371
    d->addSensor(sensorId);
}

void SensorDataModel::onSensorRemoved(const QString &sensorId)
{
372
373
374
375
    if (!d->enabled) {
        return;
    }

376
377
378
379
380
    d->removeSensor(sensorId);
}

void SensorDataModel::onMetaDataChanged(const QString &sensorId, const SensorInfo &info)
{
381
382
383
384
    if (!d->enabled) {
        return;
    }

385
386
387
388
389
390
391
    auto column = d->sensors.indexOf(sensorId);
    if (column == -1) {
        return;
    }

    qCDebug(LIBKSYSGUARD_SENSORS) << "Received metadata change for" << sensorId;

392
393
394
    d->minimum.reset();
    d->maximum.reset();

395
396
397
398
    // Simple case: Just an update for a sensor's metadata
    if (d->sensorInfos.contains(sensorId)) {
        d->sensorInfos[sensorId] = info;
        Q_EMIT dataChanged(index(0, column), index(0, column), {Qt::DisplayRole, Name, ShortName, Description, Unit, Minimum, Maximum, Type, FormattedValue});
399
        Q_EMIT sensorMetaDataChanged();
400
401
402
403
        return;
    }

    // Otherwise, it's a new sensor that was added
404
405
406
407
408
409

    // Ensure we do not insert columns that are out of range.
    while (d->sensorInfos.count() + 1 <= column && column > 0) {
        column--;
    }

410
411
412
413
414
415
416
    beginInsertColumns(QModelIndex{}, column, column);
    d->sensorInfos[sensorId] = info;
    d->sensorData[sensorId] = QVariant{};
    endInsertColumns();

    SensorDaemonInterface::instance()->requestValue(sensorId);
    emit sensorMetaDataChanged();
417
418
419
420

    if (isReady()) {
        Q_EMIT readyChanged();
    }
421
422
423
424
}

void SensorDataModel::onValueChanged(const QString &sensorId, const QVariant &value)
{
425
426
    const auto column = d->sensors.indexOf(sensorId);
    if (column == -1 || !d->enabled) {
427
428
429
430
431
432
433
434
435
        return;
    }

    d->sensorData[sensorId] = value;
    Q_EMIT dataChanged(index(0, column), index(0, column), {Qt::DisplayRole, Value, FormattedValue});
}

void SensorDataModel::Private::sensorsChanged()
{
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    q->beginResetModel();

    SensorDaemonInterface::instance()->unsubscribe(sensors);

    sensors.clear();
    sensorData.clear();
    sensorInfos.clear();

    sensors = requestedSensors;

    SensorDaemonInterface::instance()->subscribe(requestedSensors);
    SensorDaemonInterface::instance()->requestMetaData(requestedSensors);

    q->endResetModel();
450
}