#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class DBusPropertiesInterface; Q_DECLARE_LOGGING_CATEGORY(logDbus); namespace qs::dbus { QDBusError demarshallVariant(const QVariant& variant, const QMetaType& type, void* slot); template class DBusResult { public: explicit DBusResult() = default; explicit DBusResult(T value): value(std::move(value)) {} explicit DBusResult(QDBusError error): error(std::move(error)) {} explicit DBusResult(T value, QDBusError error) : value(std::move(value)) , error(std::move(error)) {} bool isValid() { return !this->error.isValid(); } T value; QDBusError error; }; template DBusResult demarshallVariant(const QVariant& variant) { T value; auto error = demarshallVariant(variant, QMetaType::fromType(), &value); return DBusResult(value, error); } void asyncReadPropertyInternal( const QMetaType& type, QDBusAbstractInterface& interface, const QString& property, std::function)> callback ); template void asyncReadProperty( QDBusAbstractInterface& interface, const QString& property, std::function callback ) { asyncReadPropertyInternal( QMetaType::fromType(), interface, property, [callback](std::function internalCallback) { // NOLINT T slot; auto error = internalCallback(static_cast(&slot)); callback(slot, error); } ); } class DBusPropertyGroup; class AbstractDBusProperty: public QObject { Q_OBJECT; public: explicit AbstractDBusProperty(QString name, const QMetaType& type, QObject* parent = nullptr) : QObject(parent) , name(std::move(name)) , type(type) {} [[nodiscard]] QString toString() const; [[nodiscard]] virtual QString valueString() = 0; public slots: void update(); signals: void changed(); protected: virtual QDBusError read(const QVariant& variant) = 0; private: void tryUpdate(const QVariant& variant); DBusPropertyGroup* group = nullptr; QString name; QMetaType type; friend class DBusPropertyGroup; }; class DBusPropertyGroup: public QObject { Q_OBJECT; public: explicit DBusPropertyGroup( QVector properties = QVector(), QObject* parent = nullptr ); void setInterface(QDBusAbstractInterface* interface); void attachProperty(AbstractDBusProperty* property); void updateAllDirect(); void updateAllViaGetAll(); [[nodiscard]] QString toString() const; signals: void getAllFinished(); private slots: void onPropertiesChanged( const QString& interfaceName, const QVariantMap& changedProperties, const QStringList& invalidatedProperties ); private: void updatePropertySet(const QVariantMap& properties); DBusPropertiesInterface* propertyInterface = nullptr; QDBusAbstractInterface* interface = nullptr; QVector properties; friend class AbstractDBusProperty; }; template class DBusProperty: public AbstractDBusProperty { public: explicit DBusProperty(QString name, QObject* parent = nullptr, T value = T()) : AbstractDBusProperty(std::move(name), QMetaType::fromType(), parent) , value(std::move(value)) {} explicit DBusProperty( DBusPropertyGroup& group, QString name, QObject* parent = nullptr, T value = T() ) : DBusProperty(std::move(name), parent, std::move(value)) { group.attachProperty(this); } [[nodiscard]] QString valueString() override { QString str; QDebug(&str) << this->value; return str; } [[nodiscard]] T get() const { return this->value; } void set(T value) { this->value = std::move(value); emit this->changed(); } protected: QDBusError read(const QVariant& variant) override { auto result = demarshallVariant(variant); if (result.isValid()) { this->set(std::move(result.value)); } return result.error; } private: T value; friend class DBusPropertyGroup; }; } // namespace qs::dbus