package org.openrosa.client.model; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.openrosa.client.OpenRosaConstants; import org.openrosa.client.util.Itext; import org.openrosa.client.util.ItextParser; import org.openrosa.client.xforms.UiElementBuilder; import org.openrosa.client.util.FormUtil; import org.openrosa.client.xforms.XformConstants; import org.openrosa.client.xforms.XmlUtil; import com.google.gwt.xml.client.Document; import com.google.gwt.xml.client.Element; /** * Definition of an answer option or one of the possible answers of a question * with a given set of allowed answers.. * * */ public class OptionDef implements IFormElement, Serializable { /** The numeric unique identifier of an answer option. */ private int id = ModelConstants.NULL_ID; /** The display text of the answer option. */ private String text = ModelConstants.EMPTY_STRING; //TODO May not need to serialize this property for smaller pay load. Then we would just rely on the id. /** The unique text identifier of an answer option. */ private String binding = ModelConstants.EMPTY_STRING; public static final char SEPARATOR_CHAR = ','; /** The xforms label node for this option. */ private Element labelNode; /** The xforms value node for this option. */ private Element valueNode; /** The xforms select or select1 node that this option belongs to. */ private Element controlNode; /** The question to which this option belongs. */ private IFormElement parent; private String itextId; /** The internal value of this OptionDef element */ private String defaultValue; /** Constructs the answer option definition object where * initialization parameters are not supplied. */ public OptionDef(QuestionDef parent) { this.parent = parent; } public List<String> getAllChildrenItextIDs(){ return new ArrayList<String>(); //This method does not apply to OptionDefs (they can never have children) } /** The copy constructor */ public OptionDef(OptionDef optionDef,QuestionDef parent) { this(parent); setId(optionDef.getId()); setText(optionDef.getText()); setQuestionID(optionDef.getQuestionID()); setItextId(optionDef.getItextId()); //setParent(parent /*optionDef.getParent()*/); } /** Constructs a new option answer definition object from the following parameters. * * @param id * @param text * @param variableName */ public OptionDef(int id,String text, String variableName,QuestionDef parent) { this(parent); setId(id); setText(text); setQuestionID(variableName); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public String getQuestionID() { return binding; } public void setQuestionID(String variableName) { this.binding = variableName; } public IFormElement getParent() { return parent; } public void setParent(IFormElement parent) { this.parent = parent; } public String getItextId() { return itextId; } public void setItextId(String itextId) { this.itextId = itextId; } /** * @return the labelNode */ public Element getLabelNode() { return labelNode; } /** * Gets the form to which this question belongs. * * @return the form. */ public FormDef getParentFormDef(){ return (FormDef)getParentFormDef(this); } private IFormElement getParentFormDef(IFormElement questionDef){ IFormElement parent = questionDef.getParent(); if(parent instanceof FormDef) return parent; return getParentFormDef(parent); } /** * @param labelNode the labelNode to set */ public void setLabelNode(Element labelNode) { this.labelNode = labelNode; if(itextId == null) setItextId(XmlUtil.getItextId(labelNode)); } /** * @return the valueNode */ public Element getValueNode() { return valueNode; } /** * @param valueNode the valueNode to set */ public void setValueNode(Element valueNode) { this.valueNode = valueNode; } /** * @return the controlNode */ public Element getControlNode() { return controlNode; } /** * @param controlNode the controlNode to set */ public void setControlNode(Element controlNode) { this.controlNode = controlNode; } public String toString() { return getText(); } /** * Updates the xforms xml document with the changes in the option. * * @param doc the xml document. * @param selectNode the select or select1 node that this option belongs to. */ public void updateDoc(Document doc, Element selectNode){ if(labelNode != null){ XmlUtil.setTextNodeValue(labelNode,getText()); UiElementBuilder.addItextRefs(labelNode, this); } if(valueNode != null){ XmlUtil.setTextNodeValue(valueNode,getDefaultValue()); } if(labelNode == null && valueNode == null){ ////Must be new option. UiElementBuilder.fromOptionDef2Xform(this,doc,selectNode); } if(controlNode != null){ // controlNode.setAttribute(XformConstants.ATTRIBUTE_NAME_ID, binding); } } /** * Builds the language xpath node for locatization of text for this option. * * @param parentXpath the parent xpath expression. * @param doc the locale document. * @param parentNode */ public void buildLanguageNodes(String parentXpath, com.google.gwt.xml.client.Document doc, Element parentNode){ if(labelNode != null && controlNode != null){ String xpath = parentXpath + "/" + FormUtil.getNodeName(controlNode); String id = controlNode.getAttribute(XformConstants.ATTRIBUTE_NAME_ID); if(id != null && id.trim().length() > 0) xpath += "[@" + XformConstants.ATTRIBUTE_NAME_ID + "='" + id + "']"; /*String parent = controlNode.getAttribute(XformConstants.ATTRIBUTE_NAME_PARENT); if(parent != null && parent.trim().length() > 0) xpath += "[@" + XformConstants.ATTRIBUTE_NAME_PARENT + "='" + parent + "']";*/ xpath += "/"+ FormUtil.getNodeName(labelNode); Element node = doc.createElement(XformConstants.NODE_NAME_TEXT); node.setAttribute(XformConstants.ATTRIBUTE_NAME_XPATH, xpath); node.setAttribute(XformConstants.ATTRIBUTE_NAME_VALUE, text); node.setAttribute(XformConstants.ATTRIBUTE_NAME_ID, itextId); node.setAttribute(OpenRosaConstants.ATTRIBUTE_NAME_UNIQUE_ID, "OptionDef"+id); parentNode.appendChild(node); } } public int getDataType(){ return QuestionDef.QTN_TYPE_OPTION_ITEM; } public IFormElement getElement(String varName){ //Method does not apply to Options. return null; } public void setDataType(int dataType){ } public List<IFormElement> getChildren(){ return null; } public void setChildren(List<IFormElement> children){ } public Element getBindNode(){ return null; } public void setBindNode(Element bindNode){ } public Element getDataNode(){ return null; } public void setDataNode(Element dataNode){ } public void refresh(IFormElement element){ } public void updateDoc(Document doc, Element xformsNode, IFormElement formDef, Element formNode, Element modelNode, boolean withData, String orgFormVarName){ throw new RuntimeException("Error in OptionDef in updateDoc, unrecognized method!"); } public void updateDataNodes(Element parentDataNode){ } public IFormElement copy(IFormElement parent){ return new OptionDef(this, (QuestionDef)parent); } public void clearChangeListeners(){ } public String getDisplayText(){ return getText(); } public void addChild(IFormElement element){ throw new RuntimeException("Can't add a child to an OptionDef!"); } public String getHelpText(){ return null; } public void setHelpText(String helpText){ } public Element getHintNode(){ return null; } public void setHintNode(Element hintNode){ } public boolean removeChild(IFormElement element){ return false; } public int getChildCount(){ return 0; } public FormDef getFormDef(){ IFormElement element = getParent(); if(parent instanceof FormDef) return (FormDef)element; return element.getFormDef(); } public boolean isLocked(){ return false; } public boolean isRequired(){ return false; } public boolean isEnabled(){ return true; } public String getDefaultValue(){ return defaultValue; } public void setDefaultValue(String defaultValue){ this.defaultValue = defaultValue; } @Override public void setEnabled(boolean enabled) { // TODO Auto-generated method stub } @Override public void setLocked(boolean locked) { // TODO Auto-generated method stub } @Override public void setRequired(boolean required) { // TODO Auto-generated method stub } /** * Get the Nodeset ref that points to the data node where the question's answer will be stored. * @return */ public String getDataNodesetPath(){ //Not Valid for an OptionDef return "No Nodeset Path for Option elements!"; } @Override public boolean hasUINode() { // TODO Auto-generated method stub return true; } @Override public void setHasUINode(boolean hasUINode) { return; //OptionDef should always have a UINode. } @Override public void moveChildToIndex(IFormElement child, int index) throws Exception { throw new Exception("OptionDefs cannot have children!"); } /** Not Applicable **/ public boolean hasAdvancedCalculate() { return false; } /** Not Applicable **/ public boolean hasAdvancedConstraint() { return false; } /** Not Applicable **/ public boolean hasAdvancedRelevant() { return false; } /** Not Applicable **/ public void setHasAdvancedCalculate(boolean enabled) { return; } /** Not Applicable **/ public void setHasAdvancedConstraint(boolean enabled) { return; } /** Not Applicable **/ public void setHasAdvancedRelevant(boolean enabled) { return; } /** Not Applicable **/ public String getAdvancedCalculate() { return null; } /** Not Applicable **/ public String getAdvancedConstraint() { return null; } /** Not Applicable **/ public String getAdvancedRelevant() { return null; } /** Not Applicable **/ public void setAdvancedCalculate(String calcValue) { return; } /** Not Applicable **/ public void setAdvancedConstraint(String constValue) { return; } /** Not Applicable **/ public void setAdvancedRelevant(String releValue) { return; } //this method does not make sense for OptionDefs public boolean insertChildAfter(IFormElement child, IFormElement target) { return false; } //this method does not make sense for OptionDefs public boolean insertChildBefore(IFormElement child, IFormElement target) { return false; } }