Skip to content

Commit 4163713

Browse files
committed
dbus/properties: decouple properties from AbstractDBusProperty
Importantly, this decouples properties from having to be QObjects, allowing future property types to be much lighter.
1 parent dca75b7 commit 4163713

File tree

2 files changed

+137
-113
lines changed

2 files changed

+137
-113
lines changed

src/dbus/properties.cpp

Lines changed: 93 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -110,100 +110,25 @@ void asyncReadPropertyInternal(
110110
QObject::connect(call, &QDBusPendingCallWatcher::finished, &interface, responseCallback);
111111
}
112112

113-
void AbstractDBusProperty::tryUpdate(const QVariant& variant) {
114-
this->mExists = true;
115-
116-
auto error = this->read(variant);
117-
if (error.isValid()) {
118-
qCWarning(logDbusProperties).noquote()
119-
<< "Error demarshalling property update for" << this->toString();
120-
qCWarning(logDbusProperties) << error;
121-
} else {
122-
qCDebug(logDbusProperties).noquote()
123-
<< "Updated property" << this->toString() << "to" << this->valueString();
124-
}
125-
}
126-
127113
void AbstractDBusProperty::update() {
128114
if (this->group == nullptr) {
129-
qFatal(logDbusProperties) << "Tried to update dbus property" << this->name
115+
qFatal(logDbusProperties) << "Tried to update dbus property" << this->nameRef()
130116
<< "which is not attached to a group";
131117
} else {
132-
const QString propStr = this->toString();
133-
134-
if (this->group->interface == nullptr) {
135-
qFatal(logDbusProperties).noquote()
136-
<< "Tried to update property" << propStr << "of a disconnected interface";
137-
}
138-
139-
qCDebug(logDbusProperties).noquote() << "Updating property" << propStr;
140-
141-
auto pendingCall =
142-
this->group->propertyInterface->Get(this->group->interface->interface(), this->name);
143-
144-
auto* call = new QDBusPendingCallWatcher(pendingCall, this);
145-
146-
auto responseCallback = [this, propStr](QDBusPendingCallWatcher* call) {
147-
const QDBusPendingReply<QDBusVariant> reply = *call;
148-
149-
if (reply.isError()) {
150-
qCWarning(logDbusProperties).noquote() << "Error updating property" << propStr;
151-
qCWarning(logDbusProperties) << reply.error();
152-
} else {
153-
this->tryUpdate(reply.value().variant());
154-
}
155-
156-
delete call;
157-
};
158-
159-
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
118+
this->group->requestPropertyUpdate(this);
160119
}
161120
}
162121

163122
void AbstractDBusProperty::write() {
164123
if (this->group == nullptr) {
165-
qFatal(logDbusProperties) << "Tried to write dbus property" << this->name
124+
qFatal(logDbusProperties) << "Tried to write dbus property" << this->nameRef()
166125
<< "which is not attached to a group";
167126
} else {
168-
const QString propStr = this->toString();
169-
170-
if (this->group->interface == nullptr) {
171-
qFatal(logDbusProperties).noquote()
172-
<< "Tried to write property" << propStr << "of a disconnected interface";
173-
}
174-
175-
qCDebug(logDbusProperties).noquote() << "Writing property" << propStr;
176-
177-
auto pendingCall = this->group->propertyInterface->Set(
178-
this->group->interface->interface(),
179-
this->name,
180-
QDBusVariant(this->serialize())
181-
);
182-
183-
auto* call = new QDBusPendingCallWatcher(pendingCall, this);
184-
185-
auto responseCallback = [propStr](QDBusPendingCallWatcher* call) {
186-
const QDBusPendingReply<> reply = *call;
187-
188-
if (reply.isError()) {
189-
qCWarning(logDbusProperties).noquote() << "Error writing property" << propStr;
190-
qCWarning(logDbusProperties) << reply.error();
191-
}
192-
delete call;
193-
};
194-
195-
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
127+
this->group->pushPropertyUpdate(this);
196128
}
197129
}
198130

199-
bool AbstractDBusProperty::exists() const { return this->mExists; }
200-
201-
QString AbstractDBusProperty::toString() const {
202-
const QString group = this->group == nullptr ? "{ NO GROUP }" : this->group->toString();
203-
return group + ':' + this->name;
204-
}
205-
206-
DBusPropertyGroup::DBusPropertyGroup(QVector<AbstractDBusProperty*> properties, QObject* parent)
131+
DBusPropertyGroup::DBusPropertyGroup(QVector<DBusPropertyCore*> properties, QObject* parent)
207132
: QObject(parent)
208133
, properties(std::move(properties)) {}
209134

@@ -246,7 +171,7 @@ void DBusPropertyGroup::updateAllDirect() {
246171
}
247172

248173
for (auto* property: this->properties) {
249-
property->update();
174+
this->requestPropertyUpdate(property);
250175
}
251176
}
252177

@@ -287,27 +212,102 @@ void DBusPropertyGroup::updatePropertySet(const QVariantMap& properties, bool co
287212
auto prop = std::find_if(
288213
this->properties.begin(),
289214
this->properties.end(),
290-
[&name](AbstractDBusProperty* prop) { return prop->name == name; }
215+
[&name](DBusPropertyCore* prop) { return prop->nameRef() == name; }
291216
);
292217

293218
if (prop == this->properties.end()) {
294219
qCDebug(logDbusProperties) << "Ignoring untracked property update" << name << "for"
295220
<< this->toString();
296221
} else {
297-
(*prop)->tryUpdate(value);
222+
this->tryUpdateProperty(*prop, value);
298223
}
299224
}
300225

301226
if (complainMissing) {
302227
for (const auto* prop: this->properties) {
303-
if (prop->required && !properties.contains(prop->name)) {
228+
if (prop->isRequired() && !properties.contains(prop->name())) {
304229
qCWarning(logDbusProperties)
305-
<< prop->name << "missing from property set for" << this->toString();
230+
<< prop->nameRef() << "missing from property set for" << this->toString();
306231
}
307232
}
308233
}
309234
}
310235

236+
void DBusPropertyGroup::tryUpdateProperty(DBusPropertyCore* property, const QVariant& variant)
237+
const {
238+
property->mExists = true;
239+
240+
auto error = property->store(variant);
241+
if (error.isValid()) {
242+
qCWarning(logDbusProperties).noquote()
243+
<< "Error demarshalling property update for" << this->propertyString(property);
244+
qCWarning(logDbusProperties) << error;
245+
} else {
246+
qCDebug(logDbusProperties).noquote()
247+
<< "Updated property" << this->propertyString(property) << "to" << property->valueString();
248+
}
249+
}
250+
251+
void DBusPropertyGroup::requestPropertyUpdate(DBusPropertyCore* property) {
252+
const QString propStr = this->propertyString(property);
253+
254+
if (this->interface == nullptr) {
255+
qFatal(logDbusProperties).noquote()
256+
<< "Tried to update property" << propStr << "of a disconnected interface";
257+
}
258+
259+
qCDebug(logDbusProperties).noquote() << "Updating property" << propStr;
260+
261+
auto pendingCall = this->propertyInterface->Get(this->interface->interface(), property->name());
262+
auto* call = new QDBusPendingCallWatcher(pendingCall, this);
263+
264+
auto responseCallback = [this, propStr, property](QDBusPendingCallWatcher* call) {
265+
const QDBusPendingReply<QDBusVariant> reply = *call;
266+
267+
if (reply.isError()) {
268+
qCWarning(logDbusProperties).noquote() << "Error updating property" << propStr;
269+
qCWarning(logDbusProperties) << reply.error();
270+
} else {
271+
this->tryUpdateProperty(property, reply.value().variant());
272+
}
273+
274+
delete call;
275+
};
276+
277+
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
278+
}
279+
280+
void DBusPropertyGroup::pushPropertyUpdate(DBusPropertyCore* property) {
281+
const QString propStr = this->propertyString(property);
282+
283+
if (this->interface == nullptr) {
284+
qFatal(logDbusProperties).noquote()
285+
<< "Tried to write property" << propStr << "of a disconnected interface";
286+
}
287+
288+
qCDebug(logDbusProperties).noquote() << "Writing property" << propStr;
289+
290+
auto pendingCall = this->propertyInterface->Set(
291+
this->interface->interface(),
292+
property->name(),
293+
QDBusVariant(property->serialize())
294+
);
295+
296+
auto* call = new QDBusPendingCallWatcher(pendingCall, this);
297+
298+
auto responseCallback = [propStr](QDBusPendingCallWatcher* call) {
299+
const QDBusPendingReply<> reply = *call;
300+
301+
if (reply.isError()) {
302+
qCWarning(logDbusProperties).noquote() << "Error writing property" << propStr;
303+
qCWarning(logDbusProperties) << reply.error();
304+
}
305+
delete call;
306+
};
307+
308+
QObject::connect(call, &QDBusPendingCallWatcher::finished, this, responseCallback);
309+
}
310+
311311
QString DBusPropertyGroup::toString() const {
312312
if (this->interface == nullptr) {
313313
return "{ DISCONNECTED }";
@@ -317,6 +317,12 @@ QString DBusPropertyGroup::toString() const {
317317
}
318318
}
319319

320+
QString DBusPropertyGroup::propertyString(const DBusPropertyCore* property) const {
321+
return this->toString() % ':' % property->nameRef();
322+
}
323+
324+
QString AbstractDBusProperty::toString() const { return this->group->propertyString(this); }
325+
320326
void DBusPropertyGroup::onPropertiesChanged(
321327
const QString& interfaceName,
322328
const QVariantMap& changedProperties,
@@ -330,14 +336,14 @@ void DBusPropertyGroup::onPropertiesChanged(
330336
auto prop = std::find_if(
331337
this->properties.begin(),
332338
this->properties.end(),
333-
[&name](AbstractDBusProperty* prop) { return prop->name == name; }
339+
[&name](DBusPropertyCore* prop) { return prop->nameRef() == name; }
334340
);
335341

336342
if (prop == this->properties.end()) {
337343
qCDebug(logDbusProperties) << "Ignoring untracked property invalidation" << name << "for"
338344
<< this;
339345
} else {
340-
(*prop)->update();
346+
this->requestPropertyUpdate(*prop);
341347
}
342348
}
343349

src/dbus/properties.hpp

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <qlogging.h>
1515
#include <qloggingcategory.h>
1616
#include <qobject.h>
17+
#include <qtclasshelpermacros.h>
1718
#include <qtmetamacros.h>
1819
#include <qvariant.h>
1920

@@ -75,24 +76,44 @@ void asyncReadProperty(
7576

7677
class DBusPropertyGroup;
7778

78-
class AbstractDBusProperty: public QObject {
79+
class DBusPropertyCore {
80+
public:
81+
DBusPropertyCore() = default;
82+
virtual ~DBusPropertyCore() = default;
83+
Q_DISABLE_COPY_MOVE(DBusPropertyCore);
84+
85+
[[nodiscard]] virtual QString name() const = 0;
86+
[[nodiscard]] virtual QStringView nameRef() const = 0;
87+
[[nodiscard]] virtual QString valueString() = 0;
88+
[[nodiscard]] virtual bool isRequired() const = 0;
89+
[[nodiscard]] bool exists() const { return this->mExists; }
90+
91+
protected:
92+
virtual QDBusError store(const QVariant& variant) = 0;
93+
[[nodiscard]] virtual QVariant serialize() = 0;
94+
95+
private:
96+
bool mExists : 1 = false;
97+
98+
friend class DBusPropertyGroup;
99+
};
100+
101+
class AbstractDBusProperty
102+
: public QObject
103+
, public DBusPropertyCore {
79104
Q_OBJECT;
80105

81106
public:
82-
explicit AbstractDBusProperty(
83-
QString name,
84-
const QMetaType& type,
85-
bool required,
86-
QObject* parent = nullptr
87-
)
107+
explicit AbstractDBusProperty(QString name, bool required, QObject* parent = nullptr)
88108
: QObject(parent)
89-
, name(std::move(name))
90-
, type(type)
91-
, required(required) {}
109+
, required(required)
110+
, mName(std::move(name)) {}
111+
112+
[[nodiscard]] QString name() const override { return this->mName; };
113+
[[nodiscard]] QStringView nameRef() const override { return this->mName; };
114+
[[nodiscard]] bool isRequired() const override { return this->required; };
92115

93-
[[nodiscard]] bool exists() const;
94116
[[nodiscard]] QString toString() const;
95-
[[nodiscard]] virtual QString valueString() = 0;
96117

97118
public slots:
98119
void update();
@@ -101,19 +122,12 @@ public slots:
101122
signals:
102123
void changed();
103124

104-
protected:
105-
virtual QDBusError read(const QVariant& variant) = 0;
106-
virtual QVariant serialize() = 0;
107-
108125
private:
109-
void tryUpdate(const QVariant& variant);
126+
bool required : 1;
127+
bool mExists : 1 = false;
110128

111129
DBusPropertyGroup* group = nullptr;
112-
113-
QString name;
114-
QMetaType type;
115-
bool required;
116-
bool mExists = false;
130+
QString mName;
117131

118132
friend class DBusPropertyGroup;
119133
};
@@ -123,7 +137,7 @@ class DBusPropertyGroup: public QObject {
123137

124138
public:
125139
explicit DBusPropertyGroup(
126-
QVector<AbstractDBusProperty*> properties = QVector<AbstractDBusProperty*>(),
140+
QVector<DBusPropertyCore*> properties = QVector<DBusPropertyCore*>(),
127141
QObject* parent = nullptr
128142
);
129143

@@ -146,10 +160,14 @@ private slots:
146160

147161
private:
148162
void updatePropertySet(const QVariantMap& properties, bool complainMissing);
163+
void requestPropertyUpdate(DBusPropertyCore* property);
164+
void pushPropertyUpdate(DBusPropertyCore* property);
165+
void tryUpdateProperty(DBusPropertyCore* property, const QVariant& variant) const;
166+
[[nodiscard]] QString propertyString(const DBusPropertyCore* property) const;
149167

150168
DBusPropertiesInterface* propertyInterface = nullptr;
151169
QDBusAbstractInterface* interface = nullptr;
152-
QVector<AbstractDBusProperty*> properties;
170+
QVector<DBusPropertyCore*> properties;
153171

154172
friend class AbstractDBusProperty;
155173
};
@@ -163,7 +181,7 @@ class DBusProperty: public AbstractDBusProperty {
163181
bool required = true,
164182
QObject* parent = nullptr
165183
)
166-
: AbstractDBusProperty(std::move(name), QMetaType::fromType<T>(), required, parent)
184+
: AbstractDBusProperty(std::move(name), required, parent)
167185
, value(std::move(value)) {}
168186

169187
explicit DBusProperty(
@@ -191,7 +209,7 @@ class DBusProperty: public AbstractDBusProperty {
191209
}
192210

193211
protected:
194-
QDBusError read(const QVariant& variant) override {
212+
QDBusError store(const QVariant& variant) override {
195213
auto result = demarshallVariant<T>(variant);
196214

197215
if (result.isValid()) {

0 commit comments

Comments
 (0)