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 */ 016package com.github.gwtbootstrap.client.ui; 017 018import com.google.gwt.core.client.GWT; 019import com.google.gwt.dom.client.Element; 020import com.google.gwt.dom.client.EventTarget; 021import com.google.gwt.event.logical.shared.ValueChangeEvent; 022import com.google.gwt.i18n.client.HasDirection.Direction; 023import com.google.gwt.i18n.shared.DirectionEstimator; 024import com.google.gwt.safehtml.shared.SafeHtml; 025import com.google.gwt.uibinder.client.UiConstructor; 026import com.google.gwt.user.client.DOM; 027import com.google.gwt.user.client.Event; 028import 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 */ 039public 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}