001    package org.gwtbootstrap3.extras.toggleswitch.client.ui.base;
002    
003    /*
004     * #%L
005     * GwtBootstrap3
006     * %%
007     * Copyright (C) 2013 - 2015 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 com.google.gwt.dom.client.Element;
024    import com.google.gwt.editor.client.IsEditor;
025    import com.google.gwt.editor.client.LeafValueEditor;
026    import com.google.gwt.editor.client.adapters.TakesValueEditor;
027    import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
028    import com.google.gwt.event.logical.shared.ValueChangeEvent;
029    import com.google.gwt.event.logical.shared.ValueChangeHandler;
030    import com.google.gwt.event.shared.HandlerRegistration;
031    import com.google.gwt.user.client.ui.*;
032    
033    import org.gwtbootstrap3.client.ui.Icon;
034    import org.gwtbootstrap3.client.ui.base.HasId;
035    import org.gwtbootstrap3.client.ui.base.HasResponsiveness;
036    import org.gwtbootstrap3.client.ui.base.HasSize;
037    import org.gwtbootstrap3.client.ui.base.helper.StyleHelper;
038    import org.gwtbootstrap3.client.ui.base.mixin.AttributeMixin;
039    import org.gwtbootstrap3.client.ui.base.mixin.IdMixin;
040    import org.gwtbootstrap3.client.ui.constants.DeviceSize;
041    import org.gwtbootstrap3.client.ui.constants.IconSize;
042    import org.gwtbootstrap3.client.ui.constants.IconType;
043    import org.gwtbootstrap3.extras.toggleswitch.client.ui.base.constants.ColorType;
044    import org.gwtbootstrap3.extras.toggleswitch.client.ui.base.constants.SizeType;
045    
046    /**
047     * Original source from http://www.bootstrap-switch.org/
048     * @author Grant Slender
049     */
050    public class ToggleSwitchBase extends Widget implements HasSize<SizeType>, HasValue<Boolean>, HasValueChangeHandlers<Boolean>,
051            HasEnabled, HasVisibility, HasId, HasName, HasResponsiveness, IsEditor<LeafValueEditor<Boolean>> {
052    
053        private final SimpleCheckBox checkBox;
054        private SizeType size = SizeType.REGULAR;
055        private ColorType onColor = ColorType.DEFAULT;
056        private ColorType offColor = ColorType.PRIMARY;
057        private final IdMixin<ToggleSwitchBase> idMixin = new IdMixin<ToggleSwitchBase>(this);
058        private final AttributeMixin<ToggleSwitchBase> attributeMixin = new AttributeMixin<ToggleSwitchBase>(this);
059        private LeafValueEditor<Boolean> editor;
060    
061        protected ToggleSwitchBase(SimpleCheckBox checkBox) {
062            this.checkBox = checkBox;
063            // remove the gwt styles
064            checkBox.setStyleName("");
065            setElement((Element) checkBox.getElement());
066        }
067    
068        @Override
069        protected void onLoad() {
070            super.onLoad();
071            switchInit(getElement());
072        }
073    
074        @Override
075        protected void onUnload() {
076            super.onUnload();
077            switchDestroy(getElement());
078        }
079    
080        @Override
081        public void setVisibleOn(final DeviceSize deviceSize) {
082            StyleHelper.setVisibleOn(this, deviceSize);
083        }
084    
085        @Override
086        public void setHiddenOn(final DeviceSize deviceSize) {
087            StyleHelper.setHiddenOn(this, deviceSize);
088        }
089    
090        @Override
091        public void setId(final String id) {
092            idMixin.setId(id);
093        }
094    
095        @Override
096        public String getId() {
097            return idMixin.getId();
098        }
099        
100        @Override
101        public void setName(String name) {
102            checkBox.setName(name);
103        }
104    
105        @Override
106        public String getName() {
107            return checkBox.getName();
108        }
109    
110        @Override
111        public boolean isEnabled() {
112            return !getBooleanAttribute(Option.DISABLED);
113        }
114    
115        @Override
116        public void setEnabled(final boolean enabled) {
117            updateSwitch(Option.DISABLED, !enabled);
118        }
119    
120        @Override
121        public SizeType getSize() {
122            return size;
123        }
124    
125        @Override
126        public void setSize(final SizeType size) {
127            this.size = size;
128            updateSwitch(Option.SIZE, size.getType());
129        }
130    
131        public ColorType getOnColor() {
132            return onColor;
133        }
134    
135        public void setOnColor(final ColorType onColor) {
136            this.onColor = onColor;
137            updateSwitch(Option.ON_COLOR, onColor.getType());
138        }
139    
140        public ColorType getOffColor() {
141            return offColor;
142        }
143    
144        public void setOffColor(final ColorType offColor) {
145            this.offColor = offColor;
146            updateSwitch(Option.OFF_COLOR, offColor.getType());
147        }
148    
149        public boolean isAnimate() {
150            return getBooleanAttribute(Option.ANIMATE);
151        }
152    
153        public void setAnimate(final boolean animate) {
154            updateSwitch(Option.ANIMATE, animate);
155        }
156    
157        public String getOnText() {
158            return getStringAttribute(Option.ON_TEXT);
159        }
160    
161        public void setOnText(final String onText) {
162            updateSwitch(Option.ON_TEXT, onText);
163        }
164    
165        public void setOnIcon(final IconType iconType) {
166            String text = createIconHtml(iconType);
167            setOnText(text);
168        }
169    
170        public String getOffText() {
171            return getStringAttribute(Option.OFF_TEXT);
172        }
173    
174        public void setOffText(final String offText) {
175            updateSwitch(Option.OFF_TEXT, offText);
176        }
177    
178        public void setOffIcon(final IconType iconType) {
179            String text = createIconHtml(iconType);
180            setOffText(text);
181        }
182    
183        public String getLabelText() {
184            return getStringAttribute(Option.LABEL_TEXT);
185        }
186    
187        public void setLabelText(final String labelText) {
188            updateSwitch(Option.LABEL_TEXT, labelText);
189        }
190    
191        @Override
192        public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Boolean> handler) {
193            return addHandler(handler, ValueChangeEvent.getType());
194        }
195    
196        @Override
197        public Boolean getValue() {
198            if (isAttached()) {
199                return switchState(getElement());
200            }
201            return checkBox.getValue();
202        }
203    
204        @Override
205        public void setValue(final Boolean value) {
206            setValue(value, false);
207        }
208    
209        @Override
210        public void setValue(final Boolean value, final boolean fireEvents) {
211            Boolean oldValue = getValue();
212            if (isAttached()) {
213                switchState(getElement(), value, true);
214            } else {
215                checkBox.setValue(value);
216            }
217            if (fireEvents) {
218                ValueChangeEvent.fireIfNotEqual(ToggleSwitchBase.this, oldValue, value);
219            }
220        }
221    
222        public void onChange(final boolean value) {
223            ValueChangeEvent.fire(this, value);
224        }
225    
226        @Override
227        public LeafValueEditor<Boolean> asEditor() {
228            if (editor == null) {
229                editor = TakesValueEditor.of(this);
230            }
231            return editor;
232        }
233        
234        public boolean isReadOnly() {
235            return getBooleanAttribute(Option.READONLY);
236        }
237    
238        public void setReadOnly(boolean readOnly) {
239            updateSwitch(Option.READONLY, readOnly);
240        }
241    
242        public boolean isIndeterminate() {
243            return getBooleanAttribute(Option.INDETERMINATE);
244        }
245    
246        /**
247         * Indeterminate state.
248         */
249        public void setIndeterminate(boolean indeterminate) {
250            updateSwitch(Option.INDETERMINATE, indeterminate);
251        }
252        
253        public boolean isInverse() {
254            return getBooleanAttribute(Option.INVERSE);
255        }
256        
257        /**
258         * Inverse switch direction.
259         */
260        public void setInverse(boolean inverse) {
261            updateSwitch(Option.INVERSE, inverse);
262        }
263        
264        public boolean isRadioAllOff() {
265            return getBooleanAttribute(Option.RADIO_ALL_OFF);
266        }
267        
268        /**
269         * Allow this radio button to be unchecked by the user.
270         */
271        public void setRadioAllOff(boolean radioAllOff) {
272            updateSwitch(Option.RADIO_ALL_OFF, radioAllOff);
273        }
274    
275        /**
276         * Sets the handle's width.
277         * @param labelWidth - set to "auto" (default) for automatic sizing, integer otherwise
278         */
279        public void setHandleWidth(String handleWidth) {
280            updateSwitch(Option.HANDLE_WIDTH, handleWidth);
281        }
282    
283        /**
284         * Sets the label's width (the space between handles).
285         * @param labelWidth - set to "auto" (default) for automatic sizing, integer otherwise
286         */
287        public void setLabelWidth(String labelWidth) {
288            updateSwitch(Option.LABEL_WIDTH, labelWidth);
289        }
290        
291        private String createIconHtml(IconType iconType) {
292            // Fix incorrect handle width when using icons
293            setHandleWidth("30");
294            final Icon icon = new Icon(iconType);
295            icon.setSize(IconSize.LARGE);
296            return icon.getElement().getString();
297        }
298        
299        private void updateSwitch(Option option, String value) {
300            if (isAttached()) {
301                switchCmd(getElement(), option.getCommand(), value);
302            } else {
303                attributeMixin.setAttribute(option.getAttribute(), value);
304            }
305        }
306        
307        private void updateSwitch(Option option, boolean value) {
308            if (isAttached()) {
309                switchCmd(getElement(), option.getCommand(), value);
310            } else {
311                attributeMixin.setAttribute(option.getAttribute(), Boolean.toString(value));
312            }
313        }
314        
315        private String getStringAttribute(Option option) {
316            if (isAttached()) {
317                return getCommandStringValue(getElement(), option.getCommand());
318            } else {
319                return attributeMixin.getAttribute(option.getAttribute());
320            }
321        }
322        
323        private boolean getBooleanAttribute(Option option) {
324            if (isAttached()) {
325                return getCommandBooleanValue(getElement(), option.getCommand());
326            } else {
327                String value = attributeMixin.getAttribute(option.getAttribute());
328                if (value != null && !value.isEmpty()) {
329                    return Boolean.valueOf(value);
330                } else {
331                    return false;
332                }
333            }
334        }
335    
336        private native void switchInit(Element e) /*-{
337            $wnd.jQuery(e).bootstrapSwitch();
338    
339            var me = this;
340            $wnd.jQuery(e).on('switchChange.bootstrapSwitch', function (em, state) {
341                me.@org.gwtbootstrap3.extras.toggleswitch.client.ui.base.ToggleSwitchBase::onChange(Z)(state);
342            });
343        }-*/;
344    
345        private native void switchDestroy(Element e) /*-{
346            $wnd.jQuery(e).off('switchChange.bootstrapSwitch');
347            $wnd.jQuery(e).bootstrapSwitch('destroy');
348        }-*/;
349    
350        private native void switchCmd(Element e, String cmd, String value) /*-{
351            $wnd.jQuery(e).bootstrapSwitch(cmd, value);
352        }-*/;
353    
354        private native void switchCmd(Element e, String cmd, boolean value) /*-{
355            $wnd.jQuery(e).bootstrapSwitch(cmd, value);
356        }-*/;
357        
358        private native String getCommandStringValue(Element e, String cmd) /*-{
359            return $wnd.jQuery(e).bootstrapSwitch(cmd);
360        }-*/;
361        
362        private native boolean getCommandBooleanValue(Element e, String cmd) /*-{
363            return $wnd.jQuery(e).bootstrapSwitch(cmd);
364        }-*/;
365    
366        private native void switchState(Element e, boolean value, boolean skip) /*-{
367            $wnd.jQuery(e).bootstrapSwitch('state', value, skip);
368        }-*/;
369    
370        private native boolean switchState(Element e) /*-{
371            return $wnd.jQuery(e).bootstrapSwitch('state');
372        }-*/;
373    }