You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/01/08 00:47:32 UTC

svn commit: r493880 [1/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/corelib/base/ main/java/org/apache/tapestry/corelib/components/ main/jav...

Author: hlship
Date: Sun Jan  7 15:47:29 2007
New Revision: 493880

URL: http://svn.apache.org/viewvc?view=rev&rev=493880
Log:
Moving Binding inteface to org.apache.tapestry.
Add Select component, along with SelectModel, OptionGroupModel, OptionModel and various implementations and supports.
Add a type coercion from String to SelectModel.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java
      - copied, changed from r493506, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Binding.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionGroupModel.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionModel.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/PrimaryKeyConverter.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/SelectModel.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Select.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionGroupModelImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionModelImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/SelectModelImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/OptionGroupModelImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/OptionModelImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/corelib/
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/corelib/components/
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/corelib/components/disabled_option.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/corelib/components/just_options.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/corelib/components/option_attributes.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/corelib/components/option_group_attributes.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/corelib/components/option_groups.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/corelib/components/option_groups_precede_ungroup_options.html
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Binding.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/mixins/DiscardBody.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryUtils.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ComponentBindingFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/LiteralBindingFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/MessageBindingFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/TranslateBindingFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ValidateBindingFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/BindingSourceImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ExpansionPageElement.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingFactory.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TranslatorDefaultSource.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/data/IncidentData.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/SimpleForm.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/TapestryUtilsTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/BindingFactoryTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/ValidateBindingFactoryTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/DefaultParameterBindingMethodComponent.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ExpansionPageElementImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.properties

Copied: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java (from r493506, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Binding.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java?view=diff&rev=493880&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Binding.java&r1=493506&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Binding.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/Binding.java Sun Jan  7 15:47:29 2007
@@ -12,45 +12,42 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-/**
- * A binding is a connection between a component and its container (another component), that allows
- * the embedded component to gain access to <em>resources</em> defined by the container. Resources
- * can represent any kind of value that can be obtained from the parent component, but is often a
- * JavaBean property that can be read and updated. Different implementations of Binding as used to
- * access different kinds of resources of the container.
- * 
- * 
- */
-public interface Binding
-{
-    /**
-     * Reads the current value of the property (or other resource). When reading properties of
-     * objects that are primitive types, this will return an instance of the wrapper type. In some
-     * cases, a binding is read only and this method will throw a runtime exception.
-     */
-    Object get();
-
-    /**
-     * Updates the current value. Most types of bindings are read-only, and this method will throw a
-     * runtime exception. It is the caller's responsibility to ensure that the value passed in is of
-     * the appropriate type.
-     * 
-     * @param value
-     */
-    void set(Object value);
-
-    /**
-     * Returns true if the value of the binding does not ever change. Components will often cache
-     * such values aggressively.
-     */
-    boolean isInvariant();
-
-    /**
-     * Returns the type of the binding, either the type of resource exposed by the binding, or the
-     * type of the property bound.
-     */
-
-    Class getBindingType();
-}
+package org.apache.tapestry;
+
+/**
+ * A binding is a connection between a component and its container (another component), that allows
+ * the embedded component to gain access to <em>resources</em> defined by the container. Resources
+ * can represent any kind of value that can be obtained from the parent component, but is often a
+ * JavaBean property that can be read and updated. Different implementations of Binding as used to
+ * access different kinds of resources of the container.
+ */
+public interface Binding
+{
+    /**
+     * Reads the current value of the property (or other resource). When reading properties of
+     * objects that are primitive types, this will return an instance of the wrapper type. In some
+     * cases, a binding is read only and this method will throw a runtime exception.
+     */
+    Object get();
+
+    /**
+     * Updates the current value. Most types of bindings are read-only, and this method will throw a
+     * runtime exception. It is the caller's responsibility to ensure that the value passed in is of
+     * the appropriate type.
+     * 
+     * @param value
+     */
+    void set(Object value);
+
+    /**
+     * Returns true if the value of the binding does not ever change. Components will often cache
+     * such values aggressively.
+     */
+    boolean isInvariant();
+
+    /**
+     * Returns the type of the binding, either the type of resource exposed by the binding, or the
+     * type of the property bound.
+     */
+    Class getBindingType();
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ComponentResources.java Sun Jan  7 15:47:29 2007
@@ -17,7 +17,6 @@
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.runtime.Component;
-import org.apache.tapestry.services.Binding;
 
 /**
  * Provides a component instance with the resources provided by the framework. In many

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionGroupModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionGroupModel.java?view=auto&rev=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionGroupModel.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionGroupModel.java Sun Jan  7 15:47:29 2007
@@ -0,0 +1,45 @@
+// Copyright 2007 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.tapestry;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Defines a group of related options. Options may be enabled or disabled as a group. Corresponds to
+ * the [X]HTML element &lt;optgroup&gt;.
+ */
+public interface OptionGroupModel
+{
+    /** Localized, user-presentable label for the group. */
+    String getLabel();
+
+    /**
+     * If true, the group (and all options within it) will be disabled. Note that some browsers do
+     * not honor the disabled attribute property.
+     * 
+     * @return true if a disabled attribute should be rendered.
+     */
+    boolean isDisabled();
+
+    /**
+     * Additional attributes to render with the &lt;optgroup&gt;. This is often used to render the
+     * CSS class attribute. May return null.
+     */
+    Map<String, String> getAttributes();
+
+    /** The list of options within the group. */
+    List<OptionModel> getOptions();
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionModel.java?view=auto&rev=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionModel.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/OptionModel.java Sun Jan  7 15:47:29 2007
@@ -0,0 +1,40 @@
+// Copyright 2007 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.tapestry;
+
+import java.util.Map;
+
+/**
+ * A single option within a {@link OptionGroupModel}. Corresponds closely to the [X]HTML
+ * &lt;option&gt; element.
+ */
+public interface OptionModel
+{
+    /** The localized, user-presentable label for the option. */
+    String getLabel();
+
+    /** If true, then a disabled attribute will be rendered with the &lt;option&gt;. */
+    boolean isDisabled();
+
+    /** Additional attributes to render within the &lt;option&gt;. May return null. */
+    Map<String, String> getAttributes();
+
+    /**
+     * The server-side value represented by this option. This is used to determine which option will
+     * be selected. It is also used, via {@link PrimaryKeyConverter#toClient(Object)}, to generate
+     * the client-side value attribute.
+     */
+    Object getValue();
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/PrimaryKeyConverter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/PrimaryKeyConverter.java?view=auto&rev=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/PrimaryKeyConverter.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/PrimaryKeyConverter.java Sun Jan  7 15:47:29 2007
@@ -0,0 +1,41 @@
+// Copyright 2007 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.tapestry;
+
+/**
+ * Used to convert objects, typically entity objects obtained from a database, into a identifier
+ * that can be passed to and from the client. Encapsulates the conversion to and from client-side
+ * string representations.
+ */
+public interface PrimaryKeyConverter<V>
+{
+    /**
+     * Extract the primary key for the entity, converts it to a string, and returns the value.
+     * 
+     * @param value
+     *            the value whose primary key is required
+     * @return the string representation of the value's primary key
+     */
+    String toClient(V value);
+
+    /**
+     * Converts a primary key value back into the corresponding entity object.
+     * 
+     * @param primaryKey
+     *            string representation of an entities primary key
+     * @return the corresponding entity, or null if not found
+     */
+    V toEntity(String primaryKey);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/SelectModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/SelectModel.java?view=auto&rev=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/SelectModel.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/SelectModel.java Sun Jan  7 15:47:29 2007
@@ -0,0 +1,38 @@
+// Copyright 2007 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.tapestry;
+
+import java.util.List;
+
+/**
+ * Defines the possible options and option groups for a &lt;select&gt; [X]HTML element.
+ */
+public interface SelectModel
+{
+    /**
+     * The list of groups, each containing some number of individual options.
+     * 
+     * @return the groups, or null
+     */
+    List<OptionGroupModel> getOptionGroups();
+
+    /**
+     * The list of ungrouped options, which appear after any grouped options. Generally, a model
+     * will either provide option groups or ungroup options, but not both.
+     * 
+     * @return the ungrouped options, or null
+     */
+    List<OptionModel> getOptions();
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Parameter.java Sun Jan  7 15:47:29 2007
@@ -46,7 +46,7 @@
      * If true (the default), then the value for the parameter is cached while the component is,
      * itself, rendering. Values from invariant bindings (such as literal strings) are always
      * cached, regardless of this setting. Set this attribute to false to force the parameter to be
-     * {@link org.apache.tapestry.services.Binding#get() re-read} every time the field is accessed,
+     * {@link org.apache.tapestry.Binding#get() re-read} every time the field is accessed,
      * even while the component is rendering.
      */
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java Sun Jan  7 15:47:29 2007
@@ -16,6 +16,7 @@
 
 import java.io.Serializable;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentAction;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.Field;
@@ -40,7 +41,6 @@
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.ioc.services.PropertyAccess;
 import org.apache.tapestry.runtime.Component;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingSource;
 import org.apache.tapestry.services.FormSupport;
 import org.apache.tapestry.services.PageRenderSupport;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java Sun Jan  7 15:47:29 2007
@@ -16,6 +16,7 @@
 
 import java.util.Locale;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.FieldValidator;
 import org.apache.tapestry.MarkupWriter;
@@ -29,11 +30,13 @@
 import org.apache.tapestry.internal.bindings.AbstractBinding;
 import org.apache.tapestry.internal.services.FormParameterLookup;
 import org.apache.tapestry.ioc.Messages;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.TranslatorDefaultSource;
 import org.apache.tapestry.services.ValidationMessagesSource;
 
-/** Abstract class for a variety of components that render some variation of a text field. */
+/**
+ * Abstract class for a variety of components that render some variation of a text field. Most of
+ * the hooks for user input validation are in this class.
+ */
 public abstract class AbstractTextField extends AbstractField
 {
     @Parameter(required = true)
@@ -65,9 +68,8 @@
     {
         // Have to do this a bit the hard way: defer getting the translator until first needed,
         // since we won't know the bound type of the value parameter until after
-        // containingPageDidLoad().
-        // This is because fields are handled in alphabetical order, and _translate is ordered
-        // before _validate.
+        // containingPageDidLoad(). This is because fields are handled in alphabetical order, and
+        // _translate is ordered before _validate.
 
         return new AbstractBinding()
         {

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java Sun Jan  7 15:47:29 2007
@@ -14,15 +14,15 @@
 
 package org.apache.tapestry.corelib.components;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.annotations.AfterRender;
 import org.apache.tapestry.annotations.BeginRender;
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.corelib.base.AbstractField;
 import org.apache.tapestry.internal.services.FormParameterLookup;
-import org.apache.tapestry.services.Binding;
 
-/** A Checkbox coponent is simply a &lt;input type="checkbox"&gt;. */
+/** A Checkbox component is simply a &lt;input type="checkbox"&gt;. */
 public class Checkbox extends AbstractField
 {
 
@@ -47,6 +47,8 @@
                 getClientId(),
                 "checked",
                 _value ? "checked" : null);
+
+        getValidationDecorator().insideField(this);
     }
 
     @AfterRender

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Loop.java Sun Jan  7 15:47:29 2007
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.corelib.components;
-
+package org.apache.tapestry.corelib.components;
+
 import java.util.Iterator;
 
 import org.apache.tapestry.annotations.AfterRender;
@@ -23,98 +23,101 @@
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.annotations.SetupRender;
 import org.apache.tapestry.services.Heartbeat;
-
-/**
- * Basic looping class; loops over a number of items (provided by its source parameter), rendering
- * its body for each one.
- * <p>
- * This is pretty primitive compared to where it will go in the future.
- * <p>
- * TODO: Render tag and informal parameters
- * <p>
- * TODO: Heartbeat / volatile
- * <p>
- * TODO: Render state management
- * <p>
- * TODO: More?
- * 
- * 
- */
-@ComponentClass
-public class Loop
-{
-    /**
-     * Defines the collection of values for the loop to iterate over.
-     */
-    @Parameter(required = true)
-    private Iterable<?> _source;
-
-    /**
-     * The current value, set before the component renders its body.
-     */
-    @Parameter
-    private Object _value;
-
-    /**
-     * The index into the source items.
-     */
-    @Parameter
-    private int _index;
-
-    private Iterator<?> _iterator;
+
+/**
+ * Basic looping class; loops over a number of items (provided by its source parameter), rendering
+ * its body for each one.
+ * <p>
+ * This is pretty primitive compared to where it will go in the future.
+ * <p>
+ * TODO: Render tag and informal parameters
+ * <p>
+ * TODO: Heartbeat / volatile
+ * <p>
+ * TODO: Render state management
+ * <p>
+ * TODO: More?
+ */
+@ComponentClass
+public class Loop
+{
+    /**
+     * Defines the collection of values for the loop to iterate over.
+     */
+    @Parameter(required = true)
+    private Iterable<?> _source;
+
+    /**
+     * The current value, set before the component renders its body.
+     */
+    @Parameter
+    private Object _value;
+
+    /**
+     * The index into the source items.
+     */
+    @Parameter
+    private int _index;
+
+    private Iterator<?> _iterator;
 
     @Environmental
     private Heartbeat _heartbeat;
-    
-    @SetupRender
-    boolean setup()
-    {
-        _index = 0;
-
-        if (_source == null)
-            return false;
-
-        _iterator = _source.iterator();
-
-        // Only render the body if there is something to iterate over
-
-        return _iterator.hasNext();
-    }
-
-    /** Begins a new heartbeat. */
-    @BeginRender
-    void begin()
-    {
+
+    @SetupRender
+    boolean setup()
+    {
+        _index = 0;
+
+        if (_source == null)
+            return false;
+
+        _iterator = _source.iterator();
+
+        // Only render the body if there is something to iterate over
+
+        return _iterator.hasNext();
+    }
+
+    /** Begins a new heartbeat. */
+    @BeginRender
+    void begin()
+    {
         _value = _iterator.next();
-        
-        _heartbeat.begin();
-    }
-
-    /**  Ends the current heartbeat. */
-    @AfterRender
-    boolean after()
+
+        _heartbeat.begin();
+    }
+
+    /** Ends the current heartbeat. */
+    @AfterRender
+    boolean after()
     {
         _heartbeat.end();
-        
-        _index++;
-        
-        return _iterator.hasNext();
-    }
-
-    // For testing:
-
-    int getIndex()
-    {
-        return _index;
-    }
-
-    Object getValue()
-    {
-        return _value;
-    }
-
-    void setSource(Iterable<?> source)
-    {
-        _source = source;
-    }
-}
+
+        _index++;
+
+        return _iterator.hasNext();
+    }
+
+    // For testing:
+
+    int getIndex()
+    {
+        return _index;
+    }
+
+    Object getValue()
+    {
+        return _value;
+    }
+
+    void setSource(Iterable<?> source)
+    {
+        _source = source;
+    }
+
+    void setHeartbeat(Heartbeat heartbeat)
+    {
+        _heartbeat = heartbeat;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Select.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Select.java?view=auto&rev=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Select.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Select.java Sun Jan  7 15:47:29 2007
@@ -0,0 +1,175 @@
+// Copyright 2007 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.tapestry.corelib.components;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.OptionGroupModel;
+import org.apache.tapestry.OptionModel;
+import org.apache.tapestry.PrimaryKeyConverter;
+import org.apache.tapestry.SelectModel;
+import org.apache.tapestry.annotations.AfterRender;
+import org.apache.tapestry.annotations.BeforeRenderTemplate;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.corelib.base.AbstractField;
+import org.apache.tapestry.internal.services.FormParameterLookup;
+
+/**
+ * Select an item from a list of values, using an [X]HTML &lt;select&gt; element on the client side.
+ * An validation decorations will go around the entire &lt;select&gt; element.
+ */
+public final class Select extends AbstractField
+{
+    @Parameter(required = true)
+    private Object _value;
+
+    @Parameter
+    private PrimaryKeyConverter _converter = new PrimaryKeyConverter<String>()
+    {
+        public String toClient(String value)
+        {
+            return value;
+        }
+
+        public String toEntity(String primaryKey)
+        {
+            // We don't do a conversion here, so it stays a String. When that String is assigned to
+            // _value, it will be coerced to the appropriate type (if possible) or an exception
+            // will be thrown.
+
+            return primaryKey;
+        }
+    };
+
+    // Maybe this should default to property "<componentId>Model"?
+
+    @Parameter(required = true)
+    private SelectModel _model;
+
+    Binding defaultValue()
+    {
+        return createDefaultParameterBinding("value");
+    }
+
+    void beginRender(MarkupWriter writer)
+    {
+        writer.element("select", "name", getElementName(), "id", getClientId());
+
+        // Disabled, informals via mixins
+    }
+
+    @BeforeRenderTemplate
+    void options(MarkupWriter writer)
+    {
+        if (_model.getOptionGroups() != null)
+        {
+            for (OptionGroupModel group : _model.getOptionGroups())
+            {
+                writeOptionGroup(writer, group);
+            }
+        }
+
+        writeOptions(writer, _model.getOptions());
+    }
+
+    private void writeOptionGroup(MarkupWriter writer, OptionGroupModel model)
+    {
+        writer.element("optgroup", "label", model.getLabel());
+
+        writeDisabled(writer, model.isDisabled());
+        writeAttributes(writer, model.getAttributes());
+
+        writeOptions(writer, model.getOptions());
+
+        writer.end(); // optgroup
+    }
+
+    @SuppressWarnings("unchecked")
+    private void writeOptions(MarkupWriter writer, List<OptionModel> optionModels)
+    {
+        if (optionModels == null)
+            return;
+
+        for (OptionModel model : optionModels)
+        {
+            Object optionValue = model.getValue();
+
+            String clientValue = _converter.toClient(optionValue);
+
+            writer.element("option", "value", clientValue);
+
+            if (isOptionValueSelected(optionValue))
+                writer.attributes("selected", "selected");
+
+            writeDisabled(writer, model.isDisabled());
+            writeAttributes(writer, model.getAttributes());
+
+            writer.write(model.getLabel());
+
+            writer.end(); // option
+        }
+    }
+
+    boolean isOptionValueSelected(Object optionValue)
+    {
+        return _value == optionValue || (_value != null && _value.equals(optionValue));
+    }
+
+    private void writeDisabled(MarkupWriter writer, boolean disabled)
+    {
+        if (disabled)
+            writer.attributes("disabled", "disabled");
+    }
+
+    private void writeAttributes(MarkupWriter writer, Map<String, String> attributes)
+    {
+        if (attributes == null)
+            return;
+
+        for (Map.Entry<String, String> e : attributes.entrySet())
+            writer.attributes(e.getKey(), e.getValue());
+    }
+
+    @AfterRender
+    void afterRender(MarkupWriter writer)
+    {
+        writer.end();
+    }
+
+    @Override
+    protected void processSubmission(FormParameterLookup paramLookup, String elementName)
+    {
+        String primaryKey = paramLookup.getParameter(elementName);
+
+        Object selectedValue = _converter.toEntity(primaryKey);
+
+        _value = selectedValue;
+    }
+
+    // For testing.
+
+    void setValue(Object value)
+    {
+        _value = value;
+    }
+
+    void setModel(SelectModel model)
+    {
+        _model = model;
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java Sun Jan  7 15:47:29 2007
@@ -22,7 +22,7 @@
  * TextArea component corresponds to a &lt;textarea&gt;. The value parameter is almost always bound
  * to a string, but this is not an absolute requirement.
  */
-public class TextArea extends AbstractTextField
+public final class TextArea extends AbstractTextField
 {
     private String _value;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java Sun Jan  7 15:47:29 2007
@@ -22,7 +22,7 @@
  * editted. TextField is generally used with string values, but other values are acceptible, as long
  * as they can be freely converted back and forth to strings.
  */
-public class TextField extends AbstractTextField
+public final class TextField extends AbstractTextField
 {
     @Override
     protected final void writeFieldTag(MarkupWriter writer, String value)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/mixins/DiscardBody.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/mixins/DiscardBody.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/mixins/DiscardBody.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/mixins/DiscardBody.java Sun Jan  7 15:47:29 2007
@@ -16,12 +16,15 @@
 
 import org.apache.tapestry.annotations.BeforeRenderBody;
 import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.MixinAfter;
 
 /**
  * Discards a component's body. Returns false from the {@link BeforeRenderBody} phase, which
- * prevents the rendering of the body.
+ * prevents the rendering of the body. Set up as a "MixinAfter" so that components can render their
+ * body if they so desire before this mixin cancels the body.
  */
 @ComponentClass
+@MixinAfter
 public class DiscardBody
 {
     boolean beforeRenderBody()

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java Sun Jan  7 15:47:29 2007
@@ -27,7 +27,7 @@
 {
     /**
      * Reads the value of a parameter, via the parameter's
-     * {@link org.apache.tapestry.services.Binding}.
+     * {@link org.apache.tapestry.Binding}.
      * 
      * @param <T>
      * @param parameterName
@@ -40,7 +40,7 @@
 
     /**
      * Updates a parameter. It is an error to update a parameter which is not bound. The parameter
-     * {@link org.apache.tapestry.services.Binding binding} may also not support updates.
+     * {@link org.apache.tapestry.Binding binding} may also not support updates.
      * 
      * @param <T>
      * @param parameterName
@@ -51,7 +51,7 @@
     <T> void writeParameter(String parameterName, T parameterValue);
 
     /**
-     * Returns true if the named parameter's {@link org.apache.tapestry.services.Binding} is
+     * Returns true if the named parameter's {@link org.apache.tapestry.Binding} is
      * invariant, false if otherwise, or if the parameter is not bound. Invariant bindings are
      * cached more aggresively than variant bindings.
      * 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java Sun Jan  7 15:47:29 2007
@@ -14,10 +14,10 @@
 
 package org.apache.tapestry.internal;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.runtime.Component;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.PersistentFieldManager;
 
 /**

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionGroupModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionGroupModelImpl.java?view=auto&rev=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionGroupModelImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionGroupModelImpl.java Sun Jan  7 15:47:29 2007
@@ -0,0 +1,75 @@
+// Copyright 2007 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.tapestry.internal;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry.OptionGroupModel;
+import org.apache.tapestry.OptionModel;
+
+public final class OptionGroupModelImpl implements OptionGroupModel
+{
+    private final String _label;
+
+    private final boolean _disabled;
+
+    private final List<OptionModel> _options;
+
+    private final Map<String, String> _attributes;
+
+    public OptionGroupModelImpl(String label, boolean disabled, List<OptionModel> options,
+            String... attributeKeysAndValues)
+    {
+        this(label, disabled, options, attributeKeysAndValues.length == 0 ? null : TapestryUtils
+                .mapFromKeysAndValues(attributeKeysAndValues));
+    }
+
+    public OptionGroupModelImpl(String label, boolean disabled, List<OptionModel> options,
+            Map<String, String> attributes)
+    {
+        _label = label;
+        _disabled = disabled;
+        _options = options;
+        _attributes = attributes;
+    }
+
+    public Map<String, String> getAttributes()
+    {
+        return _attributes;
+    }
+
+    public String getLabel()
+    {
+        return _label;
+    }
+
+    public List<OptionModel> getOptions()
+    {
+        return _options;
+    }
+
+    public boolean isDisabled()
+    {
+        return _disabled;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("OptionGroupModel[%s]", _label);
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionModelImpl.java?view=auto&rev=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionModelImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/OptionModelImpl.java Sun Jan  7 15:47:29 2007
@@ -0,0 +1,71 @@
+// Copyright 2007 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.tapestry.internal;
+
+import java.util.Map;
+
+import org.apache.tapestry.OptionModel;
+
+public final class OptionModelImpl implements OptionModel
+{
+    private final String _label;
+
+    private final boolean _disabled;
+
+    private final Object _value;
+
+    private final Map<String, String> _attributes;
+
+    public OptionModelImpl(String label, boolean disabled, Object value, String... keysAndValues)
+    {
+        this(label, disabled, value, keysAndValues.length > 0 ? TapestryUtils
+                .mapFromKeysAndValues(keysAndValues) : null);
+    }
+
+    public OptionModelImpl(String label, boolean disabled, Object value,
+            Map<String, String> attributes)
+    {
+        _label = label;
+        _disabled = disabled;
+        _value = value;
+        _attributes = attributes;
+    }
+
+    public Map<String, String> getAttributes()
+    {
+        return _attributes;
+    }
+
+    public String getLabel()
+    {
+        return _label;
+    }
+
+    public Object getValue()
+    {
+        return _value;
+    }
+
+    public boolean isDisabled()
+    {
+        return _disabled;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("OptionModel[%s %s]", _label, _value);
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/SelectModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/SelectModelImpl.java?view=auto&rev=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/SelectModelImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/SelectModelImpl.java Sun Jan  7 15:47:29 2007
@@ -0,0 +1,57 @@
+// Copyright 2007 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.tapestry.internal;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.tapestry.OptionGroupModel;
+import org.apache.tapestry.OptionModel;
+import org.apache.tapestry.SelectModel;
+
+public final class SelectModelImpl implements SelectModel
+{
+    private final List<OptionGroupModel> _optionGroups;
+
+    private final List<OptionModel> _optionModels;
+
+    public SelectModelImpl(final List<OptionGroupModel> optionGroups,
+            final List<OptionModel> optionModels)
+    {
+        _optionGroups = optionGroups;
+        _optionModels = optionModels;
+    }
+
+    public SelectModelImpl(OptionModel... optionModels)
+    {
+        this(null, Arrays.asList(optionModels));
+    }
+
+    public SelectModelImpl(OptionGroupModel... groupModels)
+    {
+        this(Arrays.asList(groupModels), null);
+    }
+
+    public List<OptionGroupModel> getOptionGroups()
+    {
+        return _optionGroups;
+    }
+
+    public List<OptionModel> getOptions()
+    {
+        return _optionModels;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryUtils.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryUtils.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryUtils.java Sun Jan  7 15:47:29 2007
@@ -14,8 +14,17 @@
 
 package org.apache.tapestry.internal;
 
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
+
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry.OptionModel;
+import org.apache.tapestry.SelectModel;
+import org.apache.tapestry.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry.ioc.internal.util.Defense;
 
 /** Shared utility methods used by various implementation classes. */
 public class TapestryUtils
@@ -81,5 +90,77 @@
         }
 
         return builder.toString();
+    }
+
+    public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
+    {
+        Map<String, String> result = CollectionFactory.newMap();
+
+        int i = 0;
+        while (i < keysAndValues.length)
+        {
+            String key = keysAndValues[i++];
+            String value = keysAndValues[i++];
+
+            result.put(key, value);
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts a string to an {@link OptionModel}. The string is of the form "value=label". If the
+     * equals sign is omitted, then the same value is used for both value and label.
+     * 
+     * @param input
+     * @return
+     */
+    public static OptionModel toOptionModel(String input)
+    {
+        Defense.notNull(input, "input");
+
+        int equalsx = input.indexOf('=');
+
+        if (equalsx < 0)
+            return new OptionModelImpl(input, false, input);
+
+        String value = input.substring(0, equalsx);
+        String label = input.substring(equalsx + 1);
+
+        return new OptionModelImpl(label, false, value);
+    }
+
+    /**
+     * Parses a string input into a series of value=label pairs compatible with
+     * {@link #toOptionModel(String)}. Splits on commas. Ignores whitespace around commas.
+     * 
+     * @param input
+     *            comma seperated list of terms
+     * @return list of option models
+     */
+    public static List<OptionModel> toOptionModels(String input)
+    {
+        Defense.notNull(input, "input");
+
+        List<OptionModel> result = newList();
+
+        for (String term : input.split(","))
+            result.add(toOptionModel(term.trim()));
+
+        return result;
+    }
+
+    /**
+     * Wraps the result of {@link #toOptionModels(String)} as a {@link SelectModel} (with no option
+     * groups).
+     * 
+     * @param input
+     * @return
+     */
+    public static SelectModel toSelectModel(String input)
+    {
+        List<OptionModel> options = toOptionModels(input);
+
+        return new SelectModelImpl(null, options);
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/AbstractBinding.java Sun Jan  7 15:47:29 2007
@@ -14,10 +14,10 @@
 
 package org.apache.tapestry.internal.bindings;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ioc.BaseLocatable;
 import org.apache.tapestry.ioc.Location;
 import org.apache.tapestry.ioc.internal.util.TapestryException;
-import org.apache.tapestry.services.Binding;
 
 /**
  * Abstract base class for bindings. Assumes that the binding is read only and invariant. Subclasses

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/BindingsMessages.java Sun Jan  7 15:47:29 2007
@@ -14,10 +14,10 @@
 
 package org.apache.tapestry.internal.bindings;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.ioc.internal.util.MessagesImpl;
-import org.apache.tapestry.services.Binding;
 
 final class BindingsMessages
 {

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ComponentBindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ComponentBindingFactory.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ComponentBindingFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ComponentBindingFactory.java Sun Jan  7 15:47:29 2007
@@ -14,9 +14,9 @@
 
 package org.apache.tapestry.internal.bindings;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ioc.Location;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 
 /** The "component:" binding prefix, which allows access to a child component via its id. */

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/LiteralBindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/LiteralBindingFactory.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/LiteralBindingFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/LiteralBindingFactory.java Sun Jan  7 15:47:29 2007
@@ -14,9 +14,9 @@
 
 package org.apache.tapestry.internal.bindings;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ioc.Location;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 
 /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/MessageBindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/MessageBindingFactory.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/MessageBindingFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/MessageBindingFactory.java Sun Jan  7 15:47:29 2007
@@ -14,9 +14,9 @@
 
 package org.apache.tapestry.internal.bindings;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ioc.Location;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 
 /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/PropBindingFactory.java Sun Jan  7 15:47:29 2007
@@ -21,6 +21,7 @@
 import java.lang.reflect.Modifier;
 import java.util.Map;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.events.InvalidationListener;
 import org.apache.tapestry.ioc.Location;
@@ -32,7 +33,6 @@
 import org.apache.tapestry.ioc.services.PropertyAccess;
 import org.apache.tapestry.ioc.services.PropertyAdapter;
 import org.apache.tapestry.ioc.util.BodyBuilder;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 
 /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/TranslateBindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/TranslateBindingFactory.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/TranslateBindingFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/TranslateBindingFactory.java Sun Jan  7 15:47:29 2007
@@ -14,10 +14,10 @@
 
 package org.apache.tapestry.internal.bindings;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.Translator;
 import org.apache.tapestry.ioc.Location;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 import org.apache.tapestry.services.TranslatorSource;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ValidateBindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ValidateBindingFactory.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ValidateBindingFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/bindings/ValidateBindingFactory.java Sun Jan  7 15:47:29 2007
@@ -14,12 +14,12 @@
 
 package org.apache.tapestry.internal.bindings;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.Field;
 import org.apache.tapestry.FieldValidator;
 import org.apache.tapestry.ioc.Location;
 import org.apache.tapestry.ioc.internal.util.TapestryException;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 import org.apache.tapestry.services.FieldValidatorSource;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/BindingSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/BindingSourceImpl.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/BindingSourceImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/BindingSourceImpl.java Sun Jan  7 15:47:29 2007
@@ -19,11 +19,11 @@
 
 import java.util.Map;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.internal.InternalConstants;
 import org.apache.tapestry.ioc.Location;
 import org.apache.tapestry.ioc.internal.util.TapestryException;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 import org.apache.tapestry.services.BindingSource;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Sun Jan  7 15:47:29 2007
@@ -22,6 +22,7 @@
 import java.util.regex.Pattern;
 
 import org.apache.commons.logging.Log;
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.events.InvalidationListener;
 import org.apache.tapestry.internal.InternalConstants;
@@ -50,7 +51,6 @@
 import org.apache.tapestry.services.ApplicationInitializer;
 import org.apache.tapestry.services.ApplicationInitializerFilter;
 import org.apache.tapestry.services.AssetFactory;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 import org.apache.tapestry.services.BindingSource;
 import org.apache.tapestry.services.ClasspathAssetAliasManager;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageElementFactoryImpl.java Sun Jan  7 15:47:29 2007
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.internal.services;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.internal.InternalConstants;
@@ -35,7 +36,6 @@
 import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.runtime.RenderQueue;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingSource;
 import org.apache.tapestry.services.ComponentClassResolver;
 import org.apache.tapestry.services.ComponentMessagesSource;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageLoaderImpl.java Sun Jan  7 15:47:29 2007
@@ -21,6 +21,7 @@
 import java.util.Set;
 
 import org.apache.commons.logging.Log;
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.events.InvalidationListener;
 import org.apache.tapestry.internal.InternalConstants;
@@ -42,7 +43,6 @@
 import org.apache.tapestry.ioc.internal.util.TapestryException;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.model.EmbeddedComponentModel;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingSource;
 import org.apache.tapestry.services.PersistentFieldManager;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ParameterWorker.java Sun Jan  7 15:47:29 2007
@@ -17,11 +17,11 @@
 import java.lang.reflect.Modifier;
 import java.util.List;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.util.BodyBuilder;
 import org.apache.tapestry.model.MutableComponentModel;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingSource;
 import org.apache.tapestry.services.ClassTransformation;
 import org.apache.tapestry.services.ComponentClassTransformWorker;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java Sun Jan  7 15:47:29 2007
@@ -23,6 +23,7 @@
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentEventHandler;
 import org.apache.tapestry.Link;
 import org.apache.tapestry.MarkupWriter;
@@ -45,7 +46,6 @@
 import org.apache.tapestry.runtime.PageLifecycleListener;
 import org.apache.tapestry.runtime.RenderCommand;
 import org.apache.tapestry.runtime.RenderQueue;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.ComponentMessagesSource;
 
 /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ExpansionPageElement.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ExpansionPageElement.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ExpansionPageElement.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ExpansionPageElement.java Sun Jan  7 15:47:29 2007
@@ -14,10 +14,10 @@
 
 package org.apache.tapestry.internal.structure;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.runtime.RenderQueue;
-import org.apache.tapestry.services.Binding;
 
 /**
  * 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java Sun Jan  7 15:47:29 2007
@@ -20,6 +20,7 @@
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentEventHandler;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.Link;
@@ -32,7 +33,6 @@
 import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.runtime.Component;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.ComponentMessagesSource;
 
 /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingFactory.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingFactory.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingFactory.java Sun Jan  7 15:47:29 2007
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.services;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ioc.Location;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingSource.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingSource.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/BindingSource.java Sun Jan  7 15:47:29 2007
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.services;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ioc.Location;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Sun Jan  7 15:47:29 2007
@@ -28,6 +28,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.ComponentEventHandler;
 import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.SelectModel;
 import org.apache.tapestry.Translator;
 import org.apache.tapestry.Validator;
 import org.apache.tapestry.annotations.AfterRender;
@@ -42,6 +43,7 @@
 import org.apache.tapestry.dom.DefaultMarkupModel;
 import org.apache.tapestry.dom.Document;
 import org.apache.tapestry.internal.InternalConstants;
+import org.apache.tapestry.internal.TapestryUtils;
 import org.apache.tapestry.internal.bindings.ComponentBindingFactory;
 import org.apache.tapestry.internal.bindings.LiteralBindingFactory;
 import org.apache.tapestry.internal.bindings.MessageBindingFactory;
@@ -128,6 +130,8 @@
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.services.ChainBuilder;
 import org.apache.tapestry.ioc.services.ClassFactory;
+import org.apache.tapestry.ioc.services.Coercion;
+import org.apache.tapestry.ioc.services.CoercionTuple;
 import org.apache.tapestry.ioc.services.PipelineBuilder;
 import org.apache.tapestry.ioc.services.PropertyAccess;
 import org.apache.tapestry.ioc.services.PropertyShadowBuilder;
@@ -964,5 +968,28 @@
     {
         configuration.add(Integer.class, new IntegerTranslator());
         configuration.add(String.class, new StringTranslator());
+    }
+
+    /**
+     * Add a coercion from String to {@link SelectModel}.
+     */
+    @Contribute("tapestry.ioc.TypeCoercer")
+    public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration)
+    {
+        add(configuration, String.class, SelectModel.class, new Coercion<String, SelectModel>()
+        {
+            public SelectModel coerce(String input)
+            {
+                return TapestryUtils.toSelectModel(input);
+            }
+        });
+    }
+
+    private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
+            Class<T> targetType, Coercion<S, T> coercion)
+    {
+        CoercionTuple<S, T> tuple = new CoercionTuple<S, T>(sourceType, targetType, coercion);
+
+        configuration.add(tuple);
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TranslatorDefaultSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TranslatorDefaultSource.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TranslatorDefaultSource.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TranslatorDefaultSource.java Sun Jan  7 15:47:29 2007
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.services;
 
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.Translator;
 
 /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java Sun Jan  7 15:47:29 2007
@@ -33,6 +33,7 @@
 import javax.servlet.http.HttpSession;
 
 import org.apache.tapestry.Asset;
+import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ComponentResourcesCommon;
 import org.apache.tapestry.Field;
@@ -56,7 +57,6 @@
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.services.AssetFactory;
 import org.apache.tapestry.services.AssetSource;
-import org.apache.tapestry.services.Binding;
 import org.apache.tapestry.services.BindingFactory;
 import org.apache.tapestry.services.BindingSource;
 import org.apache.tapestry.services.ClassTransformation;

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/SimpleForm.html Sun Jan  7 15:47:29 2007
@@ -14,7 +14,13 @@
         <br/>
         <label t:type="Label"  field="component:message"/>: <input t:type="TextArea" t:id="message" label="Incident Message"
             value="prop:incident.message" cols="50" rows="10" disabled="prop:disabled"> You can put text here, but it isn't used. </input>
-        <br/>
+        <br/>
+        <label t:type="Label" field="component:operatingSystem"/>:
+        <select t:type="Select"  t:id="operatingSystem" value="prop:incident.operatingSystem" model="message:os-values" disabled="prop:disabled"/>
+        
+        
+        <br/>
+        
         <input t:type="Checkbox" t:id="urgent" value="prop:incident.urgent" disabled="prop:disabled"/>
         <label t:type="Label" field="component:urgent"/>
         <br/>
@@ -27,7 +33,8 @@
 
     <ul>
         <li>email: [${incident.email}]</li>
-        <li>message: [${incident.message}]</li>
+        <li>message: [${incident.message}]</li>
+        <li>OS: [${incident.operatingSystem}]</li>
         <li>urgent: [${incident.urgent}]</li>
     </ul>
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml Sun Jan  7 15:47:29 2007
@@ -22,9 +22,10 @@
       <package name="org.apache.tapestry.integration.pagelevel"/>
       <package name="org.apache.tapestry.integration"/>
       <package name="org.apache.tapestry"/>
+      <package name="org.apache.tapestry.corelib.components"/>
       <package name="org.apache.tapestry.dom"/>
-      <package name="org.apache.internal"/>
-      <package name="org.apache.tapestry.internal"/>
+      <package name="org.apache.internal"/>
+      <package name="org.apache.tapestry.internal"/>
       <package name="org.apache.tapestry.internal.aspects"/>
       <package name="org.apache.tapestry.internal.services"/>
       <package name="org.apache.tapestry.internal.structure"/>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java?view=diff&rev=493880&r1=493879&r2=493880
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/corelib/components/LoopTest.java Sun Jan  7 15:47:29 2007
@@ -12,64 +12,78 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.corelib.components;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import junit.framework.Assert;
-
-import org.testng.annotations.Test;
-
-/**
- * 
- */
-public class LoopTest extends Assert
-{
-    @Test
-    public void non_empty_iterator()
-    {
-        Loop loop = new Loop();
-
-        loop.setSource(Arrays.asList("alpha", "beta", "gamma"));
-
-        assertTrue(loop.setup());
-        assertEquals(loop.getIndex(), 0);
-
-        loop.begin();
-        assertEquals(loop.getValue(), "alpha");
-        assertEquals(loop.getIndex(), 0);
-
-        assertTrue(loop.after());
-        loop.begin();
-        assertEquals(loop.getValue(), "beta");
-        assertEquals(loop.getIndex(), 1);
-
-        assertTrue(loop.after());
-        loop.begin();
-        assertEquals(loop.getValue(), "gamma");
-        assertEquals(loop.getIndex(), 2);
-
-        assertFalse(loop.after());
-    }
-
-    @Test
-    public void iterator_is_null()
-    {
-        Loop loop = new Loop();
-
-        loop.setSource(null);
-
-        assertFalse(loop.setup());
-    }
-
-    @Test
-    public void iterator_is_empty()
-    {
-        Loop loop = new Loop();
-
-        loop.setSource(Collections.EMPTY_LIST);
-
-        assertFalse(loop.setup());
-    }
-}
+package org.apache.tapestry.corelib.components;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.services.Heartbeat;
+import org.testng.annotations.Test;
+
+public class LoopTest extends InternalBaseTestCase
+{
+    @Test
+    public void non_empty_iterator()
+    {
+        Heartbeat hb = newMock(Heartbeat.class);
+
+        // Really hard to test the exact timing of all this; it will have to
+        // be "proven" by integration tests.
+
+        hb.begin();
+        getMocksControl().times(3);
+
+        hb.end();
+        getMocksControl().times(3);
+
+        replay();
+
+        Loop loop = new Loop();
+
+        loop.setHeartbeat(hb);
+
+        loop.setSource(Arrays.asList("alpha", "beta", "gamma"));
+
+        assertTrue(loop.setup());
+        assertEquals(loop.getIndex(), 0);
+
+        loop.begin();
+        assertEquals(loop.getValue(), "alpha");
+        assertEquals(loop.getIndex(), 0);
+
+        assertTrue(loop.after());
+        loop.begin();
+        assertEquals(loop.getValue(), "beta");
+        assertEquals(loop.getIndex(), 1);
+
+        assertTrue(loop.after());
+        loop.begin();
+        assertEquals(loop.getValue(), "gamma");
+        assertEquals(loop.getIndex(), 2);
+
+        assertFalse(loop.after());
+
+        verify();
+    }
+
+    @Test
+    public void iterator_is_null()
+    {
+        Loop loop = new Loop();
+
+        loop.setSource(null);
+
+        assertFalse(loop.setup());
+    }
+
+    @Test
+    public void iterator_is_empty()
+    {
+        Loop loop = new Loop();
+
+        loop.setSource(Collections.EMPTY_LIST);
+
+        assertFalse(loop.setup());
+    }
+}