001 /*
002 * Copyright 2012 GWT-Bootstrap
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package com.github.gwtbootstrap.client.ui;
017
018 import com.google.gwt.core.client.GWT;
019 import com.google.gwt.dom.client.Element;
020 import com.google.gwt.dom.client.EventTarget;
021 import com.google.gwt.event.logical.shared.ValueChangeEvent;
022 import com.google.gwt.i18n.client.HasDirection.Direction;
023 import com.google.gwt.i18n.shared.DirectionEstimator;
024 import com.google.gwt.safehtml.shared.SafeHtml;
025 import com.google.gwt.uibinder.client.UiConstructor;
026 import com.google.gwt.user.client.DOM;
027 import com.google.gwt.user.client.Event;
028 import com.google.gwt.user.client.ui.DirectionalTextHelper;
029
030 /**
031 * RadioButton widgets.
032 * <p>
033 * Re-design for Bootstrap.
034 * </p>
035 *
036 * @since 2.0.4.0
037 * @author ohashi keisuke
038 */
039 public class RadioButton extends CheckBox {
040
041 public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR = DirectionalTextHelper.DEFAULT_DIRECTION_ESTIMATOR;
042
043 private Boolean oldValue;
044
045 /**
046 * Creates a new radio associated with a particular group name. All radio
047 * buttons associated with the same group name belong to a
048 * mutually-exclusive set.
049 *
050 * Radio buttons are grouped by their name attribute, so changing their name
051 * using the setName() method will also change their associated group.
052 *
053 * @param name
054 * the group name with which to associate the radio button
055 */
056 @UiConstructor
057 public RadioButton(String name) {
058 super(DOM.createInputRadio(name));
059
060 sinkEvents(Event.ONCLICK);
061 sinkEvents(Event.ONMOUSEUP);
062 sinkEvents(Event.ONBLUR);
063 sinkEvents(Event.ONKEYDOWN);
064 }
065
066 /**
067 * Creates a new radio associated with a particular group, and initialized
068 * with the given HTML label. All radio buttons associated with the same
069 * group name belong to a mutually-exclusive set.
070 *
071 * Radio buttons are grouped by their name attribute, so changing their name
072 * using the setName() method will also change their associated group.
073 *
074 * @param name
075 * the group name with which to associate the radio button
076 * @param label
077 * this radio button's html label
078 */
079 public RadioButton(String name,
080 SafeHtml label) {
081 this(name, label.asString(), true);
082 }
083
084 /**
085 * @see #RadioButton(String, SafeHtml)
086 *
087 * @param name
088 * the group name with which to associate the radio button
089 * @param label
090 * this radio button's html label
091 * @param dir
092 * the text's direction. Note that {@code DEFAULT} means
093 * direction should be inherited from the widget's parent
094 * element.
095 */
096 public RadioButton(String name,
097 SafeHtml label,
098 Direction dir) {
099 this(name);
100 setHTML(label, dir);
101 }
102
103 /**
104 * @see #RadioButton(String, SafeHtml)
105 *
106 * @param name
107 * the group name with which to associate the radio button
108 * @param label
109 * this radio button's html label
110 * @param directionEstimator
111 * A DirectionEstimator object used for automatic direction
112 * adjustment. For convenience,
113 * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
114 */
115 public RadioButton(String name,
116 SafeHtml label,
117 DirectionEstimator directionEstimator) {
118 this(name);
119 setDirectionEstimator(directionEstimator);
120 setHTML(label.asString());
121 }
122
123 /**
124 * Creates a new radio associated with a particular group, and initialized
125 * with the given HTML label. All radio buttons associated with the same
126 * group name belong to a mutually-exclusive set.
127 *
128 * Radio buttons are grouped by their name attribute, so changing their name
129 * using the setName() method will also change their associated group.
130 *
131 * @param name
132 * the group name with which to associate the radio button
133 * @param label
134 * this radio button's label
135 */
136 public RadioButton(String name,
137 String label) {
138 this(name);
139 setText(label);
140 }
141
142 /**
143 * @see #RadioButton(String, SafeHtml)
144 *
145 * @param name
146 * the group name with which to associate the radio button
147 * @param label
148 * this radio button's label
149 * @param dir
150 * the text's direction. Note that {@code DEFAULT} means
151 * direction should be inherited from the widget's parent
152 * element.
153 */
154 public RadioButton(String name,
155 String label,
156 Direction dir) {
157 this(name);
158 setText(label, dir);
159 }
160
161 /**
162 * @see #RadioButton(String, SafeHtml)
163 *
164 * @param name
165 * the group name with which to associate the radio button
166 * @param label
167 * this radio button's label
168 * @param directionEstimator
169 * A DirectionEstimator object used for automatic direction
170 * adjustment. For convenience,
171 * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
172 */
173 public RadioButton(String name,
174 String label,
175 DirectionEstimator directionEstimator) {
176 this(name);
177 setDirectionEstimator(directionEstimator);
178 setText(label);
179 }
180
181 /**
182 * Creates a new radio button associated with a particular group, and
183 * initialized with the given label (optionally treated as HTML). All radio
184 * buttons associated with the same group name belong to a
185 * mutually-exclusive set.
186 *
187 * Radio buttons are grouped by their name attribute, so changing their name
188 * using the setName() method will also change their associated group.
189 *
190 * @param name
191 * name the group with which to associate the radio button
192 * @param label
193 * this radio button's label
194 * @param asHTML
195 * <code>true</code> to treat the specified label as HTML
196 */
197 public RadioButton(String name,
198 String label,
199 boolean asHTML) {
200 this(name);
201 if (asHTML) {
202 setHTML(label);
203 } else {
204 setText(label);
205 }
206 }
207
208 /**
209 * Overridden to send ValueChangeEvents only when appropriate.
210 */
211 @Override
212 public void onBrowserEvent(Event event) {
213
214 switch (DOM.eventGetType(event)) {
215 case Event.ONMOUSEUP:
216 case Event.ONBLUR:
217 case Event.ONKEYDOWN:
218 // Note the old value for onValueChange purposes (in ONCLICK case)
219 oldValue = getValue();
220 break;
221
222 case Event.ONCLICK:
223 EventTarget target = event.getEventTarget();
224
225 if (Element.is(target)
226 && !Element.as(target).getTagName().toUpperCase().equals("INPUT")
227 && asLabel().isOrHasChild(Element.as(target))) {
228 GWT.log("test");
229 // They clicked the label. Note our pre-click value, and
230 // short circuit event routing so that other click handlers
231 // don't hear about it
232 oldValue = getValue();
233 return;
234 }
235
236 // It's not the label. Let our handlers hear about the
237 // click...
238 super.onBrowserEvent(event);
239 // ...and now maybe tell them about the change
240 ValueChangeEvent.fireIfNotEqual(RadioButton.this, oldValue, getValue());
241 return;
242 }
243 super.onBrowserEvent(event);
244 }
245
246 /**
247 * Change the group name of this radio button.
248 *
249 * Radio buttons are grouped by their name attribute, so changing their name
250 * using the setName() method will also change their associated group.
251 *
252 * If changing this group name results in a new radio group with multiple
253 * radio buttons selected, this radio button will remain selected and the
254 * other radio buttons will be unselected.
255 *
256 * @param name
257 * name the group with which to associate the radio button
258 */
259 @Override
260 public void setName(String name) {
261 // Just changing the radio button name tends to break groupiness,
262 // so we have to replace it. Note that replaceInputElement is careful
263 // not to propagate name when it propagates everything else
264 replaceInputElement(DOM.createInputRadio(name));
265 }
266
267 @Override
268 public void sinkEvents(int eventBitsToAdd) {
269 super.sinkEvents(eventBitsToAdd);
270 }
271
272 /**
273 * No-op. CheckBox's click handler is no good for radio button, so don't use
274 * it. Our event handling is all done in {@link #onBrowserEvent}
275 */
276 @Override
277 protected void ensureDomEventHandlers() {
278 }
279 }