001/*
002 * #%L
003 * GwtMaterial
004 * %%
005 * Copyright (C) 2015 - 2017 GwtMaterialDesign
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 * 
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 * 
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package gwt.material.design.client.base;
021
022import com.google.gwt.dom.client.Element;
023import com.google.gwt.dom.client.Style;
024import com.google.gwt.dom.client.Style.Float;
025import com.google.gwt.dom.client.Style.FontWeight;
026import com.google.gwt.event.dom.client.*;
027import com.google.gwt.event.logical.shared.AttachEvent;
028import com.google.gwt.event.shared.HandlerRegistration;
029import com.google.gwt.user.client.ui.*;
030import gwt.material.design.client.base.helper.StyleHelper;
031import gwt.material.design.client.base.mixin.*;
032import gwt.material.design.client.base.validator.HasValidators;
033import gwt.material.design.client.constants.*;
034import gwt.material.design.client.events.*;
035import gwt.material.design.client.events.DragEndEvent;
036import gwt.material.design.client.events.DragEnterEvent;
037import gwt.material.design.client.events.DragLeaveEvent;
038import gwt.material.design.client.events.DragOverEvent;
039import gwt.material.design.client.events.DragStartEvent;
040import gwt.material.design.client.events.DropEvent;
041import gwt.material.design.client.events.OrientationChangeEvent.OrientationChangeHandler;
042import gwt.material.design.jquery.client.api.JQuery;
043import gwt.material.design.jquery.client.api.JQueryElement;
044
045import java.util.ArrayList;
046import java.util.HashMap;
047import java.util.List;
048import java.util.Map;
049
050import static gwt.material.design.jquery.client.api.JQuery.$;
051
052public class MaterialWidget extends ComplexPanel implements HasId, HasEnabled, HasTextAlign, HasDimension, HasColors, HasGrid,
053        HasShadow, Focusable, HasInlineStyle, HasSeparator, HasScrollspy, HasHideOn, HasShowOn, HasCenterOn, HasCircle, HasWaves,
054        HasDataAttributes, HasFloat, HasTooltip, HasFlexbox, HasHoverable, HasFontWeight, HasFontSize, HasDepth, HasInitialClasses,
055        HasInteractionHandlers, HasAllFocusHandlers, HasBorder, HasVerticalAlign, HasTransform, HasOrientation {
056
057    private static JQueryElement window = null;
058    private static JQueryElement body = null;
059
060    public static JQueryElement window() {
061        if (window == null) {
062            window = $(JQuery.window());
063        }
064        return window;
065    }
066
067    public static JQueryElement body() {
068        if (body == null) {
069            body = $("body");
070        }
071        return body;
072    }
073
074    /**
075     * Configurable features enum see {@link #enableFeature(Feature, boolean)}.
076     */
077    public enum Feature {
078        /**
079         * Feature for adding or inserting children
080         * before this widget has loaded (attached).
081         */
082        ONLOAD_ADD_QUEUE
083    }
084
085    class Appender {
086        Widget widget;
087        int index = -1;
088
089        public Appender(Widget widget, int index) {
090            this.widget = widget;
091            this.index = index;
092        }
093
094        public Appender(Widget widget) {
095            this.widget = widget;
096        }
097    }
098
099    private Map<Feature, Boolean> features;
100    private List<Appender> onLoadAdd;
101
102    private String[] initialClasses;
103    protected JQueryElement $this;
104
105    private HandlerRegistry handlerRegistry;
106
107    private IdMixin<MaterialWidget> idMixin;
108    private EnabledMixin<MaterialWidget> enabledMixin;
109    private CssNameMixin<MaterialWidget, TextAlign> textAlignMixin;
110    private ColorsMixin<MaterialWidget> colorsMixin;
111    private FocusableMixin<MaterialWidget> focusableMixin;
112    private GridMixin<MaterialWidget> gridMixin;
113    private ShadowMixin<MaterialWidget> shadowMixin;
114    private SeparatorMixin<MaterialWidget> separatorMixin;
115    private ScrollspyMixin<MaterialWidget> scrollspyMixin;
116    private CssNameMixin<MaterialWidget, HideOn> hideOnMixin;
117    private CssNameMixin<MaterialWidget, ShowOn> showOnMixin;
118    private CssNameMixin<MaterialWidget, CenterOn> centerOnMixin;
119    private FontSizeMixin<MaterialWidget> fontSizeMixin;
120    private ToggleStyleMixin<MaterialWidget> circleMixin;
121    private WavesMixin<MaterialWidget> wavesMixin;
122    private CssNameMixin<MaterialWidget, Float> floatMixin;
123    private TooltipMixin<MaterialWidget> tooltipMixin;
124    private FlexboxMixin<MaterialWidget> flexboxMixin;
125    private ToggleStyleMixin<MaterialWidget> hoverableMixin;
126    private CssNameMixin<MaterialWidget, FontWeight> fontWeightMixin;
127    private ToggleStyleMixin<MaterialWidget> truncateMixin;
128    private BorderMixin<MaterialWidget> borderMixin;
129    private DimensionMixin<MaterialWidget> dimensionMixin;
130    private VerticalAlignMixin<MaterialWidget> verticalAlignMixin;
131    private TransformMixin<MaterialWidget> transformMixin;
132    private OrientationMixin<MaterialWidget> orientationMixin;
133
134    public MaterialWidget() {
135    }
136
137    public MaterialWidget(JQueryElement jQueryElement) {
138        setElement(jQueryElement.asElement());
139
140        // We are already attached to the DOM.
141        // This will happen in instances where
142        // we are taking an element from JQuery.
143        onAttach();
144    }
145
146    public MaterialWidget(Element element) {
147        setElement(element);
148    }
149
150    public MaterialWidget(Element element, String... initialClass) {
151        this(element);
152        setInitialClasses(initialClass);
153    }
154
155    public JQueryElement $this() {
156        if ($this == null) {
157            $this = JQuery.$(this);
158        }
159        return $this;
160    }
161
162    @Override
163    protected void onLoad() {
164        super.onLoad();
165
166        if (initialClasses != null) {
167            for (String initial : initialClasses) {
168                if (!initial.isEmpty()) {
169                    removeStyleName(initial);
170                    addStyleName(initial);
171                }
172            }
173        }
174
175        if (isFeatureEnabled(Feature.ONLOAD_ADD_QUEUE) && onLoadAdd != null) {
176            // Check the onLoadAdd items.
177            for (Appender item : onLoadAdd) {
178                if (item.index == -1) {
179                    add(item.widget, (Element) getElement());
180                } else {
181                    insert(item.widget, item.index);
182                }
183            }
184            onLoadAdd.clear();
185        }
186    }
187
188    @Override
189    protected void onUnload() {
190        super.onUnload();
191
192        getHandlerRegistry().clearHandlers();
193    }
194
195    public HandlerRegistry getHandlerRegistry() {
196        if (handlerRegistry == null) {
197            handlerRegistry = new DefaultHandlerRegistry(this);
198        }
199        return handlerRegistry;
200    }
201
202    @Override
203    public void add(Widget child) {
204        super.add(child, (Element) getElement());
205    }
206
207    @Override
208    protected void add(Widget child, com.google.gwt.user.client.Element container) {
209        if (!isAttached() && isFeatureEnabled(Feature.ONLOAD_ADD_QUEUE)) {
210            if (onLoadAdd == null) {
211                onLoadAdd = new ArrayList<>();
212            }
213            onLoadAdd.add(new Appender(child));
214        } else {
215            super.add(child, container);
216        }
217    }
218
219    @Override
220    protected void insert(Widget child, com.google.gwt.user.client.Element container, int beforeIndex, boolean domInsert) {
221        if (!isAttached() && isFeatureEnabled(Feature.ONLOAD_ADD_QUEUE)) {
222            if (onLoadAdd == null) {
223                onLoadAdd = new ArrayList<>();
224            }
225            onLoadAdd.add(new Appender(child, beforeIndex));
226        } else {
227            // Regular child addition
228            super.insert(child, container, beforeIndex, domInsert);
229        }
230    }
231
232    /**
233     * Inserts a widget at a specific index
234     *
235     * @param child       - widget to be inserted
236     * @param beforeIndex - index for the widget
237     */
238    public void insert(final Widget child, final int beforeIndex) {
239        insert(child, (Element) getElement(), beforeIndex, true);
240    }
241
242    /**
243     * Set the style attribute of your element.
244     * Note that this will override any {@link Element#getStyle()} changes and vice-versa.
245     */
246    public void setStyle(String style) {
247        getElement().setAttribute("style", style);
248    }
249
250    /**
251     * Set the 'class' attribute of this element.
252     * Note that this will override {@link #addStyleName(String)} and vice-versa.
253     */
254    public void setClass(String cssClasses) {
255        getElement().setAttribute("class", cssClasses);
256    }
257
258    @Override
259    public void setId(String id) {
260        getIdMixin().setId(id);
261    }
262
263    @Override
264    public String getId() {
265        return getIdMixin().getId();
266    }
267
268    @Override
269    public boolean isEnabled() {
270        return getEnabledMixin().isEnabled();
271    }
272
273    @Override
274    public void setEnabled(boolean enabled) {
275        getEnabledMixin().setEnabled(this, enabled);
276    }
277
278    @Override
279    public TextAlign getTextAlign() {
280        return getTextAlignMixin().getCssName();
281    }
282
283    @Override
284    public void setTextAlign(TextAlign align) {
285        getTextAlignMixin().setCssName(align);
286    }
287
288    @Override
289    public void setBackgroundColor(Color bgColor) {
290        getColorsMixin().setBackgroundColor(bgColor);
291    }
292
293    @Override
294    public Color getBackgroundColor() {
295        return getColorsMixin().getBackgroundColor();
296    }
297
298    @Override
299    public void setTextColor(Color textColor) {
300        getColorsMixin().setTextColor(textColor);
301    }
302
303    @Override
304    public Color getTextColor() {
305        return getColorsMixin().getTextColor();
306    }
307
308    @Override
309    public int getTabIndex() {
310        return getFocusableMixin().getTabIndex();
311    }
312
313    @Override
314    public void setAccessKey(char key) {
315        getFocusableMixin().setAccessKey(key);
316    }
317
318    @Override
319    public void setFocus(boolean focused) {
320        getFocusableMixin().setFocus(focused);
321    }
322
323    @Override
324    public void setTabIndex(int index) {
325        getFocusableMixin().setTabIndex(index);
326    }
327
328    @Override
329    public void setGrid(String grid) {
330        getGridMixin().setGrid(grid);
331    }
332
333    @Override
334    public void setOffset(String offset) {
335        getGridMixin().setOffset(offset);
336    }
337
338    @Override
339    public void setShadow(int shadow) {
340        getShadowMixin().setShadow(shadow);
341    }
342
343    @Override
344    public int getShadow() {
345        return getShadowMixin().getShadow();
346    }
347
348    @Override
349    public void setMargin(double margin) {
350        getElement().getStyle().setMargin(margin, Style.Unit.PX);
351    }
352
353    @Override
354    public void setMarginTop(final double margin) {
355        getElement().getStyle().setMarginTop(margin, Style.Unit.PX);
356    }
357
358    @Override
359    public void setMarginLeft(final double margin) {
360        getElement().getStyle().setMarginLeft(margin, Style.Unit.PX);
361    }
362
363    @Override
364    public void setMarginRight(final double margin) {
365        getElement().getStyle().setMarginRight(margin, Style.Unit.PX);
366    }
367
368    @Override
369    public void setMarginBottom(final double margin) {
370        getElement().getStyle().setMarginBottom(margin, Style.Unit.PX);
371    }
372
373    @Override
374    public void setPadding(double padding) {
375        getElement().getStyle().setPadding(padding, Style.Unit.PX);
376    }
377
378    @Override
379    public void setPaddingTop(final double padding) {
380        getElement().getStyle().setPaddingTop(padding, Style.Unit.PX);
381    }
382
383    @Override
384    public void setPaddingLeft(final double padding) {
385        getElement().getStyle().setPaddingLeft(padding, Style.Unit.PX);
386    }
387
388    @Override
389    public void setPaddingRight(final double padding) {
390        getElement().getStyle().setPaddingRight(padding, Style.Unit.PX);
391    }
392
393    @Override
394    public void setPaddingBottom(final double padding) {
395        getElement().getStyle().setPaddingBottom(padding, Style.Unit.PX);
396    }
397
398    @Override
399    public void setGwtDisplay(Style.Display display) {
400        getFlexboxMixin().setGwtDisplay(display);
401    }
402
403    @Override
404    public void setOpacity(double opacity) {
405        getElement().getStyle().setOpacity(opacity);
406    }
407
408    @Override
409    public double getOpacity() {
410        return Double.parseDouble(getElement().getStyle().getOpacity());
411    }
412
413    @Override
414    public void setSeparator(boolean separator) {
415        getSeparatorMixin().setSeparator(separator);
416    }
417
418    @Override
419    public boolean isSeparator() {
420        return getSeparatorMixin().isSeparator();
421    }
422
423    @Override
424    public void setScrollspy(String scrollspy) {
425        getScrollspyMixin().setScrollspy(scrollspy);
426    }
427
428    @Override
429    public String getScrollspy() {
430        return getScrollspyMixin().getScrollspy();
431    }
432
433    @Override
434    public void setCenterOn(CenterOn centerOn) {
435        getCenterOnMixin().setCssName(centerOn);
436    }
437
438    @Override
439    public CenterOn getCenterOn() {
440        return getCenterOnMixin().getCssName();
441    }
442
443    @Override
444    public void setHideOn(HideOn hideOn) {
445        getHideOnMixin().setCssName(hideOn);
446    }
447
448    @Override
449    public HideOn getHideOn() {
450        return getHideOnMixin().getCssName();
451    }
452
453    @Override
454    public void setShowOn(ShowOn showOn) {
455        getShowOnMixin().setCssName(showOn);
456    }
457
458    @Override
459    public ShowOn getShowOn() {
460        return getShowOnMixin().getCssName();
461    }
462
463    @Override
464    public void setFontSize(String fontSize) {
465        getFontSizeMixin().setFontSize(fontSize);
466    }
467
468    @Override
469    public String getFontSize() {
470        return getFontSizeMixin().getFontSize();
471    }
472
473    @Override
474    public void setFontSize(double fontSize, Style.Unit unit) {
475        getFontSizeMixin().setFontSize(fontSize, unit);
476    }
477
478    @Override
479    public void setCircle(boolean circle) {
480        getCircleMixin().setOn(circle);
481    }
482
483    @Override
484    public boolean isCircle() {
485        return getCircleMixin().isOn();
486    }
487
488    @Override
489    public void setWaves(WavesType waves) {
490        getWavesMixin().setWaves(waves);
491    }
492
493    @Override
494    public WavesType getWaves() {
495        return getWavesMixin().getWaves();
496    }
497
498    @Override
499    public void setDataAttribute(String dataAttr, String value) {
500        getElement().setAttribute(!dataAttr.startsWith("data-") ? "data-" + dataAttr : dataAttr, value);
501    }
502
503    @Override
504    public String getDataAttribute(String dataAttr) {
505        return getElement().getAttribute(!dataAttr.startsWith("data-") ? "data-" + dataAttr : dataAttr);
506    }
507
508    @Override
509    public void setFloat(Float floatAlign) {
510        getFloatMixin().setCssName(floatAlign);
511    }
512
513    @Override
514    public Float getFloat() {
515        return StyleHelper.fromStyleName(Float.class, getFloatMixin().getCssName());
516    }
517
518    @Override
519    public String getTooltip() {
520        return getTooltipMixin().getTooltip();
521    }
522
523    @Override
524    public void setTooltip(String tooltip) {
525        getTooltipMixin().setTooltip(tooltip);
526    }
527
528    @Override
529    public Position getTooltipPosition() {
530        return getTooltipMixin().getTooltipPosition();
531    }
532
533    @Override
534    public void setTooltipPosition(Position position) {
535        getTooltipMixin().setTooltipPosition(position);
536    }
537
538    @Override
539    public int getTooltipDelayMs() {
540        return getTooltipMixin().getTooltipDelayMs();
541    }
542
543    @Override
544    public void setTooltipDelayMs(int delayMs) {
545        getTooltipMixin().setTooltipDelayMs(delayMs);
546    }
547
548    @Override
549    public void setTooltipHTML(String html) {
550        getTooltipMixin().setTooltipHTML(html);
551    }
552
553    @Override
554    public String getTooltipHTML() {
555        return getTooltipMixin().getTooltipHTML();
556    }
557
558    public void setVisibility(Style.Visibility visibility) {
559        getElement().getStyle().setVisibility(visibility);
560    }
561
562    @Override
563    public void setDisplay(Display display) {
564        getFlexboxMixin().setDisplay(display);
565    }
566
567    @Override
568    public void setFlexDirection(FlexDirection flexDirection) {
569        getFlexboxMixin().setFlexDirection(flexDirection);
570    }
571
572    @Override
573    public void setFlex(Flex flex) {
574        getFlexboxMixin().setFlex(flex);
575    }
576
577    @Override
578    public void setFlexGrow(Integer flexGrow) {
579        getFlexboxMixin().setFlexGrow(flexGrow);
580    }
581
582    @Override
583    public void setFlexShrink(Integer flexShrink) {
584        getFlexboxMixin().setFlexShrink(flexShrink);
585    }
586
587    @Override
588    public void setFlexBasis(String flexBasis) {
589        getFlexboxMixin().setFlexBasis(flexBasis);
590    }
591
592    @Override
593    public void setFlexOrder(Integer flexOrder) {
594        getFlexboxMixin().setFlexOrder(flexOrder);
595    }
596
597    @Override
598    public void setFlexWrap(FlexWrap flexWrap) {
599        getFlexboxMixin().setFlexWrap(flexWrap);
600    }
601
602    @Override
603    public void setFlexAlignContent(FlexAlignContent flexAlignContent) {
604        getFlexboxMixin().setFlexAlignContent(flexAlignContent);
605    }
606
607    @Override
608    public void setFlexAlignSelf(FlexAlignSelf flexAlignSelf) {
609        getFlexboxMixin().setFlexAlignSelf(flexAlignSelf);
610    }
611
612    @Override
613    public void setFlexAlignItems(FlexAlignItems flexAlignItems) {
614        getFlexboxMixin().setFlexAlignItems(flexAlignItems);
615    }
616
617    @Override
618    public void setFlexJustifyContent(FlexJustifyContent flexJustifyContent) {
619        getFlexboxMixin().setFlexJustifyContent(flexJustifyContent);
620    }
621
622    @Override
623    public void setVerticalAlign(Style.VerticalAlign value) {
624        getVerticalAlignMixin().setVerticalAlign(value);
625    }
626
627    @Override
628    public String getVerticalAlign() {
629        return getVerticalAlignMixin().getVerticalAlign();
630    }
631
632    public void setOverflow(Style.Overflow overflow) {
633        getElement().getStyle().setOverflow(overflow);
634    }
635
636    public void setLayoutPosition(Style.Position position) {
637        getElement().getStyle().setPosition(position);
638    }
639
640    public String getLayoutPosition() {
641        return getElement().getStyle().getPosition();
642    }
643
644    public void setLeft(double value) {
645        getElement().getStyle().setLeft(value, Style.Unit.PX);
646    }
647
648    public void setRight(double value) {
649        getElement().getStyle().setRight(value, Style.Unit.PX);
650    }
651
652    public void setTop(double value) {
653        getElement().getStyle().setTop(value, Style.Unit.PX);
654    }
655
656    public void setBottom(double value) {
657        getElement().getStyle().setBottom(value, Style.Unit.PX);
658    }
659
660    public void setLineHeight(double value) {
661        getElement().getStyle().setLineHeight(value, Style.Unit.PX);
662    }
663
664    @Override
665    public void setHoverable(boolean hoverable) {
666        getHoverableMixin().setOn(hoverable);
667    }
668
669    @Override
670    public boolean isHoverable() {
671        return getHoverableMixin().isOn();
672    }
673
674    @Override
675    public void setFontWeight(FontWeight fontWeight) {
676        getElement().getStyle().setFontWeight(fontWeight);
677    }
678
679    @Override
680    public String getFontWeight() {
681        return getElement().getStyle().getFontWeight();
682    }
683
684    @Override
685    public void setDepth(int depth) {
686        getElement().getStyle().setZIndex(depth);
687    }
688
689    @Override
690    public int getDepth() {
691        return Integer.parseInt(getElement().getStyle().getZIndex());
692    }
693
694    /**
695     * If true the label inside this component will be truncated by ellipsis
696     **/
697    public void setTruncate(boolean truncate) {
698        getTruncateMixin().setOn(truncate);
699    }
700
701    public boolean isTruncate() {
702        return getTruncateMixin().isOn();
703    }
704
705    @Override
706    public void setBorder(String value) {
707        getBorderMixin().setBorder(value);
708    }
709
710    @Override
711    public String getBorder() {
712        return getBorderMixin().getBorder();
713    }
714
715    @Override
716    public void setBorderLeft(String value) {
717        getBorderMixin().setBorderLeft(value);
718    }
719
720    @Override
721    public String getBorderLeft() {
722        return getBorderMixin().getBorderLeft();
723    }
724
725    @Override
726    public void setBorderRight(String value) {
727        getBorderMixin().setBorderRight(value);
728    }
729
730    @Override
731    public String getBorderRight() {
732        return getBorderMixin().getBorderRight();
733    }
734
735    @Override
736    public void setBorderTop(String value) {
737        getBorderMixin().setBorderTop(value);
738    }
739
740    @Override
741    public String getBorderTop() {
742        return getBorderMixin().getBorderTop();
743    }
744
745    @Override
746    public void setBorderBottom(String value) {
747        getBorderMixin().setBorderBottom(value);
748    }
749
750    @Override
751    public String getBorderBottom() {
752        return getBorderMixin().getBorderBottom();
753    }
754
755    @Override
756    public void setBorderRadius(String value) {
757        getBorderMixin().setBorderRadius(value);
758    }
759
760    @Override
761    public String getBorderRadius() {
762        return getBorderMixin().getBorderRadius();
763    }
764
765    @Override
766    public void setMinHeight(String value) {
767        getDimensionMixin().setMinHeight(value);
768    }
769
770    @Override
771    public String getMinHeight() {
772        return getDimensionMixin().getMinHeight();
773    }
774
775    @Override
776    public void setMaxHeight(String value) {
777        getDimensionMixin().setMaxHeight(value);
778    }
779
780    @Override
781    public String getMaxHeight() {
782        return getDimensionMixin().getMaxHeight();
783    }
784
785    @Override
786    public void setMinWidth(String value) {
787        getDimensionMixin().setMinWidth(value);
788    }
789
790    @Override
791    public String getMinWidth() {
792        return getDimensionMixin().getMinWidth();
793    }
794
795    @Override
796    public void setMaxWidth(String value) {
797        getDimensionMixin().setMaxWidth(value);
798    }
799
800    @Override
801    public String getMaxWidth() {
802        return getDimensionMixin().getMaxWidth();
803    }
804
805    @Override
806    public void setTransform(String value) {
807        getTransformMixin().setTransform(value);
808    }
809
810    @Override
811    public String getTransform() {
812        return getTransformMixin().getTransform();
813    }
814
815    @Override
816    public void setTransformOrigin(String value) {
817        getTransformMixin().setTransformOrigin(value);
818    }
819
820    @Override
821    public String getTransformOrigin() {
822        return getTransformMixin().getTransformOrigin();
823    }
824
825    @Override
826    public void setTransformStyle(String value) {
827        getTransformMixin().setTransformStyle(value);
828    }
829
830    @Override
831    public String getTransformStyle() {
832        return getTransformMixin().getTransformStyle();
833    }
834
835    @Override
836    public void setPerspective(String value) {
837        getTransformMixin().setPerspective(value);
838    }
839
840    @Override
841    public String getPerspective() {
842        return getTransformMixin().getPerspective();
843    }
844
845    @Override
846    public void setPerspectiveOrigin(String value) {
847        getTransformMixin().setPerspectiveOrigin(value);
848    }
849
850    @Override
851    public String getPerspectiveOrigin() {
852        return getTransformMixin().getPerspectiveOrigin();
853    }
854
855    @Override
856    public void setBackfaceVisibility(String value) {
857        getTransformMixin().setBackfaceVisibility(value);
858    }
859
860    @Override
861    public String getBackfaceVisibility() {
862        return getTransformMixin().getBackfaceVisibility();
863    }
864
865    @Override
866    public void setOrientation(Orientation orientation) {
867        getOrientationMixin().setOrientation(orientation);
868    }
869
870    @Override
871    public Orientation getOrientation() {
872        return getOrientationMixin().getOrientation();
873    }
874
875    @Override
876    public void setDetectOrientation(boolean detectOrientation) {
877        getOrientationMixin().setDetectOrientation(detectOrientation);
878    }
879
880    @Override
881    public boolean isDetectOrientation() {
882        return getOrientationMixin().isDetectOrientation();
883    }
884
885    public HandlerRegistration registerHandler(HandlerRegistration handler) {
886        return getHandlerRegistry().registerHandler(handler);
887    }
888
889    public void removeHandler(HandlerRegistration handler) {
890        getHandlerRegistry().removeHandler(handler);
891    }
892
893    // Avoid touch events on mobile devices
894    public void stopTouchStartEvent() {
895        $(getElement()).bind("touchstart", e -> {
896            e.stopPropagation();
897            return true;
898        });
899    }
900
901    public int getWidth() {
902        return $(getElement()).outerWidth();
903    }
904
905    protected void clearActiveClass(HasWidgets widget) {
906        for (Widget child : widget) {
907            Element element = child.getElement();
908            if (StyleHelper.containsStyle(element.getClassName(), CssName.ACTIVE)) {
909                element.removeClassName(CssName.ACTIVE);
910            }
911
912            if (child instanceof HasWidgets) {
913                clearActiveClass((HasWidgets) child);
914            }
915        }
916    }
917
918    /**
919     * Applies a CSS3 Transition property to this widget.
920     */
921    public void setTransition(TransitionConfig property) {
922        Element target = getElement();
923        if (property.getTarget() != null) {
924            target = property.getTarget();
925        }
926        target.getStyle().setProperty("WebkitTransition", property.getProperty() + " " + property.getDuration() + "ms " + property.getTimingFunction() + property.getDelay() + "ms");
927        target.getStyle().setProperty("transition", property.getProperty() + " " + property.getDuration() + "ms " + property.getTimingFunction() + property.getDelay() + "ms");
928    }
929
930
931    /**
932     * Add an {@code AttachHandler} for attachment events.
933     *
934     * @param handler Attach event handler.
935     * @param oneTime Only execute this handler once, then detach handler.
936     * @return The events handler registration.
937     */
938    public HandlerRegistration addAttachHandler(final AttachEvent.Handler handler, boolean oneTime) {
939        if (!oneTime) {
940            return addAttachHandler(handler);
941        } else {
942            final HandlerRegistration[] registration = {null};
943            registration[0] = addAttachHandler(event -> {
944                handler.onAttachOrDetach(event);
945
946                if (registration[0] != null) {
947                    registration[0].removeHandler();
948                }
949            });
950            return registration[0];
951        }
952    }
953
954    @Override
955    public void setInitialClasses(String... initialClasses) {
956        this.initialClasses = initialClasses;
957    }
958
959    @Override
960    public String[] getInitialClasses() {
961        return initialClasses;
962    }
963
964    @Override
965    public WidgetCollection getChildren() {
966        return super.getChildren();
967    }
968
969    public List<Widget> getChildrenList() {
970        List<Widget> children = new ArrayList<>();
971        for (int i = 0; i < getWidgetCount(); i++) {
972            children.add(getWidget(i));
973        }
974        return children;
975    }
976
977    /**
978     * Enable or disable a complex {@link Feature}.<br/>
979     *
980     * @param feature the feature to enable.
981     * @param enabled true to enable false to disable.
982     */
983    public void enableFeature(Feature feature, boolean enabled) {
984        if (features == null) {
985            features = new HashMap<>();
986        }
987        features.put(feature, enabled);
988    }
989
990    /**
991     * Check if a {@link Feature} is enabled.
992     */
993    public boolean isFeatureEnabled(Feature feature) {
994        if (features != null) {
995            Boolean enabled = features.get(feature);
996            return enabled != null && enabled;
997        } else {
998            return false;
999        }
1000    }
1001
1002    public boolean validate() {
1003        boolean valid = true;
1004        for (Widget child : getChildren()) {
1005            if (child instanceof HasValidators && !((HasValidators) child).validate()) {
1006                valid = false;
1007            } else if (child instanceof MaterialWidget && !((MaterialWidget) child).validate()) {
1008                valid = false;
1009            }
1010        }
1011        return valid;
1012    }
1013
1014    // Events
1015    @Override
1016    public HandlerRegistration addClickHandler(final ClickHandler handler) {
1017        return addDomHandler(event -> {
1018            if (isEnabled()) {
1019                handler.onClick(event);
1020            }
1021        }, ClickEvent.getType());
1022    }
1023
1024    @Override
1025    public HandlerRegistration addMouseDownHandler(final MouseDownHandler handler) {
1026        return addDomHandler(event -> {
1027            if (isEnabled()) {
1028                handler.onMouseDown(event);
1029            }
1030        }, MouseDownEvent.getType());
1031    }
1032
1033    @Override
1034    public HandlerRegistration addMouseMoveHandler(final MouseMoveHandler handler) {
1035        return addDomHandler(event -> {
1036            if (isEnabled()) {
1037                handler.onMouseMove(event);
1038            }
1039        }, MouseMoveEvent.getType());
1040    }
1041
1042    @Override
1043    public HandlerRegistration addMouseOutHandler(final MouseOutHandler handler) {
1044        return addDomHandler(event -> {
1045            if (isEnabled()) {
1046                handler.onMouseOut(event);
1047            }
1048        }, MouseOutEvent.getType());
1049    }
1050
1051    @Override
1052    public HandlerRegistration addMouseOverHandler(final MouseOverHandler handler) {
1053        return addDomHandler(event -> {
1054            if (isEnabled()) {
1055                handler.onMouseOver(event);
1056            }
1057        }, MouseOverEvent.getType());
1058    }
1059
1060    @Override
1061    public HandlerRegistration addMouseUpHandler(final MouseUpHandler handler) {
1062        return addDomHandler(event -> {
1063            if (isEnabled()) {
1064                handler.onMouseUp(event);
1065            }
1066        }, MouseUpEvent.getType());
1067    }
1068
1069    @Override
1070    public HandlerRegistration addMouseWheelHandler(final MouseWheelHandler handler) {
1071        return addDomHandler(event -> {
1072            if (isEnabled()) {
1073                handler.onMouseWheel(event);
1074            }
1075        }, MouseWheelEvent.getType());
1076    }
1077
1078    @Override
1079    public HandlerRegistration addDoubleClickHandler(final DoubleClickHandler handler) {
1080        return addDomHandler(event -> {
1081            if (isEnabled()) {
1082                handler.onDoubleClick(event);
1083            }
1084        }, DoubleClickEvent.getType());
1085    }
1086
1087    @Override
1088    public HandlerRegistration addDragStartHandler(DragStartEvent.DragStartHandler handler) {
1089        return addHandler(event -> {
1090            if (isEnabled()) {
1091                handler.onDragStart(event);
1092            }
1093        }, DragStartEvent.getType());
1094    }
1095
1096    @Override
1097    public HandlerRegistration addDragMoveHandler(DragMoveEvent.DragMoveHandler handler) {
1098        return addHandler(event -> {
1099            if (isEnabled()) {
1100                handler.onDragMove(event);
1101            }
1102        }, DragMoveEvent.getType());
1103    }
1104
1105    @Override
1106    public HandlerRegistration addDragEndHandler(DragEndEvent.DragEndHandler handler) {
1107        return addHandler(event -> {
1108            if (isEnabled()) {
1109                handler.onDragEnd(event);
1110            }
1111        }, DragEndEvent.getType());
1112    }
1113
1114    @Override
1115    public HandlerRegistration addDropActivateHandler(DropActivateEvent.DropActivateHandler handler) {
1116        return addHandler(event -> {
1117            if (isEnabled()) {
1118                handler.onDropActivate(event);
1119            }
1120        }, DropActivateEvent.getType());
1121    }
1122
1123    @Override
1124    public HandlerRegistration addDragEnterHandler(DragEnterEvent.DragEnterHandler handler) {
1125        return addHandler(event -> {
1126            if (isEnabled()) {
1127                handler.onDragEnter(event);
1128            }
1129        }, DragEnterEvent.getType());
1130    }
1131
1132    @Override
1133    public HandlerRegistration addDragLeaveHandler(DragLeaveEvent.DragLeaveHandler handler) {
1134        return addHandler(event -> {
1135            if (isEnabled()) {
1136                handler.onDragLeave(event);
1137            }
1138        }, DragLeaveEvent.getType());
1139    }
1140
1141    @Override
1142    public HandlerRegistration addDragOverHandler(final DragOverEvent.DragOverHandler handler) {
1143        return addHandler(event -> {
1144            if (isEnabled()) {
1145                handler.onDragOver(event);
1146            }
1147        }, DragOverEvent.getType());
1148    }
1149
1150    @Override
1151    public HandlerRegistration addDropDeactivateHandler(DropDeactivateEvent.DropDeactivateHandler handler) {
1152        return addHandler(event -> {
1153            if (isEnabled()) {
1154                handler.onDropDeactivate(event);
1155            }
1156        }, DropDeactivateEvent.getType());
1157    }
1158
1159    @Override
1160    public HandlerRegistration addDropHandler(DropEvent.DropHandler handler) {
1161        return addHandler(event -> {
1162            if (isEnabled()) {
1163                handler.onDrop(event);
1164            }
1165        }, DropEvent.getType());
1166    }
1167
1168    @Override
1169    public HandlerRegistration addTouchCancelHandler(TouchCancelHandler handler) {
1170        return addDomHandler(event -> {
1171            if (isEnabled()) {
1172                handler.onTouchCancel(event);
1173            }
1174        }, TouchCancelEvent.getType());
1175    }
1176
1177    @Override
1178    public HandlerRegistration addTouchEndHandler(TouchEndHandler handler) {
1179        return addDomHandler(event -> {
1180            if (isEnabled()) {
1181                handler.onTouchEnd(event);
1182            }
1183        }, TouchEndEvent.getType());
1184    }
1185
1186    @Override
1187    public HandlerRegistration addTouchMoveHandler(TouchMoveHandler handler) {
1188        return addDomHandler(event -> {
1189            if (isEnabled()) {
1190                handler.onTouchMove(event);
1191            }
1192        }, TouchMoveEvent.getType());
1193    }
1194
1195    @Override
1196    public HandlerRegistration addTouchStartHandler(TouchStartHandler handler) {
1197        return addDomHandler(event -> {
1198            if (isEnabled()) {
1199                handler.onTouchStart(event);
1200            }
1201        }, TouchStartEvent.getType());
1202    }
1203
1204    @Override
1205    public HandlerRegistration addGestureChangeHandler(GestureChangeHandler handler) {
1206        return addDomHandler(event -> {
1207            if (isEnabled()) {
1208                handler.onGestureChange(event);
1209            }
1210        }, GestureChangeEvent.getType());
1211    }
1212
1213    @Override
1214    public HandlerRegistration addGestureEndHandler(GestureEndHandler handler) {
1215        return addDomHandler(event -> {
1216            if (isEnabled()) {
1217                handler.onGestureEnd(event);
1218            }
1219        }, GestureEndEvent.getType());
1220    }
1221
1222    @Override
1223    public HandlerRegistration addGestureStartHandler(GestureStartHandler handler) {
1224        return addDomHandler(event -> {
1225            if (isEnabled()) {
1226                handler.onGestureStart(event);
1227            }
1228        }, GestureStartEvent.getType());
1229    }
1230
1231    @Override
1232    public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
1233        return addDomHandler(event -> {
1234            if (isEnabled()) {
1235                handler.onKeyDown(event);
1236            }
1237        }, KeyDownEvent.getType());
1238    }
1239
1240    @Override
1241    public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
1242        return addDomHandler(event -> {
1243            if (isEnabled()) {
1244                handler.onKeyPress(event);
1245            }
1246        }, KeyPressEvent.getType());
1247    }
1248
1249    @Override
1250    public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
1251        return addDomHandler(event -> {
1252            if (isEnabled()) {
1253                handler.onKeyUp(event);
1254            }
1255        }, KeyUpEvent.getType());
1256    }
1257
1258    @Override
1259    public HandlerRegistration addBlurHandler(BlurHandler handler) {
1260        return addDomHandler(event -> {
1261            if (isEnabled()) {
1262                handler.onBlur(event);
1263            }
1264        }, BlurEvent.getType());
1265    }
1266
1267    @Override
1268    public HandlerRegistration addFocusHandler(FocusHandler handler) {
1269        return addDomHandler(event -> {
1270            if (isEnabled()) {
1271                handler.onFocus(event);
1272            }
1273        }, FocusEvent.getType());
1274    }
1275
1276    @Override
1277    public HandlerRegistration addOrientationChangeHandler(OrientationChangeHandler handler) {
1278        return addHandler(event -> {
1279            if (isEnabled()) {
1280                handler.onOrientationChange(event);
1281            }
1282        }, OrientationChangeEvent.TYPE);
1283    }
1284
1285    protected IdMixin<MaterialWidget> getIdMixin() {
1286        if (idMixin == null) {
1287            idMixin = new IdMixin<>(this);
1288        }
1289        return idMixin;
1290    }
1291
1292    protected EnabledMixin<MaterialWidget> getEnabledMixin() {
1293        if (enabledMixin == null) {
1294            enabledMixin = new EnabledMixin<>(this);
1295        }
1296        return enabledMixin;
1297    }
1298
1299    protected CssNameMixin<MaterialWidget, TextAlign> getTextAlignMixin() {
1300        if (textAlignMixin == null) {
1301            textAlignMixin = new CssNameMixin<>(this);
1302        }
1303        return textAlignMixin;
1304    }
1305
1306    protected ColorsMixin<MaterialWidget> getColorsMixin() {
1307        if (colorsMixin == null) {
1308            colorsMixin = new ColorsMixin<>(this);
1309        }
1310        return colorsMixin;
1311    }
1312
1313    protected FocusableMixin<MaterialWidget> getFocusableMixin() {
1314        if (focusableMixin == null) {
1315            focusableMixin = new FocusableMixin<>(this);
1316        }
1317        return focusableMixin;
1318    }
1319
1320    protected GridMixin<MaterialWidget> getGridMixin() {
1321        if (gridMixin == null) {
1322            gridMixin = new GridMixin<>(this);
1323        }
1324        return gridMixin;
1325    }
1326
1327    protected ShadowMixin<MaterialWidget> getShadowMixin() {
1328        if (shadowMixin == null) {
1329            shadowMixin = new ShadowMixin<>(this);
1330        }
1331        return shadowMixin;
1332    }
1333
1334    protected SeparatorMixin<MaterialWidget> getSeparatorMixin() {
1335        if (separatorMixin == null) {
1336            separatorMixin = new SeparatorMixin<>(this);
1337        }
1338        return separatorMixin;
1339    }
1340
1341    protected ScrollspyMixin<MaterialWidget> getScrollspyMixin() {
1342        if (scrollspyMixin == null) {
1343            scrollspyMixin = new ScrollspyMixin<>(this);
1344        }
1345        return scrollspyMixin;
1346    }
1347
1348    protected CssNameMixin<MaterialWidget, HideOn> getHideOnMixin() {
1349        if (hideOnMixin == null) {
1350            hideOnMixin = new CssNameMixin<>(this);
1351        }
1352        return hideOnMixin;
1353    }
1354
1355    protected CssNameMixin<MaterialWidget, ShowOn> getShowOnMixin() {
1356        if (showOnMixin == null) {
1357            showOnMixin = new CssNameMixin<>(this);
1358        }
1359        return showOnMixin;
1360    }
1361
1362    protected CssNameMixin<MaterialWidget, CenterOn> getCenterOnMixin() {
1363        if (centerOnMixin == null) {
1364            centerOnMixin = new CssNameMixin<>(this);
1365        }
1366        return centerOnMixin;
1367    }
1368
1369    protected FontSizeMixin<MaterialWidget> getFontSizeMixin() {
1370        if (fontSizeMixin == null) {
1371            fontSizeMixin = new FontSizeMixin<>(this);
1372        }
1373        return fontSizeMixin;
1374    }
1375
1376    protected ToggleStyleMixin<MaterialWidget> getCircleMixin() {
1377        if (circleMixin == null) {
1378            circleMixin = new ToggleStyleMixin<>(this, CssName.CIRCLE);
1379        }
1380        return circleMixin;
1381    }
1382
1383    protected ToggleStyleMixin<MaterialWidget> getHoverableMixin() {
1384        if (hoverableMixin == null) {
1385            hoverableMixin = new ToggleStyleMixin<>(this, CssName.HOVERABLE);
1386        }
1387        return hoverableMixin;
1388    }
1389
1390    protected WavesMixin<MaterialWidget> getWavesMixin() {
1391        if (wavesMixin == null) {
1392            wavesMixin = new WavesMixin<>(this);
1393        }
1394        return wavesMixin;
1395    }
1396
1397    protected CssNameMixin<MaterialWidget, Float> getFloatMixin() {
1398        if (floatMixin == null) {
1399            floatMixin = new CssNameMixin<>(this);
1400        }
1401        return floatMixin;
1402    }
1403
1404    protected TooltipMixin<MaterialWidget> getTooltipMixin() {
1405        if (tooltipMixin == null) {
1406            tooltipMixin = new TooltipMixin<>(this);
1407        }
1408        return tooltipMixin;
1409    }
1410
1411    protected FlexboxMixin<MaterialWidget> getFlexboxMixin() {
1412        if (flexboxMixin == null) {
1413            flexboxMixin = new FlexboxMixin<>(this);
1414        }
1415        return flexboxMixin;
1416    }
1417
1418    protected CssNameMixin<MaterialWidget, FontWeight> getFontWeightMixin() {
1419        if (fontWeightMixin == null) {
1420            fontWeightMixin = new CssNameMixin<>(this);
1421        }
1422        return fontWeightMixin;
1423    }
1424
1425    public ToggleStyleMixin<MaterialWidget> getTruncateMixin() {
1426        if (truncateMixin == null) {
1427            truncateMixin = new ToggleStyleMixin<>(this, CssName.TRUNCATE);
1428        }
1429        return truncateMixin;
1430    }
1431
1432    public BorderMixin<MaterialWidget> getBorderMixin() {
1433        if (borderMixin == null) {
1434            borderMixin = new BorderMixin<>(this);
1435        }
1436        return borderMixin;
1437    }
1438
1439    public DimensionMixin<MaterialWidget> getDimensionMixin() {
1440        if (dimensionMixin == null) {
1441            dimensionMixin = new DimensionMixin<>(this);
1442        }
1443        return dimensionMixin;
1444    }
1445
1446    public VerticalAlignMixin<MaterialWidget> getVerticalAlignMixin() {
1447        if (verticalAlignMixin == null) {
1448            verticalAlignMixin = new VerticalAlignMixin<>(this);
1449        }
1450        return verticalAlignMixin;
1451    }
1452
1453    public TransformMixin<MaterialWidget> getTransformMixin() {
1454        if (transformMixin == null) {
1455            transformMixin = new TransformMixin<>(this);
1456        }
1457        return transformMixin;
1458    }
1459
1460    public OrientationMixin<MaterialWidget> getOrientationMixin() {
1461        if (orientationMixin == null) {
1462            orientationMixin = new OrientationMixin<>(this);
1463        }
1464        return orientationMixin;
1465    }
1466}