aboutsummaryrefslogtreecommitdiffstats
path: root/src/webchannel/qmetaobjectpublisher_p.h
diff options
context:
space:
mode:
authorArno Rehn <a.rehn@menlosystems.com>2021-04-16 22:45:21 +0200
committerArno Rehn <a.rehn@menlosystems.com>2021-04-22 13:31:31 +0200
commit87ca0ba70cd9cb4cd33e4c59986ede6b40cfe4be (patch)
treea2a279c7c056e4cde3402abafaa056d918896392 /src/webchannel/qmetaobjectpublisher_p.h
parent85fb5a65ee4cabd0eb319a840b82145d1f4567c1 (diff)
Use QProperty observation to push property updates to clients
If the property is BINDABLE but lacks a NOTIFY signal, the client will have no way to register a callback for change notifications. Document this behavior as such. A future patch could synthesize signals for purely BINDABLE properties on the client side, but this needs some more thought. Change-Id: I5e723e294dc01890956fee179fb3ba30aecf8cc1 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/webchannel/qmetaobjectpublisher_p.h')
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h63
1 files changed, 60 insertions, 3 deletions
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
index e87e4f0..f54f569 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -86,8 +86,24 @@ enum MessageType {
TYPES_LAST_VALUE = 10
};
+class QMetaObjectPublisher;
class QWebChannel;
class QWebChannelAbstractTransport;
+
+struct QWebChannelPropertyChangeNotifier : QPropertyObserver
+{
+ QWebChannelPropertyChangeNotifier(QMetaObjectPublisher *publisher, const QObject *object, int propertyIndex)
+ : QPropertyObserver(&QWebChannelPropertyChangeNotifier::notify),
+ publisher(publisher), object(object), propertyIndex(propertyIndex)
+ {
+ }
+
+ QMetaObjectPublisher *publisher = nullptr;
+ const QObject *object = nullptr;
+ int propertyIndex = 0;
+ static void notify(QPropertyObserver *, QUntypedPropertyData *);
+};
+
class Q_WEBCHANNEL_EXPORT QMetaObjectPublisher : public QObject
{
Q_OBJECT
@@ -136,7 +152,7 @@ public:
* When receiving a notify signal, it will store the information in pendingPropertyUpdates which
* gets send via a Qt.propertyUpdate message to the server when the grouping timer timeouts.
*/
- void initializePropertyUpdates(const QObject *const object, const QJsonObject &objectInfo);
+ void initializePropertyUpdates(QObject *const object, const QJsonObject &objectInfo);
/**
* Send the clients the new property values since the last time this function was invoked.
@@ -186,6 +202,17 @@ public:
void signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments);
/**
+ * Callback for bindable property value changes which forwards the change to the webchannel clients.
+ */
+ void propertyValueChanged(const QObject *object, const int propertyIndex);
+
+ /**
+ * Called after a property has been updated. Starts the update timer if
+ * the client is idle and updates are not blocked.
+ */
+ void startPropertyUpdateTimer();
+
+ /**
* Callback for registered or wrapped objects which erases all data related to @p object.
*
* @sa signalEmitted
@@ -319,10 +346,32 @@ private:
typedef QHash<int, QSet<int> > SignalToPropertyNameMap;
QHash<const QObject *, SignalToPropertyNameMap> signalToPropertyMap;
+ // Keeps property observers alive for as long as we track an object
+ std::unordered_multimap<const QObject*, QWebChannelPropertyChangeNotifier> propertyObservers;
+
// Objects that changed their properties and are waiting for idle client.
- // map of object name to map of signal index to arguments
typedef QHash<int, QVariantList> SignalToArgumentsMap;
- typedef QHash<const QObject *, SignalToArgumentsMap> PendingPropertyUpdates;
+
+ // A set of plain property index (for bindable properties) and a map of
+ // signal index to arguments (for property updates from a notify signal).
+ // NOTIFY signals and their arguments are first collected and then mapped to
+ // the corresponding property in sendPendingPropertyUpdates()
+ struct PropertyUpdate
+ {
+ public:
+ SignalToArgumentsMap signalMap;
+ QSet<int> plainProperties;
+
+ /**
+ * Given a SignalToPropertyNameMap, returns the set of all property
+ * indices of properties that were changed in this PropertyUpdate.
+ */
+ QSet<int> propertyIndices(const SignalToPropertyNameMap &map) const;
+ };
+
+ // map of object to either a property index for plain bindable properties
+ // or a to map of signal index to arguments
+ typedef QHash<const QObject *, PropertyUpdate> PendingPropertyUpdates;
PendingPropertyUpdates pendingPropertyUpdates;
// Aggregate property updates since we get multiple Qt.idle message when we have multiple
@@ -331,6 +380,14 @@ private:
QBasicTimer timer;
};
+inline QSet<int> QMetaObjectPublisher::PropertyUpdate::propertyIndices(const SignalToPropertyNameMap &map) const {
+ auto indexes = plainProperties;
+ for (auto it = signalMap.cbegin(); it != signalMap.cend(); ++it) {
+ indexes += map.value(it.key());
+ }
+ return indexes;
+}
+
QT_END_NAMESPACE
#endif // QMETAOBJECTPUBLISHER_P_H