1// Copyright (C) 2023 basysKom GmbH, opensource@basyskom.com
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 <QtOpcUa/qopcuastructuredefinition.h>
5#include <QtOpcUa/qopcuagenericstructvalue.h>
6
7#include <QtCore/qdebug.h>
8#include <QtCore/qhash.h>
9#include <QtCore/qstring.h>
10#include <QtCore/qvariant.h>
11
12QT_BEGIN_NAMESPACE
13
14using namespace Qt::Literals::StringLiterals;
15
16/*!
17 \class QOpcUaGenericStructValue
18 \inmodule QtOpcUa
19 \since 6.7
20
21 \brief Holds the value of a generic OPC UA structured type.
22
23 This class holds a generic OPC UA struct value which consists of named fields with their values
24 which can be built-in types or their sub types as well as other nested generic structs.
25 Some meta information like the type ID and the structure definition of the type contained in
26 an object of this class is also included.
27
28 It is used as return type for the decoding result and as input type for the encoding method of
29 \l QOpcUaGenericStructHandler.
30
31 For a struct with optional fields, only the fields that were specified are contained in the
32 \a fields() list. To omit an optional field during encoding, it must not appear in the fields()
33 list.
34 For structs derived from the Union type, only one of the fields must be specified.
35 The only entry in the fields() list of a decoded type determines which field (if any) of the
36 type definition was specified.
37
38 Example:
39 \code
40 // Decode an extension object
41 QOpcUaGenericStructValue value = decoder.decode(extensionObject, success);
42
43 // Print the value of a mandatory field
44 qDebug() << value.fields().value("MyField").value<QOpcUaLocalizedText>();
45
46 // Print the value of an optional field
47 if (value.fields().contains("MyOptionalField"))
48 qDebug() << value.fields().value("MyField").value<QOpcUaQualifiedName>();
49
50 // Get a nested struct for a field
51 const auto unionMember = value.fields().value("MyUnionMember").value<QOpcUaGenericStructValue>();
52
53 // Print the specified field
54 if (unionMember.fields().contains("UnionMember1"))
55 qDebug() << unionMember.fields().value("UnionMember1").toInt();
56 else if (unionMember.fields().contains("UnionMember2"))
57 qDebug() << unionMember.fields().value("UnionMember2").toDouble();
58 else
59 qDebug() << "Empty union";
60 \endcode
61*/
62
63class QOpcUaGenericStructValueData : public QSharedData
64{
65public:
66 QOpcUaGenericStructValueData() = default;
67 QOpcUaGenericStructValueData(const QString &typeName, const QString &typeId,
68 const QOpcUaStructureDefinition &definition, const QHash<QString, QVariant> &fields)
69 : typeName(typeName)
70 , typeId(typeId)
71 , structureDefinition(definition)
72 , fields(fields)
73 {}
74 QString typeName;
75 QString typeId;
76 QOpcUaStructureDefinition structureDefinition;
77 QHash<QString, QVariant> fields;
78};
79
80QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QOpcUaGenericStructValueData)
81
82/*!
83 Constructs a generic struct value.
84*/
85QOpcUaGenericStructValue::QOpcUaGenericStructValue()
86 : data(new QOpcUaGenericStructValueData())
87{
88}
89
90/*!
91 Destroys this generic struct value object.
92*/
93QOpcUaGenericStructValue::~QOpcUaGenericStructValue()
94{
95}
96
97/*!
98 Constructs a generic struct value from \a typeName, \a typeId and \a definition.
99*/
100QOpcUaGenericStructValue::QOpcUaGenericStructValue(const QString &typeName, const QString &typeId,
101 const QOpcUaStructureDefinition &definition)
102 : data(new QOpcUaGenericStructValueData(typeName, typeId, definition, {}))
103{
104}
105
106/*!
107 Constructs a generic struct value from \a typeName, \a typeId, \a definition and \a fields.
108*/
109QOpcUaGenericStructValue::QOpcUaGenericStructValue(const QString &typeName, const QString &typeId,
110 const QOpcUaStructureDefinition &definition, const QHash<QString, QVariant> &fields)
111 : data(new QOpcUaGenericStructValueData(typeName, typeId, definition, fields))
112{
113}
114
115/*!
116 Constructs a generic struct value from \a other.
117*/
118QOpcUaGenericStructValue::QOpcUaGenericStructValue(const QOpcUaGenericStructValue &other)
119 : data(other.data)
120{
121}
122
123/*!
124 Sets the value of \a rhs in this generic struct value.
125*/
126QOpcUaGenericStructValue &QOpcUaGenericStructValue::operator=(const QOpcUaGenericStructValue &rhs)
127{
128 if (this != &rhs)
129 this->data = rhs.data;
130
131 return *this;
132}
133
134/*!
135 \fn QOpcUaGenericStructValue::QOpcUaGenericStructValue(QOpcUaGenericStructValue &&other)
136
137 Move-constructs a new generic struct value from \a other.
138
139 \note The moved-from object \a other is placed in a
140 partially-formed state, in which the only valid operations are
141 destruction and assignment of a new value.
142*/
143
144/*!
145 \fn QOpcUaGenericStructValue &QOpcUaGenericStructValue::operator=(QOpcUaGenericStructValue &&other)
146
147 Move-assigns \a other to this QOpcUaGenericStructValue instance.
148
149 \note The moved-from object \a other is placed in a
150 partially-formed state, in which the only valid operations are
151 destruction and assignment of a new value.
152*/
153
154/*!
155 \fn void QOpcUaGenericStructValue::swap(QOpcUaGenericStructValue &other)
156
157 Swaps generic struct value object \a other with this generic struct value
158 object. This operation is very fast and never fails.
159*/
160
161/*!
162 \fn bool QOpcUaGenericStructValue::operator!=(const QOpcUaGenericStructValue &lhs, const QOpcUaGenericStructValue &rhs)
163
164 Returns \c true if \a lhs is not equal to \a rhs.
165*/
166
167/*!
168 \fn bool QOpcUaGenericStructValue::operator==(const QOpcUaGenericStructValue &lhs, const QOpcUaGenericStructValue &rhs)
169
170 Returns \c true if \a lhs is equal to \a rhs.
171*/
172bool comparesEqual(const QOpcUaGenericStructValue &lhs, const QOpcUaGenericStructValue &rhs) noexcept
173{
174 return lhs.typeName() == rhs.typeName() && lhs.typeId() == rhs.typeId() &&
175 lhs.structureDefinition() == rhs.structureDefinition() && lhs.fields() == rhs.fields();
176}
177
178/*!
179 Returns a \l QVariant containing this generic struct value.
180*/
181QOpcUaGenericStructValue::operator QVariant() const
182{
183 return QVariant::fromValue(value: *this);
184}
185
186/*!
187 Returns the type name for this generic struct value.
188*/
189QString QOpcUaGenericStructValue::typeName() const
190{
191 return data->typeName;
192}
193
194/*!
195 Sets the type name for this generic struct value to \a typeName.
196*/
197void QOpcUaGenericStructValue::setTypeName(const QString &typeName)
198{
199 if (typeName != data->typeName) {
200 data.detach();
201 data->typeName = typeName;
202 }
203}
204
205/*!
206 Returns the type node id for this generic struct value.
207*/
208QString QOpcUaGenericStructValue::typeId() const
209{
210 return data->typeId;
211}
212
213/*!
214 Sets the type node id for this generic struct value to \a typeId.
215*/
216void QOpcUaGenericStructValue::setTypeId(const QString &typeId)
217{
218 if (typeId != data->typeId) {
219 data.detach();
220 data->typeId = typeId;
221 }
222}
223
224/*!
225 Returns the structure definition for this generic struct value.
226*/
227QOpcUaStructureDefinition QOpcUaGenericStructValue::structureDefinition() const
228{
229 return data->structureDefinition;
230}
231
232/*!
233 Sets the structure definition for this generic struct value to \a structureDefinition.
234*/
235void QOpcUaGenericStructValue::setStructureDefinition(const QOpcUaStructureDefinition &structureDefinition)
236{
237 if (structureDefinition != data->structureDefinition) {
238 data.detach();
239 data->structureDefinition = structureDefinition;
240 }
241}
242
243/*!
244 Returns the fields of this generic struct value.
245*/
246QHash<QString, QVariant> QOpcUaGenericStructValue::fields() const
247{
248 return data->fields;
249}
250
251/*!
252 Returns a reference to the fields of this generic struct value.
253*/
254QHash<QString, QVariant> &QOpcUaGenericStructValue::fieldsRef()
255{
256 return data->fields;
257}
258
259/*!
260 Sets the fields of this generic struct value to \a fields.
261*/
262void QOpcUaGenericStructValue::setFields(const QHash<QString, QVariant> &fields)
263{
264 if (fields != data->fields) {
265 data.detach();
266 data->fields = fields;
267 }
268}
269
270#ifndef QT_NO_DEBUG_STREAM
271/*!
272 Returns a string representation for this generic struct value.
273 */
274QString QOpcUaGenericStructValue::toString() const
275{
276 QString out;
277 QDebug dbg(&out);
278 dbg.nospace().noquote() << *this;
279 return out;
280}
281
282/*!
283 \fn QDebug QOpcUaGenericStructValue::operator<<(QDebug debug, const QOpcUaGenericStructValue &s)
284 Outputs the string representation of \a s into \a debug.
285 */
286QDebug operator<<(QDebug debug, const QOpcUaGenericStructValue &s)
287{
288 QDebugStateSaver saver(debug);
289
290 QString structType = u"Struct"_s;
291 if (s.structureDefinition().structureType() == QOpcUaStructureDefinition::StructureType::StructureWithOptionalFields)
292 structType = u"StructWithOptionalFields"_s;
293 else if (s.structureDefinition().structureType() == QOpcUaStructureDefinition::StructureType::Union)
294 structType = u"Union"_s;
295
296 debug.noquote().nospace();
297 debug << structType << " " << s.typeName() << " (";
298 for (auto it = s.data->fields.constBegin(); it != s.data->fields.constEnd(); ++it)
299 debug << (it == s.data->fields.constBegin() ? "" : " ") << it.key() << ": " << it.value();
300 debug << ")";
301 return debug;
302}
303#endif
304
305QT_END_NAMESPACE
306

source code of qtopcua/src/opcua/client/qopcuagenericstructvalue.cpp