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.base.HasActive;
024 import org.gwtbootstrap3.client.ui.base.HasIcon;
025 import org.gwtbootstrap3.client.ui.base.HasIconPosition;
026 import org.gwtbootstrap3.client.ui.base.HasSize;
027 import org.gwtbootstrap3.client.ui.base.HasType;
028 import org.gwtbootstrap3.client.ui.base.helper.StyleHelper;
029 import org.gwtbootstrap3.client.ui.base.mixin.ActiveMixin;
030 import org.gwtbootstrap3.client.ui.constants.ButtonSize;
031 import org.gwtbootstrap3.client.ui.constants.ButtonType;
032 import org.gwtbootstrap3.client.ui.constants.IconFlip;
033 import org.gwtbootstrap3.client.ui.constants.IconPosition;
034 import org.gwtbootstrap3.client.ui.constants.IconRotate;
035 import org.gwtbootstrap3.client.ui.constants.IconSize;
036 import org.gwtbootstrap3.client.ui.constants.IconType;
037 import org.gwtbootstrap3.client.ui.constants.Styles;
038
039 import com.google.gwt.dom.client.Document;
040 import com.google.gwt.dom.client.InputElement;
041 import com.google.gwt.event.dom.client.ClickEvent;
042 import com.google.gwt.event.dom.client.ClickHandler;
043 import com.google.gwt.event.logical.shared.ValueChangeEvent;
044 import com.google.gwt.i18n.client.HasDirection.Direction;
045 import com.google.gwt.i18n.shared.DirectionEstimator;
046 import com.google.gwt.safehtml.shared.SafeHtml;
047 import com.google.gwt.uibinder.client.UiConstructor;
048 import com.google.gwt.user.client.DOM;
049 import com.google.gwt.user.client.Event;
050
051 /**
052 * Button representing a radio button used within a {@link ButtonGroup} that has
053 * toggle set to {@code Toogle.BUTTONS}.
054 * <p/>
055 * If you are looking for a classic radio button see {@link RadioButton}.
056 *
057 * @author Sven Jacobs
058 */
059 public class RadioButton extends Radio implements HasActive,
060 HasType<ButtonType>, HasSize<ButtonSize>, HasIcon, HasIconPosition {
061
062 private final ActiveMixin<RadioButton> activeMixin = new ActiveMixin<RadioButton>(this);
063
064 private IconPosition iconPosition = IconPosition.LEFT;
065 private Icon icon;
066
067
068 /**
069 * Creates a new radio associated with a particular group, and initialized
070 * with the given HTML label. All radio buttons associated with the same
071 * group name belong to a mutually-exclusive set.
072 *
073 * Radio buttons are grouped by their name attribute, so changing their name
074 * using the setName() method will also change their associated group.
075 *
076 * @param name
077 * the group name with which to associate the radio button
078 * @param label
079 * this radio button's html label
080 */
081 public RadioButton(String name, SafeHtml label) {
082 this(name, label.asString(), true);
083 }
084
085 /**
086 * @see #RadioButtonToggle(String, SafeHtml)
087 *
088 * @param name
089 * the group name with which to associate the radio button
090 * @param label
091 * this radio button's html label
092 * @param dir
093 * the text's direction. Note that {@code DEFAULT} means
094 * direction should be inherited from the widget's parent
095 * element.
096 */
097 public RadioButton(String name, SafeHtml label, Direction dir) {
098 this(name);
099 setHTML(label, dir);
100 }
101
102 /**
103 * @see #RadioButtonToggle(String, SafeHtml)
104 *
105 * @param name
106 * the group name with which to associate the radio button
107 * @param label
108 * this radio button's html label
109 * @param directionEstimator
110 * A DirectionEstimator object used for automatic direction
111 * adjustment. For convenience,
112 * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
113 */
114 public RadioButton(String name, SafeHtml label, DirectionEstimator directionEstimator) {
115 this(name);
116 setDirectionEstimator(directionEstimator);
117 setHTML(label.asString());
118 }
119
120 /**
121 * Creates a new radio associated with a particular group, and initialized
122 * with the given HTML label. All radio buttons associated with the same
123 * group name belong to a mutually-exclusive set.
124 *
125 * Radio buttons are grouped by their name attribute, so changing their name
126 * using the setName() method will also change their associated group.
127 *
128 * @param name
129 * the group name with which to associate the radio button
130 * @param label
131 * this radio button's label
132 */
133 public RadioButton(String name, String label) {
134 this(name);
135 setText(label);
136 }
137
138 /**
139 * @see #RadioButtonToggle(String, SafeHtml)
140 *
141 * @param name
142 * the group name with which to associate the radio button
143 * @param label
144 * this radio button's label
145 * @param dir
146 * the text's direction. Note that {@code DEFAULT} means
147 * direction should be inherited from the widget's parent
148 * element.
149 */
150 public RadioButton(String name, String label, Direction dir) {
151 this(name);
152 setText(label, dir);
153 }
154
155 /**
156 * @see #RadioButtonToggle(String, SafeHtml)
157 *
158 * @param name
159 * the group name with which to associate the radio button
160 * @param label
161 * this radio button's label
162 * @param directionEstimator
163 * A DirectionEstimator object used for automatic direction
164 * adjustment. For convenience,
165 * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
166 */
167 public RadioButton(String name, String label, DirectionEstimator directionEstimator) {
168 this(name);
169 setDirectionEstimator(directionEstimator);
170 setText(label);
171 }
172
173 /**
174 * Creates a new radio button associated with a particular group, and
175 * initialized with the given label (optionally treated as HTML). All radio
176 * buttons associated with the same group name belong to a
177 * mutually-exclusive set.
178 *
179 * Radio buttons are grouped by their name attribute, so changing their name
180 * using the setName() method will also change their associated group.
181 *
182 * @param name
183 * name the group with which to associate the radio button
184 * @param label
185 * this radio button's label
186 * @param asHTML
187 * <code>true</code> to treat the specified label as HTML
188 */
189 public RadioButton(String name, String label, boolean asHTML) {
190 this(name);
191 if (asHTML) {
192 setHTML(label);
193 } else {
194 setText(label);
195 }
196 }
197
198 @UiConstructor
199 public RadioButton(String name) {
200 this(Document.get().createRadioInputElement(name));
201 }
202
203 protected RadioButton(InputElement element) {
204 super(DOM.createLabel(), element);
205
206 setStyleName(Styles.BTN);
207 setType(ButtonType.DEFAULT);
208
209 getElement().appendChild(inputElem);
210 getElement().appendChild(Document.get().createTextNode(" "));
211 getElement().appendChild(labelElem);
212 getElement().appendChild(Document.get().createTextNode(" "));
213 }
214
215 @Override
216 protected void ensureDomEventHandlers() {
217 // Use a ClickHandler since Bootstrap's jQuery does not trigger native
218 // change events:
219 // http://learn.jquery.com/events/triggering-event-handlers/
220 addClickHandler(new ClickHandler() {
221
222 @Override
223 public void onClick(ClickEvent event) {
224 ValueChangeEvent.fire(RadioButton.this, getValue());
225 }
226
227 });
228 }
229
230 @Override
231 public void sinkEvents(int eventBitsToAdd) {
232 // Sink on the actual element because that's what gets clicked
233 if (isOrWasAttached()) {
234 Event.sinkEvents(getElement(),
235 eventBitsToAdd | Event.getEventsSunk(getElement()));
236 } else {
237 super.sinkEvents(eventBitsToAdd);
238 }
239 }
240
241 @Override
242 public void setSize(ButtonSize size) {
243 StyleHelper.addUniqueEnumStyleName(this, ButtonSize.class, size);
244 }
245
246 @Override
247 public ButtonSize getSize() {
248 return ButtonSize.fromStyleName(getStyleName());
249 }
250
251 @Override
252 public void setType(ButtonType type) {
253 StyleHelper.addUniqueEnumStyleName(this, ButtonType.class, type);
254 }
255
256 @Override
257 public ButtonType getType() {
258 return ButtonType.fromStyleName(getStyleName());
259 }
260
261 @Override
262 public void setActive(boolean active) {
263 setValue(active);
264 activeMixin.setActive(active);
265 }
266
267 @Override
268 public boolean isActive() {
269 return activeMixin.isActive();
270 }
271
272 @Override
273 public void setIconPosition(IconPosition iconPosition) {
274 this.iconPosition = iconPosition;
275 render();
276 }
277
278 @Override
279 public IconPosition getIconPosition() {
280 return iconPosition;
281 }
282
283 @Override
284 public void setIcon(IconType iconType) {
285 getActualIcon().setType(iconType);
286 }
287
288 @Override
289 public IconType getIcon() {
290 return getActualIcon().getType();
291 }
292
293 @Override
294 public void setIconSize(IconSize iconSize) {
295 getActualIcon().setSize(iconSize);
296 }
297
298 @Override
299 public IconSize getIconSize() {
300 return getActualIcon().getSize();
301 }
302
303 @Override
304 public void setIconFlip(IconFlip iconFlip) {
305 getActualIcon().setFlip(iconFlip);
306 }
307
308 @Override
309 public IconFlip getIconFlip() {
310 return getActualIcon().getFlip();
311 }
312
313 @Override
314 public void setIconRotate(IconRotate iconRotate) {
315 getActualIcon().setRotate(iconRotate);
316 }
317
318 @Override
319 public IconRotate getIconRotate() {
320 return getActualIcon().getRotate();
321 }
322
323 @Override
324 public void setIconBordered(boolean iconBordered) {
325 getActualIcon().setBorder(iconBordered);
326 }
327
328 @Override
329 public boolean isIconBordered() {
330 return getActualIcon().isBorder();
331 }
332
333 @Override
334 public void setIconMuted(boolean iconMuted) {
335 getActualIcon().setMuted(iconMuted);
336 }
337
338 @Override
339 public boolean isIconMuted() {
340 return getActualIcon().isMuted();
341 }
342
343 @Override
344 public void setIconLight(boolean iconLight) {
345 getActualIcon().setLight(iconLight);
346 }
347
348 @Override
349 public boolean isIconLight() {
350 return getActualIcon().isLight();
351 }
352
353 @Override
354 public void setIconSpin(boolean iconSpin) {
355 getActualIcon().setSpin(iconSpin);
356 }
357
358 @Override
359 public boolean isIconSpin() {
360 return getActualIcon().isSpin();
361 }
362
363 @Override
364 public void setIconFixedWidth(boolean iconFixedWidth) {
365 getActualIcon().setFixedWidth(iconFixedWidth);
366 }
367
368 @Override
369 public boolean isIconFixedWidth() {
370 return getActualIcon().isFixedWidth();
371 }
372
373 private Icon getActualIcon() {
374 if (icon == null) {
375 icon = new Icon();
376 render();
377 }
378 return icon;
379 }
380
381 private void render() {
382 if (iconPosition == IconPosition.LEFT) {
383 getElement().insertAfter(icon.getElement(), inputElem);
384 } else {
385 getElement().insertAfter(icon.getElement(), null);
386 }
387 }
388
389 }