@@ -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 */
405414QString 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" );
0 commit comments