Search in sources :

Example 16 with QuestionDef

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

the class FormEntryPrompt method getSelectChoices.

public List<SelectChoice> getSelectChoices() {
    QuestionDef q = getQuestion();
    ItemsetBinding itemset = q.getDynamicChoices();
    if (itemset != null) {
        if (!dynamicChoicesPopulated) {
            form.populateDynamicChoices(itemset, mTreeElement.getRef());
            dynamicChoicesPopulated = true;
        }
        return itemset.getChoices();
    } else {
        // static choices
        return q.getChoices();
    }
}
Also used : ItemsetBinding(org.javarosa.core.model.ItemsetBinding) QuestionDef(org.javarosa.core.model.QuestionDef)

Example 17 with QuestionDef

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

the class ExternalAnswerResolver method resolveAnswer.

@Override
public IAnswerData resolveAnswer(String textVal, TreeElement treeElement, FormDef formDef) {
    QuestionDef questionDef = XFormParser.ghettoGetQuestionDef(treeElement.getDataType(), formDef, treeElement.getRef());
    if (questionDef != null && (questionDef.getControlType() == Constants.CONTROL_SELECT_ONE || questionDef.getControlType() == Constants.CONTROL_SELECT_MULTI)) {
        boolean containsSearchExpression = false;
        XPathFuncExpr xpathExpression = null;
        try {
            xpathExpression = ExternalDataUtil.getSearchXPathExpression(questionDef.getAppearanceAttr());
        } catch (Exception e) {
            Timber.e(e);
            // there is a search expression, but has syntax errors
            containsSearchExpression = true;
        }
        if (xpathExpression != null || containsSearchExpression) {
            // that means that we have dynamic selects
            // read the static choices from the options sheet
            List<SelectChoice> staticChoices = questionDef.getChoices();
            for (int index = 0; index < staticChoices.size(); index++) {
                SelectChoice selectChoice = staticChoices.get(index);
                String selectChoiceValue = selectChoice.getValue();
                if (ExternalDataUtil.isAnInteger(selectChoiceValue)) {
                    Selection selection = selectChoice.selection();
                    switch(questionDef.getControlType()) {
                        case Constants.CONTROL_SELECT_ONE:
                            {
                                if (selectChoiceValue.equals(textVal)) {
                                    // we just need to make sure, so we will override that.
                                    if (questionDef.getControlType() == Constants.CONTROL_SELECT_ONE) {
                                        // we don't need another, just return the static choice.
                                        return new SelectOneData(selection);
                                    }
                                }
                                break;
                            }
                        case Constants.CONTROL_SELECT_MULTI:
                            {
                                // we should search in a potential comma-separated string of
                                // values for a match
                                // copied from org.javarosa.xform.util.XFormAnswerDataParser
                                // .getSelections()
                                List<String> textValues = DateUtils.split(textVal, XFormAnswerDataSerializer.DELIMITER, true);
                                if (textValues.contains(textVal)) {
                                    // choice.
                                    if (selectChoiceValue.equals(textVal)) {
                                        // this means that the user selected ONLY the static
                                        // answer, so just return that
                                        List<Selection> customSelections = new ArrayList<Selection>();
                                        customSelections.add(selection);
                                        return new SelectMultiData(customSelections);
                                    } else {
                                    // we will ignore it for now since we will return that
                                    // selection together with the dynamic ones.
                                    }
                                }
                                break;
                            }
                        default:
                            {
                                // There is a bug if we get here, so let's throw an Exception
                                throw createBugRuntimeException(treeElement, textVal);
                            }
                    }
                } else {
                    switch(questionDef.getControlType()) {
                        case Constants.CONTROL_SELECT_ONE:
                            {
                                // the default implementation will search for the "textVal"
                                // (saved answer) inside the static choices.
                                // Since we know that there isn't such, we just wrap the textVal
                                // in a virtual choice in order to
                                // create a SelectOneData object to be used as the IAnswer to the
                                // TreeElement.
                                // (the caller of this function is searching for such an answer
                                // to populate the in-memory model.)
                                SelectChoice customSelectChoice = new SelectChoice(textVal, textVal, false);
                                customSelectChoice.setIndex(index);
                                return new SelectOneData(customSelectChoice.selection());
                            }
                        case Constants.CONTROL_SELECT_MULTI:
                            {
                                // we should create multiple selections and add them to the pile
                                List<SelectChoice> customSelectChoices = createCustomSelectChoices(textVal);
                                List<Selection> customSelections = new ArrayList<Selection>();
                                for (SelectChoice customSelectChoice : customSelectChoices) {
                                    customSelections.add(customSelectChoice.selection());
                                }
                                return new SelectMultiData(customSelections);
                            }
                        default:
                            {
                                // There is a bug if we get here, so let's throw an Exception
                                throw createBugRuntimeException(treeElement, textVal);
                            }
                    }
                }
            }
            // if we get there then that means that we have a bug
            throw createBugRuntimeException(treeElement, textVal);
        }
    }
    // default behavior matches original behavior (for static selects, etc.)
    return super.resolveAnswer(textVal, treeElement, formDef);
}
Also used : SelectOneData(org.javarosa.core.model.data.SelectOneData) SelectChoice(org.javarosa.core.model.SelectChoice) Selection(org.javarosa.core.model.data.helper.Selection) XPathFuncExpr(org.javarosa.xpath.expr.XPathFuncExpr) SelectMultiData(org.javarosa.core.model.data.SelectMultiData) ArrayList(java.util.ArrayList) List(java.util.List) QuestionDef(org.javarosa.core.model.QuestionDef)

Example 18 with QuestionDef

use of org.javarosa.core.model.QuestionDef 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)

Example 19 with QuestionDef

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

the class FormEntryModel method getCaptionHierarchy.

/**
 * Returns a hierarchical list of FormEntryCaption objects for the given
 * FormIndex
 *
 * @param index
 * @return list of FormEntryCaptions in hierarchical order
 */
public FormEntryCaption[] getCaptionHierarchy(FormIndex index) {
    List<FormEntryCaption> captions = new ArrayList<FormEntryCaption>();
    FormIndex remaining = index;
    while (remaining != null) {
        remaining = remaining.getNextLevel();
        FormIndex localIndex = index.diff(remaining);
        IFormElement element = form.getChild(localIndex);
        if (element != null) {
            FormEntryCaption caption = null;
            if (element instanceof GroupDef)
                caption = new FormEntryCaption(getForm(), localIndex);
            else if (element instanceof QuestionDef)
                caption = new FormEntryPrompt(getForm(), localIndex);
            if (caption != null) {
                captions.add(caption);
            }
        }
    }
    FormEntryCaption[] captionArray = new FormEntryCaption[captions.size()];
    return captions.toArray(captionArray);
}
Also used : IFormElement(org.javarosa.core.model.IFormElement) ArrayList(java.util.ArrayList) FormIndex(org.javarosa.core.model.FormIndex) QuestionDef(org.javarosa.core.model.QuestionDef) GroupDef(org.javarosa.core.model.GroupDef)

Example 20 with QuestionDef

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

the class FormEntryController method answerQuestion.

/**
 * Attempts to save the answer at the specified FormIndex into the
 * datamodel.
 *
 * @param index
 * @param data
 * @return OK if save was successful, error if a constraint was violated.
 */
public int answerQuestion(FormIndex index, IAnswerData data, boolean midSurvey) {
    QuestionDef q = model.getQuestionPrompt(index).getQuestion();
    if (model.getEvent(index) != FormEntryController.EVENT_QUESTION) {
        throw new RuntimeException("Non-Question object at the form index.");
    }
    TreeElement element = model.getTreeElement(index);
    boolean complexQuestion = q.isComplex();
    boolean hasConstraints = false;
    if (element.isRequired() && data == null) {
        return ANSWER_REQUIRED_BUT_EMPTY;
    } else if (!complexQuestion && !model.getForm().evaluateConstraint(index.getReference(), data)) {
        return ANSWER_CONSTRAINT_VIOLATED;
    } else if (!complexQuestion) {
        commitAnswer(element, index, data, midSurvey);
        return ANSWER_OK;
    } else if (complexQuestion && hasConstraints) {
        // TODO: itemsets: don't currently evaluate constraints for itemset/copy -- haven't figured out how handle it yet
        throw new RuntimeException("Itemsets do not currently evaluate constraints. Your constraint will not work, please remove it before proceeding.");
    } else {
        try {
            model.getForm().copyItemsetAnswer(q, element, data, midSurvey);
        } catch (InvalidReferenceException ire) {
            Std.printStack(ire);
            throw new RuntimeException("Invalid reference while copying itemset answer: " + ire.getMessage());
        }
        return ANSWER_OK;
    }
}
Also used : QuestionDef(org.javarosa.core.model.QuestionDef) InvalidReferenceException(org.javarosa.core.model.instance.InvalidReferenceException) TreeElement(org.javarosa.core.model.instance.TreeElement)

Aggregations

QuestionDef (org.javarosa.core.model.QuestionDef)30 IFormElement (org.javarosa.core.model.IFormElement)8 SelectChoice (org.javarosa.core.model.SelectChoice)7 Test (org.junit.Test)6 ArrayList (java.util.ArrayList)5 GroupDef (org.javarosa.core.model.GroupDef)5 IDataReference (org.javarosa.core.model.IDataReference)4 Selection (org.javarosa.core.model.data.helper.Selection)4 TreeElement (org.javarosa.core.model.instance.TreeElement)4 FormEntryPrompt (org.javarosa.form.api.FormEntryPrompt)4 TreeReference (org.javarosa.core.model.instance.TreeReference)3 Localizer (org.javarosa.core.services.locale.Localizer)3 List (java.util.List)2 FormDef (org.javarosa.core.model.FormDef)2 ItemsetBinding (org.javarosa.core.model.ItemsetBinding)2 Constraint (org.javarosa.core.model.condition.Constraint)2 EvaluationContext (org.javarosa.core.model.condition.EvaluationContext)2 SelectMultiData (org.javarosa.core.model.data.SelectMultiData)2 SelectOneData (org.javarosa.core.model.data.SelectOneData)2 AbstractTreeElement (org.javarosa.core.model.instance.AbstractTreeElement)2