Skip to content

Commit 9e9c9c8

Browse files
committed
LP-599 Allow "cloneof" attribute to reference other objects. Allow some other attributes to override cloned values (options, limits, defaultvalue).
1 parent a4c0bcf commit 9e9c9c8

2 files changed

Lines changed: 100 additions & 31 deletions

File tree

ground/uavobjgenerator/uavobjectparser.cpp

Lines changed: 97 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ ObjectInfo *UAVObjectParser::getObjectByIndex(int objIndex)
6969
return objInfo[objIndex];
7070
}
7171

72+
ObjectInfo *UAVObjectParser::getObjectByName(const QString & objName)
73+
{
74+
foreach(ObjectInfo * info, objInfo) {
75+
if (objName == info->name) {
76+
return info;
77+
}
78+
}
79+
return 0;
80+
}
7281
/**
7382
* Get the name of the object
7483
*/
@@ -404,6 +413,7 @@ QString UAVObjectParser::processObjectAccess(QDomNode & childNode, ObjectInfo *i
404413
*/
405414
QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *info)
406415
{
416+
bool isClone = false;
407417
// Create field
408418
FieldInfo *field = new FieldInfo;
409419
// Get name attribute
@@ -419,20 +429,39 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
419429
// field that has already been declared
420430
elemAttr = elemAttributes.namedItem("cloneof");
421431
if (!elemAttr.isNull()) {
422-
QString parentName = elemAttr.nodeValue();
432+
QString parentName = elemAttr.nodeValue().section('.', 1);
433+
434+
ObjectInfo *parentObject;
435+
436+
if (parentName.isEmpty()) {
437+
parentName = elemAttr.nodeValue();
438+
parentObject = info;
439+
} else {
440+
QString objName = elemAttr.nodeValue().section('.', 0, 0);
441+
parentObject = getObjectByName(objName);
442+
if (!parentObject) {
443+
return QString("Object:field:cloneof parent object unknown");
444+
}
445+
}
446+
423447
if (!parentName.isEmpty()) {
424-
foreach(FieldInfo * parent, info->fields) {
448+
foreach(FieldInfo * parent, parentObject->fields) {
425449
if (parent->name == parentName) {
426450
// clone from this parent
427451
*field = *parent; // safe shallow copy, no ptrs in struct
428452
field->name = name; // set our name
429-
// Add field to object
430-
info->fields.append(field);
431-
// Done
432-
return QString();
453+
// Done, but allow certain overrides
454+
field->parentObjectName = parentObject->name;
455+
field->parentFieldName = parent->name;
456+
isClone = true;
457+
458+
break;
433459
}
434460
}
435-
return QString("Object:field::cloneof parent unknown");
461+
462+
if (!isClone) {
463+
return QString("Object:field:cloneof parent unknown");
464+
}
436465
} else {
437466
return QString("Object:field:cloneof attribute is empty");
438467
}
@@ -459,31 +488,45 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
459488
// Get units attribute
460489
elemAttr = elemAttributes.namedItem("units");
461490
if (elemAttr.isNull()) {
462-
return QString("Object:field:units attribute is missing");
491+
if (!isClone) {
492+
return QString("Object:field:units attribute is missing");
493+
}
494+
} else {
495+
if (isClone) {
496+
return QString("Object:field:units attribute is not allowed for cloned fields");
497+
}
498+
field->units = elemAttr.nodeValue();
499+
all_units << field->units;
463500
}
464-
465-
field->units = elemAttr.nodeValue();
466-
all_units << field->units;
467-
468501
// Get type attribute
469502
elemAttr = elemAttributes.namedItem("type");
470503
if (elemAttr.isNull()) {
471-
return QString("Object:field:type attribute is missing");
472-
}
473-
474-
int index = fieldTypeStrXML.indexOf(elemAttr.nodeValue());
475-
if (index >= 0) {
476-
field->type = (FieldType)index;
477-
field->numBytes = fieldTypeNumBytes[index];
504+
if (!isClone) {
505+
return QString("Object:field:type attribute is missing");
506+
}
478507
} else {
479-
return QString("Object:field:type attribute value is invalid");
508+
if (isClone) {
509+
return QString("Object:field:type attribute is not allowed for cloned fields");
510+
}
511+
int index = fieldTypeStrXML.indexOf(elemAttr.nodeValue());
512+
if (index >= 0) {
513+
field->type = (FieldType)index;
514+
field->numBytes = fieldTypeNumBytes[index];
515+
} else {
516+
return QString("Object:field:type attribute value is invalid");
517+
}
480518
}
481519

482520
// Get numelements or elementnames attribute
483-
field->numElements = 0;
521+
if (!isClone) {
522+
field->numElements = 0;
523+
}
484524
// Look for element names as an attribute first
485525
elemAttr = elemAttributes.namedItem("elementnames");
486526
if (!elemAttr.isNull()) {
527+
if (isClone) {
528+
return QString("Object:field:elementnames attribute is not allowed for cloned fields");
529+
}
487530
// Get element names
488531
QStringList names = elemAttr.nodeValue().split(",", QString::SkipEmptyParts);
489532
for (int n = 0; n < names.length(); ++n) {
@@ -497,6 +540,9 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
497540
// Look for a list of child elementname nodes
498541
QDomNode listNode = childNode.firstChildElement("elementnames");
499542
if (!listNode.isNull()) {
543+
if (isClone) {
544+
return QString("Object:field:elementnames element is not allowed for cloned fields");
545+
}
500546
for (QDomElement node = listNode.firstChildElement("elementname");
501547
!node.isNull(); node = node.nextSiblingElement("elementname")) {
502548
QDomNode name = node.firstChild();
@@ -515,6 +561,9 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
515561
if (elemAttr.isNull()) {
516562
return QString("Object:field:elements and Object:field:elementnames attribute/element is missing");
517563
} else {
564+
if (isClone) {
565+
return QString("Object:field:elements attribute is not allowed for cloned fields");
566+
}
518567
field->numElements = elemAttr.nodeValue().toInt();
519568
for (int n = 0; n < field->numElements; ++n) {
520569
field->elementNames.append(QString("%1").arg(n));
@@ -524,15 +573,18 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
524573
}
525574
}
526575
// Get options attribute or child elements (only if an enum type)
576+
// We allow "options" attribute/element for cloned fields also, but they work slightly different here -
577+
// they set limits on parent options.
578+
527579
if (field->type == FIELDTYPE_ENUM) {
528580
// Look for options attribute
581+
QStringList options;
529582
elemAttr = elemAttributes.namedItem("options");
530583
if (!elemAttr.isNull()) {
531-
QStringList options = elemAttr.nodeValue().split(",", QString::SkipEmptyParts);
584+
options = elemAttr.nodeValue().split(",", QString::SkipEmptyParts);
532585
for (int n = 0; n < options.length(); ++n) {
533586
options[n] = options[n].trimmed();
534587
}
535-
field->options = options;
536588
} else {
537589
// Look for a list of child 'option' nodes
538590
QDomNode listNode = childNode.firstChildElement("options");
@@ -541,25 +593,36 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
541593
!node.isNull(); node = node.nextSiblingElement("option")) {
542594
QDomNode name = node.firstChild();
543595
if (!name.isNull() && name.isText() && !name.nodeValue().isEmpty()) {
544-
field->options.append(name.nodeValue());
596+
options.append(name.nodeValue());
545597
}
546598
}
547599
}
548600
}
549-
field->numOptions = field->options.size();
601+
602+
if (isClone) {
603+
if (!options.isEmpty()) {
604+
// Verify options subset and build limits value from it.
605+
foreach(const QString &option, options) {
606+
if (!field->options.contains(option)) {
607+
return QString("Object:field:options is not a subset of parent options");
608+
}
609+
}
610+
field->limitValues = QString("%EQ:") + options.join(':');
611+
qDebug() << "Created field->limitValues: " << field->limitValues;
612+
}
613+
} else {
614+
field->numOptions = options.size();
615+
field->options = options;
616+
}
617+
550618
if (field->numOptions == 0) {
551619
return QString("Object:field:options attribute/element is missing");
552620
}
553621
}
554622

555623
// Get the default value attribute (required for settings objects, optional for the rest)
556624
elemAttr = elemAttributes.namedItem("defaultvalue");
557-
if (elemAttr.isNull()) {
558-
if (info->isSettings) {
559-
return QString("Object:field:defaultvalue attribute is missing (required for settings objects)");
560-
}
561-
field->defaultValues = QStringList();
562-
} else {
625+
if (!elemAttr.isNull()) {
563626
QStringList defaults = elemAttr.nodeValue().split(",", QString::SkipEmptyParts);
564627
for (int n = 0; n < defaults.length(); ++n) {
565628
defaults[n] = defaults[n].trimmed();
@@ -578,6 +641,9 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
578641
}
579642
field->defaultValues = defaults;
580643
}
644+
if (field->defaultValues.isEmpty() && info->isSettings) {
645+
return QString("Object:field:defaultvalue attribute is missing (required for settings objects)");
646+
}
581647

582648
// Limits attribute
583649
elemAttr = elemAttributes.namedItem("limits");

ground/uavobjgenerator/uavobjectparser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ typedef struct {
5959
bool defaultElementNames;
6060
QStringList defaultValues;
6161
QString limitValues;
62+
QString parentObjectName;
63+
QString parentFieldName;
6264
} FieldInfo;
6365

6466
/**
@@ -113,6 +115,7 @@ class UAVObjectParser {
113115
quint32 getObjectID(int objIndex);
114116

115117
ObjectInfo *getObjectByIndex(int objIndex);
118+
ObjectInfo *getObjectByName(const QString & objName);
116119
int getNumBytes(int objIndex);
117120
QStringList all_units;
118121

0 commit comments

Comments
 (0)