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