001/*
002 *  Copyright 2012 GWT-Bootstrap
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.github.gwtbootstrap.client.ui;
017
018import com.github.gwtbootstrap.client.ui.base.HasType;
019import com.github.gwtbootstrap.client.ui.base.IconAnchor;
020import com.github.gwtbootstrap.client.ui.base.NavbarButton;
021import com.github.gwtbootstrap.client.ui.base.StyleHelper;
022import com.github.gwtbootstrap.client.ui.constants.ButtonType;
023import com.github.gwtbootstrap.client.ui.constants.Constants;
024import com.github.gwtbootstrap.client.ui.constants.IconType;
025import com.github.gwtbootstrap.client.ui.resources.ButtonSize;
026import com.google.gwt.dom.client.Element;
027import com.google.gwt.event.dom.client.BlurEvent;
028import com.google.gwt.event.dom.client.BlurHandler;
029import com.google.gwt.event.dom.client.ClickEvent;
030import com.google.gwt.event.dom.client.ClickHandler;
031import com.google.gwt.event.dom.client.DoubleClickEvent;
032import com.google.gwt.event.dom.client.DoubleClickHandler;
033import com.google.gwt.event.dom.client.DragEndEvent;
034import com.google.gwt.event.dom.client.DragEndHandler;
035import com.google.gwt.event.dom.client.DragEnterEvent;
036import com.google.gwt.event.dom.client.DragEnterHandler;
037import com.google.gwt.event.dom.client.DragEvent;
038import com.google.gwt.event.dom.client.DragHandler;
039import com.google.gwt.event.dom.client.DragLeaveEvent;
040import com.google.gwt.event.dom.client.DragLeaveHandler;
041import com.google.gwt.event.dom.client.DragOverEvent;
042import com.google.gwt.event.dom.client.DragOverHandler;
043import com.google.gwt.event.dom.client.DragStartEvent;
044import com.google.gwt.event.dom.client.DragStartHandler;
045import com.google.gwt.event.dom.client.DropEvent;
046import com.google.gwt.event.dom.client.DropHandler;
047import com.google.gwt.event.dom.client.FocusEvent;
048import com.google.gwt.event.dom.client.FocusHandler;
049import com.google.gwt.event.dom.client.GestureChangeEvent;
050import com.google.gwt.event.dom.client.GestureChangeHandler;
051import com.google.gwt.event.dom.client.GestureEndEvent;
052import com.google.gwt.event.dom.client.GestureEndHandler;
053import com.google.gwt.event.dom.client.GestureStartEvent;
054import com.google.gwt.event.dom.client.GestureStartHandler;
055import com.google.gwt.event.dom.client.HasAllDragAndDropHandlers;
056import com.google.gwt.event.dom.client.HasAllFocusHandlers;
057import com.google.gwt.event.dom.client.HasAllGestureHandlers;
058import com.google.gwt.event.dom.client.HasAllKeyHandlers;
059import com.google.gwt.event.dom.client.HasAllMouseHandlers;
060import com.google.gwt.event.dom.client.HasAllTouchHandlers;
061import com.google.gwt.event.dom.client.HasClickHandlers;
062import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
063import com.google.gwt.event.dom.client.KeyDownEvent;
064import com.google.gwt.event.dom.client.KeyDownHandler;
065import com.google.gwt.event.dom.client.KeyPressEvent;
066import com.google.gwt.event.dom.client.KeyPressHandler;
067import com.google.gwt.event.dom.client.KeyUpEvent;
068import com.google.gwt.event.dom.client.KeyUpHandler;
069import com.google.gwt.event.dom.client.MouseDownEvent;
070import com.google.gwt.event.dom.client.MouseDownHandler;
071import com.google.gwt.event.dom.client.MouseMoveEvent;
072import com.google.gwt.event.dom.client.MouseMoveHandler;
073import com.google.gwt.event.dom.client.MouseOutEvent;
074import com.google.gwt.event.dom.client.MouseOutHandler;
075import com.google.gwt.event.dom.client.MouseOverEvent;
076import com.google.gwt.event.dom.client.MouseOverHandler;
077import com.google.gwt.event.dom.client.MouseUpEvent;
078import com.google.gwt.event.dom.client.MouseUpHandler;
079import com.google.gwt.event.dom.client.MouseWheelEvent;
080import com.google.gwt.event.dom.client.MouseWheelHandler;
081import com.google.gwt.event.dom.client.TouchCancelEvent;
082import com.google.gwt.event.dom.client.TouchCancelHandler;
083import com.google.gwt.event.dom.client.TouchEndEvent;
084import com.google.gwt.event.dom.client.TouchEndHandler;
085import com.google.gwt.event.dom.client.TouchMoveEvent;
086import com.google.gwt.event.dom.client.TouchMoveHandler;
087import com.google.gwt.event.dom.client.TouchStartEvent;
088import com.google.gwt.event.dom.client.TouchStartHandler;
089import com.google.gwt.event.shared.HandlerRegistration;
090import com.google.gwt.user.client.ui.HasEnabled;
091
092//@formatter:off
093/**
094 * Button with optional icon.
095 *
096 * <p>
097 * <h3>UiBinder Usage:</h3>
098 *
099 * <pre>
100 * {@code <b:Button icon="TRASH" type="ERROR" toggle="true" loadingText="I'm loading..." completeText="Oh hoh, I completed the action!">Delete</b:Button>}
101 * </pre>
102 *
103 * All arguments are optional.
104 * </p>
105 *
106 * @since 2.0.4.0
107 *
108 * @author Carlos Alexandro Becker
109 *
110 * @author Dominik Mayer
111 *
112 * @see <a
113 *      href="http://twitter.github.com/bootstrap/base-css.html#buttons">Bootstrap
114 *      documentation</a>
115 * @see ButtonGroup
116 * @see ButtonToolbar
117 * @see DropdownButton
118 * @see SplitDropdownButton
119 * @see NavbarButton
120 */
121// @formatter:on
122public class Button extends IconAnchor implements HasClickHandlers,
123                HasDoubleClickHandlers, HasEnabled, HasType<ButtonType>,
124                HasAllDragAndDropHandlers, HasAllFocusHandlers, HasAllGestureHandlers,
125                HasAllKeyHandlers, HasAllMouseHandlers, HasAllTouchHandlers {
126
127        private final LoadingStateBehavior state = new LoadingStateBehavior();
128    private ButtonType type;
129    private ButtonSize size;
130
131        /**
132         * Creates an empty Button.
133         */
134        public Button() {
135                super();
136                addStyleName(Constants.BTN);
137        }
138
139        /**
140         * Creates an Button with ClickHandler
141         * @param handler Butotn ClickHandler
142         */
143        public Button(ClickHandler handler) {
144            this();
145            addClickHandler(handler);
146
147        }
148
149        /**
150         * Creates a Button with the given caption.
151         *
152         * @param caption
153         *            the caption of the Button
154         */
155        public Button(String caption) {
156                this();
157                setText(caption);
158        }
159
160        /**
161         * Create Button with click handler.
162         * @param caption the caption of the Button
163         * @param handler Button Click Handler
164         */
165        public Button(String caption, ClickHandler handler) {
166            this(caption);
167            addClickHandler(handler);
168        }
169
170        /**
171         * Creates a Button with the given caption and icon.
172         *
173         * @param caption
174         *            the caption of the Button
175         * @param icon
176         *            the Icon on the caption's left
177         */
178        public Button(String caption, IconType icon) {
179                this(caption);
180                setIcon(icon);
181        }
182
183    /**
184     * Creates a Button with the given caption and icon and ClickHandler.
185     *
186     * @param caption
187     *            the caption of the Button
188     * @param icon
189     *            the Icon on the caption's left
190     * @param handler
191     *            the ClickHandler of the Button.
192     */
193        public Button(String caption, IconType icon, ClickHandler handler) {
194            this(caption, icon);
195            addClickHandler(handler);
196        }
197
198        /**
199         * Sets the type of the Button.
200         * <p>
201         * Different types give the button a different look.
202         *
203         * @param type
204         *            the type of the Button.
205         */
206        public void setType(ButtonType type) {
207                this.type = type;
208        StyleHelper.changeStyle(this, type, ButtonType.class);
209        }
210
211        /**
212         * Sets the size of the Button.
213         *
214         * @param size
215         *            the size of the Button.
216         */
217        public void setSize(ButtonSize size) {
218                this.size = size;
219        StyleHelper.changeStyle(this, size, ButtonSize.class);
220        }
221
222        /**
223         * Whether the Button is enabled or disabled.
224         * <p>
225         * A disabled widget cannot be used.
226         *
227         * @return <code>false</code> if the Button is disabled.
228         */
229        public boolean isEnabled() {
230                return !getStyleName().contains(Constants.DISABLED);
231        }
232
233        /**
234         * Sets whether the Button is enabled or disabled.
235         * <p>
236         * A disabled widget cannot be used.
237         *
238         * @param enabled
239         *            <code>false</code> if the Button should be disabled. Default:
240         *            <code>true</code>
241         */
242        public void setEnabled(boolean enabled) {
243                if (enabled)
244                        removeStyleName(Constants.DISABLED);
245                else
246                        addStyleName(Constants.DISABLED);
247        }
248
249        /**
250         * Enable ou disable the data-toggle behavior.
251         *
252         * @param toggle
253         *            <code>true</code> will enable this behavior.
254         *            <code>false</code> will disable it or do nothing if it never
255         *            was enabled.
256         */
257        public void setToggle(boolean toggle) {
258                if (toggle)
259                        getElement().setAttribute(Constants.DATA_TOGGLE, "button");
260                else
261                        getElement().removeAttribute(Constants.DATA_TOGGLE);
262        }
263
264    /**
265     * Verify if the property "toggle" is set.
266     *
267     * @return  true: if the data-toggle is equal 'button'
268     *          false: otherwise
269     */
270    public boolean isToggle() {
271        return getElement().getAttribute(Constants.DATA_TOGGLE).equals("button");
272    }
273
274    /**
275     * Verify if the button is toggled.
276     * @return true: if yes (it will contain the "active" styleclass
277     *          false: otherwise.
278     */
279    public boolean isToggled() {
280        return getStyleName().toLowerCase().contains("active");
281    }
282
283        /**
284         * Set a Loading Text to show when some action are in work with this button.
285         *
286         * @see LoadingStateBehavior
287         * @param text
288         */
289        public void setLoadingText(String text) {
290                if (text == null || text.trim().isEmpty()) {
291                        getElement().removeAttribute(Constants.DATA_LOADING_TEXT);
292                        return;
293                }
294
295                getElement().setAttribute(Constants.DATA_LOADING_TEXT, text);
296        }
297
298        /**
299         * Set a Loading Text to show when some action are completed with this
300         * button.
301         *
302         * @see LoadingStateBehavior
303         * @param text
304         */
305        public void setCompleteText(String text) {
306                if (text == null || text.trim().isEmpty()) {
307                        getElement().removeAttribute(Constants.DATA_COMPLETE_TEXT);
308                        return;
309                }
310
311                getElement().setAttribute(Constants.DATA_COMPLETE_TEXT, text);
312        }
313
314        /**
315         * A simple DSL to change the button state to loading, complete, or reset
316         * it.
317         *
318         * @return
319         */
320        public LoadingStateBehavior state() {
321                return state;
322        }
323
324        /**
325         * A simple class to encapsulate the button state managing from the user.
326         *
327         * @author Carlos Alexandro Becker
328         */
329        public class LoadingStateBehavior {
330
331                /**
332                 * put the button in the loading state.
333                 */
334                public void loading() {
335                        setLoadingBehavior("loading");
336                }
337
338                /**
339                 * reset the button state.
340                 */
341                public void reset() {
342                        setLoadingBehavior("reset");
343                }
344
345                /**
346                 * put the button in the completed state.
347                 */
348                public void complete() {
349                        setLoadingBehavior("complete");
350                }
351
352                private void setLoadingBehavior(String behavior) {
353                        setLoadingBehavior(getElement(), behavior);
354                }
355
356                private native void setLoadingBehavior(Element e, String behavior) /*-{
357                        $wnd.jQuery(e).button(behavior);
358                }-*/;
359        }
360
361        /**
362         * {@inheritDoc}
363         */
364        public HandlerRegistration addClickHandler(ClickHandler handler) {
365                return addDomHandler(handler, ClickEvent.getType());
366        }
367
368        /**
369         * {@inheritDoc}
370         */
371        public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) {
372                return addDomHandler(handler, DoubleClickEvent.getType());
373        }
374
375        /**
376         * {@inheritDoc}
377         */
378        public HandlerRegistration addDragEndHandler(DragEndHandler handler) {
379                return addDomHandler(handler, DragEndEvent.getType());
380        }
381
382        /**
383         * {@inheritDoc}
384         */
385        public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) {
386                return addDomHandler(handler, DragEnterEvent.getType());
387        }
388
389        /**
390         * {@inheritDoc}
391         */
392        public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
393                return addDomHandler(handler, DragLeaveEvent.getType());
394        }
395
396        /**
397         * {@inheritDoc}
398         */
399        public HandlerRegistration addDragHandler(DragHandler handler) {
400                return addDomHandler(handler, DragEvent.getType());
401        }
402
403        /**
404         * {@inheritDoc}
405         */
406        public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
407                return addDomHandler(handler, DragOverEvent.getType());
408        }
409
410        /**
411         * {@inheritDoc}
412         */
413        public HandlerRegistration addDragStartHandler(DragStartHandler handler) {
414                return addDomHandler(handler, DragStartEvent.getType());
415        }
416
417        /**
418         * {@inheritDoc}
419         */
420        public HandlerRegistration addDropHandler(DropHandler handler) {
421                return addDomHandler(handler, DropEvent.getType());
422        }
423
424        /**
425         * {@inheritDoc}
426         */
427        public HandlerRegistration addFocusHandler(FocusHandler handler) {
428                return addDomHandler(handler, FocusEvent.getType());
429        }
430
431        /**
432         * {@inheritDoc}
433         */
434        public HandlerRegistration addBlurHandler(BlurHandler handler) {
435                return addDomHandler(handler, BlurEvent.getType());
436        }
437
438        /**
439         * {@inheritDoc}
440         */
441        public HandlerRegistration addGestureStartHandler(
442                        GestureStartHandler handler) {
443                return addDomHandler(handler, GestureStartEvent.getType());
444        }
445
446        /**
447         * {@inheritDoc}
448         */
449        public HandlerRegistration addGestureChangeHandler(
450                        GestureChangeHandler handler) {
451                return addDomHandler(handler, GestureChangeEvent.getType());
452        }
453
454        /**
455         * {@inheritDoc}
456         */
457        public HandlerRegistration addGestureEndHandler(GestureEndHandler handler) {
458                return addDomHandler(handler, GestureEndEvent.getType());
459        }
460
461        /**
462         * {@inheritDoc}
463         */
464        public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
465                return addDomHandler(handler, KeyUpEvent.getType());
466        }
467
468        /**
469         * {@inheritDoc}
470         */
471        public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
472                return addDomHandler(handler, KeyDownEvent.getType());
473        }
474
475        /**
476         * {@inheritDoc}
477         */
478        public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
479                return addDomHandler(handler, KeyPressEvent.getType());
480        }
481
482        /**
483         * {@inheritDoc}
484         */
485        public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
486                return addDomHandler(handler, MouseDownEvent.getType());
487        }
488
489        /**
490         * {@inheritDoc}
491         */
492        public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
493                return addDomHandler(handler, MouseUpEvent.getType());
494        }
495
496        /**
497         * {@inheritDoc}
498         */
499        public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
500                return addDomHandler(handler, MouseOutEvent.getType());
501        }
502
503        /**
504         * {@inheritDoc}
505         */
506        public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
507                return addDomHandler(handler, MouseOverEvent.getType());
508        }
509
510        /**
511         * {@inheritDoc}
512         */
513        public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
514                return addDomHandler(handler, MouseMoveEvent.getType());
515        }
516
517        /**
518         * {@inheritDoc}
519         */
520        public HandlerRegistration addMouseWheelHandler(MouseWheelHandler handler) {
521                return addDomHandler(handler, MouseWheelEvent.getType());
522        }
523
524        /**
525         * {@inheritDoc}
526         */
527        public HandlerRegistration addTouchStartHandler(TouchStartHandler handler) {
528                return addDomHandler(handler, TouchStartEvent.getType());
529        }
530
531        /**
532         * {@inheritDoc}
533         */
534        public HandlerRegistration addTouchMoveHandler(TouchMoveHandler handler) {
535                return addDomHandler(handler, TouchMoveEvent.getType());
536        }
537
538        /**
539         * {@inheritDoc}
540         */
541        public HandlerRegistration addTouchEndHandler(TouchEndHandler handler) {
542                return addDomHandler(handler, TouchEndEvent.getType());
543        }
544
545        /**
546         * {@inheritDoc}
547         */
548        public HandlerRegistration addTouchCancelHandler(TouchCancelHandler handler) {
549                return addDomHandler(handler, TouchCancelEvent.getType());
550        }
551
552    /**
553     * Get Button Type
554     * @return Current Button Type
555     */
556    public ButtonType getType() {
557        return type;
558    }
559
560    /**
561     * Get Button Size
562     * @return Current Button Size
563     */
564    public ButtonSize getSize() {
565        return size;
566    }
567    
568    /**
569     * Set element as a Block Level Button
570     * @param block true:Block Level false:Default
571     */
572    public void setBlock(boolean block) {
573        setStyleName(Constants.BTN_BLOCK, block);
574    }
575
576}