Warning, file /plasma/libksysguard/systemstats/AggregateSensor.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "AggregateSensor.h" 0008 0009 #include "SensorContainer.h" 0010 #include <QTimer> 0011 0012 using namespace KSysGuard; 0013 0014 // Add two QVariants together. 0015 // 0016 // This will try to add two QVariants together based on the type of first. This 0017 // will try to convert first and second to a common type, add them, then convert 0018 // back to the type of first. 0019 // 0020 // If any conversion fails or there is no way to add two types, first will be 0021 // returned. 0022 QVariant addVariants(const QVariant &first, const QVariant &second) 0023 { 0024 auto result = QVariant{}; 0025 0026 bool convertFirst = false; 0027 bool convertSecond = false; 0028 0029 auto type = first.type(); 0030 switch (static_cast<QMetaType::Type>(type)) { 0031 case QMetaType::Char: 0032 case QMetaType::Short: 0033 case QMetaType::Int: 0034 case QMetaType::Long: 0035 case QMetaType::LongLong: 0036 result = first.toLongLong(&convertFirst) + second.toLongLong(&convertSecond); 0037 break; 0038 case QMetaType::UChar: 0039 case QMetaType::UShort: 0040 case QMetaType::UInt: 0041 case QMetaType::ULong: 0042 case QMetaType::ULongLong: 0043 result = first.toULongLong(&convertFirst) + second.toULongLong(&convertSecond); 0044 break; 0045 case QMetaType::Float: 0046 case QMetaType::Double: 0047 result = first.toDouble(&convertFirst) + second.toDouble(&convertSecond); 0048 break; 0049 default: 0050 return first; 0051 } 0052 0053 if (!convertFirst || !convertSecond) { 0054 return first; 0055 } 0056 0057 if (!result.convert(type)) { 0058 return first; 0059 } 0060 0061 return result; 0062 } 0063 0064 class Q_DECL_HIDDEN AggregateSensor::Private 0065 { 0066 public: 0067 QRegularExpression matchObjects; 0068 QString matchProperty; 0069 SensorHash sensors; 0070 bool dataChangeQueued = false; 0071 int dataCompressionDuration = 100; 0072 SensorContainer *subsystem = nullptr; 0073 0074 std::function<QVariant(AggregateSensor::SensorIterator, const AggregateSensor::SensorIterator)> aggregateFunction; 0075 }; 0076 0077 QVariant AggregateSensor::SensorIterator::operator*() const 0078 { 0079 return m_it.value()->value(); 0080 } 0081 0082 AggregateSensor::SensorIterator &AggregateSensor::SensorIterator::operator++() 0083 { 0084 do { 0085 ++m_it; 0086 } while (!(m_it == m_end || m_it.value())); 0087 return *this; 0088 } 0089 0090 AggregateSensor::SensorIterator AggregateSensor::SensorIterator::operator++(int) 0091 { 0092 AggregateSensor::SensorIterator tmp = *this; 0093 operator++(); 0094 return tmp; 0095 } 0096 0097 bool AggregateSensor::SensorIterator::operator==(const SensorIterator &other) const 0098 { 0099 return m_it == other.m_it; 0100 } 0101 0102 bool AggregateSensor::SensorIterator::operator!=(const SensorIterator &other) const 0103 { 0104 return m_it != other.m_it; 0105 } 0106 0107 AggregateSensor::AggregateSensor(SensorObject *provider, const QString &id, const QString &name) 0108 : AggregateSensor(provider, id, name, QVariant{}) 0109 { 0110 } 0111 0112 AggregateSensor::AggregateSensor(SensorObject *provider, const QString &id, const QString &name, const QVariant &initialValue) 0113 : SensorProperty(id, name, initialValue, provider) 0114 , d(std::make_unique<Private>()) 0115 { 0116 d->subsystem = qobject_cast<SensorContainer *>(provider->parent()); 0117 setAggregateFunction(addVariants); 0118 connect(d->subsystem, &SensorContainer::objectAdded, this, &AggregateSensor::updateSensors); 0119 connect(d->subsystem, &SensorContainer::objectRemoved, this, &AggregateSensor::updateSensors); 0120 } 0121 0122 AggregateSensor::~AggregateSensor() = default; 0123 0124 QRegularExpression AggregateSensor::matchSensors() const 0125 { 0126 return d->matchObjects; 0127 } 0128 0129 QVariant AggregateSensor::value() const 0130 { 0131 if (d->sensors.isEmpty()) { 0132 return QVariant(); 0133 } 0134 0135 auto it = d->sensors.constBegin(); 0136 while (!it.value() && it != d->sensors.constEnd()) { 0137 it++; 0138 } 0139 0140 if (it == d->sensors.constEnd()) { 0141 return QVariant{}; 0142 } 0143 0144 auto begin = SensorIterator(it, d->sensors.constEnd()); 0145 const auto end = SensorIterator(d->sensors.constEnd(), d->sensors.constEnd()); 0146 auto result = d->aggregateFunction(begin, end); 0147 0148 return result; 0149 } 0150 0151 void AggregateSensor::subscribe() 0152 { 0153 bool wasSubscribed = SensorProperty::isSubscribed(); 0154 SensorProperty::subscribe(); 0155 if (!wasSubscribed && isSubscribed()) { 0156 for (auto sensor : std::as_const(d->sensors)) { 0157 if (sensor) { 0158 sensor->subscribe(); 0159 } 0160 } 0161 } 0162 } 0163 0164 void AggregateSensor::unsubscribe() 0165 { 0166 bool wasSubscribed = SensorProperty::isSubscribed(); 0167 SensorProperty::unsubscribe(); 0168 if (wasSubscribed && !isSubscribed()) { 0169 for (auto sensor : std::as_const(d->sensors)) { 0170 if (sensor) { 0171 sensor->unsubscribe(); 0172 } 0173 } 0174 } 0175 } 0176 0177 void AggregateSensor::setMatchSensors(const QRegularExpression &objectIds, const QString &propertyName) 0178 { 0179 if (objectIds == d->matchObjects && propertyName == d->matchProperty) { 0180 return; 0181 } 0182 0183 d->matchProperty = propertyName; 0184 d->matchObjects = objectIds; 0185 updateSensors(); 0186 } 0187 0188 std::function<QVariant(AggregateSensor::SensorIterator, AggregateSensor::SensorIterator)> AggregateSensor::aggregateFunction() const 0189 { 0190 return d->aggregateFunction; 0191 } 0192 0193 void AggregateSensor::setAggregateFunction(const std::function<QVariant(QVariant, QVariant)> &newAggregateFunction) 0194 { 0195 auto aggregateFunction = [newAggregateFunction](AggregateSensor::SensorIterator begin, const AggregateSensor::SensorIterator end) -> QVariant { 0196 auto &it = begin; 0197 QVariant result = *begin; 0198 ++it; 0199 for (; it != end; ++it) { 0200 result = newAggregateFunction(result, *it); 0201 } 0202 return result; 0203 }; 0204 0205 d->aggregateFunction = aggregateFunction; 0206 } 0207 0208 void AggregateSensor::setAggregateFunction(const std::function<QVariant(SensorIterator, const SensorIterator)> &newAggregateFunction) 0209 { 0210 d->aggregateFunction = newAggregateFunction; 0211 } 0212 0213 void AggregateSensor::addSensor(SensorProperty *sensor) 0214 { 0215 if (!sensor || sensor->path() == path() || d->sensors.contains(sensor->path())) { 0216 return; 0217 } 0218 0219 if (isSubscribed()) { 0220 sensor->subscribe(); 0221 } 0222 0223 connect(sensor, &SensorProperty::valueChanged, this, [this, sensor]() { 0224 sensorDataChanged(sensor); 0225 }); 0226 d->sensors.insert(sensor->path(), sensor); 0227 } 0228 0229 void AggregateSensor::removeSensor(const QString &sensorPath) 0230 { 0231 auto sensor = d->sensors.take(sensorPath); 0232 sensor->disconnect(this); 0233 if (isSubscribed()) { 0234 sensor->unsubscribe(); 0235 } 0236 } 0237 0238 int AggregateSensor::matchCount() const 0239 { 0240 return d->sensors.size(); 0241 } 0242 0243 void AggregateSensor::updateSensors() 0244 { 0245 if (!d->matchObjects.isValid()) { 0246 return; 0247 } 0248 0249 auto itr = d->sensors.begin(); 0250 while (itr != d->sensors.end()) { 0251 if (!itr.value()) { 0252 itr = d->sensors.erase(itr); 0253 } else if (itr.value()->parent() && itr.value()->parent()->parent() != d->subsystem) { 0254 itr.value()->disconnect(this); 0255 if (isSubscribed()) { 0256 itr.value()->unsubscribe(); 0257 } 0258 itr = d->sensors.erase(itr); 0259 } else { 0260 ++itr; 0261 } 0262 } 0263 0264 for (auto obj : d->subsystem->objects()) { 0265 if (d->matchObjects.match(obj->id()).hasMatch()) { 0266 auto sensor = obj->sensor(d->matchProperty); 0267 if (sensor) { 0268 addSensor(sensor); 0269 } 0270 } 0271 } 0272 0273 delayedEmitDataChanged(); 0274 } 0275 0276 void AggregateSensor::sensorDataChanged(SensorProperty *sensor) 0277 { 0278 Q_UNUSED(sensor) 0279 delayedEmitDataChanged(); 0280 } 0281 0282 void AggregateSensor::delayedEmitDataChanged() 0283 { 0284 if (!d->dataChangeQueued) { 0285 d->dataChangeQueued = true; 0286 QTimer::singleShot(d->dataCompressionDuration, [this]() { 0287 Q_EMIT valueChanged(); 0288 d->dataChangeQueued = false; 0289 }); 0290 } 0291 } 0292 0293 class Q_DECL_HIDDEN PercentageSensor::Private 0294 { 0295 public: 0296 SensorProperty *sensor = nullptr; 0297 }; 0298 0299 PercentageSensor::PercentageSensor(SensorObject *provider, const QString &id, const QString &name) 0300 : SensorProperty(id, name, provider) 0301 , d(std::make_unique<Private>()) 0302 { 0303 setUnit(KSysGuard::UnitPercent); 0304 setMax(100); 0305 } 0306 0307 PercentageSensor::~PercentageSensor() = default; 0308 0309 void PercentageSensor::setBaseSensor(SensorProperty *property) 0310 { 0311 d->sensor = property; 0312 connect(property, &SensorProperty::valueChanged, this, &PercentageSensor::valueChanged); 0313 connect(property, &SensorProperty::sensorInfoChanged, this, &PercentageSensor::valueChanged); 0314 } 0315 0316 QVariant PercentageSensor::value() const 0317 { 0318 if (!d->sensor) { 0319 return QVariant(); 0320 } 0321 QVariant value = d->sensor->value(); 0322 if (!value.isValid()) { 0323 return QVariant(); 0324 } 0325 return (value.toReal() / d->sensor->info().max) * 100.0; 0326 } 0327 0328 void PercentageSensor::subscribe() 0329 { 0330 d->sensor->subscribe(); 0331 } 0332 0333 void PercentageSensor::unsubscribe() 0334 { 0335 d->sensor->unsubscribe(); 0336 }