cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jheym...@apache.org
Subject svn commit: r330548 [96/132] - in /cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/ cocoon-ajax-block/api/ cocoon-ajax-block/api/src/ cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/ cocoon-ajax-block/api/src/main/...
Date Thu, 03 Nov 2005 14:00:48 GMT
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerDefinition.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerDefinition.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerDefinition.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Interface to be implemented by WidgetDefinitions for Widgets which contain other widgets.
+ *
+ * @version $Id: ContainerDefinition.java 56582 2004-11-04 10:16:22Z sylvain $
+ */
+public interface ContainerDefinition extends WidgetDefinition {
+
+    /**
+     * Resolve references to widget definition classes
+     */
+    public void resolve(List parents, WidgetDefinition parent) throws Exception;
+
+    /**
+     * Create a widget from a contained widget definition.
+     */
+    public void createWidget(Widget parent, String id);
+
+    /**
+     * Create widgets from the contained widget definitions.
+     */
+    public void createWidgets(Widget parent);
+
+    /**
+     * Adds a (sub) widget definition to this definition.
+     */
+    public void addWidgetDefinition(WidgetDefinition definition) throws Exception, DuplicateIdException;
+
+    /**
+     * Check if this definition contains the named definition.
+     */
+    public boolean hasWidget(String id);
+
+    /**
+     * Gets a (sub) widget definition from this definition.
+     */
+    public WidgetDefinition getWidgetDefinition(String id);
+
+    /**
+     * Gets the collection of (sub) widget definition from this definition.
+     */
+    public Collection getWidgetDefinitions();
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerDefinition.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerWidget.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerWidget.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerWidget.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerWidget.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import java.util.Iterator;
+
+/**
+ * Interface to be implemented by Widgets which contain other widgets. So all
+ * widgets together form a widget tree, with its root being the {@link Form}
+ * widget, the {@link ContainerWidget}s being the branches/forks, and the
+ * {@link Widget}s with values being the leaves.
+ *
+ * @version $Id: ContainerWidget.java 180096 2005-06-05 14:36:02Z reinhard $
+ */
+public interface ContainerWidget extends Widget {
+    
+    /**
+     * Adds a child widget.
+     */
+    public void addChild(Widget widget);
+    //TODO: check to remove since we have no removeChild
+    
+
+    /**
+     * Checks if there is a child widget with the given id.
+     */
+    public boolean hasChild(String id);
+
+    /**
+     * Gets the child widget with the given id.
+     * @return null if there is no child with the given id.
+     */
+    public Widget getChild(String id);
+
+    /**
+     * @return an iterator over the widgets this object contains
+     */
+    public Iterator getChildren();
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ContainerWidget.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DataWidget.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DataWidget.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DataWidget.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DataWidget.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,28 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.apache.cocoon.forms.datatype.Datatype;
+
+/**
+ * @version $Id: DataWidget.java 56582 2004-11-04 10:16:22Z sylvain $
+ * 
+ */
+public interface DataWidget extends Widget {
+
+    public Datatype getDatatype();
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DataWidget.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DuplicateIdException.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DuplicateIdException.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DuplicateIdException.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DuplicateIdException.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+/**
+ * This exception is thrown by WidgetDefinitions that contain other WidgetDefinitions,
+ * such as the {@link FormDefinition} or the {@link RepeaterDefinition}, in case
+ * one tries to add a WidgetDefinition that has the same id as another,
+ * previously added, WidgetDefinition.
+ * 
+ * @version $Id: DuplicateIdException.java 56582 2004-11-04 10:16:22Z sylvain $
+ */
+public class DuplicateIdException extends Exception {
+    public DuplicateIdException(String message) {
+        super(message);
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/DuplicateIdException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.apache.cocoon.forms.util.DomHelper;
+import org.w3c.dom.Element;
+
+/**
+ * Builds definitions by using library definitions.
+ *
+ * @version $Id: ExpandDefinitionBuilder.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public class ExpandDefinitionBuilder extends AbstractWidgetDefinitionBuilder {
+
+    public WidgetDefinition buildWidgetDefinition(Element element) throws Exception {
+        String id = DomHelper.getAttribute(element, "id");
+        
+        WidgetDefinition definition = context.getLocalLibrary().getDefinition(id);
+        
+        if(definition == null)
+        	throw new Exception("Widget '"+id+"' not found! (at "+DomHelper.getLocation(element)+")");
+        
+        return definition;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpandDefinitionBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpressionContextImpl.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpressionContextImpl.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpressionContextImpl.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpressionContextImpl.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,98 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.outerj.expression.ExpressionContext;
+
+import java.math.BigDecimal;
+
+/**
+ * Implementation of the ExpressionContext required for the evaluation of
+ * expressions by xReporter expression interpreter.
+ * 
+ * @version $Id: ExpressionContextImpl.java 56582 2004-11-04 10:16:22Z sylvain $
+ */
+public class ExpressionContextImpl implements ExpressionContext {
+    private Widget widget;
+    private boolean referenceChildren;
+
+    public ExpressionContextImpl(Widget widget) {
+        this.widget = widget;
+        this.referenceChildren = false;
+    }
+
+    /**
+     * @param referenceChildren if true, variables will be resolved among the children of the given
+     * container widget, rather than among the siblings of the widget.
+     */
+    public ExpressionContextImpl(Widget widget, boolean referenceChildren) {
+        this.widget = widget;
+        this.referenceChildren = referenceChildren;
+    }
+
+    /**
+     * Variables refer to other widgets.
+     *
+     * <p>The current implementation only allows access to sibling widgets.
+     *
+     * <p>In case the value of a widget is null but the widget is required, then a special
+     * exception will be thrown, the {@link CannotYetResolveWarning}. This is because in
+     * that case, you'll probably want to re-evaluate the expression at a later time (since
+     * the widget is required, it will eventually get a value).
+     *
+     * <p>In case the value of the widget is null but the field is not required, then simply
+     * null is returned. (TODO: a function IsNull() will provided in the expression library
+     * so that expression writers can check for the likely condition where a non-required field
+     * is null).
+     *
+     * <p>If the variable name does not refer to an existing widget, null is returned (TODO: this
+     * behaviour will probably change in the future)
+     */
+    public Object resolveVariable(String name) {
+        // TODO allow to access other widgets instead of only siblings (allow going up with ../ notation or something)
+        Widget widget;
+        if (!referenceChildren)
+            widget = ((ContainerWidget)this.widget.getParent()).lookupWidget(name);
+        else
+            widget = ((ContainerWidget)this.widget).lookupWidget(name);
+        if (widget != null) {
+            Object value = widget.getValue();
+
+            if (value == null && widget.isRequired()) {
+                // the widget currently has not yet a value, but since it is required, it will get a value sooner
+                // or later. Therefore, we throw an exception here indicating that this expression can currenlty
+                // not yet be evaluated, but will be at a later time.
+                throw new CannotYetResolveWarning();
+            }
+
+            // do some type conversions:
+            //   * the expression library only knows about BigDecimals as being numbers, so convert Longs first to BigDecimals
+            //   * ...
+            if (value instanceof Long)
+                return new BigDecimal(((Long)value).longValue());
+            else if (value instanceof Integer)
+                return new BigDecimal(((Integer)value).intValue());
+            else
+                return value;
+        }
+        return null;
+    }
+
+    public Object get(String s) {
+        return null;
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ExpressionContextImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Field.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Field.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Field.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Field.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,542 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.apache.cocoon.forms.FormsConstants;
+import org.apache.cocoon.forms.FormContext;
+import org.apache.cocoon.forms.datatype.Datatype;
+import org.apache.cocoon.forms.datatype.SelectionList;
+import org.apache.cocoon.forms.datatype.convertor.ConversionResult;
+import org.apache.cocoon.forms.event.*;
+import org.apache.cocoon.forms.util.I18nMessage;
+import org.apache.cocoon.forms.validation.ValidationError;
+import org.apache.cocoon.forms.validation.ValidationErrorAware;
+import org.apache.cocoon.xml.AttributesImpl;
+import org.apache.cocoon.xml.XMLUtils;
+import org.apache.commons.lang.ObjectUtils;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+import java.util.Locale;
+
+/**
+ * A general-purpose Widget that can hold one value. A Field widget can be associated
+ * with a {@link org.apache.cocoon.forms.datatype.Datatype Datatype}, and thus
+ * a Field widget can be used to edit different kinds of data, such as strings,
+ * numbers and dates. A Datatype can also have an associated SelectionList, so
+ * that the value for the Field can be selected from a list, rather than being
+ * entered in a textbox. The validation of the field is delegated to its associated
+ * Datatype.
+ *
+ * @author Bruno Dumon
+ * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
+ * @version $Id: Field.java 326930 2005-10-20 16:03:19Z sylvain $
+ */
+public class Field extends AbstractWidget
+                   implements ValidationErrorAware, DataWidget, SelectableWidget, ValueChangedListenerEnabled {
+
+    private static final String FIELD_EL = "field";
+    private static final String VALUE_EL = "value";
+    private static final String VALIDATION_MSG_EL = "validation-message";
+
+    /** Overrides selection list defined in FieldDefinition, if any. */
+    protected SelectionList selectionList;
+    /** Additional listeners to those defined as part of the widget definition (if any). */
+    private ValueChangedListener listener;
+
+    private final FieldDefinition fieldDefinition;
+
+    protected String enteredValue;
+    protected Object value;
+
+    /**
+     * Value state indicating that a new value has been read from the request,
+     * but has not yet been parsed.
+     */
+    protected final static int VALUE_UNPARSED = 0;
+
+    /**
+     * Value state indicating that a value has been parsed, but needs to be
+     * validated (that must occur before the value is given to the application)
+     */
+    protected final static int VALUE_PARSED = 1;
+
+    /**
+     * Value state indicating that a parse error was encountered but should not
+     * yet be displayed.
+     */
+    protected final static int VALUE_PARSE_ERROR = 2;
+
+    /**
+     * Value state indicating that validate() has been called when state was
+     * VALUE_PARSE_ERROR. This makes the error visible on output.
+     */
+    protected final static int VALUE_DISPLAY_PARSE_ERROR = 3;
+
+    /**
+     * Transient value state indicating that validation is going on.
+     *
+     * @see #validate()
+     */
+    protected final static int VALUE_VALIDATING = 4;
+
+    /**
+     * Value state indicating that validation has occured, but that any error should not
+     * yet be displayed.
+     */
+    protected final static int VALUE_VALIDATED = 5;
+
+    /**
+     * Value state indicating that value validation has occured, and the
+     * validation error, if any, should be displayed.
+     */
+    protected final static int VALUE_DISPLAY_VALIDATION = 6;
+
+    // At startup, we have no value to parse (both enteredValue and value are null),
+    // but need to validate (e.g. error if field is required)
+    /**
+     * Transient widget processing state indicating that the widget is currently validating
+     * (used to avoid endless loops when a validator calls getValue)
+     */
+    protected int valueState = VALUE_PARSED;
+
+    protected ValidationError validationError;
+
+
+    public Field(FieldDefinition fieldDefinition) {
+        super(fieldDefinition);
+        this.fieldDefinition = fieldDefinition;
+        this.listener = fieldDefinition.getValueChangedListener();
+    }
+
+    public final FieldDefinition getFieldDefinition() {
+        return this.fieldDefinition;
+    }
+
+    public WidgetDefinition getDefinition() {
+        return this.fieldDefinition;
+    }
+
+    public void initialize() {
+        Object value = this.fieldDefinition.getInitialValue();
+        if (value != null) {
+            setValue(value);
+        }
+        this.selectionList = this.fieldDefinition.getSelectionList();
+        super.initialize();
+    }
+
+    public Object getValue() {
+        // if getValue() is called on this field while we're validating, then it's because a validation
+        // rule called getValue(), so then we just return the parsed (but not VALUE_VALIDATED) value to avoid an endless loop
+        if (this.valueState == VALUE_VALIDATING) {
+            return this.value;
+        }
+
+        ValidationError oldError = this.validationError;
+
+        // Parse the value
+        if (this.valueState == VALUE_UNPARSED) {
+            doParse();
+        }
+
+        // Validate the value if it was successfully parsed
+        if (this.valueState == VALUE_PARSED) {
+            doValidate();
+        }
+
+        if (oldError != null && this.validationError == null) {
+            // The parsing process removed an existing validation error. This happens
+            // mainly when a required field is given a value.
+            getForm().addWidgetUpdate(this);
+        }
+
+        return this.validationError == null ? this.value : null;
+    }
+
+    public void setValue(Object newValue) {
+        if (newValue != null && !getDatatype().getTypeClass().isAssignableFrom(newValue.getClass())) {
+            throw new RuntimeException("Incorrect value type for \"" + getRequestParameterName() +
+                           "\" (expected " + getDatatype().getTypeClass() +
+                           ", got " + newValue.getClass() + ").");
+        }
+
+        // Is it a new value?
+        boolean changed;
+        if (this.valueState == VALUE_UNPARSED) {
+            // Current value was not parsed
+            changed = true;
+        } else if (this.value == null) {
+            // Is current value not null?
+            changed = (newValue != null);
+        } else {
+            // Is current value different?
+            changed = !this.value.equals(newValue);
+        }
+
+        // Do something only if value is different or null
+        // (null allows to reset validation error)
+        if (changed || newValue == null) {
+            // Do we need to call listeners? If yes, keep (and parse if needed) old value.
+            boolean callListeners = changed && hasValueChangedListeners();
+            Object oldValue = callListeners ? getValue() : null;
+
+            this.value = newValue;
+            this.validationError = null;
+            // Force validation, even if set by the application
+            this.valueState = VALUE_PARSED;
+            if (newValue != null) {
+                this.enteredValue = getDatatype().convertToString(newValue, getForm().getLocale());
+            } else {
+                this.enteredValue = null;
+            }
+
+            if (callListeners) {
+                getForm().addWidgetEvent(new ValueChangedEvent(this, oldValue, newValue));
+            }
+            getForm().addWidgetUpdate(this);
+        }
+    }
+
+    public void readFromRequest(FormContext formContext) {
+        if (!getCombinedState().isAcceptingInputs()) {
+            return;
+        }
+
+        String newEnteredValue = formContext.getRequest().getParameter(getRequestParameterName());
+        // FIXME: Should we consider only non-null values?
+        // Although distinguishing an empty value (input present but blank) from a null value
+        // (input not present in the form) is possible, this distinction is not possible for
+        // several other kinds of widgets such as BooleanField or MultiValueField. So we keep
+        // it consistent with other widgets.
+        //if (newEnteredValue != null) {
+        readFromRequest(newEnteredValue);
+        //}
+    }
+
+    protected void readFromRequest(String newEnteredValue) {
+        // whitespace & empty field handling
+        if (newEnteredValue != null) {
+            // TODO make whitespace behaviour configurable !!
+            newEnteredValue = newEnteredValue.trim();
+            if (newEnteredValue.length() == 0) {
+                newEnteredValue = null;
+            }
+        }
+
+        // Only convert if the text value actually changed. Otherwise, keep the old value
+        // and/or the old validation error (allows to keep errors when clicking on actions)
+        boolean changed;
+        if (enteredValue == null) {
+            changed = (newEnteredValue != null);
+        } else {
+            changed = !enteredValue.equals(newEnteredValue);
+        }
+
+        if (changed) {
+            ValidationError oldError = this.validationError;
+
+            // If we have some value-changed listeners, we must make sure the current value has been
+            // parsed, to fill the event. Otherwise, we don't need to spend that extra CPU time.
+            boolean hasListeners = hasValueChangedListeners();
+            Object oldValue = hasListeners ? getValue() : null;
+
+            enteredValue = newEnteredValue;
+            validationError = null;
+            value = null;
+            this.valueState = VALUE_UNPARSED;
+
+            if (hasListeners) {
+                // Throw an event that will hold the old value and
+                // will lazily compute the new value only if needed.
+                getForm().addWidgetEvent(new DeferredValueChangedEvent(this, oldValue));
+            }
+
+            if (oldError != null) {
+                // There was a validation error, and the user entered a new value: refresh
+                // the widget, because the previous error was cleared
+                getForm().addWidgetUpdate(this);
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.cocoon.forms.formmodel.Widget#validate()
+     */
+    public boolean validate() {
+        if (!getCombinedState().isValidatingValues()) {
+            this.wasValid = true;
+            return true;
+        }
+
+        if (this.valueState == VALUE_UNPARSED) {
+            doParse();
+        }
+
+        // Force validation on already validated values (but keep invalid parsings)
+        if (this.valueState >= VALUE_VALIDATED) {
+            this.valueState = VALUE_PARSED;
+        }
+
+        if (this.valueState == VALUE_PARSED) {
+            doValidate();
+            this.valueState = VALUE_DISPLAY_VALIDATION;
+            if (this.validationError != null) {
+                getForm().addWidgetUpdate(this);
+            }
+        } else if (this.valueState == VALUE_PARSE_ERROR) {
+            this.valueState = VALUE_DISPLAY_PARSE_ERROR;
+            getForm().addWidgetUpdate(this);
+        }
+
+        this.wasValid = this.validationError == null;
+        return this.wasValid;
+    }
+
+    /**
+     * Parse the value that has been read from the request.
+     * Should be called when valueState is VALUE_UNPARSED.
+     * On exit, valueState is set to either:
+     * - VALUE_PARSED: successful parsing or null value. Value is set and ValidationError
+     *   is cleared.
+     * - VALUE_PARSE_ERROR: datatype parsing error. In that case, value is null and
+     *   validationError is set.
+     */
+    private void doParse() {
+        if (this.valueState != VALUE_UNPARSED) {
+            throw new IllegalStateException("Field is not in UNPARSED state (" + this.valueState + ")");
+        }
+
+        // Clear value, it will be recomputed
+        this.value = null;
+        this.validationError = null;
+
+        if (this.enteredValue != null) {
+            // Parse the value
+            ConversionResult conversionResult = getDatatype().convertFromString(this.enteredValue, getForm().getLocale());
+            if (conversionResult.isSuccessful()) {
+                this.value = conversionResult.getResult();
+                this.valueState = VALUE_PARSED;
+            } else {
+                // Conversion failed
+                this.validationError = conversionResult.getValidationError();
+                // No need for further validation (and need to keep the above error)
+                this.valueState = VALUE_PARSE_ERROR;
+            }
+        } else {
+            // No value: needs to be validated
+            this.valueState = VALUE_PARSED;
+        }
+    }
+
+    /**
+     * Validate the value once it has been parsed.
+     * Should be called when valueState is VALUE_PARSED.
+     * On exit, valueState is set to VALUE_VALIDATED, and validationError is set if
+     * validation failed.
+     */
+    private void doValidate() {
+        if (this.valueState != VALUE_PARSED) {
+            throw new IllegalStateException("Field is not in PARSED state (" + this.valueState + ")");
+        }
+
+        // Go to transient validating state
+        this.valueState = VALUE_VALIDATING;
+
+        // reset validation errot
+        this.validationError = null;
+
+        try {
+            if (this.value == null && getFieldDefinition().isRequired()) {
+                // Field is required
+                this.validationError = new ValidationError(new I18nMessage("general.field-required", FormsConstants.I18N_CATALOGUE));
+            } else if (!super.validate()) {
+                // New-style validators failed.
+            } else if (this.value != null) {
+                // Check the old-style ones.
+                this.validationError = getDatatype().validate(this.value, new ExpressionContextImpl(this));
+            }
+        } finally {
+            // Consider validation finished even in case of exception
+            this.valueState = VALUE_VALIDATED;
+        }
+    }
+
+    /**
+     * Returns the validation error, if any. There will always be a validation error in case the
+     * {@link #validate} method returned false.
+     *
+     * <br>This method does not cause parsing to take effect, use {@link #getValue} if value
+     * is not parsed yet.
+     */
+    public ValidationError getValidationError() {
+        return this.validationError;
+    }
+
+    /**
+     * Set a validation error on this field. This allows fields to be externally marked as invalid by
+     * application logic.
+     *
+     * @param error the validation error
+     */
+    public void setValidationError(ValidationError error) {
+        if (this.valueState >= VALUE_VALIDATED) {
+            this.valueState = VALUE_DISPLAY_VALIDATION;
+        }
+
+        if (!ObjectUtils.equals(this.validationError, error)) {
+            this.validationError = error;
+            getForm().addWidgetUpdate(this);
+        }
+    }
+
+    public boolean isRequired() {
+        return getFieldDefinition().isRequired();
+    }
+
+    /**
+     * @return "field"
+     */
+    public String getXMLElementName() {
+        return FIELD_EL;
+    }
+
+    /**
+     * Adds the @required attribute
+     */
+    public AttributesImpl getXMLElementAttributes() {
+        AttributesImpl attrs = super.getXMLElementAttributes();
+        attrs.addCDATAAttribute("required", String.valueOf(isRequired()));
+        return attrs;
+    }
+
+    public void generateItemSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException {
+        if (locale == null) {
+            locale = getForm().getLocale();
+        }
+
+        if (enteredValue != null || value != null) {
+            contentHandler.startElement(FormsConstants.INSTANCE_NS, VALUE_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALUE_EL, XMLUtils.EMPTY_ATTRIBUTES);
+            String stringValue;
+            if (value != null) {
+                stringValue = getDatatype().convertToString(value, locale);
+            } else {
+                stringValue = enteredValue;
+            }
+            contentHandler.characters(stringValue.toCharArray(), 0, stringValue.length());
+            contentHandler.endElement(FormsConstants.INSTANCE_NS, VALUE_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALUE_EL);
+        }
+
+        // validation message element: only present if the value is not valid
+        if (validationError != null && (this.valueState == VALUE_DISPLAY_VALIDATION || this.valueState == VALUE_DISPLAY_PARSE_ERROR)) {
+            contentHandler.startElement(FormsConstants.INSTANCE_NS, VALIDATION_MSG_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_MSG_EL, XMLUtils.EMPTY_ATTRIBUTES);
+            validationError.generateSaxFragment(contentHandler);
+            contentHandler.endElement(FormsConstants.INSTANCE_NS, VALIDATION_MSG_EL, FormsConstants.INSTANCE_PREFIX_COLON + VALIDATION_MSG_EL);
+        }
+
+        // generate selection list, if any
+        if (selectionList != null) {
+            selectionList.generateSaxFragment(contentHandler, locale);
+        }
+
+        // include some info about the datatype
+        fieldDefinition.getDatatype().generateSaxFragment(contentHandler, locale);
+    }
+
+
+    /**
+     * Set this field's selection list.
+     * @param selectionList The new selection list.
+     */
+    public void setSelectionList(SelectionList selectionList) {
+        if (selectionList != null &&
+            selectionList.getDatatype() != null &&
+            selectionList.getDatatype() != getDatatype()) {
+            throw new RuntimeException("Tried to assign a SelectionList that is not associated with this widget's datatype.");
+        }
+        this.selectionList = selectionList;
+        getForm().addWidgetUpdate(this);
+    }
+
+    /**
+     * Read this field's selection list from an external source.
+     * All Cocoon-supported protocols can be used.
+     * The format of the XML produced by the source should be the
+     * same as in case of inline specification of the selection list,
+     * thus the root element should be a <code>fd:selection-list</code>
+     * element.
+     * @param uri The URI of the source.
+     */
+    public void setSelectionList(String uri) {
+        setSelectionList(getFieldDefinition().buildSelectionList(uri));
+    }
+
+    /**
+     * Set this field's selection list using values from an in-memory
+     * object. The <code>object</code> parameter should point to a collection
+     * (Java collection or array, or Javascript array) of objects. Each object
+     * belonging to the collection should have a <em>value</em> property and a
+     * <em>label</em> property, whose values are used to specify the <code>value</code>
+     * attribute and the contents of the <code>fd:label</code> child element
+     * of every <code>fd:item</code> in the list.
+     * <p>Access to the values of the above mentioned properties is done
+     * via <a href="http://jakarta.apache.org/commons/jxpath/users-guide.html">XPath</a> expressions.
+     * @param model The collection used as a model for the selection list.
+     * @param valuePath An XPath expression referring to the attribute used
+     * to populate the values of the list's items.
+     * @param labelPath An XPath expression referring to the attribute used
+     * to populate the labels of the list's items.
+     */
+    public void setSelectionList(Object model, String valuePath, String labelPath) {
+        setSelectionList(getFieldDefinition().buildSelectionListFromModel(model, valuePath, labelPath));
+    }
+    
+    public SelectionList getSuggestionList() {
+        return getFieldDefinition().getSuggestionList();
+    }
+
+    public Datatype getDatatype() {
+        return getFieldDefinition().getDatatype();
+    }
+
+    /**
+     * Adds a ValueChangedListener to this widget instance. Listeners defined
+     * on the widget instance will be executed in addtion to any listeners
+     * that might have been defined in the widget definition.
+     */
+    public void addValueChangedListener(ValueChangedListener listener) {
+        this.listener = WidgetEventMulticaster.add(this.listener, listener);
+    }
+
+    public void removeValueChangedListener(ValueChangedListener listener) {
+        this.listener = WidgetEventMulticaster.remove(this.listener, listener);
+    }
+
+    public boolean hasValueChangedListeners() {
+        return this.listener != null || this.getForm().hasFormHandler();
+    }
+
+    public void broadcastEvent(WidgetEvent event) {
+        if (event instanceof ValueChangedEvent) {
+            if (this.listener != null) {
+                this.listener.valueChanged((ValueChangedEvent)event);
+            }
+        } else {
+            // Other kinds of events
+            super.broadcastEvent(event);
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Field.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.apache.cocoon.forms.datatype.SelectionList;
+
+/**
+ * The {@link WidgetDefinition} part of a Field widget, see {@link Field} for more information.
+ * 
+ * @version $Id: FieldDefinition.java 292158 2005-09-28 10:24:51Z sylvain $
+ */
+public class FieldDefinition extends AbstractDatatypeWidgetDefinition {
+    private boolean required;
+    private SelectionList suggestionList;
+
+    public Widget createInstance() {
+        Field field = new Field(this);
+        return field;
+    }
+    
+    /**
+     * initialize this definition with the other, sort of like a copy constructor
+     */
+    public void initializeFrom(WidgetDefinition definition) throws Exception {
+        if(!(definition instanceof FieldDefinition)) {
+            throw new Exception("Definition to inherit from is not of the right type! (at "+getLocation()+")");
+        }
+        super.initializeFrom(definition);
+        
+        FieldDefinition other = (FieldDefinition)definition;
+        
+        this.required = other.required;
+        
+        if (suggestionList == null) {
+            suggestionList = other.getSuggestionList();
+        }
+    }
+
+    public boolean isRequired() {
+        return required;
+    }
+
+    public void setRequired(boolean required) {
+        checkMutable();
+        this.required = required;
+    }
+
+    public SelectionList getSuggestionList() {
+        return this.suggestionList;
+    }
+
+    public void setSuggestionList(SelectionList list) {
+        this.suggestionList = list;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinition.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,48 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.apache.cocoon.forms.datatype.SelectionList;
+import org.apache.cocoon.forms.util.DomHelper;
+import org.w3c.dom.Element;
+
+/**
+ * Builds {FieldDefinition}s.
+ *
+ * @version $Id: FieldDefinitionBuilder.java 327125 2005-10-21 08:52:51Z sylvain $
+ */
+public class FieldDefinitionBuilder extends AbstractDatatypeWidgetDefinitionBuilder {
+
+    public WidgetDefinition buildWidgetDefinition(Element widgetElement) throws Exception {
+        FieldDefinition definition = new FieldDefinition();
+        setupDefinition(widgetElement, definition);
+        definition.makeImmutable();
+        return definition;
+    }
+
+    protected void setupDefinition(Element widgetElement, FieldDefinition definition) throws Exception {
+        super.setupDefinition(widgetElement, definition);
+        
+        // parse "@required"
+        if(widgetElement.hasAttribute("required"))
+            definition.setRequired(DomHelper.getAttributeAsBoolean(widgetElement, "required", false));
+        
+        SelectionList list = buildSelectionList(widgetElement, definition, "suggestion-list");
+        if (list != null) {
+            definition.setSuggestionList(list);
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FieldDefinitionBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,425 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.cocoon.forms.FormContext;
+import org.apache.cocoon.forms.event.FormHandler;
+import org.apache.cocoon.forms.event.ProcessingPhase;
+import org.apache.cocoon.forms.event.ProcessingPhaseEvent;
+import org.apache.cocoon.forms.event.ProcessingPhaseListener;
+import org.apache.cocoon.forms.event.WidgetEvent;
+import org.apache.cocoon.forms.event.WidgetEventMulticaster;
+import org.apache.cocoon.forms.validation.ValidationError;
+import org.apache.cocoon.forms.validation.ValidationErrorAware;
+import org.apache.commons.collections.list.CursorableLinkedList;
+import org.apache.commons.lang.BooleanUtils;
+
+/**
+ * A widget that serves as a container for other widgets, the top-level widget in
+ * a form description file.
+ *
+ * @author Bruno Dumon
+ * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
+ * @version $Id: Form.java 326930 2005-10-20 16:03:19Z sylvain $
+ */
+public class Form extends AbstractContainerWidget
+                  implements ValidationErrorAware {
+
+    private static final String FORM_EL = "form";
+
+    private final FormDefinition definition;
+
+    /**
+     * If non-null, indicates that form processing should terminate at the end of the current phase.
+     * If true, interaction with the form is finished. It doesn't imply that the form is valid though.
+     * If false, interaction isn't finished and the form should be redisplayed (processing was triggered
+     * by e.g. and action or a field with event listeners).
+     */
+    private Boolean endProcessing;
+    private Locale locale = Locale.getDefault();
+    private FormHandler formHandler;
+    private Widget submitWidget;
+    private ProcessingPhase phase = ProcessingPhase.LOAD_MODEL;
+    private boolean isValid = false;
+    private ProcessingPhaseListener listener;
+
+    //In the "readFromRequest" phase, events are buffered to ensure that all widgets had the chance
+    //to read their value before events get fired.
+    private boolean bufferEvents = false;
+    private CursorableLinkedList events;
+
+    // Widgets that need to be updated in the client when in AJAX mode
+    private Set updatedWidgets;
+    // Widgets that have at least one descendant that has to be updated
+    private Set childUpdatedWidgets;
+
+
+    public Form(FormDefinition definition) {
+        super(definition);
+        this.definition = definition;
+    }
+
+    /**
+     * Initialize the form by recursively initializing all its children. Any events occuring within the
+     * initialization phase are buffered and fired after initialization is complete, so that any action
+     * from a widget on another one occurs after that other widget has been given the opportunity to
+     * initialize itself.
+     */
+    public void initialize() {
+        try {
+            // Start buffering events
+            this.bufferEvents = true;
+            super.initialize();
+            // Fire events, still buffering them: this ensures they will be handled in the same
+            // order as they were added.
+            fireEvents();
+        } finally {
+            // Stop buffering events
+            this.bufferEvents = false;
+        }
+    }
+
+    public WidgetDefinition getDefinition() {
+        return this.definition;
+    }
+
+    /**
+     * Events produced by child widgets should not be fired immediately, but queued in order to ensure
+     * an overall consistency of the widget tree before being handled.
+     *
+     * @param event the event to queue
+     */
+    public void addWidgetEvent(WidgetEvent event) {
+
+        if (this.bufferEvents) {
+            if (this.events == null) {
+                this.events = new CursorableLinkedList();
+            }
+
+            // FIXME: limit the number of events to detect recursive event loops ?
+            this.events.add(event);
+        } else {
+            // Send it right now
+            event.getSourceWidget().broadcastEvent(event);
+        }
+    }
+
+    /**
+     * Mark a widget as being updated. When it Ajax mode, only updated widgets will be redisplayed
+     * 
+     * @param widget the updated widget
+     * @return <code>true</code> if this widget was added to the list (i.e. wasn't alredy marked for update)
+     */
+    public boolean addWidgetUpdate(Widget widget) {
+        if (this.updatedWidgets != null) {
+            if (this.updatedWidgets.add(widget.getRequestParameterName())) {
+                // Wasn't already there: register parents
+                Widget parent = widget.getParent();
+                addParents: while (parent != this && parent != null) {
+                    if (this.childUpdatedWidgets.add(parent.getRequestParameterName())) {
+                        parent = parent.getParent();
+                    } else {
+                        // Parent already there, and therefore its own parents.
+                        break addParents;
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public Set getUpdatedWidgetIds() {
+        return this.updatedWidgets;
+    }
+
+    public Set getChildUpdatedWidgetIds() {
+        return this.childUpdatedWidgets;
+    }
+
+    /**
+     * Fire the events that have been queued.
+     * Note that event handling can fire new events.
+     */
+    private void fireEvents() {
+        if (this.events != null) {
+            CursorableLinkedList.Cursor cursor = this.events.cursor();
+            while(cursor.hasNext()) {
+                WidgetEvent event = (WidgetEvent)cursor.next();
+                event.getSourceWidget().broadcastEvent(event);
+                if (formHandler != null)
+                    formHandler.handleEvent(event);
+            }
+            cursor.close();
+
+            this.events.clear();
+        }
+    }
+
+    /**
+     * Get the locale to be used to process this form.
+     *
+     * @return the form's locale.
+     */
+    public Locale getLocale() {
+        return this.locale;
+    }
+
+    /**
+     * Get the widget that triggered the current processing. Note that it can be any widget, and
+     * not necessarily an action or a submit.
+     *
+     * @return the widget that submitted this form.
+     */
+    public Widget getSubmitWidget() {
+        return this.submitWidget;
+    }
+
+    /**
+     * Set the widget that triggered the current form processing.
+     *
+     * @param widget the widget
+     */
+    public void setSubmitWidget(Widget widget) {
+        if (this.submitWidget != null && this.submitWidget != widget) {
+            throw new IllegalStateException("Submit widget already set to " + this.submitWidget +
+                    ". Cannot set also " + widget);
+        }
+        
+        // Check that the submit widget is active
+        if (widget.getCombinedState() != WidgetState.ACTIVE) {
+            throw new IllegalStateException("Widget " + widget + " that submitted the form is not active.");
+        }
+        
+        // If the submit widget is not an action (e.g. a field with an event listener),
+        // we end form processing after the current phase and redisplay the form.
+        // Actions (including submits) will call endProcessing() themselves and it's their
+        // responsibility to indicate how form processing should continue.
+        if (!(widget instanceof Action)) {
+            endProcessing(true);
+        }
+        this.submitWidget = widget;
+    }
+
+    public boolean hasFormHandler() {
+       return (this.formHandler != null);
+    }
+
+    public void setFormHandler(FormHandler formHandler) {
+        this.formHandler = formHandler;
+    }
+
+// TODO: going through the form for load and save ensures state consistency. To we add this or
+// keep the binding strictly separate ?
+//    public void load(Object data, Binding binding) {
+//        if (this.phase != ProcessingPhase.LOAD_MODEL) {
+//            throw new IllegalStateException("Cannot load form in phase " + this.phase);
+//        }
+//        binding.loadFormFromModel(this, data);
+//    }
+//
+//    public void save(Object data, Binding binding) throws BindingException {
+//        if (this.phase != ProcessingPhase.VALIDATE) {
+//            throw new IllegalStateException("Cannot save model in phase " + this.phase);
+//        }
+//
+//        if (!isValid()) {
+//            throw new IllegalStateException("Cannot save an invalid form.");
+//        }
+//        this.phase = ProcessingPhase.SAVE_MODEL;
+//        binding.saveFormToModel(this, data);
+//    }
+
+    public void addProcessingPhaseListener(ProcessingPhaseListener listener) {
+        this.listener = WidgetEventMulticaster.add(this.listener, listener);
+    }
+
+    public void removeProcessingPhaseListener(ProcessingPhaseListener listener) {
+        this.listener = WidgetEventMulticaster.remove(this.listener, listener);
+    }
+
+    /**
+     * Processes a form submit. If the form is finished, i.e. the form should not be redisplayed to the user,
+     * then this method returns true, otherwise it returns false. To know if the form was sucessfully
+     * validated, use the {@link #isValid()} method.
+     * <p>
+     * Form processing consists in multiple steps:
+     * <ul>
+     *  <li>all widgets read their value from the request (i.e.
+     *      {@link #readFromRequest(FormContext)} is called recursively on
+     *       the whole widget tree)
+     *  <li>if there is an action event, call the FormHandler
+     *  <li>perform validation.
+     * </ul>
+     * This processing can be interrupted by the widgets (or their event listeners) by calling
+     * {@link #endProcessing(boolean)}.
+     * <p>
+     * Note that this method is synchronized as a Form is not thread-safe. This should not be a
+     * bottleneck as such concurrent requests can only happen for a single user.
+     */
+    public synchronized boolean process(FormContext formContext) {
+        // Is this an AJAX request?
+        if (formContext.getRequest().getParameter("cocoon-ajax") != null) {
+            this.updatedWidgets = new HashSet();
+            this.childUpdatedWidgets = new HashSet();
+        }
+
+        // Fire the binding phase events
+        fireEvents();
+
+        // setup processing
+        this.submitWidget = null;
+        this.locale = formContext.getLocale();
+        this.endProcessing = null;
+        this.isValid = false;
+
+        // Notify the end of the current phase
+        if (this.listener != null) {
+            this.listener.phaseEnded(new ProcessingPhaseEvent(this, this.phase));
+        }
+
+        this.phase = ProcessingPhase.READ_FROM_REQUEST;
+        // Find the submit widget, if not an action
+        this.submitWidget = null;
+        String submitId = formContext.getRequest().getParameter("forms_submit_id");
+        if (submitId != null && submitId.length() > 0) {
+            // if the form has an ID, it is used as part of the submitId too
+            // this has ID has to be cut off
+            if(this.getId() != null && !"".equals(this.getId())) {
+                submitId = submitId.substring(submitId.indexOf('.')+1);
+            }
+            StringTokenizer stok = new StringTokenizer(submitId, ".");
+            Widget submit = this;
+            while (stok.hasMoreTokens()) {
+                submit = submit.lookupWidget(stok.nextToken());
+                if (submit == null) {
+                    throw new IllegalArgumentException("Invalid submit id (no such widget): " + submitId);
+                }
+            }
+
+            setSubmitWidget(submit);
+        }
+
+        try {
+            // Start buffering events
+            this.bufferEvents = true;
+
+            doReadFromRequest(formContext);
+
+            // Fire events, still buffering them: this ensures they will be handled in the same
+            // order as they were added.
+            fireEvents();
+        } finally {
+            // No need for buffering in the following phases
+            this.bufferEvents = false;
+        }
+
+        // Notify the end of the current phase
+        if (this.listener != null) {
+            this.listener.phaseEnded(new ProcessingPhaseEvent(this, this.phase));
+        }
+        if (this.endProcessing != null) {
+            return this.endProcessing.booleanValue();
+        }
+
+        return validate();
+    }
+
+    /**
+     * End the current form processing after the current phase.
+     *
+     * @param redisplayForm indicates if the form should be redisplayed to the user.
+     */
+    public void endProcessing(boolean redisplayForm) {
+        // Set the indicator that terminates the form processing.
+        // If redisplayForm is true, interaction is not finished and process() must
+        // return false, hence the negation below.
+        this.endProcessing = BooleanUtils.toBooleanObject( !redisplayForm );
+    }
+
+    /**
+     * Was form validation successful ?
+     *
+     * @return <code>true</code> if the form was successfully validated.
+     */
+    public boolean isValid() {
+        return this.isValid;
+    }
+
+    public void readFromRequest(FormContext formContext) {
+        throw new UnsupportedOperationException("Please use Form.process()");
+    }
+
+    private void doReadFromRequest(FormContext formContext) {
+        // let all individual widgets read their value from the request object
+        super.readFromRequest(formContext);
+    }
+
+    /**
+     * Set a validation error on this field. This allows the form to be externally marked as invalid by
+     * application logic.
+     *
+     * @return the validation error
+     */
+    public ValidationError getValidationError() {
+        return this.validationError;
+    }
+
+    /**
+     * set a validation error
+     */
+    public void setValidationError(ValidationError error) {
+        this.validationError = error;
+    }
+
+    /**
+     * Performs validation phase of form processing.
+     */
+    public boolean validate() {
+        // Validate the form
+        this.phase = ProcessingPhase.VALIDATE;
+        this.isValid = super.validate();
+
+        // FIXME: Is this check needed, before invoking the listener?
+        if (this.endProcessing != null) {
+            this.wasValid = this.endProcessing.booleanValue();
+            return this.wasValid;
+        }
+
+        // Notify the end of the current phase
+        if (this.listener != null) {
+            this.listener.phaseEnded(new ProcessingPhaseEvent(this, this.phase));
+        }
+        if (this.endProcessing != null) {
+            // De-validate the form if one of the listeners asked to end the processing
+            // This allows for additional application-level validation.
+            this.isValid = false;
+            this.wasValid = this.endProcessing.booleanValue();
+            return this.wasValid;
+        }
+        this.wasValid = this.isValid && this.validationError == null;
+        return this.wasValid;
+    }
+
+    public String getXMLElementName() {
+        return FORM_EL;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Form.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinition.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinition.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinition.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cocoon.forms.event.ProcessingPhaseEvent;
+import org.apache.cocoon.forms.event.ProcessingPhaseListener;
+import org.apache.cocoon.forms.event.WidgetEventMulticaster;
+import org.apache.cocoon.forms.formmodel.library.Library;
+import org.apache.cocoon.forms.formmodel.library.LibraryManager;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * The {@link WidgetDefinition} part of a Form widget, see {@link Form} for more information.
+ * 
+ * @version $Id: FormDefinition.java 291005 2005-09-22 19:08:29Z sylvain $
+ */
+public class FormDefinition extends AbstractContainerDefinition {
+    private ProcessingPhaseListener listener;
+    
+    private Library localLibrary = null;
+
+    public FormDefinition(LibraryManager libraryManager) {
+        super();
+        localLibrary = libraryManager.getNewLibrary();
+    }
+    
+    public Library getLocalLibrary() {
+    	return localLibrary;
+    }
+
+    public void resolve() throws Exception {
+        List parents = new ArrayList();
+        parents.add(this);
+        resolve(parents, this);
+        
+        // TODO: test if this actually gets called!
+        checkCompleteness();
+    }
+
+    public Widget createInstance() {
+        Form form = new Form(this);
+        createWidgets(form);
+        return form;
+    }
+    
+    public void addProcessingPhaseListener(ProcessingPhaseListener listener) {
+        this.listener = WidgetEventMulticaster.add(this.listener, listener);
+    }
+    
+    public boolean hasProcessingPhaseListeners() {
+        return this.listener != null;
+    }
+    
+    public void fireEvent(ProcessingPhaseEvent event) {
+        if (this.listener != null) {
+            this.listener.phaseEnded(event);
+        }
+    }
+    
+    public void addWidgetDefinition(WidgetDefinition definition) throws Exception, DuplicateIdException {
+        // Check that no child is named "submit" if this form has no id. This causes some weird behaviour
+        // in HTML as it collides with the submit() function on the <form> element...
+        if ("submit".equals(definition.getId()) && StringUtils.isEmpty(this.getId())) {
+            throw new IllegalArgumentException("Top-level widgets should not be named 'submit' to avoid problems "
+                    + " with HTML <form> elements, at " + definition.getLocation());
+        }
+
+        super.addWidgetDefinition(definition);
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinition.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.forms.formmodel.library.LibraryManager;
+import org.apache.cocoon.util.location.LocationAttributes;
+import org.w3c.dom.Element;
+
+/**
+ * Builds {@link FormDefinition}s.
+ * 
+ * @version $Id: FormDefinitionBuilder.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public final class FormDefinitionBuilder extends AbstractContainerDefinitionBuilder {
+
+	protected LibraryManager libraryManager;
+	
+	public void service(ServiceManager manager) throws ServiceException {
+		super.service(manager);
+		
+		libraryManager = (LibraryManager) serviceManager.lookup(LibraryManager.ROLE);
+	}
+	
+	public WidgetDefinition buildWidgetDefinition(Element widgetElement, WidgetDefinitionBuilderContext context) throws Exception {
+    	throw new UnsupportedOperationException("Please use the other signature without WidgetDefinitionBuilderContext!");
+    }
+	
+    public WidgetDefinition buildWidgetDefinition(Element formElement) throws Exception {
+        FormDefinition formDefinition = new FormDefinition(libraryManager);
+        this.context = new WidgetDefinitionBuilderContext();
+        this.context.setLocalLibrary(formDefinition.getLocalLibrary());
+        
+        // set local URI
+        formDefinition.getLocalLibrary().setSourceURI(LocationAttributes.getURI(formElement));
+        
+        super.setupDefinition(formElement, formDefinition);
+        setDisplayData(formElement, formDefinition);
+
+        setupContainer(formElement,"widgets",formDefinition);
+
+        formDefinition.resolve();
+
+        formDefinition.makeImmutable();
+        
+        this.context = null;
+        return formDefinition;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/FormDefinitionBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Group.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Group.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Group.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Group.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+
+/**
+ * A container {@link Widget} which can hold zero or more child widgets.
+ *
+ * @version $Id: Group.java 155211 2005-02-24 17:05:51Z sylvain $
+ */
+public class Group extends AbstractContainerWidget {
+    private static final String GROUP_EL = "group";
+    
+    private final GroupDefinition definition; 
+
+    public Group(GroupDefinition definition) {
+        super(definition);
+        this.definition = definition;
+    }
+    
+    public WidgetDefinition getDefinition() {
+        return this.definition;
+    }
+    
+    /**
+     * @return "group"
+     */
+    public String getXMLElementName() {
+        return GROUP_EL;
+    }
+    
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/Group.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinition.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinition.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinition.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+/**
+ * The {@link WidgetDefinition} corresponding to a {@link Group} widget.
+ *
+ * @version $Id: GroupDefinition.java 149397 2005-02-01 13:49:55Z tim $
+ */
+public class GroupDefinition extends AbstractContainerDefinition {
+
+    public Widget createInstance() {
+        Group groupWidget = new Group(this);
+        createWidgets(groupWidget);
+        return groupWidget;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinition.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.w3c.dom.Element;
+
+/**
+ * Builds {GroupDefinition}s.
+ *
+ * @version $Id: GroupDefinitionBuilder.java 289538 2005-09-16 13:46:22Z sylvain $
+ */
+public final class GroupDefinitionBuilder extends AbstractContainerDefinitionBuilder {
+
+    public WidgetDefinition buildWidgetDefinition(Element element) throws Exception {
+        GroupDefinition definition = new GroupDefinition();
+        
+        super.setupDefinition(element, definition);
+        setDisplayData(element, definition);
+
+        setupContainer(element,"widgets",definition);
+        
+        definition.makeImmutable();
+        return definition;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/GroupDefinitionBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMap.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMap.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMap.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMap.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,192 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */package org.apache.cocoon.forms.formmodel;
+
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.forms.FormContext;
+import org.apache.cocoon.forms.event.*;
+import org.apache.cocoon.xml.AttributesImpl;
+
+/**
+ * A server-side map widget. An ImageMap widget can cause a {@link ImageMapEvent} to be triggered
+ * on the server side, which will be handled by either the event handlers defined in the
+ * form definition, and/or by the {@link org.apache.cocoon.forms.event.FormHandler FormHandler}
+ * registered with the form, if any. An ImageMap widget is basically an Action widget
+ * displayed as an image and with mouse coordinates stored upon clicking.
+ * The image's URI can be set or get, or bind via the binding framework, mouse coordinates
+ * can be either retrieved from the ImageMapEvent triggered or from the widget itself.
+ * 
+ * @version $Id$
+ * @since 2.1.8
+ */
+public class ImageMap extends AbstractWidget implements ActionListenerEnabled {
+
+	private final ImageMapDefinition definition;
+    private ActionListener listener;
+    private String imgURI; // URI of widget's image
+	private int x; // Mouse x coordinate
+	private int y; // Mouse y coordinate
+
+	// XML element and attributes
+	public static final String COMMAND_AT = "command";
+	public static final String VALUE_EL = "imageuri";
+	public static final String ONACTION_EL = "on-action";
+	public static final String IMAGEMAP_EL = "imagemap";
+
+    public ImageMap(ImageMapDefinition definition) {
+        super(definition);
+        this.definition = definition;
+    	this.imgURI= definition.getImageURI();
+    	this.x= 0;
+    	this.y= 0;
+    }
+
+    public WidgetDefinition getDefinition() {
+        return this.definition;
+    }
+
+    // Retrieves mouse coordinates
+    public int getX() {
+    	return this.x;
+    }
+    
+    public int getY() {
+    	return this.y;
+    }
+    
+    // Get/set image URI
+    public String getImageURI() {
+    	if ( this.imgURI != null ) {
+    		return this.imgURI;
+   		} else {
+   			return "";
+   	    }
+    }
+
+    public void setImageURI(String newImgURI) {
+    	this.imgURI= newImgURI;
+    }
+
+    // The set/getValue methods are used to set the widget's image URI during binding 
+    public void setValue(Object newImgURI) {
+    	this.setImageURI(newImgURI.toString());
+    }
+
+    public Object getValue() {
+    	return this.getImageURI();
+    }
+
+    public void readFromRequest(final FormContext formContext) {
+        if (!getCombinedState().isAcceptingInputs())
+            return;
+
+        Form form = getForm();
+
+        // Set the submit widget if we can determine it from the request
+        String fullId = getRequestParameterName();
+        Request request = formContext.getRequest();
+
+        // Extracts mouse coordinates from request (ignores malformed numbers)
+        try {
+        	this.x= (new Integer(formContext.getRequest().getParameter(fullId + ".x"))).intValue();
+        	this.y= (new Integer(formContext.getRequest().getParameter(fullId + ".y"))).intValue();
+        } catch (java.lang.NumberFormatException e) {
+        	this.x= 0;
+        	this.y= 0;
+       	}
+        
+        String value = request.getParameter(fullId);
+        if (value != null && value.length() > 0) {
+            form.setSubmitWidget(this);
+
+        } else {
+            // Special workaround an IE bug for <input type="image" name="foo"> :
+            // in that case, IE only sends "foo.x" and "foo.y" and not "foo" whereas
+            // standards-compliant browsers such as Mozilla do send the "foo" parameter.
+            //
+            // Note that since actions are terminal widgets, there's no chance of conflict
+            // with a child "x" or "y" widget.
+            value = request.getParameter(fullId + ".x");
+            if ((value != null) && value.length() > 0) {
+                form.setSubmitWidget(this);
+            }
+        }
+
+        if (form.getSubmitWidget() == this) {
+            form.addWidgetEvent(new ImageMapEvent(this, definition.getActionCommand()));
+
+            handleActivate();
+        }
+    }
+
+    /**
+     * Adds the @imageuri attribute to the XML element
+     */
+    public AttributesImpl getXMLElementAttributes() {
+        AttributesImpl attrs = super.getXMLElementAttributes();
+        attrs.addCDATAAttribute("imageuri", this.imgURI);
+        return attrs;
+    }
+    
+    /**
+     * Handle the fact that this action was activated. The default here is to end the
+     * current form processing and redisplay the form, which means that actual behaviour
+     * should be implemented in event listeners.
+     */
+    protected void handleActivate() {
+        getForm().endProcessing(true);
+    }
+
+    /**
+     * Always return <code>true</code> (an action has no validation)
+     */
+    public boolean validate() {
+        return true;
+    }
+
+    public String getXMLElementName() {        
+        return IMAGEMAP_EL;
+    }  
+
+    /**
+     * Adds an ActionListener to this widget instance. Listeners defined
+     * on the widget instance will be executed in addtion to any listeners
+     * that might have been defined in the widget definition.
+     */
+    public void addActionListener(ActionListener listener) {
+        this.listener = WidgetEventMulticaster.add(this.listener, listener);
+    }
+
+    public void removeActionListener(ActionListener listener) {
+        this.listener = WidgetEventMulticaster.remove(this.listener, listener);
+    }
+
+    private void fireActionEvent(ActionEvent event) {
+        if (this.listener != null) {
+            this.listener.actionPerformed(event);
+        }
+    }
+
+    public void broadcastEvent(WidgetEvent event) {
+        if (event instanceof ActionEvent) {
+            this.definition.fireActionEvent((ActionEvent)event);
+            fireActionEvent((ActionEvent)event);
+        } else {
+            // Other kinds of events
+            super.broadcastEvent(event);
+        }
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMapDefinition.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMapDefinition.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMapDefinition.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMapDefinition.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,70 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.forms.formmodel;
+
+import org.apache.cocoon.forms.event.ActionEvent;
+import org.apache.cocoon.forms.event.ActionListener;
+import org.apache.cocoon.forms.event.WidgetEventMulticaster;
+
+/**
+ * The {@link WidgetDefinition} part of an ImageMap widget, see {@link ImageMap} 
+ * for more information.
+ * 
+ * @version $Id$
+ * @since 2.1.8
+ */
+public class ImageMapDefinition extends AbstractWidgetDefinition {
+	
+    private String actionCommand;
+    private String imgURI; // URI of widget's image
+    private ActionListener listener;
+
+    public void setActionCommand(String actionCommand) {
+        this.actionCommand = actionCommand;
+    }
+
+    public String getActionCommand() {
+        return actionCommand;
+    }
+
+    public Widget createInstance() {
+        return new ImageMap(this);
+    }
+
+    public void addActionListener(ActionListener listener) {
+        checkMutable();
+        this.listener = WidgetEventMulticaster.add(this.listener, listener);
+    }
+    
+    public void fireActionEvent(ActionEvent event) {
+        if (this.listener != null) {
+            this.listener.actionPerformed(event);
+        }
+    }
+
+    public boolean hasActionListeners() {
+        return this.listener != null;
+    }
+
+    // Set/get image's URI
+    public String getImageURI() {
+        return imgURI;
+    }
+
+    public void setImageURI(String newImgURI) {
+    	this.imgURI= newImgURI;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-forms-block/impl/src/main/java/org/apache/cocoon/forms/formmodel/ImageMapDefinition.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message