Browse Source

Colorpicker validation handling (#10821)

* ColorTextField, helper methods, and regex for validating and handling text input

* Refactored structure to avoid creating new component for validation

* Style to adapt to error indicator

* Tests for validating input in ColorPickerPreview component's TextField

* Merge branch 'master' into colorpicker_validation

* Fix path to server class

* Fix test: Submit the new value

* Fix test: ignore Phantom JS

* Fix hsl+hsla validation patterns to accept '%', test value tweaking

* Merge branch 'master' of github.com:vaadin/framework into colorpicker_validation

* Fix: remove warning when color is updated from elsewhere

* Revisions: input validation only once, Logging level WARN

* Revisions: unit tests for color pattern matching

* Revisions: moved parsing to utility class, tests for parsing all accepted input formats

* Fixed import in tests, comments

* Revisions: Logger as constant, ignore utility class in serialization test

* Corner case tests

* Revisions: protected method for parsing error text, fix to test

* Revisions: NPE fix
tags/8.5.0.alpha1
KatriHaapalinna 6 years ago
parent
commit
bdbb0b4328

+ 42
- 58
server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java View File

@@ -16,9 +16,15 @@
package com.vaadin.ui.components.colorpicker;

import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.vaadin.data.HasValue;
import com.vaadin.server.AbstractErrorMessage.ContentMode;
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.UserError;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
@@ -31,6 +37,8 @@ import com.vaadin.ui.TextField;
* @since 7.0.0
*/
public class ColorPickerPreview extends CssLayout implements HasValue<Color> {
private static final Logger LOGGER = Logger
.getLogger(ColorPickerPreview.class.getName());

private static final String STYLE_DARK_COLOR = "v-textfield-dark";
private static final String STYLE_LIGHT_COLOR = "v-textfield-light";
@@ -86,6 +94,7 @@ public class ColorPickerPreview extends CssLayout implements HasValue<Color> {

String colorCSS = color.getCSS();
field.setValue(colorCSS);
field.setComponentError(null);

oldValue = colorCSS;

@@ -120,68 +129,29 @@ public class ColorPickerPreview extends CssLayout implements HasValue<Color> {
}

private void valueChange(ValueChangeEvent<String> event) {
ErrorMessage errorMessage = null;
String value = event.getValue();
value = Objects.toString(value, "").trim();
Color oldColor = color;
try {
if (value != null) {
/*
* Description of supported formats see
* http://www.w3schools.com/cssref/css_colors_legal.asp
*/
if (value.length() == 7 && value.startsWith("#")) {
// CSS color format (e.g. #000000)
int red = Integer.parseInt(value.substring(1, 3), 16);
int green = Integer.parseInt(value.substring(3, 5), 16);
int blue = Integer.parseInt(value.substring(5, 7), 16);
color = new Color(red, green, blue);

} else if (value.startsWith("rgb")) {
// RGB color format rgb/rgba(255,255,255,0.1)
String[] colors = value.substring(value.indexOf('(') + 1,
value.length() - 1).split(",");

int red = Integer.parseInt(colors[0]);
int green = Integer.parseInt(colors[1]);
int blue = Integer.parseInt(colors[2]);
if (colors.length > 3) {
int alpha = (int) (Double.parseDouble(colors[3])
* 255d);
color = new Color(red, green, blue, alpha);
} else {
color = new Color(red, green, blue);
}

} else if (value.startsWith("hsl")) {
// HSL color format hsl/hsla(100,50%,50%,1.0)
String[] colors = value.substring(value.indexOf('(') + 1,
value.length() - 1).split(",");

int hue = Integer.parseInt(colors[0]);
int saturation = Integer
.parseInt(colors[1].replace("%", ""));
int lightness = Integer
.parseInt(colors[2].replace("%", ""));
int rgb = Color.HSLtoRGB(hue, saturation, lightness);

if (colors.length > 3) {
int alpha = (int) (Double.parseDouble(colors[3])
* 255d);
color = new Color(rgb);
color.setAlpha(alpha);
} else {
color = new Color(rgb);
}
}

oldValue = value;
fireEvent(new ValueChangeEvent<>(this, oldColor,
event.isUserOriginated()));
}

} catch (NumberFormatException nfe) {
// Revert value
field.setValue(oldValue);
/*
* Description of supported formats see
* http://www.w3schools.com/cssref/css_colors_legal.asp
*/
color = ColorUtil.stringToColor(value);

oldValue = value;
fireEvent(new ValueChangeEvent<>(this, oldColor,
event.isUserOriginated()));
} catch (NumberFormatException e) {
// Pattern matching ensures the validity of
// the input, this should never happen
LOGGER.log(Level.INFO, e.getMessage());
errorMessage = new UserError(getUserErrorText(value),
ContentMode.TEXT, ErrorLevel.WARNING);
}
field.setComponentError(errorMessage);
}

@Override
@@ -224,4 +194,18 @@ public class ColorPickerPreview extends CssLayout implements HasValue<Color> {
}
}
}
}

/**
* Get the client error message text for color input parsing error.
*
* @param value
* input which caused the error
* @return error message text
*/
protected String getUserErrorText(String value) {
return value.isEmpty() ? "Input cannot be empty"
: "Input '".concat(value)
.concat("' is not in any recognized format");
}

}

+ 229
- 0
server/src/main/java/com/vaadin/ui/components/colorpicker/ColorUtil.java View File

@@ -0,0 +1,229 @@
/*
* Copyright 2000-2018 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.ui.components.colorpicker;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.vaadin.shared.ui.colorpicker.Color;

/**
* Utility class for matching and parsing {@link Color} objects from
* {@code String} input.
*
* Description of supported formats see
* http://www.w3schools.com/cssref/css_colors_legal.asp
*
* @since
*/
public class ColorUtil {
private ColorUtil() {
}

/**
* Parses {@link Color} from any of the following {@link String} inputs:
* <br>
* - RGB hex (e.g. "#FFAA00"), {@link #HEX_PATTERN}<br>
* - RGB "function" (e.g. "rgb(128,0,255)"), {@link #RGB_PATTERN}<br>
* - RGBA "function" (e.g. "rgba(50,50,50,0.2)"), {@link #RGBA_PATTERN}<br>
* - HSL "function" (e.g. "hsl(50,50,50)"), {@link #HSL_PATTERN}<br>
* - HSLA "function" (e.g. "hsl(50,50,50,0.2)"), {@link #HSLA_PATTERN}
* <p>
* Parsing is case-insensitive.
*
* @param input
* String input
* @return {@link Color} parsed from input
* @throws NumberFormatException
* Input does not match any recognized pattern
*/
public static Color stringToColor(String input) {
Matcher m = HEX_PATTERN.matcher(input);
if (m.matches()) {
return getHexPatternColor(m);
}
m = RGB_PATTERN.matcher(input);
if (m.matches()) {
return getRGBPatternColor(m);
}
m = RGBA_PATTERN.matcher(input);
if (m.matches()) {
return getRGBAPatternColor(m);
}
m = HSL_PATTERN.matcher(input);
if (m.matches()) {
return getHSLPatternColor(m);
}
m = HSLA_PATTERN.matcher(input);
if (m.matches()) {
return getHSLAPatternColor(m);
}

throw new NumberFormatException("Parsing color from input failed.");
}

/**
* Parses {@link Color} from matched hexadecimal {@link Matcher}.
*
* @param matcher
* {@link Matcher} matching hexadecimal pattern with named regex
* groups {@code red}, {@code green}, and {@code blue}
* @return {@link Color} parsed from {@link Matcher}
*/
public static Color getHexPatternColor(Matcher matcher) {
int red = Integer.parseInt(matcher.group("red"), 16);
int green = Integer.parseInt(matcher.group("green"), 16);
int blue = Integer.parseInt(matcher.group("blue"), 16);
return new Color(red, green, blue);
}

/**
* Parses {@link Color} from matched RGB {@link Matcher}.
*
* @param matcher
* {@link Matcher} matching RGB pattern with named regex groups
* {@code red}, {@code green}, and {@code blue}
* @return {@link Color} parsed from {@link Matcher}
*/
public static Color getRGBPatternColor(Matcher matcher) {
int red = Integer.parseInt(matcher.group("red"));
int green = Integer.parseInt(matcher.group("green"));
int blue = Integer.parseInt(matcher.group("blue"));
return new Color(red, green, blue);
}

/**
* Parses {@link Color} from matched RGBA {@link Matcher}.
*
* @param matcher
* {@link Matcher} matching RGBA pattern with named regex groups
* {@code red}, {@code green}, {@code blue}, and {@code alpha}
* @return {@link Color} parsed from {@link Matcher}
*/
public static Color getRGBAPatternColor(Matcher matcher) {
Color c = getRGBPatternColor(matcher);
c.setAlpha((int) (Double.parseDouble(matcher.group("alpha")) * 255d));
return c;
}

/**
* Parses {@link Color} from matched HSL {@link Matcher}.
*
* @param matcher
* {@link Matcher} matching HSL pattern with named regex groups
* {@code hue}, {@code saturation}, and {@code light}
* @return {@link Color} parsed from {@link Matcher}
*/
public static Color getHSLPatternColor(Matcher matcher) {
int hue = Integer.parseInt(matcher.group("hue"));
int saturation = Integer.parseInt(matcher.group("saturation"));
int light = Integer.parseInt(matcher.group("light"));
int rgb = Color.HSLtoRGB(hue, saturation, light);
return new Color(rgb);
}

/**
* Parses {@link Color} from matched HSLA {@link Matcher}.
*
* @param matcher
* {@link Matcher} matching HSLA pattern with named regex groups
* {@code hue}, {@code saturation}, {@code light}, and
* {@code alpha}
* @return {@link Color} parsed from {@link Matcher}
*/
public static Color getHSLAPatternColor(Matcher matcher) {
Color c = getHSLPatternColor(matcher);
c.setAlpha((int) (Double.parseDouble(matcher.group("alpha")) * 255d));
return c;
}

/**
* Case-insensitive {@link Pattern} with regular expression matching the
* default hexadecimal color presentation pattern:<br>
* '#' followed by six <code>[\da-fA-F]</code> characters.
* <p>
* Pattern contains named groups <code>red</code>, <code>green</code>, and
* <code>blue</code>, which represent the individual values.
*/
public static final Pattern HEX_PATTERN = Pattern.compile(
"(?i)^#\\s*(?<red>[\\da-f]{2})(?<green>[\\da-f]{2})(?<blue>[\\da-f]{2}"
+ ")\\s*$");
/**
* Case-insensitive {@link Pattern} with regular expression matching common
* RGB color presentation patterns:<br>
* 'rgb' followed by three [0-255] number values. Values can be separated
* with either comma or whitespace.
* <p>
* Pattern contains named groups <code>red</code>, <code>green</code>, and
* <code>blue</code>, which represent the individual values.
*/
public static final Pattern RGB_PATTERN = Pattern.compile(
"(?i)^rgb\\(\\s*(?<red>[01]?\\d{1,2}|2[0-4]\\d|25[0-5])(?:\\s*[,+|\\"
+ "s+]\\s*)(?<green>[01]?\\d\\d?|2[0-4]\\d|25[0-5])(?:\\s*[,"
+ "+|\\s+]\\s*)(?<blue>[01]?\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\"
+ ")$");
/**
* Case-insensitive {@link Pattern} with regular expression matching common
* RGBA presentation patterns:<br>
* 'rgba' followed by three [0-255] values and one [0.0-1.0] value. Values
* can be separated with either comma or whitespace. The only accepted
* decimal marker is point ('.').
* <p>
* Pattern contains named groups <code>red</code>, <code>green</code>,
* <code>blue</code>, and <code>alpha</code>, which represent the individual
* values.
*/
public static final Pattern RGBA_PATTERN = Pattern.compile(
"(?i)^rgba\\(\\s*(?<red>[01]?\\d{1,2}|2[0-4]\\d|25[0-5])(?:\\s*[,+|"
+ "\\s+]\\s*)(?<green>[01]?\\d\\d?|2[0-4]\\d|25[0-5])(?:\\s"
+ "*[,+|\\s+]\\s*)(?<blue>[01]?\\d\\d?|2[0-4]\\d|25[0-5])(?"
+ ":\\s*[,+|\\s+]\\s*)(?<alpha>0(?:\\.\\d{1,2})?|0?(?:\\.\\"
+ "d{1,2})|1(?:\\.0{1,2})?)\\s*\\)$");

/**
* Case-insensitive {@link Pattern} with regular expression matching common
* HSL presentation patterns:<br>
* 'hsl' followed by one [0-360] value and two [0-100] percentage value.
* Values can be separated with either comma or whitespace. The percent sign
* ('%') is optional.
* <p>
* Pattern contains named groups <code>hue</code>,<code>saturation</code>,
* and <code>light</code>, which represent the individual values.
*/
public static final Pattern HSL_PATTERN = Pattern.compile(
"(?i)hsl\\(\\s*(?<hue>[12]?\\d{1,2}|3[0-5]\\d|360)(?:\\s*[,+|\\s+]"
+ "\\s*)(?<saturation>\\d{1,2}|100)(?:\\s*%?\\s*[,+|\\s+]\\"
+ "s*)(?<light>\\d{1,2}|100)(?:\\s*%?\\s*)\\)$");

/**
* Case-insensitive {@link Pattern} with regular expression matching common
* HSLA presentation patterns:<br>
* 'hsla' followed by one [0-360] value, two [0-100] percentage values, and
* one [0.0-1.0] value. Values can be separated with either comma or
* whitespace. The percent sign ('%') is optional. The only accepted decimal
* marker is point ('.').
* <p>
* Pattern contains named groups <code>hue</code>,<code>saturation</code>,
* <code>light</code>, and <code>alpha</code>, which represent the
* individual values.
*/
public static final Pattern HSLA_PATTERN = Pattern.compile(
"(?i)hsla\\(\\s*(?<hue>[12]?\\d{1,2}|3[0-5]\\d|360)(?:\\s*[,+|\\s+"
+ "]\\s*)(?<saturation>\\d{1,2}|100)(?:\\s*%?\\s*[,+|\\s+]\\s*"
+ ")(?<light>\\d{1,2}|100)(?:\\s*%?[,+|\\s+]\\s*)(?<alpha>"
+ "0(?:\\.\\d{1,2})?|0?(?:\\.\\d{1,2})|1(?:\\.0{1,2})?)"
+ "\\s*\\)$");
}

+ 1
- 0
server/src/test/java/com/vaadin/tests/server/ClassesSerializableTest.java View File

@@ -94,6 +94,7 @@ public class ClassesSerializableTest {
"com\\.vaadin\\.server\\.JsonCodec\\$1", //
"com\\.vaadin\\.server\\.communication\\.PushConnection", //
"com\\.vaadin\\.server\\.communication\\.AtmospherePushConnection.*", //
"com\\.vaadin\\.ui\\.components\\.colorpicker\\.ColorUtil", //
"com\\.vaadin\\.util\\.ConnectorHelper", //
"com\\.vaadin\\.server\\.VaadinSession\\$FutureAccess", //
"com\\.vaadin\\.external\\..*", //

+ 88
- 0
server/src/test/java/com/vaadin/tests/server/component/colorpicker/HSLAPatternParsingTest.java View File

@@ -0,0 +1,88 @@
package com.vaadin.tests.server.component.colorpicker;

import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.ui.components.colorpicker.ColorUtil;

@RunWith(value = Parameterized.class)
public class HSLAPatternParsingTest {

@Parameter(value = 0)
public String input;

@Parameter(value = 1)
public int expectedHue;
@Parameter(value = 2)
public int expectedSaturation;
@Parameter(value = 3)
public int expectedLight;
@Parameter(value = 4)
public int expectedAlpha;

@Parameter(value = 5)
public boolean expectedMatches;

@Parameters(name = "{index}: testHSLAData({0}) = ({1},{2},{3},{4},{5})")
public static Collection<Object[]> hsladata() {
Object[][] validValues = { { "hsla(0,0,0,0)", 0, 0, 0, 0, true },
{ "HSLA(0, 0, 0, 0)", 0, 0, 0, 0, true },
{ "hsla(0,0%,0%, 0.1)", 0, 0, 0, 25, true },
{ "hsla(0 0 0 0.00 )", 0, 0, 0, 0, true },
{ "hsla(0 0% 0% 0.50)", 0, 0, 0, 127, true },
{ "hsla(360,100,100,1.0)", 360, 100, 100, 255, true },
{ "hsla(360, 100, 100, 1.0)", 360, 100, 100, 255, true },
{ "hsla(360, 100%, 100%, 1.00)", 360, 100, 100, 255, true },
{ "hsla(360 100% 100% 1.00)", 360, 100, 100, 255, true },
{ "hsla(20, 10, 10, 0.24)", 20, 10, 10, 61, true },
{ "hsla(100, 0, 50, 0.8)", 100, 0, 50, 204, true },
{ "hsla(269, 50, 0, .6)", 269, 50, 0, 153, true }, };
Object[][] invalidValues = { { "hsla(361,0,0,0)", 0, 0, 0, 0, false },
{ "hsla(0.0, 0, 0, 0)", 0, 0, 0, 0, false },
{ "hsla(0,0%,0%, 1.1)", 0, 0, 0, 0, false },
{ "hsla(0 0 0 0.009 )", 0, 0, 0, 0, false },
{ "hsla(0 0% -100% 0.50)", 0, 0, 0, 0, false },
{ "hsla(360,1000,100,1.0)", 0, 0, 0, 0, false },
{ "hsla(0, 100, 100, 2.0)", 0, 0, 0, 0, false },
{ "hsla(360, 100%, 100%, 10.00)", 0, 0, 0, 0, false },
{ "hsl a(360 100% 100% 1.)", 0, 0, 0, 0, false },
{ "hsla(20, -10, 10, 0.24)", 0, 0, 0, 0, false },
{ "hsla(400, 0, 50, 0.8)", 0, 0, 0, 0, false },
{ "hsla(200, 50, 0, 0.996)", 0, 0, 0, 0, false },
{ "hsla 200, 50, 0, 0.9", 0, 0, 0, 0, false },
{ "hsla(0,0,0,0.)", 0, 0, 0, 0, false } };

ArrayList<Object[]> values = new ArrayList<>();
Collections.addAll(values, validValues);
Collections.addAll(values, invalidValues);

return values;
}

@Test
public void testHSLAData() {
Matcher m = ColorUtil.HSLA_PATTERN.matcher(input);
boolean matches = m.matches();
if (expectedMatches) {
Color expectedColor = new Color(Color.HSLtoRGB(expectedHue,
expectedSaturation, expectedLight));
expectedColor.setAlpha(expectedAlpha);
Color c1 = ColorUtil.getHSLAPatternColor(m);
assertTrue(expectedColor.equals(c1));
} else {
assertTrue(!matches);
}
}

}

+ 89
- 0
server/src/test/java/com/vaadin/tests/server/component/colorpicker/HSLPatternParsingTest.java View File

@@ -0,0 +1,89 @@
package com.vaadin.tests.server.component.colorpicker;

import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.ui.components.colorpicker.ColorUtil;

@RunWith(value = Parameterized.class)
public class HSLPatternParsingTest {

@Parameter(value = 0)
public String input;

@Parameter(value = 1)
public Color expectedColor;

@Parameter(value = 2)
public boolean expectedMatches;

@Parameters(name = "{index}: testHSLData({0}) = ({1},{2})")
public static Collection<Object[]> hsldata() {
Object[][] validValues = {
{ "hsl(0,0,0)", new Color(Color.HSLtoRGB(0, 0, 0)), true },
{ "hsl(0, 0, 0)", new Color(Color.HSLtoRGB(0, 0, 0)), true },
{ "hsl(0,0%,0% )", new Color(Color.HSLtoRGB(0, 0, 0)), true },
{ "hsl(0 0 0)", new Color(Color.HSLtoRGB(0, 0, 0)), true },
{ "hsl(0 0% 0%)", new Color(Color.HSLtoRGB(0, 0, 0)), true },
{ "hsl(360,100,100)", new Color(Color.HSLtoRGB(360, 100, 100)),
true },
{ "hsl(360, 100, 100)",
new Color(Color.HSLtoRGB(360, 100, 100)), true },
{ "hsl(360, 100%, 100%)",
new Color(Color.HSLtoRGB(360, 100, 100)), true },
{ "hsl(360 100% 100%)",
new Color(Color.HSLtoRGB(360, 100, 100)), true },
{ "hsl(20, 10, 10)", new Color(Color.HSLtoRGB(20, 10, 10)),
true },
{ "hsl(100, 0, 50)", new Color(Color.HSLtoRGB(100, 0, 50)),
true },
{ "hsl(200, 50, 0)", new Color(Color.HSLtoRGB(200, 50, 0)),
true },
{ "hsl(200, 50, 05)", new Color(Color.HSLtoRGB(200, 50, 5)),
true } };
Object[][] invalidValues = { { "hsl(361,0,0)", null, false },
{ "hsl(-0, 0, 0)", null, false },
{ "hsl (100%,0%,0% )", null, false },
{ "hsl(0 101 0)", null, false },
{ "hsl(0 0% -99%)", null, false },
{ "hsl(360,100,10 0)", null, false },
{ "hsl(360, 100, 101)", null, false },
{ "hsl(360, 110%, 100%)", null, false },
{ "hsl(3600 100% 100%)", null, false },
{ "hs l(420, 10, 10)", null, false },
{ "hsl(100, 0, 5,0)", null, false },
{ "hsla(200, 50, 0)", null, false },
{ "hsl(0,0,0", null, false }, { "rgb\\(\\.*", null, false },
{ "hsl(\\.*)", null, false }, { "#\\d.*", null, false },
{ "", null, false } };
ArrayList<Object[]> values = new ArrayList<>();
Collections.addAll(values, validValues);
Collections.addAll(values, invalidValues);

return values;
}

@Test
public void testHSLData() {
Matcher m = ColorUtil.HSL_PATTERN.matcher(input);
boolean matches = m.matches();
if (expectedMatches) {
Color c1 = ColorUtil.getHSLPatternColor(m);
assertTrue(expectedColor.equals(c1));
} else {
assertTrue(!matches);
}
}

}

+ 76
- 0
server/src/test/java/com/vaadin/tests/server/component/colorpicker/HexPatternParsingTest.java View File

@@ -0,0 +1,76 @@
package com.vaadin.tests.server.component.colorpicker;

import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.ui.components.colorpicker.ColorUtil;

@RunWith(value = Parameterized.class)
public class HexPatternParsingTest {

@Parameter(value = 0)
public String input;

@Parameter(value = 1)
public int expectedRed;
@Parameter(value = 2)
public int expectedGreen;
@Parameter(value = 3)
public int expectedBlue;

@Parameter(value = 4)
public boolean expectedMatches;

@Parameters(name = "{index}: textValidHEX({0}) = ({1},{2},{3},{4})")
public static Collection<Object[]> hexdata() {
Object[][] validValues = { { "#000000", 0, 0, 0, true },
{ "#ffffff", 255, 255, 255, true },
{ "#FF00ff", 255, 0, 255, true }, { "#aa90e3",170,144,227, true },
{ "#016953", 1, 105, 83, true },
{ "#bC64D0", 188, 100, 208, true },
{ "#F100FF", 241, 0, 255, true },
{ "#F0E9a5", 240, 233, 165, true },
{ "#990077", 153, 0, 119, true } };
Object[][] invalidValues = { { "#0000000", 0, 0, 0, false },
{ "#ffgfff", 0, 0, 0, false }, { "#FF10f", 0, 0, 0, false },
{ "#aa9", 0, 0, 0, false }, { "#03", 0, 0, 0, false },
{ "#aab3c4c", 0, 0, 0, false }, { "#6010", 0, 0, 0, false },
{ "#CCCC", 0, 0, 0, false }, { "#9", 0, 0, 0, false },
{ "#10 10 10", 0, 0, 0, false }, { "101010", 0, 0, 0, false },
{ "#10101q", 0, 0, 0, false },
{ "\\s%\\d[0-9]", 0, 0, 0, false },
{ "#\\d.*", 0, 0, 0, false }, { "rgb\\(\\.*", 0, 0, 0, false },
{ "#\\d\\d\\d", 0, 0, 0, false }, { "#\\d.*", 0, 0, 0, false },
{ "", 0, 0, 0, false }, { "hsl(25,25,25)", 0, 0, 0, false } };
ArrayList<Object[]> values = new ArrayList<>();
Collections.addAll(values, validValues);
Collections.addAll(values, invalidValues);

return values;
}

@Test
public void testValidHEX() {
Matcher m = ColorUtil.HEX_PATTERN.matcher(input);
boolean matches = m.matches();
if (expectedMatches) {
Color c = new Color(expectedRed, expectedGreen, expectedBlue);
Color c1 = ColorUtil.getHexPatternColor(m);
assertTrue(c.equals(c1));
} else {
assertTrue(!matches);
}
}

}

+ 92
- 0
server/src/test/java/com/vaadin/tests/server/component/colorpicker/RGBAPatternParsingTest.java View File

@@ -0,0 +1,92 @@
package com.vaadin.tests.server.component.colorpicker;

import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.ui.components.colorpicker.ColorUtil;

@RunWith(value = Parameterized.class)
public class RGBAPatternParsingTest {

@Parameter(value = 0)
public String input;

@Parameter(value = 1)
public int expectedRed;
@Parameter(value = 2)
public int expectedGreen;
@Parameter(value = 3)
public int expectedBlue;
@Parameter(value = 4)
public int expectedAlpha;

@Parameter(value = 5)
public boolean expectedMatches;

@Parameters(name = "{index}: testRGBAData({0}) = ({1},{2},{3},{4},{5})")
public static Collection<Object[]> rgbdata() {
Object[][] validValues = { { "rgba(0,0,0,0)", 0, 0, 0, 0, true },
{ "RGBA(0, 0, 0, 0 )", 0, 0, 0, 0, true },
{ "rgba(0 0 0 0.00)", 0, 0, 0, 0, true },
{ "rgba(1 1 1 1.00)", 1, 1, 1, 255, true },
{ "rgba(0 100 200 0.50)", 0, 100, 200, 127, true },
{ "rgba(255,255,255,1.0)", 255, 255, 255, 255, true },
{ "rgba(255, 255, 255, 1.0)", 255, 255, 255, 255, true },
{ "rgba(255 255 255 0)", 255, 255, 255, 0, true },
{ "rgba(1, 10, 100, 0.00)", 1, 10, 100, 0, true } };
Object[][] invalidValues = { { "rgba(256,0,0,0)", 0, 0, 0, 0, false },
{ "rgba(0, 256, 0, -0 )", 0, 0, 0, 0, false },
{ "rgba(0,0,10.0, 00)", 0, 0, 0, 0, false },
{ "rgba(0 0 0 2.00)", 0, 0, 0, 0, false },
{ "rgba(0 -99 0 0.50)", 0, 0, 0, 0, false },
{ "rgba(0,255%,255,1.0)", 0, 0, 0, 0, false },
{ "rgba(255, 255, 255, 1.05)", 0, 0, 0, 0, false },
{ "rgba(255, 255, 255, 1.50)", 0, 0, 0, 0, false },
{ "rgb a(255 255 0.005)", 0, 0, 0, 0, false },
{ "rgba(163, 256, 1000, 0.24)", 0, 0, 0, 0, false },
{ "rgba(100, 0.5, 250, 0.8)", 0, 0, 0, 0, false },
{ "rgba(, 50, 0, 0.6)", 0, 0, 0, 0, false },
{ "rgba(200, 50, 0, 10.6)", 0, 0, 0, 0, false },
{ "rgba 200, 50, 0, 1.", 0, 0, 0, 0, false },
{ "rgba(0,0,0,0.)", 0, 0, 0, 0, false },
{ "rgb(200, 50, 0)", 0, 0, 0, 0, false },
{ "hsla,0(10,0,0)", 0, 0, 0, 0, false },
{ "rgba(\\s.*\\d[0-9])", 0, 0, 0, 0, false },
{ "rgba(\\.*,255,255, 0)", 0, 0, 0, 0, false },
{ "#\\d.*", 0, 0, 0, 0, false }, { "", 0, 0, 0, 0, false },
{ "rgba(\\d,\\d,\\d,0.0)", 0, 0, 0, 0, false },
{ "^rgba\\( \\.*)", 0, 0, 0, 0, false } };

ArrayList<Object[]> values = new ArrayList<>();
Collections.addAll(values, validValues);
Collections.addAll(values, invalidValues);

return values;
}

@Test
public void testRGBAData() {
Matcher m = ColorUtil.RGBA_PATTERN.matcher(input);
boolean matches = m.matches();
if (expectedMatches) {
Color expectedColor = new Color(expectedRed, expectedGreen,
expectedBlue, expectedAlpha);
Color c1 = ColorUtil.getRGBAPatternColor(m);

assertTrue(expectedColor.equals(c1));
} else {
assertTrue(!matches);
}
}
}

+ 87
- 0
server/src/test/java/com/vaadin/tests/server/component/colorpicker/RGBPatternParsingTest.java View File

@@ -0,0 +1,87 @@
package com.vaadin.tests.server.component.colorpicker;

import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.ui.components.colorpicker.ColorUtil;

@RunWith(value = Parameterized.class)
public class RGBPatternParsingTest {

@Parameter(value = 0)
public String input;

@Parameter(value = 1)
public int expectedRed;
@Parameter(value = 2)
public int expectedGreen;
@Parameter(value = 3)
public int expectedBlue;

@Parameter(value = 4)
public boolean expectedMatches;

@Parameters(name = "{index}: testRGBData({0}) = ({1},{2},{3},{4})")
public static Collection<Object[]> rgbdata() {
Object[][] validValues = { { "rgb(0,0,0)", 0, 0, 0, true },
{ "rgb(0, 0, 0)", 0, 0, 0, true },
{ "rgb(0 0 0)", 0, 0, 0, true },
{ "rgb(1 1 1)", 1, 1, 1, true },
{ "rgb(0 100 255)", 0, 100, 255, true },
{ "rgb(255,255,255)", 255, 255, 255, true },
{ "RGB(255, 255, 255 )", 255, 255, 255, true },
{ "rgb(255 255 255)", 255, 255, 255, true },
{ "rgb(1, 10, 100)", 1, 10, 100, true } };
Object[][] invalidValues = { { "rgb(,0,0)", 0, 0, 0, false },
{ "rgb(0, 0, 0, )", 0, 0, 0, false },
{ "rgb(0.0,0,0)", 0, 0, 0, false },
{ "rgb( 0 0 -1 )", 0, 0, 0, false },
{ "rgb(1 00)", 0, 0, 0, false },
{ "rgb(255,255,255.)", 0, 0, 0, false },
{ "r gb(255, 256, 255)", 0, 0, 0, false },
{ "rgb( 255, 255, 256 )", 0, 0, 0, false },
{ "rgb(163, 2%, 210)", 0, 0, 0, false },
{ "rGb(000)", 0, 0, 0, false },
{ "rgb(255255255)", 0, 0, 0, false },
{ "rGBA(255,255,255)", 0, 0, 0, false },
{ "rgb 255 255 255)", 0, 0, 0, false },
{ "255, 255, 0", 0, 0, 0, false },
{ "hsl(10,0,0)", 0, 0, 0, false },
{ "\\s%\\d[0-9]", 0, 0, 0, false },
{ "rgb(\\.*,255,255)", 0, 0, 0, false },
{ "#\\d.*", 0, 0, 0, false }, { "", 0, 0, 0, false },
{ "rgb(\\d,\\d,\\d)", 0, 0, 0, false },
{ "^rgb\\( \\.*)", 0, 0, 0, false } };

ArrayList<Object[]> values = new ArrayList<>();
Collections.addAll(values, validValues);
Collections.addAll(values, invalidValues);

return values;
}

@Test
public void testRGBData() {
Matcher m = ColorUtil.RGB_PATTERN.matcher(input);
boolean matches = m.matches();
if (expectedMatches) {
Color expectedColor = new Color(expectedRed, expectedGreen,
expectedBlue);
Color c1 = ColorUtil.getRGBPatternColor(m);
assertTrue(expectedColor.equals(c1));
} else {
assertTrue(!matches);
}
}
}

+ 58
- 1
testbench-api/src/main/java/com/vaadin/testbench/elements/ColorPickerPreviewElement.java View File

@@ -15,9 +15,66 @@
*/
package com.vaadin.testbench.elements;

import java.util.List;

import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elementsbase.ServerClass;

@ServerClass("com.vaadin.ui.ColorPickerPreview")
@ServerClass("com.vaadin.ui.components.colorpicker.ColorPickerPreview")
public class ColorPickerPreviewElement extends CssLayoutElement {

/**
* Get whether TextField in ColorPickerPreview has validation errors.
*
* @return true if field has errors, false otherwise
*
* @since
*/
public boolean getColorFieldContainsErrors() {
List<WebElement> caption = findElements(
By.className("v-caption-v-colorpicker-preview-textfield"));
boolean noCaption = caption.isEmpty();
return noCaption ? noCaption
: caption.get(0).findElements(By.className("v-errorindicator"))
.isEmpty();
}

/**
* Get the value of the input element TextField in ColorPickerPreview.
*
* @return the value of the attribute 'value' of the input element
*
* @since
*/
public String getColorFieldValue() {
return getColorTextField().getAttribute("value");
}

/**
* Set value of TextField in ColorPickerPreview. Any existing value in the
* field is replaced.
*
* @param value
* text to insert
*
* @since
*/
public void setColorTextFieldValue(String value) {
// Select all text
getColorTextField().sendKeys(Keys.chord(Keys.CONTROL, "a"));
getColorTextField().sendKeys(value);
}

/**
* @return <code>WebElement</code> representing TextField in
* ColorPickerPreviewComponent
*
* @since
*/
public WebElement getColorTextField() {
return findElement(By.className("v-colorpicker-preview-textfield"));
}
}

+ 1
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_colorpicker.scss View File

@@ -189,6 +189,7 @@
width: 100% !important;
height: auto !important;
padding: round($v-unit-size/4);
display: inline-flex;
}

.#{$primary-stylename}-preview-textfield {

+ 474
- 0
uitest/src/main/java/com/vaadin/tests/components/colorpicker/ValoColorPickerTestUI.java View File

@@ -0,0 +1,474 @@
package com.vaadin.tests.components.colorpicker;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.imageio.ImageIO;

import com.vaadin.annotations.Widgetset;
import com.vaadin.data.HasValue.ValueChangeEvent;
import com.vaadin.server.StreamResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.AbstractColorPicker;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ColorPicker;
import com.vaadin.ui.ColorPickerArea;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;

@Widgetset("com.vaadin.DefaultWidgetSet")
public class ValoColorPickerTestUI extends AbstractTestUI {

@Override
public String getTestDescription() {
return "Vaadin 8 Valo theme ColorPicker";
}

@Override
protected Integer getTicketNumber() {
return 10802;
}

/** The foreground color. */
private Color foregroundColor = Color.BLACK; // The currently selected

/** The background color. */
private Color backgroundColor = Color.WHITE; // The currently selected

// The display box where the image is rendered
/** The display. */
private Embedded display;

private AbstractColorPicker colorpicker1;
private AbstractColorPicker colorpicker2;
private AbstractColorPicker colorpicker3;
private AbstractColorPicker colorpicker4;
private AbstractColorPicker colorpicker5;
private AbstractColorPicker colorpicker6;

private boolean rgbVisible = true;
private boolean hsvVisible = true;
private boolean swaVisible = true;
private boolean historyVisible = true;
private boolean txtfieldVisible = true;

private final CheckBox rgbBox = new CheckBox("RGB tab visible");
private final CheckBox hsvBox = new CheckBox("HSV tab visible");
private final CheckBox swaBox = new CheckBox("Swatches tab visible");
private final CheckBox hisBox = new CheckBox("History visible");
private final CheckBox txtBox = new CheckBox("CSS field visible");

/**
* This class is used to represent the preview of the color selection.
*/
public class MyImageSource implements StreamResource.StreamSource {

/** The imagebuffer. */
private ByteArrayOutputStream imagebuffer;

/** The bg color. */
private final java.awt.Color bgColor;

/** The fg color. */
private final java.awt.Color fgColor;

/**
* Instantiates a new my image source.
*
* @param fg
* the foreground
* @param bg
* the background
*/
public MyImageSource(java.awt.Color fg, java.awt.Color bg) {
fgColor = fg;
bgColor = bg;
}

/*
* Must implement this method that returns the resource as a stream.
*/
@Override
public InputStream getStream() {

/* Create an image and draw something on it. */
BufferedImage image = new BufferedImage(270, 270,
BufferedImage.TYPE_INT_RGB);
Graphics drawable = image.getGraphics();
drawable.setColor(bgColor);
drawable.fillRect(0, 0, 270, 270);
drawable.setColor(fgColor);
drawable.fillOval(25, 25, 220, 220);
drawable.setColor(java.awt.Color.blue);
drawable.drawRect(0, 0, 269, 269);
drawable.setColor(java.awt.Color.black);
drawable.drawString("r=" + String.valueOf(fgColor.getRed()) + ",g="
+ String.valueOf(fgColor.getGreen()) + ",b="
+ String.valueOf(fgColor.getBlue()), 50, 100);
drawable.drawString("r=" + String.valueOf(bgColor.getRed()) + ",g="
+ String.valueOf(bgColor.getGreen()) + ",b="
+ String.valueOf(bgColor.getBlue()), 5, 15);

try {
/* Write the image to a buffer. */
imagebuffer = new ByteArrayOutputStream();
ImageIO.write(image, "png", imagebuffer);

/* Return a stream from the buffer. */
return new ByteArrayInputStream(imagebuffer.toByteArray());
} catch (IOException e) {
return null;
}
}
}

private void setPopupVisibilities() {

rgbBox.setEnabled(!(rgbVisible && !hsvVisible && !swaVisible));
hsvBox.setEnabled(!(!rgbVisible && hsvVisible && !swaVisible));
swaBox.setEnabled(!(!rgbVisible && !hsvVisible && swaVisible));

colorpicker1.setRGBVisibility(rgbVisible);
colorpicker2.setRGBVisibility(rgbVisible);
colorpicker3.setRGBVisibility(rgbVisible);
colorpicker4.setRGBVisibility(rgbVisible);
colorpicker5.setRGBVisibility(rgbVisible);
colorpicker6.setRGBVisibility(rgbVisible);

colorpicker1.setHSVVisibility(hsvVisible);
colorpicker2.setHSVVisibility(hsvVisible);
colorpicker3.setHSVVisibility(hsvVisible);
colorpicker4.setHSVVisibility(hsvVisible);
colorpicker5.setHSVVisibility(hsvVisible);
colorpicker6.setHSVVisibility(hsvVisible);

colorpicker1.setSwatchesVisibility(swaVisible);
colorpicker2.setSwatchesVisibility(swaVisible);
colorpicker3.setSwatchesVisibility(swaVisible);
colorpicker4.setSwatchesVisibility(swaVisible);
colorpicker5.setSwatchesVisibility(swaVisible);
colorpicker6.setSwatchesVisibility(swaVisible);

colorpicker1.setHistoryVisibility(historyVisible);
colorpicker2.setHistoryVisibility(historyVisible);
colorpicker3.setHistoryVisibility(historyVisible);
colorpicker4.setHistoryVisibility(historyVisible);
colorpicker5.setHistoryVisibility(historyVisible);
colorpicker6.setHistoryVisibility(historyVisible);

colorpicker1.setTextfieldVisibility(txtfieldVisible);
colorpicker2.setTextfieldVisibility(txtfieldVisible);
colorpicker3.setTextfieldVisibility(txtfieldVisible);
colorpicker4.setTextfieldVisibility(txtfieldVisible);
colorpicker5.setTextfieldVisibility(txtfieldVisible);
colorpicker6.setTextfieldVisibility(txtfieldVisible);
}

@Override
protected void setup(VaadinRequest request) {
getLayout().setWidth("1100px");
getLayout().setHeight(null);
getLayout().addStyleName("colorpicker-mainwindow-content");

// Create an instance of the preview and add it to the window
display = new Embedded("Color preview");
display.setWidth("270px");
display.setHeight("270px");

// Add the foreground and background colorpickers to a layout
HorizontalLayout mainLayout = new HorizontalLayout();
mainLayout.addStyleName("colorpicker-mainlayout");
mainLayout.setWidth("100%");
mainLayout.setHeight(null);
mainLayout.setMargin(true);
mainLayout.setSpacing(true);
getLayout().addComponent(mainLayout);

VerticalLayout layoutLeft = new VerticalLayout();
layoutLeft.setWidth("550px");
layoutLeft.setHeight(null);
layoutLeft.setSpacing(true);

GridLayout optLayout = new GridLayout(2, 3);
optLayout.setWidth("100%");
optLayout.setHeight(null);
optLayout.setMargin(true);
optLayout.setSpacing(true);

rgbBox.setValue(rgbVisible);
rgbBox.addValueChangeListener(event -> {
rgbVisible = event.getValue();
setPopupVisibilities();
});
rgbBox.setId("rgbBox");
optLayout.addComponent(rgbBox);

hsvBox.setValue(hsvVisible);
hsvBox.addValueChangeListener(event -> {
hsvVisible = event.getValue();
setPopupVisibilities();
});
hsvBox.setId("hsvBox");
optLayout.addComponent(hsvBox);

swaBox.setValue(swaVisible);
swaBox.addValueChangeListener(event -> {
swaVisible = event.getValue();
setPopupVisibilities();
});
swaBox.setId("swaBox");
optLayout.addComponent(swaBox);

hisBox.setValue(historyVisible);
hisBox.addValueChangeListener(event -> {
historyVisible = event.getValue();
setPopupVisibilities();
});
hisBox.setId("hisBox");
optLayout.addComponent(hisBox);

txtBox.setValue(txtfieldVisible);
txtBox.addValueChangeListener(event -> {
txtfieldVisible = event.getValue();
setPopupVisibilities();
});
txtBox.setId("txtBox");
optLayout.addComponent(txtBox);

Panel optPanel = new Panel("Customize the color picker popup window",
optLayout);
layoutLeft.addComponent(optPanel);

HorizontalLayout layout1 = createHorizontalLayout();

colorpicker1 = new ColorPicker("Foreground", foregroundColor);
colorpicker1.setCaptionAsHtml(true);
colorpicker1.addValueChangeListener(this::colorChanged);
colorpicker1.setId("colorpicker1");
layout1.addComponent(colorpicker1);
layout1.setComponentAlignment(colorpicker1, Alignment.MIDDLE_CENTER);

colorpicker2 = new ColorPicker("Background", backgroundColor);
colorpicker2.addValueChangeListener(this::colorChanged);
colorpicker2.setId("colorpicker2");
layout1.addComponent(colorpicker2);
layout1.setComponentAlignment(colorpicker2, Alignment.MIDDLE_CENTER);

Panel panel1 = new Panel(
"Button-like colorpicker with current color and CSS code",
layout1);
layoutLeft.addComponent(panel1);

HorizontalLayout layout2 = createHorizontalLayout();

colorpicker3 = new ColorPicker("Foreground", foregroundColor);
colorpicker3.addValueChangeListener(this::colorChanged);
colorpicker3.setWidth("130px");
colorpicker3.setCaption("Foreground");
colorpicker3.setId("colorpicker3");
layout2.addComponent(colorpicker3);
layout2.setComponentAlignment(colorpicker3, Alignment.MIDDLE_CENTER);

colorpicker4 = new ColorPicker("Background", backgroundColor);
colorpicker4.addValueChangeListener(this::colorChanged);
colorpicker4.setWidth("130px");
colorpicker4.setCaption("Background");
colorpicker4.setId("colorpicker4");
layout2.addComponent(colorpicker4);
layout2.setComponentAlignment(colorpicker4, Alignment.MIDDLE_CENTER);

Panel panel2 = new Panel(
"Button-like colorpicker with current color and custom caption",
layout2);
layoutLeft.addComponent(panel2);

HorizontalLayout layout3 = createHorizontalLayout();

colorpicker5 = new ColorPickerArea("Foreground", foregroundColor);
colorpicker5.setCaption("Foreground");
colorpicker5.addValueChangeListener(this::colorChanged);
colorpicker5.setId("colorpicker5");
layout3.addComponent(colorpicker5);
layout3.setComponentAlignment(colorpicker5, Alignment.MIDDLE_CENTER);

colorpicker6 = new ColorPickerArea("Background", backgroundColor);
colorpicker6.setCaption("Background");
colorpicker6.setDefaultCaptionEnabled(false);
colorpicker6.addValueChangeListener(this::colorChanged);
colorpicker6.setId("colorpicker6");
layout3.addComponent(colorpicker6);
layout3.setComponentAlignment(colorpicker6, Alignment.MIDDLE_CENTER);

Panel panel3 = new Panel("Color area colorpicker with caption",
layout3);
panel3.setWidth("100%");
panel3.setHeight(null);
layoutLeft.addComponent(panel3);

Label divider1 = new Label("<hr>", ContentMode.HTML);
layoutLeft.addComponent(divider1);

Label divider2 = new Label("<hr>", ContentMode.HTML);
layoutLeft.addComponent(divider2);

HorizontalLayout layout4 = createHorizontalLayout();

addShadeButton(new Color(Integer.parseInt("000000", 16)), layout4);
addShadeButton(new Color(Integer.parseInt("333333", 16)), layout4);
addShadeButton(new Color(Integer.parseInt("666666", 16)), layout4);
addShadeButton(new Color(Integer.parseInt("999999", 16)), layout4);
addShadeButton(new Color(Integer.parseInt("cccccc", 16)), layout4);
addShadeButton(new Color(Integer.parseInt("ffffff", 16)), layout4);

Panel panel4 = new Panel(
"Button-like colorpickers with disabled caption (no effect on fg/bg colors)",
layout4);
layoutLeft.addComponent(panel4);

HorizontalLayout layout5 = createHorizontalLayout();

addShadeArea(new Color(Integer.parseInt("000000", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("111111", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("222222", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("333333", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("444444", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("555555", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("666666", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("777777", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("888888", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("999999", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("aaaaaa", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("bbbbbb", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("cccccc", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("dddddd", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("eeeeee", 16)), layout5);
addShadeArea(new Color(Integer.parseInt("ffffff", 16)), layout5);

Panel panel5 = new Panel(
"Area colorpickers with no given caption (no effect on fg/bg colors)",
layout5);
layoutLeft.addComponent(panel5);

mainLayout.addComponent(layoutLeft);

mainLayout.addComponent(display);

updateDisplay(foregroundColor, backgroundColor);
}

private HorizontalLayout createHorizontalLayout() {
HorizontalLayout layout = new HorizontalLayout();
layout.setWidth("100%");
layout.setHeight(null);
layout.setMargin(true);
return layout;
}

private int shadeButtonCounter = 1;

private void addShadeButton(Color color, HorizontalLayout layout) {
AbstractColorPicker colorPicker = new ColorPicker(color.toString(),
color);
colorPicker.setDefaultCaptionEnabled(false);
colorPicker.setWidth("41px");
colorPicker.setId("shadebutton_" + shadeButtonCounter);
layout.addComponent(colorPicker);
layout.setComponentAlignment(colorPicker, Alignment.MIDDLE_CENTER);

++shadeButtonCounter;
}

private int shadeAreaCounter = 1;

private void addShadeArea(Color color, HorizontalLayout layout) {
AbstractColorPicker colorPicker = new ColorPickerArea(color.toString(),
color);
colorPicker.setWidth("20px");
colorPicker.setHeight("20px");
colorPicker.setId("shadearea_" + shadeAreaCounter);
layout.addComponent(colorPicker);
layout.setComponentAlignment(colorPicker, Alignment.MIDDLE_CENTER);

++shadeAreaCounter;
}

// This is called whenever a colorpicker popup is closed
/**
* Update display.
*
* @param fg
* the fg
* @param bg
* the bg
*/
public void updateDisplay(Color fg, Color bg) {
java.awt.Color awtFg = new java.awt.Color(fg.getRed(), fg.getGreen(),
fg.getBlue());
java.awt.Color awtBg = new java.awt.Color(bg.getRed(), bg.getGreen(),
bg.getBlue());
StreamResource.StreamSource imagesource = new MyImageSource(awtFg,
awtBg);

Date now = new Date();
SimpleDateFormat format = new SimpleDateFormat("hhmmss");

StreamResource imageresource = new StreamResource(imagesource,
"myimage" + format.format(now) + ".png");
imageresource.setCacheTime(0);

display.setSource(imageresource);
}

private void colorChanged(ValueChangeEvent<Color> event) {
if (event.getSource() == colorpicker1
|| event.getSource() == colorpicker3
|| event.getSource() == colorpicker5) {
foregroundColor = event.getValue();

if (event.getSource() != colorpicker1) {
colorpicker1.setValue(event.getValue());
}
if (event.getSource() != colorpicker3) {
colorpicker3.setValue(event.getValue());
}
if (event.getSource() != colorpicker5) {
colorpicker5.setValue(event.getValue());
}

} else if (event.getSource() == colorpicker2
|| event.getSource() == colorpicker4
|| event.getSource() == colorpicker6) {
backgroundColor = event.getValue();

if (event.getSource() != colorpicker2) {
colorpicker2.setValue(event.getValue());
}
if (event.getSource() != colorpicker4) {
colorpicker4.setValue(event.getValue());
}
if (event.getSource() != colorpicker6) {
colorpicker6.setValue(event.getValue());
}

} else {
return;
}

updateDisplay(foregroundColor, backgroundColor);
}

}

+ 166
- 0
uitest/src/test/java/com/vaadin/tests/components/colorpicker/ValoColorPickerInputFormatsTest.java View File

@@ -0,0 +1,166 @@
package com.vaadin.tests.components.colorpicker;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;

import com.vaadin.testbench.elements.ColorPickerElement;
import com.vaadin.testbench.elements.ColorPickerPreviewElement;
import com.vaadin.testbench.parallel.Browser;
import com.vaadin.tests.tb3.MultiBrowserTest;

/**
* Test legal color values according to
* http://www.w3schools.com/cssref/css_colors_legal.asp
*/
public class ValoColorPickerInputFormatsTest extends MultiBrowserTest {

@Override
public List<DesiredCapabilities> getBrowsersToTest() {
// Ignoring Phantom JS
return getBrowserCapabilities(Browser.IE11, Browser.FIREFOX,
Browser.CHROME);
}

private ColorPickerPreviewElement previewElement;

@Before
public void setUp() {
openTestURL();
getPreviewElement();
}

private void getPreviewElement() {
ColorPickerElement cpElement = $(ColorPickerElement.class)
.id("colorpicker1");
// Open ColorPicker
cpElement.click();
// Find preview element
previewElement = $(ColorPickerPreviewElement.class).first();
}

@Override
protected Class<?> getUIClass() {
return ValoColorPickerTestUI.class;
}

@Test
public void testRGBValue() throws Exception {
setColorpickerValue("rgb(100 100 100)");

assertEquals("#646464", previewElement.getColorFieldValue());
}

@Test
public void testRGBAValue() {
setColorpickerValue("rgba(100,100,100, 0.5)");

assertEquals("#646464", previewElement.getColorFieldValue());
}

@Test
public void testHSLValue() {
setColorpickerValue("hsl(120,100%, 50%)");

assertEquals("#00ff00", previewElement.getColorFieldValue());
}

@Test
public void testHSLAValue() {
setColorpickerValue("hsla(120, 0, 50%, 0.3)");

assertEquals("#00ff00", previewElement.getColorFieldValue());
}

@Test
public void testHexTextInputValidation() {
// set valid hex value to ColorTextField
setColorpickerValue("#AAbb33");
assertFalse(previewElement.getColorFieldContainsErrors());
}

@Test
public void testRGBTextInputValidation() {
String rgbString = "rgb(255 10 0)";
// set valid rgb value to ColorTextField
setColorpickerValue(rgbString);
assertFalse(previewElement.getColorFieldContainsErrors());
}

@Test
public void testHSLTextInputValidation() {
String hslString = "HSL(300, 60, 100)";
setColorpickerValue(hslString);
assertFalse(previewElement.getColorFieldContainsErrors());
}

@Test
public void testHexTextInputValidationError() {
// set invalid hex value to ColorTextField
setColorpickerValue("#xyz");
assertTrue(previewElement.getColorFieldContainsErrors());
}

@Test
public void testRGBTextInputValidationError() {
String rgbString = "rgb(300, 60, 90)";
// set invalid rgb value to ColorTextField
setColorpickerValue(rgbString);
assertTrue(previewElement.getColorFieldContainsErrors());
}

@Test
public void testRGBATextInputValidationError() {
String rgbaString = "rgba(250, 0, 10, 6.0)";
// set invalid rgba value to ColorTextField
setColorpickerValue(rgbaString);
assertTrue(previewElement.getColorFieldContainsErrors());
}

@Test
public void testHSLTextInputValidationError() {
String hslString = "hsl(370,60%,120%)";
// set invalid hsl value to ColorTextField
setColorpickerValue(hslString);
assertTrue(previewElement.getColorFieldContainsErrors());
}

@Test
public void testHSLATextInputValidationError() {
String hslaString = "hsla(300, 50, 10, 1.1)";
// set invalid hsla value to ColorTextField
setColorpickerValue(hslaString);
assertTrue(previewElement.getColorFieldContainsErrors());
}

@Test
public void testFailedValidationResult() {
// set invalid hex value to ColorTextField
setColorpickerValue("#xyz");
// verify there are errors
assertTrue(previewElement.getColorFieldContainsErrors());
// verify value has not been changed
assertEquals(previewElement.getColorFieldValue(), "#xyz");
}

private void setColorpickerValue(String value) {
WebElement field = previewElement.getColorTextField();

// Select all text
field.sendKeys(Keys.chord(Keys.CONTROL, "a"));

// Replace with new value
field.sendKeys(value);

// Submit
field.sendKeys(Keys.RETURN);
}
}

Loading…
Cancel
Save