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