]> source.dussan.org Git - vaadin-framework.git/commitdiff
Implement error level on client side (#9816)
authorAdam Wagner <wbadam@users.noreply.github.com>
Tue, 26 Sep 2017 07:20:49 +0000 (10:20 +0300)
committerHenri Sara <henri.sara@gmail.com>
Tue, 26 Sep 2017 07:20:49 +0000 (10:20 +0300)
Add additional class names and style to components and error indicators to distinguish different error levels.

Vaadin 7 solution for #3139

36 files changed:
client/src/main/java/com/vaadin/client/StyleConstants.java
client/src/main/java/com/vaadin/client/TooltipInfo.java
client/src/main/java/com/vaadin/client/VCaption.java
client/src/main/java/com/vaadin/client/VErrorMessage.java
client/src/main/java/com/vaadin/client/VTooltip.java
client/src/main/java/com/vaadin/client/WidgetUtil.java
client/src/main/java/com/vaadin/client/ui/AbstractComponentConnector.java
client/src/main/java/com/vaadin/client/ui/VAccordion.java
client/src/main/java/com/vaadin/client/ui/VFormLayout.java
client/src/main/java/com/vaadin/client/ui/VPanel.java
client/src/main/java/com/vaadin/client/ui/VTabsheet.java
client/src/main/java/com/vaadin/client/ui/button/ButtonConnector.java
client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
client/src/main/java/com/vaadin/client/ui/form/FormConnector.java
client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java
client/src/main/java/com/vaadin/client/ui/link/LinkConnector.java
client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
client/src/main/java/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
client/src/main/java/com/vaadin/client/ui/orderedlayout/Slot.java
client/src/main/java/com/vaadin/client/ui/panel/PanelConnector.java
server/src/main/java/com/vaadin/server/ErrorMessage.java
server/src/main/java/com/vaadin/ui/AbstractComponent.java
server/src/main/java/com/vaadin/ui/TabSheet.java
shared/src/main/java/com/vaadin/shared/AbstractComponentState.java
shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java [new file with mode: 0644]
shared/src/main/java/com/vaadin/shared/ui/tabsheet/TabState.java
themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss
themes/src/main/themes/VAADIN/themes/valo/components/_datefield.scss
themes/src/main/themes/VAADIN/themes/valo/components/_textfield.scss
themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss
themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss
themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss
themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss
uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java

index fe04fc7c4622a2e4dec6b593adcc6e15f36ba634..61ee4327a46ac8227c4c29cd42a7a82e38031b48 100644 (file)
@@ -44,4 +44,9 @@ public class StyleConstants {
     public static final String REQUIRED_EXT = "-required";
 
     public static final String ERROR_EXT = "-error";
+
+    /**
+     * Style name and style name prefix for the error indicator element.
+     */
+    public static final String STYLE_NAME_ERROR_INDICATOR = "v-errorindicator";
 }
index 6e3e063be2faf7d8d65b8d363ba76aa7bc60bccb..b264f930ad93b0ddffe37dc9c13fdd9549bbdf4a 100644 (file)
  */
 package com.vaadin.client;
 
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.shared.util.SharedUtil;
 
+/**
+ * An object that contains information about a tooltip, such as the tooltip's
+ * title, error message, error level and an ID.
+ */
 public class TooltipInfo {
 
     private String title;
 
     private String errorMessageHtml;
 
+    private ErrorLevel errorLevel;
+
     // Contains the tooltip's identifier. If a tooltip's contents and this
     // identifier haven't changed, the tooltip won't be updated in subsequent
     // events.
     private Object identifier;
 
+    /**
+     * Constructs a new tooltip info instance.
+     */
     public TooltipInfo() {
     }
 
+    /**
+     * Constructs a new tooltip info instance.
+     *
+     * @param tooltip
+     *         tooltip title
+     */
     public TooltipInfo(String tooltip) {
         setTitle(tooltip);
     }
 
+    /**
+     * Constructs a new tooltip info instance.
+     *
+     * @param tooltip
+     *         tooltip title
+     * @param errorMessage
+     *         error message
+     */
     public TooltipInfo(String tooltip, String errorMessage) {
         this(tooltip, errorMessage, null);
     }
 
+    /**
+     * Constructs a new tooltip info instance.
+     *
+     * @param tooltip
+     *         tooltip title
+     * @param errorMessage
+     *         error message
+     * @param identifier
+     *         the tooltip's identifier
+     */
     public TooltipInfo(String tooltip, String errorMessage, Object identifier) {
+        this(tooltip, errorMessage, identifier, null);
+    }
+
+    /**
+     * Constructs a new tooltip info instance.
+     *
+     * @param tooltip
+     *         tooltip title
+     * @param errorMessage
+     *         error message
+     * @param identifier
+     *         the tooltip's identifier
+     * @param errorLevel
+     *         error level
+     */
+    public TooltipInfo(String tooltip, String errorMessage, Object identifier,
+            ErrorLevel errorLevel) {
         setIdentifier(identifier);
         setTitle(tooltip);
         setErrorMessage(errorMessage);
+        setErrorLevel(errorLevel);
     }
 
+    /**
+     * Sets the tooltip's identifier.
+     *
+     * @param identifier
+     *         the identifier to set
+     */
     public void setIdentifier(Object identifier) {
         this.identifier = identifier;
     }
 
+    /**
+     * Gets the tooltip's identifier.
+     *
+     * @return the identifier
+     */
     public Object getIdentifier() {
         return identifier;
     }
 
+    /**
+     * Gets the tooltip title.
+     *
+     * @return the title
+     */
     public String getTitle() {
         return title;
     }
 
+    /**
+     * Sets the tooltip title.
+     *
+     * @param title
+     *         the title to set
+     */
     public void setTitle(String title) {
         this.title = title;
     }
 
+    /**
+     * Gets the error message.
+     *
+     * @return the error message
+     */
     public String getErrorMessage() {
         return errorMessageHtml;
     }
 
+    /**
+     * Sets the error message.
+     *
+     * @param errorMessage
+     *         the error message to set
+     */
     public void setErrorMessage(String errorMessage) {
         errorMessageHtml = errorMessage;
     }
 
+    /**
+     * Gets the error level.
+     *
+     * @return the error level
+     */
+    public ErrorLevel getErrorLevel() {
+        return errorLevel;
+    }
+
+    /**
+     * Sets the error level.
+     *
+     * @param errorLevel
+     *         the error level to set
+     */
+    public void setErrorLevel(ErrorLevel errorLevel) {
+        this.errorLevel = errorLevel;
+    }
+
     /**
      * Checks is a message has been defined for the tooltip.
      *
@@ -80,9 +184,19 @@ public class TooltipInfo {
                 || (errorMessageHtml != null && !errorMessageHtml.isEmpty());
     }
 
+    /**
+     * Indicates whether another tooltip info instance is equal to this one. Two
+     * instances are equal if their title, error message, error level and
+     * identifier are equal.
+     *
+     * @param other
+     *         the reference tooltip info instance with which to compare
+     * @return {@code true} if the instances are equal, {@code false} otherwise
+     */
     public boolean equals(TooltipInfo other) {
         return (other != null && SharedUtil.equals(other.title, title)
                 && SharedUtil.equals(other.errorMessageHtml, errorMessageHtml)
+                && SharedUtil.equals(other.errorLevel, errorLevel)
                 && other.identifier == identifier);
     }
 }
index 1d79bd57ccd87c2610bfd40ebc9f31a6c66e213b..7268e68e2ac0e8e8980b49a7fe42cabb704a84b2 100644 (file)
@@ -25,6 +25,7 @@ import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.HasHTML;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.communication.StateChangeEvent;
 import com.vaadin.client.ui.AbstractFieldConnector;
 import com.vaadin.client.ui.Icon;
@@ -34,6 +35,7 @@ import com.vaadin.shared.AbstractComponentState;
 import com.vaadin.shared.AbstractFieldState;
 import com.vaadin.shared.ComponentConstants;
 import com.vaadin.shared.ui.ComponentStateUtil;
+import com.vaadin.shared.ui.ErrorLevel;
 
 public class VCaption extends HTML {
 
@@ -264,7 +266,7 @@ public class VCaption extends HTML {
                 errorIndicatorElement = DOM.createDiv();
                 DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
                 DOM.setElementProperty(errorIndicatorElement, "className",
-                        "v-errorindicator");
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR);
 
                 DOM.insertChild(getElement(), errorIndicatorElement,
                         getInsertPosition(InsertPosition.ERROR));
@@ -273,6 +275,11 @@ public class VCaption extends HTML {
                 Roles.getTextboxRole().setAriaHiddenState(errorIndicatorElement,
                         true);
             }
+
+            ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR,
+                    owner.getState().errorLevel);
+
         } else if (errorIndicatorElement != null) {
             // Remove existing
             getElement().removeChild(errorIndicatorElement);
@@ -323,6 +330,14 @@ public class VCaption extends HTML {
     public boolean updateCaptionWithoutOwner(String caption, boolean disabled,
             boolean hasDescription, boolean hasError, String iconURL,
             String iconAltText) {
+        return updateCaptionWithoutOwner(caption, disabled, hasDescription,
+                hasError, null, iconURL, iconAltText);
+    }
+
+    @Deprecated
+    public boolean updateCaptionWithoutOwner(String caption, boolean disabled,
+            boolean hasDescription, boolean hasError, ErrorLevel errorLevel,
+            String iconURL, String iconAltText) {
         boolean wasPlacedAfterComponent = placedAfterComponent;
 
         // Caption is placed after component unless there is some part which
@@ -406,11 +421,15 @@ public class VCaption extends HTML {
                 errorIndicatorElement = DOM.createDiv();
                 DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
                 DOM.setElementProperty(errorIndicatorElement, "className",
-                        "v-errorindicator");
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR);
 
                 DOM.insertChild(getElement(), errorIndicatorElement,
                         getInsertPosition(InsertPosition.ERROR));
             }
+
+            ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel);
+
         } else if (errorIndicatorElement != null) {
             // Remove existing
             getElement().removeChild(errorIndicatorElement);
index fa7fe1a51ab76c076c455679e2231d1aae3b0b1d..e13bca9c6a74b638490fa2f7a5986dedde2362ac 100644 (file)
@@ -22,6 +22,8 @@ import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.ui.VOverlay;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
+import com.vaadin.shared.ui.ErrorLevel;
 
 public class VErrorMessage extends FlowPanel {
     public static final String CLASSNAME = "v-errormessage";
@@ -57,6 +59,18 @@ public class VErrorMessage extends FlowPanel {
         }
     }
 
+    /**
+     * Sets the correct error level style name for the error message and removes
+     * all previous style names.
+     *
+     * @param errorLevel
+     *         error level
+     * @since
+     */
+    public void updateErrorLevel(ErrorLevel errorLevel) {
+        ErrorUtil.setErrorLevelStyle(getStyleElement(), CLASSNAME, errorLevel);
+    }
+
     /**
      * Shows this error message next to given element.
      *
index 09d3ab5d650351f0a9d8ced01d2c4c233a1e4ce5..64f36fda4760a48825dbdb392b4a8051f81b1ab2 100644 (file)
@@ -137,6 +137,7 @@ public class VTooltip extends VOverlay {
                 && !info.getErrorMessage().isEmpty()) {
             em.setVisible(true);
             em.updateMessage(info.getErrorMessage());
+            em.updateErrorLevel(info.getErrorLevel());
         } else {
             em.setVisible(false);
         }
@@ -440,6 +441,7 @@ public class VTooltip extends VOverlay {
     @Override
     public void hide() {
         em.updateMessage("");
+        em.updateErrorLevel(null);
         description.setInnerHTML("");
 
         updatePosition(null, true);
index d6d36c1cb1451dc6b11aaf2d7282a85ded6645a9..8ce2e0c500138eda7c0a6ab4b7ed6227cc850943 100644 (file)
@@ -45,6 +45,7 @@ import com.google.gwt.user.client.EventListener;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.shared.util.SharedUtil;
 
 /**
@@ -1822,4 +1823,35 @@ public class WidgetUtil {
         // 12 + int(30.6) / 60 = 12 + 30/60 = 12.5
         return integerPart + ((int) nrFractions) / divisor;
     }
+
+    /**
+     * Utility methods for displaying error message on components.
+     */
+    public static class ErrorUtil {
+
+        /**
+         * Sets the error level style name for the given element and removes all
+         * previously applied error level style names. The style name has the
+         * {@code prefix-errorLevel} format.
+         *
+         * @param element
+         *         element to apply the style name to
+         * @param prefix
+         *         part of the style name before the error level string
+         * @param errorLevel
+         *         error level for which the style will be applied
+         */
+        public static void setErrorLevelStyle(Element element, String prefix,
+                ErrorLevel errorLevel) {
+            for (ErrorLevel errorLevelValue : ErrorLevel.values()) {
+                String className =
+                        prefix + "-" + errorLevelValue.toString().toLowerCase();
+                if (errorLevel == errorLevelValue) {
+                    element.addClassName(className);
+                } else {
+                    element.removeClassName(className);
+                }
+            }
+        }
+    }
 }
index 9e2854c2593ae9abe3f2bd4b67698465a8554d8e..0416375d6ffdcf8963a24cecff78d273dcea95fb 100644 (file)
@@ -46,6 +46,7 @@ import com.vaadin.client.UIDL;
 import com.vaadin.client.Util;
 import com.vaadin.client.VConsole;
 import com.vaadin.client.WidgetUtil;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.annotations.OnStateChange;
 import com.vaadin.client.communication.StateChangeEvent;
 import com.vaadin.client.metadata.NoDataException;
@@ -637,6 +638,10 @@ public abstract class AbstractComponentConnector extends AbstractConnector
         setWidgetStyleNameWithPrefix(primaryStyleName, StyleConstants.ERROR_EXT,
                 null != state.errorMessage);
 
+        // add or remove error level style name
+        ErrorUtil.setErrorLevelStyle(getWidget().getElement(),
+                primaryStyleName + StyleConstants.ERROR_EXT, state.errorLevel);
+
         // add additional user defined style names as class names, prefixed with
         // component default class name. remove nonexistent style names.
 
@@ -764,7 +769,8 @@ public abstract class AbstractComponentConnector extends AbstractConnector
 
     @Override
     public TooltipInfo getTooltipInfo(Element element) {
-        return new TooltipInfo(getState().description, getState().errorMessage);
+        return new TooltipInfo(getState().description, getState().errorMessage,
+                null, getState().errorLevel);
     }
 
     @Override
index 0e202c31531bfbb373e7ac62293e225ee591f75f..642669d10d27ef8983dc3135d939a9c941408e64 100644 (file)
@@ -364,8 +364,10 @@ public class VAccordion extends VTabsheetBase {
             caption.updateCaptionWithoutOwner(tabState.caption,
                     !tabState.enabled, hasAttribute(tabState.description),
                     hasAttribute(tabState.componentError),
+                    tabState.componentErrorLevel,
                     connector.getResourceUrl(
-                            ComponentConstants.ICON_RESOURCE + tabState.key));
+                            ComponentConstants.ICON_RESOURCE + tabState.key),
+                    tabState.iconAltText);
         }
 
         private boolean hasAttribute(String string) {
index a221222b9255cbad83957e1ecc7dd64262ba00cc..9ee10cd99c786d638613b7fbeb1c035f5595972e 100644 (file)
@@ -34,10 +34,12 @@ import com.vaadin.client.ComponentConnector;
 import com.vaadin.client.Focusable;
 import com.vaadin.client.StyleConstants;
 import com.vaadin.client.VTooltip;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.ui.aria.AriaHelper;
 import com.vaadin.shared.AbstractComponentState;
 import com.vaadin.shared.ComponentConstants;
 import com.vaadin.shared.ui.ComponentStateUtil;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.shared.ui.MarginInfo;
 
 /**
@@ -201,10 +203,10 @@ public class VFormLayout extends SimplePanel {
         }
 
         public void updateError(Widget widget, String errorMessage,
-                boolean hideErrors) {
+                ErrorLevel errorLevel, boolean hideErrors) {
             final ErrorFlag e = widgetToError.get(widget);
             if (e != null) {
-                e.updateError(errorMessage, hideErrors);
+                e.updateError(errorMessage, errorLevel, hideErrors);
             }
 
         }
@@ -360,7 +362,8 @@ public class VFormLayout extends SimplePanel {
             return owner;
         }
 
-        public void updateError(String errorMessage, boolean hideErrors) {
+        public void updateError(String errorMessage, ErrorLevel errorLevel,
+                boolean hideErrors) {
             boolean showError = null != errorMessage;
             if (hideErrors) {
                 showError = false;
@@ -373,7 +376,7 @@ public class VFormLayout extends SimplePanel {
                     errorIndicatorElement = DOM.createDiv();
                     DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
                     DOM.setElementProperty(errorIndicatorElement, "className",
-                            "v-errorindicator");
+                            StyleConstants.STYLE_NAME_ERROR_INDICATOR);
                     DOM.appendChild(getElement(), errorIndicatorElement);
 
                     // Hide the error indicator from screen reader, as this
@@ -382,6 +385,9 @@ public class VFormLayout extends SimplePanel {
                             .setAriaHiddenState(errorIndicatorElement, true);
                 }
 
+                ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel);
+
             } else if (errorIndicatorElement != null) {
                 DOM.removeChild(getElement(), errorIndicatorElement);
                 errorIndicatorElement = null;
index a48703c91487bb7b230fd2fed88001790a4d14a9..177d026fa1c7dfe2065dae26827f409067cefc1d 100644 (file)
@@ -24,8 +24,11 @@ import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.SimplePanel;
 import com.vaadin.client.ApplicationConnection;
 import com.vaadin.client.Focusable;
+import com.vaadin.client.StyleConstants;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
 import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
+import com.vaadin.shared.ui.ErrorLevel;
 
 public class VPanel extends SimplePanel
         implements ShortcutActionHandlerOwner, Focusable {
@@ -134,15 +137,20 @@ public class VPanel extends SimplePanel
     }
 
     /** For internal use only. May be removed or replaced in the future. */
-    public void setErrorIndicatorVisible(boolean showError) {
+    public void setErrorIndicatorVisible(boolean showError,
+            ErrorLevel errorLevel) {
         if (showError) {
             if (errorIndicatorElement == null) {
                 errorIndicatorElement = DOM.createSpan();
                 DOM.setElementProperty(errorIndicatorElement, "className",
-                        "v-errorindicator");
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR);
                 DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS);
                 sinkEvents(Event.MOUSEEVENTS);
             }
+
+            ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel);
+
             DOM.insertBefore(captionNode, errorIndicatorElement, captionText);
         } else if (errorIndicatorElement != null) {
             DOM.removeChild(captionNode, errorIndicatorElement);
index ca7db968d8e6891ec4ec9713224930abfc1a52f9..4a57a40f1646cc69721236b9f5144386a1675c5b 100644 (file)
@@ -339,7 +339,8 @@ public class VTabsheet extends VTabsheetBase
             if (tabState.description != null
                     || tabState.componentError != null) {
                 setTooltipInfo(new TooltipInfo(tabState.description,
-                        tabState.componentError, this));
+                        tabState.componentError, this,
+                        tabState.componentErrorLevel));
             } else {
                 setTooltipInfo(null);
             }
@@ -351,6 +352,7 @@ public class VTabsheet extends VTabsheetBase
             boolean ret = updateCaptionWithoutOwner(captionString,
                     !tabState.enabled, hasAttribute(tabState.description),
                     hasAttribute(tabState.componentError),
+                    tabState.componentErrorLevel,
                     tab.getTabsheet().connector.getResourceUrl(
                             ComponentConstants.ICON_RESOURCE + tabState.key),
                     tabState.iconAltText);
index 0bd403edff0d2c45b6476ac23f034401df70492f..34e72b2fb5e4f10508aeae379b8a6815951a9bb8 100644 (file)
@@ -20,7 +20,9 @@ import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.DOM;
 import com.vaadin.client.MouseEventDetailsBuilder;
+import com.vaadin.client.StyleConstants;
 import com.vaadin.client.VCaption;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.annotations.OnStateChange;
 import com.vaadin.client.ui.AbstractComponentConnector;
 import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
@@ -50,14 +52,19 @@ public class ButtonConnector extends AbstractComponentConnector
         ConnectorFocusAndBlurHandler.addHandlers(this);
     }
 
-    @OnStateChange("errorMessage")
-    void setErrorMessage() {
+    @OnStateChange({"errorMessage", "errorLevel"})
+    void setErrorMessageAndLevel() {
         if (null != getState().errorMessage) {
             if (getWidget().errorIndicatorElement == null) {
                 getWidget().errorIndicatorElement = DOM.createSpan();
-                getWidget().errorIndicatorElement
-                        .setClassName("v-errorindicator");
+                getWidget().errorIndicatorElement.setClassName(
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR);
             }
+
+            ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR,
+                    getState().errorLevel);
+
             getWidget().wrapper.insertFirst(getWidget().errorIndicatorElement);
 
         } else if (getWidget().errorIndicatorElement != null) {
index 2e58124494a7d6f8c73475f6172e575c8670bffc..0c877406c20f82f818e2e5ce052b1c486ad70592 100644 (file)
@@ -21,8 +21,10 @@ import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 import com.vaadin.client.MouseEventDetailsBuilder;
+import com.vaadin.client.StyleConstants;
 import com.vaadin.client.VCaption;
 import com.vaadin.client.VTooltip;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.annotations.OnStateChange;
 import com.vaadin.client.communication.StateChangeEvent;
 import com.vaadin.client.ui.AbstractFieldConnector;
@@ -67,7 +69,7 @@ public class CheckBoxConnector extends AbstractFieldConnector
                 getWidget().errorIndicatorElement = DOM.createSpan();
                 getWidget().errorIndicatorElement.setInnerHTML("&nbsp;");
                 DOM.setElementProperty(getWidget().errorIndicatorElement,
-                        "className", "v-errorindicator");
+                        "className", StyleConstants.STYLE_NAME_ERROR_INDICATOR);
                 DOM.appendChild(getWidget().getElement(),
                         getWidget().errorIndicatorElement);
                 DOM.sinkEvents(getWidget().errorIndicatorElement,
@@ -75,6 +77,11 @@ public class CheckBoxConnector extends AbstractFieldConnector
             } else {
                 getWidget().errorIndicatorElement.getStyle().clearDisplay();
             }
+
+            ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR,
+                    getState().errorLevel);
+
         } else if (getWidget().errorIndicatorElement != null) {
             getWidget().errorIndicatorElement.getStyle()
                     .setDisplay(Display.NONE);
index 3c5da2bbd86380969abf8ac2464774df7ca5165e..0203987d31d379d175a4c98ffe921a2457ab0f36 100644 (file)
@@ -125,6 +125,7 @@ public class FormConnector extends AbstractComponentContainerConnector
 
         if (null != getState().errorMessage) {
             getWidget().errorMessage.updateMessage(getState().errorMessage);
+            getWidget().errorMessage.updateErrorLevel(getState().errorLevel);
             getWidget().errorMessage.setVisible(true);
         } else {
             getWidget().errorMessage.setVisible(false);
index 682d0dfd1fab032bb05cc13ba71303450ea7abd0..da1fd9047763d56c87b03b67bac31110bcccb7a1 100644 (file)
@@ -255,7 +255,8 @@ public class FormLayoutConnector extends AbstractLayoutConnector
         }
 
         getWidget().table.updateError(component.getWidget(),
-                component.getState().errorMessage, hideErrors);
+                component.getState().errorMessage,
+                component.getState().errorLevel, hideErrors);
     }
 
     @Override
index fb49db05c9798321863461cd7b7dbcdb8557bf97..03ddbd067c9a843d120cf7ba7f60f907d304c1d7 100644 (file)
@@ -18,7 +18,9 @@ package com.vaadin.client.ui.link;
 
 import com.google.gwt.dom.client.Style.Display;
 import com.google.gwt.user.client.DOM;
+import com.vaadin.client.StyleConstants;
 import com.vaadin.client.VCaption;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.communication.StateChangeEvent;
 import com.vaadin.client.ui.AbstractComponentConnector;
 import com.vaadin.client.ui.Icon;
@@ -75,8 +77,13 @@ public class LinkConnector extends AbstractComponentConnector {
             if (getWidget().errorIndicatorElement == null) {
                 getWidget().errorIndicatorElement = DOM.createDiv();
                 DOM.setElementProperty(getWidget().errorIndicatorElement,
-                        "className", "v-errorindicator");
+                        "className", StyleConstants.STYLE_NAME_ERROR_INDICATOR);
             }
+
+            ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR,
+                    getState().errorLevel);
+
             DOM.insertChild(getWidget().getElement(),
                     getWidget().errorIndicatorElement, 0);
         } else if (getWidget().errorIndicatorElement != null) {
index 81823c3d3ce0b5638b37f8e2e9f971ed56420776..8a9f53cfc4113739d56810034a56e8695d7ac2e4 100644 (file)
@@ -16,7 +16,9 @@
 package com.vaadin.client.ui.nativebutton;
 
 import com.google.gwt.user.client.DOM;
+import com.vaadin.client.StyleConstants;
 import com.vaadin.client.VCaption;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.communication.StateChangeEvent;
 import com.vaadin.client.ui.AbstractComponentConnector;
 import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
@@ -59,9 +61,14 @@ public class NativeButtonConnector extends AbstractComponentConnector {
         if (null != getState().errorMessage) {
             if (getWidget().errorIndicatorElement == null) {
                 getWidget().errorIndicatorElement = DOM.createSpan();
-                getWidget().errorIndicatorElement
-                        .setClassName("v-errorindicator");
+                getWidget().errorIndicatorElement.setClassName(
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR);
             }
+
+            ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR,
+                    getState().errorLevel);
+
             getWidget().getElement().insertBefore(
                     getWidget().errorIndicatorElement,
                     getWidget().captionElement);
index 960bf71884c29c92a5d76b70d8bb9adb2640a806..6fe2b4af184bd93ba31fe22d736b68aaba5dd9c1 100644 (file)
@@ -276,8 +276,9 @@ public abstract class AbstractOrderedLayoutConnector
             slot.setCaptionResizeListener(null);
         }
 
-        slot.setCaption(caption, icon, styles, error, showError, required,
-                enabled, child.getState().captionAsHtml);
+        slot.setCaption(caption, icon, styles, error,
+                child.getState().errorLevel, showError, required, enabled,
+                child.getState().captionAsHtml);
 
         AriaHelper.handleInputRequired(child.getWidget(), required);
         AriaHelper.handleInputInvalid(child.getWidget(), showError);
index 2315f0bc4be851de7955fae512dc7db23c65ce12..e7654091da3d21f899006c9f2c75ae0a50f5d9d2 100644 (file)
@@ -31,12 +31,14 @@ import com.vaadin.client.BrowserInfo;
 import com.vaadin.client.LayoutManager;
 import com.vaadin.client.StyleConstants;
 import com.vaadin.client.WidgetUtil;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.ui.FontIcon;
 import com.vaadin.client.ui.Icon;
 import com.vaadin.client.ui.ImageIcon;
 import com.vaadin.client.ui.layout.ElementResizeEvent;
 import com.vaadin.client.ui.layout.ElementResizeListener;
 import com.vaadin.shared.ui.AlignmentInfo;
+import com.vaadin.shared.ui.ErrorLevel;
 
 /**
  * Represents a slot which contains the actual widget in the layout.
@@ -519,6 +521,36 @@ public class Slot extends SimplePanel {
     public void setCaption(String captionText, Icon icon, List<String> styles,
             String error, boolean showError, boolean required, boolean enabled,
             boolean captionAsHtml) {
+        setCaption(captionText, icon, styles, error, null, showError, required,
+                enabled, captionAsHtml);
+    }
+
+    /**
+     * Set the caption of the slot
+     *
+     * @param captionText
+     *            The text of the caption
+     * @param icon
+     *            The icon
+     * @param styles
+     *            The style names
+     * @param error
+     *            The error message
+     * @param errorLevel
+     *            The error level
+     * @param showError
+     *            Should the error message be shown
+     * @param required
+     *            Is the (field) required
+     * @param enabled
+     *            Is the component enabled
+     * @param captionAsHtml
+     *            true if the caption should be rendered as HTML, false
+     *            otherwise
+     */
+    public void setCaption(String captionText, Icon icon, List<String> styles,
+            String error, ErrorLevel errorLevel, boolean showError,
+            boolean required, boolean enabled, boolean captionAsHtml) {
 
         // TODO place for optimization: check if any of these have changed
         // since last time, and only run those changes
@@ -611,8 +643,13 @@ public class Slot extends SimplePanel {
         if (error != null && showError) {
             if (errorIcon == null) {
                 errorIcon = DOM.createSpan();
-                errorIcon.setClassName("v-errorindicator");
+                errorIcon.setClassName(
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR);
             }
+
+            ErrorUtil.setErrorLevelStyle(errorIcon,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel);
+
             caption.appendChild(errorIcon);
         } else if (errorIcon != null) {
             errorIcon.removeFromParent();
index 9cf90b625463fab0e51ca4770d9ffbd16a2fca16..8e6358b1567bd41d3499f7d00630e1cb3be81f27 100644 (file)
@@ -143,7 +143,8 @@ public class PanelConnector extends AbstractSingleComponentContainerConnector
             getWidget().setIconUri(null, client);
         }
 
-        getWidget().setErrorIndicatorVisible(null != getState().errorMessage);
+        getWidget().setErrorIndicatorVisible(null != getState().errorMessage,
+                getState().errorLevel);
 
         // We may have actions attached to this panel
         if (uidl.getChildCount() > 0) {
index 48ce3a78df70252d4802027224978f96847f5a85..6107d5ab5b54d054ae908fb06234a16808268b35 100644 (file)
@@ -80,6 +80,26 @@ public interface ErrorMessage extends Serializable {
             return text;
         }
 
+        /**
+         * Converts this to an error level that can be used on the client side.
+         *
+         * @return error level for the client side
+         */
+        public com.vaadin.shared.ui.ErrorLevel convertToShared() {
+            switch (this) {
+            case INFORMATION:
+                return com.vaadin.shared.ui.ErrorLevel.INFO;
+            case WARNING:
+                return com.vaadin.shared.ui.ErrorLevel.WARNING;
+            case CRITICAL:
+                return com.vaadin.shared.ui.ErrorLevel.CRITICAL;
+            case SYSTEMERROR:
+                return com.vaadin.shared.ui.ErrorLevel.SYSTEM;
+            case ERROR:
+            default:
+                return com.vaadin.shared.ui.ErrorLevel.ERROR;
+            }
+        }
     }
 
     /**
index 24bb9f8f7923d7402e5612993714aaf50ae296bd..4da06d3848546db2c9e140c680a956ad6a105e1d 100644 (file)
@@ -782,8 +782,10 @@ public abstract class AbstractComponent extends AbstractClientConnector
         ErrorMessage error = getErrorMessage();
         if (null != error) {
             getState().errorMessage = error.getFormattedHtmlMessage();
+            getState().errorLevel = error.getErrorLevel().convertToShared();
         } else {
             getState().errorMessage = null;
+            getState().errorLevel = null;
         }
 
         getState().immediate = isImmediate();
index ce9214ae408f2cf6fba8476ae62c62d8eea84708..27b2cfb395138e695ba0b3e3b8558612b6e20fab 100644 (file)
@@ -1264,9 +1264,16 @@ public class TabSheet extends AbstractComponentContainer
         public void setComponentError(ErrorMessage componentError) {
             this.componentError = componentError;
 
-            String formattedHtmlMessage = componentError != null
-                    ? componentError.getFormattedHtmlMessage() : null;
-            tabState.componentError = formattedHtmlMessage;
+            if (componentError != null) {
+                tabState.componentError = componentError
+                        .getFormattedHtmlMessage();
+                tabState.componentErrorLevel = componentError.getErrorLevel()
+                        .convertToShared();
+            } else {
+                tabState.componentError = null;
+                tabState.componentErrorLevel = null;
+            }
+
 
             markAsDirty();
         }
index 755615c00b3ecedddcf914b3ac782107d762fcfb..8bbcc3eb1592a5074f4ae212ba4b5596e33f759f 100644 (file)
@@ -20,6 +20,7 @@ import java.util.List;
 
 import com.vaadin.shared.annotations.NoLayout;
 import com.vaadin.shared.communication.SharedState;
+import com.vaadin.shared.ui.ErrorLevel;
 
 /**
  * Default shared state implementation for AbstractComponent.
@@ -43,9 +44,11 @@ public class AbstractComponentState extends SharedState {
     public String id = null;
     public String primaryStyleName = null;
 
-    // HTML formatted error message for the component
-    // TODO this could be an object with more information, but currently the UI
-    // only uses the message
+    /** HTML formatted error message for the component */
     public String errorMessage = null;
+
+    /** Level of error */
+    public ErrorLevel errorLevel = null;
+
     public boolean captionAsHtml = false;
 }
diff --git a/shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java b/shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java
new file mode 100644 (file)
index 0000000..2993bef
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui;
+
+/**
+ * Represents the error levels displayed on components.
+ * @author Vaadin Ltd
+ * @since
+ */
+public enum ErrorLevel {
+
+    /**
+     * Error level for informational messages.
+     */
+    INFO,
+
+    /**
+     * Error level for warning messages.
+     */
+    WARNING,
+
+    /**
+     * Error level for regular messages.
+     */
+    ERROR,
+
+    /**
+     * Error level for critical messages.
+     */
+    CRITICAL,
+
+    /**
+     * Error level for system errors and bugs.
+     */
+    SYSTEM
+}
index 243dd92afb6f3262f6efd4d30ee56d4f3fd1adc7..c9e18508f7ebd656a6c782667dadba52bd8593a8 100644 (file)
@@ -17,6 +17,8 @@ package com.vaadin.shared.ui.tabsheet;
 
 import java.io.Serializable;
 
+import com.vaadin.shared.ui.ErrorLevel;
+
 /**
  * Shared state of a single tab in a Tabsheet or an Accordion.
  *
@@ -33,6 +35,7 @@ public class TabState implements Serializable {
     public String styleName;
     public String key;
     public String componentError;
+    public ErrorLevel componentErrorLevel;
     public String id;
     public String iconAltText;
 
index e9056ef17aeba2c448cac63c0d1484c973ad8795..32b2aec3bc8e47fa1a9ce379f498761cbb34ce54 100644 (file)
     }
   }
 
+  .#{$primary-stylename}-error-info {
+    .#{$primary-stylename}-input {
+      @include valo-textfield-error-level-info-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-info-color;
+      border-color: $v-error-indicator-level-info-color;
+    }
+  }
+
+  .#{$primary-stylename}-error-warning {
+    .#{$primary-stylename}-input {
+      @include valo-textfield-error-level-warning-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-warning-color;
+      border-color: $v-error-indicator-level-warning-color;
+    }
+  }
+
+  .#{$primary-stylename}-error-error {
+    .#{$primary-stylename}-input {
+      @include valo-textfield-error-level-error-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-error-color;
+      border-color: $v-error-indicator-level-error-color;
+    }
+  }
+
+  .#{$primary-stylename}-error-critical {
+    .#{$primary-stylename}-input {
+      @include valo-textfield-error-level-critical-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-critical-color;
+      border-color: $v-error-indicator-level-critical-color;
+    }
+  }
+
+  .#{$primary-stylename}-error-system {
+    .#{$primary-stylename}-input {
+      @include valo-textfield-error-level-system-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-system-color;
+      border-color: $v-error-indicator-level-system-color;
+    }
+  }
+
   .#{$primary-stylename}-suggestpopup {
     @include valo-combobox-popup-style;
   }
index 6ff8a70dbac2ca3ff91d22f4be91a40a2648f201..f5cb8154e82184d00e1bd7ae9658bb688e740b08 100644 (file)
     }
   }
 
+  .#{$primary-stylename}-error-info {
+    .#{$primary-stylename}-textfield {
+      @include valo-textfield-error-level-info-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-info-color;
+      border-color: $v-error-indicator-level-info-color;
+    }
+  }
+
+  .#{$primary-stylename}-error-warning {
+    .#{$primary-stylename}-textfield {
+      @include valo-textfield-error-level-warning-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-warning-color;
+      border-color: $v-error-indicator-level-warning-color;
+    }
+  }
+
+  .#{$primary-stylename}-error-error {
+    .#{$primary-stylename}-textfield {
+      @include valo-textfield-error-level-error-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-error-color;
+      border-color: $v-error-indicator-level-error-color;
+    }
+  }
+
+  .#{$primary-stylename}-error-critical {
+    .#{$primary-stylename}-textfield {
+      @include valo-textfield-error-level-critical-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-critical-color;
+      border-color: $v-error-indicator-level-critical-color;
+    }
+  }
+
+  .#{$primary-stylename}-error-system {
+    .#{$primary-stylename}-textfield {
+      @include valo-textfield-error-level-system-style;
+    }
+
+    .#{$primary-stylename}-button {
+      color: $v-error-indicator-level-system-color;
+      border-color: $v-error-indicator-level-system-color;
+    }
+  }
+
   // Different widths for different resolutions
   .#{$primary-stylename}-full {
     width: round($v-font-size * 15);
index 50cb7b80420927dd3a732efd34b26e3d7480827d..1b3552763d8f806ab0c0ed9c58e9478ecc868615 100644 (file)
@@ -70,6 +70,25 @@ $v-textfield-disabled-opacity: $v-disabled-opacity !default;
     @include valo-textfield-error-style;
   }
 
+  .#{$primary-stylename}-error-info {
+    @include valo-textfield-error-level-info-style;
+  }
+
+  .#{$primary-stylename}-error-warning {
+    @include valo-textfield-error-level-warning-style;
+  }
+
+  .#{$primary-stylename}-error-error {
+    @include valo-textfield-error-level-error-style;
+  }
+
+  .#{$primary-stylename}-error-critical {
+    @include valo-textfield-error-level-critical-style;
+  }
+
+  .#{$primary-stylename}-error-system {
+    @include valo-textfield-error-level-system-style;
+  }
 
   @if $include-additional-styles {
     .#{$primary-stylename}-borderless {
@@ -326,13 +345,58 @@ $v-textfield-disabled-opacity: $v-disabled-opacity !default;
  * 
  * @group textfield
  */
-@mixin valo-textfield-error-style {
-  border-color: $v-error-indicator-color !important;
-  $bg: scale-color($v-error-indicator-color, $lightness: 98%);
+@mixin valo-textfield-error-style($indicator-color: $v-error-indicator-color) {
+  border-color: $indicator-color !important;
+  $bg: scale-color($indicator-color, $lightness: 98%);
   background: $bg;
   color: valo-font-color($bg);
 }
 
+/**
+ * Outputs the styles for a text field error state with error level 'info'.
+ *
+ * @group textfield
+ */
+@mixin valo-textfield-error-level-info-style {
+  @include valo-textfield-error-style($v-error-indicator-level-info-color);
+}
+
+/**
+ * Outputs the styles for a text field error state with error level 'warning'.
+ *
+ * @group textfield
+ */
+@mixin valo-textfield-error-level-warning-style {
+  @include valo-textfield-error-style($v-error-indicator-level-warning-color);
+}
+
+/**
+ * Outputs the styles for a text field error state with error level 'error'.
+ *
+ * @group textfield
+ */
+@mixin valo-textfield-error-level-error-style {
+  @include valo-textfield-error-style($v-error-indicator-level-error-color);
+}
+
+/**
+ * Outputs the styles for a text field error state with error level 'critical'.
+ *
+ * @group textfield
+ */
+@mixin valo-textfield-error-level-critical-style {
+  @include valo-textfield-error-style($v-error-indicator-level-critical-color);
+}
+
+/**
+ * Outputs the styles for a text field error state with error level 'system'.
+ *
+ * @group textfield
+ */
+@mixin valo-textfield-error-level-system-style {
+  @include valo-textfield-error-style($v-error-indicator-level-system-color);
+}
+
 
 /**
  * Outputs the selectors and styles for an inline-icon style for a text field. Included indipendently (i.e. not enclosed with a parent text field selector). 
index 1d9a7e773edbc05b135b983e2b21165b62acfbd3..8d220292e7d28b069b0c4aaa624cd0a50ad7dee3 100644 (file)
     }
   }
 
+  .#{$primary-stylename}-error-info {
+    .#{$primary-stylename}-options,
+    .#{$primary-stylename}-selections {
+      @include valo-textfield-error-level-info-style;
+    }
+  }
+
+  .#{$primary-stylename}-error-warning {
+    .#{$primary-stylename}-options,
+    .#{$primary-stylename}-selections {
+      @include valo-textfield-error-level-warning-style;
+    }
+  }
+
+  .#{$primary-stylename}-error-error {
+    .#{$primary-stylename}-options,
+    .#{$primary-stylename}-selections {
+      @include valo-textfield-error-level-error-style;
+    }
+  }
+
+  .#{$primary-stylename}-error-critical {
+    .#{$primary-stylename}-options,
+    .#{$primary-stylename}-selections {
+      @include valo-textfield-error-level-critical-style;
+    }
+  }
+
+  .#{$primary-stylename}-error-system {
+    .#{$primary-stylename}-options,
+    .#{$primary-stylename}-selections {
+      @include valo-textfield-error-level-system-style;
+    }
+  }
 }
 
 
index 55de987120c44ff1cd6b883318f184a7117c57cd..c36864e6993f5ec17f6804e75a38e222e745a19f 100644 (file)
@@ -339,6 +339,26 @@ $valo-shared-pathPrefix: null;
     @include valo-error-indicator-style;
   }
 
+  .v-errorindicator-info {
+    @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-info-color);
+  }
+
+  .v-errorindicator-warning {
+    @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-warning-color);
+  }
+
+  .v-errorindicator-error {
+    @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-error-color);
+  }
+
+  .v-errorindicator-critical {
+    @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-critical-color);
+  }
+
+  .v-errorindicator-system {
+    @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-system-color);
+  }
+
   .v-required-field-indicator {
     color: $v-required-field-indicator-color;
     padding: 0 .2em;
@@ -400,8 +420,8 @@ $valo-shared-pathPrefix: null;
  *
  * @requires {mixin} valo-error-indicator-icon-style by default
  */
-@mixin valo-error-indicator-style ($is-pseudo-element: false) {
-  color: $v-error-indicator-color;
+@mixin valo-error-indicator-style ($is-pseudo-element: false, $indicator-color: $v-error-indicator-color) {
+  color: $indicator-color;
   font-weight: 600;
   width: ceil($v-unit-size/2);
   text-align: center;
index 3c9c91449945e9ae9252512ba1cebe3eed3a4b35..b8ab05351323c37b4e3ea9e322678822c38a3ab1 100644 (file)
@@ -62,6 +62,46 @@ $v-tooltip-error-message-background-color: #fff !default;
  */
 $v-tooltip-error-message-font-color: $v-error-indicator-color !default;
 
+/**
+ * The font color for error tooltips for level 'info'.
+ *
+ * @type color
+ * @group tooltip
+ */
+$v-tooltip-error-message-level-info-font-color: $v-error-indicator-level-info-color !default;
+
+/**
+ * The font color for error tooltips for level 'warning'.
+ *
+ * @type color
+ * @group tooltip
+ */
+$v-tooltip-error-message-level-warning-font-color: $v-error-indicator-level-warning-color !default;
+
+/**
+ * The font color for error tooltips for level 'error'.
+ *
+ * @type color
+ * @group tooltip
+ */
+$v-tooltip-error-message-level-error-font-color: $v-error-indicator-level-error-color !default;
+
+/**
+ * The font color for error tooltips for level 'critical'.
+ *
+ * @type color
+ * @group tooltip
+ */
+$v-tooltip-error-message-level-critical-font-color: $v-error-indicator-level-critical-color !default;
+
+/**
+ * The font color for error tooltips for level 'system'.
+ *
+ * @type color
+ * @group tooltip
+ */
+$v-tooltip-error-message-level-system-font-color: $v-error-indicator-level-system-color !default;
+
 /**
  * The corner radius for tooltips.
  *
@@ -100,6 +140,26 @@ $v-tooltip-border-radius: $v-border-radius - 1px !default;
       }
     }
 
+    .v-errormessage-info {
+      color: $v-tooltip-error-message-level-info-font-color;
+    }
+
+    .v-errormessage-warning {
+      color: $v-tooltip-error-message-level-warning-font-color;
+    }
+
+    .v-errormessage-error {
+      color: $v-tooltip-error-message-level-error-font-color;
+    }
+
+    .v-errormessage-critical {
+      color: $v-tooltip-error-message-level-critical-font-color;
+    }
+
+    .v-errormessage-system {
+      color: $v-tooltip-error-message-level-system-font-color;
+    }
+
     .v-tooltip-text {
       max-height: 10em;
       overflow: auto;
index 4634a71feae5de7d96f6a8f2eabb470294f1e760..8f1aaa257bbd42b7a01250da6f99e030fc9018b9 100644 (file)
@@ -206,6 +206,46 @@ $v-disabled-opacity: 0.5 !default;
  */
 $v-selection-color: $v-focus-color !default;
 
+/**
+ * Color of the component error indication for 'info' error level.
+
+ * @group color
+ * @type color
+ */
+$v-error-indicator-level-info-color: #00a7f5 !default;
+
+/**
+ * Color of the component error indication for 'warning' error level.
+
+ * @group color
+ * @type color
+ */
+$v-error-indicator-level-warning-color: #fc9c00 !default;
+
+/**
+ * Color of the component error indication for 'error' error level.
+
+ * @group color
+ * @type color
+ */
+$v-error-indicator-level-error-color: #ed473b !default;
+
+/**
+ * Color of the component error indication for 'critical' error level.
+
+ * @group color
+ * @type color
+ */
+$v-error-indicator-level-critical-color: #fa007d !default;
+
+/**
+ * Color of the component error indication for 'system' error level.
+
+ * @group color
+ * @type color
+ */
+$v-error-indicator-level-system-color: #bb00ff !default;
+
 /**
  * Color of the component error indicator and other error indications, such as the
  * error style notification.
@@ -213,7 +253,7 @@ $v-selection-color: $v-focus-color !default;
  * @group color
  * @type color
  */
-$v-error-indicator-color: #ed473b !default;
+$v-error-indicator-color: $v-error-indicator-level-error-color !default;
 
 /**
  * Color of the required indicator in field components.
diff --git a/uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java b/uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java
new file mode 100644 (file)
index 0000000..f4a25bd
--- /dev/null
@@ -0,0 +1,172 @@
+package com.vaadin.tests.components;
+
+import java.util.Arrays;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.data.Property;
+import com.vaadin.server.AbstractErrorMessage;
+import com.vaadin.server.ErrorMessage;
+import com.vaadin.server.ExternalResource;
+import com.vaadin.server.UserError;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Accordion;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.FormLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.TwinColSelect;
+import com.vaadin.ui.themes.ValoTheme;
+
+@Theme("valo")
+public class ErrorLevels extends AbstractTestUI {
+
+    private ComboBox errorLevels;
+    private Button button;
+    private Button borderlessButton;
+    private Link link;
+    private ComboBox comboBox;
+    private TextField textField;
+    private TextField textFieldBorderless;
+    private TabSheet tabSheet;
+    private Accordion accordion;
+    private CheckBox checkBox;
+    private NativeButton nativeButton;
+    private FormLayout formLayout;
+    private TextField formLayoutTextField;
+    private Panel panel;
+    private DateField dateField;
+    private TwinColSelect twinColSelect;
+
+    @Override
+    protected void setup(VaadinRequest request) {
+
+        errorLevels = new ComboBox("Error level",
+                Arrays.asList(ErrorMessage.ErrorLevel.values()));
+        errorLevels.setNullSelectionAllowed(false);
+        errorLevels.setValue(ErrorMessage.ErrorLevel.ERROR);
+        errorLevels.addValueChangeListener(new Property.ValueChangeListener() {
+            @Override
+            public void valueChange(Property.ValueChangeEvent event) {
+                setErrorMessages();
+            }
+        });
+        addComponent(errorLevels);
+
+        Label subtitle = new Label("Components");
+        subtitle.setStyleName(ValoTheme.LABEL_H3);
+        addComponent(subtitle);
+
+        // Button
+        button = new Button("Button");
+
+        borderlessButton = new Button("Borderless button");
+        borderlessButton.setStyleName(ValoTheme.BUTTON_BORDERLESS);
+
+        addComponent(new HorizontalLayout(button, borderlessButton));
+
+        // Native button
+        nativeButton = new NativeButton("Native button");
+        addComponent(nativeButton);
+
+        // Link
+        link = new Link("Link", new ExternalResource("#"));
+        addComponent(link);
+
+        // Combo box
+        comboBox = new ComboBox("Combo box");
+        addComponent(comboBox);
+
+        // Text field
+        textField = new TextField("Text field");
+        textField.setValue("text");
+
+        textFieldBorderless = new TextField("Borderless text field");
+        textFieldBorderless.setStyleName(ValoTheme.TEXTFIELD_BORDERLESS);
+        textFieldBorderless.setValue("text");
+
+        addComponent(new HorizontalLayout(textField, textFieldBorderless));
+
+        // Date field
+        dateField = new DateField("Date field");
+        addComponent(dateField);
+
+        // Check box
+        checkBox = new CheckBox("Check box");
+        addComponent(checkBox);
+
+        // Tab sheet
+        tabSheet = new TabSheet();
+        tabSheet.addTab(new Label("Label1"), "Tab1");
+        tabSheet.addTab(new Label("Label2"), "Tab2");
+        tabSheet.setWidth("400px");
+        addComponent(tabSheet);
+
+        // Accordion
+        accordion = new Accordion();
+        accordion.addTab(new Label("Label1"), "Tab1");
+        accordion.addTab(new Label("Label2"), "Tab2");
+        accordion.setWidth("400px");
+        addComponent(accordion);
+
+        // Form layout
+        formLayout = new FormLayout();
+        formLayout.setWidth("400px");
+
+        formLayoutTextField = new TextField("Form layout text field");
+        formLayout.addComponent(formLayoutTextField);
+
+        addComponent(formLayout);
+
+        // Panel
+        panel = new Panel();
+        panel.setContent(new Label("Panel"));
+        panel.setWidth("400px");
+        addComponent(panel);
+
+        // TwinColSelect
+        twinColSelect = new TwinColSelect("Twin col select");
+        addComponent(twinColSelect);
+
+        setErrorMessages();
+
+        getLayout().setSpacing(true);
+    }
+
+    private void setErrorMessages() {
+        button.setComponentError(createErrorMessage("Button error"));
+        borderlessButton.setComponentError(
+                createErrorMessage("Borderless button error"));
+        link.setComponentError(createErrorMessage("Link error"));
+        comboBox.setComponentError(createErrorMessage("ComboBox error"));
+        textField.setComponentError(createErrorMessage("Text field error"));
+        textFieldBorderless.setComponentError(
+                createErrorMessage("Borderless text field error"));
+        tabSheet.setComponentError(createErrorMessage("Tab sheet error"));
+        tabSheet.getTab(0).setComponentError(createErrorMessage("Tab error"));
+        accordion.setComponentError(createErrorMessage("Accordion error"));
+        accordion.getTab(0).setComponentError(createErrorMessage("Tab error"));
+        checkBox.setComponentError(createErrorMessage("Check box error"));
+        nativeButton
+                .setComponentError(createErrorMessage("Native button error"));
+        formLayout.setComponentError(createErrorMessage("Form layout error"));
+        formLayoutTextField.setComponentError(
+                createErrorMessage("Form layout text field error"));
+        panel.setComponentError(createErrorMessage("Panel error"));
+        dateField.setComponentError(createErrorMessage("Date field error"));
+        twinColSelect.setComponentError(createErrorMessage("Twin col select error"));
+    }
+
+    private ErrorMessage createErrorMessage(String text) {
+        return new UserError(text, AbstractErrorMessage.ContentMode.TEXT,
+                (ErrorMessage.ErrorLevel) errorLevels.getValue());
+    }
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java b/uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java
new file mode 100644 (file)
index 0000000..adf0b1a
--- /dev/null
@@ -0,0 +1,161 @@
+package com.vaadin.tests.components;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.client.StyleConstants;
+import com.vaadin.shared.ui.ErrorLevel;
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.AccordionElement;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.CheckBoxElement;
+import com.vaadin.testbench.elements.DateFieldElement;
+import com.vaadin.testbench.elements.FormLayoutElement;
+import com.vaadin.testbench.elements.LinkElement;
+import com.vaadin.testbench.elements.NativeButtonElement;
+import com.vaadin.testbench.elements.PanelElement;
+import com.vaadin.testbench.elements.TabSheetElement;
+import com.vaadin.testbench.elements.TwinColSelectElement;
+import com.vaadin.testbench.parallel.BrowserUtil;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+import com.vaadin.tests.tb3.newelements.ComboBoxElement;
+
+public class ErrorLevelsTest extends SingleBrowserTest {
+
+    private ComboBoxElement errorLevelSelector;
+
+    @Override
+    public void setup() throws Exception {
+        super.setup();
+        openTestURL();
+
+        errorLevelSelector = $(ComboBoxElement.class).first();
+    }
+
+    @Test
+    public void testErrorIndicatorsClassName() {
+        ErrorLevel errorLevel = ErrorLevel.WARNING;
+        selectErrorLevel(errorLevel);
+
+        List<WebElement> errorIndicators = findElements(
+                By.className(StyleConstants.STYLE_NAME_ERROR_INDICATOR));
+        for (WebElement errorIndicator : errorIndicators) {
+            assertHasRightClassNames(errorIndicator,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR,
+                    errorLevel);
+        }
+    }
+
+    @Test
+    public void testComponentsClassName() {
+        ErrorLevel errorLevel = ErrorLevel.WARNING;
+        selectErrorLevel(errorLevel);
+
+        // Button
+        ButtonElement buttonElement = $(ButtonElement.class).first();
+        assertHasRightClassNames(buttonElement, "v-button-error", errorLevel);
+
+        // Native button
+        NativeButtonElement nativeButtonElement = $(NativeButtonElement.class)
+                .first();
+        assertHasRightClassNames(nativeButtonElement, "v-nativebutton-error",
+                errorLevel);
+
+        // Link
+        LinkElement linkElement = $(LinkElement.class).first();
+        assertHasRightClassNames(linkElement, "v-link-error", errorLevel);
+
+        // Combo box
+        ComboBoxElement comboBoxElement = $(ComboBoxElement.class).get(1);
+        assertHasRightClassNames(comboBoxElement, "v-filterselect-error",
+                errorLevel);
+
+        // Date field
+        DateFieldElement dateFieldElement = $(DateFieldElement.class).first();
+        assertHasRightClassNames(dateFieldElement, "v-datefield-error",
+                errorLevel);
+
+        // Checkbox
+        CheckBoxElement checkBoxElement = $(CheckBoxElement.class).first();
+        assertHasRightClassNames(checkBoxElement, "v-checkbox-error",
+                errorLevel);
+
+        // Tab sheet
+        TabSheetElement tabSheetElement = $(TabSheetElement.class).first();
+        assertHasRightClassNames(tabSheetElement, "v-tabsheet-error",
+                errorLevel);
+
+        // Accordion
+        AccordionElement accordionElement = $(AccordionElement.class).first();
+        assertHasRightClassNames(accordionElement, "v-accordion-error",
+                errorLevel);
+
+        // Form layout
+        FormLayoutElement formLayoutElement = $(FormLayoutElement.class)
+                .first();
+        assertHasRightClassNames(formLayoutElement, "v-formlayout-error",
+                errorLevel);
+
+        // Panel
+        PanelElement panelElement = $(PanelElement.class).first();
+        assertHasRightClassNames(panelElement, "v-panel-error", errorLevel);
+
+        // Twin col select
+        TwinColSelectElement twinColSelectElement = $(
+                TwinColSelectElement.class).first();
+        assertHasRightClassNames(twinColSelectElement, "v-select-twincol-error",
+                errorLevel);
+    }
+
+    private void assertHasRightClassNames(WebElement element, String prefix,
+            ErrorLevel errorLevel) {
+        Assert.assertTrue("Element must have only one error level class name",
+                containsCorrectErrorLevelClassNameOnly(element, prefix,
+                        errorLevel));
+    }
+
+    private boolean containsCorrectErrorLevelClassNameOnly(WebElement element,
+            String prefix, ErrorLevel errorLevel) {
+        List<String> classNames = new ArrayList<String>(
+                Arrays.asList(element.getAttribute("class").split(" ")));
+        classNames.retainAll(getErrorLevelClassNames(prefix,
+                Arrays.asList(ErrorLevel.values())));
+        return classNames.size() == 1 && classNames
+                .contains(getErrorLevelClassName(prefix, errorLevel));
+    }
+
+    private String getErrorLevelClassName(String prefix,
+            ErrorLevel errorLevel) {
+        return prefix + "-" + errorLevel.toString().toLowerCase();
+    }
+
+    private List<String> getErrorLevelClassNames(String prefix,
+            Collection<ErrorLevel> errorLevels) {
+        List<String> classNames = new ArrayList<String>(errorLevels.size());
+        for (ErrorLevel errorLevel : errorLevels) {
+            classNames.add(getErrorLevelClassName(prefix, errorLevel));
+        }
+        return classNames;
+    }
+
+    private void selectErrorLevel(ErrorLevel errorLevel) {
+        errorLevelSelector.clear();
+        errorLevelSelector.sendKeys(errorLevel.toString().toLowerCase());
+        errorLevelSelector.sendKeys(getReturn());
+    }
+
+    private Keys getReturn() {
+        if (BrowserUtil.isPhantomJS(getDesiredCapabilities())) {
+            return Keys.ENTER;
+        } else {
+            return Keys.RETURN;
+        }
+    }
+}
index 2e15c5bfaae18335627137f83204ffd283c7d4dc..89e06b3b28032ed659e2dc86204168a47c71221a 100644 (file)
@@ -84,8 +84,8 @@ public class TabSheetErrorTooltipTest extends MultiBrowserTest {
     }
 
     private WebElement getCurrentErrorMessage() {
-        return getDriver()
-                .findElement(By.xpath("//div[@class='v-errormessage']"));
+        return getDriver().findElement(
+                By.xpath("//div[contains(@class, 'v-errormessage')]"));
     }
 
     private void assertTooltip(String tooltip) {