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