Skip to content

Commit

Permalink
Add QuantityObject and QuantityObjectModel
Browse files Browse the repository at this point in the history
QuantityObject provides QObject-based access to a quantity value.
QuantityObjectModel provides a model of QuantityObject values; it
filters out objects without valid values.

This allows ListQuantityGroup and its derived types to specify their
models without creating a JavaScript array that directly refers each
quantity value. Otherwise, whenever a quantity value is updated, the
entire array is rebuilt, which in turn causes the QuantityRow repeater
to rebuild its delegates.

Part of #1338
  • Loading branch information
blammit committed Jan 30, 2025
1 parent f5600d1 commit e49caa2
Show file tree
Hide file tree
Showing 9 changed files with 713 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,11 @@ list(APPEND VenusQMLModule_CPP_SOURCES
src/productinfo.h
src/quantityinfo.h
src/quantityinfo.cpp
src/quantityinfo.cpp
src/quantityobject.h
src/quantityobject.cpp
src/quantityobjectmodel.h
src/quantityobjectmodel.cpp
src/qrangemodel_p.h
src/qrangemodel.h
src/qrangemodel.cpp
Expand Down
137 changes: 137 additions & 0 deletions src/quantityobject.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
** Copyright (C) 2025 Victron Energy B.V.
** See LICENSE.txt for license information.
*/

#include "quantityobject.h"

#include <QQmlInfo>

using namespace Victron::VenusOS;

QuantityObject::QuantityObject(QObject *parent)
: QObject(parent)
{
}

QObject* QuantityObject::object() const
{
return m_object;
}

void QuantityObject::setObject(QObject* object)
{
if (m_object != object) {
m_object = object;
connectNotifySignal();
emit objectChanged();
}
}

QString QuantityObject::key() const
{
return m_key;
}

void QuantityObject::setKey(const QString &key)
{
if (m_key != key) {
m_key = key;
connectNotifySignal();
emit keyChanged();
}
}

Victron::VenusOS::Enums::Units_Type QuantityObject::unit() const
{
return m_unit;
}

void QuantityObject::setUnit(Victron::VenusOS::Enums::Units_Type unit)
{
if (m_unit != unit) {
m_unit = unit;
emit unitChanged();
}
}

int QuantityObject::precision() const
{
return m_precision;
}

void QuantityObject::setPrecision(int precision)
{
if (m_precision != precision) {
m_precision = precision;
emit precisionChanged();
}
}

qreal QuantityObject::numberValue() const
{
return m_value.value<qreal>();
}

QString QuantityObject::textValue() const
{
return m_value.metaType() == QMetaType(QMetaType::QString) ? m_value.toString() : QString();
}

bool QuantityObject::hasValue() const
{
// Return true if the value is not NaN or the text is not empty.
return m_object && m_key.length() && m_value.isValid()
&& (!qIsNaN(numberValue()) || textValue().length() > 0);
}

void QuantityObject::connectNotifySignal()
{
if (m_notifySignalConnection) {
QObject::disconnect(m_notifySignalConnection);
}

static const QMetaMethod updateValueMethod =
staticMetaObject.method(staticMetaObject.indexOfMethod("updateValue()"));
if (!updateValueMethod.isValid()) {
qmlInfo(this) << "Failed to find updateValue() method!";
return;
}

if (m_object && m_key.length()) {
const QMetaObject *metaObject = m_object->metaObject();
m_property = metaObject->property(metaObject->indexOfProperty(m_key.toLatin1()));
if (m_property.isValid()) {
m_notifySignalConnection = QObject::connect(m_object.data(), m_property.notifySignal(), this, updateValueMethod);
if (!m_notifySignalConnection) {
qmlInfo(this) << "Failed to connect to notify signal for: " << m_key;
}
updateValue();
} else {
qmlInfo(this) << "Cannot find property: " << m_key;
}
}
}

void QuantityObject::updateValue()
{
const qreal prevNumberValue = numberValue();
const QString prevTextValue = textValue();
const bool prevHasValue = hasValue();

if (m_object && m_property.isValid()) {
m_value = m_property.read(m_object);
} else {
m_value.clear();
}

if (prevNumberValue != numberValue()) {
emit numberValueChanged();
}
if (prevTextValue != textValue()) {
emit textValueChanged();
}
if (prevHasValue != hasValue()) {
emit hasValueChanged();
}
}
90 changes: 90 additions & 0 deletions src/quantityobject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
** Copyright (C) 2025 Victron Energy B.V.
** See LICENSE.txt for license information.
*/

#ifndef QUANTITYMODEL_H
#define QUANTITYMODEL_H

#include <qqmlintegration.h>
#include <QMetaObject>
#include <QMetaProperty>

#include "enums.h"

namespace Victron {
namespace VenusOS {

/*
Provides QObject-based access to a quantity value.
Example usage:
QtObject {
id: dataObject
property real voltage: 0.14
property real power: 536
}
QuantityObject { object: dataObject; key: "voltage"; unit: VenusOS.Units_Volt_DC }
QuantityObject { object: dataObject; key: "power"; unit: VenusOS.Units_Watt }
*/
class QuantityObject : public QObject
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QObject* object READ object WRITE setObject NOTIFY objectChanged FINAL)
Q_PROPERTY(QString key READ key WRITE setKey NOTIFY keyChanged FINAL)
Q_PROPERTY(Victron::VenusOS::Enums::Units_Type unit READ unit WRITE setUnit NOTIFY unitChanged FINAL)
Q_PROPERTY(int precision READ precision WRITE setPrecision NOTIFY precisionChanged FINAL)
Q_PROPERTY(qreal numberValue READ numberValue NOTIFY numberValueChanged FINAL)
Q_PROPERTY(QString textValue READ textValue NOTIFY textValueChanged FINAL)
Q_PROPERTY(bool hasValue READ hasValue NOTIFY hasValueChanged FINAL)

public:
explicit QuantityObject(QObject *parent = nullptr);

QObject* object() const;
void setObject(QObject* object);

QString key() const;
void setKey(const QString &key);

Victron::VenusOS::Enums::Units_Type unit() const;
void setUnit(Victron::VenusOS::Enums::Units_Type unit);

int precision() const;
void setPrecision(int precision);

qreal numberValue() const;
QString textValue() const; // if the value has a string type
bool hasValue() const;

Q_SIGNALS:
void objectChanged();
void keyChanged();
void unitChanged();
void precisionChanged();
void numberValueChanged();
void textValueChanged();
void hasValueChanged();

private Q_SLOTS:
void updateValue();

private:
void connectNotifySignal();

QPointer<QObject> m_object;
QString m_key = QStringLiteral("value");
QVariant m_value;
QMetaProperty m_property;
QMetaObject::Connection m_notifySignalConnection;
Victron::VenusOS::Enums::Units_Type m_unit = Victron::VenusOS::Enums::Units_None;
int m_precision = Victron::VenusOS::Enums::Units_Precision_Default;
};

} /* VenusOS */
} /* Victron */

#endif // QUANTITYMODEL_H
Loading

0 comments on commit e49caa2

Please sign in to comment.