1// Copyright (C) 2017 Ford Motor Company
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qremoteobjectdynamicreplica.h"
5#include "qremoteobjectreplica_p.h"
6
7#include <QtCore/qmetaobject.h>
8
9QT_BEGIN_NAMESPACE
10
11/*!
12 \class QRemoteObjectDynamicReplica
13 \inmodule QtRemoteObjects
14 \brief A dynamically instantiated \l {Replica}.
15
16 There are generated replicas (replicas having the header files produced by
17 the \l {repc} {Replica Compiler}), and dynamic replicas, that are generated
18 on-the-fly. This is the class for the dynamic type of replica.
19
20 When the connection to the \l {Source} object is made, the initialization
21 step passes the current property values (see \l {Replica Initialization}).
22 In a DynamicReplica, the property/signal/slot details are also sent,
23 allowing the replica object to be created on-the-fly. This can be convenient
24 in QML or scripting, but has two primary disadvantages. First, the object is
25 in effect "empty" until it is successfully initialized by the \l {Source}.
26 Second, in C++, calls must be made using QMetaObject::invokeMethod(), as the
27 moc generated lookup will not be available.
28
29 This class does not have a public constructor. It can only be instantiated
30 by using the dynamic QRemoteObjectNode::acquire method.
31*/
32
33QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica()
34 : QRemoteObjectReplica()
35{
36}
37
38QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica(QRemoteObjectNode *node, const QString &name)
39 : QRemoteObjectReplica(ConstructWithNode)
40{
41 initializeNode(node, name);
42}
43
44/*!
45 Destroys the dynamic replica.
46
47 \sa {Replica Ownership}
48*/
49QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica()
50{
51}
52
53/*!
54 \internal
55 Returns a pointer to the dynamically generated meta-object of this object, or
56 QRemoteObjectDynamicReplica's metaObject if the object is not initialized. This
57 function overrides the QObject::metaObject() virtual function to provide the same
58 functionality for dynamic replicas.
59
60 \sa QObject::metaObject(), {Replica Initialization}
61*/
62const QMetaObject* QRemoteObjectDynamicReplica::metaObject() const
63{
64 auto impl = qSharedPointerCast<QRemoteObjectReplicaImplementation>(src: d_impl);
65 // Returning nullptr will likely result in a crash if this type is used before the
66 // definition is received. Note: QRemoteObjectDynamicReplica doesn't include the
67 // QObject macro, so it's metaobject would resolve to QRemoteObjectReplica::metaObject()
68 // if we weren't overriding it.
69 if (!impl->m_metaObject) {
70 qWarning() << "Dynamic metaobject is not assigned, returning generic Replica metaObject.";
71 qWarning() << "This may cause issues if used for more than checking the Replica state.";
72 return QRemoteObjectReplica::metaObject();
73 }
74
75 return impl->m_metaObject;
76}
77
78/*!
79 \internal
80 This function overrides the QObject::qt_metacast() virtual function to provide the same functionality for dynamic replicas.
81
82 \sa QObject::qt_metacast()
83*/
84void *QRemoteObjectDynamicReplica::qt_metacast(const char *name)
85{
86 if (!name)
87 return nullptr;
88
89 if (!strcmp(s1: name, s2: "QRemoteObjectDynamicReplica"))
90 return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
91
92 // not entirely sure that one is needed... TODO: check
93 auto impl = qSharedPointerCast<QRemoteObjectReplicaImplementation>(src: d_impl);
94 if (QString::fromLatin1(ba: name) == impl->m_objectName)
95 return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
96
97 return QObject::qt_metacast(name);
98}
99
100/*!
101 \internal
102 This function overrides the QObject::qt_metacall() virtual function to provide the same functionality for dynamic replicas.
103
104 \sa QObject::qt_metacall()
105*/
106int QRemoteObjectDynamicReplica::qt_metacall(QMetaObject::Call call, int id, void **argv)
107{
108 static const bool debugArgs = qEnvironmentVariableIsSet(varName: "QT_REMOTEOBJECT_DEBUG_ARGUMENTS");
109
110 auto impl = qSharedPointerCast<QConnectedReplicaImplementation>(src: d_impl);
111
112 int saved_id = id;
113 id = QRemoteObjectReplica::qt_metacall(call, id, argv);
114 if (id < 0 || impl->m_metaObject == nullptr)
115 return id;
116
117 if (call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) {
118 QMetaProperty mp = metaObject()->property(index: saved_id);
119
120 if (call == QMetaObject::WriteProperty) {
121 QVariantList args;
122 if (mp.userType() == QMetaType::QVariant)
123 args << *reinterpret_cast<QVariant*>(argv[0]);
124 else
125 args << QVariant(mp.metaType(), argv[0]);
126 QRemoteObjectReplica::send(call: QMetaObject::WriteProperty, index: saved_id, args);
127 } else {
128 if (mp.userType() == QMetaType::QVariant)
129 *reinterpret_cast<QVariant*>(argv[0]) = impl->m_propertyStorage[id];
130 else {
131 const QVariant value = propAsVariant(i: id);
132 mp.metaType().destruct(data: argv[0]);
133 mp.metaType().construct(where: argv[0], copy: value.data());
134 }
135 }
136
137 id = -1;
138 } else if (call == QMetaObject::InvokeMetaMethod) {
139 if (id < impl->m_numSignals) {
140 qCDebug(QT_REMOTEOBJECT) << "DynamicReplica Activate" << impl->m_metaObject->method(index: saved_id).methodSignature();
141 // signal relay from Source world to Replica
142 QMetaObject::activate(sender: this, impl->m_metaObject, local_signal_index: id, argv);
143
144 } else {
145 // method relay from Replica to Source
146 const QMetaMethod mm = impl->m_metaObject->method(index: saved_id);
147 const int nParam = mm.parameterCount();
148 QVariantList args;
149 args.reserve(asize: nParam);
150 for (int i = 0; i < nParam; ++i) {
151 const auto metaType = mm.parameterMetaType(index: i);
152 if (metaType.flags().testFlag(flag: QMetaType::IsEnumeration)) {
153 auto transferType = QRemoteObjectPackets::transferTypeForEnum(enumType: metaType);
154 args.push_back(t: QVariant(transferType, argv[i + 1]));
155 } else
156 args.push_back(t: QVariant(metaType, argv[i + 1]));
157 }
158
159 if (debugArgs) {
160 qCDebug(QT_REMOTEOBJECT) << "method" << mm.methodSignature() << "invoked - args:" << args;
161 } else {
162 qCDebug(QT_REMOTEOBJECT) << "method" << mm.methodSignature() << "invoked";
163 }
164
165 if (mm.returnType() == QMetaType::Void)
166 QRemoteObjectReplica::send(call: QMetaObject::InvokeMetaMethod, index: saved_id, args);
167 else {
168 QRemoteObjectPendingCall call = QRemoteObjectReplica::sendWithReply(call: QMetaObject::InvokeMetaMethod, index: saved_id, args);
169 if (argv[0])
170 *(static_cast<QRemoteObjectPendingCall*>(argv[0])) = call;
171 }
172 }
173
174 id = -1;
175 }
176
177 return id;
178}
179
180QT_END_NAMESPACE
181

source code of qtremoteobjects/src/remoteobjects/qremoteobjectdynamicreplica.cpp