001package org.gwtbootstrap3.client.ui.base.button;
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 java.util.List;
024
025import org.gwtbootstrap3.client.ui.base.ComplexWidget;
026import org.gwtbootstrap3.client.ui.base.HasActive;
027import org.gwtbootstrap3.client.ui.base.HasDataTarget;
028import org.gwtbootstrap3.client.ui.base.HasSize;
029import org.gwtbootstrap3.client.ui.base.HasType;
030import org.gwtbootstrap3.client.ui.base.helper.StyleHelper;
031import org.gwtbootstrap3.client.ui.base.mixin.ActiveMixin;
032import org.gwtbootstrap3.client.ui.base.mixin.DataTargetMixin;
033import org.gwtbootstrap3.client.ui.base.mixin.EnabledMixin;
034import org.gwtbootstrap3.client.ui.base.mixin.FocusableMixin;
035import org.gwtbootstrap3.client.ui.constants.Attributes;
036import org.gwtbootstrap3.client.ui.constants.ButtonDismiss;
037import org.gwtbootstrap3.client.ui.constants.ButtonSize;
038import org.gwtbootstrap3.client.ui.constants.ButtonType;
039import org.gwtbootstrap3.client.ui.constants.Styles;
040
041import com.google.gwt.dom.client.Document;
042import com.google.gwt.dom.client.Element;
043import com.google.gwt.dom.client.NativeEvent;
044import com.google.gwt.event.dom.client.ClickEvent;
045import com.google.gwt.event.dom.client.ClickHandler;
046import com.google.gwt.event.dom.client.DomEvent;
047import com.google.gwt.event.dom.client.HasAllMouseHandlers;
048import com.google.gwt.event.dom.client.HasClickHandlers;
049import com.google.gwt.event.dom.client.MouseDownEvent;
050import com.google.gwt.event.dom.client.MouseDownHandler;
051import com.google.gwt.event.dom.client.MouseMoveEvent;
052import com.google.gwt.event.dom.client.MouseMoveHandler;
053import com.google.gwt.event.dom.client.MouseOutEvent;
054import com.google.gwt.event.dom.client.MouseOutHandler;
055import com.google.gwt.event.dom.client.MouseOverEvent;
056import com.google.gwt.event.dom.client.MouseOverHandler;
057import com.google.gwt.event.dom.client.MouseUpEvent;
058import com.google.gwt.event.dom.client.MouseUpHandler;
059import com.google.gwt.event.dom.client.MouseWheelEvent;
060import com.google.gwt.event.dom.client.MouseWheelHandler;
061import com.google.gwt.event.shared.HandlerRegistration;
062import com.google.gwt.user.client.ui.Focusable;
063import com.google.gwt.user.client.ui.HasEnabled;
064import com.google.gwt.user.client.ui.Widget;
065
066/**
067 * Abstract base class for different kinds of buttons.
068 *
069 * @author Sven Jacobs
070 * @author Joshua Godi
071 */
072public abstract class AbstractButton extends ComplexWidget implements HasEnabled, HasActive, HasType<ButtonType>,
073        HasSize<ButtonSize>, HasDataTarget, HasClickHandlers, Focusable, HasAllMouseHandlers {
074
075    public class ButtonStateHandler {
076        private ButtonStateHandler() {
077        }
078
079        public void loading() {
080            button(getElement(), "loading");
081        }
082
083        public void reset() {
084            button(getElement(), "reset");
085        }
086
087        /**
088         * Resets button to specified text state.
089         *
090         * @param state Text state
091         */
092        public void reset(final String state) {
093            button(getElement(), state);
094        }
095    }
096
097    private final ButtonStateHandler buttonStateHandler = new ButtonStateHandler();
098    private final DataTargetMixin<AbstractButton> targetMixin = new DataTargetMixin<AbstractButton>(this);
099    private final ActiveMixin<AbstractButton> activeMixin = new ActiveMixin<AbstractButton>(this);
100    private final FocusableMixin<AbstractButton> focusableMixin = new FocusableMixin<AbstractButton>(this);
101    private final EnabledMixin<AbstractButton> enabledMixin = new EnabledMixin<AbstractButton>(this);
102
103    /**
104     * Creates button with DEFAULT type.
105     */
106    protected AbstractButton() {
107        this(ButtonType.DEFAULT);
108    }
109
110    protected AbstractButton(final ButtonType type) {
111        setElement(createElement());
112        setStyleName(Styles.BTN);
113        setType(type);
114    }
115
116    @Override
117    public boolean isActive() {
118        return activeMixin.isActive();
119    }
120
121    @Override
122    public void setActive(final boolean active) {
123        activeMixin.setActive(active);
124    }
125
126    @Override
127    public void setEnabled(final boolean enabled) {
128        enabledMixin.setEnabled(enabled);
129    }
130
131    @Override
132    public boolean isEnabled() {
133        return enabledMixin.isEnabled();
134    }
135
136    @Override
137    public HandlerRegistration addClickHandler(final ClickHandler handler) {
138        return addDomHandler(handler, ClickEvent.getType());
139    }
140
141    /**
142     * Sets type of button.
143     *
144     * @param type Type of button
145     */
146    @Override
147    public void setType(final ButtonType type) {
148        StyleHelper.addUniqueEnumStyleName(this, ButtonType.class, type);
149    }
150
151    @Override
152    public ButtonType getType() {
153        return ButtonType.fromStyleName(getStyleName());
154    }
155
156    /**
157     * Sets size of button.
158     *
159     * @param size Size of button
160     */
161    @Override
162    public void setSize(final ButtonSize size) {
163        StyleHelper.addUniqueEnumStyleName(this, ButtonSize.class, size);
164    }
165
166    @Override
167    public ButtonSize getSize() {
168        return ButtonSize.fromStyleName(getStyleName());
169    }
170
171    @Override
172    public void setDataTargetWidgets(final List<Widget> widgets) {
173        targetMixin.setDataTargetWidgets(widgets);
174    }
175
176    @Override
177    public void setDataTargetWidget(final Widget widget) {
178        targetMixin.setDataTargetWidget(widget);
179    }
180
181    @Override
182    public void setDataTarget(final String dataTarget) {
183        targetMixin.setDataTarget(dataTarget);
184    }
185
186    @Override
187    public String getDataTarget() {
188        return targetMixin.getDataTarget();
189    }
190
191    @Override
192    public int getTabIndex() {
193        return focusableMixin.getTabIndex();
194    }
195
196    @Override
197    public void setAccessKey(final char key) {
198        focusableMixin.setAccessKey(key);
199    }
200
201    @Override
202    public void setFocus(final boolean focused) {
203        focusableMixin.setFocus(focused);
204    }
205
206    @Override
207    public void setTabIndex(final int index) {
208        focusableMixin.setTabIndex(index);
209    }
210
211    @Override
212    public HandlerRegistration addMouseDownHandler(final MouseDownHandler handler) {
213        return addDomHandler(handler, MouseDownEvent.getType());
214    }
215
216    @Override
217    public HandlerRegistration addMouseMoveHandler(final MouseMoveHandler handler) {
218        return addDomHandler(handler, MouseMoveEvent.getType());
219    }
220
221    @Override
222    public HandlerRegistration addMouseOutHandler(final MouseOutHandler handler) {
223        return addDomHandler(handler, MouseOutEvent.getType());
224    }
225
226    @Override
227    public HandlerRegistration addMouseOverHandler(final MouseOverHandler handler) {
228        return addDomHandler(handler, MouseOverEvent.getType());
229    }
230
231    @Override
232    public HandlerRegistration addMouseUpHandler(final MouseUpHandler handler) {
233        return addDomHandler(handler, MouseUpEvent.getType());
234    }
235
236    @Override
237    public HandlerRegistration addMouseWheelHandler(final MouseWheelHandler handler) {
238        return addDomHandler(handler, MouseWheelEvent.getType());
239    }
240
241    /**
242     * Makes button a block level element that spawns full width of parent.
243     *
244     * @param block True for block level element
245     */
246    public void setBlock(final boolean block) {
247        if (block) {
248            addStyleName(Styles.BTN_BLOCK);
249        } else {
250            removeStyleName(Styles.BTN_BLOCK);
251        }
252    }
253
254    /**
255     * Sets dismiss type of button.
256     * <p/>
257     * If button is inside a
258     * {@link org.gwtbootstrap3.client.ui.Modal} and dismiss type is
259     * {@code MODAL} the button will act as the dismiss (close) button for this
260     * Modal. Same goes for {@link org.gwtbootstrap3.client.ui.Alert}
261     * and dismiss type {@code ALERT}.
262     *
263     * @param dismiss Dismiss type of button
264     * @see org.gwtbootstrap3.client.ui.Modal
265     * @see org.gwtbootstrap3.client.ui.Alert
266     */
267    public void setDataDismiss(final ButtonDismiss dismiss) {
268        if (dismiss != null) {
269            getElement().setAttribute(Attributes.DATA_DISMISS, dismiss.getDismiss());
270        } else {
271            getElement().removeAttribute(Attributes.DATA_DISMISS);
272        }
273    }
274
275    public void setDataLoadingText(final String loadingText) {
276        if (loadingText != null) {
277            getElement().setAttribute(Attributes.DATA_LOADING_TEXT, loadingText);
278        } else {
279            getElement().removeAttribute(Attributes.DATA_LOADING_TEXT);
280        }
281    }
282
283    public void toggle() {
284        button(getElement(), "toggle");
285    }
286
287    public ButtonStateHandler state() {
288        return buttonStateHandler;
289    }
290
291    public void click() {
292        final NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false, false, false, false);
293        DomEvent.fireNativeEvent(event, this);
294    }
295
296    protected abstract Element createElement();
297
298    // @formatter:off
299
300    private native void button(final Element e, final String arg) /*-{
301        $wnd.jQuery(e).button(arg);
302    }-*/;
303}