Warning, file /frameworks/kquickcharts/src/datasource/HistoryProxySource.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of KQuickCharts
0003  * SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006  */
0007 
0008 #include "HistoryProxySource.h"
0009 
0010 #include <QDebug>
0011 
0012 HistoryProxySource::HistoryProxySource(QObject *parent)
0013     : ChartDataSource(parent)
0014 {
0015 }
0016 
0017 int HistoryProxySource::itemCount() const
0018 {
0019     if (m_fillMode == DoNotFill) {
0020         return m_history.size();
0021     } else {
0022         return m_maximumHistory;
0023     }
0024 }
0025 
0026 QVariant HistoryProxySource::item(int index) const
0027 {
0028     if (index < 0 || !m_dataSource || m_dataSource->itemCount() == 0) {
0029         return QVariant{};
0030     }
0031 
0032     if (m_fillMode == DoNotFill && index >= m_history.count()) {
0033         return QVariant{};
0034     }
0035 
0036     if (m_fillMode == FillFromStart && index >= m_history.count()) {
0037         return QVariant{m_dataSource->item(0).type()};
0038     }
0039 
0040     if (m_fillMode == FillFromEnd && m_history.count() != m_maximumHistory) {
0041         auto actualIndex = index - (m_maximumHistory - m_history.count());
0042         if (actualIndex < 0 || actualIndex >= m_history.size()) {
0043             return QVariant{m_dataSource->item(0).type()};
0044         } else {
0045             return m_history.at(actualIndex);
0046         }
0047     }
0048 
0049     if (index < m_history.count()) {
0050         return m_history.at(index);
0051     } else {
0052         return QVariant{};
0053     }
0054 }
0055 
0056 QVariant HistoryProxySource::minimum() const
0057 {
0058     if (m_history.isEmpty() || !m_dataSource) {
0059         return QVariant{};
0060     }
0061 
0062     // TODO: Find a nicer solution for data sources to indicate
0063     // "I provide a min/max value not derived from my items"
0064     auto model = m_dataSource->property("model").value<QObject *>();
0065     if (model) {
0066         auto minProperty = model->property("minimum");
0067         auto maxProperty = model->property("maximum");
0068         if (minProperty.isValid() && minProperty != maxProperty) {
0069             return minProperty;
0070         }
0071     }
0072 
0073     return *std::min_element(m_history.begin(), m_history.end(), variantCompare);
0074 }
0075 
0076 QVariant HistoryProxySource::maximum() const
0077 {
0078     if (m_history.isEmpty() || !m_dataSource) {
0079         return QVariant{};
0080     }
0081 
0082     auto model = m_dataSource->property("model").value<QObject *>();
0083     if (model) {
0084         auto minProperty = model->property("minimum");
0085         auto maxProperty = model->property("maximum");
0086         if (maxProperty.isValid() && maxProperty != minProperty) {
0087             return maxProperty;
0088         }
0089     }
0090 
0091     return *std::max_element(m_history.begin(), m_history.end(), variantCompare);
0092 }
0093 
0094 QVariant HistoryProxySource::first() const
0095 {
0096     if (!m_history.isEmpty()) {
0097         return m_history.first();
0098     }
0099     return QVariant{};
0100 }
0101 
0102 ChartDataSource *HistoryProxySource::source() const
0103 {
0104     return m_dataSource;
0105 }
0106 
0107 void HistoryProxySource::setSource(ChartDataSource *newSource)
0108 {
0109     if (newSource == m_dataSource) {
0110         return;
0111     }
0112 
0113     if (m_dataSource) {
0114         m_dataSource->disconnect(this);
0115     }
0116 
0117     m_dataSource = newSource;
0118     clear();
0119     if (m_dataSource) {
0120         connect(m_dataSource, &ChartDataSource::dataChanged, this, [this]() {
0121             if (!m_updateTimer) {
0122                 update();
0123             }
0124         });
0125     }
0126     Q_EMIT sourceChanged();
0127 }
0128 
0129 int HistoryProxySource::item() const
0130 {
0131     return m_item;
0132 }
0133 
0134 void HistoryProxySource::setItem(int newItem)
0135 {
0136     if (newItem == m_item) {
0137         return;
0138     }
0139 
0140     m_item = newItem;
0141     clear();
0142     Q_EMIT itemChanged();
0143 }
0144 
0145 int HistoryProxySource::maximumHistory() const
0146 {
0147     return m_maximumHistory;
0148 }
0149 
0150 void HistoryProxySource::setMaximumHistory(int newMaximumHistory)
0151 {
0152     if (newMaximumHistory == m_maximumHistory) {
0153         return;
0154     }
0155 
0156     m_maximumHistory = newMaximumHistory;
0157     while (m_history.size() > 0 && m_history.size() > m_maximumHistory) {
0158         m_history.removeLast();
0159     }
0160 
0161     Q_EMIT maximumHistoryChanged();
0162 }
0163 
0164 int HistoryProxySource::interval() const
0165 {
0166     return m_updateTimer ? m_updateTimer->interval() : -1;
0167 }
0168 
0169 void HistoryProxySource::setInterval(int newInterval)
0170 {
0171     if (m_updateTimer && newInterval == m_updateTimer->interval()) {
0172         return;
0173     }
0174 
0175     if (newInterval > 0) {
0176         if (!m_updateTimer) {
0177             m_updateTimer = std::make_unique<QTimer>();
0178             // We need precise timers to avoid missing updates when dealing with semi-constantly
0179             // updating source. That is, if the source updates at 500ms and we also update at that
0180             // rate, a drift of 2ms can cause us to miss updates.
0181             m_updateTimer->setTimerType(Qt::PreciseTimer);
0182             connect(m_updateTimer.get(), &QTimer::timeout, this, &HistoryProxySource::update);
0183         }
0184         m_updateTimer->setInterval(newInterval);
0185         m_updateTimer->start();
0186     } else {
0187         m_updateTimer.reset();
0188     }
0189 
0190     Q_EMIT intervalChanged();
0191 }
0192 
0193 HistoryProxySource::FillMode HistoryProxySource::fillMode() const
0194 {
0195     return m_fillMode;
0196 }
0197 
0198 void HistoryProxySource::setFillMode(FillMode newFillMode)
0199 {
0200     if (newFillMode == m_fillMode) {
0201         return;
0202     }
0203 
0204     m_fillMode = newFillMode;
0205     clear();
0206     Q_EMIT fillModeChanged();
0207 }
0208 
0209 void HistoryProxySource::clear()
0210 {
0211     m_history.clear();
0212     Q_EMIT dataChanged();
0213 }
0214 
0215 void HistoryProxySource::update()
0216 {
0217     if (!m_dataSource) {
0218         return;
0219     }
0220 
0221     m_history.prepend(m_dataSource->item(m_item));
0222     while (m_history.size() > 0 && m_history.size() > m_maximumHistory) {
0223         m_history.removeLast();
0224     }
0225 
0226     Q_EMIT dataChanged();
0227 }
0228 
0229 #include "moc_HistoryProxySource.cpp"