nymea-app/libnymea-app/models/boolseriesadapter.cpp

147 lines
4.7 KiB
C++

#include "boolseriesadapter.h"
BoolSeriesAdapter::BoolSeriesAdapter(QObject *parent)
: QObject{parent}
{
}
LogsModel *BoolSeriesAdapter::logsModel() const
{
return m_model;
}
void BoolSeriesAdapter::setLogsModel(LogsModel *logsModel)
{
if (m_model != logsModel) {
m_model = logsModel;
emit logsModelChanged();
// update();
connect(logsModel, &LogsModel::logEntryAdded, this, &BoolSeriesAdapter::logEntryAdded);
}
}
QtCharts::QXYSeries *BoolSeriesAdapter::xySeries() const
{
return m_series;
}
void BoolSeriesAdapter::setXySeries(QtCharts::QXYSeries *series)
{
if (m_series != series) {
m_series = series;
emit xySeriesChanged();
m_series->clear();
m_series->append(QDateTime::currentDateTime().addYears(1).toMSecsSinceEpoch(), 0);
m_series->append(0, 0);
qWarning() << "Initialized series" << m_series->count();
}
}
bool BoolSeriesAdapter::inverted() const
{
return m_inverted;
}
void BoolSeriesAdapter::setInverted(bool inverted)
{
if (m_inverted != inverted) {
m_inverted = inverted;
emit invertedChanged();
}
}
void BoolSeriesAdapter::logEntryAdded(LogEntry *entry)
{
if (!m_series) {
return;
}
int idx = findIndex(entry->timestamp().toMSecsSinceEpoch());
qreal value = entry->value().toBool() != m_inverted ? 1 : 0;
if (m_series->count() >= 2000) {
qCWarning(dcLogEngine()) << "Thing logs too excessively. Discarding entry.";
return;
}
// QDebug dbg = qWarning();
// dbg << "List before insert:\n";
// for (int i = 0; i < m_series->count(); i++) {
// dbg << i << QDateTime::fromMSecsSinceEpoch(m_series->at(i).x()) << m_series->at(i).y() << "\n";
// }
// qWarning() << "Inserting" << entry->timestamp() << entry->value() << "real value:" << value << "at" << idx << "total:" << m_series->count();
// We're keeping a fake entry at the beginning (timestamp 0) with a static value of 0
// and on in the beginning (+1 year from now) for which we'll update the value according to
// the newest real entry to continue painting the last value.
// Update the future value if this is the new newest real entry
if (idx == 1) {
m_series->replace(0, QDateTime::currentDateTime().addYears(1).toMSecsSinceEpoch(), value);
}
// If the next older entry is different than this, first insert the other value right before this one
if (qFuzzyIsNull(m_series->at(idx).y()) != qFuzzyIsNull(value)) {
m_series->insert(idx, QPointF(entry->timestamp().toMSecsSinceEpoch() - 1, !value));
}
m_series->insert(idx, QPointF(entry->timestamp().toMSecsSinceEpoch(), value));
// If the next newer entry is differnt than this, also insert this value right before the next one
if (qFuzzyIsNull(m_series->at(idx-1).y()) != qFuzzyIsNull(value)) {
m_series->insert(idx, QPointF(m_series->at(idx-1).x() - 1, value));
}
// qWarning() << "***** series count" << m_series->count();
// dbg << "List after insert:\n";
// for (int i = 0; i < m_series->count(); i++) {
// dbg << i << QDateTime::fromMSecsSinceEpoch(m_series->at(i).x()) << m_series->at(i).y() << "\n";
// }
}
quint64 BoolSeriesAdapter::findIndex(qulonglong timestamp)
{
if (m_series->count() == 2) {
return 1;
}
// In 99.9% of the cases we'll be prepending (adding live entries) or appending (fetching history)
if (timestamp < m_series->at(m_series->count() - 2).x()) {
return m_series->count() - 1;
}
if (timestamp > m_series->at(1).x()) {
return 1;
}
// If for any reason a entry in the middle is added (can't think of one but hey), a binary search will probably do.
int idx = m_series->count() / 2;
int range = idx;
int i = 0;
while (true) {
// qWarning() << "CNT:" << m_series->count()
// << "first:" << QDateTime::fromMSecsSinceEpoch(m_series->at(1).x())
// << "last:" << QDateTime::fromMSecsSinceEpoch(m_series->at(m_series->count()- 2).x())
// << "current:" << idx << QDateTime::fromMSecsSinceEpoch(m_series->at(idx).x())
// << "search:" << QDateTime::fromMSecsSinceEpoch(timestamp);
if (timestamp >= m_series->at(idx).x() && timestamp < m_series->at(idx-1).x()) {
return idx;
}
if (timestamp <= m_series->at(idx).x() && timestamp > m_series->at(idx+1).x()) {
return idx+1;
}
range = qMax(1, range / 2);
if (timestamp > m_series->at(idx).x()) {
idx = idx - range;
} else {
idx = idx + range;
}
if (i++ > 2000) {
break;
}
}
return 1;
}