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 "util.h"
5#include "datatypefilewriter.h"
6#include "enumeratedtype.h"
7#include "enumeratedvalue.h"
8#include "field.h"
9#include "stringidentifier.h"
10#include "structuredtype.h"
11
12#include <QtCore/qdir.h>
13#include <QtCore/qfile.h>
14#include <QtCore/qset.h>
15
16DataTypeFileWriter::DataTypeFileWriter(const QString &path,
17 const QString &prefix,
18 const QString &header)
19 : m_path(path)
20 , m_prefix(prefix)
21 , m_header(header)
22{}
23
24void DataTypeFileWriter::visit(XmlElement *xmlElement)
25{
26 Q_UNUSED(xmlElement);
27}
28
29void DataTypeFileWriter::visit(EnumeratedType *enumeratedType)
30{
31 bool isPrecodedType = false;
32 for (const auto &precodedType : StringIdentifier::opcUaPrecodedTypes) {
33 if (precodedType.contains(name: enumeratedType->name())) {
34 isPrecodedType = true;
35 break;
36 }
37 }
38 if (!isPrecodedType) {
39 m_generateMapping.append(t: enumeratedType);
40 }
41}
42
43void DataTypeFileWriter::visit(EnumeratedValue *enumeratedValue)
44{
45 Q_UNUSED(enumeratedValue);
46}
47
48void DataTypeFileWriter::visit(Field *field)
49{
50 Q_UNUSED(field);
51}
52
53void DataTypeFileWriter::visit(Import *import)
54{
55 Q_UNUSED(import);
56}
57
58void DataTypeFileWriter::visit(StructuredType *structuredType)
59{
60 if (!structuredType->fields().empty()) {
61 bool isPrecodedType = false;
62 for (const auto &precodedType : StringIdentifier::opcUaPrecodedTypes) {
63 if (precodedType.contains(name: structuredType->name())) {
64 isPrecodedType = true;
65 break;
66 }
67 }
68 if (!isPrecodedType) {
69 m_generateMapping.append(t: structuredType);
70 }
71 }
72}
73
74void DataTypeFileWriter::visit(TypeDictionary *typeDictionary)
75{
76 Q_UNUSED(typeDictionary);
77}
78
79void DataTypeFileWriter::writeLicenseHeader(QTextStream &output)
80{
81 if (!m_header.isEmpty())
82 output << m_header << Util::lineBreak(n: 2);
83}
84
85void DataTypeFileWriter::writeStructuredTypeCpp(const StructuredType *structuredType,
86 QTextStream &output)
87{
88 if (!m_generatedStructuredTypeFilenames.contains(
89 QStringLiteral("%1%2").arg(args&: m_prefix, args: structuredType->name())))
90 m_generatedStructuredTypeFilenames.push_back(
91 QStringLiteral("%1%2").arg(args&: m_prefix, args: structuredType->name()));
92 output << "#include \"" << m_prefix.toLower() << structuredType->name().toLower() << ".h\"";
93
94 QList<QString> mutualIncludes;
95 for (const auto field : structuredType->fields()) {
96 const auto typeName = field->typeNameSecondPart();
97 for (const auto &type : m_generateMapping) {
98 StructuredType *tempStructuredType = dynamic_cast<StructuredType *>(type);
99 if (tempStructuredType) {
100 if (tempStructuredType == structuredType)
101 continue;
102 for (const auto &tempField : tempStructuredType->fields()) {
103 if (typeName == tempStructuredType->name()
104 && tempField->typeNameSecondPart() == structuredType->name()) {
105 if (!mutualIncludes.contains(
106 QStringLiteral("#include \"%1%2.h\"\n")
107 .arg(args: m_prefix.toLower(), args: tempStructuredType->name().toLower())))
108 mutualIncludes.push_back(
109 QStringLiteral("#include \"%1%2.h\"\n")
110 .arg(args: m_prefix.toLower(), args: tempStructuredType->name().toLower()));
111 }
112 }
113 }
114 }
115 }
116 if (!mutualIncludes.isEmpty()) {
117 output << Util::lineBreak();
118 std::sort(first: mutualIncludes.begin(), last: mutualIncludes.end());
119 for (const auto &include : mutualIncludes) {
120 output << include;
121 }
122 }
123 if (structuredType->recursive()) {
124 output << Util::lineBreak();
125 output << "#include <optional>";
126 output << Util::lineBreak();
127 }
128 output << Util::lineBreak(n: 2);
129
130 writeStructuredTypeCppClassComment(structuredType, output);
131 writeStructuredTypeCppDataClass(structuredType, output);
132 writeStructuredTypeCppConstructors(structuredType, output);
133 writeStructuredTypeCppOperatorAssignment(structuredType, output);
134 writeStructuredTypeCppOperatorEquality(structuredType, output);
135 writeStructuredTypeCppQVariant(structuredType, output);
136 writeStructuredTypeCppDestructor(structuredType, output);
137 writeStructuredTypeCppGetterSetter(structuredType, output);
138 writeStructuredTypeCppDebug(structuredType, output);
139}
140
141void DataTypeFileWriter::writeStructuredTypeCppClassComment(const StructuredType *structuredType,
142 QTextStream &output)
143{
144 output << "/*!"
145 << Util::lineBreak();
146 output << Util::indent(level: 1) << "\\class " << m_prefix << structuredType->name() << Util::lineBreak();
147 output << Util::indent(level: 1) << "\\brief the OPC UA " << structuredType->name() << "."
148 << Util::lineBreak();
149 output << "*/"
150 << Util::lineBreak();
151}
152
153void DataTypeFileWriter::writeStructuredTypeCppDataClass(const StructuredType *structuredType,
154 QTextStream &output)
155{
156 output << "class " << m_prefix << structuredType->name() << "Data : public QSharedData"
157 << Util::lineBreak();
158 output << "{"
159 << Util::lineBreak();
160 output << "public:"
161 << Util::lineBreak();
162
163 writeStructuredTypeCppDataClassMember(structuredType, output);
164
165 output << "};"
166 << Util::lineBreak(n: 2);
167}
168
169void DataTypeFileWriter::writeStructuredTypeCppDataClassMember(const StructuredType *structuredType,
170 QTextStream &output)
171{
172 QList<Field *> unionMember;
173 if (structuredType->hasUnion()) {
174 for (const auto &possibleUnionMember : structuredType->fields()) {
175 for (const auto &field : structuredType->fields()) {
176 if (field->isUnion()) {
177 if (field->switchField() == possibleUnionMember->name()
178 && !unionMember.contains(t: possibleUnionMember))
179 unionMember.push_back(t: possibleUnionMember);
180 }
181 }
182 }
183 }
184 QList<Field *> arrayLengthfields;
185 for (const auto &possibleArrayLengthField : structuredType->fields()) {
186 for (const auto &field : structuredType->fields()) {
187 if (possibleArrayLengthField->name() == field->lengthField()
188 && !arrayLengthfields.contains(t: possibleArrayLengthField))
189 arrayLengthfields.push_back(t: possibleArrayLengthField);
190 }
191 }
192
193 QList<Field *> switchFields;
194 if (structuredType->hasSwitchfield()) {
195 for (const auto &possibleOptionalMember : structuredType->fields()) {
196 for (const auto &field : structuredType->fields()) {
197 if (!possibleOptionalMember->switchField().isEmpty() && possibleOptionalMember->switchField() == field->name())
198 switchFields.push_back(t: field);
199 }
200 }
201 }
202
203 for (const auto &field : structuredType->fields()) {
204 if (field->isInStructuredTypeBitMask() && !switchFields.contains(t: field))
205 continue;
206
207 bool isEnumeration = false;
208 for (const auto &enumeratedType : m_enumeratedTypes) {
209 if (enumeratedType->name() == field->typeName().split(sep: ":").at(i: 1)) {
210 isEnumeration = true;
211 field->setIsEnum(true);
212 }
213 }
214
215 bool isPreCoded = false;
216 if (!arrayLengthfields.contains(t: field)) {
217 if (!unionMember.contains(t: field)) {
218 output << Util::indent(level: 1);
219 if (StringIdentifier::typeNameDataTypeConverter.contains(key: field->typeName())) {
220 if (!field->needContainer()) {
221 output << StringIdentifier::typeNameDataTypeConverter.value(
222 key: field->typeName())
223 << " ";
224 } else {
225 output << "QList<"
226 << StringIdentifier::typeNameDataTypeConverter.value(
227 key: field->typeName())
228 << "> ";
229 }
230 } else {
231 const auto typeName = field->typeNameSecondPart();
232 for (const auto &preCodedType : StringIdentifier::opcUaPrecodedTypes) {
233 if (preCodedType.contains(name: typeName)) {
234 isPreCoded = true;
235 if (field->needContainer())
236 output << "QList<";
237 if (preCodedType.deEncoderName().isEmpty())
238 output << preCodedType.className();
239 else
240 output << preCodedType.deEncoderName();
241 if (field->needContainer())
242 output << ">";
243 output << " ";
244 break;
245 }
246 }
247 if (!isPreCoded) {
248 if (field->needContainer())
249 output << "QList<" << m_prefix << typeName << "> ";
250 else if (field->recursive())
251 output << "std::optional<" << m_prefix << typeName << "> ";
252 else if (isEnumeration)
253 output << m_prefix << "::" << typeName << " ";
254 else
255 output << m_prefix << typeName << " ";
256 }
257 }
258
259 const auto lowerCaseFieldName = field->lowerFirstName();
260 output << lowerCaseFieldName;
261 if (!field->needContainer()) {
262 if (StringIdentifier::typeNameDataTypeConverter.contains(key: field->typeName())) {
263 if (field->typeName().contains(s: StringIdentifier::integerIdentifier)
264 || field->typeName().contains(s: StringIdentifier::doubleIdentifier)
265 || field->typeName().contains(s: StringIdentifier::floatIdentifier)
266 || field->typeName().contains(s: StringIdentifier::byteIdentifier)
267 || field->typeName().contains(s: StringIdentifier::sbyteIdentifier))
268 output << " {0}";
269 else if (field->typeName().contains(s: StringIdentifier::booleanIdentifier)
270 || field->typeName().contains(s: StringIdentifier::bitIdentifier))
271 output << " {false}";
272 } else if (field->isEnum()) {
273 const auto enumType = std::find_if(first: m_enumeratedTypes.constBegin(), last: m_enumeratedTypes.constEnd(),
274 pred: [field](EnumeratedType *e) { return e->name() == field->typeNameSecondPart(); });
275 const auto firstValueName = enumType != m_enumeratedTypes.constEnd() && !(*enumType)->values().empty()
276 ? (*enumType)->values().first()->name() : "Unknown";
277 if (!firstValueName.isEmpty())
278 output << " {" << m_prefix << "::" << field->typeNameSecondPart() << "::" << firstValueName << "}";
279 else
280 output << " {}";
281 } else {
282 if (field->typeName().contains(s: StringIdentifier::uaStatusCodeIdentifier))
283 output << " {QOpcUa::UaStatusCode::Good}";
284 }
285 }
286 output << ";"
287 << Util::lineBreak();
288 } else {
289 const auto fieldNameLowerCase = field->lowerFirstName();
290 output << Util::indent(level: 1) << m_prefix << structuredType->name() << "::" << field->name()
291 << " " << fieldNameLowerCase << " = " << m_prefix << structuredType->name()
292 << "::" << field->name() << "::"
293 << "None";
294
295 output << ";"
296 << Util::lineBreak();
297 }
298 }
299 }
300}
301
302void DataTypeFileWriter::writeStructuredTypeCppConstructors(const StructuredType *structuredType,
303 QTextStream &output)
304{
305 output << m_prefix << structuredType->name() << "::" << m_prefix << structuredType->name()
306 << "()"
307 << Util::lineBreak();
308 output << " : data(new " << m_prefix << structuredType->name() << "Data)\n";
309 output << "{"
310 << Util::lineBreak();
311 output << "}"
312 << Util::lineBreak(n: 2);
313
314 output << "/*!"
315 << Util::lineBreak();
316 output << " Constructs a " << structuredType->name() << " from \\a rhs"
317 << Util::lineBreak();
318 output << "*/"
319 << Util::lineBreak();
320 output << m_prefix << structuredType->name() << "::" << m_prefix << structuredType->name()
321 << "(const " << m_prefix << structuredType->name() << " &rhs)"
322 << Util::lineBreak();
323 output << " : data(rhs.data)"
324 << Util::lineBreak();
325 output << "{"
326 << Util::lineBreak();
327 output << "}"
328 << Util::lineBreak(n: 2);
329}
330
331void DataTypeFileWriter::writeStructuredTypeCppOperatorAssignment(
332 const StructuredType *structuredType, QTextStream &output)
333{
334 output << "/*!"
335 << Util::lineBreak();
336 output << " Sets the values from \\a rhs in this " << structuredType->name() << Util::lineBreak();
337 output << "*/"
338 << Util::lineBreak();
339 output << m_prefix << structuredType->name() << " &" << m_prefix << structuredType->name()
340 << "::operator=(const " << m_prefix << structuredType->name() << " &rhs)"
341 << Util::lineBreak();
342 output << "{"
343 << Util::lineBreak();
344 output << Util::indent(level: 1) << "if (this != &rhs)"
345 << Util::lineBreak();
346 output << Util::indent(level: 2) << "data.operator=(rhs.data);"
347 << Util::lineBreak();
348 output << Util::indent(level: 1) << "return *this;"
349 << Util::lineBreak();
350 output << "}"
351 << Util::lineBreak(n: 2);
352}
353
354void DataTypeFileWriter::writeStructuredTypeCppOperatorEquality(const StructuredType *structuredType,
355 QTextStream &output)
356{
357 output << "/*!"
358 << Util::lineBreak();
359 output << Util::indent(level: 1) << "Returns \\c true if this " << structuredType->name()
360 << " has the same value as \\a rhs"
361 << Util::lineBreak();
362 output << "*/"
363 << Util::lineBreak();
364
365 output << "bool " << m_prefix << structuredType->name() << "::operator==(const " << m_prefix
366 << structuredType->name() << " &rhs) const"
367 << Util::lineBreak();
368 output << "{"
369 << Util::lineBreak();
370 QList<Field *> unionSwitchfield;
371 QList<Field *> arrayLengthfields;
372 for (const auto &possibleMember : structuredType->fields()) {
373 for (const auto &field : structuredType->fields()) {
374 if (possibleMember->name() == field->lengthField()
375 && !arrayLengthfields.contains(t: possibleMember))
376 arrayLengthfields.push_back(t: possibleMember);
377 if (possibleMember->name() == field->switchField()
378 && !unionSwitchfield.contains(t: possibleMember) && field->isUnion())
379 unionSwitchfield.push_back(t: possibleMember);
380 }
381 }
382
383 if (!unionSwitchfield.isEmpty()) {
384 const auto switchField = unionSwitchfield.first()->lowerFirstName();
385 output << Util::indent(level: 1) << "if (data->" << switchField << " != " << " rhs.data->" << switchField << ")" << Util::lineBreak();
386 output << Util::indent(level: 2) << "return false;" << Util::lineBreak(n: 2);
387 }
388
389 if (structuredType->containsBitMask()) {
390 for (const auto &field : structuredType->fields()) {
391 if (!field->switchField().isEmpty() && !arrayLengthfields.contains(t: field)) {
392 const auto switchField = Util::lowerFirstLetter(temp: field->switchField());
393 output << Util::indent(level: 1) << "if (data->" << switchField << " != rhs.data->" << switchField << " || (data->" << switchField << " && ";
394 output << "!(data->" << field->lowerFirstName() << " == rhs.data->" << field->lowerFirstName() << ")";
395 output << "))";
396 output << Util::lineBreak() << Util::indent(level: 2) << "return false;" << Util::lineBreak();
397 }
398 }
399 output << Util::lineBreak();
400 }
401
402 auto counterGeneratedTypes = 0;
403 if (structuredType->hasUnion()) {
404 for (const auto &field : structuredType->fields()) {
405 if (!arrayLengthfields.contains(t: field) && !unionSwitchfield.contains(t: field) && !field->isInStructuredTypeBitMask()) {
406 if (structuredType->containsBitMask() && !field->switchField().isEmpty())
407 continue;
408
409
410 output << Util::indent(level: 1) << "if (static_cast<qint32>(data->" << unionSwitchfield.first()->lowerFirstName() << ") == " << field->switchValue() << " && ";
411 output << "!(data->" << field->lowerFirstName() << " == rhs.data->" << field->lowerFirstName() << ")";
412 output << ")" << Util::lineBreak();
413 output << Util::indent(level: 2) << "return false;" << Util::lineBreak(n: 2);
414 }
415 }
416
417 output << Util::indent(level: 1) << "return true;" << Util::lineBreak();
418 } else {
419 output << Util::indent(level: 1) << "return ";
420
421 for (const auto &field : structuredType->fields()) {
422 if (!arrayLengthfields.contains(t: field) && !unionSwitchfield.contains(t: field) && !field->isInStructuredTypeBitMask()) {
423 if (structuredType->containsBitMask() && !field->switchField().isEmpty())
424 continue;
425
426 const auto memberName = field->lowerFirstName();
427 if (counterGeneratedTypes != 0)
428 output << Util::lineBreak() << Util::indent(level: 2) << " && ";
429 output << "data->" << memberName << " == rhs.data->" << memberName;
430 counterGeneratedTypes++;
431 }
432 }
433
434 output << ";" << Util::lineBreak();
435 }
436
437 output << "}"
438 << Util::lineBreak(n: 2);
439}
440
441void DataTypeFileWriter::writeStructuredTypeCppQVariant(const StructuredType *structuredType,
442 QTextStream &output)
443{
444 output << "/*!"
445 << Util::lineBreak();
446 output << " Converts this " << structuredType->name() << " to \\l QVariant"
447 << Util::lineBreak();
448 output << "*/"
449 << Util::lineBreak();
450
451 output << m_prefix << structuredType->name() << "::operator QVariant() const"
452 << Util::lineBreak();
453 output << "{"
454 << Util::lineBreak();
455 output << Util::indent(level: 1) << "return QVariant::fromValue(*this);"
456 << Util::lineBreak();
457 output << "}"
458 << Util::lineBreak(n: 2);
459}
460
461void DataTypeFileWriter::writeStructuredTypeCppDestructor(const StructuredType *structuredType,
462 QTextStream &output)
463{
464 output << m_prefix << structuredType->name() << "::~" << m_prefix << structuredType->name()
465 << "()"
466 << Util::lineBreak();
467 output << "{"
468 << Util::lineBreak();
469 output << "}"
470 << Util::lineBreak(n: 2);
471}
472
473void DataTypeFileWriter::writeStructuredTypeCppGetterSetter(const StructuredType *structuredType,
474 QTextStream &output)
475{
476 writeStructuredTypeCppGetter(structuredType, output);
477}
478
479void DataTypeFileWriter::writeStructuredTypeCppGetter(const StructuredType *structuredType,
480 QTextStream &output)
481{
482 QList<Field *> unionMember;
483 if (structuredType->hasUnion()) {
484 for (const auto &possibleUnionMember : structuredType->fields()) {
485 for (const auto &field : structuredType->fields()) {
486 if (field->isUnion()) {
487 if (field->switchField() == possibleUnionMember->name()
488 && !unionMember.contains(t: possibleUnionMember))
489 unionMember.push_back(t: possibleUnionMember);
490 }
491 }
492 }
493 }
494 QList<Field *> arrayLengthfields;
495 for (const auto &possibleArrayLengthField : structuredType->fields()) {
496 for (const auto &field : structuredType->fields()) {
497 if (possibleArrayLengthField->name() == field->lengthField()
498 && !arrayLengthfields.contains(t: possibleArrayLengthField))
499 arrayLengthfields.push_back(t: possibleArrayLengthField);
500 }
501 }
502
503 QList<Field *> switchFields;
504 if (structuredType->hasSwitchfield()) {
505 for (const auto &possibleOptionalMember : structuredType->fields()) {
506 for (const auto &field : structuredType->fields()) {
507 if (!possibleOptionalMember->switchField().isEmpty() && possibleOptionalMember->switchField() == field->name())
508 switchFields.push_back(t: field);
509 }
510 }
511 }
512
513 for (const auto &field : structuredType->fields()) {
514 if (!arrayLengthfields.contains(t: field) && !(field->isInStructuredTypeBitMask() && !switchFields.contains(t: field))) {
515 const auto tmpFunctionName = field->lowerFirstName();
516
517 output << "/*!\n";
518 output << Util::indent(level: 1) << "Returns the field " << field->name() << " of this " << structuredType->name() << " object"
519 << Util::lineBreak();
520 output << "*/\n";
521
522 const auto typeName = field->typeNameSecondPart();
523 if (!unionMember.contains(t: field)) {
524 if (field->needContainer())
525 output << "QList<";
526 if (StringIdentifier::typeNameDataTypeConverter.contains(key: field->typeName())) {
527 output << StringIdentifier::typeNameDataTypeConverter.value(key: field->typeName());
528 } else {
529 bool isPreCoded = false;
530 for (const auto &preCodedType : StringIdentifier::opcUaPrecodedTypes) {
531 if (preCodedType.contains(name: typeName)) {
532 isPreCoded = true;
533 if (preCodedType.deEncoderName().isEmpty())
534 output << preCodedType.className();
535 else
536 output << preCodedType.deEncoderName();
537 break;
538 }
539 }
540 if (!isPreCoded) {
541 bool isEnum = false;
542 for (const auto &enumeratedType : m_enumeratedTypes) {
543 if (enumeratedType->name() == field->typeName().split(sep: ":").at(i: 1))
544 isEnum = true;
545 }
546 if (isEnum)
547 output << m_prefix << "::" << field->typeName().split(sep: ":").at(i: 1);
548 else
549 output << m_prefix << typeName;
550 }
551 }
552 if (field->needContainer())
553 output << ">";
554 output << " ";
555
556 } else {
557 output << m_prefix << structuredType->name() << "::" << field->name() << " ";
558 }
559
560 output << m_prefix << structuredType->name() << "::" << tmpFunctionName << "() const"
561 << Util::lineBreak();
562 output << "{"
563 << Util::lineBreak();
564 if (!field->isUnion()) {
565 if (field->recursive())
566 if (field->needContainer()) {
567 output << Util::indent(level: 1) << "return data->" << tmpFunctionName << ";"
568 << Util::lineBreak();
569 } else {
570 output << Util::indent(level: 1) << "return data->" << tmpFunctionName << ".value_or(" << m_prefix
571 << field->typeName().split(sep: QChar::fromLatin1(c: ':')).at(i: 1) << "()"
572 << ");"
573 << Util::lineBreak();
574 }
575 else
576 output << Util::indent(level: 1) << "return data->" << tmpFunctionName << ";"
577 << Util::lineBreak();
578 } else {
579 const auto switchfieldToLower = Util::lowerFirstLetter(temp: field->switchField());
580 output << Util::indent(level: 1) << "if (data->" << switchfieldToLower << " == " << m_prefix
581 << structuredType->name() << "::" << field->switchField()
582 << "::" << field->name() << ")"
583 << Util::lineBreak();
584 output << Util::indent(level: 2) << "return data->" << tmpFunctionName << ";"
585 << Util::lineBreak();
586 output << Util::indent(level: 1) << "else"
587 << Util::lineBreak();
588 output << Util::indent(level: 2) << "return {};" << Util::lineBreak();
589 }
590 output << "}"
591 << Util::lineBreak(n: 2);
592 if (!unionMember.contains(t: field))
593 writeStructuredTypeCppSetter(field, structuredType, output);
594 }
595 }
596}
597
598void DataTypeFileWriter::writeStructuredTypeCppSetter(const Field *field,
599 const StructuredType *structuredType,
600 QTextStream &output)
601{
602 output << "/*!"
603 << Util::lineBreak();
604 output << Util::indent(level: 1) << "Sets the field " << field->name() << " of this " << structuredType->name() << " object to \\a "
605 << field->lowerFirstName() << Util::lineBreak();
606 output << "*/"
607 << Util::lineBreak();
608
609 output << "void " << m_prefix << structuredType->name() << "::set" << field->name() << "(";
610 const auto tmpFunctionName = field->lowerFirstName();
611 if (StringIdentifier::typeNameDataTypeConverter.contains(key: field->typeName())) {
612 if (field->typeName().contains(s: StringIdentifier::booleanIdentifier)
613 || field->typeName().contains(s: StringIdentifier::integerIdentifier)
614 || field->typeName().contains(s: StringIdentifier::floatIdentifier)
615 || field->typeName().contains(s: StringIdentifier::doubleIdentifier)) {
616 if (field->needContainer())
617 output << "QList<"
618 << StringIdentifier::typeNameDataTypeConverter.value(key: field->typeName())
619 << "> ";
620 else
621 output << StringIdentifier::typeNameDataTypeConverter.value(key: field->typeName())
622 << " ";
623 } else {
624 output << "const ";
625 if (field->needContainer())
626 output << "QList<"
627 << StringIdentifier::typeNameDataTypeConverter.value(key: field->typeName())
628 << "> &";
629 else
630 output << StringIdentifier::typeNameDataTypeConverter.value(key: field->typeName())
631 << " &";
632 }
633 } else {
634 const auto typeName = field->typeNameSecondPart();
635 bool isPreCoded = false;
636 for (const auto &preCodedType : StringIdentifier::opcUaPrecodedTypes) {
637 if (preCodedType.contains(name: typeName)) {
638 isPreCoded = true;
639 output << "const ";
640 if (field->needContainer())
641 output << "QList<";
642 if (preCodedType.deEncoderName().isEmpty())
643 output << preCodedType.className();
644 else
645 output << preCodedType.deEncoderName();
646 if (field->needContainer())
647 output << ">";
648 output << " &";
649 break;
650 }
651 }
652
653 if (!isPreCoded) {
654 bool isEnum = false;
655 for (const auto &enumeratedType : m_enumeratedTypes) {
656 if (enumeratedType->name() == field->typeName().split(sep: ":").at(i: 1))
657 isEnum = true;
658 }
659 output << "const ";
660 if (field->needContainer())
661 output << "QList <" << m_prefix << typeName << "> &";
662 else if (isEnum)
663 output << m_prefix << "::" << field->typeName().split(sep: ":").at(i: 1) << " &";
664 else
665 output << m_prefix << typeName << " &";
666 }
667 }
668 output << tmpFunctionName << ")"
669 << Util::lineBreak();
670 output << "{"
671 << Util::lineBreak();
672 output << Util::indent(level: 1) << "data->" << tmpFunctionName << " = " << tmpFunctionName << ";"
673 << Util::lineBreak();
674 if (field->isUnion()) {
675 const auto switchfieldToLower = Util::lowerFirstLetter(temp: field->switchField());
676 output << Util::indent(level: 1) << "data->" << switchfieldToLower << " = " << m_prefix << structuredType->name()
677 << "::" << field->switchField() << "::" << field->name() << ";"
678 << Util::lineBreak();
679 }
680 output << "}"
681 << Util::lineBreak(n: 2);
682}
683
684void DataTypeFileWriter::writeStructuredTypeHeader(const StructuredType *structuredType,
685 QTextStream &output)
686{
687 output << "#pragma once"
688 << Util::lineBreak();
689
690 writeStructuredTypeHeaderIncludes(structuredType, output);
691
692 output << "class " << m_prefix << structuredType->name() << Util::lineBreak();
693 output << "{"
694 << Util::lineBreak();
695 output << "public:"
696 << Util::lineBreak();
697
698 writeStructuredTypeHeaderUnion(structuredType, output);
699
700 output << Util::indent(level: 1) << m_prefix << structuredType->name() << "();"
701 << Util::lineBreak();
702 output << Util::indent(level: 1) << m_prefix << structuredType->name() << "(const " << m_prefix
703 << structuredType->name() << " &);"
704 << Util::lineBreak();
705 output << Util::indent(level: 1) << m_prefix << structuredType->name() << " &operator=(const " << m_prefix
706 << structuredType->name() << " &rhs);"
707 << Util::lineBreak();
708 output << Util::indent(level: 1) << "bool operator==(const " << m_prefix << structuredType->name() << " &rhs) const;"
709 << Util::lineBreak();
710 output << Util::indent(level: 1) << "inline bool operator!=(const " << m_prefix << structuredType->name() << " &rhs) const"
711 << Util::lineBreak(n: 1)
712 << Util::indent(level: 2) << "{ return !(*this == rhs); }"
713 << Util::lineBreak();
714 output << Util::indent(level: 1) << "operator QVariant() const;"
715 << Util::lineBreak();
716 output << Util::indent(level: 1) << "~" << m_prefix << structuredType->name() << "();"
717 << Util::lineBreak(n: 2);
718
719 writeStructuredTypeHeaderGetterSetter(structuredType, output);
720
721 writeStructuredTypeHeaderDebug(structuredType, output);
722
723 output << "private:"
724 << Util::lineBreak();
725 output << Util::indent(level: 1) << "QSharedDataPointer<" << m_prefix << structuredType->name() << "Data> data;"
726 << Util::lineBreak();
727 output << "};"
728 << Util::lineBreak(n: 2);
729 output << "Q_DECLARE_METATYPE(" << m_prefix << structuredType->name() << ")"
730 << Util::lineBreak();
731}
732
733void DataTypeFileWriter::writeStructuredTypeHeaderIncludes(const StructuredType *structuredType,
734 QTextStream &output)
735{
736 QList<QString> qtCoreIncludes{"#include <QSharedData>\n",
737 "#include <QVariant>\n"};
738 QList<QString> qtOpcUaIncludes{};
739 QList<QString> qtClassIncludes;
740 QList<QString> qtPredifinedClasses;
741
742 for (const auto &field : structuredType->fields()) {
743 const auto typeName = field->typeNameSecondPart();
744 QString include;
745 if (field->typeName().startsWith(QStringLiteral("%1:").arg(a: StringIdentifier::binaryTypeIdentifier))) {
746 if (typeName == StringIdentifier::datetimeIdentifier) {
747 include = "#include <QDateTime>\n";
748 } else if (typeName == StringIdentifier::byteStringIdentifier) {
749 include = "#include <QByteArray>\n";
750 } else if (typeName == StringIdentifier::charArrayIdentifier) {
751 include = "#include <QString>\n";
752 } else if (typeName == StringIdentifier::guidIdentifier) {
753 include = "#include <QUuid>\n";
754 }
755
756 if (!qtCoreIncludes.contains(str: include)) {
757 qtCoreIncludes.push_back(t: include);
758 }
759 } else {
760 bool isPrecoded = false;
761 for (const auto &precodedType : StringIdentifier::opcUaPrecodedTypes) {
762 if (precodedType.contains(name: typeName)) {
763 isPrecoded = true;
764 if (!precodedType.filename().isEmpty()) {
765 include = QStringLiteral("#include <QtOpcUa/%1>\n")
766 .arg(a: precodedType.filename());
767 break;
768 }
769 }
770 }
771 if (typeName != structuredType->name()) {
772 if (!isPrecoded) {
773 bool isEnum = false;
774 for (const auto &enumeratedType : m_enumeratedTypes) {
775 if (enumeratedType->name() == typeName)
776 isEnum = true;
777 }
778 if (isEnum) {
779 if (!qtClassIncludes.contains(
780 QStringLiteral("#include \"%1enumerations.h\"\n")
781 .arg(a: m_prefix.toLower())))
782 qtClassIncludes.push_back(
783 QStringLiteral("#include \"%1enumerations.h\"\n")
784 .arg(a: m_prefix.toLower()));
785
786 } else {
787 bool isMutualInclude = false;
788 for (const auto &type : m_generateMapping) {
789 StructuredType *tempStructuredType = dynamic_cast<StructuredType *>(
790 type);
791 if (tempStructuredType) {
792 if (tempStructuredType == structuredType)
793 continue;
794 for (const auto &tempField : tempStructuredType->fields()) {
795 const auto tempTypeName = tempField->typeNameSecondPart();
796 if (typeName == tempStructuredType->name()
797 && tempTypeName == structuredType->name()) {
798 isMutualInclude = true;
799 if (!qtPredifinedClasses.contains(
800 QStringLiteral("%1%2")
801 .arg(args&: m_prefix, args: tempStructuredType->name())))
802 qtPredifinedClasses.push_back(
803 QStringLiteral("%1%2")
804 .arg(args&: m_prefix, args: tempStructuredType->name()));
805 }
806 }
807 }
808 }
809
810 if (!qtClassIncludes.contains(
811 QStringLiteral("#include \"%1%2.h\"\n")
812 .arg(args: m_prefix.toLower(), args: typeName.toLower()))
813 && !isMutualInclude
814 && typeName != StringIdentifier::xmlElementIdentifier)
815 qtClassIncludes.push_back(
816 QStringLiteral("#include \"%1%2.h\"\n")
817 .arg(args: m_prefix.toLower(), args: typeName.toLower()));
818 }
819 } else {
820 if (!qtOpcUaIncludes.contains(str: include)) {
821 qtOpcUaIncludes.push_back(t: include);
822 }
823 }
824 }
825 }
826 if (field->needContainer()) {
827 include = "#include <QList>\n";
828 if (!qtCoreIncludes.contains(str: include)) {
829 qtCoreIncludes.push_back(t: include);
830 }
831 }
832 }
833 if (!qtClassIncludes.isEmpty()) {
834 std::sort(first: qtClassIncludes.begin(), last: qtClassIncludes.end());
835 for (const auto &include : qtClassIncludes) {
836 output << include;
837 }
838 output << Util::lineBreak();
839 }
840 std::sort(first: qtOpcUaIncludes.begin(), last: qtOpcUaIncludes.end());
841 for (const auto &include : qtOpcUaIncludes) {
842 output << include;
843 }
844 output << Util::lineBreak();
845 std::sort(first: qtCoreIncludes.begin(), last: qtCoreIncludes.end());
846 for (const auto &include : qtCoreIncludes) {
847 output << include;
848 }
849 output << Util::lineBreak();
850
851 if (!qtPredifinedClasses.isEmpty()) {
852 std::sort(first: qtPredifinedClasses.begin(), last: qtPredifinedClasses.end());
853 for (const auto &predefinedClass : qtPredifinedClasses) {
854 output << "class " << predefinedClass << ";"
855 << Util::lineBreak();
856 }
857 }
858
859 output << "class " << m_prefix << structuredType->name() << "Data;"
860 << Util::lineBreak();
861}
862
863void DataTypeFileWriter::writeStructuredTypeHeaderUnion(const StructuredType *structuredType,
864 QTextStream &output)
865{
866 if (structuredType->hasUnion()) {
867 QList<Field *> unions;
868 QList<Field *> switchFields;
869 for (const auto &field : structuredType->fields()) {
870 if (field->isUnion())
871 switchFields.push_back(t: field);
872 }
873 for (const auto &switchField : switchFields) {
874 for (const auto &structuredTypeField : structuredType->fields()) {
875 if (switchField->switchField() == structuredTypeField->name()) {
876 if (!unions.contains(t: structuredTypeField))
877 unions.push_back(t: structuredTypeField);
878 }
879 }
880 }
881 QList<Field *> arrayLengthfields;
882 for (const auto &possibleArrayLengthField : structuredType->fields()) {
883 for (const auto &field : structuredType->fields()) {
884 if (possibleArrayLengthField->name() == field->lengthField()
885 && !arrayLengthfields.contains(t: possibleArrayLengthField))
886 arrayLengthfields.push_back(t: possibleArrayLengthField);
887 }
888 }
889 for (const auto &field : unions) {
890 output << Util::indent(level: 1) << "enum class " << field->name() << " {"
891 << Util::lineBreak();
892 output << Util::indent(level: 2) << "None = 0,\n";
893 for (int i = 0; i < switchFields.size(); i++) {
894 const int nextField = i + 1;
895 if (!arrayLengthfields.contains(t: switchFields.at(i))) {
896 if (nextField >= switchFields.size()) {
897 if (switchFields.at(i)->switchField() == field->name()) {
898 output << Util::indent(level: 2) << switchFields.at(i)->name() << " = "
899 << switchFields.at(i)->switchValue() << Util::lineBreak();
900 output << Util::indent(level: 1) << "};"
901 << Util::lineBreak(n: 2);
902 }
903 } else {
904 if (field->name() == switchFields.at(i: nextField)->switchField()) {
905 output << Util::indent(level: 2) << switchFields.at(i)->name() << " = "
906 << switchFields.at(i)->switchValue() << ","
907 << Util::lineBreak();
908 } else {
909 output << Util::indent(level: 2) << switchFields.at(i)->name() << " = "
910 << switchFields.at(i)->switchValue() << Util::lineBreak();
911 output << Util::indent(level: 1) << "};"
912 << Util::lineBreak(n: 2);
913 }
914 }
915 }
916 }
917 }
918 }
919}
920
921void DataTypeFileWriter::writeStructuredTypeHeaderGetterSetter(const StructuredType *structuredType,
922 QTextStream &output)
923{
924 QList<Field *> unionMember;
925 QList<Field *> arrayLengthfields;
926 QList<Field *> switchFields;
927 for (const auto &possibleMember : structuredType->fields()) {
928 for (const auto &field : structuredType->fields()) {
929 if (possibleMember->name() == field->lengthField()
930 && !arrayLengthfields.contains(t: possibleMember))
931 arrayLengthfields.push_back(t: possibleMember);
932 if (field->isUnion() && field->switchField() == possibleMember->name()
933 && !unionMember.contains(t: possibleMember))
934 unionMember.push_back(t: possibleMember);
935 if (!possibleMember->switchField().isEmpty() && field->name() == possibleMember->switchField())
936 switchFields.push_back(t: field);
937 }
938 }
939 for (const auto &field : structuredType->fields()) {
940 if (!arrayLengthfields.contains(t: field) && !(field->isInStructuredTypeBitMask() && !switchFields.contains(t: field))) {
941 const auto typeName = field->typeNameSecondPart();
942 const auto tmpFunctionName = field->lowerFirstName();
943 if (!unionMember.contains(t: field)) {
944 if (StringIdentifier::typeNameDataTypeConverter.contains(key: field->typeName())) {
945 if (field->typeName().contains(s: StringIdentifier::booleanIdentifier)
946 || field->typeName().contains(s: StringIdentifier::integerIdentifier)
947 || field->typeName().contains(s: StringIdentifier::floatIdentifier)
948 || field->typeName().contains(s: StringIdentifier::doubleIdentifier)) {
949 if (!field->needContainer()) {
950 output << Util::indent(level: 1)
951 << StringIdentifier::typeNameDataTypeConverter.value(
952 key: field->typeName())
953 << " " << tmpFunctionName << "() const;"
954 << Util::lineBreak();
955 output << Util::indent(level: 1) << "void set" << field->name() << "("
956 << StringIdentifier::typeNameDataTypeConverter.value(
957 key: field->typeName())
958 << " " << tmpFunctionName << ");"
959 << Util::lineBreak(n: 2);
960 } else {
961 output << Util::indent(level: 1) << "QList<"
962 << StringIdentifier::typeNameDataTypeConverter.value(
963 key: field->typeName())
964 << "> " << tmpFunctionName << "() const;"
965 << Util::lineBreak();
966 output << Util::indent(level: 1) << "void set" << field->name() << "(QList<"
967 << StringIdentifier::typeNameDataTypeConverter.value(
968 key: field->typeName())
969 << "> " << tmpFunctionName << ");"
970 << Util::lineBreak(n: 2);
971 }
972 } else {
973 if (!field->needContainer()) {
974 output << Util::indent(level: 1)
975 << StringIdentifier::typeNameDataTypeConverter.value(
976 key: field->typeName())
977 << " " << tmpFunctionName << "() const;"
978 << Util::lineBreak();
979 output << Util::indent(level: 1) << "void set" << field->name() << "(const "
980 << StringIdentifier::typeNameDataTypeConverter.value(
981 key: field->typeName())
982 << " &" << tmpFunctionName << ");"
983 << Util::lineBreak(n: 2);
984 } else {
985 output << Util::indent(level: 1) << "QList<"
986 << StringIdentifier::typeNameDataTypeConverter.value(
987 key: field->typeName())
988 << "> " << tmpFunctionName << "() const;"
989 << Util::lineBreak();
990 output << Util::indent(level: 1) << "void set" << field->name() << "(const QList<"
991 << StringIdentifier::typeNameDataTypeConverter.value(
992 key: field->typeName())
993 << "> &" << tmpFunctionName << ");"
994 << Util::lineBreak(n: 2);
995 }
996 }
997 } else {
998 bool isPreCoded = false;
999 for (const auto &preCodedType : StringIdentifier::opcUaPrecodedTypes) {
1000 if (preCodedType.contains(name: typeName)) {
1001 isPreCoded = true;
1002 if (preCodedType.deEncoderName().isEmpty()) {
1003 output << Util::indent(level: 1);
1004 if (field->needContainer())
1005 output << "QList<";
1006 output << preCodedType.className();
1007 if (field->needContainer())
1008 output << ">";
1009 output << " " << tmpFunctionName << "() const;"
1010 << Util::lineBreak();
1011 output << Util::indent(level: 1) << "void set" << field->name() << "(const ";
1012 if (field->needContainer())
1013 output << "QList<";
1014 output << preCodedType.className();
1015 if (field->needContainer())
1016 output << ">";
1017 output << " &" << tmpFunctionName << ");"
1018 << Util::lineBreak(n: 2);
1019 } else {
1020 output << Util::indent(level: 1);
1021 if (field->needContainer())
1022 output << "QList<";
1023 output << preCodedType.deEncoderName();
1024 if (field->needContainer())
1025 output << ">";
1026 output << " " << tmpFunctionName << "() const;"
1027 << Util::lineBreak();
1028 output << Util::indent(level: 1) << "void set" << field->name() << "(const ";
1029 if (field->needContainer())
1030 output << "QList<";
1031 output << preCodedType.deEncoderName();
1032 if (field->needContainer())
1033 output << ">";
1034 output << " &" << tmpFunctionName << ");"
1035 << Util::lineBreak(n: 2);
1036 }
1037 break;
1038 }
1039 }
1040
1041 if (!isPreCoded) {
1042 if (field->needContainer()) {
1043 output << Util::indent(level: 1) << "QList <" << m_prefix << typeName << "> "
1044 << tmpFunctionName << "() const;"
1045 << Util::lineBreak();
1046 output << Util::indent(level: 1) << "void set" << field->name() << "(const QList <"
1047 << m_prefix << typeName << "> &" << tmpFunctionName
1048 << ");"
1049 << Util::lineBreak(n: 2);
1050 } else {
1051 bool isEnum = false;
1052 for (const auto &enumeratedType : m_enumeratedTypes) {
1053 if (enumeratedType->name() == field->typeName().split(sep: ":").at(i: 1))
1054 isEnum = true;
1055 }
1056 if (isEnum) {
1057 output << Util::indent(level: 1) << m_prefix << "::" << typeName << " "
1058 << tmpFunctionName << "() const;"
1059 << Util::lineBreak();
1060 output << Util::indent(level: 1) << "void set" << field->name() << "(const " << m_prefix
1061 << "::" << typeName << " &" << tmpFunctionName << ");"
1062 << Util::lineBreak(n: 2);
1063 } else {
1064 output << Util::indent(level: 1) << m_prefix << typeName << " "
1065 << tmpFunctionName << "() const;"
1066 << Util::lineBreak();
1067 output << Util::indent(level: 1) << "void set" << field->name() << "(const " << m_prefix
1068 << typeName << " &" << tmpFunctionName << ");"
1069 << Util::lineBreak(n: 2);
1070 }
1071 }
1072 }
1073 }
1074 } else { // is union switchfield, create just getter
1075 output << Util::indent(level: 1) << field->name() << " " << tmpFunctionName << "() const;"
1076 << Util::lineBreak();
1077 output << Util::lineBreak();
1078 }
1079 }
1080 }
1081}
1082
1083void DataTypeFileWriter::writeStructuredTypeHeaderDebug(const StructuredType *structuredType, QTextStream &output)
1084{
1085 output << Util::indent(level: 1) << "friend QDebug operator<<(QDebug debug, const " << m_prefix << structuredType->name() << " &v);";
1086 output << Util::lineBreak(n: 2);
1087}
1088
1089void DataTypeFileWriter::writeStructuredTypeCppDebug(const StructuredType *structuredType, QTextStream &output)
1090{
1091 const auto typeName = QStringLiteral("%1%2").arg(args&: m_prefix, args: structuredType->name());
1092
1093 output << "/*!" << Util::lineBreak();
1094 output << Util::indent(level: 1) << "Prints the field values of object \\a v to \\a debug" << Util::lineBreak();
1095 output << "*/" << Util::lineBreak();
1096 output << "QDebug operator<<(QDebug debug, const " << typeName << " &v)" << Util::lineBreak();
1097 output << "{" << Util::lineBreak();
1098 output << Util::indent(level: 1) << "QDebugStateSaver saver(debug);" << Util::lineBreak();
1099 output << Util::indent(level: 1) << "debug.nospace().noquote();" << Util::lineBreak(n: 2);
1100 output << Util::indent(level: 1) << "debug << \"" << typeName << " (\";" << Util::lineBreak(n: 2);
1101
1102 if (!structuredType->hasUnion() && structuredType->hasSwitchfield())
1103 output << Util::indent(level: 1) << "bool firstFieldPrinted = false;" << Util::lineBreak(n: 2);
1104
1105 bool isFirst = true;
1106
1107 QSet<Field *> lengthFields;
1108
1109 for (const auto &field : structuredType->fields()) {
1110 for (const auto &innerField : structuredType->fields()) {
1111 if (!field->lengthField().isEmpty() && field->lengthField() == innerField->name())
1112 lengthFields.insert(value: innerField);
1113 }
1114 }
1115
1116 for (const auto &field : structuredType->fields()) {
1117 if (structuredType->hasUnion() && field == structuredType->fields().constFirst())
1118 continue;
1119
1120 if (field->isInStructuredTypeBitMask())
1121 continue;
1122
1123 if (lengthFields.contains(value: field))
1124 continue;
1125
1126 if (structuredType->hasUnion())
1127 output << Util::indent(level: 1) << "if (static_cast<quint32>(v." << Util::lowerFirstLetter(temp: field->switchField()) << "()) == " << field->switchValue() << ") {" << Util::lineBreak();
1128 else if (!field->switchField().isEmpty())
1129 output << Util::indent(level: 1) << "if (v." << Util::lowerFirstLetter(temp: field->switchField()) << "()) {" << Util::lineBreak();
1130
1131 int indentOffset = 0;
1132 if (structuredType->hasUnion() || !field->switchField().isEmpty())
1133 indentOffset = 1;
1134
1135 if (!structuredType->hasUnion() && !isFirst) {
1136 if (structuredType->hasSwitchfield())
1137 output << Util::indent(level: 1 + indentOffset) << "if (firstFieldPrinted)" << Util::lineBreak();
1138 output << Util::indent(level: 1 + (structuredType->hasSwitchfield() ? indentOffset + 1 : 0)) << "debug << \", \";" << Util::lineBreak();
1139 }
1140
1141 output << Util::indent(level: 1 + indentOffset) << "debug << \"" << field->name() << ": \";" << Util::lineBreak();
1142
1143 // Not all types have an operator<< for QDebug...
1144 const auto isPrecoded = std::find_if(first: StringIdentifier::opcUaPrecodedTypes.constBegin(), last: StringIdentifier::opcUaPrecodedTypes.constEnd(),
1145 pred: [&](const auto &entry) { return entry.name() == field->typeNameSecondPart(); });
1146
1147 if (isPrecoded == StringIdentifier::opcUaPrecodedTypes.constEnd() || StringIdentifier::precodedTypesWithDebugOperator.contains(value: field->typeNameSecondPart())) {
1148 output << Util::indent(level: 1 + indentOffset) << "debug << v." << field->lowerFirstName() << "();" << Util::lineBreak();
1149 } else {
1150 if (field->needContainer()) {
1151 const auto tempListName = QStringLiteral("%1%2").arg(args: field->lowerFirstName(), args: "Strings");
1152 output << Util::indent(level: 1 + indentOffset) << "QStringList " << tempListName << ";" << Util::lineBreak();
1153 output << Util::indent(level: 1 + indentOffset) << "for (int i = 0; i < v." << field->lowerFirstName() << "().size(); ++i)" << Util::lineBreak();
1154 output << Util::indent(level: 2 + indentOffset) << tempListName << ".push_back(\"" << isPrecoded->className() << "(...)\"" << ");" << Util::lineBreak();
1155 output << Util::indent(level: 1 + indentOffset) << "debug << \"QList(\" << " << tempListName << ".join(\", \") << \")\";";
1156 } else {
1157 output << Util::indent(level: 1 + indentOffset) << "debug << \"" << isPrecoded->className() << "(...)\";";
1158 }
1159 output << Util::lineBreak();
1160 }
1161
1162 if (!structuredType->hasUnion() && structuredType->hasSwitchfield() && field != structuredType->fields().constLast())
1163 output << Util::indent(level: 1 + indentOffset) << "firstFieldPrinted = true;" << Util::lineBreak();
1164
1165 if (structuredType->hasUnion() || !field->switchField().isEmpty())
1166 output << Util::indent(level: 1) << "}" << Util::lineBreak();
1167
1168 output << Util::lineBreak();
1169
1170 isFirst = false;
1171 }
1172
1173 output << Util::indent(level: 1) << "debug << \")\";" << Util::lineBreak();
1174 output << Util::indent(level: 1) << "return debug;" << Util::lineBreak();
1175 output << "}" << Util::lineBreak();
1176}
1177
1178DataTypeFileWriter::GeneratingError DataTypeFileWriter::writeEnumeratedTypes()
1179{
1180 QFile file;
1181 const auto fileName = QStringLiteral("%1enumerations.h").arg(a: m_prefix.toLower());
1182 QDir dir(m_path);
1183 if (!dir.exists(name: m_path))
1184 if (!dir.mkpath(dirPath: m_path))
1185 return UnableToWrite;
1186 file.setFileName(dir.absoluteFilePath(fileName));
1187 file.open(flags: QIODevice::WriteOnly | QIODevice::Text);
1188 QTextStream output(&file);
1189 writeLicenseHeader(output);
1190
1191 if (!m_generatedEnumeratedTypeFilenames.contains(
1192 QStringLiteral("%1enumerations").arg(a: m_prefix.toLower())))
1193 m_generatedEnumeratedTypeFilenames.push_back(
1194 QStringLiteral("%1enumerations").arg(a: m_prefix.toLower()));
1195 output << "#pragma once"
1196 << Util::lineBreak();
1197 output << "#include <QMetaType>"
1198 << Util::lineBreak(n: 2);
1199 output << "namespace " << m_prefix << " {"
1200 << Util::lineBreak();
1201 output << "Q_NAMESPACE"
1202 << Util::lineBreak(n: 2);
1203 for (const auto &enumeratedType : m_enumeratedTypes) {
1204 output << "enum class " << enumeratedType->name() << " {" << Util::lineBreak(n: 1);
1205 for (const auto &enumeratedValue : enumeratedType->values()) {
1206 output << Util::indent(level: 1) << enumeratedValue->name() << " = " << enumeratedValue->value();
1207 if (!enumeratedType->values().endsWith(t: enumeratedValue))
1208 output << ",";
1209 output << Util::lineBreak();
1210 }
1211 output << "};"
1212 << Util::lineBreak();
1213 output << "Q_ENUM_NS(" << enumeratedType->name() << ")"
1214 << Util::lineBreak(n: 2);
1215 }
1216
1217 output << Util::lineBreak();
1218 output << "}"
1219 << Util::lineBreak();
1220 return GeneratingError::NoError;
1221}
1222
1223DataTypeFileWriter::GeneratingError DataTypeFileWriter::generateFile(const XmlElement *type,
1224 const QString &fileExtension)
1225{
1226 QFile file;
1227 const auto fileName = QStringLiteral("%1%2%3").arg(args: m_prefix.toLower(),
1228 args: type->name().toLower(),
1229 args: fileExtension);
1230 QDir dir(m_path);
1231 if (!dir.exists(name: m_path))
1232 if (!dir.mkpath(dirPath: m_path))
1233 return UnableToWrite;
1234 file.setFileName(dir.absoluteFilePath(fileName));
1235 file.open(flags: QIODevice::WriteOnly | QIODevice::Text);
1236 QTextStream output(&file);
1237 writeLicenseHeader(output);
1238
1239 auto structuredType = dynamic_cast<const StructuredType *>(type);
1240 if (structuredType) {
1241 if (fileExtension == StringIdentifier::headerIdentifier) {
1242 writeStructuredTypeHeader(structuredType, output);
1243 } else {
1244 if (fileExtension == StringIdentifier::cppIdentifier) {
1245 writeStructuredTypeCpp(structuredType, output);
1246 }
1247 }
1248 }
1249 file.close();
1250 return NoError;
1251}
1252
1253DataTypeFileWriter::GeneratingError DataTypeFileWriter::generateTypes(
1254 const QList<XmlElement *> &types)
1255{
1256 m_generateMapping.append(l: types);
1257 for (const auto &type : m_generateMapping) {
1258 const auto enumeratedType = dynamic_cast<EnumeratedType *>(type);
1259 if (enumeratedType)
1260 if (!m_enumeratedTypes.contains(t: enumeratedType))
1261 m_enumeratedTypes.append(t: enumeratedType);
1262 }
1263 if (writeEnumeratedTypes() != GeneratingError::NoError) {
1264 return GeneratingError::UnableToWrite;
1265 }
1266
1267 for (const auto &type : m_generateMapping) {
1268 const auto structuredType = dynamic_cast<StructuredType *>(type);
1269 if (structuredType) {
1270 if (generateFile(type, fileExtension: StringIdentifier::headerIdentifier) != GeneratingError::NoError)
1271 return GeneratingError::UnableToWrite;
1272 if (generateFile(type, fileExtension: StringIdentifier::cppIdentifier) != GeneratingError::NoError)
1273 return GeneratingError::UnableToWrite;
1274 }
1275 }
1276 return NoError;
1277}
1278
1279QList<XmlElement *> DataTypeFileWriter::generateMapping() const
1280{
1281 return m_generateMapping;
1282}
1283
1284void DataTypeFileWriter::setGenerateMapping(const QList<XmlElement *> &generateMapping)
1285{
1286 m_generateMapping = generateMapping;
1287}
1288

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtopcua/tools/datatypecodegenerator/datatypefilewriter.cpp