Search in sources :

Example 16 with IFormElement

use of org.javarosa.core.model.IFormElement in project collect by opendatakit.

the class FormController method getIndicesForGroup.

private List<FormIndex> getIndicesForGroup(GroupDef gd, FormIndex currentChildIndex) {
    List<FormIndex> indices = new ArrayList<>();
    for (int i = 0; i < gd.getChildren().size(); i++) {
        final FormEntryModel formEntryModel = formEntryController.getModel();
        if (getEvent(currentChildIndex) == FormEntryController.EVENT_GROUP) {
            IFormElement nestedElement = formEntryModel.getForm().getChild(currentChildIndex);
            if (nestedElement instanceof GroupDef) {
                indices.addAll(getIndicesForGroup((GroupDef) nestedElement, formEntryModel.incrementIndex(currentChildIndex, true)));
                currentChildIndex = formEntryModel.incrementIndex(currentChildIndex, false);
            }
        } else {
            indices.add(currentChildIndex);
            currentChildIndex = formEntryModel.incrementIndex(currentChildIndex, false);
        }
    }
    return indices;
}
Also used : IFormElement(org.javarosa.core.model.IFormElement) FormEntryModel(org.javarosa.form.api.FormEntryModel) ArrayList(java.util.ArrayList) FormIndex(org.javarosa.core.model.FormIndex) GroupDef(org.javarosa.core.model.GroupDef)

Example 17 with IFormElement

use of org.javarosa.core.model.IFormElement in project javarosa by opendatakit.

the class XFormParser method parseItemset.

private void parseItemset(QuestionDef q, Element e, IFormElement qparent) {
    ItemsetBinding itemset = new ItemsetBinding();
    // //////////////USED FOR PARSER WARNING OUTPUT ONLY
    // catalogue of used attributes in this method/element
    List<String> usedAtts = new ArrayList<>();
    // for child with name 'label'
    List<String> labelUA = new ArrayList<>();
    // for child with name 'value'
    List<String> valueUA = new ArrayList<>();
    // for child with name 'copy'
    List<String> copyUA = new ArrayList<>();
    usedAtts.add(NODESET_ATTR);
    labelUA.add(REF_ATTR);
    valueUA.add(REF_ATTR);
    valueUA.add(FORM_ATTR);
    copyUA.add(REF_ATTR);
    // //////////////////////////////////////////////////
    /*
         * At this point in time, we cannot construct a valid nodesetRef
         *
         * Leave all ...Ref entries as null and test the ...Expr entries for null / non-null values.
         *
         * We will patch this all up in the verifyItemsetBindings() method.
         */
    String nodesetStr = e.getAttributeValue("", NODESET_ATTR);
    if (nodesetStr == null)
        throw new RuntimeException("No nodeset attribute in element: [" + e.getName() + "]. This is required. (Element Printout:" + XFormSerializer.elementToString(e) + ")");
    XPathPathExpr path = XPathReference.getPathExpr(nodesetStr);
    itemset.nodesetExpr = new XPathConditional(path);
    itemset.contextRef = getFormElementRef(qparent);
    // this is not valid yet...
    itemset.nodesetRef = null;
    // itemset.nodesetRef = FormInstance.unpackReference(getAbsRef(new XPathReference(path.getReference(true)), itemset.contextRef));
    itemset.copyMode = false;
    for (int i = 0; i < e.getChildCount(); i++) {
        int type = e.getType(i);
        Element child = (type == Node.ELEMENT ? e.getElement(i) : null);
        String childName = (child != null ? child.getName() : null);
        if (LABEL_ELEMENT.equals(childName)) {
            String labelXpath = child.getAttributeValue("", REF_ATTR);
            boolean labelItext = false;
            // print unused attribute warning message for child element
            if (XFormUtils.showUnusedAttributeWarning(child, labelUA)) {
                reporter.warning(XFormParserReporter.TYPE_UNKNOWN_MARKUP, XFormUtils.unusedAttWarning(child, labelUA), getVagueLocation(child));
            }
            if (labelXpath != null) {
                if (labelXpath.startsWith(DYNAMIC_ITEXT_OPEN) && labelXpath.endsWith(DYNAMIC_ITEXT_CLOSE)) {
                    labelXpath = labelXpath.substring(DYNAMIC_ITEXT_OPEN.length(), labelXpath.lastIndexOf(DYNAMIC_ITEXT_CLOSE));
                    labelItext = true;
                }
            } else {
                throw new XFormParseException("<label> in <itemset> requires 'ref'");
            }
            XPathPathExpr labelPath = XPathReference.getPathExpr(labelXpath);
            itemset.labelRef = null;
            // itemset.labelRef = FormInstance.unpackReference(getAbsRef(new XPathReference(labelPath), itemset.nodesetRef));
            itemset.labelExpr = new XPathConditional(labelPath);
            itemset.labelIsItext = labelItext;
        } else if ("copy".equals(childName)) {
            String copyXpath = child.getAttributeValue("", REF_ATTR);
            // print unused attribute warning message for child element
            if (XFormUtils.showUnusedAttributeWarning(child, copyUA)) {
                reporter.warning(XFormParserReporter.TYPE_UNKNOWN_MARKUP, XFormUtils.unusedAttWarning(child, copyUA), getVagueLocation(child));
            }
            if (copyXpath == null) {
                throw new XFormParseException("<copy> in <itemset> requires 'ref'");
            }
            XPathPathExpr copyPath = XPathReference.getPathExpr(copyXpath);
            itemset.copyRef = null;
            // itemset.copyRef = FormInstance.unpackReference(getAbsRef(new XPathReference(copyPath), itemset.nodesetRef));
            itemset.copyExpr = new XPathConditional(copyPath);
            itemset.copyMode = true;
        } else if (VALUE.equals(childName)) {
            String valueXpath = child.getAttributeValue("", REF_ATTR);
            // print unused attribute warning message for child element
            if (XFormUtils.showUnusedAttributeWarning(child, valueUA)) {
                reporter.warning(XFormParserReporter.TYPE_UNKNOWN_MARKUP, XFormUtils.unusedAttWarning(child, valueUA), getVagueLocation(child));
            }
            if (valueXpath == null) {
                throw new XFormParseException("<value> in <itemset> requires 'ref'");
            }
            XPathPathExpr valuePath = XPathReference.getPathExpr(valueXpath);
            itemset.valueRef = null;
            // itemset.valueRef = FormInstance.unpackReference(getAbsRef(new XPathReference(valuePath), itemset.nodesetRef));
            itemset.valueExpr = new XPathConditional(valuePath);
        }
    }
    if (itemset.labelExpr == null) {
        throw new XFormParseException("<itemset> requires <label>");
    } else if (itemset.copyExpr == null && itemset.valueExpr == null) {
        throw new XFormParseException("<itemset> requires <copy> or <value>");
    }
    if (itemset.copyExpr != null) {
        if (itemset.valueExpr == null) {
            reporter.warning(XFormParserReporter.TYPE_TECHNICAL, "<itemset>s with <copy> are STRONGLY recommended to have <value> as well; pre-selecting, default answers, and display of answers will not work properly otherwise", getVagueLocation(e));
        }
    }
    itemsets.add(itemset);
    q.setDynamicChoices(itemset);
    // print unused attribute warning message for parent element
    if (XFormUtils.showUnusedAttributeWarning(e, usedAtts)) {
        reporter.warning(XFormParserReporter.TYPE_UNKNOWN_MARKUP, XFormUtils.unusedAttWarning(e, usedAtts), getVagueLocation(e));
    }
}
Also used : XPathPathExpr(org.javarosa.xpath.expr.XPathPathExpr) TreeElement(org.javarosa.core.model.instance.TreeElement) AbstractTreeElement(org.javarosa.core.model.instance.AbstractTreeElement) Element(org.kxml2.kdom.Element) IFormElement(org.javarosa.core.model.IFormElement) ArrayList(java.util.ArrayList) ItemsetBinding(org.javarosa.core.model.ItemsetBinding) XPathConditional(org.javarosa.xpath.XPathConditional)

Example 18 with IFormElement

use of org.javarosa.core.model.IFormElement in project javarosa by opendatakit.

the class XFormParser method collapseRepeatGroups.

/**
 * Collapses groups whose only child is a repeat into a single repeat that uses the label of the wrapping group
 */
private static void collapseRepeatGroups(IFormElement fe) {
    if (fe.getChildren() == null)
        return;
    for (int i = 0; i < fe.getChildren().size(); i++) {
        IFormElement child = fe.getChild(i);
        GroupDef group = null;
        if (child instanceof GroupDef)
            group = (GroupDef) child;
        if (group != null) {
            if (!group.getRepeat() && group.getChildren().size() == 1) {
                IFormElement grandchild = group.getChildren().get(0);
                GroupDef repeat = null;
                if (grandchild instanceof GroupDef)
                    repeat = (GroupDef) grandchild;
                if (repeat != null && repeat.getRepeat()) {
                    // collapse the wrapping group
                    // merge group into repeat
                    // id - later
                    // name - later
                    repeat.setLabelInnerText(group.getLabelInnerText());
                    repeat.setTextID(group.getTextID());
                    // don't merge binding; repeat will always already have one
                    // replace group with repeat
                    fe.getChildren().set(i, repeat);
                    group = repeat;
                }
            }
            collapseRepeatGroups(group);
        }
    }
}
Also used : IFormElement(org.javarosa.core.model.IFormElement) GroupDef(org.javarosa.core.model.GroupDef)

Example 19 with IFormElement

use of org.javarosa.core.model.IFormElement in project javarosa by opendatakit.

the class XFormParser method parseGroup.

private void parseGroup(IFormElement parent, Element e, int groupType) {
    GroupDef group = new GroupDef();
    // until we come up with a better scheme
    group.setID(serialQuestionID++);
    IDataReference dataRef = null;
    boolean refFromBind = false;
    List<String> usedAtts = new ArrayList<>();
    usedAtts.add(REF_ATTR);
    usedAtts.add(NODESET_ATTR);
    usedAtts.add(BIND_ATTR);
    usedAtts.add(APPEARANCE_ATTR);
    usedAtts.add("count");
    usedAtts.add("noAddRemove");
    if (groupType == CONTAINER_REPEAT) {
        group.setRepeat(true);
    }
    String ref = e.getAttributeValue(null, REF_ATTR);
    String nodeset = e.getAttributeValue(null, NODESET_ATTR);
    String bind = e.getAttributeValue(null, BIND_ATTR);
    group.setAppearanceAttr(e.getAttributeValue(null, APPEARANCE_ATTR));
    if (bind != null) {
        DataBinding binding = bindingsByID.get(bind);
        if (binding == null) {
            throw new XFormParseException("XForm Parse: invalid binding ID [" + bind + "]", e);
        }
        dataRef = binding.getReference();
        refFromBind = true;
    } else {
        if (group.getRepeat()) {
            if (nodeset != null) {
                dataRef = new XPathReference(nodeset);
            } else {
                throw new XFormParseException("XForm Parse: <repeat> with no binding ('bind' or 'nodeset')", e);
            }
        } else {
            if (ref != null) {
                dataRef = new XPathReference(ref);
            } else if (nodeset != null) {
                dataRef = new XPathReference(nodeset);
            }
        // <group> not required to have a binding so no exception thrown
        }
    }
    if (!refFromBind) {
        dataRef = getAbsRef(dataRef, parent);
    }
    group.setBind(dataRef);
    if (group.getRepeat()) {
        repeats.add((TreeReference) dataRef.getReference());
        String countRef = e.getAttributeValue(NAMESPACE_JAVAROSA, "count");
        if (countRef != null) {
            group.count = getAbsRef(new XPathReference(countRef), parent);
            group.noAddRemove = true;
        } else {
            group.noAddRemove = (e.getAttributeValue(NAMESPACE_JAVAROSA, "noAddRemove") != null);
        }
    }
    for (int i = 0; i < e.getChildCount(); i++) {
        int type = e.getType(i);
        Element child = (type == Node.ELEMENT ? e.getElement(i) : null);
        String childName = (child != null ? child.getName() : null);
        String childNamespace = (child != null ? child.getNamespace() : null);
        if (group.getRepeat() && NAMESPACE_JAVAROSA.equals(childNamespace)) {
            if ("chooseCaption".equals(childName)) {
                group.chooseCaption = getLabel(child);
            } else if ("addCaption".equals(childName)) {
                group.addCaption = getLabel(child);
            } else if ("delCaption".equals(childName)) {
                group.delCaption = getLabel(child);
            } else if ("doneCaption".equals(childName)) {
                group.doneCaption = getLabel(child);
            } else if ("addEmptyCaption".equals(childName)) {
                group.addEmptyCaption = getLabel(child);
            } else if ("doneEmptyCaption".equals(childName)) {
                group.doneEmptyCaption = getLabel(child);
            } else if ("entryHeader".equals(childName)) {
                group.entryHeader = getLabel(child);
            } else if ("delHeader".equals(childName)) {
                group.delHeader = getLabel(child);
            } else if ("mainHeader".equals(childName)) {
                group.mainHeader = getLabel(child);
            }
        }
    }
    for (int i = 0; i < e.getChildCount(); i++) {
        if (e.getType(i) == Element.ELEMENT) {
            parseElement(e.getElement(i), group, groupLevelHandlers);
        }
    }
    // save all the unused attributes verbatim...
    for (int i = 0; i < e.getAttributeCount(); i++) {
        String name = e.getAttributeName(i);
        if (usedAtts.contains(name))
            continue;
        group.setAdditionalAttribute(e.getAttributeNamespace(i), name, e.getAttributeValue(i));
    }
    // print unused attribute warning message for parent element
    if (XFormUtils.showUnusedAttributeWarning(e, usedAtts)) {
        reporter.warning(XFormParserReporter.TYPE_UNKNOWN_MARKUP, XFormUtils.unusedAttWarning(e, usedAtts), getVagueLocation(e));
    }
    parent.addChild(group);
}
Also used : IDataReference(org.javarosa.core.model.IDataReference) DataBinding(org.javarosa.core.model.DataBinding) TreeElement(org.javarosa.core.model.instance.TreeElement) AbstractTreeElement(org.javarosa.core.model.instance.AbstractTreeElement) Element(org.kxml2.kdom.Element) IFormElement(org.javarosa.core.model.IFormElement) ArrayList(java.util.ArrayList) XPathReference(org.javarosa.model.xform.XPathReference) GroupDef(org.javarosa.core.model.GroupDef)

Example 20 with IFormElement

use of org.javarosa.core.model.IFormElement in project javarosa by opendatakit.

the class FormInstanceParser method verifyControlBindings.

private void verifyControlBindings(IFormElement fe, FormInstance instance, List<String> errors) {
    // throws XmlPullParserException {
    if (fe.getChildren() == null)
        return;
    for (int i = 0; i < fe.getChildren().size(); i++) {
        IFormElement child = fe.getChildren().get(i);
        IDataReference ref = null;
        String type = null;
        if (child instanceof GroupDef) {
            ref = child.getBind();
            type = (((GroupDef) child).getRepeat() ? "Repeat" : "Group");
        } else if (child instanceof QuestionDef) {
            ref = child.getBind();
            type = "Question";
        }
        TreeReference tref = FormInstance.unpackReference(ref);
        if (child instanceof QuestionDef && tref.size() == 0) {
            // group can bind to '/'; repeat can't, but that's checked above
            reporter.warning(XFormParserReporter.TYPE_INVALID_STRUCTURE, "Cannot bind control to '/'", null);
        } else {
            List<TreeReference> nodes = new EvaluationContext(instance).expandReference(tref, true);
            if (nodes.size() == 0) {
                String error = type + " bound to non-existent node: [" + tref.toString() + "]";
                reporter.error(error);
                errors.add(error);
            }
        // we can't check whether questions map to the right kind of node ('data' node vs. 'sub-tree' node) as that depends
        // on the question's data type, which we don't know yet
        }
        verifyControlBindings(child, instance, errors);
    }
}
Also used : IFormElement(org.javarosa.core.model.IFormElement) IDataReference(org.javarosa.core.model.IDataReference) TreeReference(org.javarosa.core.model.instance.TreeReference) EvaluationContext(org.javarosa.core.model.condition.EvaluationContext) QuestionDef(org.javarosa.core.model.QuestionDef) Constraint(org.javarosa.core.model.condition.Constraint) GroupDef(org.javarosa.core.model.GroupDef)

Aggregations

IFormElement (org.javarosa.core.model.IFormElement)26 GroupDef (org.javarosa.core.model.GroupDef)19 QuestionDef (org.javarosa.core.model.QuestionDef)10 ArrayList (java.util.ArrayList)9 TreeReference (org.javarosa.core.model.instance.TreeReference)8 FormIndex (org.javarosa.core.model.FormIndex)6 TreeElement (org.javarosa.core.model.instance.TreeElement)6 FormEntryPrompt (org.javarosa.form.api.FormEntryPrompt)5 IDataReference (org.javarosa.core.model.IDataReference)4 AbstractTreeElement (org.javarosa.core.model.instance.AbstractTreeElement)3 XPathReference (org.javarosa.model.xform.XPathReference)3 Element (org.kxml2.kdom.Element)3 DataBinding (org.javarosa.core.model.DataBinding)2 Constraint (org.javarosa.core.model.condition.Constraint)2 IAnswerData (org.javarosa.core.model.data.IAnswerData)2 FormEntryModel (org.javarosa.form.api.FormEntryModel)2 Test (org.junit.Test)2 QuestionDetails (org.odk.collect.android.formentry.questions.QuestionDetails)2 MockFormEntryPromptBuilder (org.odk.collect.android.support.MockFormEntryPromptBuilder)2 Activity (android.app.Activity)1