001    package org.gwtbootstrap3.client.ui;
002    
003    /*
004     * #%L
005     * GwtBootstrap3
006     * %%
007     * Copyright (C) 2013 GwtBootstrap3
008     * %%
009     * Licensed under the Apache License, Version 2.0 (the "License");
010     * you may not use this file except in compliance with the License.
011     * You may obtain a copy of the License at
012     * 
013     *      http://www.apache.org/licenses/LICENSE-2.0
014     * 
015     * Unless required by applicable law or agreed to in writing, software
016     * distributed under the License is distributed on an "AS IS" BASIS,
017     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018     * See the License for the specific language governing permissions and
019     * limitations under the License.
020     * #L%
021     */
022    
023    import org.gwtbootstrap3.client.ui.constants.Styles;
024    import org.gwtbootstrap3.client.ui.impl.RadioImpl;
025    
026    import com.google.gwt.core.shared.GWT;
027    import com.google.gwt.dom.client.Document;
028    import com.google.gwt.dom.client.Element;
029    import com.google.gwt.dom.client.InputElement;
030    import com.google.gwt.dom.client.LabelElement;
031    import com.google.gwt.event.logical.shared.ValueChangeEvent;
032    import com.google.gwt.i18n.client.HasDirection.Direction;
033    import com.google.gwt.i18n.shared.DirectionEstimator;
034    import com.google.gwt.safehtml.shared.SafeHtml;
035    import com.google.gwt.uibinder.client.UiConstructor;
036    import com.google.gwt.user.client.DOM;
037    
038    /**
039     * A mutually-exclusive selection radio button widget. Fires
040     * {@link com.google.gwt.event.dom.client.ClickEvent ClickEvents} when the radio
041     * button is clicked, and {@link ValueChangeEvent ValueChangeEvents} when the
042     * button becomes checked. Note, however, that browser limitations prevent
043     * ValueChangeEvents from being sent when the radio button is cleared as a side
044     * effect of another in the group being clicked.
045     * 
046     * <p>
047     * <h3>Built-in Bidi Text Support</h3>
048     * This widget is capable of automatically adjusting its direction according to
049     * its content. This feature is controlled by {@link #setDirectionEstimator} or
050     * passing a DirectionEstimator parameter to the constructor, and is off by
051     * default.
052     * </p>
053     *
054     * @author Sven Jacobs
055     */
056    public class Radio extends CheckBox {
057    
058        private static final RadioImpl impl = GWT.create(RadioImpl.class);
059    
060        /**
061         * Creates a new radio associated with a particular group, and initialized
062         * with the given HTML label. All radio buttons associated with the same
063         * group name belong to a mutually-exclusive set.
064         * 
065         * Radio buttons are grouped by their name attribute, so changing their name
066         * using the setName() method will also change their associated group.
067         * 
068         * @param name
069         *            the group name with which to associate the radio button
070         * @param label
071         *            this radio button's html label
072         */
073        public Radio(String name, SafeHtml label) {
074            this(name, label.asString(), true);
075        }
076    
077        /**
078         * @see #RadioButton(String, SafeHtml)
079         * 
080         * @param name
081         *            the group name with which to associate the radio button
082         * @param label
083         *            this radio button's html label
084         * @param dir
085         *            the text's direction. Note that {@code DEFAULT} means
086         *            direction should be inherited from the widget's parent
087         *            element.
088         */
089        public Radio(String name, SafeHtml label, Direction dir) {
090            this(name);
091            setHTML(label, dir);
092        }
093    
094        /**
095         * @see #RadioButton(String, SafeHtml)
096         * 
097         * @param name
098         *            the group name with which to associate the radio button
099         * @param label
100         *            this radio button's html label
101         * @param directionEstimator
102         *            A DirectionEstimator object used for automatic direction
103         *            adjustment. For convenience,
104         *            {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
105         */
106        public Radio(String name, SafeHtml label, DirectionEstimator directionEstimator) {
107            this(name);
108            setDirectionEstimator(directionEstimator);
109            setHTML(label.asString());
110        }
111    
112        /**
113         * Creates a new radio associated with a particular group, and initialized
114         * with the given HTML label. All radio buttons associated with the same
115         * group name belong to a mutually-exclusive set.
116         * 
117         * Radio buttons are grouped by their name attribute, so changing their name
118         * using the setName() method will also change their associated group.
119         * 
120         * @param name
121         *            the group name with which to associate the radio button
122         * @param label
123         *            this radio button's label
124         */
125        public Radio(String name, String label) {
126            this(name);
127            setText(label);
128        }
129    
130        /**
131         * @see #RadioButton(String, SafeHtml)
132         * 
133         * @param name
134         *            the group name with which to associate the radio button
135         * @param label
136         *            this radio button's label
137         * @param dir
138         *            the text's direction. Note that {@code DEFAULT} means
139         *            direction should be inherited from the widget's parent
140         *            element.
141         */
142        public Radio(String name, String label, Direction dir) {
143            this(name);
144            setText(label, dir);
145        }
146    
147        /**
148         * @see #RadioButton(String, SafeHtml)
149         * 
150         * @param name
151         *            the group name with which to associate the radio button
152         * @param label
153         *            this radio button's label
154         * @param directionEstimator
155         *            A DirectionEstimator object used for automatic direction
156         *            adjustment. For convenience,
157         *            {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
158         */
159        public Radio(String name, String label, DirectionEstimator directionEstimator) {
160            this(name);
161            setDirectionEstimator(directionEstimator);
162            setText(label);
163        }
164    
165        /**
166         * Creates a new radio button associated with a particular group, and
167         * initialized with the given label (optionally treated as HTML). All radio
168         * buttons associated with the same group name belong to a
169         * mutually-exclusive set.
170         * 
171         * Radio buttons are grouped by their name attribute, so changing their name
172         * using the setName() method will also change their associated group.
173         * 
174         * @param name
175         *            name the group with which to associate the radio button
176         * @param label
177         *            this radio button's label
178         * @param asHTML
179         *            <code>true</code> to treat the specified label as HTML
180         */
181        public Radio(String name, String label, boolean asHTML) {
182            this(name);
183            if (asHTML) {
184                setHTML(label);
185            } else {
186                setText(label);
187            }
188        }
189    
190        /**
191         * Creates a new radio associated with a particular group name. All radio
192         * buttons associated with the same group name belong to a
193         * mutually-exclusive set.
194         * 
195         * Radio buttons are grouped by their name attribute, so changing their name
196         * using the setName() method will also change their associated group.
197         * 
198         * @param name
199         *            the group name with which to associate the radio button
200         */
201        @UiConstructor
202        public Radio(String name) {
203            super(DOM.createDiv(), Document.get().createRadioInputElement(name));
204            setStyleName(Styles.RADIO);
205    
206            LabelElement label = Document.get().createLabelElement();
207            label.appendChild(inputElem);
208            label.appendChild(labelElem);
209    
210            getElement().appendChild(label);
211        }
212    
213        protected Radio(Element elem, InputElement inputElement) {
214            super(elem, inputElement);
215        }
216    
217        /**
218         * Change the group name of this radio button.
219         * 
220         * Radio buttons are grouped by their name attribute, so changing their name
221         * using the setName() method will also change their associated group.
222         * 
223         * If changing this group name results in a new radio group with multiple
224         * radio buttons selected, this radio button will remain selected and the
225         * other radio buttons will be unselected.
226         * 
227         * @param name
228         *            name the group with which to associate the radio button
229         */
230        @Override
231        public void setName(String name) {
232            super.setName(name);
233        }
234    
235        @Override
236        protected void ensureDomEventHandlers() {
237            impl.ensureDomEventHandlers(this);
238        }
239    
240        @Override
241        public void sinkEvents(int eventBitsToAdd) {
242            if (isOrWasAttached()) {
243                impl.sinkEvents(eventBitsToAdd, inputElem, labelElem);
244            } else {
245                super.sinkEvents(eventBitsToAdd);
246            }
247        }
248    
249    }