File indexing completed on 2025-03-09 03:42:14
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{QMetaType(m_dataSource->item(0).userType())}; 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{QMetaType(m_dataSource->item(0).userType())}; 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"