File indexing completed on 2024-05-05 16:16:41

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 "ModelHistorySource.h"
0009 
0010 #include <QAbstractItemModel>
0011 #include <QDebug>
0012 #include <QTimer>
0013 #include <QVariantList>
0014 
0015 #include "QmlDeprecated.h"
0016 
0017 #if QUICKCHARTS_BUILD_DEPRECATED_SINCE(5, 78)
0018 
0019 ModelHistorySource::ModelHistorySource(QObject *parent)
0020     : ModelSource(parent)
0021 {
0022     QML_DEPRECATED("ModelHistorySource", "5.78", "Use HistoryProxySource instead.")
0023 
0024     connect(this, &ModelHistorySource::modelChanged, this, &ModelHistorySource::onModelChanged);
0025 }
0026 
0027 int ModelHistorySource::itemCount() const
0028 {
0029     return m_history.size();
0030 }
0031 
0032 QVariant ModelHistorySource::item(int index) const
0033 {
0034     if (index < 0 || index >= m_history.size()) {
0035         return {};
0036     }
0037 
0038     return m_history.at(index);
0039 }
0040 
0041 QVariant ModelHistorySource::minimum() const
0042 {
0043     if (m_history.isEmpty()) {
0044         return {};
0045     }
0046 
0047     auto minProperty = model()->property("minimum");
0048     auto maxProperty = model()->property("maximum");
0049     if (maxProperty.isValid() && maxProperty != minProperty) {
0050         return maxProperty;
0051     }
0052 
0053     return *std::min_element(m_history.begin(), m_history.end());
0054 }
0055 
0056 QVariant ModelHistorySource::maximum() const
0057 {
0058     if (m_history.isEmpty()) {
0059         return {};
0060     }
0061 
0062     auto minProperty = model()->property("minimum");
0063     auto maxProperty = model()->property("maximum");
0064     if (maxProperty.isValid() && maxProperty != minProperty) {
0065         return maxProperty;
0066     }
0067 
0068     return *std::max_element(m_history.begin(), m_history.end());
0069 }
0070 
0071 int ModelHistorySource::row() const
0072 {
0073     return m_row;
0074 }
0075 
0076 void ModelHistorySource::setRow(int row)
0077 {
0078     if (m_row == row) {
0079         return;
0080     }
0081 
0082     m_row = row;
0083     Q_EMIT rowChanged();
0084 }
0085 
0086 int ModelHistorySource::maximumHistory() const
0087 {
0088     return m_maximumHistory;
0089 }
0090 
0091 void ModelHistorySource::setMaximumHistory(int maximumHistory)
0092 {
0093     if (m_maximumHistory == maximumHistory) {
0094         return;
0095     }
0096 
0097     m_maximumHistory = maximumHistory;
0098     Q_EMIT maximumHistoryChanged();
0099 }
0100 
0101 int ModelHistorySource::interval() const
0102 {
0103     return m_updateTimer ? m_updateTimer->interval() : -1;
0104 }
0105 
0106 void ModelHistorySource::setInterval(int newInterval)
0107 {
0108     if (m_updateTimer && newInterval == m_updateTimer->interval()) {
0109         return;
0110     }
0111 
0112     if (newInterval > 0) {
0113         if (!m_updateTimer) {
0114             m_updateTimer = std::make_unique<QTimer>();
0115             // We need precise timers to avoid missing updates when dealing with semi-constantly
0116             // updating model. That is, if the model updates at 500ms and we also update at that
0117             // rate, a drift of 2ms can cause us to miss updates.
0118             m_updateTimer->setTimerType(Qt::PreciseTimer);
0119             connect(m_updateTimer.get(), &QTimer::timeout, this, [this]() {
0120                 if (!model()) {
0121                     return;
0122                 }
0123 
0124                 auto index = model()->index(m_row, column());
0125                 onDataChanged(index, index, {role()});
0126             });
0127             if (model()) {
0128                 disconnect(model(), &QAbstractItemModel::dataChanged, this, &ModelHistorySource::onDataChanged);
0129             }
0130         }
0131         m_updateTimer->setInterval(newInterval);
0132         m_updateTimer->start();
0133     } else {
0134         m_updateTimer.reset();
0135         onModelChanged();
0136     }
0137 
0138     Q_EMIT intervalChanged();
0139 }
0140 
0141 void ModelHistorySource::clear()
0142 {
0143     m_history.clear();
0144     Q_EMIT dataChanged();
0145 }
0146 
0147 void ModelHistorySource::onModelChanged()
0148 {
0149     if (model() && !m_updateTimer) {
0150         connect(model(), &QAbstractItemModel::dataChanged, this, &ModelHistorySource::onDataChanged);
0151     }
0152 }
0153 
0154 void ModelHistorySource::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
0155 {
0156     if (!model()) {
0157         return;
0158     }
0159 
0160     if (!roles.isEmpty() && !roles.contains(role())) {
0161         return;
0162     }
0163 
0164     if (topLeft.row() > m_row || bottomRight.row() < m_row) {
0165         return;
0166     }
0167 
0168     if (topLeft.column() > column() || bottomRight.column() < column()) {
0169         return;
0170     }
0171 
0172     auto entry = model()->data(model()->index(m_row, column()), role());
0173 
0174     m_history.prepend(entry);
0175     while (m_history.size() > m_maximumHistory) {
0176         m_history.pop_back();
0177     }
0178 
0179     Q_EMIT dataChanged();
0180 }
0181 
0182 #include "moc_ModelHistorySource.cpp"
0183 
0184 #endif // QUICKCHARTS_BUILD_DEPRECATED_SINCE