Search in sources :

Example 26 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class FormInstanceParser method trimRepeatChildren.

/**
 * Trims repeatable children of newly created template nodes; we trim because the templates are supposed to be devoid of 'data',
 * and # of repeats for a given repeat node is a kind of data.
 */
private static void trimRepeatChildren(TreeElement node) {
    for (int i = 0; i < node.getNumChildren(); i++) {
        TreeElement child = node.getChildAt(i);
        if (child.isRepeatable()) {
            node.removeChildAt(i);
            i--;
        } else {
            trimRepeatChildren(child);
        }
    }
}
Also used : Constraint(org.javarosa.core.model.condition.Constraint) TreeElement(org.javarosa.core.model.instance.TreeElement)

Example 27 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class FormInstanceParser method verifyItemsetSrcDstCompatibility.

private void verifyItemsetSrcDstCompatibility(FormInstance instance) {
    for (ItemsetBinding itemset : itemsets) {
        boolean destRepeatable = (instance.getTemplate(itemset.getDestRef()) != null);
        if (itemset.copyMode) {
            if (!destRepeatable) {
                throw new XFormParseException("itemset copies to node(s) which are not repeatable");
            }
            // validate homogeneity between src and dst nodes
            TreeElement srcNode = instance.getTemplatePath(itemset.copyRef);
            TreeElement dstNode = instance.getTemplate(itemset.getDestRef());
            if (!FormInstance.isHomogeneous(srcNode, dstNode)) {
                reporter.warning(XFormParserReporter.TYPE_INVALID_STRUCTURE, "Your itemset source [" + srcNode.getRef().toString() + "] and dest [" + dstNode.getRef().toString() + "] of appear to be incompatible!", null);
            }
        // TODO: i feel like, in theory, i should additionally check that the repeatable children of src and dst
        // match up (Achild is repeatable <--> Bchild is repeatable). isHomogeneous doesn't check this. but i'm
        // hard-pressed to think of scenarios where this would actually cause problems
        } else {
            if (destRepeatable) {
                throw new XFormParseException("itemset sets value on repeatable nodes");
            }
        }
    }
}
Also used : ItemsetBinding(org.javarosa.core.model.ItemsetBinding) TreeElement(org.javarosa.core.model.instance.TreeElement)

Example 28 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class FormInstanceParser method verifyRepeatMemberBindings.

private void verifyRepeatMemberBindings(IFormElement fe, FormInstance instance, GroupDef parentRepeat) {
    if (fe.getChildren() == null)
        return;
    for (int i = 0; i < fe.getChildren().size(); i++) {
        IFormElement child = fe.getChildren().get(i);
        boolean isRepeat = (child instanceof GroupDef && ((GroupDef) child).getRepeat());
        // get bindings of current node and nearest enclosing repeat
        TreeReference repeatBind = (parentRepeat == null ? TreeReference.rootRef() : FormInstance.unpackReference(parentRepeat.getBind()));
        TreeReference childBind = FormInstance.unpackReference(child.getBind());
        // check if current binding is within scope of repeat binding
        if (!repeatBind.isParentOf(childBind, false)) {
            // catch <repeat nodeset="/a/b"><input ref="/a/c" /></repeat>: repeat question is not a child of the repeated node
            throw new XFormParseException("<repeat> member's binding [" + childBind.toString() + "] is not a descendant of <repeat> binding [" + repeatBind.toString() + "]!");
        } else if (repeatBind.equals(childBind) && isRepeat) {
            // catch <repeat nodeset="/a/b"><repeat nodeset="/a/b">...</repeat></repeat> (<repeat nodeset="/a/b"><input ref="/a/b" /></repeat> is ok)
            throw new XFormParseException("child <repeat>s [" + childBind.toString() + "] cannot bind to the same node as their parent <repeat>; only questions/groups can");
        }
        // check that, in the instance, current node is not within the scope of any closer repeat binding
        // build a list of all the node's instance ancestors
        List<TreeElement> repeatAncestry = new ArrayList<>();
        TreeElement repeatNode = (repeatTree == null ? null : repeatTree.getRoot());
        if (repeatNode != null) {
            repeatAncestry.add(repeatNode);
            for (int j = 1; j < childBind.size(); j++) {
                repeatNode = repeatNode.getChild(childBind.getName(j), 0);
                if (repeatNode != null) {
                    repeatAncestry.add(repeatNode);
                } else {
                    break;
                }
            }
        }
        // check that no nodes between the parent repeat and the target are repeatable
        for (int k = repeatBind.size(); k < childBind.size(); k++) {
            TreeElement rChild = (k < repeatAncestry.size() ? repeatAncestry.get(k) : null);
            boolean repeatable = rChild != null && rChild.isRepeatable();
            if (repeatable && !(k == childBind.size() - 1 && isRepeat)) {
                // question's/group's/repeat's most immediate repeat parent in the instance is not its most immediate repeat parent in the form def
                throw new XFormParseException("<repeat> member's binding [" + childBind.toString() + "] is within the scope of a <repeat> that is not its closest containing <repeat>!");
            }
        }
        verifyRepeatMemberBindings(child, instance, (isRepeat ? (GroupDef) child : parentRepeat));
    }
}
Also used : IFormElement(org.javarosa.core.model.IFormElement) TreeReference(org.javarosa.core.model.instance.TreeReference) ArrayList(java.util.ArrayList) Constraint(org.javarosa.core.model.condition.Constraint) GroupDef(org.javarosa.core.model.GroupDef) TreeElement(org.javarosa.core.model.instance.TreeElement)

Example 29 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class FormInstanceParser method buildRepeatTree.

/**
 * Builds a pseudo-data model tree that describes the repeat structure of the instance. The
 * result is a FormInstance collapsed where all indexes are 0, and repeatable nodes are flagged as such.
 * Ignores (invalid) repeats that bind outside the top-level instance data node. Returns null if no repeats.
 */
private static FormInstance buildRepeatTree(List<TreeReference> repeatRefs, String topLevelName) {
    TreeElement root = new TreeElement(null, 0);
    for (TreeReference repeatRef : repeatRefs) {
        // check and see if this references a repeat from a non-main instance, if so, skip it
        if (repeatRef.getInstanceName() != null) {
            continue;
        }
        if (repeatRef.size() <= 1) {
            // invalid repeat: binds too high. ignore for now and error will be raised in verifyBindings
            continue;
        }
        TreeElement cur = root;
        for (int j = 0; j < repeatRef.size(); j++) {
            String name = repeatRef.getName(j);
            TreeElement child = cur.getChild(name, 0);
            if (child == null) {
                child = new TreeElement(name, 0);
                cur.addChild(child);
            }
            cur = child;
        }
        cur.setRepeatable(true);
    }
    return (root.getNumChildren() == 0) ? null : new FormInstance(root.getChild(topLevelName, TreeReference.DEFAULT_MULTIPLICITY));
}
Also used : TreeReference(org.javarosa.core.model.instance.TreeReference) FormInstance(org.javarosa.core.model.instance.FormInstance) Constraint(org.javarosa.core.model.condition.Constraint) TreeElement(org.javarosa.core.model.instance.TreeElement)

Example 30 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class FormEntryModel method isIndexRelevant.

/**
 * Determine if the current FormIndex is relevant. Only relevant indexes
 * should be returned when filling out a form.
 *
 * @param index
 * @return true if current element at FormIndex is relevant
 */
public boolean isIndexRelevant(FormIndex index) {
    TreeReference ref = form.getChildInstanceRef(index);
    boolean isAskNewRepeat = (getEvent(index) == FormEntryController.EVENT_PROMPT_NEW_REPEAT);
    boolean isRepeatJuncture = (getEvent(index) == FormEntryController.EVENT_REPEAT_JUNCTURE);
    boolean relevant;
    if (isAskNewRepeat) {
        relevant = form.isRepeatRelevant(ref) && form.canCreateRepeat(ref, index);
    // repeat junctures are still relevant if no new repeat can be created; that option
    // is simply missing from the menu
    } else if (isRepeatJuncture) {
        relevant = form.isRepeatRelevant(ref);
    } else {
        TreeElement node = form.getMainInstance().resolveReference(ref);
        // check instance flag first
        relevant = node != null && node.isRelevant();
    }
    if (relevant) {
        // if instance flag/condition says relevant, we still
        // have to check the <group>/<repeat> hierarchy
        FormIndex ancestorIndex = index;
        while (!ancestorIndex.isTerminal()) {
            // This should be safe now that the TreeReference is contained
            // in the ancestor index itself
            TreeElement ancestorNode = form.getMainInstance().resolveReference(ancestorIndex.getLocalReference());
            if (!ancestorNode.isRelevant()) {
                relevant = false;
                break;
            }
            ancestorIndex = ancestorIndex.getNextLevel();
        }
    }
    return relevant;
}
Also used : TreeReference(org.javarosa.core.model.instance.TreeReference) FormIndex(org.javarosa.core.model.FormIndex) TreeElement(org.javarosa.core.model.instance.TreeElement)

Aggregations

TreeElement (org.javarosa.core.model.instance.TreeElement)86 AbstractTreeElement (org.javarosa.core.model.instance.AbstractTreeElement)33 TreeReference (org.javarosa.core.model.instance.TreeReference)28 FormInstance (org.javarosa.core.model.instance.FormInstance)16 ArrayList (java.util.ArrayList)15 Constraint (org.javarosa.core.model.condition.Constraint)11 Test (org.junit.Test)10 Element (org.kxml2.kdom.Element)9 EvaluationContext (org.javarosa.core.model.condition.EvaluationContext)8 FormDef (org.javarosa.core.model.FormDef)7 InstanceInitializationFactory (org.javarosa.core.model.instance.InstanceInitializationFactory)7 IOException (java.io.IOException)6 IFormElement (org.javarosa.core.model.IFormElement)6 StringData (org.javarosa.core.model.data.StringData)6 HashMap (java.util.HashMap)5 IAnswerData (org.javarosa.core.model.data.IAnswerData)4 File (java.io.File)3 GroupDef (org.javarosa.core.model.GroupDef)3 IDataReference (org.javarosa.core.model.IDataReference)3 QuestionDef (org.javarosa.core.model.QuestionDef)3