diff --git a/src/dbus/properties.cpp b/src/dbus/properties.cpp index 6156b2a3..a1cd7e68 100644 --- a/src/dbus/properties.cpp +++ b/src/dbus/properties.cpp @@ -110,100 +110,25 @@ void asyncReadPropertyInternal( QObject::connect(call, &QDBusPendingCallWatcher::finished, &interface, responseCallback); } -void AbstractDBusProperty::tryUpdate(const QVariant& variant) { - this->mExists = true; - - auto error = this->read(variant); - if (error.isValid()) { - qCWarning(logDbusProperties).noquote() - << "Error demarshalling property update for" << this->toString(); - qCWarning(logDbusProperties) << error; - } else { - qCDebug(logDbusProperties).noquote() - << "Updated property" << this->toString() << "to" << this->valueString(); - } -} - void AbstractDBusProperty::update() { if (this->group == nullptr) { - qFatal(logDbusProperties) << "Tried to update dbus property" << this->name + qFatal(logDbusProperties) << "Tried to update dbus property" << this->nameRef() << "which is not attached to a group"; } else { - const QString propStr = this->toString(); - - if (this->group->interface == nullptr) { - qFatal(logDbusProperties).noquote() - << "Tried to update property" << propStr << "of a disconnected interface"; - } - - qCDebug(logDbusProperties).noquote() << "Updating property" << propStr; - - auto pendingCall = - this->group->propertyInterface->Get(this->group->interface->interface(), this->name); - - auto* call = new QDBusPendingCallWatcher(pendingCall, this); - - auto responseCallback = [this, propStr](QDBusPendingCallWatcher* call) { - const QDBusPendingReply reply = *call; - - if (reply.isError()) { - qCWarning(logDbusProperties).noquote() << "Error updating property" << propStr; - qCWarning(logDbusProperties) << reply.error(); - } else { - this->tryUpdate(reply.value().variant()); - } - - delete call; - }; - - QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); + this->group->requestPropertyUpdate(this); } } void AbstractDBusProperty::write() { if (this->group == nullptr) { - qFatal(logDbusProperties) << "Tried to write dbus property" << this->name + qFatal(logDbusProperties) << "Tried to write dbus property" << this->nameRef() << "which is not attached to a group"; } else { - const QString propStr = this->toString(); - - if (this->group->interface == nullptr) { - qFatal(logDbusProperties).noquote() - << "Tried to write property" << propStr << "of a disconnected interface"; - } - - qCDebug(logDbusProperties).noquote() << "Writing property" << propStr; - - auto pendingCall = this->group->propertyInterface->Set( - this->group->interface->interface(), - this->name, - QDBusVariant(this->serialize()) - ); - - auto* call = new QDBusPendingCallWatcher(pendingCall, this); - - auto responseCallback = [propStr](QDBusPendingCallWatcher* call) { - const QDBusPendingReply<> reply = *call; - - if (reply.isError()) { - qCWarning(logDbusProperties).noquote() << "Error writing property" << propStr; - qCWarning(logDbusProperties) << reply.error(); - } - delete call; - }; - - QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); + this->group->pushPropertyUpdate(this); } } -bool AbstractDBusProperty::exists() const { return this->mExists; } - -QString AbstractDBusProperty::toString() const { - const QString group = this->group == nullptr ? "{ NO GROUP }" : this->group->toString(); - return group + ':' + this->name; -} - -DBusPropertyGroup::DBusPropertyGroup(QVector properties, QObject* parent) +DBusPropertyGroup::DBusPropertyGroup(QVector properties, QObject* parent) : QObject(parent) , properties(std::move(properties)) {} @@ -246,7 +171,7 @@ void DBusPropertyGroup::updateAllDirect() { } for (auto* property: this->properties) { - property->update(); + this->requestPropertyUpdate(property); } } @@ -287,27 +212,102 @@ void DBusPropertyGroup::updatePropertySet(const QVariantMap& properties, bool co auto prop = std::find_if( this->properties.begin(), this->properties.end(), - [&name](AbstractDBusProperty* prop) { return prop->name == name; } + [&name](DBusPropertyCore* prop) { return prop->nameRef() == name; } ); if (prop == this->properties.end()) { qCDebug(logDbusProperties) << "Ignoring untracked property update" << name << "for" << this->toString(); } else { - (*prop)->tryUpdate(value); + this->tryUpdateProperty(*prop, value); } } if (complainMissing) { for (const auto* prop: this->properties) { - if (prop->required && !properties.contains(prop->name)) { + if (prop->isRequired() && !properties.contains(prop->name())) { qCWarning(logDbusProperties) - << prop->name << "missing from property set for" << this->toString(); + << prop->nameRef() << "missing from property set for" << this->toString(); } } } } +void DBusPropertyGroup::tryUpdateProperty(DBusPropertyCore* property, const QVariant& variant) + const { + property->mExists = true; + + auto error = property->store(variant); + if (error.isValid()) { + qCWarning(logDbusProperties).noquote() + << "Error demarshalling property update for" << this->propertyString(property); + qCWarning(logDbusProperties) << error; + } else { + qCDebug(logDbusProperties).noquote() + << "Updated property" << this->propertyString(property) << "to" << property->valueString(); + } +} + +void DBusPropertyGroup::requestPropertyUpdate(DBusPropertyCore* property) { + const QString propStr = this->propertyString(property); + + if (this->interface == nullptr) { + qFatal(logDbusProperties).noquote() + << "Tried to update property" << propStr << "of a disconnected interface"; + } + + qCDebug(logDbusProperties).noquote() << "Updating property" << propStr; + + auto pendingCall = this->propertyInterface->Get(this->interface->interface(), property->name()); + auto* call = new QDBusPendingCallWatcher(pendingCall, this); + + auto responseCallback = [this, propStr, property](QDBusPendingCallWatcher* call) { + const QDBusPendingReply reply = *call; + + if (reply.isError()) { + qCWarning(logDbusProperties).noquote() << "Error updating property" << propStr; + qCWarning(logDbusProperties) << reply.error(); + } else { + this->tryUpdateProperty(property, reply.value().variant()); + } + + delete call; + }; + + QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); +} + +void DBusPropertyGroup::pushPropertyUpdate(DBusPropertyCore* property) { + const QString propStr = this->propertyString(property); + + if (this->interface == nullptr) { + qFatal(logDbusProperties).noquote() + << "Tried to write property" << propStr << "of a disconnected interface"; + } + + qCDebug(logDbusProperties).noquote() << "Writing property" << propStr; + + auto pendingCall = this->propertyInterface->Set( + this->interface->interface(), + property->name(), + QDBusVariant(property->serialize()) + ); + + auto* call = new QDBusPendingCallWatcher(pendingCall, this); + + auto responseCallback = [propStr](QDBusPendingCallWatcher* call) { + const QDBusPendingReply<> reply = *call; + + if (reply.isError()) { + qCWarning(logDbusProperties).noquote() << "Error writing property" << propStr; + qCWarning(logDbusProperties) << reply.error(); + } + delete call; + }; + + QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback); +} + QString DBusPropertyGroup::toString() const { if (this->interface == nullptr) { return "{ DISCONNECTED }"; @@ -317,6 +317,12 @@ QString DBusPropertyGroup::toString() const { } } +QString DBusPropertyGroup::propertyString(const DBusPropertyCore* property) const { + return this->toString() % ':' % property->nameRef(); +} + +QString AbstractDBusProperty::toString() const { return this->group->propertyString(this); } + void DBusPropertyGroup::onPropertiesChanged( const QString& interfaceName, const QVariantMap& changedProperties, @@ -330,14 +336,14 @@ void DBusPropertyGroup::onPropertiesChanged( auto prop = std::find_if( this->properties.begin(), this->properties.end(), - [&name](AbstractDBusProperty* prop) { return prop->name == name; } + [&name](DBusPropertyCore* prop) { return prop->nameRef() == name; } ); if (prop == this->properties.end()) { qCDebug(logDbusProperties) << "Ignoring untracked property invalidation" << name << "for" << this; } else { - (*prop)->update(); + this->requestPropertyUpdate(*prop); } } diff --git a/src/dbus/properties.hpp b/src/dbus/properties.hpp index 65f51afc..3008d357 100644 --- a/src/dbus/properties.hpp +++ b/src/dbus/properties.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -75,24 +76,44 @@ void asyncReadProperty( class DBusPropertyGroup; -class AbstractDBusProperty: public QObject { +class DBusPropertyCore { +public: + DBusPropertyCore() = default; + virtual ~DBusPropertyCore() = default; + Q_DISABLE_COPY_MOVE(DBusPropertyCore); + + [[nodiscard]] virtual QString name() const = 0; + [[nodiscard]] virtual QStringView nameRef() const = 0; + [[nodiscard]] virtual QString valueString() = 0; + [[nodiscard]] virtual bool isRequired() const = 0; + [[nodiscard]] bool exists() const { return this->mExists; } + +protected: + virtual QDBusError store(const QVariant& variant) = 0; + [[nodiscard]] virtual QVariant serialize() = 0; + +private: + bool mExists : 1 = false; + + friend class DBusPropertyGroup; +}; + +class AbstractDBusProperty + : public QObject + , public DBusPropertyCore { Q_OBJECT; public: - explicit AbstractDBusProperty( - QString name, - const QMetaType& type, - bool required, - QObject* parent = nullptr - ) + explicit AbstractDBusProperty(QString name, bool required, QObject* parent = nullptr) : QObject(parent) - , name(std::move(name)) - , type(type) - , required(required) {} + , required(required) + , mName(std::move(name)) {} + + [[nodiscard]] QString name() const override { return this->mName; }; + [[nodiscard]] QStringView nameRef() const override { return this->mName; }; + [[nodiscard]] bool isRequired() const override { return this->required; }; - [[nodiscard]] bool exists() const; [[nodiscard]] QString toString() const; - [[nodiscard]] virtual QString valueString() = 0; public slots: void update(); @@ -101,19 +122,12 @@ public slots: signals: void changed(); -protected: - virtual QDBusError read(const QVariant& variant) = 0; - virtual QVariant serialize() = 0; - private: - void tryUpdate(const QVariant& variant); + bool required : 1; + bool mExists : 1 = false; DBusPropertyGroup* group = nullptr; - - QString name; - QMetaType type; - bool required; - bool mExists = false; + QString mName; friend class DBusPropertyGroup; }; @@ -123,7 +137,7 @@ class DBusPropertyGroup: public QObject { public: explicit DBusPropertyGroup( - QVector properties = QVector(), + QVector properties = QVector(), QObject* parent = nullptr ); @@ -146,10 +160,14 @@ private slots: private: void updatePropertySet(const QVariantMap& properties, bool complainMissing); + void requestPropertyUpdate(DBusPropertyCore* property); + void pushPropertyUpdate(DBusPropertyCore* property); + void tryUpdateProperty(DBusPropertyCore* property, const QVariant& variant) const; + [[nodiscard]] QString propertyString(const DBusPropertyCore* property) const; DBusPropertiesInterface* propertyInterface = nullptr; QDBusAbstractInterface* interface = nullptr; - QVector properties; + QVector properties; friend class AbstractDBusProperty; }; @@ -163,7 +181,7 @@ public: bool required = true, QObject* parent = nullptr ) - : AbstractDBusProperty(std::move(name), QMetaType::fromType(), required, parent) + : AbstractDBusProperty(std::move(name), required, parent) , value(std::move(value)) {} explicit DBusProperty( @@ -191,7 +209,7 @@ public: } protected: - QDBusError read(const QVariant& variant) override { + QDBusError store(const QVariant& variant) override { auto result = demarshallVariant(variant); if (result.isValid()) {