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

Vaadin 8 implementation of #9816. Cherry picked changes and added compatibility package component changes and tests.

Resolves #3139

55 files changed:
all/src/main/templates/release-notes.html
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/HasErrorIndicatorElement.java [new file with mode: 0644]
client/src/main/java/com/vaadin/client/ui/VAccordion.java
client/src/main/java/com/vaadin/client/ui/VButton.java
client/src/main/java/com/vaadin/client/ui/VCheckBox.java
client/src/main/java/com/vaadin/client/ui/VFormLayout.java
client/src/main/java/com/vaadin/client/ui/VLink.java
client/src/main/java/com/vaadin/client/ui/VNativeButton.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/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
compatibility-client/src/main/java/com/vaadin/v7/client/ui/checkbox/CheckBoxConnector.java
compatibility-client/src/main/java/com/vaadin/v7/client/ui/form/FormConnector.java
compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java
compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java
compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java
compatibility-server/src/test/java/com/vaadin/v7/ui/AbstractLegacyComponentDeclarativeTest.java
server/src/main/java/com/vaadin/server/AbstractErrorMessage.java
server/src/main/java/com/vaadin/server/CompositeErrorMessage.java
server/src/main/java/com/vaadin/server/ErrorMessage.java
server/src/main/java/com/vaadin/server/SystemError.java
server/src/main/java/com/vaadin/server/UserError.java
server/src/main/java/com/vaadin/ui/AbstractComponent.java
server/src/main/java/com/vaadin/ui/TabSheet.java
server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTest.java
server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTestBase.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
tests/screenshots
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/main/java/com/vaadin/tests/themes/valo/CommonParts.java
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 fab73eff2a7aa6c87a2a5f6bb16ae86d17f4f5a5..7087b6c46c52fde8f6174e3472cd2d86a5eeccef 100644 (file)
         <li><tt>DataCommunicator</tt> method <tt>getDataProviderSize</tt> is now <tt>public</tt>, not <tt>protected</tt>.</li>
         <li><tt>Binder</tt> method <tt>getBindings</tt> now returns a Collection, not a Set.</li>
         <li><tt>BindingBuilder</tt> now works like a proper builder. Adding a converter will not mark Binding as <tt>bound</tt> allowing chaining to the same object.</li>
+        <li><tt>ErrorLevel</tt> is removed from <tt>ErrorMessage</tt> and now <tt>com.vaadin.shared.ui.ErrorLevel</tt> should be used.</li>
+        <li>Error indicators are now <tt>&lt;span class="v-errorindicator"&gt;&lt;/span&gt;</tt> elements.</li>
 
         <h2>For incompatible or behaviour-altering changes in 8.1, please see <a href="https://vaadin.com/download/release/8.1/8.1.0/release-notes.html#incompatible">8.1 release notes</a></h2>
         
index 3b587ce23355f5f2919685d6349ab2567695c349..13549b49387b18419d83ec04c7719831698ccc40 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 a84e45e988a448407ed6e4f7f355f766758a03e6..1f01dab811eece070c36a1a50a3ef99012cc1afd 100644 (file)
 package com.vaadin.client;
 
 import com.vaadin.shared.ui.ContentMode;
+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;
@@ -26,14 +31,25 @@ public class TooltipInfo {
 
     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) {
         this(tooltip, ContentMode.PREFORMATTED);
     }
@@ -41,12 +57,12 @@ public class TooltipInfo {
     /**
      * Constructs a new instance using the {@code tooltip} for the title and
      * {@code errorMessage} as a description.
-     * 
+     *
      * @param tooltip
      *            tooltip title
      * @param errorMessage
      *            error description
-     * 
+     *
      * @deprecated use {@link #TooltipInfo(String, ContentMode, String)} instead
      */
     @Deprecated
@@ -57,13 +73,14 @@ public class TooltipInfo {
     /**
      * Constructs a new instance using the {@code tooltip} for the title,
      * {@code errorMessage} as a description and {@code identifier} as its id.
-     * 
+     *
      * @param tooltip
      *            tooltip title
      * @param errorMessage
      *            error description
      * @param identifier
-     * 
+     *            the tooltip's identifier
+     *
      * @deprecated use {@link #TooltipInfo(String, ContentMode, String, Object)}
      *             instead
      */
@@ -72,55 +89,194 @@ public class TooltipInfo {
         this(tooltip, ContentMode.HTML, errorMessage, identifier);
     }
 
+    /**
+     * Constructs a new instance using the {@code tooltip} for the title,
+     * {@code errorMessage} as a description, {@code identifier} as its id and
+     * {@code errorLevel} as the error level.
+     *
+     * @param tooltip
+     *            tooltip title
+     * @param errorMessage
+     *            error description
+     * @param identifier
+     *            the tooltip's identifier
+     * @param errorLevel
+     *            error level
+     *
+     * @deprecated use {@link #TooltipInfo(String, ContentMode, String, Object,
+     *             ErrorLevel)} instead
+     * @since 8.2
+     */
+    @Deprecated
+    public TooltipInfo(String tooltip, String errorMessage, Object identifier,
+            ErrorLevel errorLevel) {
+        this(tooltip, ContentMode.HTML, errorMessage, identifier, errorLevel);
+    }
+
+    /**
+     * Constructs a new tooltip info instance.
+     *
+     * @param tooltip
+     *         tooltip title
+     * @param mode
+     *         content mode
+     */
     public TooltipInfo(String tooltip, ContentMode mode) {
         setTitle(tooltip);
         setContentMode(mode);
     }
 
+    /**
+     * Constructs a new tooltip info instance.
+     *
+     * @param tooltip
+     *         tooltip title
+     * @param mode
+     *         content mode
+     * @param errorMessage
+     *         error message
+     */
     public TooltipInfo(String tooltip, ContentMode mode, String errorMessage) {
         this(tooltip, mode, errorMessage, null);
     }
 
+    /**
+     * Constructs a new tooltip info instance.
+     *
+     * @param tooltip
+     *         tooltip title
+     * @param mode
+     *         content mode
+     * @param errorMessage
+     *         error message
+     * @param identifier
+     *         the tooltip's identifier
+     */
     public TooltipInfo(String tooltip, ContentMode mode, String errorMessage,
             Object identifier) {
+        this(tooltip, mode, errorMessage, identifier, null);
+    }
+
+    /**
+     * Constructs a new tooltip info instance.
+     *
+     * @param tooltip
+     *         tooltip title
+     * @param mode
+     *         content mode
+     * @param errorMessage
+     *         error message
+     * @param identifier
+     *         the tooltip's identifier
+     * @param errorLevel
+     *         error level
+     */
+    public TooltipInfo(String tooltip, ContentMode mode, String errorMessage,
+            Object identifier, ErrorLevel errorLevel) {
         setIdentifier(identifier);
         setTitle(tooltip);
         setContentMode(mode);
         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 tooltip title's content mode.
+     *
+     * @return the content mode
+     */
     public ContentMode getContentMode() {
         return contentMode;
     }
 
+    /**
+     * Sets the tooltip title's content mode.
+     *
+     * @param contentMode
+     *         the content mode to set
+     */
     public void setContentMode(ContentMode contentMode) {
         this.contentMode = contentMode;
     }
 
+    /**
+     * Gets the error level.
+     *
+     * @return the error level
+     * @since
+     */
+    public ErrorLevel getErrorLevel() {
+        return errorLevel;
+    }
+
+    /**
+     * Sets the error level.
+     *
+     * @param errorLevel
+     *         the error level to set
+     * @since
+     */
+    public void setErrorLevel(ErrorLevel errorLevel) {
+        this.errorLevel = errorLevel;
+    }
+
     /**
      * Checks is a message has been defined for the tooltip.
      *
@@ -132,9 +288,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 1bff175d7e713e5bec5531628a4fe416c29f6ec9..f7d7d55ffe954b833968042e0fd54ddaf3eef6c3 100644 (file)
@@ -25,8 +25,10 @@ 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.HasErrorIndicator;
+import com.vaadin.client.ui.HasErrorIndicatorElement;
 import com.vaadin.client.ui.HasRequiredIndicator;
 import com.vaadin.client.ui.Icon;
 import com.vaadin.client.ui.ImageIcon;
@@ -34,8 +36,9 @@ 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;
 
-public class VCaption extends HTML {
+public class VCaption extends HTML implements HasErrorIndicatorElement {
 
     public static final String CLASSNAME = "v-caption";
 
@@ -259,23 +262,17 @@ public class VCaption extends HTML {
         AriaHelper.handleInputInvalid(owner.getWidget(), showError);
 
         if (showError) {
-            if (errorIndicatorElement == null) {
-                errorIndicatorElement = DOM.createDiv();
-                DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
-                DOM.setElementProperty(errorIndicatorElement, "className",
-                        "v-errorindicator");
+            setErrorIndicatorElementVisible(true);
 
-                DOM.insertChild(getElement(), errorIndicatorElement,
-                        getInsertPosition(InsertPosition.ERROR));
+            // Hide error indicator from assistive devices
+            Roles.getTextboxRole()
+                    .setAriaHiddenState(errorIndicatorElement, true);
 
-                // Hide error indicator from assistive devices
-                Roles.getTextboxRole().setAriaHiddenState(errorIndicatorElement,
-                        true);
-            }
-        } else if (errorIndicatorElement != null) {
-            // Remove existing
-            getElement().removeChild(errorIndicatorElement);
-            errorIndicatorElement = null;
+            ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR,
+                    owner.getState().errorLevel);
+        } else {
+            setErrorIndicatorElementVisible(false);
         }
 
         return (wasPlacedAfterComponent != placedAfterComponent);
@@ -322,6 +319,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
@@ -401,19 +406,11 @@ public class VCaption extends HTML {
         }
 
         if (hasError) {
-            if (errorIndicatorElement == null) {
-                errorIndicatorElement = DOM.createDiv();
-                DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
-                DOM.setElementProperty(errorIndicatorElement, "className",
-                        "v-errorindicator");
-
-                DOM.insertChild(getElement(), errorIndicatorElement,
-                        getInsertPosition(InsertPosition.ERROR));
-            }
-        } else if (errorIndicatorElement != null) {
-            // Remove existing
-            getElement().removeChild(errorIndicatorElement);
-            errorIndicatorElement = null;
+            setErrorIndicatorElementVisible(true);
+            ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel);
+        } else {
+            setErrorIndicatorElementVisible(false);
         }
 
         return (wasPlacedAfterComponent != placedAfterComponent);
@@ -775,4 +772,23 @@ public class VCaption extends HTML {
     private static Logger getLogger() {
         return Logger.getLogger(VCaption.class.getName());
     }
+
+    @Override
+    public Element getErrorIndicatorElement() {
+        return errorIndicatorElement;
+    }
+
+    @Override
+    public void setErrorIndicatorElementVisible(boolean visible) {
+        if (visible) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = ErrorUtil.createErrorIndicatorElement();
+                DOM.insertChild(getElement(), errorIndicatorElement,
+                        getInsertPosition(InsertPosition.ERROR));
+            }
+        } else if (errorIndicatorElement != null) {
+            getElement().removeChild(errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+    }
 }
index 0baa1baff1864e3947d15d4b314792bea43aa3c8..7caffa1275f49bf987a9dd61b1e87693293de0df 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 74da680c66f5d5b11e247610789cc8bf5b839347..84647abf9a8f889122fb34cb5ba621ff12216eac 100644 (file)
@@ -138,6 +138,7 @@ public class VTooltip extends VOverlay {
                 && !info.getErrorMessage().isEmpty()) {
             em.setVisible(true);
             em.updateMessage(info.getErrorMessage());
+            em.updateErrorLevel(info.getErrorLevel());
         } else {
             em.setVisible(false);
         }
@@ -459,6 +460,7 @@ public class VTooltip extends VOverlay {
     @Override
     public void hide() {
         em.updateMessage("");
+        em.updateErrorLevel(null);
         description.setHTML("");
 
         updatePosition(null, true);
index 0aced86b0382f17f0a354613d1264113a88c5d30..fed9320edc2586253b7ff508f50f7b0a5829fcd2 100644 (file)
@@ -44,6 +44,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;
 
 /**
@@ -790,7 +791,7 @@ public class WidgetUtil {
             com.google.gwt.dom.client.Element el, String p)
     /*-{
         try {
-    
+
         if (el.currentStyle) {
             // IE
             return el.currentStyle[p];
@@ -805,7 +806,7 @@ public class WidgetUtil {
         } catch (e) {
             return "";
         }
-    
+
      }-*/;
 
     /**
@@ -819,7 +820,7 @@ public class WidgetUtil {
         try {
             el.focus();
         } catch (e) {
-    
+
         }
     }-*/;
 
@@ -1172,7 +1173,7 @@ public class WidgetUtil {
        if ($wnd.document.activeElement) {
            return $wnd.document.activeElement;
        }
-    
+
        return null;
      }-*/;
 
@@ -1243,11 +1244,11 @@ public class WidgetUtil {
     /*-{
         var top = elem.offsetTop;
         var height = elem.offsetHeight;
-    
+
         if (elem.parentNode != elem.offsetParent) {
           top -= elem.parentNode.offsetTop;
         }
-    
+
         var cur = elem.parentNode;
         while (cur && (cur.nodeType == 1)) {
           if (top < cur.scrollTop) {
@@ -1256,12 +1257,12 @@ public class WidgetUtil {
           if (top + height > cur.scrollTop + cur.clientHeight) {
             cur.scrollTop = (top + height) - cur.clientHeight;
           }
-    
+
           var offsetTop = cur.offsetTop;
           if (cur.parentNode != cur.offsetParent) {
             offsetTop -= cur.parentNode.offsetTop;
           }
-    
+
           top += offsetTop - cur.scrollTop;
           cur = cur.parentNode;
         }
@@ -1710,7 +1711,7 @@ public class WidgetUtil {
             }
             var heightWithoutBorder = cloneElement.offsetHeight;
             parentElement.removeChild(cloneElement);
-    
+
             return heightWithBorder - heightWithoutBorder;
         }
     }-*/;
@@ -1866,4 +1867,48 @@ public class WidgetUtil {
         int relativeTop = element.getAbsoluteTop() - Window.getScrollTop();
         return WidgetUtil.getTouchOrMouseClientY(event) - relativeTop;
     }
+
+    /**
+     * Utility methods for displaying error message on components.
+     *
+     * @since 8.2
+     */
+    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);
+                }
+            }
+        }
+
+        /**
+         * Creates an element to use by widgets as an error indicator.
+         *
+         * @return the error indicator element
+         */
+        public static Element createErrorIndicatorElement() {
+            Element indicator = DOM.createSpan();
+            indicator.setClassName(StyleConstants.STYLE_NAME_ERROR_INDICATOR);
+            return indicator;
+        }
+    }
 }
index 7ce3e5c9b744ccbb1ac45cea3ec8b5e2e30d819c..d3b595b55a2e3798a3358dc96c920b5e784b96c3 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.extensions.DragSourceExtensionConnector;
@@ -489,6 +490,27 @@ public abstract class AbstractComponentConnector extends AbstractConnector
         Profiler.leave("AbstractComponentConnector.onStateChanged");
     }
 
+    @OnStateChange({"errorMessage", "errorLevel"})
+    private void setErrorLevel() {
+        // Add or remove the widget's error level style name
+        ErrorUtil.setErrorLevelStyle(getWidget().getElement(),
+                getWidget().getStylePrimaryName() + StyleConstants.ERROR_EXT,
+                getState().errorLevel);
+
+        // Add or remove error indicator element
+        if (getWidget() instanceof HasErrorIndicatorElement) {
+            HasErrorIndicatorElement widget = (HasErrorIndicatorElement) getWidget();
+            if (getState().errorMessage != null) {
+                widget.setErrorIndicatorElementVisible(true);
+                ErrorUtil.setErrorLevelStyle(widget.getErrorIndicatorElement(),
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR,
+                        getState().errorLevel);
+            } else {
+                widget.setErrorIndicatorElementVisible(false);
+            }
+        }
+    }
+
     @Override
     public void setWidgetEnabled(boolean widgetEnabled) {
         // add or remove v-disabled style name from the widget
@@ -764,7 +786,8 @@ public abstract class AbstractComponentConnector extends AbstractConnector
     @Override
     public TooltipInfo getTooltipInfo(Element element) {
         return new TooltipInfo(getState().description,
-                getState().descriptionContentMode, getState().errorMessage);
+                getState().descriptionContentMode, getState().errorMessage,
+                null, getState().errorLevel);
     }
 
     @Override
diff --git a/client/src/main/java/com/vaadin/client/ui/HasErrorIndicatorElement.java b/client/src/main/java/com/vaadin/client/ui/HasErrorIndicatorElement.java
new file mode 100644 (file)
index 0000000..8ee0e5e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2016 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.client.ui;
+
+import com.google.gwt.dom.client.Element;
+
+/**
+ * Implemented by widgets supporting an error indicator.
+ *
+ * @since 8.2
+ */
+public interface HasErrorIndicatorElement {
+
+    /**
+     * Gets the error indicator element.
+     *
+     * @return the error indicator element
+     */
+    Element getErrorIndicatorElement();
+
+    /**
+     * Sets the visibility of the error indicator element.
+     *
+     * @param visible
+     *         {@code true} to show the error indicator element, {@code false}
+     *         to hide it
+     */
+    void setErrorIndicatorElementVisible(boolean visible);
+}
index 16c16935d0c998f775f74232d4a6b16434e9ef98..642c647a621556f10c0c1dd92717e3182773c371 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 0e738032b53939bd6f08554ecbaa50ed5c2471b1..725931008e3a2e84fb47d275a5aabfc96e38b6c3 100644 (file)
@@ -30,8 +30,10 @@ import com.vaadin.client.ApplicationConnection;
 import com.vaadin.client.BrowserInfo;
 import com.vaadin.client.Util;
 import com.vaadin.client.WidgetUtil;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 
-public class VButton extends FocusWidget implements ClickHandler {
+public class VButton extends FocusWidget implements ClickHandler,
+        HasErrorIndicatorElement {
 
     public static final String CLASSNAME = "v-button";
     private static final String CLASSNAME_PRESSED = "v-pressed";
@@ -48,7 +50,7 @@ public class VButton extends FocusWidget implements ClickHandler {
     public final Element wrapper = DOM.createSpan();
 
     /** For internal use only. May be removed or replaced in the future. */
-    public Element errorIndicatorElement;
+    private Element errorIndicatorElement;
 
     /** For internal use only. May be removed or replaced in the future. */
     public final Element captionElement = DOM.createSpan();
@@ -481,4 +483,21 @@ public class VButton extends FocusWidget implements ClickHandler {
         return ret;
     }-*/;
 
+    @Override
+    public Element getErrorIndicatorElement() {
+        return errorIndicatorElement;
+    }
+
+    @Override
+    public void setErrorIndicatorElementVisible(boolean visible) {
+        if (visible) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = ErrorUtil.createErrorIndicatorElement();
+                wrapper.insertFirst(errorIndicatorElement);
+            }
+        } else if (errorIndicatorElement != null) {
+            wrapper.removeChild(errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+    }
 }
index b2f78dce31b9ff1b444b0806349c0d392f261990..18140c203d1140552f750282c43d7dce10555410 100644 (file)
@@ -25,12 +25,14 @@ import com.vaadin.client.ApplicationConnection;
 import com.vaadin.client.BrowserInfo;
 import com.vaadin.client.Util;
 import com.vaadin.client.VTooltip;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.client.ui.aria.AriaHelper;
 import com.vaadin.client.ui.aria.HandlesAriaInvalid;
 import com.vaadin.client.ui.aria.HandlesAriaRequired;
 
 public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox
-        implements Field, HandlesAriaInvalid, HandlesAriaRequired {
+        implements Field, HandlesAriaInvalid, HandlesAriaRequired,
+        HasErrorIndicatorElement {
 
     public static final String CLASSNAME = "v-checkbox";
 
@@ -41,7 +43,7 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox
     public ApplicationConnection client;
 
     /** For internal use only. May be removed or replaced in the future. */
-    public Element errorIndicatorElement;
+    private Element errorIndicatorElement;
 
     /** For internal use only. May be removed or replaced in the future. */
     public Icon icon;
@@ -101,4 +103,24 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox
     public void setAriaInvalid(boolean invalid) {
         AriaHelper.handleInputInvalid(getCheckBoxElement(), invalid);
     }
+
+    @Override
+    public Element getErrorIndicatorElement() {
+        return errorIndicatorElement;
+    }
+
+    @Override
+    public void setErrorIndicatorElementVisible(boolean visible) {
+        if (visible) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = ErrorUtil.createErrorIndicatorElement();
+                getElement().appendChild(errorIndicatorElement);
+                DOM.sinkEvents(errorIndicatorElement,
+                        VTooltip.TOOLTIP_EVENTS | Event.ONCLICK);
+            }
+        } else if (errorIndicatorElement != null) {
+            getElement().removeChild(errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+    }
 }
index a8a43a2d8d1566d7ffc88e918c6eca8b36ec9904..5704dc497de2b984012c3804138ce438e182c7ed 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);
             }
 
         }
@@ -340,7 +342,7 @@ public class VFormLayout extends SimplePanel {
     }
 
     /** For internal use only. May be removed or replaced in the future. */
-    public class ErrorFlag extends HTML {
+    public class ErrorFlag extends HTML implements HasErrorIndicatorElement {
         private static final String CLASSNAME = VFormLayout.CLASSNAME
                 + "-error-indicator";
         Element errorIndicatorElement;
@@ -361,7 +363,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;
@@ -370,24 +373,37 @@ public class VFormLayout extends SimplePanel {
             AriaHelper.handleInputInvalid(owner.getWidget(), showError);
 
             if (showError) {
-                if (errorIndicatorElement == null) {
-                    errorIndicatorElement = DOM.createDiv();
-                    DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
-                    DOM.setElementProperty(errorIndicatorElement, "className",
-                            "v-errorindicator");
-                    DOM.appendChild(getElement(), errorIndicatorElement);
+                setErrorIndicatorElementVisible(true);
 
-                    // Hide the error indicator from screen reader, as this
-                    // information is set directly at the input field
-                    Roles.getFormRole()
-                            .setAriaHiddenState(errorIndicatorElement, true);
-                }
+                // Hide the error indicator from screen reader, as this
+                // information is set directly at the input field
+                Roles.getFormRole()
+                        .setAriaHiddenState(errorIndicatorElement, true);
+
+                ErrorUtil.setErrorLevelStyle(errorIndicatorElement,
+                        StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel);
+            } else {
+                setErrorIndicatorElementVisible(false);
+            }
+        }
+
+        @Override
+        public Element getErrorIndicatorElement() {
+            return errorIndicatorElement;
+        }
 
+        @Override
+        public void setErrorIndicatorElementVisible(boolean visible) {
+            if (visible) {
+                if (errorIndicatorElement == null) {
+                    errorIndicatorElement = ErrorUtil
+                            .createErrorIndicatorElement();
+                    getElement().appendChild(errorIndicatorElement);
+                }
             } else if (errorIndicatorElement != null) {
-                DOM.removeChild(getElement(), errorIndicatorElement);
+                getElement().removeChild(errorIndicatorElement);
                 errorIndicatorElement = null;
             }
         }
-
     }
 }
index 84aac0f17e3f20e951fd451d058bafde0eae1120..28e262b1102c034a0b41e34f1a0976b29e504bd5 100644 (file)
@@ -25,9 +25,11 @@ import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.HasEnabled;
 import com.vaadin.client.Util;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.shared.ui.BorderStyle;
 
-public class VLink extends HTML implements ClickHandler, HasEnabled {
+public class VLink extends HTML implements ClickHandler, HasEnabled,
+        HasErrorIndicatorElement {
 
     public static final String CLASSNAME = "v-link";
 
@@ -59,7 +61,7 @@ public class VLink extends HTML implements ClickHandler, HasEnabled {
     public int targetHeight;
 
     /** For internal use only. May be removed or replaced in the future. */
-    public Element errorIndicatorElement;
+    private Element errorIndicatorElement;
 
     /** For internal use only. May be removed or replaced in the future. */
     public final Element anchor = DOM.createAnchor();
@@ -145,4 +147,21 @@ public class VLink extends HTML implements ClickHandler, HasEnabled {
         this.enabled = enabled;
     }
 
+    @Override
+    public Element getErrorIndicatorElement() {
+        return errorIndicatorElement;
+    }
+
+    @Override
+    public void setErrorIndicatorElementVisible(boolean visible) {
+        if (visible) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = ErrorUtil.createErrorIndicatorElement();
+                getElement().insertFirst(errorIndicatorElement);
+            }
+        } else if (errorIndicatorElement != null) {
+            getElement().removeChild(errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+    }
 }
index ec95a287559ec3f735312d04007de1e0db2f6ec0..db8e820b829d57cdc3ea1932b00e866994845c77 100644 (file)
@@ -27,10 +27,12 @@ import com.vaadin.client.BrowserInfo;
 import com.vaadin.client.MouseEventDetailsBuilder;
 import com.vaadin.client.StyleConstants;
 import com.vaadin.client.Util;
+import com.vaadin.client.WidgetUtil.ErrorUtil;
 import com.vaadin.shared.MouseEventDetails;
 import com.vaadin.shared.ui.button.ButtonServerRpc;
 
-public class VNativeButton extends Button implements ClickHandler {
+public class VNativeButton extends Button implements ClickHandler,
+        HasErrorIndicatorElement {
 
     public static final String CLASSNAME = "v-nativebutton";
 
@@ -44,7 +46,7 @@ public class VNativeButton extends Button implements ClickHandler {
     public ButtonServerRpc buttonRpcProxy;
 
     /** For internal use only. May be removed or replaced in the future. */
-    public Element errorIndicatorElement;
+    private Element errorIndicatorElement;
 
     /** For internal use only. May be removed or replaced in the future. */
     public final Element captionElement = DOM.createSpan();
@@ -159,4 +161,22 @@ public class VNativeButton extends Button implements ClickHandler {
         clickPending = false;
     }
 
+    @Override
+    public Element getErrorIndicatorElement() {
+        return errorIndicatorElement;
+    }
+
+    @Override
+    public void setErrorIndicatorElementVisible(boolean visible) {
+        if (visible) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = ErrorUtil.createErrorIndicatorElement();
+                getElement()
+                        .insertBefore(errorIndicatorElement, captionElement);
+            }
+        } else if (errorIndicatorElement != null) {
+            getElement().removeChild(errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+    }
 }
index fa4a939a955ab7a40ae708cba4572016c4aee18b..bf41ef1f9edcd46df9cb5d5c2708863ffd7d2868 100644 (file)
@@ -24,11 +24,12 @@ 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.WidgetUtil.ErrorUtil;
 import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
 import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
 
-public class VPanel extends SimplePanel
-        implements ShortcutActionHandlerOwner, Focusable {
+public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner,
+        Focusable, HasErrorIndicatorElement {
 
     public static final String CLASSNAME = "v-panel";
 
@@ -133,23 +134,6 @@ public class VPanel extends SimplePanel
         DOM.setInnerHTML(captionText, text);
     }
 
-    /** For internal use only. May be removed or replaced in the future. */
-    public void setErrorIndicatorVisible(boolean showError) {
-        if (showError) {
-            if (errorIndicatorElement == null) {
-                errorIndicatorElement = DOM.createSpan();
-                DOM.setElementProperty(errorIndicatorElement, "className",
-                        "v-errorindicator");
-                DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS);
-                sinkEvents(Event.MOUSEEVENTS);
-            }
-            DOM.insertBefore(captionNode, errorIndicatorElement, captionText);
-        } else if (errorIndicatorElement != null) {
-            DOM.removeChild(captionNode, errorIndicatorElement);
-            errorIndicatorElement = null;
-        }
-    }
-
     /** For internal use only. May be removed or replaced in the future. */
     public void setIconUri(String iconUri, ApplicationConnection client) {
         if (icon != null) {
@@ -201,4 +185,24 @@ public class VPanel extends SimplePanel
         }
         touchScrollHandler.addElement(contentNode);
     }
+
+    @Override
+    public Element getErrorIndicatorElement() {
+        return errorIndicatorElement;
+    }
+
+    @Override
+    public void setErrorIndicatorElementVisible(boolean visible) {
+        if (visible) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = ErrorUtil.createErrorIndicatorElement();
+                DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS);
+                sinkEvents(Event.MOUSEEVENTS);
+                captionNode.insertBefore(errorIndicatorElement, captionText);
+            }
+        } else if (errorIndicatorElement != null){
+            captionNode.removeChild(errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+    }
 }
index 52b48899dd16d09501f6dc4d0fac13a71b08c015..44814f9e0a4d1daa2eff6d01eec4364fd3bb6aa8 100644 (file)
@@ -340,7 +340,8 @@ public class VTabsheet extends VTabsheetBase
                     || tabState.componentError != null) {
                 setTooltipInfo(new TooltipInfo(tabState.description,
                         tabState.descriptionContentMode,
-                        tabState.componentError, this));
+                        tabState.componentError, this,
+                        tabState.componentErrorLevel));
             } else {
                 setTooltipInfo(null);
             }
@@ -352,6 +353,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 b0d17465bb343b2fe1ad3d0f2931e46b41953667..eac2ffd11ec6eaa98cc47aaedfb595d5a74b571a 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,22 +52,6 @@ public class ButtonConnector extends AbstractComponentConnector
         ConnectorFocusAndBlurHandler.addHandlers(this);
     }
 
-    @OnStateChange("errorMessage")
-    void setErrorMessage() {
-        if (null != getState().errorMessage) {
-            if (getWidget().errorIndicatorElement == null) {
-                getWidget().errorIndicatorElement = DOM.createSpan();
-                getWidget().errorIndicatorElement
-                        .setClassName("v-errorindicator");
-            }
-            getWidget().wrapper.insertFirst(getWidget().errorIndicatorElement);
-
-        } else if (getWidget().errorIndicatorElement != null) {
-            getWidget().wrapper.removeChild(getWidget().errorIndicatorElement);
-            getWidget().errorIndicatorElement = null;
-        }
-    }
-
     @OnStateChange("resources")
     void onResourceChange() {
         if (getWidget().icon != null) {
index cf39e5ee212a664dcded7dd5f67c701d99e58dfe..c02607790fe0d06174b8d2202879f111b854972c 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;
@@ -66,27 +68,7 @@ public class CheckBoxConnector extends AbstractFieldConnector
     public void onStateChanged(StateChangeEvent stateChangeEvent) {
         super.onStateChanged(stateChangeEvent);
 
-        if (null != getState().errorMessage) {
-            getWidget().setAriaInvalid(true);
-
-            if (getWidget().errorIndicatorElement == null) {
-                getWidget().errorIndicatorElement = DOM.createSpan();
-                getWidget().errorIndicatorElement.setInnerHTML("&nbsp;");
-                DOM.setElementProperty(getWidget().errorIndicatorElement,
-                        "className", "v-errorindicator");
-                DOM.appendChild(getWidget().getElement(),
-                        getWidget().errorIndicatorElement);
-                DOM.sinkEvents(getWidget().errorIndicatorElement,
-                        VTooltip.TOOLTIP_EVENTS | Event.ONCLICK);
-            } else {
-                getWidget().errorIndicatorElement.getStyle().clearDisplay();
-            }
-        } else if (getWidget().errorIndicatorElement != null) {
-            getWidget().errorIndicatorElement.getStyle()
-                    .setDisplay(Display.NONE);
-
-            getWidget().setAriaInvalid(false);
-        }
+        getWidget().setAriaInvalid(getState().errorMessage != null);
 
         getWidget().setAriaRequired(isRequiredIndicatorVisible());
         if (isReadOnly()) {
index ba1d79c776b7854ddbf521f23191365fe4be97fd..ea9fd57c2692f6b96ed9eb6238f4c27edd27c97e 100644 (file)
@@ -254,7 +254,8 @@ public class FormLayoutConnector extends AbstractLayoutConnector
         }
 
         getWidget().table.updateError(component.getWidget(),
-                component.getState().errorMessage, hideErrors);
+                component.getState().errorMessage,
+                component.getState().errorLevel, hideErrors);
     }
 
     @Override
index e110bbb93514f72fdb9167205836218ec6b6a1c1..edc544912711cd4994f9ceb43f0b3a6e67e3ba2f 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;
@@ -70,20 +72,6 @@ public class LinkConnector extends AbstractComponentConnector {
         // Set link caption
         VCaption.setCaptionText(getWidget().captionElement, getState());
 
-        // handle error
-        if (null != getState().errorMessage) {
-            if (getWidget().errorIndicatorElement == null) {
-                getWidget().errorIndicatorElement = DOM.createDiv();
-                DOM.setElementProperty(getWidget().errorIndicatorElement,
-                        "className", "v-errorindicator");
-            }
-            DOM.insertChild(getWidget().getElement(),
-                    getWidget().errorIndicatorElement, 0);
-        } else if (getWidget().errorIndicatorElement != null) {
-            getWidget().errorIndicatorElement.getStyle()
-                    .setDisplay(Display.NONE);
-        }
-
         if (getWidget().icon != null) {
             getWidget().anchor.removeChild(getWidget().icon.getElement());
             getWidget().icon = null;
index 18db2cf4246c270338d88f0af2324f7118d41a85..5560e9825cb5f4974541c8725fcaf3470bcf5460 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;
@@ -55,23 +57,6 @@ public class NativeButtonConnector extends AbstractComponentConnector {
         // Set text
         VCaption.setCaptionText(getWidget(), getState());
 
-        // handle error
-        if (null != getState().errorMessage) {
-            if (getWidget().errorIndicatorElement == null) {
-                getWidget().errorIndicatorElement = DOM.createSpan();
-                getWidget().errorIndicatorElement
-                        .setClassName("v-errorindicator");
-            }
-            getWidget().getElement().insertBefore(
-                    getWidget().errorIndicatorElement,
-                    getWidget().captionElement);
-
-        } else if (getWidget().errorIndicatorElement != null) {
-            getWidget().getElement()
-                    .removeChild(getWidget().errorIndicatorElement);
-            getWidget().errorIndicatorElement = null;
-        }
-
         if (getWidget().icon != null) {
             getWidget().getElement().removeChild(getWidget().icon.getElement());
             getWidget().icon = null;
index 5ab5f5fcda65e30501d04adac1149f8d9b5b3c22..ee8438de22891a1bdc3e2c62c6d9cbe761a69260 100644 (file)
@@ -275,8 +275,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 d8e0544aaf884731fe3883dc206d73aff6d96f3b..fb89972d0495e15f4e620d8b1316c23f27122b7f 100644 (file)
@@ -30,16 +30,19 @@ import com.google.gwt.user.client.ui.Widget;
 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.HasErrorIndicatorElement;
 import com.vaadin.client.ui.Icon;
 import com.vaadin.client.ui.ImageIcon;
 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.
  */
-public class Slot extends SimplePanel {
+public class Slot extends SimplePanel implements HasErrorIndicatorElement {
 
     private static final String ALIGN_CLASS_PREFIX = "v-align-";
 
@@ -493,6 +496,37 @@ 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
+     * @since 8.2
+     */
+    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
@@ -583,14 +617,11 @@ public class Slot extends SimplePanel {
 
         // Error
         if (error != null && showError) {
-            if (errorIcon == null) {
-                errorIcon = DOM.createSpan();
-                errorIcon.setClassName("v-errorindicator");
-            }
-            caption.appendChild(errorIcon);
-        } else if (errorIcon != null) {
-            errorIcon.removeFromParent();
-            errorIcon = null;
+            setErrorIndicatorElementVisible(true);
+            ErrorUtil.setErrorLevelStyle(getErrorIndicatorElement(),
+                    StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel);
+        } else {
+            setErrorIndicatorElementVisible(false);
         }
 
         if (caption != null) {
@@ -799,4 +830,22 @@ public class Slot extends SimplePanel {
             return hasRelativeWidth();
         }
     }
+
+    @Override
+    public Element getErrorIndicatorElement() {
+        return errorIcon;
+    }
+
+    @Override
+    public void setErrorIndicatorElementVisible(boolean visible) {
+        if (visible) {
+            if (errorIcon == null) {
+                errorIcon = ErrorUtil.createErrorIndicatorElement();
+            }
+            caption.appendChild(errorIcon);
+        } else if (errorIcon != null) {
+            errorIcon.removeFromParent();
+            errorIcon = null;
+        }
+    }
 }
index 84ed73e537409fab194bafb568be0e277e526ebd..25434e2701f05dd7e4d6f2c74289313cf61b80cf 100644 (file)
@@ -143,8 +143,6 @@ public class PanelConnector extends AbstractSingleComponentContainerConnector
             getWidget().setIconUri(null, client);
         }
 
-        getWidget().setErrorIndicatorVisible(isErrorIndicatorVisible());
-
         // We may have actions attached to this panel
         if (uidl.getChildCount() > 0) {
             final int cnt = uidl.getChildCount();
index d2a761ba0abd939bf4140168f535b20070efdb75..714367b0ae384f1fb97109219b260cd93d3859d5 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.ConnectorFocusAndBlurHandler;
@@ -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 e904cd68035f98b89d2cf6033042ac5f20689c41..ab28118c66ba572d9318b75e5c79c7f46194f03f 100644 (file)
@@ -126,6 +126,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 2bb40659214b7f07d07a6cae95b4354a51d86628..8bb2cefccc794c49f82d81747d6eaf97c3c06feb 100644 (file)
@@ -21,9 +21,9 @@ import java.io.Serializable;
 import com.vaadin.data.Binder;
 import com.vaadin.server.AbstractErrorMessage;
 import com.vaadin.server.ErrorMessage;
-import com.vaadin.server.ErrorMessage.ErrorLevel;
 import com.vaadin.server.ErrorMessageProducer;
 import com.vaadin.server.UserError;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.v7.data.Validator.InvalidValueException;
 
 /**
index f226622359c44bbc3b94d6f4e52165d3d4f06d32..f13a01a5b5091600ddf5290c4815fda87581fb5f 100644 (file)
@@ -22,10 +22,10 @@ import com.vaadin.data.Binder;
 import com.vaadin.server.AbstractErrorMessage;
 import com.vaadin.server.AbstractErrorMessage.ContentMode;
 import com.vaadin.server.ErrorMessage;
-import com.vaadin.server.ErrorMessage.ErrorLevel;
 import com.vaadin.server.ErrorMessageProducer;
 import com.vaadin.server.UserError;
 import com.vaadin.server.VaadinServlet;
+import com.vaadin.shared.ui.ErrorLevel;
 
 /**
  * Interface that implements a method for validating if an {@link Object} is
index 9b64d1e6f82d71b6856d1a42060950bab220bab2..6cd7323cd90b1496c454276d6f4d191d5da4dd53 100644 (file)
@@ -58,6 +58,7 @@ import com.vaadin.server.VaadinSession;
 import com.vaadin.shared.MouseEventDetails;
 import com.vaadin.shared.Registration;
 import com.vaadin.shared.data.sort.SortDirection;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.shared.util.SharedUtil;
 import com.vaadin.ui.AbstractComponent;
 import com.vaadin.ui.Component;
index 5a26833169fafd592c4005443ecea20335de0bb2..938e2d61de901dd0e9c4199463d1a0417992538e 100644 (file)
@@ -29,12 +29,12 @@ import org.jsoup.parser.Tag;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.vaadin.server.ErrorMessage.ErrorLevel;
 import com.vaadin.server.ExternalResource;
 import com.vaadin.server.FileResource;
 import com.vaadin.server.Responsive;
 import com.vaadin.server.ThemeResource;
 import com.vaadin.server.UserError;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.tests.design.DeclarativeTestBase;
 import com.vaadin.ui.AbstractComponent;
 import com.vaadin.ui.Label;
index cad1dc425d3db071e751a3b45f1e5ba6109fccc8..b7e439244e734544acabedef45b7ba3867a01688 100644 (file)
@@ -21,6 +21,8 @@ import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
 
+import com.vaadin.shared.ui.ErrorLevel;
+
 /**
  * Base class for component error messages.
  *
index 6d6a775a1b25c82ca66c8a33f45a4a358d8f2543..510ef4ed00e709a93841c67b8cb64a7504a58296 100644 (file)
@@ -19,6 +19,8 @@ package com.vaadin.server;
 import java.util.Collection;
 import java.util.Iterator;
 
+import com.vaadin.shared.ui.ErrorLevel;
+
 /**
  * Class for combining multiple error messages together.
  *
@@ -37,7 +39,7 @@ public class CompositeErrorMessage extends AbstractErrorMessage {
      */
     public CompositeErrorMessage(ErrorMessage... errorMessages) {
         super(null);
-        setErrorLevel(ErrorLevel.INFORMATION);
+        setErrorLevel(ErrorLevel.INFO);
 
         for (ErrorMessage errorMessage : errorMessages) {
             addErrorMessage(errorMessage);
@@ -60,7 +62,7 @@ public class CompositeErrorMessage extends AbstractErrorMessage {
     public CompositeErrorMessage(
             Collection<? extends ErrorMessage> errorMessages) {
         super(null);
-        setErrorLevel(ErrorLevel.INFORMATION);
+        setErrorLevel(ErrorLevel.INFO);
 
         for (ErrorMessage errorMessage : errorMessages) {
             addErrorMessage(errorMessage);
index f4030ed4c9926109f0d1298fb17818eba98388b3..8095a5afddc2baf7f443f287e3534ba3ce0e6e52 100644 (file)
@@ -18,6 +18,8 @@ package com.vaadin.server;
 
 import java.io.Serializable;
 
+import com.vaadin.shared.ui.ErrorLevel;
+
 /**
  * Interface for rendering error messages to terminal. All the visible errors
  * shown to user must implement this interface.
@@ -27,66 +29,11 @@ import java.io.Serializable;
  */
 public interface ErrorMessage extends Serializable {
 
-    public enum ErrorLevel {
-        /**
-         * Error code for informational messages.
-         */
-        INFORMATION("info", 0),
-        /**
-         * Error code for warning messages.
-         */
-        WARNING("warning", 1),
-        /**
-         * Error code for regular error messages.
-         */
-        ERROR("error", 2),
-        /**
-         * Error code for critical error messages.
-         */
-        CRITICAL("critical", 3),
-        /**
-         * Error code for system errors and bugs.
-         */
-        SYSTEMERROR("system", 4);
-
-        String text;
-        int errorLevel;
-
-        private ErrorLevel(String text, int errorLevel) {
-            this.text = text;
-            this.errorLevel = errorLevel;
-        }
-
-        /**
-         * Textual representation for server-client communication of level
-         *
-         * @return String for error severity
-         */
-        public String getText() {
-            return text;
-        }
-
-        /**
-         * Integer representation of error severity for comparison
-         *
-         * @return integer for error severity
-         */
-        public int intValue() {
-            return errorLevel;
-        }
-
-        @Override
-        public String toString() {
-            return text;
-        }
-
-    }
-
     /**
-     * @deprecated As of 7.0, use {@link ErrorLevel#SYSTEMERROR} instead Â  Â 
+     * @deprecated As of 7.0, use {@link ErrorLevel#SYSTEM} instead Â  Â 
      */
     @Deprecated
-    public static final ErrorLevel SYSTEMERROR = ErrorLevel.SYSTEMERROR;
+    public static final ErrorLevel SYSTEMERROR = ErrorLevel.SYSTEM;
 
     /**
      * @deprecated As of 7.0, use {@link ErrorLevel#CRITICAL} instead Â  Â 
@@ -108,10 +55,10 @@ public interface ErrorMessage extends Serializable {
     public static final ErrorLevel WARNING = ErrorLevel.WARNING;
 
     /**
-     * @deprecated As of 7.0, use {@link ErrorLevel#INFORMATION} instead Â  Â 
+     * @deprecated As of 7.0, use {@link ErrorLevel#INFO} instead Â  Â 
      */
     @Deprecated
-    public static final ErrorLevel INFORMATION = ErrorLevel.INFORMATION;
+    public static final ErrorLevel INFORMATION = ErrorLevel.INFO;
 
     /**
      * Gets the errors level.
index 734b4862a8828ecfb3aaf17b419c6ddf5775219c..151021d1f84c278de28650bed0024c59adf802b0 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.vaadin.server;
 
+import com.vaadin.shared.ui.ErrorLevel;
+
 /**
  * <code>SystemError</code> is an error message for a problem caused by error in
  * system, not the user application code. The system error can contain technical
@@ -39,7 +41,7 @@ public class SystemError extends AbstractErrorMessage {
      */
     public SystemError(String message) {
         super(message);
-        setErrorLevel(ErrorLevel.SYSTEMERROR);
+        setErrorLevel(ErrorLevel.SYSTEM);
         setMode(ContentMode.HTML);
         setMessage(getHtmlMessage());
     }
index b017c9e1f98b996e1631417b3b6fd9785096de8d..636e98a02feadcd02d019b493762300b79a59e12 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.vaadin.server;
 
+import com.vaadin.shared.ui.ErrorLevel;
+
 /**
  * <code>UserError</code> is a controlled error occurred in application. User
  * errors are occur in normal usage of the application and guide the user.
index a0bb648ffb188155575fccd300d4555df3846acb..f74f2141da841ce4fe79fadbe990e257a04609a7 100644 (file)
@@ -45,7 +45,6 @@ import com.vaadin.server.AbstractClientConnector;
 import com.vaadin.server.ClientConnector;
 import com.vaadin.server.ComponentSizeValidator;
 import com.vaadin.server.ErrorMessage;
-import com.vaadin.server.ErrorMessage.ErrorLevel;
 import com.vaadin.server.Extension;
 import com.vaadin.server.Resource;
 import com.vaadin.server.Responsive;
@@ -62,6 +61,7 @@ import com.vaadin.shared.MouseEventDetails;
 import com.vaadin.shared.Registration;
 import com.vaadin.shared.ui.ComponentStateUtil;
 import com.vaadin.shared.ui.ContentMode;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.shared.util.SharedUtil;
 import com.vaadin.ui.declarative.DesignAttributeHandler;
 import com.vaadin.ui.declarative.DesignContext;
@@ -723,8 +723,10 @@ public abstract class AbstractComponent extends AbstractClientConnector
         ErrorMessage error = getErrorMessage();
         if (null != error) {
             getState().errorMessage = error.getFormattedHtmlMessage();
+            getState().errorLevel = error.getErrorLevel();
         } else {
             getState().errorMessage = null;
+            getState().errorLevel = null;
         }
     }
 
index 385c6b5f5c0c8fff6158d864818409d7e513e1b0..ac3a22eb41566d05a6290ee4a18cc921accaf047 100644 (file)
@@ -1314,9 +1314,15 @@ 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();
+            } else {
+                tabState.componentError = null;
+                tabState.componentErrorLevel = null;
+            }
+
 
             markAsDirty();
         }
index 018aa25cd4af1ba05ca010ec1ea135af1412b4d5..b2a32efaa09bbf5068c3c46ed7530e23b16f0d85 100644 (file)
@@ -28,13 +28,13 @@ import org.jsoup.parser.Tag;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.vaadin.server.ErrorMessage.ErrorLevel;
 import com.vaadin.shared.ui.ContentMode;
 import com.vaadin.server.ExternalResource;
 import com.vaadin.server.FileResource;
 import com.vaadin.server.Responsive;
 import com.vaadin.server.ThemeResource;
 import com.vaadin.server.UserError;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.tests.design.DeclarativeTestBase;
 import com.vaadin.ui.AbstractComponent;
 import com.vaadin.ui.Button;
index 84c2534f849db3723257f7a758ca3dfa7b059732..48d9646c37e5e4ec726b4c114cd7de7c7cf7edeb 100644 (file)
@@ -24,11 +24,11 @@ import java.util.Locale;
 
 import org.junit.Test;
 
-import com.vaadin.server.ErrorMessage.ErrorLevel;
 import com.vaadin.server.ExternalResource;
 import com.vaadin.server.FileResource;
 import com.vaadin.server.ThemeResource;
 import com.vaadin.server.UserError;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.tests.design.DeclarativeTestBase;
 import com.vaadin.ui.AbstractComponent;
 import com.vaadin.ui.declarative.DesignContext;
index 81f808f676ba6fff617e46c84222a788c41d0f8b..9b949111a74c238b11c2e8ab741546e6879d40d7 100644 (file)
@@ -21,6 +21,7 @@ import java.util.List;
 import com.vaadin.shared.annotations.NoLayout;
 import com.vaadin.shared.communication.SharedState;
 import com.vaadin.shared.ui.ContentMode;
+import com.vaadin.shared.ui.ErrorLevel;
 
 /**
  * Default shared state implementation for AbstractComponent.
@@ -43,9 +44,15 @@ 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
+     *
+     * @since 8.2
+     */
+    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..fe216fb
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2016 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;
+
+    /**
+     * Integer representation of error severity for comparison
+     *
+     * @return integer for error severity
+     */
+    public int intValue() {
+        return ordinal();
+    }
+}
index 763f2cf20fe10be3a2bbd88489ec12fd12b94d01..b337d4f06367f283bbd40b6f15d21b9fd9463e7c 100644 (file)
@@ -19,6 +19,8 @@ import java.io.Serializable;
 
 import com.vaadin.shared.ui.ContentMode;
 
+import com.vaadin.shared.ui.ErrorLevel;
+
 /**
  * Shared state of a single tab in a Tabsheet or an Accordion.
  *
@@ -36,6 +38,13 @@ public class TabState implements Serializable {
     public String styleName;
     public String key;
     public String componentError;
+
+    /**
+     * Represents the level of error on a tab.
+     *
+     * @since 8.2
+     */
+    public ErrorLevel componentErrorLevel;
     public String id;
     public String iconAltText;
 
index 3a4a26065d36ac5fb706c159f1dd757fb52bf8eb..37f67cd836df7d34469f55298bb167696338f2a5 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3a4a26065d36ac5fb706c159f1dd757fb52bf8eb
+Subproject commit 37f67cd836df7d34469f55298bb167696338f2a5
index 40694159859be276f5c412a805c188d2bc3f7cc0..8e45fc4afc2a9f6e23fbcee21b922092aa898aa2 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 bfe1e33743d1974538c0e3a953fe0893e6f0c510..e92c9ce4361755b68bafe787eea34e5a31c98f9e 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 5a62be5dbca94d0e24e31050df5b6be960f6da66..91fad017444087c511de17ffb6c31a93d06d4864 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 {
@@ -319,13 +338,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 ecd8e1a59b16a51141558631ae00a1d6ba51806a..99fbd360b17af41f6d3ed9540271909b785fdf89 100644 (file)
@@ -313,6 +313,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;
@@ -366,8 +386,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 cb3824d26fdaa75090600c95bd4203790823afc7..99c453b16eb90f57d7444ce39b3e59bf9f73d537 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 323701808730e8fdb1da99fbe52669d9f8c1603a..51f6f73350ea0baafb58fcc907703449c213ff92 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..9ab5ca6
--- /dev/null
@@ -0,0 +1,210 @@
+package com.vaadin.tests.components;
+
+import java.util.Arrays;
+
+import com.vaadin.annotations.Theme;
+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.shared.ui.ErrorLevel;
+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<ErrorLevel> errorLevels;
+    private Button button;
+    private Button borderlessButton;
+    private Link link;
+    private ComboBox<String> 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;
+
+    private com.vaadin.v7.ui.ComboBox comboBoxCompat;
+    private com.vaadin.v7.ui.TextField textFieldCompat;
+    private com.vaadin.v7.ui.CheckBox checkBoxCompat;
+    private com.vaadin.v7.ui.DateField dateFieldCompat;
+    private com.vaadin.v7.ui.TwinColSelect twinColSelectCompat;
+
+    @Override
+    protected void setup(VaadinRequest request) {
+
+        errorLevels = new ComboBox<>("Error level",
+                Arrays.asList(ErrorLevel.values()));
+        errorLevels.setEmptySelectionAllowed(false);
+        errorLevels.setValue(ErrorLevel.ERROR);
+        errorLevels.addValueChangeListener(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);
+
+        Label subtitleCompat = new Label("Compatibility components");
+        subtitleCompat.setStyleName(ValoTheme.LABEL_H3);
+        addComponent(subtitleCompat);
+
+        // Compatibility combo box
+        comboBoxCompat = new com.vaadin.v7.ui.ComboBox(
+                "Compatibility combo box");
+        addComponent(comboBoxCompat);
+
+        // Compatibility text field
+        textFieldCompat = new com.vaadin.v7.ui.TextField(
+                "Compatibility text field");
+        textFieldCompat.setValue("text");
+
+        // Compatibility check box
+        checkBoxCompat = new com.vaadin.v7.ui.CheckBox("Check box");
+        addComponent(checkBoxCompat);
+
+        // Compatibility date field
+        dateFieldCompat = new com.vaadin.v7.ui.DateField("Date field");
+        addComponent(dateFieldCompat);
+
+        // Compatibility twin col select
+        twinColSelectCompat = new com.vaadin.v7.ui.TwinColSelect(
+                "Twin col select");
+        addComponent(twinColSelectCompat);
+
+        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"));
+        comboBoxCompat.setComponentError(
+                createErrorMessage("Compatibility combo box error"));
+        textFieldCompat.setComponentError(
+                createErrorMessage("Compatibility text field error"));
+        checkBoxCompat.setComponentError(
+                createErrorMessage("Compatibility check box error"));
+        dateFieldCompat.setComponentError(
+                createErrorMessage("Compatibility date field error"));
+        twinColSelectCompat.setComponentError(
+                createErrorMessage("Compatibility twin col select error"));
+    }
+
+    private ErrorMessage createErrorMessage(String text) {
+        return new UserError(text, AbstractErrorMessage.ContentMode.TEXT,
+                errorLevels.getValue());
+    }
+}
index 6d7a67cfa8bbe63b20a31c1abd6af5b9055c57cd..4c83430832013fe97a784391d3eef34d20e3cb78 100644 (file)
@@ -20,11 +20,11 @@ import com.vaadin.icons.VaadinIcons;
 import com.vaadin.navigator.View;
 import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
 import com.vaadin.server.AbstractErrorMessage;
-import com.vaadin.server.ErrorMessage.ErrorLevel;
 import com.vaadin.server.Page;
 import com.vaadin.server.UserError;
 import com.vaadin.shared.Position;
 import com.vaadin.shared.ui.ContentMode;
+import com.vaadin.shared.ui.ErrorLevel;
 import com.vaadin.ui.Alignment;
 import com.vaadin.ui.Button;
 import com.vaadin.ui.Button.ClickEvent;
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..750545c
--- /dev/null
@@ -0,0 +1,160 @@
+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.ComboBoxElement;
+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;
+
+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 99c7a1d770d0d5caabd0ccac23b504ea04207b74..31011b88373a89ecff24cd7fc451d73ec6b29927 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) {