001package gwt.material.design.client.base; 002 003/* 004 * #%L 005 * GwtMaterial 006 * %% 007 * Copyright (C) 2015 GwtMaterialDesign 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 com.google.gwt.dom.client.Element; 024import com.google.gwt.dom.client.Style; 025import com.google.gwt.dom.client.Style.Float; 026import com.google.gwt.dom.client.Style.FontWeight; 027import com.google.gwt.user.client.ui.*; 028import gwt.material.design.client.base.helper.StyleHelper; 029import gwt.material.design.client.base.mixin.ColorsMixin; 030import gwt.material.design.client.base.mixin.CssNameMixin; 031import gwt.material.design.client.base.mixin.EnabledMixin; 032import gwt.material.design.client.base.mixin.FlexboxMixin; 033import gwt.material.design.client.base.mixin.FocusableMixin; 034import gwt.material.design.client.base.mixin.FontSizeMixin; 035import gwt.material.design.client.base.mixin.GridMixin; 036import gwt.material.design.client.base.mixin.IdMixin; 037import gwt.material.design.client.base.mixin.ScrollspyMixin; 038import gwt.material.design.client.base.mixin.SeparatorMixin; 039import gwt.material.design.client.base.mixin.ShadowMixin; 040import gwt.material.design.client.base.mixin.ToggleStyleMixin; 041import gwt.material.design.client.base.mixin.TooltipMixin; 042import gwt.material.design.client.base.mixin.WavesMixin; 043import gwt.material.design.client.constants.CenterOn; 044import gwt.material.design.client.constants.Display; 045import gwt.material.design.client.constants.Flex; 046import gwt.material.design.client.constants.FlexAlignContent; 047import gwt.material.design.client.constants.FlexAlignItems; 048import gwt.material.design.client.constants.FlexAlignSelf; 049import gwt.material.design.client.constants.FlexDirection; 050import gwt.material.design.client.constants.FlexJustifyContent; 051import gwt.material.design.client.constants.FlexWrap; 052import gwt.material.design.client.constants.HideOn; 053import gwt.material.design.client.constants.Position; 054import gwt.material.design.client.constants.ShowOn; 055import gwt.material.design.client.constants.TextAlign; 056import gwt.material.design.client.constants.WavesType; 057 058import java.util.ArrayList; 059import java.util.HashMap; 060import java.util.List; 061import java.util.Map; 062 063public class MaterialWidget extends ComplexPanel implements HasId, HasEnabled, HasTextAlign, HasColors, HasGrid, 064 HasShadow, Focusable, HasInlineStyle, HasSeparator, HasScrollspy, HasHideOn, HasShowOn, HasCenterOn, 065 HasCircle, HasWaves, HasDataAttributes, HasFloat, HasTooltip, HasFlexbox, HasHoverable, HasFontWeight, 066 HasDepth, HasInitialClasses { 067 068 /** 069 * Configurable features enum see {@link #enableFeature(Feature, boolean)}. 070 */ 071 public enum Feature { 072 // Feature for adding or inserting children 073 // before this widget has loaded (attached). 074 ONLOAD_ADD_QUEUE 075 } 076 077 class Appender { 078 Widget widget; 079 int index = -1; 080 081 public Appender(Widget widget, int index) { 082 this.widget = widget; 083 this.index = index; 084 } 085 086 public Appender(Widget widget) { 087 this.widget = widget; 088 } 089 } 090 091 private Map<Feature, Boolean> features; 092 private List<Appender> onLoadAdd; 093 094 private String[] initialClasses; 095 096 private IdMixin<MaterialWidget> idMixin; 097 private EnabledMixin<MaterialWidget> enabledMixin; 098 private CssNameMixin<MaterialWidget, TextAlign> textAlignMixin; 099 private ColorsMixin<MaterialWidget> colorsMixin; 100 private FocusableMixin<MaterialWidget> focusableMixin; 101 private GridMixin<MaterialWidget> gridMixin; 102 private ShadowMixin<MaterialWidget> shadowMixin; 103 private SeparatorMixin<MaterialWidget> separatorMixin; 104 private ScrollspyMixin<MaterialWidget> scrollspyMixin; 105 private CssNameMixin<MaterialWidget, HideOn> hideOnMixin; 106 private CssNameMixin<MaterialWidget, ShowOn> showOnMixin; 107 private CssNameMixin<MaterialWidget, CenterOn> centerOnMixin; 108 private FontSizeMixin<MaterialWidget> fontSizeMixin; 109 private ToggleStyleMixin<MaterialWidget> circleMixin; 110 private WavesMixin<MaterialWidget> wavesMixin; 111 private CssNameMixin<MaterialWidget, Float> floatMixin; 112 private TooltipMixin<MaterialWidget> tooltipMixin; 113 private FlexboxMixin<MaterialWidget> flexboxMixin; 114 private ToggleStyleMixin<MaterialWidget> hoverableMixin; 115 private CssNameMixin<MaterialWidget, FontWeight> fontWeightMixin; 116 private ToggleStyleMixin<MaterialWidget> truncateMixin; 117 118 public MaterialWidget() { 119 } 120 121 public MaterialWidget(Element element) { 122 setElement(element); 123 } 124 125 public MaterialWidget(Element element, String... initialClass) { 126 this(element); 127 setInitialClasses(initialClass); 128 } 129 130 @Override 131 protected void onLoad() { 132 super.onLoad(); 133 134 if(initialClasses != null) { 135 for (String intial : initialClasses) { 136 if (!intial.isEmpty()) { 137 removeStyleName(intial); 138 addStyleName(intial); 139 } 140 } 141 } 142 143 if(isFeatureEnabled(Feature.ONLOAD_ADD_QUEUE) && onLoadAdd != null) { 144 // Check the on load add items. 145 for (Appender item : onLoadAdd) { 146 if(item.index == -1) { 147 add(item.widget, (Element) getElement()); 148 } else { 149 insert(item.widget, item.index); 150 } 151 } 152 onLoadAdd.clear(); 153 } 154 } 155 156 @Override 157 public void add(Widget child) { 158 super.add(child, (Element)getElement()); 159 } 160 161 @Override 162 protected void add(Widget child, com.google.gwt.user.client.Element container) { 163 if(!isAttached() && isFeatureEnabled(Feature.ONLOAD_ADD_QUEUE)) { 164 if(onLoadAdd == null) { onLoadAdd = new ArrayList<>(); } 165 onLoadAdd.add(new Appender(child)); 166 } else { 167 super.add(child, container); 168 } 169 } 170 171 @Override 172 protected void insert(Widget child, com.google.gwt.user.client.Element container, int beforeIndex, boolean domInsert) { 173 if(!isAttached() && isFeatureEnabled(Feature.ONLOAD_ADD_QUEUE)) { 174 if(onLoadAdd == null) { onLoadAdd = new ArrayList<>(); } 175 onLoadAdd.add(new Appender(child, beforeIndex)); 176 } else { 177 // Regular child addition 178 super.insert(child, container, beforeIndex, domInsert); 179 } 180 } 181 182 /** 183 * Inserts a widget at a specific index 184 * 185 * @param child - widget to be inserted 186 * @param beforeIndex - index for the widget 187 */ 188 public void insert(final Widget child, final int beforeIndex) { 189 insert(child, (Element) getElement(), beforeIndex, true); 190 } 191 192 protected IdMixin<MaterialWidget> getIdMixin() { 193 if(idMixin == null) { idMixin = new IdMixin<>(this); } 194 return idMixin; 195 } 196 197 protected EnabledMixin<MaterialWidget> getEnabledMixin() { 198 if(enabledMixin == null) { enabledMixin = new EnabledMixin<>(this); } 199 return enabledMixin; 200 } 201 202 protected CssNameMixin<MaterialWidget, TextAlign> getTextAlignMixin() { 203 if(textAlignMixin == null) { textAlignMixin = new CssNameMixin<>(this); } 204 return textAlignMixin; 205 } 206 207 protected ColorsMixin<MaterialWidget> getColorsMixin() { 208 if(colorsMixin == null) { colorsMixin = new ColorsMixin<>(this); } 209 return colorsMixin; 210 } 211 212 protected FocusableMixin<MaterialWidget> getFocusableMixin() { 213 if(focusableMixin == null) { focusableMixin = new FocusableMixin<>(this); } 214 return focusableMixin; 215 } 216 217 protected GridMixin<MaterialWidget> getGridMixin() { 218 if(gridMixin == null) { gridMixin = new GridMixin<>(this); } 219 return gridMixin; 220 } 221 222 protected ShadowMixin<MaterialWidget> getShadowMixin() { 223 if(shadowMixin == null) { shadowMixin = new ShadowMixin<>(this); } 224 return shadowMixin; 225 } 226 227 protected SeparatorMixin<MaterialWidget> getSeparatorMixin() { 228 if(separatorMixin == null) { separatorMixin = new SeparatorMixin<>(this); } 229 return separatorMixin; 230 } 231 232 protected ScrollspyMixin<MaterialWidget> getScrollspyMixin() { 233 if(scrollspyMixin == null) { scrollspyMixin = new ScrollspyMixin<>(this); } 234 return scrollspyMixin; 235 } 236 237 protected CssNameMixin<MaterialWidget, HideOn> getHideOnMixin() { 238 if(hideOnMixin == null) { hideOnMixin = new CssNameMixin<>(this); } 239 return hideOnMixin; 240 } 241 242 protected CssNameMixin<MaterialWidget, ShowOn> getShowOnMixin() { 243 if(showOnMixin == null) { showOnMixin = new CssNameMixin<>(this); } 244 return showOnMixin; 245 } 246 247 protected CssNameMixin<MaterialWidget, CenterOn> getCenterOnMixin() { 248 if(centerOnMixin == null) { centerOnMixin = new CssNameMixin<>(this); } 249 return centerOnMixin; 250 } 251 252 protected FontSizeMixin<MaterialWidget> getFontSizeMixin() { 253 if(fontSizeMixin == null) { fontSizeMixin = new FontSizeMixin<>(this); } 254 return fontSizeMixin; 255 } 256 257 protected ToggleStyleMixin<MaterialWidget> getCircleMixin() { 258 if(circleMixin == null) { circleMixin = new ToggleStyleMixin<>(this, "circle"); } 259 return circleMixin; 260 } 261 262 protected ToggleStyleMixin<MaterialWidget> getHoverableMixin() { 263 if(hoverableMixin == null) { hoverableMixin = new ToggleStyleMixin<>(this, "hoverable"); } 264 return hoverableMixin; 265 } 266 267 protected WavesMixin<MaterialWidget> getWavesMixin() { 268 if(wavesMixin == null) { wavesMixin = new WavesMixin<>(this); } 269 return wavesMixin; 270 } 271 272 protected CssNameMixin<MaterialWidget, Float> getFloatMixin() { 273 if(floatMixin == null) { floatMixin = new CssNameMixin<>(this); } 274 return floatMixin; 275 } 276 277 protected TooltipMixin<MaterialWidget> getTooltipMixin() { 278 if(tooltipMixin == null) { tooltipMixin = new TooltipMixin<>(this); } 279 return tooltipMixin; 280 } 281 282 protected FlexboxMixin<MaterialWidget> getFlexboxMixin() { 283 if(flexboxMixin == null) { flexboxMixin = new FlexboxMixin<>(this); } 284 return flexboxMixin; 285 } 286 287 protected CssNameMixin<MaterialWidget, FontWeight> getFontWeightMixin() { 288 if(fontWeightMixin == null) { fontWeightMixin = new CssNameMixin<>(this); } 289 return fontWeightMixin; 290 } 291 292 public ToggleStyleMixin<MaterialWidget> getTruncateMixin() { 293 if(truncateMixin == null) { truncateMixin = new ToggleStyleMixin<>(this, "truncate"); } 294 return truncateMixin; 295 } 296 297 @Override 298 public void setId(String id) { 299 getIdMixin().setId(id); 300 } 301 302 @Override 303 public String getId() { 304 return getIdMixin().getId(); 305 } 306 307 @Override 308 public boolean isEnabled() { 309 return getEnabledMixin().isEnabled(); 310 } 311 312 @Override 313 public void setEnabled(boolean enabled) { 314 getEnabledMixin().setEnabled(enabled); 315 } 316 317 @Override 318 public TextAlign getTextAlign() { 319 return getTextAlignMixin().getCssName(); 320 } 321 322 @Override 323 public void setTextAlign(TextAlign align) { 324 getTextAlignMixin().setCssName(align); 325 } 326 327 @Override 328 public void setBackgroundColor(String bgColor) { 329 getColorsMixin().setBackgroundColor(bgColor); 330 } 331 332 @Override 333 public String getBackgroundColor() { 334 return getColorsMixin().getBackgroundColor(); 335 } 336 337 @Override 338 public void setTextColor(String textColor) { 339 getColorsMixin().setTextColor(textColor); 340 } 341 342 @Override 343 public String getTextColor() { 344 return getColorsMixin().getTextColor(); 345 } 346 347 @Override 348 public int getTabIndex() { 349 return getFocusableMixin().getTabIndex(); 350 } 351 352 @Override 353 public void setAccessKey(char key) { 354 getFocusableMixin().setAccessKey(key); 355 } 356 357 @Override 358 public void setFocus(boolean focused) { 359 getFocusableMixin().setFocus(focused); 360 } 361 362 @Override 363 public void setTabIndex(int index) { 364 getFocusableMixin().setTabIndex(index); 365 } 366 367 @Override 368 public void setGrid(String grid) { 369 getGridMixin().setGrid(grid); 370 } 371 372 @Override 373 public void setOffset(String offset) { 374 getGridMixin().setOffset(offset); 375 } 376 377 @Override 378 public void setShadow(int shadow) { 379 getShadowMixin().setShadow(shadow); 380 } 381 382 @Override 383 public int getShadow() { 384 return getShadowMixin().getShadow(); 385 } 386 387 @Override 388 public void setMargin(double margin) { 389 getElement().getStyle().setMargin(margin, Style.Unit.PX); 390 } 391 392 @Override 393 public void setMarginTop(final double margin) { 394 getElement().getStyle().setMarginTop(margin, Style.Unit.PX); 395 } 396 397 @Override 398 public void setMarginLeft(final double margin) { 399 getElement().getStyle().setMarginLeft(margin, Style.Unit.PX); 400 } 401 402 @Override 403 public void setMarginRight(final double margin) { 404 getElement().getStyle().setMarginRight(margin, Style.Unit.PX); 405 } 406 407 @Override 408 public void setMarginBottom(final double margin) { 409 getElement().getStyle().setMarginBottom(margin, Style.Unit.PX); 410 } 411 412 @Override 413 public void setPadding(double padding) { 414 getElement().getStyle().setPadding(padding, Style.Unit.PX); 415 } 416 417 @Override 418 public void setPaddingTop(final double padding) { 419 getElement().getStyle().setPaddingTop(padding, Style.Unit.PX); 420 } 421 422 @Override 423 public void setPaddingLeft(final double padding) { 424 getElement().getStyle().setPaddingLeft(padding, Style.Unit.PX); 425 } 426 427 @Override 428 public void setPaddingRight(final double padding) { 429 getElement().getStyle().setPaddingRight(padding, Style.Unit.PX); 430 } 431 432 @Override 433 public void setPaddingBottom(final double padding) { 434 getElement().getStyle().setPaddingBottom(padding, Style.Unit.PX); 435 } 436 437 @Override 438 public void setGwtDisplay(Style.Display display) { 439 getFlexboxMixin().setGwtDisplay(display); 440 } 441 442 @Override 443 public void setOpacity(double opacity) { 444 getElement().getStyle().setOpacity(opacity); 445 } 446 447 @Override 448 public double getOpacity() { 449 return Double.parseDouble(getElement().getStyle().getOpacity()); 450 } 451 452 @Override 453 public void setSeparator(boolean separator) { 454 getSeparatorMixin().setSeparator(separator); 455 } 456 457 @Override 458 public boolean isSeparator() { 459 return getSeparatorMixin().isSeparator(); 460 } 461 462 @Override 463 public void setScrollspy(String scrollspy) { 464 getScrollspyMixin().setScrollspy(scrollspy); 465 } 466 467 @Override 468 public String getScrollspy() { 469 return getScrollspyMixin().getScrollspy(); 470 } 471 472 @Override 473 public void setCenterOn(CenterOn centerOn) { 474 getCenterOnMixin().setCssName(centerOn); 475 } 476 477 @Override 478 public CenterOn getCenterOn() { 479 return getCenterOnMixin().getCssName(); 480 } 481 482 @Override 483 public void setHideOn(HideOn hideOn) { 484 getHideOnMixin().setCssName(hideOn); 485 } 486 487 @Override 488 public HideOn getHideOn() { 489 return getHideOnMixin().getCssName(); 490 } 491 492 @Override 493 public void setShowOn(ShowOn showOn) { 494 getShowOnMixin().setCssName(showOn); 495 } 496 497 @Override 498 public ShowOn getShowOn() { 499 return getShowOnMixin().getCssName(); 500 } 501 502 @Override 503 public void setFontSize(String fontSize) { 504 getFontSizeMixin().setFontSize(fontSize); 505 } 506 507 @Override 508 public String getFontSize() { 509 return getFontSizeMixin().getFontSize(); 510 } 511 512 @Override 513 public void setFontSize(double fontSize, Style.Unit unit) { 514 getFontSizeMixin().setFontSize(fontSize, unit); 515 } 516 517 @Override 518 public void setCircle(boolean circle) { 519 getCircleMixin().setOn(circle); 520 } 521 522 @Override 523 public boolean isCircle() { 524 return getCircleMixin().isOn(); 525 } 526 527 @Override 528 public void setWaves(WavesType waves) { 529 getWavesMixin().setWaves(waves); 530 } 531 532 @Override 533 public WavesType getWaves() { 534 return getWavesMixin().getWaves(); 535 } 536 537 @Override 538 public void setDataAttribute(String dataAttr, String value) { 539 if(!dataAttr.startsWith("data-")) { 540 dataAttr = "data-" + dataAttr; 541 } 542 getElement().setAttribute(dataAttr, value); 543 } 544 545 @Override 546 public String getDataAttribute(String dataAttr) { 547 if(!dataAttr.startsWith("data-")) { 548 dataAttr = "data-" + dataAttr; 549 } 550 return getElement().getAttribute(dataAttr); 551 } 552 553 @Override 554 public void setFloat(Float floatAlign) { 555 getFloatMixin().setCssName(floatAlign); 556 } 557 558 @Override 559 public Float getFloat() { 560 return StyleHelper.fromStyleName(Float.class, getFloatMixin().getCssName()); 561 } 562 563 @Override 564 public String getTooltip() { 565 return getTooltipMixin().getTooltip(); 566 } 567 568 @Override 569 public void setTooltip(String tooltip) { 570 getTooltipMixin().setTooltip(tooltip); 571 } 572 573 @Override 574 public Position getTooltipPosition() { 575 return getTooltipMixin().getTooltipPosition(); 576 } 577 578 @Override 579 public void setTooltipPosition(Position position) { 580 getTooltipMixin().setTooltipPosition(position); 581 } 582 583 @Override 584 public int getTooltipDelayMs() { 585 return getTooltipMixin().getTooltipDelayMs(); 586 } 587 588 @Override 589 public void setTooltipDelayMs(int delayMs) { 590 getTooltipMixin().setTooltipDelayMs(delayMs); 591 } 592 593 public void setVisibility(Style.Visibility visibility) { 594 getElement().getStyle().setVisibility(visibility); 595 } 596 597 @Override 598 public void setDisplay(Display display) { 599 getFlexboxMixin().setDisplay(display); 600 } 601 602 @Override 603 public void setFlexDirection(FlexDirection flexDirection) { 604 getFlexboxMixin().setFlexDirection(flexDirection); 605 } 606 607 @Override 608 public void setFlex(Flex flex) { 609 getFlexboxMixin().setFlex(flex); 610 } 611 612 @Override 613 public void setFlexGrow(Integer flexGrow) { 614 getFlexboxMixin().setFlexGrow(flexGrow); 615 } 616 617 @Override 618 public void setFlexShrink(Integer flexShrink) { 619 getFlexboxMixin().setFlexShrink(flexShrink); 620 } 621 622 @Override 623 public void setFlexBasis(String flexBasis) { 624 getFlexboxMixin().setFlexBasis(flexBasis); 625 } 626 627 @Override 628 public void setFlexOrder(Integer flexOrder) { 629 getFlexboxMixin().setFlexOrder(flexOrder); 630 } 631 632 @Override 633 public void setFlexWrap(FlexWrap flexWrap) { 634 getFlexboxMixin().setFlexWrap(flexWrap); 635 } 636 637 @Override 638 public void setFlexAlignContent(FlexAlignContent flexAlignContent) { 639 getFlexboxMixin().setFlexAlignContent(flexAlignContent); 640 } 641 642 @Override 643 public void setFlexAlignSelf(FlexAlignSelf flexAlignSelf) { 644 getFlexboxMixin().setFlexAlignSelf(flexAlignSelf); 645 } 646 647 @Override 648 public void setFlexAlignItems(FlexAlignItems flexAlignItems) { 649 getFlexboxMixin().setFlexAlignItems(flexAlignItems); 650 } 651 652 @Override 653 public void setFlexJustifyContent(FlexJustifyContent flexJustifyContent) { 654 getFlexboxMixin().setFlexJustifyContent(flexJustifyContent); 655 } 656 657 public void setOverflow(Style.Overflow overflow) { 658 getElement().getStyle().setOverflow(overflow); 659 } 660 661 public void setLayoutPosition(Style.Position position) { 662 getElement().getStyle().setPosition(position); 663 } 664 665 public void setLeft(double value) { 666 getElement().getStyle().setLeft(value, Style.Unit.PX); 667 } 668 669 public void setRight(double value) { 670 getElement().getStyle().setRight(value, Style.Unit.PX); 671 } 672 673 public void setTop(double value) { 674 getElement().getStyle().setTop(value, Style.Unit.PX); 675 } 676 677 public void setBottom(double value) { 678 getElement().getStyle().setBottom(value, Style.Unit.PX); 679 } 680 681 @Override 682 public void setHoverable(boolean hoverable) { 683 getHoverableMixin().setOn(hoverable); 684 } 685 686 @Override 687 public boolean isHoverable() { 688 return getHoverableMixin().isOn(); 689 } 690 691 @Override 692 public void setFontWeight(FontWeight fontWeight) { 693 getElement().getStyle().setFontWeight(fontWeight); 694 } 695 696 @Override 697 public String getFontWeight() { 698 return getElement().getStyle().getFontWeight(); 699 } 700 701 @Override 702 public void setDepth(int depth) { 703 getElement().getStyle().setZIndex(depth); 704 } 705 706 @Override 707 public int getDepth() { 708 return Integer.parseInt(getElement().getStyle().getZIndex()); 709 } 710 711 /** If true the label inside this component will be truncated by ellipsis **/ 712 public void setTruncate(boolean truncate) { 713 getTruncateMixin().setOn(truncate); 714 } 715 716 public void stopTouchStartEvent() { 717 stopTouchStartEvent(getElement()); 718 } 719 720 // Avoid touch events on mobile devices 721 protected native void stopTouchStartEvent(Element e) /*-{ 722 $wnd.jQuery(e).bind('touchstart', function(event) { 723 event.stopPropagation(); 724 }); 725 }-*/; 726 727 public int getWidth() { 728 return getWidth(getElement()); 729 } 730 731 protected native int getWidth(Element element) /*-{ 732 return $wnd.jQuery(element).outerWidth(); 733 }-*/; 734 735 protected void clearActiveClass(HasWidgets widget) { 736 for(Widget child : widget) { 737 Element element = child.getElement(); 738 if(StyleHelper.containsStyle(element.getClassName(), "active")) { 739 element.removeClassName("active"); 740 } 741 742 if(child instanceof HasWidgets) { 743 clearActiveClass((HasWidgets)child); 744 } 745 } 746 } 747 748 @Override 749 public void setInitialClasses(String... initialClasses) { 750 this.initialClasses = initialClasses; 751 } 752 753 @Override 754 public String[] getInitialClasses() { 755 return initialClasses; 756 } 757 758 /** 759 * Enable or disable a complex {@link Feature}.<br/> 760 * @param feature the feature to enable. 761 * @param enabled true to enable false to disable. 762 */ 763 public void enableFeature(Feature feature, boolean enabled) { 764 if(features == null) { features = new HashMap<>(); } 765 features.put(feature, enabled); 766 } 767 768 /** 769 * Check if a {@link Feature} is enabled. 770 */ 771 public boolean isFeatureEnabled(Feature feature) { 772 if(features != null) { 773 Boolean enabled = features.get(feature); 774 return enabled != null && enabled; 775 } else { 776 return false; 777 } 778 } 779}