001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.form;
016    
017    import org.apache.tapestry.IMarkupWriter;
018    import org.apache.tapestry.IRequestCycle;
019    import org.apache.tapestry.Tapestry;
020    import org.apache.tapestry.valid.ValidatorException;
021    
022    /**
023     * A component used to render a drop-down list of options that the user may select. [ <a
024     * href="../../../../../ComponentReference/PropertySelection.html">Component Reference </a>]
025     * <p>
026     * Earlier versions of PropertySelection (through release 2.2) were more flexible, they included a
027     * <b>renderer </b> property that controlled how the selection was rendered. Ultimately, this proved
028     * of little value and this portion of functionality was deprecated in 2.3 and will be removed in
029     * 2.3.
030     * <p>
031     * Typically, the values available to be selected are defined using an
032     * {@link java.lang.Enum}. A PropertySelection is dependent on an
033     * {@link IPropertySelectionModel} to provide the list of possible values.
034     * <p>
035     * Often, this is used to select a particular {@link java.lang.Enum} to assign to
036     * a property; the {@link org.apache.tapestry.form.EnumPropertySelectionModel} class simplifies this.
037     * <p>
038     * Often, a drop-down list will contain an initial option that serves both as a label and to represent 
039     * that nothing is selected. This can behavior can easily be achieved by decorating an existing 
040     * {@link IPropertySelectionModel} with a {@link LabeledPropertySelectionModel}.
041     * <p>
042     * 
043     */
044    public abstract class PropertySelection extends AbstractFormComponent implements ValidatableField
045    {   
046        /**
047         * @see org.apache.tapestry.form.AbstractFormComponent#renderFormComponent(org.apache.tapestry.IMarkupWriter, org.apache.tapestry.IRequestCycle)
048         */
049        protected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle)
050        {
051            renderDelegatePrefix(writer, cycle);
052            
053            writer.begin("select");
054            writer.attribute("name", getName());
055            
056            if (isDisabled())
057                writer.attribute("disabled", "disabled");
058            
059            renderIdAttribute(writer, cycle);
060            
061            renderDelegateAttributes(writer, cycle);
062            
063            getValidatableFieldSupport().renderContributions(this, writer, cycle);
064            
065            // Apply informal attributes.
066            renderInformalParameters(writer, cycle);
067            
068            writer.println();
069            
070            IPropertySelectionModel model = getModel();
071            
072            if (model == null)
073                throw Tapestry.createRequiredParameterException(this, "model");
074            
075            getOptionRenderer().renderOptions(writer, cycle, model, getValue());
076            
077            writer.end(); // <select>
078    
079            renderDelegateSuffix(writer, cycle);
080        }
081    
082        /**
083         * @see org.apache.tapestry.form.AbstractFormComponent#rewindFormComponent(org.apache.tapestry.IMarkupWriter, org.apache.tapestry.IRequestCycle)
084         */
085        protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle)
086        {
087            String value = cycle.getParameter(getName());
088            
089            Object object = getModel().translateValue(value);
090            
091            try
092            {
093                getValidatableFieldSupport().validate(this, writer, cycle, object);
094                
095                setValue(object);
096            }
097            catch (ValidatorException e)
098            {
099                getForm().getDelegate().record(e);
100            }
101        }
102        
103        public abstract IPropertySelectionModel getModel();
104        
105        /** @since 2.2 * */
106        public abstract Object getValue();
107    
108        /** @since 2.2 * */
109        public abstract void setValue(Object value);
110        
111        /** Responsible for rendering individual options. */
112        public abstract IOptionRenderer getOptionRenderer();
113        
114        /**
115         * Injected.
116         */
117        public abstract ValidatableFieldSupport getValidatableFieldSupport();
118        
119        /**
120         * @see org.apache.tapestry.form.AbstractFormComponent#isRequired()
121         */
122        public boolean isRequired()
123        {
124            return getValidatableFieldSupport().isRequired(this);
125        }
126    }