fixed some basic xforms bug (too many setXFormsValue requests for textfields, multiselect lists not behaving)

- partial fix for repeat 0 to n bug.  still needs much work.

quasi functional nested repeats.  
- refactored the way triggers are generated to use nodesets rather than simple binding.
- reimplemented the way triggers are located in the xform to not rely on ids.
- reimplemented handling of prototype-cloned.  need to actually keep track of prototype ids, and different mechanism for locating the prototype node

what doesn't work:
- it's not usable for many reasons, among them no identation in the ui.
- setRepeatIndex calls aren't bubbling properly so occasionally things get added to the wrong repeat.
- constraints remain unenforced.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4490 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ariel Backenroth
2006-12-02 04:46:23 +00:00
parent ce1ab1a6d0
commit 8d2eb8ff45
3 changed files with 432 additions and 269 deletions

View File

@@ -121,6 +121,11 @@ public class SchemaFormBuilder
this.maximum = maximum;
}
public boolean isRepeated()
{
return this.isUnbounded() || this.maximum > 1;
}
public boolean isUnbounded()
{
return this.maximum == UNBOUNDED;
@@ -428,14 +433,12 @@ public class SchemaFormBuilder
this.counter = new HashMap();
final Document xForm = createFormTemplate(rootElementName);
final Element envelopeElement = xForm.getDocumentElement();
//find form element: last element created
final NodeList children = xForm.getDocumentElement().getChildNodes();
final Element formSection = (Element)children.item(children.getLength() - 1);
final Element formSection = (Element)
xForm.getDocumentElement().getLastChild();
final Element modelSection = (Element)
envelopeElement.getElementsByTagNameNS(XFORMS_NS, "model").item(0);
xForm.getDocumentElement().getElementsByTagNameNS(XFORMS_NS, "model").item(0);
//add XMLSchema if we use schema types
modelSection.setAttributeNS(XFORMS_NS, "schema", "#schema-1");
@@ -463,12 +466,6 @@ public class SchemaFormBuilder
// this.targetNamespace);
final Comment comment =
xForm.createComment("This XForm was automatically generated by " + this.getClass().getName() +
" on " + (new Date()) + " from the '" + rootElementName +
"' element of the '" + this.targetNamespace + "' XML Schema.");
xForm.insertBefore(comment, envelopeElement);
//TODO: WARNING: in Xerces 2.6.1, parameters are switched !!! (name, namespace)
//XSElementDeclaration rootElementDecl =schema.getElementDeclaration(this.targetNamespace, _rootElementName);
XSElementDeclaration rootElementDecl =
@@ -564,6 +561,14 @@ public class SchemaFormBuilder
submitButton.appendChild(submitButtonCaption);
submitButtonCaption.appendChild(xForm.createTextNode("Submit"));
this.setXFormsId(submitButtonCaption);
this.createTriggersForRepeats(xForm);
final Comment comment =
xForm.createComment("This XForm was automatically generated by " + this.getClass().getName() +
" on " + (new Date()) + " from the '" + rootElementName +
"' element of the '" + this.targetNamespace + "' XML Schema.");
xForm.getDocumentElement().insertBefore(comment,
xForm.getDocumentElement().getFirstChild());
return xForm;
}
@@ -2132,9 +2137,14 @@ public class SchemaFormBuilder
element,
element.getTypeDefinition(),
path);
for (int i = 1; i < this.getOccurance(element).minimum; i++)
// update the default instance
if (this.getOccurance(element).isRepeated())
{
defaultInstanceElement.appendChild(newDefaultInstanceElement.cloneNode(true));
for (int i = 0; i < this.getOccurance(element).minimum; i++)
{
defaultInstanceElement.appendChild(newDefaultInstanceElement.cloneNode(true));
}
}
}
}
@@ -2207,13 +2217,6 @@ public class SchemaFormBuilder
SchemaFormBuilder.XFORMS_NS_PREFIX + "appearance",
"full");
//triggers
this.addTriggersForRepeat(xForm,
formSection,
repeatSection,
o,
bindId);
final Element controlWrapper =
this.wrapper.createControlsWrapper(repeatSection);
formSection.appendChild(controlWrapper);
@@ -2256,18 +2259,17 @@ public class SchemaFormBuilder
bindElement = this.startBindElement(bindElement, schema, controlType, owner, pathToRoot, o);
// add a group if a repeat !
// if (owner instanceof XSElementDeclaration && o.maximum != 1)
// {
// Element groupElement = this.createGroup(xForm,
// modelSection,
// formSection,
// (XSElementDeclaration) owner);
// //set content
// Element groupWrapper = groupElement;
// if (groupElement != modelSection)
// groupWrapper = this.wrapper.createGroupContentWrapper(groupElement);
// formSection = groupWrapper;
// }
if (owner instanceof XSElementDeclaration && o.maximum != 1)
{
final Element groupElement = this.createGroup(xForm,
modelSection,
formSection,
(XSElementDeclaration)owner);
//set content
formSection = (groupElement == modelSection
? groupElement
: this.wrapper.createGroupContentWrapper(groupElement));
}
//eventual repeat
final Element repeatSection = this.addRepeatIfNecessary(xForm,
@@ -2370,160 +2372,8 @@ public class SchemaFormBuilder
pathToRoot,
new Occurs(owningAttribute.getRequired() ? 1 : 0, 1));
}
private Element createTriggerForRepeat(final Document xForm,
final String id,
final String label,
final Element action)
{
final Element trigger =
xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "trigger");
this.setXFormsId(trigger, id != null ? id : null);
//label insert
final Element triggerLabel =
xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "label");
this.setXFormsId(triggerLabel);
trigger.appendChild(triggerLabel);
triggerLabel.appendChild(xForm.createTextNode(label));
//hint insert
//Element hint_insert =
// xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
// SchemaFormBuilder.XFORMS_NS_PREFIX + "hint");
//this.setXFormsId(hint_insert);
//Text hint_insert_text =
// xForm.createTextNode("inserts a new entry in this collection");
//hint_insert.appendChild(hint_insert_text);
//trigger_insert.appendChild(hint_insert);
//insert action
final Element actionWrapper =
xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "action");
actionWrapper.appendChild(action);
trigger.appendChild(action);
this.setXFormsId(action);
return trigger;
}
/**
* add triggers to use the repeat elements (allow to add an element, ...)
*/
private void addTriggersForRepeat(final Document xForm,
final Element formSection,
final Element repeatSection,
final Occurs o,
final String bindId) {
//xforms:at = xforms:index from the "id" attribute on the repeat element
final String repeatId =
repeatSection.getAttributeNS(SchemaFormBuilder.XFORMS_NS, "id");
///////////// insert //////////////////
//trigger insert
Element action =
xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "insert");
//insert: bind & other attributes
if (bindId != null)
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "bind",
bindId);
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "position",
"before");
if (repeatId != null)
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "at",
"1");
final Element trigger_insert_before =
this.createTriggerForRepeat(xForm,
repeatId != null ? repeatId + "-insert_before" : null,
"insert at beginning",
action);
action = xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "insert");
//insert: bind & other attributes
if (bindId != null)
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "bind",
bindId);
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "position",
"after");
if (repeatId != null)
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "at",
SchemaFormBuilder.XFORMS_NS_PREFIX + "index('" + repeatId + "')");
final Element trigger_insert_after =
this.createTriggerForRepeat(xForm,
repeatId != null ? repeatId + "-insert_after" : null,
"insert after selected",
action);
///////////// delete //////////////////
//trigger delete
action = xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "delete");
//delete: bind & other attributes
if (bindId != null)
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "bind",
bindId);
//xforms:at = xforms:index from the "id" attribute on the repeat element
if (repeatId != null)
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "at",
SchemaFormBuilder.XFORMS_NS_PREFIX + "index('" + repeatId + "')");
final Element trigger_delete =
this.createTriggerForRepeat(xForm,
repeatId != null ? repeatId + "-delete" : null,
"delete selected",
action);
//add the triggers
final Element wrapper_triggers =
this.wrapper.createControlsWrapper(trigger_insert_before);
if (wrapper_triggers == trigger_insert_before)
{
//no wrapper
formSection.appendChild(trigger_insert_before);
formSection.appendChild(trigger_insert_after);
formSection.appendChild(trigger_delete);
}
else
{
formSection.appendChild(wrapper_triggers);
final Element insert_parent = (Element)trigger_insert_before.getParentNode();
if (insert_parent != null)
{
insert_parent.appendChild(trigger_insert_after);
insert_parent.appendChild(trigger_delete);
}
}
}
private void buildTypeTree(final XSTypeDefinition type,
final TreeSet descendents)
{
@@ -2691,7 +2541,6 @@ public class SchemaFormBuilder
formControl.appendChild(alertElement);
this.setXFormsId(alertElement);
final Element envelope = xForm.getDocumentElement();
String alert = this.extractPropertyFromAnnotation(ALFRESCO_NS,
"alert",
this.getAnnotation(owner));
@@ -2699,7 +2548,7 @@ public class SchemaFormBuilder
alert = ("Please provide a valid value for '" + caption + "'." +
" '" + caption +
"' is " + (o.minimum == 0 ? "an optional" : "a required") + " '" +
createCaption(this.getXFormsTypeName(envelope, schema, controlType)) +
createCaption(this.getXFormsTypeName(xForm, schema, controlType)) +
"' value.");
alertElement.appendChild(xForm.createTextNode(alert));
return formControl;
@@ -2712,10 +2561,11 @@ public class SchemaFormBuilder
* @param controlType the type from which we want the name
* @return the complete type name (with namespace prefix) of the type in the XForms doc
*/
protected String getXFormsTypeName(final Element context,
protected String getXFormsTypeName(final Document xformsDocument,
final XSModel schema,
final XSTypeDefinition controlType)
{
final Element context = xformsDocument.getDocumentElement();
final String typeName = controlType.getName();
final String typeNS = controlType.getNamespace();
@@ -3325,7 +3175,7 @@ public class SchemaFormBuilder
// static string (see bug #1172541 on sf.net)
String nodeset = pathToRoot;
// if (o.maximum > 1 || o.isUnbounded())
// if (o.isRepeated())
// nodeset = pathToRoot + "[position() != last()]";
bindElement.setAttributeNS(XFORMS_NS,
@@ -3334,8 +3184,9 @@ public class SchemaFormBuilder
if (!"anyType".equals(controlType.getName()))
{
Element enveloppe = bindElement.getOwnerDocument().getDocumentElement();
String typeName = this.getXFormsTypeName(enveloppe, schema, controlType);
String typeName = this.getXFormsTypeName(bindElement.getOwnerDocument(),
schema,
controlType);
if (typeName != null && typeName.length() != 0)
bindElement.setAttributeNS(XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "type",
@@ -3447,8 +3298,9 @@ public class SchemaFormBuilder
prefix = basePrefix + (i++);
}
namespacePrefixes.put(namespace, prefix);
Element envelope = xForm.getDocumentElement();
envelope.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns:" + prefix, namespace);
xForm.getDocumentElement().setAttributeNS(XMLNS_NAMESPACE_URI,
"xmlns:" + prefix,
namespace);
}
elementName = prefix + ":" + elementName;
}
@@ -3506,4 +3358,182 @@ public class SchemaFormBuilder
if (!e.hasAttributeNS(XMLNS_NAMESPACE_URI, p))
e.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns:" + p, ns);
}
private void createTriggersForRepeats(final Document xformsDocument)
{
LOGGER.debug("creating triggers for repeats");
final HashMap<String, Element> bindIdToBind = new HashMap<String, Element>();
final NodeList binds = xformsDocument.getElementsByTagNameNS(XFORMS_NS, "bind");
for (int i = 0; i < binds.getLength(); i++)
{
final Element b = (Element)binds.item(i);
LOGGER.debug("adding bind " + b.getAttributeNS(XFORMS_NS, "id"));
bindIdToBind.put(b.getAttributeNS(XFORMS_NS, "id"), b);
}
final NodeList repeats = xformsDocument.getElementsByTagNameNS(XFORMS_NS, "repeat");
final HashMap<Element, Element> bindToRepeat = new HashMap<Element, Element>();
for (int i = 0; i < repeats.getLength(); i++)
{
Element r = (Element)repeats.item(i);
LOGGER.debug("processing repeat " + r.getAttributeNS(XFORMS_NS, "id"));
Element bind = bindIdToBind.get(r.getAttributeNS(XFORMS_NS, "bind"));
bindToRepeat.put(bind, r);
String xpath = "";
do
{
if (xpath.length() != 0)
{
xpath = '/' + xpath;
}
LOGGER.debug("walking bind " + bind.getAttributeNS(XFORMS_NS, "id"));
String s = bind.getAttributeNS(XFORMS_NS, "nodeset");
if (bindToRepeat.containsKey(bind) && !r.equals(bindToRepeat.get(bind)))
{
s += "[index(\'" + bindToRepeat.get(bind).getAttributeNS(XFORMS_NS, "id") + "\')]";
}
xpath = s + xpath;
bind = ((XFORMS_NS_PREFIX + "bind").equals(bind.getParentNode().getNodeName())
? (Element)bind.getParentNode()
: null);
}
while (bind != null);
this.createTriggersForRepeat(xformsDocument,
r.getAttributeNS(XFORMS_NS, "id"),
xpath,
r.getAttributeNS(XFORMS_NS, "bind"));
}
}
private Element createTriggerForRepeat(final Document xForm,
final String id,
final String bindId,
final String label,
final Element action)
{
final Element trigger =
xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "trigger");
this.setXFormsId(trigger, id != null ? id : null);
//copy the bind attribute
trigger.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "bind",
bindId);
//label insert
final Element triggerLabel =
xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "label");
this.setXFormsId(triggerLabel);
trigger.appendChild(triggerLabel);
triggerLabel.appendChild(xForm.createTextNode(label));
//insert action
final Element actionWrapper =
xForm.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "action");
actionWrapper.appendChild(action);
trigger.appendChild(action);
this.setXFormsId(action);
return trigger;
}
/**
* add triggers to use the repeat elements (allow to add an element, ...)
*/
private void createTriggersForRepeat(final Document xformsDocument,
final String repeatId,
final String nodeset,
final String bindId)
{
//xforms:at = xforms:index from the "id" attribute on the repeat element
///////////// insert //////////////////
//trigger insert
Element action =
xformsDocument.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "insert");
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "nodeset",
nodeset);
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "position",
"before");
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "at",
"1");
final Element trigger_insert_before =
this.createTriggerForRepeat(xformsDocument,
repeatId + "-insert_before",
bindId,
"insert at beginning",
action);
action = xformsDocument.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "insert");
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "nodeset",
nodeset);
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "position",
"after");
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "at",
SchemaFormBuilder.XFORMS_NS_PREFIX + "index('" + repeatId + "')");
final Element trigger_insert_after =
this.createTriggerForRepeat(xformsDocument,
repeatId + "-insert_after",
bindId,
"insert after selected",
action);
//trigger delete
action = xformsDocument.createElementNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "delete");
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "nodeset",
nodeset);
action.setAttributeNS(SchemaFormBuilder.XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "at",
SchemaFormBuilder.XFORMS_NS_PREFIX + "index('" + repeatId + "')");
final Element trigger_delete =
this.createTriggerForRepeat(xformsDocument,
repeatId != null ? repeatId + "-delete" : null,
bindId,
"delete selected",
action);
final Element formSection = (Element)xformsDocument.getDocumentElement().getLastChild();
//add the triggers
final Element wrapper_triggers =
this.wrapper.createControlsWrapper(trigger_insert_before);
if (wrapper_triggers == trigger_insert_before)
{
//no wrapper
formSection.appendChild(trigger_insert_before);
formSection.appendChild(trigger_insert_after);
formSection.appendChild(trigger_delete);
}
else
{
formSection.appendChild(wrapper_triggers);
final Element insert_parent = (Element)trigger_insert_before.getParentNode();
if (insert_parent != null)
{
insert_parent.appendChild(trigger_insert_after);
insert_parent.appendChild(trigger_delete);
}
}
}
}