001    // Copyright 2007, 2008 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.tapestry5.corelib.components;
016    
017    import org.apache.tapestry5.*;
018    import org.apache.tapestry5.annotations.Environmental;
019    import org.apache.tapestry5.annotations.Mixin;
020    import org.apache.tapestry5.annotations.Parameter;
021    import org.apache.tapestry5.corelib.mixins.DiscardBody;
022    import org.apache.tapestry5.corelib.mixins.RenderDisabled;
023    import org.apache.tapestry5.corelib.mixins.RenderInformals;
024    import org.apache.tapestry5.ioc.annotations.Inject;
025    import org.apache.tapestry5.services.ComponentDefaultProvider;
026    
027    /**
028     * A radio button (i.e., &lt;input type="radio"&gt;). Radio buttons <strong>must</strong> operate within a {@link
029     * RadioContainer} (normally, the {@link RadioGroup} component).
030     * <p/>
031     * If the value parameter is not bound, then the default value is a property of the container component whose name
032     * matches the Radio component's id.
033     */
034    public class Radio implements Field
035    {
036        @Environmental
037        private RadioContainer container;
038    
039        /**
040         * The user presentable label for the field. If not provided, a reasonable label is generated from the component's
041         * id, first by looking for a message key named "id-label" (substituting the component's actual id), then by
042         * converting the actual id to a presentable string (for example, "userId" to "User Id").
043         */
044        @Parameter(defaultPrefix = BindingConstants.LITERAL)
045        private String label;
046    
047        /**
048         * The value associated with this radio button. This is used to determine which radio button will be selected when
049         * the page is rendered, and also becomes the value assigned when the form is submitted.
050         */
051        @Parameter(required = true, principal = true, autoconnect = true)
052        private Object value;
053    
054        @Inject
055        private ComponentDefaultProvider defaultProvider;
056    
057        @Inject
058        private ComponentResources resources;
059    
060        @SuppressWarnings("unused")
061        @Mixin
062        private RenderInformals renderInformals;
063    
064        @SuppressWarnings("unused")
065        @Mixin
066        private RenderDisabled renderDisabled;
067    
068        @SuppressWarnings("unused")
069        @Mixin
070        private DiscardBody discardBody;
071    
072        @Inject
073        private RenderSupport renderSupport;
074    
075        private String clientId;
076    
077        private String controlName;
078    
079        /**
080         * If true, then the field will render out with a disabled attribute (to turn off client-side behavior). Further, a
081         * disabled field ignores any value in the request when the form is submitted.
082         */
083        @Parameter("false")
084        private boolean disabled;
085    
086        String defaultLabel()
087        {
088            return defaultProvider.defaultLabel(resources);
089        }
090    
091        /**
092         * Returns the control name provided by the containing {@link org.apache.tapestry5.RadioContainer}.
093         */
094        public String getControlName()
095        {
096            return controlName;
097        }
098    
099        public String getLabel()
100        {
101            return label;
102        }
103    
104        /**
105         * Returns true if this component has been expressly disabled (via its disabled parameter), or if the {@link
106         * RadioContainer container} has been disabled.
107         */
108        public boolean isDisabled()
109        {
110            return disabled || container.isDisabled();
111        }
112    
113        public String getClientId()
114        {
115            return clientId;
116        }
117    
118        void beginRender(MarkupWriter writer)
119        {
120            String value = container.toClient(this.value);
121    
122            clientId = renderSupport.allocateClientId(resources);
123            controlName = container.getControlName();
124    
125            writer.element("input", "type", "radio", "id", clientId, "name", controlName, "value", value);
126    
127            if (container.isSelected(this.value)) writer.attributes("checked", "checked");
128        }
129    
130        void afterRender(MarkupWriter writer)
131        {
132            writer.end();
133        }
134    
135        /**
136         * Returns false; the RadioComponent component does not support declarative field validation.
137         */
138        public boolean isRequired()
139        {
140            return false;
141        }
142    }