KQuickCharts

HistoryProxySource.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 "HistoryProxySource.h"
9
10#include <QDebug>
11
12HistoryProxySource::HistoryProxySource(QObject *parent)
13 : ChartDataSource(parent)
14{
15}
16
17int HistoryProxySource::itemCount() const
18{
19 if (m_fillMode == DoNotFill) {
20 return m_history.size();
21 } else {
22 return m_maximumHistory;
23 }
24}
25
27{
28 if (index < 0 || !m_dataSource || m_dataSource->itemCount() == 0) {
29 return QVariant{};
30 }
31
32 if (m_fillMode == DoNotFill && index >= m_history.count()) {
33 return QVariant{};
34 }
35
36 if (m_fillMode == FillFromStart && index >= m_history.count()) {
37 return QVariant{QMetaType(m_dataSource->item(0).userType())};
38 }
39
40 if (m_fillMode == FillFromEnd && m_history.count() != m_maximumHistory) {
41 auto actualIndex = index - (m_maximumHistory - m_history.count());
42 if (actualIndex < 0 || actualIndex >= m_history.size()) {
43 return QVariant{QMetaType(m_dataSource->item(0).userType())};
44 } else {
45 return m_history.at(actualIndex);
46 }
47 }
48
49 if (index < m_history.count()) {
50 return m_history.at(index);
51 } else {
52 return QVariant{};
53 }
54}
55
56QVariant HistoryProxySource::minimum() const
57{
58 if (m_history.isEmpty() || !m_dataSource) {
59 return QVariant{};
60 }
61
62 // TODO: Find a nicer solution for data sources to indicate
63 // "I provide a min/max value not derived from my items"
64 auto model = m_dataSource->property("model").value<QObject *>();
65 if (model) {
66 auto minProperty = model->property("minimum");
67 auto maxProperty = model->property("maximum");
68 if (minProperty.isValid() && minProperty != maxProperty) {
69 return minProperty;
70 }
71 }
72
73 return *std::min_element(m_history.begin(), m_history.end(), variantCompare);
74}
75
76QVariant HistoryProxySource::maximum() const
77{
78 if (m_history.isEmpty() || !m_dataSource) {
79 return QVariant{};
80 }
81
82 auto model = m_dataSource->property("model").value<QObject *>();
83 if (model) {
84 auto minProperty = model->property("minimum");
85 auto maxProperty = model->property("maximum");
86 if (maxProperty.isValid() && maxProperty != minProperty) {
87 return maxProperty;
88 }
89 }
90
91 return *std::max_element(m_history.begin(), m_history.end(), variantCompare);
92}
93
94QVariant HistoryProxySource::first() const
95{
96 if (!m_history.isEmpty()) {
97 return m_history.first();
98 }
99 return QVariant{};
100}
101
103{
104 return m_dataSource;
105}
106
107void HistoryProxySource::setSource(ChartDataSource *newSource)
108{
109 if (newSource == m_dataSource) {
110 return;
111 }
112
113 if (m_dataSource) {
114 m_dataSource->disconnect(this);
115 }
116
117 m_dataSource = newSource;
118 clear();
119 if (m_dataSource) {
120 connect(m_dataSource, &ChartDataSource::dataChanged, this, [this]() {
121 if (!m_updateTimer) {
122 update();
123 }
124 });
125 }
126 Q_EMIT sourceChanged();
127}
128
129int HistoryProxySource::item() const
130{
131 return m_item;
132}
133
134void HistoryProxySource::setItem(int newItem)
135{
136 if (newItem == m_item) {
137 return;
138 }
139
140 m_item = newItem;
141 clear();
142 Q_EMIT itemChanged();
143}
144
146{
147 return m_maximumHistory;
148}
149
150void HistoryProxySource::setMaximumHistory(int newMaximumHistory)
151{
152 if (newMaximumHistory == m_maximumHistory) {
153 return;
154 }
155
156 m_maximumHistory = newMaximumHistory;
157 while (m_history.size() > 0 && m_history.size() > m_maximumHistory) {
158 m_history.removeLast();
159 }
160
161 Q_EMIT maximumHistoryChanged();
162}
163
165{
166 return m_updateTimer ? m_updateTimer->interval() : -1;
167}
168
169void HistoryProxySource::setInterval(int newInterval)
170{
171 if (m_updateTimer && newInterval == m_updateTimer->interval()) {
172 return;
173 }
174
175 if (newInterval > 0) {
176 if (!m_updateTimer) {
177 m_updateTimer = std::make_unique<QTimer>();
178 // We need precise timers to avoid missing updates when dealing with semi-constantly
179 // updating source. That is, if the source updates at 500ms and we also update at that
180 // rate, a drift of 2ms can cause us to miss updates.
181 m_updateTimer->setTimerType(Qt::PreciseTimer);
182 connect(m_updateTimer.get(), &QTimer::timeout, this, &HistoryProxySource::update);
183 }
184 m_updateTimer->setInterval(newInterval);
185 m_updateTimer->start();
186 } else {
187 m_updateTimer.reset();
188 }
189
190 Q_EMIT intervalChanged();
191}
192
194{
195 return m_fillMode;
196}
197
198void HistoryProxySource::setFillMode(FillMode newFillMode)
199{
200 if (newFillMode == m_fillMode) {
201 return;
202 }
203
204 m_fillMode = newFillMode;
205 clear();
206 Q_EMIT fillModeChanged();
207}
208
210{
211 m_history.clear();
212 Q_EMIT dataChanged();
213}
214
215void HistoryProxySource::update()
216{
217 if (!m_dataSource) {
218 return;
219 }
220
221 m_history.prepend(m_dataSource->item(m_item));
222 while (m_history.size() > 0 && m_history.size() > m_maximumHistory) {
223 m_history.removeLast();
224 }
225
226 Q_EMIT dataChanged();
227}
228
229#include "moc_HistoryProxySource.cpp"
Abstract base class for data sources.
ChartDataSource * source
The data source to read data from.
FillMode
The different fill modes.
@ DoNotFill
Do not fill with any items.
@ FillFromEnd
Fill with empty values, placing partial history at the end.
@ FillFromStart
Fill with empty values, starting at 0.
int item
The item of the data source to read data from.
int interval
The interval, in milliseconds, with which to query the data source.
FillMode fillMode
The fill mode.
int maximumHistory
The maximum amount of history to keep.
Q_INVOKABLE void clear()
Clear the entire history of this source.
const_reference at(qsizetype i) const const
iterator begin()
void clear()
qsizetype count() const const
iterator end()
T & first()
bool isEmpty() const const
void prepend(parameter_type value)
void removeLast()
qsizetype size() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QVariant property(const char *name) const const
PreciseTimer
void timeout()
int userType() const const
T value() 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.