diff options
114 files changed, 4307 insertions, 1439 deletions
diff --git a/.classpath b/.classpath index ccbd35cffb..62c06df6c8 100644 --- a/.classpath +++ b/.classpath @@ -6,6 +6,7 @@ <classpathentry kind="src" path="client/src"/> <classpathentry kind="src" path="server/src"/> <classpathentry kind="src" path="client-compiler/src"/> + <classpathentry kind="src" path="client-compiler/tests/src"/> <classpathentry kind="src" path="uitest/src"/> <classpathentry kind="src" path="buildhelpers/src"/> <classpathentry kind="src" path="shared/src"/> diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml index 7d86cf7cc2..268fe1ea66 100644 --- a/WebContent/WEB-INF/web.xml +++ b/WebContent/WEB-INF/web.xml @@ -24,8 +24,11 @@ <param-name>application</param-name> <param-value>com.vaadin.tests.components.button.Buttons</param-value> </init-param> + <init-param> + <param-name>org.atmosphere.cpr.scanClassPath</param-name> + <param-value>false</param-value> + </init-param> <async-supported>true</async-supported> - <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>Embed App 2</servlet-name> @@ -34,8 +37,11 @@ <param-name>UI</param-name> <param-value>com.vaadin.tests.components.label.MarginsInLabels</param-value> </init-param> + <init-param> + <param-name>org.atmosphere.cpr.scanClassPath</param-name> + <param-value>false</param-value> + </init-param> <async-supported>true</async-supported> - <load-on-startup>2</load-on-startup> </servlet> <servlet> <servlet-name>UI provider app</servlet-name> @@ -48,8 +54,11 @@ <param-name>UI</param-name> <param-value>com.vaadin.tests.VerifyAssertionsEnabled</param-value> </init-param> + <init-param> + <param-name>org.atmosphere.cpr.scanClassPath</param-name> + <param-value>false</param-value> + </init-param> <async-supported>true</async-supported> - <load-on-startup>3</load-on-startup> </servlet> <servlet> @@ -61,6 +70,10 @@ <param-value>false</param-value> </init-param> <init-param> + <param-name>org.atmosphere.cpr.scanClassPath</param-name> + <param-value>false</param-value> + </init-param> + <init-param> <param-name>heartbeatInterval</param-name> <param-value>301</param-value> </init-param> @@ -77,7 +90,6 @@ <param-value>42</param-value> </init-param> <async-supported>true</async-supported> - <load-on-startup>4</load-on-startup> </servlet> <servlet> @@ -88,7 +100,10 @@ --> <servlet-name>VaadinApplicationRunnerWithTimeoutRedirect</servlet-name> <servlet-class>com.vaadin.launcher.ApplicationRunnerServlet</servlet-class> - <load-on-startup>5</load-on-startup> + <init-param> + <param-name>org.atmosphere.cpr.scanClassPath</param-name> + <param-value>false</param-value> + </init-param> </servlet> <servlet> @@ -99,7 +114,10 @@ <param-value>automatic</param-value> </init-param> <async-supported>true</async-supported> - <load-on-startup>6</load-on-startup> + <init-param> + <param-name>org.atmosphere.cpr.scanClassPath</param-name> + <param-value>false</param-value> + </init-param> </servlet> <!-- For testing GAE - the deployment script changes this to use GAEVaadinServlet --> @@ -111,7 +129,10 @@ <param-value>com.vaadin.tests.integration.ServletIntegrationUI</param-value> </init-param> <async-supported>true</async-supported> - <load-on-startup>7</load-on-startup> + <init-param> + <param-name>org.atmosphere.cpr.scanClassPath</param-name> + <param-value>false</param-value> + </init-param> </servlet> <servlet-mapping> <servlet-name>Embed App 1</servlet-name> @@ -149,7 +170,7 @@ </servlet-mapping> <servlet-mapping> - <servlet-name>IntegrationTest</servlet-name> + <servlet-name>VaadinApplicationRunner</servlet-name> <url-pattern>/VAADIN/*</url-pattern> </servlet-mapping> diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java index cc1841ec05..5519dd1aae 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -48,6 +48,7 @@ import com.vaadin.client.JsArrayObject; import com.vaadin.client.ServerConnector; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.metadata.ConnectorBundleLoader; +import com.vaadin.client.metadata.ConnectorBundleLoader.CValUiInfo; import com.vaadin.client.metadata.InvokationHandler; import com.vaadin.client.metadata.OnStateChangeMethod; import com.vaadin.client.metadata.ProxyHandler; @@ -70,6 +71,9 @@ import com.vaadin.shared.communication.ClientRpc; import com.vaadin.shared.communication.ServerRpc; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.Connect.LoadStyle; +import com.vaadin.tools.CvalAddonsChecker; +import com.vaadin.tools.CvalChecker; +import com.vaadin.tools.CvalChecker.InvalidCvalException; public class ConnectorBundleLoaderFactory extends Generator { /** @@ -211,6 +215,8 @@ public class ConnectorBundleLoaderFactory extends Generator { } + private CvalAddonsChecker cvalChecker = new CvalAddonsChecker(); + @Override public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException { @@ -231,7 +237,6 @@ public class ConnectorBundleLoaderFactory extends Generator { logger.log(Type.ERROR, getClass() + " failed", e); throw new UnableToCompleteException(); } - } private void generateClass(TreeLogger logger, GeneratorContext context, @@ -243,6 +248,23 @@ public class ConnectorBundleLoaderFactory extends Generator { return; } + List<CValUiInfo> cvalInfos = null; + try { + if (cvalChecker != null) { + cvalInfos = cvalChecker.run(); + // Don't run twice + cvalChecker = null; + } + } catch (InvalidCvalException e) { + System.err.println("\n\n\n\n" + CvalChecker.LINE); + for (String line : e.getMessage().split("\n")) { + System.err.println(line); + } + System.err.println(CvalChecker.LINE + "\n\n\n\n"); + System.exit(1); + throw new UnableToCompleteException(); + } + List<ConnectorBundle> bundles = buildBundles(logger, context.getTypeOracle()); @@ -364,6 +386,18 @@ public class ConnectorBundleLoaderFactory extends Generator { w.println("});"); } + if (cvalInfos != null && !cvalInfos.isEmpty()) { + w.println("{"); + for (CValUiInfo c : cvalInfos) { + if ("evaluation".equals(c.type)) { + w.println("cvals.add(new CValUiInfo(\"" + c.product + + "\", \"" + c.version + "\", \"" + c.widgetset + + "\", null));"); + } + } + w.println("}"); + } + w.outdent(); w.println("}"); @@ -1101,7 +1135,7 @@ public class ConnectorBundleLoaderFactory extends Generator { * {@link ServerConnector} that have a @{@link Connect} annotation. It also * checks that multiple connectors aren't connected to the same server-side * class. - * + * * @param logger * the logger to which information can be logged * @param typeOracle diff --git a/client-compiler/src/com/vaadin/tools/CvalAddonsChecker.java b/client-compiler/src/com/vaadin/tools/CvalAddonsChecker.java new file mode 100644 index 0000000000..6780b1bc75 --- /dev/null +++ b/client-compiler/src/com/vaadin/tools/CvalAddonsChecker.java @@ -0,0 +1,191 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tools; + +import static com.vaadin.tools.CvalChecker.LINE; +import static com.vaadin.tools.CvalChecker.computeMajorVersion; +import static com.vaadin.tools.CvalChecker.getErrorMessage; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import com.vaadin.client.metadata.ConnectorBundleLoader.CValUiInfo; +import com.vaadin.tools.CvalChecker.CvalInfo; +import com.vaadin.tools.CvalChecker.CvalServer; +import com.vaadin.tools.CvalChecker.InvalidCvalException; +import com.vaadin.tools.CvalChecker.UnreachableCvalServerException; + +/** + * This class is able to visit all MANIFEST.MF files present in the classpath, + * filter by name, and check if the user has a valid license. + * + * Manifest files should have a few attributes indicating the license type of + * the addon: + * <ul> + * <li>Implementation-Version: 4.x.x + * <li>AdVaaName: addon_name + * <li>AdVaaLicen: cval, agpl, empty + * <li>AdVaaPkg: package of the widgets in this addon + * </ul> + * + * The class also have a method to check just one product. + */ +public final class CvalAddonsChecker { + + // Manifest attributes + public static final String VAADIN_ADDON_LICENSE = "AdVaaLicen"; + public static final String VAADIN_ADDON_NAME = "AdVaaName"; + public static final String VAADIN_ADDON_WIDGETSET = "Vaadin-Widgetsets"; + public static final String VAADIN_ADDON_VERSION = "Implementation-Version"; + public static final String VAADIN_ADDON_TITLE = "Implementation-Title"; + + // License types + public static final String VAADIN_AGPL = "agpl"; + public static final String VAADIN_CVAL = "cval"; + + private CvalChecker cvalChecker = new CvalChecker(); + private String filterPattern; + + /** + * The constructor. + */ + public CvalAddonsChecker() { + setLicenseProvider(new CvalServer()); + setFilter(".*vaadin.*"); + } + + /** + * Visit all MANIFEST.MF files in the classpath validating licenses. + * + * Return a list of Cval licensed products in order to have enough info to + * generate nag messages in the UI. + */ + public List<CValUiInfo> run() throws InvalidCvalException { + List<CValUiInfo> ret = new ArrayList<CValUiInfo>(); + try { + // Visit all MANIFEST in our classpath + Enumeration<URL> manifests = Thread.currentThread() + .getContextClassLoader() + .getResources(JarFile.MANIFEST_NAME); + while (manifests.hasMoreElements()) { + try { + URL url = manifests.nextElement(); + // Discard manifests whose name does not match the filter + // pattern + if (!url.getPath().matches(filterPattern)) { + continue; + } + InputStream is = url.openStream(); + // Should never happen, but we don't want a NPE here + if (is == null) { + continue; + } + // Read manifest attributes + Manifest manifest = new Manifest(is); + Attributes attribs = manifest.getMainAttributes(); + String license = attribs.getValue(VAADIN_ADDON_LICENSE); + String name = attribs.getValue(VAADIN_ADDON_NAME); + String vers = attribs.getValue(VAADIN_ADDON_VERSION) == null ? "" + : attribs.getValue(VAADIN_ADDON_VERSION); + String title = attribs.getValue(VAADIN_ADDON_TITLE) == null ? name + : attribs.getValue(VAADIN_ADDON_TITLE); + + String widgetsets = attribs + .getValue(VAADIN_ADDON_WIDGETSET) == null ? name + : attribs.getValue(VAADIN_ADDON_WIDGETSET); + + if (name == null || license == null) { + continue; + } + if (VAADIN_AGPL.equals(license)) { + // For agpl version we print an info message + printAgplLicense(title, vers); + } else if (VAADIN_CVAL.equals(license)) { + // We only check cval licensed products + CvalInfo info; + try { + info = cvalChecker.validateProduct(name, vers, + title); + printValidLicense(info, title, vers); + } catch (UnreachableCvalServerException e) { + info = CvalChecker.parseJson("{'product':{'name':'" + + name + "'}}"); + printServerUnreachable(title, vers); + } + for (String w : widgetsets.split("[, ]+")) { + ret.add(new CValUiInfo(title, String + .valueOf(computeMajorVersion(vers)), w, + info.getType())); + } + } + } catch (IOException ignored) { + } + } + } catch (IOException ignored) { + } + return ret; + } + + /** + * Set the filter regexp of .jar names which we have to consider. + * + * default is '.*touchkit.*' + */ + public CvalAddonsChecker setFilter(String regexp) { + filterPattern = regexp; + return this; + } + + /* + * Change the license provider, only used in tests. + */ + protected CvalAddonsChecker setLicenseProvider(CvalServer p) { + cvalChecker.setLicenseProvider(p); + return this; + } + + private void printAgplLicense(String name, String version) { + System.out.println(LINE + "\n" + + getErrorMessage("agpl", name, computeMajorVersion(version)) + + "\n" + LINE); + } + + private void printServerUnreachable(String name, String version) { + System.out.println(LINE + + "\n" + + getErrorMessage("unreachable", name, + computeMajorVersion(version)) + "\n" + LINE); + } + + private void printValidLicense(CvalInfo info, String title, String version) { + String msg = info.getMessage(); + if (msg == null) { + String key = "evaluation".equals(info.getType()) ? "evaluation" + : "valid"; + msg = getErrorMessage(key, title, computeMajorVersion(version), + info.getLicensee()); + } + System.out.println("\n" + LINE + "\n" + msg + "\n" + LINE + "\n"); + } +} diff --git a/client-compiler/src/com/vaadin/tools/CvalChecker.java b/client-compiler/src/com/vaadin/tools/CvalChecker.java new file mode 100644 index 0000000000..5ad44a70f8 --- /dev/null +++ b/client-compiler/src/com/vaadin/tools/CvalChecker.java @@ -0,0 +1,488 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tools; + +import static java.lang.Integer.parseInt; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.prefs.Preferences; + +import org.apache.commons.io.IOUtils; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * This class is able to validate the vaadin CVAL license. + * + * It reads the developer license file and asks the server to validate the + * licenseKey. If the license is invalid it throws an exception with the + * information about the problem and the server response. + */ +public final class CvalChecker { + + /* + * Class used for binding the JSON gotten from server. + * + * It is not in a separate f le, so as it is easier to copy into any product + * which does not depend on vaadin core. + * + * We are using org.json in order not to use additional dependency like + * auto-beans, gson, etc. + */ + public static class CvalInfo { + + public static class Product { + private JSONObject o; + + public Product(JSONObject o) { + this.o = o; + } + + public String getName() { + return get(o, "name", String.class); + } + + public Integer getVersion() { + return get(o, "version", Integer.class); + } + } + + @SuppressWarnings("unchecked") + private static <T> T get(JSONObject o, String k, Class<T> clz) { + Object ret = null; + try { + if (clz == String.class) { + ret = o.getString(k); + } else if (clz == JSONObject.class) { + ret = o.getJSONObject(k); + } else if (clz == Integer.class) { + ret = o.getInt(k); + } else if (clz == Date.class) { + ret = new Date(o.getLong(k)); + } else if (clz == Boolean.class) { + ret = o.getBoolean(k); + } + } catch (JSONException e) { + } + return (T) ret; + } + + private static <T> T put(JSONObject o, String k, Object v) { + try { + o.put(k, v); + } catch (JSONException e) { + } + return null; + } + + private JSONObject o; + + private Product product; + + public CvalInfo(JSONObject o) { + this.o = o; + product = new Product(get(o, "product", JSONObject.class)); + } + + public Boolean getExpired() { + return get(o, "expired", Boolean.class); + } + + public Date getExpiredEpoch() { + return get(o, "expiredEpoch", Date.class); + } + + public String getLicensee() { + return get(o, "licensee", String.class); + } + + public String getLicenseKey() { + return get(o, "licenseKey", String.class); + } + + public String getMessage() { + return get(o, "message", String.class); + } + + public Product getProduct() { + return product; + } + + public String getType() { + return get(o, "type", String.class); + } + + public void setExpiredEpoch(Date expiredEpoch) { + put(o, "expiredEpoch", expiredEpoch.getTime()); + } + + public void setMessage(String msg) { + put(o, "message", msg); + } + + @Override + public String toString() { + return o.toString(); + } + + public boolean isLicenseExpired() { + return (getExpired() != null && getExpired()) + || (getExpiredEpoch() != null && getExpiredEpoch().before( + new Date())); + } + + public boolean isValidVersion(int majorVersion) { + return getProduct().getVersion() == null + || getProduct().getVersion() >= majorVersion; + + } + + private boolean isValidInfo(String name, String key) { + return getProduct() != null && getProduct().getName() != null + && getLicenseKey() != null + && getProduct().getName().equals(name) + && getLicenseKey().equals(key); + } + } + + /* + * The class with the method for getting json from server side. It is here + * and protected just for replacing it in tests. + */ + public static class CvalServer { + protected String licenseUrl = LICENSE_URL_PROD; + + String askServer(String productName, String productKey, int timeoutMs) + throws IOException { + String url = licenseUrl + productKey; + URLConnection con; + try { + // Send some additional info in the User-Agent string. + String ua = "Cval " + productName + " " + productKey + " " + + getFirstLaunch(); + for (String prop : Arrays.asList("java.vendor.url", + "java.version", "os.name", "os.version", "os.arch")) { + ua += " " + System.getProperty(prop, "-").replace(" ", "_"); + } + con = new URL(url).openConnection(); + con.setRequestProperty("User-Agent", ua); + con.setConnectTimeout(timeoutMs); + con.setReadTimeout(timeoutMs); + String r = IOUtils.toString(con.getInputStream()); + return r; + } catch (MalformedURLException e) { + e.printStackTrace(); + return null; + } + } + + /* + * Get the GWT firstLaunch timestamp. + */ + String getFirstLaunch() { + try { + Class<?> clz = Class + .forName("com.google.gwt.dev.shell.CheckForUpdates"); + return Preferences.userNodeForPackage(clz).get("firstLaunch", + "-"); + } catch (ClassNotFoundException e) { + return "-"; + } + } + } + + /** + * Exception thrown when the user does not have a valid cval license. + */ + public static class InvalidCvalException extends Exception { + private static final long serialVersionUID = 1L; + public final CvalInfo info; + public final String name; + public final String key; + public final String version; + public final String title; + + public InvalidCvalException(String name, String version, String title, + String key, CvalInfo info) { + super(composeMessage(title, version, key, info)); + this.info = info; + this.name = name; + this.key = key; + this.version = version; + this.title = title; + } + + static String composeMessage(String title, String version, String key, + CvalInfo info) { + String msg = ""; + int majorVers = computeMajorVersion(version); + + if (info != null && info.getMessage() != null) { + msg = info.getMessage().replace("\\n", "\n"); + } else if (info != null && info.isLicenseExpired()) { + String type = "evaluation".equals(info.getType()) ? "Evaluation license" + : "License"; + msg = getErrorMessage("expired", title, majorVers, type); + } else if (key == null) { + msg = getErrorMessage("none", title, majorVers); + } else { + msg = getErrorMessage("invalid", title, majorVers); + } + return msg; + } + } + + /** + * Exception thrown when the license server is unreachable + */ + public static class UnreachableCvalServerException extends Exception { + private static final long serialVersionUID = 1L; + public final String name; + + public UnreachableCvalServerException(String name, Exception e) { + super(e); + this.name = name; + } + } + + public static final String LINE = "----------------------------------------------------------------------------------------------------------------------"; + + static final int GRACE_DAYS_MSECS = 2 * 24 * 60 * 60 * 1000; + + private static final String LICENSE_URL_PROD = "https://tools.vaadin.com/vaadin-license-server/licenses/"; + + /* + * used in tests + */ + static void cacheLicenseInfo(CvalInfo info) { + if (info != null) { + Preferences p = Preferences.userNodeForPackage(CvalInfo.class); + if (info.toString().length() > Preferences.MAX_VALUE_LENGTH) { + // This should never happen since MAX_VALUE_LENGTH is big + // enough. + // But server could eventually send a very big message, so we + // discard it in cache and would use hard-coded messages. + info.setMessage(null); + } + p.put(info.getProduct().getName(), info.toString()); + } + } + + /* + * used in tests + */ + static void deleteCache(String productName) { + Preferences p = Preferences.userNodeForPackage(CvalInfo.class); + p.remove(productName); + } + + /** + * Given a product name returns the name of the file with the license key. + * + * Traditionally we have delivered license keys with a name like + * 'vaadin.touchkit.developer.license' but our database product name is + * 'vaadin-touchkit' so we have to replace '-' by '.' to maintain + * compatibility. + */ + static final String computeLicenseName(String productName) { + return productName.replace("-", ".") + ".developer.license"; + } + + static final int computeMajorVersion(String productVersion) { + return productVersion == null || productVersion.isEmpty() ? 0 + : parseInt(productVersion.replaceFirst("[^\\d]+.*$", "")); + } + + /* + * used in tests + */ + static CvalInfo parseJson(String json) { + if (json == null) { + return null; + } + try { + JSONObject o = new JSONObject(json); + return new CvalInfo(o); + } catch (JSONException e) { + return null; + } + } + + private CvalServer provider; + + /** + * The constructor. + */ + public CvalChecker() { + setLicenseProvider(new CvalServer()); + } + + /** + * Validate whether there is a valid license key for a product. + * + * @param productName + * for example vaadin-touchkit + * @param productVersion + * for instance 4.0.1 + * @return CvalInfo Server response or cache response if server is offline + * @throws InvalidCvalException + * when there is no a valid license for the product + * @throws UnreachableCvalServerException + * when we have license key but server is unreachable + */ + public CvalInfo validateProduct(String productName, String productVersion, + String productTitle) throws InvalidCvalException, + UnreachableCvalServerException { + String key = getDeveloperLicenseKey(productName, productVersion, + productTitle); + + CvalInfo info = null; + if (key != null && !key.isEmpty()) { + info = getCachedLicenseInfo(productName); + if (info != null && !info.isValidInfo(productName, key)) { + deleteCache(productName); + info = null; + } + info = askLicenseServer(productName, key, productVersion, info); + if (info != null && info.isValidInfo(productName, key) + && info.isValidVersion(computeMajorVersion(productVersion)) + && !info.isLicenseExpired()) { + return info; + } + } + + throw new InvalidCvalException(productName, productVersion, + productTitle, key, info); + } + + /* + * Change the license provider, only used in tests. + */ + final CvalChecker setLicenseProvider(CvalServer p) { + provider = p; + return this; + } + + private CvalInfo askLicenseServer(String productName, String productKey, + String productVersion, CvalInfo info) + throws UnreachableCvalServerException { + + int majorVersion = computeMajorVersion(productVersion); + + // If we have a valid license info here, it means that we got it from + // cache. + // We add a grace time when so as if the server is unreachable + // we allow the user to use the product. + if (info != null && info.getExpiredEpoch() != null + && !"evaluation".equals(info.getType())) { + long ts = info.getExpiredEpoch().getTime() + GRACE_DAYS_MSECS; + info.setExpiredEpoch(new Date(ts)); + } + + boolean validCache = info != null + && info.isValidInfo(productName, productKey) + && info.isValidVersion(majorVersion) + && !info.isLicenseExpired(); + + // if we have a validCache we set the timeout smaller + int timeout = validCache ? 2000 : 10000; + + try { + CvalInfo srvinfo = parseJson(provider.askServer(productName + "-" + + productVersion, productKey, timeout)); + if (srvinfo != null && srvinfo.isValidInfo(productName, productKey) + && srvinfo.isValidVersion(majorVersion)) { + // We always cache the info if it is valid although it is + // expired + cacheLicenseInfo(srvinfo); + info = srvinfo; + } + } catch (FileNotFoundException e) { + // 404 + return null; + } catch (Exception e) { + if (info == null) { + throw new UnreachableCvalServerException(productName, e); + } + } + return info; + } + + private CvalInfo getCachedLicenseInfo(String productName) { + Preferences p = Preferences.userNodeForPackage(CvalInfo.class); + String json = p.get(productName, ""); + if (!json.isEmpty()) { + CvalInfo info = parseJson(json); + if (info != null) { + return info; + } + } + return null; + } + + private String getDeveloperLicenseKey(String productName, + String productVersion, String productTitle) + throws InvalidCvalException { + String licenseName = computeLicenseName(productName); + + String key = System.getProperty(licenseName); + if (key != null && !key.isEmpty()) { + return key; + } + + try { + String dotLicenseName = "." + licenseName; + String userHome = "file://" + System.getProperty("user.home") + "/"; + for (URL url : new URL[] { new URL(userHome + dotLicenseName), + new URL(userHome + licenseName), + URL.class.getResource("/" + dotLicenseName), + URL.class.getResource("/" + licenseName) }) { + + if (url != null) { + try { + key = IOUtils.toString(url.openStream()); + if (key != null && !(key = key.trim()).isEmpty()) { + return key; + } + } catch (IOException ignored) { + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + throw new InvalidCvalException(productName, productVersion, + productTitle, null, null); + } + + static String getErrorMessage(String key, Object... pars) { + Locale loc = Locale.getDefault(); + ResourceBundle res = ResourceBundle.getBundle( + CvalChecker.class.getName(), loc); + String msg = res.getString(key); + return new MessageFormat(msg, loc).format(pars); + } +} diff --git a/client-compiler/src/com/vaadin/tools/CvalChecker.properties b/client-compiler/src/com/vaadin/tools/CvalChecker.properties new file mode 100644 index 0000000000..3f4fd52cb7 --- /dev/null +++ b/client-compiler/src/com/vaadin/tools/CvalChecker.properties @@ -0,0 +1,13 @@ +expired={2} for {0} {1} has expired. Get a valid license at vaadin.com/pro + +none=License for {0} {1} not found. Go to vaadin.com/pro for more details. + +invalid=License for {0} {1} is not valid. Get a valid license from vaadin.com/pro + +unreachable=License for {0} {1} has not been validated. Check your network connection. + +evaluation= > Using an evaluation license for {0} {1}. + +valid= > Using a valid license for {0} {1}. + +agpl=Using AGPL version of {0} {1}. Commercial licensing options available at vaadin.com/pro
\ No newline at end of file diff --git a/client-compiler/tests/src/com/vaadin/tools/CvalAddonsCheckerTest.java b/client-compiler/tests/src/com/vaadin/tools/CvalAddonsCheckerTest.java new file mode 100644 index 0000000000..1fb9413ee4 --- /dev/null +++ b/client-compiler/tests/src/com/vaadin/tools/CvalAddonsCheckerTest.java @@ -0,0 +1,184 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tools; + +import static com.vaadin.tools.CvalAddonsChecker.VAADIN_AGPL; +import static com.vaadin.tools.CvalAddonsChecker.VAADIN_CVAL; +import static com.vaadin.tools.CvalChecker.GRACE_DAYS_MSECS; +import static com.vaadin.tools.CvalChecker.computeLicenseName; +import static com.vaadin.tools.CvalChecker.deleteCache; +import static com.vaadin.tools.CvalCheckerTest.VALID_KEY; +import static com.vaadin.tools.CvalCheckerTest.addLicensedJarToClasspath; +import static com.vaadin.tools.CvalCheckerTest.cacheExists; +import static com.vaadin.tools.CvalCheckerTest.captureSystemOut; +import static com.vaadin.tools.CvalCheckerTest.productNameAgpl; +import static com.vaadin.tools.CvalCheckerTest.productNameApache; +import static com.vaadin.tools.CvalCheckerTest.productNameCval; +import static com.vaadin.tools.CvalCheckerTest.readSystemOut; +import static com.vaadin.tools.CvalCheckerTest.saveCache; +import static com.vaadin.tools.CvalCheckerTest.unreachableLicenseProvider; +import static com.vaadin.tools.CvalCheckerTest.validLicenseProvider; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.client.metadata.ConnectorBundleLoader.CValUiInfo; +import com.vaadin.tools.CvalChecker.InvalidCvalException; + +/** + * The CvalAddonsChecker test. + */ +public class CvalAddonsCheckerTest { + + CvalAddonsChecker addonChecker; + private String licenseName; + + @Before + public void setup() { + addonChecker = new CvalAddonsChecker().setLicenseProvider( + validLicenseProvider).setFilter(".*test.*"); + licenseName = computeLicenseName(productNameCval); + + deleteCache(productNameCval); + System.getProperties().remove(licenseName); + } + + @Test + public void testRunChecker() throws Exception { + // Create a product .jar with a cval license non required and add to our + // classpath + addLicensedJarToClasspath(productNameCval, VAADIN_CVAL); + // Remove other products in case other tests added them previously + addLicensedJarToClasspath(productNameAgpl, null); + addLicensedJarToClasspath(productNameApache, null); + + // No license + // -> Break compilation + System.getProperties().remove(licenseName); + addonChecker.setLicenseProvider(validLicenseProvider); + try { + addonChecker.run(); + Assert.fail(); + } catch (InvalidCvalException expected) { + } + Assert.assertFalse(cacheExists(productNameCval)); + + // We have a license that has never been validated from the server and + // we are offline + // -> Show a message on compile time (“Your license for TouchKit 4 has + // not been validated.”) + System.setProperty(licenseName, VALID_KEY); + addonChecker.setLicenseProvider(unreachableLicenseProvider); + captureSystemOut(); + addonChecker.run(); + Assert.assertTrue(readSystemOut().contains("has not been validated")); + Assert.assertFalse(cacheExists(productNameCval)); + + // Valid license has previously been validated from the server and we + // are offline + // -> Use the cached server response + System.setProperty(licenseName, VALID_KEY); + addonChecker.setLicenseProvider(validLicenseProvider); + captureSystemOut(); + addonChecker.run(); + Assert.assertTrue(cacheExists(productNameCval)); + addonChecker.setLicenseProvider(unreachableLicenseProvider); + addonChecker.run(); + + // Expired license and we are offline + // -> If it has expired less than 14 days ago, just work with no nag + // messages + System.setProperty(licenseName, VALID_KEY); + addonChecker.setLicenseProvider(unreachableLicenseProvider); + setCacheFileTs(System.currentTimeMillis() - (GRACE_DAYS_MSECS / 2), + "normal"); + captureSystemOut(); + addonChecker.run(); + + // Expired license and we are offline + // -> After 14 days, interpret it as expired license + setCacheFileTs(System.currentTimeMillis() - (GRACE_DAYS_MSECS * 2), + "normal"); + try { + addonChecker.run(); + Assert.fail(); + } catch (InvalidCvalException expected) { + } + + // Invalid evaluation license + // -> Fail compilation with a message + // "Your evaluation license for TouchKit 4 is not valid" + System.setProperty(licenseName, VALID_KEY); + addonChecker.setLicenseProvider(unreachableLicenseProvider); + setCacheFileTs(System.currentTimeMillis() - (GRACE_DAYS_MSECS / 2), + "evaluation"); + try { + addonChecker.run(); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.assertTrue(expected.getMessage().contains("expired")); + } + + // Valid evaluation license + // -> The choice on whether to show the message is generated in + // widgetset + // compilation phase. No license checks are done in application runtime. + System.setProperty(licenseName, VALID_KEY); + addonChecker.setLicenseProvider(unreachableLicenseProvider); + setCacheFileTs(System.currentTimeMillis() + GRACE_DAYS_MSECS, + "evaluation"); + List<CValUiInfo> uiInfo = addonChecker.run(); + Assert.assertEquals(1, uiInfo.size()); + Assert.assertEquals("Test " + productNameCval, uiInfo.get(0).product); + Assert.assertEquals("evaluation", uiInfo.get(0).type); + + // Valid real license + // -> Work as expected + // -> Show info message “Using TouchKit 4 license + // 312-312321-321312-3-12-312-312 + // licensed to <licensee> (1 developer license)” + System.setProperty(licenseName, VALID_KEY); + addonChecker.setLicenseProvider(validLicenseProvider); + captureSystemOut(); + addonChecker.run(); + Assert.assertTrue(readSystemOut().contains("valid")); + } + + @Test + public void validateMultipleLicenses() throws Exception { + addLicensedJarToClasspath(productNameCval, VAADIN_CVAL); + addLicensedJarToClasspath(productNameAgpl, VAADIN_AGPL); + addLicensedJarToClasspath(productNameApache, "apache"); + + // We have a valid license for all products + System.setProperty(licenseName, VALID_KEY); + captureSystemOut(); + addonChecker.run(); + String out = readSystemOut(); + Assert.assertTrue(out.contains("valid")); + Assert.assertTrue(out.contains("AGPL")); + Assert.assertTrue(cacheExists(productNameCval)); + } + + private void setCacheFileTs(long expireTs, String type) { + saveCache(productNameCval, null, false, expireTs, type); + } + +} diff --git a/client-compiler/tests/src/com/vaadin/tools/CvalAddonstCheckerUseCasesTest.java b/client-compiler/tests/src/com/vaadin/tools/CvalAddonstCheckerUseCasesTest.java new file mode 100644 index 0000000000..89c8fc1f81 --- /dev/null +++ b/client-compiler/tests/src/com/vaadin/tools/CvalAddonstCheckerUseCasesTest.java @@ -0,0 +1,217 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tools; + +import static com.vaadin.tools.CvalAddonsChecker.VAADIN_AGPL; +import static com.vaadin.tools.CvalAddonsChecker.VAADIN_CVAL; +import static com.vaadin.tools.CvalChecker.computeLicenseName; +import static com.vaadin.tools.CvalChecker.deleteCache; +import static com.vaadin.tools.CvalCheckerTest.INVALID_KEY; +import static com.vaadin.tools.CvalCheckerTest.VALID_KEY; +import static com.vaadin.tools.CvalCheckerTest.addLicensedJarToClasspath; +import static com.vaadin.tools.CvalCheckerTest.cachedPreferences; +import static com.vaadin.tools.CvalCheckerTest.captureSystemOut; +import static com.vaadin.tools.CvalCheckerTest.expiredLicenseProvider; +import static com.vaadin.tools.CvalCheckerTest.productNameAgpl; +import static com.vaadin.tools.CvalCheckerTest.productNameCval; +import static com.vaadin.tools.CvalCheckerTest.readSystemOut; +import static com.vaadin.tools.CvalCheckerTest.restoreSystemOut; +import static com.vaadin.tools.CvalCheckerTest.saveCache; +import static com.vaadin.tools.CvalCheckerTest.unreachableLicenseProvider; +import static com.vaadin.tools.CvalCheckerTest.validEvaluationLicenseProvider; +import static com.vaadin.tools.CvalCheckerTest.validLicenseProvider; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.tools.CvalChecker.CvalServer; + +/** + * Tests for Use Cases + */ +public class CvalAddonstCheckerUseCasesTest { + + enum License { + NONE, EVAL, INVALID, REAL, EVAL_EXPIRED, REAL_EXPIRED + }; + + enum Version { + AGPL, CVAL + }; + + enum Validated { + YES, NO, OLD_KEY + }; + + enum Network { + ON, OFF + }; + + enum Compile { + YES, NO + }; + + enum Cached { + YES, NO + }; + + enum Message { + AGPL("AGPL"), VALID(">.* valid"), INVALID("not valid"), NO_LICENSE( + "not found"), NO_VALIDATED("has not been validated"), EXPIRED( + "has expired"), EVALUATION("evaluation"); + + String msg; + + Message(String s) { + msg = s; + } + } + + @Test + public void testUseCases() throws Exception { + useCase(1, License.NONE, Version.AGPL, Validated.NO, Network.OFF, + Compile.YES, Cached.NO, Message.AGPL); + + useCase(2, License.NONE, Version.CVAL, Validated.NO, Network.ON, + Compile.NO, Cached.NO, Message.NO_LICENSE); + + useCase(3, License.NONE, Version.CVAL, Validated.NO, Network.OFF, + Compile.NO, Cached.NO, Message.NO_LICENSE); + + useCase(4, License.EVAL, Version.CVAL, Validated.NO, Network.ON, + Compile.YES, Cached.YES, Message.EVALUATION); + + useCase(5, License.INVALID, Version.CVAL, Validated.NO, Network.OFF, + Compile.YES, Cached.NO, Message.NO_VALIDATED); + + useCase(6, License.INVALID, Version.CVAL, Validated.NO, Network.ON, + Compile.NO, Cached.NO, Message.INVALID); + + useCase(7, License.REAL, Version.CVAL, Validated.NO, Network.ON, + Compile.YES, Cached.YES, Message.VALID); + + useCase(8, License.REAL, Version.CVAL, Validated.NO, Network.OFF, + Compile.YES, Cached.NO, Message.NO_VALIDATED); + + useCase(9, License.REAL, Version.CVAL, Validated.YES, Network.OFF, + Compile.YES, Cached.YES, Message.VALID); + + useCase(10, License.EVAL_EXPIRED, Version.CVAL, Validated.NO, + Network.ON, Compile.NO, Cached.YES, Message.EXPIRED); + + useCase(11, License.EVAL_EXPIRED, Version.CVAL, Validated.YES, + Network.OFF, Compile.NO, Cached.YES, Message.EXPIRED); + + useCase(12, License.REAL_EXPIRED, Version.CVAL, Validated.YES, + Network.OFF, Compile.NO, Cached.YES, Message.EXPIRED); + + useCase(13, License.REAL_EXPIRED, Version.CVAL, Validated.NO, + Network.ON, Compile.NO, Cached.YES, Message.EXPIRED); + + useCase(14, License.INVALID, Version.CVAL, Validated.OLD_KEY, + Network.OFF, Compile.YES, Cached.NO, Message.NO_VALIDATED); + } + + @Test + public void testMultipleLicenseUseCases() throws Exception { + addLicensedJarToClasspath("test.foo", VAADIN_CVAL); + System.setProperty(computeLicenseName("test.foo"), VALID_KEY); + + useCase(15, License.REAL, Version.CVAL, Validated.YES, Network.OFF, + Compile.YES, Cached.YES, Message.NO_VALIDATED); + + useCase(16, License.REAL, Version.CVAL, Validated.YES, Network.ON, + Compile.NO, Cached.YES, Message.INVALID); + } + + private void useCase(int number, License lic, Version ver, Validated val, + Network net, Compile res, Cached cached, Message msg) + throws Exception { + + if (ver == Version.AGPL) { + addLicensedJarToClasspath(productNameAgpl, VAADIN_AGPL); + addLicensedJarToClasspath(productNameCval, null); + } else { + addLicensedJarToClasspath(productNameAgpl, null); + addLicensedJarToClasspath(productNameCval, VAADIN_CVAL); + } + + String licenseName = computeLicenseName(productNameCval); + + if (lic == License.NONE) { + System.getProperties().remove(licenseName); + } else if (lic == License.INVALID) { + System.setProperty(licenseName, INVALID_KEY); + } else { + System.setProperty(licenseName, VALID_KEY); + } + + if (val == Validated.NO) { + deleteCache(productNameCval); + } else { + String type = lic == License.EVAL || lic == License.EVAL_EXPIRED ? "evaluation" + : null; + Boolean expired = lic == License.EVAL_EXPIRED + || lic == License.REAL_EXPIRED ? true : null; + String key = val == Validated.OLD_KEY ? "oldkey" : null; + saveCache(productNameCval, key, expired, null, type); + } + + CvalServer licenseProvider = validLicenseProvider; + if (net == Network.OFF) { + licenseProvider = unreachableLicenseProvider; + } else if (lic == License.EVAL_EXPIRED || lic == License.REAL_EXPIRED) { + licenseProvider = expiredLicenseProvider; + } else if (lic == License.EVAL) { + licenseProvider = validEvaluationLicenseProvider; + } + + CvalAddonsChecker addonChecker = new CvalAddonsChecker(); + addonChecker.setLicenseProvider(licenseProvider).setFilter(".*test.*"); + + captureSystemOut(); + + String testNumber = "Test #" + number + " "; + String message; + try { + addonChecker.run(); + message = readSystemOut(); + if (res == Compile.NO) { + Assert.fail(testNumber + "Exception not thrown:" + message); + } + } catch (Exception e) { + restoreSystemOut(); + message = e.getMessage(); + if (res == Compile.YES) { + Assert.fail(testNumber + "Unexpected Exception: " + + e.getMessage()); + } + } + + // System.err.println("\n> " + testNumber + " " + lic + " " + ver + " " + // + val + " " + net + " " + res + " " + cached + "\n" + message); + + Assert.assertTrue(testNumber + "Fail:\n" + message + + "\nDoes not match:" + msg.msg, + message.matches("(?s).*" + msg.msg + ".*")); + + String c = cachedPreferences(productNameCval); + Assert.assertTrue(testNumber + "Fail: cacheExists != " + + (cached == Cached.YES) + "\n " + c, + (c != null) == (cached == Cached.YES)); + } +} diff --git a/client-compiler/tests/src/com/vaadin/tools/CvalCheckerTest.java b/client-compiler/tests/src/com/vaadin/tools/CvalCheckerTest.java new file mode 100644 index 0000000000..51b12f4c7e --- /dev/null +++ b/client-compiler/tests/src/com/vaadin/tools/CvalCheckerTest.java @@ -0,0 +1,342 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tools; + +import static com.vaadin.tools.CvalAddonsChecker.VAADIN_ADDON_LICENSE; +import static com.vaadin.tools.CvalAddonsChecker.VAADIN_ADDON_NAME; +import static com.vaadin.tools.CvalAddonsChecker.VAADIN_ADDON_TITLE; +import static com.vaadin.tools.CvalAddonsChecker.VAADIN_ADDON_VERSION; +import static com.vaadin.tools.CvalChecker.GRACE_DAYS_MSECS; +import static com.vaadin.tools.CvalChecker.cacheLicenseInfo; +import static com.vaadin.tools.CvalChecker.deleteCache; +import static com.vaadin.tools.CvalChecker.parseJson; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.prefs.Preferences; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.tools.CvalChecker.CvalInfo; +import com.vaadin.tools.CvalChecker.CvalServer; +import com.vaadin.tools.CvalChecker.InvalidCvalException; +import com.vaadin.tools.CvalChecker.UnreachableCvalServerException; + +/** + * The CvalChecker test. + */ +public class CvalCheckerTest { + + static final String productNameCval = "test.cval"; + static final String productTitleCval = "Vaadin Test"; + static final String productNameAgpl = "test.agpl"; + static final String productTitleAgpl = "Vaadin Test"; + static final String productNameApache = "test.apache"; + static final String VALID_KEY = "valid"; + static final String INVALID_KEY = "invalid"; + + static final String responseJson = "{'licenseKey':'" + VALID_KEY + "'," + + "'licensee':'Test User','type':'normal'," + + "'expiredEpoch':'1893511225000'," + "'product':{'name':'" + + productNameCval + "', 'version': 2}}"; + + private static ByteArrayOutputStream outContent; + + // A provider returning a valid license if productKey is valid or null if + // invalid + static final CvalServer validLicenseProvider = new CvalServer() { + @Override + String askServer(String productName, String productKey, int timeout) { + return VALID_KEY.equals(productKey) ? responseJson : null; + } + }; + // A provider returning a valid evaluation license + static final CvalServer validEvaluationLicenseProvider = new CvalServer() { + @Override + String askServer(String productName, String productKey, int timeout) { + return responseJson.replace("normal", "evaluation"); + } + }; + // A provider returning an expired license with a server message + static final CvalServer expiredLicenseProviderWithMessage = new CvalServer() { + @Override + String askServer(String productName, String productKey, int timeout) { + return responseJson + .replace("'expired", + "'message':'Custom\\\\nServer\\\\nMessage','expired':true,'expired"); + } + }; + // A provider returning an expired license with a server message + static final CvalServer expiredLicenseProvider = new CvalServer() { + @Override + String askServer(String productName, String productKey, int timeout) { + return responseJson.replace("'expired", "'expired':true,'expired"); + } + }; + // A provider returning an expired epoch license + static final CvalServer expiredEpochLicenseProvider = new CvalServer() { + @Override + String askServer(String productName, String productKey, int timeout) { + long ts = System.currentTimeMillis() - GRACE_DAYS_MSECS - 1000; + return responseJson.replace("1893511225000", "" + ts); + } + }; + // A provider returning an unlimited license + static final CvalServer unlimitedLicenseProvider = new CvalServer() { + @Override + String askServer(String productName, String productKey, int timeout) { + return responseJson.replaceFirst("1893511225000", ""); + } + }; + // An unreachable provider + static final CvalServer unreachableLicenseProvider = new CvalServer() { + @Override + String askServer(String productName, String productKey, int timeout) + throws IOException { + // Normally there is no route for this ip in public routers, so we + // should get a timeout. + licenseUrl = "http://localhost:9999/"; + return super.askServer(productName, productKey, 1000); + } + }; + + private CvalChecker licenseChecker; + private String licenseName; + + @Before + public void setup() { + licenseChecker = new CvalChecker() + .setLicenseProvider(validLicenseProvider); + licenseName = CvalChecker.computeLicenseName(productNameCval); + System.getProperties().remove(licenseName); + deleteCache(productNameCval); + } + + @Test + public void testValidateProduct() throws Exception { + deleteCache(productNameCval); + + // If the license key in our environment is null, throw an exception + try { + licenseChecker.validateProduct(productNameCval, "2.1", + productTitleCval); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.assertEquals(productNameCval, expected.name); + } + Assert.assertFalse(cacheExists(productNameCval)); + + // If the license key is empty, throw an exception + System.setProperty(licenseName, ""); + try { + licenseChecker.validateProduct(productNameCval, "2.1", + productTitleCval); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.assertEquals(productNameCval, expected.name); + } + Assert.assertFalse(cacheExists(productNameCval)); + + // If license key is invalid, throw an exception + System.setProperty(licenseName, "invalid"); + try { + licenseChecker.validateProduct(productNameCval, "2.1", + productTitleCval); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.assertEquals(productNameCval, expected.name); + } + Assert.assertFalse(cacheExists(productNameCval)); + + // Fail if version is bigger + System.setProperty(licenseName, VALID_KEY); + try { + licenseChecker.validateProduct(productNameCval, "3.0", + productTitleCval); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.assertEquals(productNameCval, expected.name); + } + Assert.assertFalse(cacheExists(productNameCval)); + + // Success if license key and version are valid + System.setProperty(licenseName, VALID_KEY); + licenseChecker + .validateProduct(productNameCval, "2.1", productTitleCval); + Assert.assertTrue(cacheExists(productNameCval)); + + // Success if license and cache file are valid, although the license + // server is offline + licenseChecker.setLicenseProvider(unreachableLicenseProvider); + licenseChecker + .validateProduct(productNameCval, "2.1", productTitleCval); + Assert.assertTrue(cacheExists(productNameCval)); + + // Fail if license key changes although cache file were validated + // previously and it is ok, we are offline + try { + System.setProperty(licenseName, INVALID_KEY); + licenseChecker.validateProduct(productNameCval, "2.1", + productTitleCval); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.fail(); + } catch (UnreachableCvalServerException expected) { + Assert.assertEquals(productNameCval, expected.name); + } + Assert.assertFalse(cacheExists(productNameCval)); + + // Fail with unreachable exception if license has never verified and + // server is offline + try { + System.setProperty(licenseName, VALID_KEY); + licenseChecker.validateProduct(productNameCval, "2.1", + productTitleCval); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.fail(); + } catch (UnreachableCvalServerException expected) { + Assert.assertEquals(productNameCval, expected.name); + } + Assert.assertFalse(cacheExists(productNameCval)); + + // Fail when expired flag comes in the server response, although the + // expired is valid. + deleteCache(productNameCval); + licenseChecker.setLicenseProvider(expiredLicenseProviderWithMessage); + try { + licenseChecker.validateProduct(productNameCval, "2.1", + productTitleCval); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.assertEquals(productNameCval, expected.name); + // Check that we use server customized message if it comes + Assert.assertTrue(expected.getMessage().contains("Custom")); + } + Assert.assertTrue(cacheExists(productNameCval)); + + // Check an unlimited license + licenseChecker.setLicenseProvider(unlimitedLicenseProvider); + licenseChecker + .validateProduct(productNameCval, "2.1", productTitleCval); + Assert.assertTrue(cacheExists(productNameCval)); + + // Fail if expired flag does not come, but expired epoch is in the past + System.setProperty(licenseName, VALID_KEY); + deleteCache(productNameCval); + licenseChecker.setLicenseProvider(expiredEpochLicenseProvider); + try { + licenseChecker.validateProduct(productNameCval, "2.1", + productTitleCval); + Assert.fail(); + } catch (InvalidCvalException expected) { + Assert.assertEquals(productNameCval, expected.name); + } + Assert.assertTrue(cacheExists(productNameCval)); + } + + /* + * Creates a new .jar file with a MANIFEST.MF with all vaadin license info + * attributes set, and add the .jar to the classpath + */ + static void addLicensedJarToClasspath(String productName, String licenseType) + throws Exception { + // Create a manifest with Vaadin CVAL license + Manifest testManifest = new Manifest(); + testManifest.getMainAttributes().putValue("Manifest-Version", "1.0"); + testManifest.getMainAttributes().putValue(VAADIN_ADDON_LICENSE, + licenseType); + testManifest.getMainAttributes().putValue(VAADIN_ADDON_NAME, + productName); + testManifest.getMainAttributes().putValue(VAADIN_ADDON_TITLE, + "Test " + productName); + testManifest.getMainAttributes().putValue(VAADIN_ADDON_VERSION, "2"); + + // Create a temporary Jar + String tmpDir = System.getProperty("java.io.tmpdir"); + File testJarFile = new File(tmpDir + "vaadin." + productName + ".jar"); + testJarFile.deleteOnExit(); + JarOutputStream target = new JarOutputStream(new FileOutputStream( + testJarFile), testManifest); + target.close(); + + // Add the new jar to our classpath (use reflection) + URL url = new URL("file://" + testJarFile.getAbsolutePath()); + final Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", + new Class[] { URL.class }); + addURL.setAccessible(true); + final URLClassLoader urlClassLoader = (URLClassLoader) Thread + .currentThread().getContextClassLoader(); + addURL.invoke(urlClassLoader, new Object[] { url }); + } + + static boolean cacheExists(String productName) { + return cachedPreferences(productName) != null; + } + + static String cachedPreferences(String productName) { + // ~/Library/Preferences/com.apple.java.util.prefs.plist + // .java/.userPrefs/com/google/gwt/dev/shell/prefs.xml + // HKEY_CURRENT_USER\SOFTWARE\JavaSoft\Prefs + Preferences p = Preferences.userNodeForPackage(CvalInfo.class); + return p.get(productName, null); + } + + static void saveCache(String productName, String key, Boolean expired, + Long expireTs, String type) { + String json = responseJson.replace(productNameCval, productName); + if (expired != null && expired) { + expireTs = System.currentTimeMillis() - GRACE_DAYS_MSECS - 1000; + } + if (expireTs != null) { + json = json.replace("1893511225000", "" + expireTs); + } + if (key != null) { + json = json.replace(VALID_KEY, key); + } + if (type != null) { + json = json.replace("normal", type); + + } + cacheLicenseInfo(parseJson(json)); + } + + static void captureSystemOut() { + outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + } + + static String readSystemOut() { + restoreSystemOut(); + return outContent.toString(); + } + + static void restoreSystemOut() { + System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out))); + } +} diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 694fc71060..8bc43dda9a 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -1432,12 +1432,19 @@ public class ApplicationConnection implements HasHandlers { if (json.containsKey(ApplicationConstants.SERVER_SYNC_ID)) { int syncId = json.getInt(ApplicationConstants.SERVER_SYNC_ID); - assert (lastSeenServerSyncId == UNDEFINED_SYNC_ID || syncId == lastSeenServerSyncId + 1) : "Newly retrieved server sync id was not exactly one larger than the previous one (new: " - + syncId + ", last seen: " + lastSeenServerSyncId + ")"; + /* + * Use sync id unless explicitly set as undefined, as is done by + * e.g. critical server-side notifications + */ + if (syncId != -1) { + assert (lastSeenServerSyncId == UNDEFINED_SYNC_ID || syncId == lastSeenServerSyncId + 1) : "Newly retrieved server sync id was not exactly one larger than the previous one (new: " + + syncId + ", last seen: " + lastSeenServerSyncId + ")"; - lastSeenServerSyncId = syncId; + lastSeenServerSyncId = syncId; + } } else { - VConsole.error("Server response didn't contain an id."); + VConsole.error("Server response didn't contain a sync id. " + + "Please verify that the server is up-to-date and that the response data has not been modified in transmission."); } // Handle redirect diff --git a/client/src/com/vaadin/client/TooltipInfo.java b/client/src/com/vaadin/client/TooltipInfo.java index 06940536c8..c1dd5037eb 100644 --- a/client/src/com/vaadin/client/TooltipInfo.java +++ b/client/src/com/vaadin/client/TooltipInfo.java @@ -15,6 +15,8 @@ */ package com.vaadin.client; +import com.vaadin.shared.util.SharedUtil; + public class TooltipInfo { private String title; @@ -79,7 +81,7 @@ public class TooltipInfo { } public boolean equals(TooltipInfo other) { - return (other != null && other.title == title - && other.errorMessageHtml == errorMessageHtml && other.identifier == identifier); + return (other != null && SharedUtil.equals(other.title, title) + && SharedUtil.equals(other.errorMessageHtml, errorMessageHtml) && other.identifier == identifier); } } diff --git a/client/src/com/vaadin/client/Util.java b/client/src/com/vaadin/client/Util.java index e031b37422..f12a02c64f 100644 --- a/client/src/com/vaadin/client/Util.java +++ b/client/src/com/vaadin/client/Util.java @@ -35,6 +35,7 @@ import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.Touch; +import com.google.gwt.event.dom.client.KeyEvent; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; @@ -66,7 +67,23 @@ public class Util { }-*/; /** - * + * Helper method for a bug fix #14041. For mozilla getKeyCode return 0 for + * space bar (because space is considered as char). If return 0 use + * getCharCode. + * + * @param event + * @return return key code + */ + public static int getKeyCode(KeyEvent<?> event) { + int keyCode = event.getNativeEvent().getKeyCode(); + if (keyCode == 0) { + keyCode = event.getNativeEvent().getCharCode(); + } + return keyCode; + } + + /** + * * Returns the topmost element of from given coordinates. * * TODO fix crossplat issues clientX vs pageX. See quircksmode. Not critical diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java index 8e653a0476..d1a2c395f7 100644 --- a/client/src/com/vaadin/client/VTooltip.java +++ b/client/src/com/vaadin/client/VTooltip.java @@ -22,13 +22,13 @@ import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.DomEvent; import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.dom.client.MouseDownEvent; +import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.dom.client.MouseMoveEvent; import com.google.gwt.event.dom.client.MouseMoveHandler; import com.google.gwt.user.client.DOM; @@ -109,13 +109,13 @@ public class VTooltip extends VWindowOverlay { } private void setTooltipText(TooltipInfo info) { - if (info.getErrorMessage() != null) { + if (info.getErrorMessage() != null && !info.getErrorMessage().isEmpty()) { em.setVisible(true); em.updateMessage(info.getErrorMessage()); } else { em.setVisible(false); } - if (info.getTitle() != null && !"".equals(info.getTitle())) { + if (info.getTitle() != null && !info.getTitle().isEmpty()) { description.setInnerHTML(info.getTitle()); description.getStyle().clearDisplay(); } else { @@ -130,13 +130,7 @@ public class VTooltip extends VWindowOverlay { * */ private void showTooltip() { - boolean hasContent = false; - if (currentTooltipInfo.getErrorMessage() != null - || (currentTooltipInfo.getTitle() != null && !"" - .equals(currentTooltipInfo.getTitle()))) { - hasContent = true; - } - if (hasContent) { + if (currentTooltipInfo.hasMessage()) { // Issue #8454: With IE7 the tooltips size is calculated based on // the last tooltip's position, causing problems if the last one was // in the right or bottom edge. For this reason the tooltip is moved @@ -229,18 +223,23 @@ public class VTooltip extends VWindowOverlay { /** * For assistive tooltips to work correctly we must have the tooltip visible - * and attached to the DOM well in advance. + * and attached to the DOM well in advance. For this reason both isShowing + * and isVisible return false positives. We can't override either of them as + * external code may depend on this behavior. * - * @return + * @return boolean */ - public boolean isActuallyVisible() { - return super.isShowing() && getPopupLeft() > 0 && getPopupTop() > 0; + public boolean isTooltipOpen() { + return super.isShowing() && super.isVisible() && getPopupLeft() > 0 + && getPopupTop() > 0; } private void closeNow() { hide(); setWidth(""); closing = false; + justClosedTimer.schedule(getQuickOpenTimeout()); + justClosed = true; } private Timer showTimer = new Timer() { @@ -255,8 +254,6 @@ public class VTooltip extends VWindowOverlay { @Override public void run() { closeNow(); - justClosedTimer.schedule(getQuickOpenTimeout()); - justClosed = true; } }; @@ -279,7 +276,7 @@ public class VTooltip extends VWindowOverlay { // already about to close return; } - if (isActuallyVisible()) { + if (isTooltipOpen()) { closeTimer.schedule(getCloseTimeout()); closing = true; } @@ -331,6 +328,8 @@ public class VTooltip extends VWindowOverlay { if (closing) { closeTimer.cancel(); closeNow(); + justClosedTimer.cancel(); + justClosed = false; } showTooltip(); @@ -338,7 +337,7 @@ public class VTooltip extends VWindowOverlay { } private class TooltipEventHandler implements MouseMoveHandler, - ClickHandler, KeyDownHandler, FocusHandler, BlurHandler { + KeyDownHandler, FocusHandler, BlurHandler, MouseDownHandler { /** * Current element hovered @@ -404,7 +403,7 @@ public class VTooltip extends VWindowOverlay { } @Override - public void onClick(ClickEvent event) { + public void onMouseDown(MouseDownEvent event) { handleHideEvent(); } @@ -449,10 +448,10 @@ public class VTooltip extends VWindowOverlay { // hasn't changed, we ignore the event. // TooltipInfo contains a reference to the parent component that is // checked in it's equals-method. - if (currentElement != null && isActuallyVisible()) { - TooltipInfo currentTooltip = getTooltipFor(currentElement); + if (currentElement != null && isTooltipOpen()) { TooltipInfo newTooltip = getTooltipFor(element); - if (currentTooltip != null && currentTooltip.equals(newTooltip)) { + if (currentTooltipInfo != null + && currentTooltipInfo.equals(newTooltip)) { return; } } @@ -465,31 +464,27 @@ public class VTooltip extends VWindowOverlay { closeTimer.cancel(); closing = false; } + + if (isTooltipOpen()) { + closeNow(); + } + setTooltipText(info); updatePosition(event, isFocused); - if (isActuallyVisible() && !isFocused) { + // Schedule timer for showing the tooltip according to if it + // was recently closed or not. + int timeout = justClosed ? getQuickOpenDelay() : getOpenDelay(); + if (timeout == 0) { showTooltip(); } else { - if (isActuallyVisible()) { - closeNow(); - } - // Schedule timer for showing the tooltip according to if it - // was recently closed or not. - int timeout = justClosed ? getQuickOpenDelay() - : getOpenDelay(); - if (timeout == 0) { - showTooltip(); - } else { - showTimer.schedule(timeout); - opening = true; - } + showTimer.schedule(timeout); + opening = true; } } handledByFocus = isFocused; currentElement = element; } - } private final TooltipEventHandler tooltipEventHandler = new TooltipEventHandler(); @@ -503,7 +498,7 @@ public class VTooltip extends VWindowOverlay { public void connectHandlersToWidget(Widget widget) { Profiler.enter("VTooltip.connectHandlersToWidget"); widget.addDomHandler(tooltipEventHandler, MouseMoveEvent.getType()); - widget.addDomHandler(tooltipEventHandler, ClickEvent.getType()); + widget.addDomHandler(tooltipEventHandler, MouseDownEvent.getType()); widget.addDomHandler(tooltipEventHandler, KeyDownEvent.getType()); widget.addDomHandler(tooltipEventHandler, FocusEvent.getType()); widget.addDomHandler(tooltipEventHandler, BlurEvent.getType()); diff --git a/client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java b/client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java index 7d2078061e..846bfd4671 100644 --- a/client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java +++ b/client/src/com/vaadin/client/metadata/ConnectorBundleLoader.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -15,13 +15,35 @@ */ package com.vaadin.client.metadata; +import java.util.ArrayList; import java.util.List; import com.google.gwt.core.shared.GWT; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.ApplicationConfiguration; import com.vaadin.client.FastStringMap; import com.vaadin.client.metadata.AsyncBundleLoader.State; +import com.vaadin.client.ui.VNotification; +import com.vaadin.shared.Position; public abstract class ConnectorBundleLoader { + + public static class CValUiInfo { + public final String widgetset; + public final String product; + public final String version; + public final String type; + + public CValUiInfo(String product, String version, String widgetset, + String type) { + this.product = product; + this.version = version; + this.widgetset = widgetset; + this.type = type; + } + } + public static final String EAGER_BUNDLE_NAME = "__eager"; public static final String DEFERRED_BUNDLE_NAME = "__deferred"; @@ -113,4 +135,27 @@ public abstract class ConnectorBundleLoader { public abstract void init(); + protected List<CValUiInfo> cvals = new ArrayList<CValUiInfo>(); + + public void cval(String typeName) { + if (!cvals.isEmpty()) { + String msg = ""; + for (CValUiInfo c : cvals) { + String ns = c.widgetset.replaceFirst("\\.[^\\.]+$", ""); + if (typeName.startsWith(ns)) { + cvals.remove(c); + msg += c.product + " " + c.version + "<br/>"; + } + } + if (!msg.isEmpty()) { + // We need a widget for using VNotification, using the + // context-menu parent. Is there an easy way? + Widget w = ApplicationConfiguration.getRunningApplications() + .get(0).getContextMenu().getParent(); + VNotification n = VNotification.createNotification(0, w); + n.setWidget(new HTML("Using Evaluation License of:<br/>" + msg)); + n.show(Position.BOTTOM_RIGHT); + } + } + } } diff --git a/client/src/com/vaadin/client/metadata/Type.java b/client/src/com/vaadin/client/metadata/Type.java index cc185dff96..15617ffe3c 100644 --- a/client/src/com/vaadin/client/metadata/Type.java +++ b/client/src/com/vaadin/client/metadata/Type.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -19,6 +19,7 @@ import java.util.Collection; import com.google.gwt.core.client.JsArrayString; import com.vaadin.client.JsArrayObject; +import com.vaadin.client.ServerConnector; import com.vaadin.client.communication.JSONSerializer; public class Type { @@ -47,7 +48,11 @@ public class Type { public Object createInstance() throws NoDataException { Invoker invoker = TypeDataStore.getConstructor(this); - return invoker.invoke(null); + Object ret = invoker.invoke(null); + if (ret instanceof ServerConnector) { + ConnectorBundleLoader.get().cval(name); + } + return ret; } public Method getMethod(String name) { @@ -57,7 +62,7 @@ public class Type { /** * @return * @throws NoDataException - * + * * @deprecated As of 7.0.1, use {@link #getPropertiesAsArray()} instead for * improved performance */ @@ -96,7 +101,7 @@ public class Type { * returned string may change without notice and should not be used for any * other purpose than identification. The signature is currently based on * the fully qualified name of the type. - * + * * @return the unique signature of this type */ public String getSignature() { diff --git a/client/src/com/vaadin/client/ui/VAbstractSplitPanel.java b/client/src/com/vaadin/client/ui/VAbstractSplitPanel.java index 269db23366..6ee88d51dd 100644 --- a/client/src/com/vaadin/client/ui/VAbstractSplitPanel.java +++ b/client/src/com/vaadin/client/ui/VAbstractSplitPanel.java @@ -511,6 +511,10 @@ public class VAbstractSplitPanel extends ComplexPanel { firstChild = w; } + public Widget getFirstWidget() { + return firstChild; + } + /** For internal use only. May be removed or replaced in the future. */ public void setSecondWidget(Widget w) { if (secondChild == w) { @@ -525,6 +529,10 @@ public class VAbstractSplitPanel extends ComplexPanel { secondChild = w; } + public Widget getSecondWidget() { + return secondChild; + } + @Override public void onBrowserEvent(Event event) { switch (DOM.eventGetType(event)) { diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java index d8c96917d8..eaa2292c69 100644 --- a/client/src/com/vaadin/client/ui/VCalendarPanel.java +++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java @@ -813,14 +813,12 @@ public class VCalendarPanel extends FocusableFlexTable implements buildCalendarBody(); } - if (isTimeSelectorNeeded() && time == null) { + if (isTimeSelectorNeeded()) { time = new VTime(); setWidget(2, 0, time); getFlexCellFormatter().setColSpan(2, 0, 5); getFlexCellFormatter().setStyleName(2, 0, parent.getStylePrimaryName() + "-calendarpanel-time"); - } else if (isTimeSelectorNeeded()) { - time.updateTimes(); } else if (time != null) { remove(time); } diff --git a/client/src/com/vaadin/client/ui/VColorPickerArea.java b/client/src/com/vaadin/client/ui/VColorPickerArea.java index e581cf3448..23a9379c80 100644 --- a/client/src/com/vaadin/client/ui/VColorPickerArea.java +++ b/client/src/com/vaadin/client/ui/VColorPickerArea.java @@ -34,6 +34,7 @@ import com.google.gwt.user.client.ui.Widget; public class VColorPickerArea extends Widget implements ClickHandler, HasHTML, HasClickHandlers { + public static final String CLASSNAME = "v-colorpicker"; private String color = null; private boolean isOpen; @@ -47,6 +48,7 @@ public class VColorPickerArea extends Widget implements ClickHandler, HasHTML, public VColorPickerArea() { super(); setElement(DOM.createDiv()); + setStyleName(CLASSNAME); caption = new HTML(); caption.addStyleName("v-caption"); diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index a1de2c2b6d..7157ef99b3 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -81,7 +81,7 @@ import com.vaadin.shared.ui.combobox.FilteringMode; /** * Client side implementation of the Select component. - * + * * TODO needs major refactoring (to be extensible etc) */ @SuppressWarnings("deprecation") @@ -101,7 +101,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Constructor - * + * * @param uidl * The UIDL recieved from the server */ @@ -150,7 +150,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Get the option key which represents the item on the server side. - * + * * @return The key of the item */ public String getOptionKey() { @@ -159,7 +159,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Get the URI of the icon. Used when constructing the displayed option. - * + * * @return */ public String getIconUri() { @@ -256,7 +256,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Shows the popup where the user can see the filtered options - * + * * @param currentSuggestions * The filtered suggestions * @param currentPage @@ -342,7 +342,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Should the next page button be visible to the user? - * + * * @param active */ private void setNextButtonActive(boolean active) { @@ -362,7 +362,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Should the previous page button be visible to the user - * + * * @param active */ private void setPrevButtonActive(boolean active) { @@ -449,7 +449,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * because otherwise the waiting flag will be reset in * the first response and the second response will be * ignored, causing an empty popup... - * + * * As long as the scrolling delay is suitable * double/triple clicks will work by scrolling two or * three pages at a time and this should not be a @@ -484,7 +484,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt * .user.client.Event) @@ -521,7 +521,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * amount of items are visible at a time and a scrollbar or buttons are * visible to change page. If paging is turned of then all options are * rendered into the popup menu. - * + * * @param paging * Should the paging be turned on? */ @@ -544,7 +544,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see * com.google.gwt.user.client.ui.PopupPanel$PositionCallback#setPosition * (int, int) @@ -637,7 +637,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Was the popup just closed? - * + * * @return true if popup was just closed */ public boolean isJustClosed() { @@ -648,7 +648,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google * .gwt.event.logical.shared.CloseEvent) @@ -666,7 +666,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Updates style names in suggestion popup to help theme building. - * + * * @param uidl * UIDL for the whole combo box * @param componentState @@ -746,7 +746,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Sets the suggestions rendered in the menu - * + * * @param suggestions * The suggestions to be rendered in the menu */ @@ -941,7 +941,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * TextBox variant used as input element for filter selects, which prevents * selecting text when disabled. - * + * * @since 7.1.5 */ public class FilterSelectTextBox extends TextBox { @@ -993,7 +993,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt * .user.client.Event) @@ -1166,7 +1166,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see * com.google.gwt.user.client.ui.Composite#onBrowserEvent(com.google.gwt * .user.client.Event) @@ -1193,7 +1193,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * It is invoked during the Constructor and should only be overridden if a * custom TextBox shall be used. The overriding method cannot use any * instance variables. - * + * * @since 7.1.5 * @return TextBox instance used by this VFilterSelect */ @@ -1206,7 +1206,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * instance. It is invoked during the Constructor and should only be * overridden if a custom SuggestionPopup shall be used. The overriding * method cannot use any instance variables. - * + * * @since 7.1.5 * @return SuggestionPopup instance used by this VFilterSelect */ @@ -1234,7 +1234,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Does the Select have more pages? - * + * * @return true if a next page exists, else false if the current page is the * last page */ @@ -1249,7 +1249,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Filters the options at a certain page. Uses the text box input as a * filter - * + * * @param page * The page which items are to be filtered */ @@ -1259,7 +1259,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Filters the options at certain page using the given filter - * + * * @param page * The page to filter * @param filter @@ -1271,7 +1271,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Filters the options at certain page using the given filter - * + * * @param page * The page to filter * @param filter @@ -1336,7 +1336,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Sets the text in the text box. - * + * * @param text * the text to set in the text box */ @@ -1365,7 +1365,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * shown in the text box if nothing has been entered. * <p> * For internal use only. May be removed or replaced in the future. - * + * * @param text * The text the text box should contain. */ @@ -1380,7 +1380,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Triggered when a suggestion is selected - * + * * @param suggestion * The suggestion that just got selected. */ @@ -1420,7 +1420,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Sets the icon URI of the selected item. The icon is shown on the left * side of the item caption text. Set the URI to null to remove the icon. - * + * * @param iconUri * The URI of the icon */ @@ -1493,7 +1493,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see * com.google.gwt.event.dom.client.KeyDownHandler#onKeyDown(com.google.gwt * .event.dom.client.KeyDownEvent) @@ -1546,7 +1546,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Triggered when a key is pressed in the text box - * + * * @param event * The KeyDownEvent */ @@ -1591,7 +1591,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Triggered when a key was pressed in the suggestion popup. - * + * * @param event * The KeyDownEvent of the key */ @@ -1673,7 +1673,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Triggered when a key was depressed - * + * * @param event * The KeyUpEvent of the key depressed */ @@ -1716,7 +1716,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, setPromptingOff(text); selectedOptionKey = currentSuggestion.key; } else { - if (focused) { + if (focused || readonly || !enabled) { setPromptingOff(""); } else { setPromptingOn(); @@ -1816,7 +1816,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see * com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event * .dom.client.FocusEvent) @@ -1860,7 +1860,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see * com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event * .dom.client.BlurEvent) @@ -1925,7 +1925,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /* * (non-Javadoc) - * + * * @see com.vaadin.client.Focusable#focus() */ @@ -1946,22 +1946,9 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * For internal use only. May be removed or replaced in the future. */ public void updateRootWidth() { - updateRootWidth(false); - } - - /** - * Calculates the width of the select if the select has undefined width. - * Should be called when the width changes or when the icon changes. - * <p> - * For internal use only. May be removed or replaced in the future. - * - * @param forceUpdate - * a flag that forces a recalculation even if one would not - * normally be done - */ - public void updateRootWidth(boolean forceUpdate) { ComponentConnector paintable = ConnectorMap.get(client).getConnector( this); + if (paintable.isUndefinedWidth()) { /* @@ -1973,7 +1960,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, */ int w = Util.getRequiredWidth(this); - if (forceUpdate || (!initDone || currentPage + 1 < 0) + if ((!initDone || currentPage + 1 < 0) && suggestionPopupMinWidth > w) { /* * We want to compensate for the paddings just to preserve the @@ -1987,11 +1974,25 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, String originalBorder = style.getBorderWidth(); style.setPaddingLeft(0, Unit.PX); style.setBorderWidth(0, Unit.PX); - int offset = w - Util.getRequiredWidth(this); style.setProperty("padding", originalPadding); style.setProperty("borderWidth", originalBorder); - setWidth(suggestionPopupMinWidth + offset + "px"); + // Use util.getRequiredWidth instead of getOffsetWidth here + + int iconWidth = selectedItemIcon == null ? 0 : Util + .getRequiredWidth(selectedItemIcon); + int buttonWidth = popupOpener == null ? 0 : Util + .getRequiredWidth(popupOpener); + + /* + * Instead of setting the width of the wrapper, set the width of + * the combobox. Subtract the width of the icon and the + * popupopener + */ + + tb.setWidth((suggestionPopupMinWidth - iconWidth - buttonWidth) + + "px"); + } /* @@ -2009,7 +2010,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Get the width of the select in pixels where the text area and icon has * been included. - * + * * @return The width in pixels */ private int getMainWidth() { @@ -2026,7 +2027,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** * Handles special behavior of the mouse down event - * + * * @param event */ private void handleMouseDownEvent(Event event) { diff --git a/client/src/com/vaadin/client/ui/VMenuBar.java b/client/src/com/vaadin/client/ui/VMenuBar.java index 11fda6222c..909b25f7fb 100644 --- a/client/src/com/vaadin/client/ui/VMenuBar.java +++ b/client/src/com/vaadin/client/ui/VMenuBar.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -243,7 +243,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * This is called by the items in the menu and it communicates the * information to the server - * + * * @param clickedItemId * id of the item that was clicked */ @@ -280,7 +280,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Returns the containing element of the menu - * + * * @return */ @Override @@ -290,7 +290,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Add a new item to this menu - * + * * @param html * items text * @param cmd @@ -307,7 +307,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Add a new item to this menu - * + * * @param item */ public void addItem(CustomMenuItem item) { @@ -332,7 +332,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Remove the given item from this menu - * + * * @param item */ public void removeItem(CustomMenuItem item) { @@ -429,7 +429,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * When an item is clicked - * + * * @param item */ public void itemClick(CustomMenuItem item) { @@ -460,7 +460,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * When the user hovers the mouse over the item - * + * * @param item */ public void itemOver(CustomMenuItem item) { @@ -485,7 +485,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * When the mouse is moved away from an item - * + * * @param item */ public void itemOut(CustomMenuItem item) { @@ -543,7 +543,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Shows the child menu of an item. The caller must ensure that the item has * a submenu. - * + * * @param item */ public void showChildMenu(CustomMenuItem item) { @@ -665,7 +665,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Hides the submenu of an item - * + * * @param item */ public void hideChildMenu(CustomMenuItem item) { @@ -729,7 +729,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Returns the parent menu of this menu, or null if this is the top-level * menu - * + * * @return */ public VMenuBar getParentMenu() { @@ -738,7 +738,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Set the parent menu of this menu - * + * * @param parent */ public void setParentMenu(VMenuBar parent) { @@ -748,7 +748,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Returns the currently selected item of this menu, or null if nothing is * selected - * + * * @return */ public CustomMenuItem getSelected() { @@ -757,7 +757,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Set the currently selected item of this menu - * + * * @param item */ public void setSelected(CustomMenuItem item) { @@ -774,9 +774,9 @@ public class VMenuBar extends SimpleFocusablePanel implements } /** - * + * * A class to hold information on menu items - * + * */ public static class CustomMenuItem extends Widget implements HasHTML { @@ -795,7 +795,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Default menu item {@link Widget} constructor for GWT.create(). - * + * * Use {@link #setHTML(String)} and {@link #setCommand(Command)} after * constructing a menu item. */ @@ -805,7 +805,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Creates a menu item {@link Widget}. - * + * * @param html * @param cmd * @deprecated use the default constructor and {@link #setHTML(String)} @@ -1039,7 +1039,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Checks if the item can be selected. - * + * * @return true if it is possible to select this item, false otherwise */ public boolean isSelectable() { @@ -1157,7 +1157,14 @@ public class VMenuBar extends SimpleFocusablePanel implements */ @Override public void onKeyPress(KeyPressEvent event) { - if (handleNavigation(event.getNativeEvent().getKeyCode(), + // A bug fix for #14041 + // getKeyCode and getCharCode return different values for different + // browsers + int keyCode = event.getNativeEvent().getKeyCode(); + if (keyCode == 0) { + keyCode = event.getNativeEvent().getCharCode(); + } + if (handleNavigation(keyCode, event.isControlKeyDown() || event.isMetaKeyDown(), event.isShiftKeyDown())) { event.preventDefault(); @@ -1173,7 +1180,14 @@ public class VMenuBar extends SimpleFocusablePanel implements */ @Override public void onKeyDown(KeyDownEvent event) { - if (handleNavigation(event.getNativeEvent().getKeyCode(), + // A bug fix for #14041 + // getKeyCode and getCharCode return different values for different + // browsers + int keyCode = event.getNativeEvent().getKeyCode(); + if (keyCode == 0) { + keyCode = event.getNativeEvent().getCharCode(); + } + if (handleNavigation(keyCode, event.isControlKeyDown() || event.isMetaKeyDown(), event.isShiftKeyDown())) { event.preventDefault(); @@ -1184,7 +1198,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Get the key that moves the selection upwards. By default it is the up * arrow key but by overriding this you can change the key to whatever you * want. - * + * * @return The keycode of the key */ protected int getNavigationUpKey() { @@ -1195,7 +1209,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Get the key that moves the selection downwards. By default it is the down * arrow key but by overriding this you can change the key to whatever you * want. - * + * * @return The keycode of the key */ protected int getNavigationDownKey() { @@ -1206,7 +1220,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Get the key that moves the selection left. By default it is the left * arrow key but by overriding this you can change the key to whatever you * want. - * + * * @return The keycode of the key */ protected int getNavigationLeftKey() { @@ -1217,7 +1231,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Get the key that moves the selection right. By default it is the right * arrow key but by overriding this you can change the key to whatever you * want. - * + * * @return The keycode of the key */ protected int getNavigationRightKey() { @@ -1227,7 +1241,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Get the key that selects a menu item. By default it is the Enter key but * by overriding this you can change the key to whatever you want. - * + * * @deprecated use {@link #isNavigationSelectKey(int)} instead * @return */ @@ -1240,7 +1254,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Checks whether key code selects a menu item. By default it is the Enter * and Space keys but by overriding this you can change the keys to whatever * you want. - * + * * @since 7.2 * @param keycode * @return true if key selects menu item @@ -1253,7 +1267,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Get the key that closes the menu. By default it is the escape key but by * overriding this yoy can change the key to whatever you want. - * + * * @return */ protected int getCloseMenuKey() { @@ -1262,7 +1276,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Handles the keyboard events handled by the MenuBar - * + * * @param event * The keyboard event received * @return true iff the navigation event was handled @@ -1549,7 +1563,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Get menu item with given DOM element - * + * * @param element * Element used in search * @return Menu item or null if not found @@ -1578,11 +1592,11 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Get menu item with given DOM element - * + * * @param element * Element used in search * @return Menu item or null if not found - * + * * @since 7.2 */ public CustomMenuItem getMenuItemWithElement(Element element) { diff --git a/client/src/com/vaadin/client/ui/VRichTextArea.java b/client/src/com/vaadin/client/ui/VRichTextArea.java index 52e3782f32..3f63f38067 100644 --- a/client/src/com/vaadin/client/ui/VRichTextArea.java +++ b/client/src/com/vaadin/client/ui/VRichTextArea.java @@ -21,10 +21,6 @@ import java.util.Map; import java.util.Map.Entry; import com.google.gwt.core.client.Scheduler; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Style.Position; -import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.dom.client.Style.Visibility; import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; @@ -32,7 +28,6 @@ import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; @@ -43,7 +38,6 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.BrowserInfo; import com.vaadin.client.ConnectorMap; -import com.vaadin.client.Util; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; import com.vaadin.client.ui.richtextarea.VRichTextToolbar; @@ -73,7 +67,8 @@ public class VRichTextArea extends Composite implements Field, KeyPressHandler, /** For internal use only. May be removed or replaced in the future. */ public RichTextArea rta; - private VRichTextToolbar formatter; + /** For internal use only. May be removed or replaced in the future. */ + public VRichTextToolbar formatter; /** For internal use only. May be removed or replaced in the future. */ public HTML html = new HTML(); @@ -82,9 +77,6 @@ public class VRichTextArea extends Composite implements Field, KeyPressHandler, private boolean enabled = true; - private int extraHorizontalPixels = -1; - private int extraVerticalPixels = -1; - /** For internal use only. May be removed or replaced in the future. */ public int maxLength = -1; @@ -193,92 +185,17 @@ public class VRichTextArea extends Composite implements Field, KeyPressHandler, return readOnly; } - /** - * @return space used by components paddings and borders - */ - private int getExtraHorizontalPixels() { - if (extraHorizontalPixels < 0) { - detectExtraSizes(); - } - return extraHorizontalPixels; - } - - /** - * @return space used by components paddings and borders - */ - private int getExtraVerticalPixels() { - if (extraVerticalPixels < 0) { - detectExtraSizes(); - } - return extraVerticalPixels; - } - - /** - * Detects space used by components paddings and borders. - */ - private void detectExtraSizes() { - Element clone = Util.cloneNode(getElement(), false); - DOM.setElementAttribute(clone, "id", ""); - clone.getStyle().setVisibility(Visibility.HIDDEN); - clone.getStyle().setPosition(Position.ABSOLUTE); - // due FF3 bug set size to 10px and later subtract it from extra pixels - clone.getStyle().setWidth(10, Unit.PX); - clone.getStyle().setHeight(10, Unit.PX); - DOM.appendChild(DOM.getParent(getElement()), clone); - extraHorizontalPixels = DOM.getElementPropertyInt(clone, "offsetWidth") - 10; - extraVerticalPixels = DOM.getElementPropertyInt(clone, "offsetHeight") - 10; - - DOM.removeChild(DOM.getParent(getElement()), clone); - } - @Override public void setHeight(String height) { - if (height.endsWith("px")) { - float h = Float - .parseFloat(height.substring(0, height.length() - 2)); - h -= getExtraVerticalPixels(); - if (h < 0) { - h = 0; - } - - super.setHeight(h + "px"); - } else { - super.setHeight(height); - } - + super.setHeight(height); if (height == null || height.equals("")) { rta.setHeight(""); - } else { - /* - * The formatter height will be initially calculated wrong so we - * delay the height setting so the DOM has had time to stabilize. - */ - Scheduler.get().scheduleDeferred(new Command() { - @Override - public void execute() { - int editorHeight = getOffsetHeight() - - getExtraVerticalPixels() - - formatter.getOffsetHeight(); - if (editorHeight < 0) { - editorHeight = 0; - } - rta.setHeight(editorHeight + "px"); - } - }); } } @Override public void setWidth(String width) { - if (width.endsWith("px")) { - float w = Float.parseFloat(width.substring(0, width.length() - 2)); - w -= getExtraHorizontalPixels(); - if (w < 0) { - w = 0; - } - - super.setWidth(w + "px"); - } else if (width.equals("")) { + if (width.equals("")) { /* * IE cannot calculate the width of the 100% iframe correctly if * there is no width specified for the parent. In this case we would diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index d3317abd4d..7ec6845a11 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -1083,11 +1083,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, keyboardSelectionOverRowFetchInProgress = true; } if (selected) { + if (focusedRow == null || !selectedRowKeys.contains(focusedRow .getKey())) { - // The focus is no longer on a selected row, - // move focus to first selected row + /* + * The focus is no longer on a selected row. Move + * focus to the selected row. (#10522) + */ + setRowFocus(row); } } @@ -7258,7 +7262,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // Set new focused row focusedRow = row; - ensureRowIsVisible(row); + /* + * Don't scroll to the focused row when in multiselect mode. + * (#13341) + */ + + if (isSingleSelectMode()) { + ensureRowIsVisible(row); + } return true; } diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java index bbbd355a32..3b168b636c 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java @@ -298,6 +298,7 @@ public class DateCellDayEvent extends FocusableHTML implements weekGrid.getCalendar().getEventResizeListener() .eventResized(calendarEvent); } + dateCell.recalculateEventWidths(); } } diff --git a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java index a72049aa90..28f6beefa6 100644 --- a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java +++ b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java @@ -144,14 +144,18 @@ public class CheckBoxConnector extends AbstractFieldConnector implements return; } - getState().checked = getWidget().getValue(); - - // Add mouse details - MouseEventDetails details = MouseEventDetailsBuilder - .buildMouseEventDetails(event.getNativeEvent(), getWidget() - .getElement()); - getRpcProxy(CheckBoxServerRpc.class).setChecked(getState().checked, - details); - + // We get click events also from the label text, which do not alter the + // actual value. The server-side is only interested in real changes to + // the state. + if (getState().checked != getWidget().getValue()) { + getState().checked = getWidget().getValue(); + + // Add mouse details + MouseEventDetails details = MouseEventDetailsBuilder + .buildMouseEventDetails(event.getNativeEvent(), getWidget() + .getElement()); + getRpcProxy(CheckBoxServerRpc.class).setChecked(getState().checked, + details); + } } } diff --git a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java index c3cdb43703..78505d034c 100644 --- a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java +++ b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java @@ -24,7 +24,6 @@ import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.Paintable; import com.vaadin.client.UIDL; -import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.SimpleManagedLayout; import com.vaadin.client.ui.VFilterSelect; @@ -44,10 +43,6 @@ public class ComboBoxConnector extends AbstractFieldConnector implements // update textbox text by a changed item caption. private boolean oldSuggestionTextMatchTheOldSelection; - // Need to recompute the width of the combobox when styles change, see - // #13444 - private boolean stylesChanged; - /* * (non-Javadoc) * @@ -201,16 +196,11 @@ public class ComboBoxConnector extends AbstractFieldConnector implements getWidget().popupOpenerClicked = false; /* - * if styles have changed or this is our first time we need to - * recalculate the root width. + * if this is our first time we need to recalculate the root width. */ if (!getWidget().initDone) { - // no need to force update since we have no existing width - getWidget().updateRootWidth(false); - } else if (stylesChanged) { - // we have previously calculated a width, we must force an update - // due to changed styles - getWidget().updateRootWidth(true); + + getWidget().updateRootWidth(); } // Focus dependent style names are lost during the update, so we add @@ -219,9 +209,6 @@ public class ComboBoxConnector extends AbstractFieldConnector implements getWidget().addStyleDependentName("focus"); } - // width has been recalculated above, clear style change flag - stylesChanged = false; - getWidget().initDone = true; } @@ -303,8 +290,10 @@ public class ComboBoxConnector extends AbstractFieldConnector implements * ALWAYS set the prompting style at this point, even though we * think it has been set already... */ - getWidget().prompting = false; - getWidget().setPromptingOn(); + getWidget().setPromptingOff(""); + if (getWidget().enabled && !getWidget().readonly) { + getWidget().setPromptingOn(); + } } else { // we have focus in field, prompting can't be set on, instead // just clear the input if the value has changed from something @@ -345,12 +334,4 @@ public class ComboBoxConnector extends AbstractFieldConnector implements getWidget().tb.setEnabled(widgetEnabled); } - @Override - public void onStateChanged(StateChangeEvent event) { - super.onStateChanged(event); - if (event.hasPropertyChanged("styles")) { - stylesChanged = true; - } - } - } diff --git a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java index 6b3bf84578..5fe637447e 100644 --- a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java +++ b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java @@ -23,6 +23,7 @@ import com.vaadin.client.Paintable; import com.vaadin.client.UIDL; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; +import com.vaadin.client.ui.SimpleManagedLayout; import com.vaadin.client.ui.VRichTextArea; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.Connect.LoadStyle; @@ -31,7 +32,7 @@ import com.vaadin.ui.RichTextArea; @Connect(value = RichTextArea.class, loadStyle = LoadStyle.LAZY) public class RichTextAreaConnector extends AbstractFieldConnector implements - Paintable, BeforeShortcutActionListener { + Paintable, BeforeShortcutActionListener, SimpleManagedLayout { /* * Last value received from the server @@ -47,6 +48,15 @@ public class RichTextAreaConnector extends AbstractFieldConnector implements flush(); } }); + getLayoutManager().registerDependency(this, + getWidget().formatter.getElement()); + } + + @Override + public void onUnregister() { + super.onUnregister(); + getLayoutManager().unregisterDependency(this, + getWidget().formatter.getElement()); } @Override @@ -110,4 +120,19 @@ public class RichTextAreaConnector extends AbstractFieldConnector implements } } } + + @Override + public void layout() { + if (!isUndefinedHeight()) { + int rootElementInnerHeight = getLayoutManager().getInnerHeight( + getWidget().getElement()); + int formatterHeight = getLayoutManager().getOuterHeight( + getWidget().formatter.getElement()); + int editorHeight = rootElementInnerHeight - formatterHeight; + if (editorHeight < 0) { + editorHeight = 0; + } + getWidget().rta.setHeight(editorHeight + "px"); + } + } } diff --git a/client/src/com/vaadin/client/ui/splitpanel/AbstractSplitPanelConnector.java b/client/src/com/vaadin/client/ui/splitpanel/AbstractSplitPanelConnector.java index ce8b3c8fea..6bf03ad880 100644 --- a/client/src/com/vaadin/client/ui/splitpanel/AbstractSplitPanelConnector.java +++ b/client/src/com/vaadin/client/ui/splitpanel/AbstractSplitPanelConnector.java @@ -161,6 +161,35 @@ public abstract class AbstractSplitPanelConnector extends getLayoutManager().setNeedsLayout(this); getWidget().makeScrollable(); + + handleSingleComponentMove(); + } + + /** + * Handles the case when there is only one child component and that + * component is moved between first <-> second. This does not trigger a + * hierarchy change event as the list of children contains the same + * component in both cases. + */ + private void handleSingleComponentMove() { + if (getChildComponents().size() == 1) { + Widget stateFirstChild = null; + Widget stateSecondChild = null; + if (getState().firstChild != null) { + stateFirstChild = ((ComponentConnector) getState().firstChild) + .getWidget(); + } + if (getState().secondChild != null) { + stateSecondChild = ((ComponentConnector) getState().secondChild) + .getWidget(); + } + + if (stateFirstChild == getWidget().getSecondWidget() + || stateSecondChild == getWidget().getFirstWidget()) { + handleHierarchyChange(); + } + } + } @Override @@ -212,6 +241,10 @@ public abstract class AbstractSplitPanelConnector extends @Override public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + handleHierarchyChange(); + } + + private void handleHierarchyChange() { /* * When the connector gets detached, the state isn't updated but there's * still a hierarchy change -> verify that the child from the state is diff --git a/scripts/install-local-maven.sh b/scripts/install-local-maven.sh index 2883258808..f36b603db9 100755 --- a/scripts/install-local-maven.sh +++ b/scripts/install-local-maven.sh @@ -10,31 +10,31 @@ fi for base in * do - if [ ! -d $base ] + if [ ! -d "$base" ] then continue fi - pushd $base - version=`ls $base-*.pom|sed "s/$base-//"|sed "s/.pom//"` + pushd "$base" + version=`ls "$base"-*.pom|sed "s/$base-//"|sed "s/.pom//"` pomTemplate="$base-$version.pom" if [ -e "$pomTemplate" ] then - id=$base-$version - pomFile=$pomTemplate-modified - file=$id.jar - javadocFile=$id-javadoc.jar - sourcesFile=$id-sources.jar + id="$base-$version" + pomFile="$pomTemplate-modified" + file="$id.jar" + javadocFile="$id-javadoc.jar" + sourcesFile="$id-sources.jar" # Install using real version for easy testing - cat $pomTemplate|sed "s/<version>7.*-SNAPSHOT</<version>$version</g" > $pomFile + cat "$pomTemplate"|sed "s/<version>7.*-SNAPSHOT</<version>$version</g" > "$pomFile" echo "Installing $base $version..." if [ -e "$javadocFile" ] then - mvn org.apache.maven.plugins:maven-install-plugin:2.5.1:install-file -DpomFile=$pomFile -Djavadoc=$javadocFile -Dsources=$sourcesFile -Dfile=$file + mvn org.apache.maven.plugins:maven-install-plugin:2.5.1:install-file -DpomFile="$pomFile" -Djavadoc="$javadocFile" -Dsources="$sourcesFile" -Dfile="$file" else - mvn org.apache.maven.plugins:maven-install-plugin:2.5.1:install-file -DpomFile=$pomFile -Dfile=$file + mvn org.apache.maven.plugins:maven-install-plugin:2.5.1:install-file -DpomFile="$pomFile" -Dfile="$file" fi fi popd diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java index 92c235167c..bafecdabf4 100644 --- a/server/src/com/vaadin/server/AbstractClientConnector.java +++ b/server/src/com/vaadin/server/AbstractClientConnector.java @@ -243,7 +243,7 @@ public abstract class AbstractClientConnector implements ClientConnector, @Override public JSONObject encodeState() throws JSONException { - return LegacyCommunicationManager.encodeState(this, getState()); + return LegacyCommunicationManager.encodeState(this, getState(false)); } /** @@ -292,11 +292,13 @@ public abstract class AbstractClientConnector implements ClientConnector, Method m = class1.getDeclaredMethod("getState", (Class[]) null); Class<?> type = m.getReturnType(); - return type.asSubclass(SharedState.class); + if (!m.isSynthetic()) { + return type.asSubclass(SharedState.class); + } } catch (NoSuchMethodException nsme) { - // Try in superclass instead - class1 = class1.getSuperclass(); } + // Try in superclass instead + class1 = class1.getSuperclass(); } throw new NoSuchMethodException(getClass().getCanonicalName() + ".getState()"); @@ -664,7 +666,8 @@ public abstract class AbstractClientConnector implements ClientConnector, * @see #setResource(String, Resource) */ protected Resource getResource(String key) { - return ResourceReference.getResource(getState().resources.get(key)); + return ResourceReference + .getResource(getState(false).resources.get(key)); } /** diff --git a/server/src/com/vaadin/server/AbstractErrorMessage.java b/server/src/com/vaadin/server/AbstractErrorMessage.java index c733cc493e..b56521993a 100644 --- a/server/src/com/vaadin/server/AbstractErrorMessage.java +++ b/server/src/com/vaadin/server/AbstractErrorMessage.java @@ -126,7 +126,7 @@ public abstract class AbstractErrorMessage implements ErrorMessage { StringBuilder sb = new StringBuilder(); for (ErrorMessage cause : getCauses()) { String childMessage = cause.getFormattedHtmlMessage(); - if (null != childMessage) { + if (null != childMessage && !childMessage.isEmpty()) { sb.append("<div>"); sb.append(childMessage); sb.append("</div>\n"); diff --git a/server/src/com/vaadin/server/BrowserWindowOpener.java b/server/src/com/vaadin/server/BrowserWindowOpener.java index df03e76bcd..44679fbfbb 100644 --- a/server/src/com/vaadin/server/BrowserWindowOpener.java +++ b/server/src/com/vaadin/server/BrowserWindowOpener.java @@ -147,7 +147,7 @@ public class BrowserWindowOpener extends AbstractExtension { * @return the window target string */ public String getWindowName() { - return getState().target; + return getState(false).target; } // Avoid breaking url to multiple lines @@ -171,7 +171,7 @@ public class BrowserWindowOpener extends AbstractExtension { * @return */ public String getFeatures() { - return getState().features; + return getState(false).features; } @Override @@ -180,6 +180,11 @@ public class BrowserWindowOpener extends AbstractExtension { } @Override + protected BrowserWindowOpenerState getState(boolean markAsDirty) { + return (BrowserWindowOpenerState) super.getState(markAsDirty); + } + + @Override public void attach() { super.attach(); if (uiProvider != null @@ -226,7 +231,7 @@ public class BrowserWindowOpener extends AbstractExtension { * @see #setUriFragment(String) */ public String getUriFragment() { - return getState().uriFragment; + return getState(false).uriFragment; } /** @@ -301,7 +306,7 @@ public class BrowserWindowOpener extends AbstractExtension { if (name == null) { throw new IllegalArgumentException("Null not allowed"); } - return getState().parameters.get(name); + return getState(false).parameters.get(name); } } diff --git a/server/src/com/vaadin/server/FontAwesome.java b/server/src/com/vaadin/server/FontAwesome.java index 71a2249dca..c99f42fac1 100644 --- a/server/src/com/vaadin/server/FontAwesome.java +++ b/server/src/com/vaadin/server/FontAwesome.java @@ -25,6 +25,9 @@ package com.vaadin.server; * these icons, and all of them, so you might want to consider making a custom * icon font - either to get other icons, or to minimize the size of the font. * </p> + * <p> + * The Font Awesome version currently included is 4.0.3. + * </p> * * @since 7.2 * @author Vaadin Ltd diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 08bc6f5c79..e8cdcd7055 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -59,6 +59,7 @@ import com.vaadin.server.communication.HeartbeatHandler; import com.vaadin.server.communication.PublishedFileHandler; import com.vaadin.server.communication.SessionRequestHandler; import com.vaadin.server.communication.UidlRequestHandler; +import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.JsonConstants; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.ui.UI; @@ -1590,6 +1591,7 @@ public abstract class VaadinService implements Serializable { json.put("resources", new JSONObject()); json.put("locales", new JSONObject()); json.put("meta", meta); + json.put(ApplicationConstants.SERVER_SYNC_ID, -1); returnString = json.toString(); } catch (JSONException e) { getLogger().log(Level.WARNING, diff --git a/server/src/com/vaadin/ui/AbstractColorPicker.java b/server/src/com/vaadin/ui/AbstractColorPicker.java index db4239f8a6..acf3b2c042 100644 --- a/server/src/com/vaadin/ui/AbstractColorPicker.java +++ b/server/src/com/vaadin/ui/AbstractColorPicker.java @@ -189,7 +189,7 @@ public abstract class AbstractColorPicker extends AbstractComponent implements * currently selected color, e.g. #ffffff) if no other caption is available. */ public boolean isDefaultCaptionEnabled() { - return getState().showDefaultCaption; + return getState(false).showDefaultCaption; } /** @@ -358,6 +358,11 @@ public abstract class AbstractColorPicker extends AbstractComponent implements return (ColorPickerState) super.getState(); } + @Override + protected ColorPickerState getState(boolean markAsDirty) { + return (ColorPickerState) super.getState(markAsDirty); + } + /** * Sets the default styles of the component * @@ -462,6 +467,6 @@ public abstract class AbstractColorPicker extends AbstractComponent implements * <code>false</code> otherwise */ public boolean isHtmlContentAllowed() { - return getState().htmlContentAllowed; + return getState(false).htmlContentAllowed; } } diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java index b6289e0b7d..9dbd9a093d 100644 --- a/server/src/com/vaadin/ui/AbstractComponent.java +++ b/server/src/com/vaadin/ui/AbstractComponent.java @@ -151,8 +151,8 @@ public abstract class AbstractComponent extends AbstractClientConnector @Override public String getStyleName() { String s = ""; - if (ComponentStateUtil.hasStyles(getState())) { - for (final Iterator<String> it = getState().styles.iterator(); it + if (ComponentStateUtil.hasStyles(getState(false))) { + for (final Iterator<String> it = getState(false).styles.iterator(); it .hasNext();) { s += it.next(); if (it.hasNext()) { @@ -191,7 +191,7 @@ public abstract class AbstractComponent extends AbstractClientConnector @Override public String getPrimaryStyleName() { - return getState().primaryStyleName; + return getState(false).primaryStyleName; } @Override diff --git a/server/src/com/vaadin/ui/AbstractEmbedded.java b/server/src/com/vaadin/ui/AbstractEmbedded.java index 8c574fd59e..66752aa5d7 100644 --- a/server/src/com/vaadin/ui/AbstractEmbedded.java +++ b/server/src/com/vaadin/ui/AbstractEmbedded.java @@ -34,6 +34,11 @@ public abstract class AbstractEmbedded extends AbstractComponent { return (AbstractEmbeddedState) super.getState(); } + @Override + protected AbstractEmbeddedState getState(boolean markAsDirty) { + return (AbstractEmbeddedState) super.getState(markAsDirty); + } + /** * Sets the object source resource. The dimensions are assumed if possible. * The type is guessed from resource. @@ -73,7 +78,7 @@ public abstract class AbstractEmbedded extends AbstractComponent { * @returns Alternate text */ public String getAlternateText() { - return getState().alternateText; + return getState(false).alternateText; } } diff --git a/server/src/com/vaadin/ui/AbstractMedia.java b/server/src/com/vaadin/ui/AbstractMedia.java index a841aa672e..0bd8c3ea77 100644 --- a/server/src/com/vaadin/ui/AbstractMedia.java +++ b/server/src/com/vaadin/ui/AbstractMedia.java @@ -47,6 +47,11 @@ public abstract class AbstractMedia extends AbstractComponent { return (AbstractMediaState) super.getState(); } + @Override + protected AbstractMediaState getState(boolean markAsDirty) { + return (AbstractMediaState) super.getState(markAsDirty); + } + /** * Sets a single media file as the source of the media component. * @@ -141,7 +146,7 @@ public abstract class AbstractMedia extends AbstractComponent { */ public List<Resource> getSources() { ArrayList<Resource> sources = new ArrayList<Resource>(); - for (URLReference ref : getState().sources) { + for (URLReference ref : getState(false).sources) { sources.add(((ResourceReference) ref).getResource()); } return sources; @@ -160,7 +165,7 @@ public abstract class AbstractMedia extends AbstractComponent { * @return true if the browser is to show native media controls. */ public boolean isShowControls() { - return getState().showControls; + return getState(false).showControls; } /** @@ -183,7 +188,7 @@ public abstract class AbstractMedia extends AbstractComponent { * HTML5. */ public String getAltText() { - return getState().altText; + return getState(false).altText; } /** @@ -201,7 +206,7 @@ public abstract class AbstractMedia extends AbstractComponent { * be rendered as HTML. */ public boolean isHtmlContentAllowed() { - return getState().htmlContentAllowed; + return getState(false).htmlContentAllowed; } /** @@ -218,7 +223,7 @@ public abstract class AbstractMedia extends AbstractComponent { * @return true if the media is set to automatically start playback. */ public boolean isAutoplay() { - return getState().autoplay; + return getState(false).autoplay; } /** @@ -234,7 +239,7 @@ public abstract class AbstractMedia extends AbstractComponent { * @return true if the audio is muted. */ public boolean isMuted() { - return getState().muted; + return getState(false).muted; } /** diff --git a/server/src/com/vaadin/ui/AbstractOrderedLayout.java b/server/src/com/vaadin/ui/AbstractOrderedLayout.java index 039c87333e..27880db75f 100644 --- a/server/src/com/vaadin/ui/AbstractOrderedLayout.java +++ b/server/src/com/vaadin/ui/AbstractOrderedLayout.java @@ -69,6 +69,11 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements return (AbstractOrderedLayoutState) super.getState(); } + @Override + protected AbstractOrderedLayoutState getState(boolean markAsDirty) { + return (AbstractOrderedLayoutState) super.getState(markAsDirty); + } + /** * Add a component into this container. The component is added to the right * or under the previous component. @@ -285,7 +290,7 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements */ @Override public boolean isSpacing() { - return getState().spacing; + return getState(false).spacing; } /** @@ -335,7 +340,7 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements * @return expand ratio of given component, 0.0f by default. */ public float getExpandRatio(Component component) { - ChildComponentData childData = getState().childData.get(component); + ChildComponentData childData = getState(false).childData.get(component); if (childData == null) { throw new IllegalArgumentException( "The given component is not a child of this layout"); @@ -413,7 +418,7 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements */ @Override public MarginInfo getMargin() { - return new MarginInfo(getState().marginsBitmask); + return new MarginInfo(getState(false).marginsBitmask); } /* diff --git a/server/src/com/vaadin/ui/AbstractSplitPanel.java b/server/src/com/vaadin/ui/AbstractSplitPanel.java index 3a1b7ca35a..1c69ebf87e 100644 --- a/server/src/com/vaadin/ui/AbstractSplitPanel.java +++ b/server/src/com/vaadin/ui/AbstractSplitPanel.java @@ -186,7 +186,7 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer { * @return the first component of this split panel */ public Component getFirstComponent() { - return (Component) getState().firstChild; + return (Component) getState(false).firstChild; } /** @@ -196,7 +196,7 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer { * @return the second component of this split panel */ public Component getSecondComponent() { - return (Component) getState().secondChild; + return (Component) getState(false).secondChild; } /** @@ -534,7 +534,12 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer { return (AbstractSplitPanelState) super.getState(); } + @Override + protected AbstractSplitPanelState getState(boolean markAsDirty) { + return (AbstractSplitPanelState) super.getState(markAsDirty); + } + private SplitterState getSplitterState() { - return getState().splitterState; + return getState(false).splitterState; } } diff --git a/server/src/com/vaadin/ui/AbstractTextField.java b/server/src/com/vaadin/ui/AbstractTextField.java index 25b34ae19f..e0318ddf2b 100644 --- a/server/src/com/vaadin/ui/AbstractTextField.java +++ b/server/src/com/vaadin/ui/AbstractTextField.java @@ -96,6 +96,11 @@ public abstract class AbstractTextField extends AbstractField<String> implements } @Override + protected AbstractTextFieldState getState(boolean markAsDirty) { + return (AbstractTextFieldState) super.getState(markAsDirty); + } + + @Override public void beforeClientResponse(boolean initial) { super.beforeClientResponse(initial); @@ -311,7 +316,7 @@ public abstract class AbstractTextField extends AbstractField<String> implements * @return the maxLength */ public int getMaxLength() { - return getState().maxLength; + return getState(false).maxLength; } /** @@ -333,7 +338,7 @@ public abstract class AbstractTextField extends AbstractField<String> implements * @return the number of columns in the editor. */ public int getColumns() { - return getState().columns; + return getState(false).columns; } /** @@ -358,7 +363,7 @@ public abstract class AbstractTextField extends AbstractField<String> implements * @return the current input prompt, or null if not enabled */ public String getInputPrompt() { - return getState().inputPrompt; + return getState(false).inputPrompt; } /** diff --git a/server/src/com/vaadin/ui/Button.java b/server/src/com/vaadin/ui/Button.java index 5a5d03a3ee..58b6f9de81 100644 --- a/server/src/com/vaadin/ui/Button.java +++ b/server/src/com/vaadin/ui/Button.java @@ -556,7 +556,7 @@ public class Button extends AbstractComponent implements * @return true if the button is disabled when clicked, false otherwise */ public boolean isDisableOnClick() { - return getState().disableOnClick; + return getState(false).disableOnClick; } /** @@ -582,7 +582,7 @@ public class Button extends AbstractComponent implements */ @Override public int getTabIndex() { - return getState().tabIndex; + return getState(false).tabIndex; } /* @@ -606,6 +606,11 @@ public class Button extends AbstractComponent implements return (ButtonState) super.getState(); } + @Override + protected ButtonState getState(boolean markAsDirty) { + return (ButtonState) super.getState(markAsDirty); + } + /** * Sets the component's icon and alt text. * @@ -628,7 +633,7 @@ public class Button extends AbstractComponent implements * @return String with the alt text */ public String getIconAlternateText() { - return getState().iconAltText; + return getState(false).iconAltText; } public void setIconAlternateText(String iconAltText) { @@ -658,7 +663,7 @@ public class Button extends AbstractComponent implements * <code>false</code> otherwise */ public boolean isHtmlContentAllowed() { - return getState().htmlContentAllowed; + return getState(false).htmlContentAllowed; } } diff --git a/server/src/com/vaadin/ui/CustomLayout.java b/server/src/com/vaadin/ui/CustomLayout.java index fd56ed9219..7f1aa1ce46 100644 --- a/server/src/com/vaadin/ui/CustomLayout.java +++ b/server/src/com/vaadin/ui/CustomLayout.java @@ -124,6 +124,11 @@ public class CustomLayout extends AbstractLayout implements LegacyComponent { return (CustomLayoutState) super.getState(); } + @Override + protected CustomLayoutState getState(boolean markAsDirty) { + return (CustomLayoutState) super.getState(markAsDirty); + } + /** * Adds the component into this container to given location. If the location * is already populated, the old component is removed. @@ -251,12 +256,12 @@ public class CustomLayout extends AbstractLayout implements LegacyComponent { /** Get the name of the template */ public String getTemplateName() { - return getState().templateName; + return getState(false).templateName; } /** Get the contents of the template */ public String getTemplateContents() { - return getState().templateContents; + return getState(false).templateContents; } /** @@ -292,7 +297,7 @@ public class CustomLayout extends AbstractLayout implements LegacyComponent { public void paintContent(PaintTarget target) throws PaintException { // Workaround to make the CommunicationManager read the template file // and send it to the client - String templateName = getState().templateName; + String templateName = getState(false).templateName; if (templateName != null && templateName.length() != 0) { Set<Object> usedResources = ((JsonPaintTarget) target) .getUsedResources(); diff --git a/server/src/com/vaadin/ui/DragAndDropWrapper.java b/server/src/com/vaadin/ui/DragAndDropWrapper.java index cb94a774a5..3d3356b338 100644 --- a/server/src/com/vaadin/ui/DragAndDropWrapper.java +++ b/server/src/com/vaadin/ui/DragAndDropWrapper.java @@ -187,6 +187,10 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget, private Set<String> sentIds = new HashSet<String>(); + private DragAndDropWrapper() { + super(); + } + /** * Wraps given component in a {@link DragAndDropWrapper}. * @@ -194,7 +198,8 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget, * the component to be wrapped */ public DragAndDropWrapper(Component root) { - super(root); + this(); + setCompositionRoot(root); } /** diff --git a/server/src/com/vaadin/ui/Flash.java b/server/src/com/vaadin/ui/Flash.java index 791202f4a9..bbbd4e3285 100644 --- a/server/src/com/vaadin/ui/Flash.java +++ b/server/src/com/vaadin/ui/Flash.java @@ -67,6 +67,11 @@ public class Flash extends AbstractEmbedded { return (FlashState) super.getState(); } + @Override + protected FlashState getState(boolean markAsDirty) { + return (FlashState) super.getState(markAsDirty); + } + /** * This attribute specifies the base path used to resolve relative URIs * specified by the classid, data, and archive attributes. When absent, its @@ -156,7 +161,7 @@ public class Flash extends AbstractEmbedded { * @return the Value of parameter or null if not found. */ public String getParameter(String name) { - return getState().embedParams != null ? getState().embedParams + return getState(false).embedParams != null ? getState(false).embedParams .get(name) : null; } diff --git a/server/src/com/vaadin/ui/Form.java b/server/src/com/vaadin/ui/Form.java index 5653a83cee..391ee45536 100644 --- a/server/src/com/vaadin/ui/Form.java +++ b/server/src/com/vaadin/ui/Form.java @@ -198,6 +198,11 @@ public class Form extends AbstractField<Object> implements Item.Editor, return (FormState) super.getState(); } + @Override + protected FormState getState(boolean markAsDirty) { + return (FormState) super.getState(markAsDirty); + } + /* Documented in interface */ @Override public void paintContent(PaintTarget target) throws PaintException { @@ -775,7 +780,7 @@ public class Form extends AbstractField<Object> implements Item.Editor, * @return the Layout of the form. */ public Layout getLayout() { - return (Layout) getState().layout; + return (Layout) getState(false).layout; } /** @@ -1054,8 +1059,9 @@ public class Form extends AbstractField<Object> implements Item.Editor, * @return the Field. */ private Field<?> getFirstFocusableField() { - if (getItemPropertyIds() != null) { - for (Object id : getItemPropertyIds()) { + Collection<?> itemPropertyIds = getItemPropertyIds(); + if (itemPropertyIds != null && itemPropertyIds.size() > 0) { + for (Object id : itemPropertyIds) { if (id != null) { Field<?> field = getField(id); if (field.isEnabled() && !field.isReadOnly()) { @@ -1065,7 +1071,7 @@ public class Form extends AbstractField<Object> implements Item.Editor, } // fallback: first field if none of the fields is enabled and // writable - Object id = getItemPropertyIds().iterator().next(); + Object id = itemPropertyIds.iterator().next(); if (id != null) { return getField(id); } @@ -1214,7 +1220,7 @@ public class Form extends AbstractField<Object> implements Item.Editor, * is used */ public Layout getFooter() { - return (Layout) getState().footer; + return (Layout) getState(false).footer; } /** diff --git a/server/src/com/vaadin/ui/GridLayout.java b/server/src/com/vaadin/ui/GridLayout.java index 989f5efdea..0c097abc83 100644 --- a/server/src/com/vaadin/ui/GridLayout.java +++ b/server/src/com/vaadin/ui/GridLayout.java @@ -39,12 +39,12 @@ import com.vaadin.shared.ui.gridlayout.GridLayoutState.ChildComponentData; /** * A layout where the components are laid out on a grid using cell coordinates. - * + * * <p> * The GridLayout also maintains a cursor for adding components in * left-to-right, top-to-bottom order. * </p> - * + * * <p> * Each component in a <code>GridLayout</code> uses a defined * {@link GridLayout.Area area} (column1,row1,column2,row2) from the grid. The @@ -52,12 +52,12 @@ import com.vaadin.shared.ui.gridlayout.GridLayoutState.ChildComponentData; * you will get an {@link OverlapsException}. Adding a component with cursor * automatically extends the grid by increasing the grid height. * </p> - * + * * <p> * The grid coordinates, which are specified by a row and column index, always * start from 0 for the topmost row and the leftmost column. * </p> - * + * * @author Vaadin Ltd. * @since 3.0 */ @@ -96,10 +96,10 @@ public class GridLayout extends AbstractLayout implements /** * Constructor for a grid of given size (number of columns and rows). - * + * * The grid may grow or shrink later. Grid grows automatically if you add * components outside its area. - * + * * @param columns * Number of columns in the grid. * @param rows @@ -121,9 +121,9 @@ public class GridLayout extends AbstractLayout implements /** * Constructs a GridLayout of given size (number of columns and rows) and * adds the given components in order to the grid. - * + * * @see #addComponents(Component...) - * + * * @param columns * Number of columns in the grid. * @param rows @@ -141,19 +141,24 @@ public class GridLayout extends AbstractLayout implements return (GridLayoutState) super.getState(); } + @Override + protected GridLayoutState getState(boolean markAsDirty) { + return (GridLayoutState) super.getState(markAsDirty); + } + /** * <p> * Adds a component to the grid in the specified area. The area is defined * by specifying the upper left corner (column1, row1) and the lower right * corner (column2, row2) of the area. The coordinates are zero-based. * </p> - * + * * <p> * If the area overlaps with any of the existing components already present * in the grid, the operation will fail and an {@link OverlapsException} is * thrown. * </p> - * + * * @param component * the component to be added, not <code>null</code>. * @param column1 @@ -257,7 +262,7 @@ public class GridLayout extends AbstractLayout implements /** * Tests if the given area overlaps with any of the items already on the * grid. - * + * * @param area * the Area to be checked for overlapping. * @throws OverlapsException @@ -279,7 +284,7 @@ public class GridLayout extends AbstractLayout implements * the area.) End coordinates (SouthEast corner of the area) are the same as * column1,row1. The coordinates are zero-based. Component width and height * is 1. - * + * * @param component * the component to be added, not <code>null</code>. * @param column @@ -299,16 +304,16 @@ public class GridLayout extends AbstractLayout implements /** * Forces the next component to be added at the beginning of the next line. - * + * * <p> * Sets the cursor column to 0 and increments the cursor row by one. * </p> - * + * * <p> * By calling this function you can ensure that no more components are added * right of the previous component. * </p> - * + * * @see #space() */ public void newLine() { @@ -319,7 +324,7 @@ public class GridLayout extends AbstractLayout implements /** * Moves the cursor forward by one. If the cursor goes out of the right grid * border, it is moved to the first column of the next row. - * + * * @see #newLine() */ public void space() { @@ -335,7 +340,7 @@ public class GridLayout extends AbstractLayout implements * cursor position is already occupied, the cursor is moved forwards to find * free position. If the cursor goes out from the bottom of the grid, the * grid is automatically extended. - * + * * @param component * the component to be added, not <code>null</code>. */ @@ -371,7 +376,7 @@ public class GridLayout extends AbstractLayout implements /** * Removes the specified component from the layout. - * + * * @param component * the component to be removed. */ @@ -391,7 +396,7 @@ public class GridLayout extends AbstractLayout implements /** * Removes the component specified by its cell coordinates. - * + * * @param column * the component's column, starting from 0. * @param row @@ -414,7 +419,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets an Iterator for the components contained in the layout. By using the * Iterator it is possible to step through the contents of the layout. - * + * * @return the Iterator of the components inside the layout. */ @Override @@ -425,7 +430,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the number of components contained in the layout. Consistent with * the iterator returned by {@link #getComponentIterator()}. - * + * * @return the number of contained components */ @Override @@ -440,7 +445,7 @@ public class GridLayout extends AbstractLayout implements /** * Paints the contents of this component. - * + * * @param target * the Paint Event. * @throws PaintException @@ -519,7 +524,7 @@ public class GridLayout extends AbstractLayout implements */ @Override public Alignment getComponentAlignment(Component childComponent) { - ChildComponentData childComponentData = getState().childData + ChildComponentData childComponentData = getState(false).childData .get(childComponent); if (childComponentData == null) { throw new IllegalArgumentException( @@ -531,17 +536,17 @@ public class GridLayout extends AbstractLayout implements /** * Defines a rectangular area of cells in a GridLayout. - * + * * <p> * Also maintains a reference to the component contained in the area. * </p> - * + * * <p> * The area is specified by the cell coordinates of its upper left corner * (column1,row1) and lower right corner (column2,row2). As otherwise with * GridLayout, the column and row coordinates start from zero. * </p> - * + * * @author Vaadin Ltd. * @since 3.0 */ @@ -553,7 +558,7 @@ public class GridLayout extends AbstractLayout implements * <p> * Construct a new area on a grid. * </p> - * + * * @param component * the component connected to the area. * @param column1 @@ -587,7 +592,7 @@ public class GridLayout extends AbstractLayout implements /** * Tests if this Area overlaps with another Area. - * + * * @param other * the other Area that is to be tested for overlap with this * area @@ -600,7 +605,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the component connected to the area. - * + * * @return the Component. */ public Component getComponent() { @@ -609,7 +614,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the column of the top-left corner cell. - * + * * @return the column of the top-left corner cell. */ public int getColumn1() { @@ -618,7 +623,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the column of the bottom-right corner cell. - * + * * @return the column of the bottom-right corner cell. */ public int getColumn2() { @@ -627,7 +632,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the row of the top-left corner cell. - * + * * @return the row of the top-left corner cell. */ public int getRow1() { @@ -636,7 +641,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the row of the bottom-right corner cell. - * + * * @return the row of the bottom-right corner cell. */ public int getRow2() { @@ -655,7 +660,7 @@ public class GridLayout extends AbstractLayout implements * Gridlayout does not support laying components on top of each other. An * <code>OverlapsException</code> is thrown when a component already exists * (even partly) at the same space on a grid with the new component. - * + * * @author Vaadin Ltd. * @since 3.0 */ @@ -665,7 +670,7 @@ public class GridLayout extends AbstractLayout implements /** * Constructs an <code>OverlapsException</code>. - * + * * @param existingArea */ public OverlapsException(Area existingArea) { @@ -700,7 +705,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the area . - * + * * @return the existing area. */ public Area getArea() { @@ -711,7 +716,7 @@ public class GridLayout extends AbstractLayout implements /** * An <code>Exception</code> object which is thrown when an area exceeds the * bounds of the grid. - * + * * @author Vaadin Ltd. * @since 3.0 */ @@ -722,7 +727,7 @@ public class GridLayout extends AbstractLayout implements /** * Constructs an <code>OoutOfBoundsException</code> with the specified * detail message. - * + * * @param areaOutOfBounds */ public OutOfBoundsException(Area areaOutOfBounds) { @@ -731,7 +736,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the area that is out of bounds. - * + * * @return the area out of Bound. */ public Area getArea() { @@ -742,7 +747,7 @@ public class GridLayout extends AbstractLayout implements /** * Sets the number of columns in the grid. The column count can not be * reduced if there are any areas that would be outside of the shrunk grid. - * + * * @param columns * the new number of columns in the grid. */ @@ -776,17 +781,17 @@ public class GridLayout extends AbstractLayout implements /** * Get the number of columns in the grid. - * + * * @return the number of columns in the grid. */ public int getColumns() { - return getState().columns; + return getState(false).columns; } /** * Sets the number of rows in the grid. The number of rows can not be * reduced if there are any areas that would be outside of the shrunk grid. - * + * * @param rows * the new number of rows in the grid. */ @@ -820,23 +825,23 @@ public class GridLayout extends AbstractLayout implements /** * Get the number of rows in the grid. - * + * * @return the number of rows in the grid. */ public int getRows() { - return getState().rows; + return getState(false).rows; } /** * Gets the current x-position (column) of the cursor. - * + * * <p> * The cursor position points the position for the next component that is * added without specifying its coordinates (grid cell). When the cursor * position is occupied, the next component will be added to first free * position after the cursor. * </p> - * + * * @return the grid column the cursor is on, starting from 0. */ public int getCursorX() { @@ -846,7 +851,7 @@ public class GridLayout extends AbstractLayout implements /** * Sets the current cursor x-position. This is usually handled automatically * by GridLayout. - * + * * @param cursorX */ public void setCursorX(int cursorX) { @@ -855,14 +860,14 @@ public class GridLayout extends AbstractLayout implements /** * Gets the current y-position (row) of the cursor. - * + * * <p> * The cursor position points the position for the next component that is * added without specifying its coordinates (grid cell). When the cursor * position is occupied, the next component will be added to the first free * position after the cursor. * </p> - * + * * @return the grid row the Cursor is on. */ public int getCursorY() { @@ -872,7 +877,7 @@ public class GridLayout extends AbstractLayout implements /** * Sets the current y-coordinate (row) of the cursor. This is usually * handled automatically by GridLayout. - * + * * @param cursorY * the row number, starting from 0 for the topmost row. */ @@ -951,12 +956,12 @@ public class GridLayout extends AbstractLayout implements */ @Override public boolean isSpacing() { - return getState().spacing; + return getState(false).spacing; } /** * Inserts an empty row at the specified position in the grid. - * + * * @param row * Index of the row before which the new row will be inserted. * The leftmost row has index 0. @@ -990,18 +995,18 @@ public class GridLayout extends AbstractLayout implements /** * Removes a row and all the components in the row. - * + * * <p> * Components which span over several rows are removed if the selected row * is on the first row of such a component. * </p> - * + * * <p> * If the last row is removed then all remaining components will be removed * and the grid will be reduced to one row. The cursor will be moved to the * upper left cell of the grid. * </p> - * + * * @param row * Index of the row to remove. The leftmost row has index 0. */ @@ -1048,20 +1053,20 @@ public class GridLayout extends AbstractLayout implements /** * Sets the expand ratio of given column. - * + * * <p> * The expand ratio defines how excess space is distributed among columns. * Excess space means space that is left over from components that are not * sized relatively. By default, the excess space is distributed evenly. * </p> - * + * * <p> * Note that the component width of the GridLayout must be defined (fixed or * relative, as opposed to undefined) for this method to have any effect. * </p> - * + * * @see #setWidth(float, int) - * + * * @param columnIndex * @param ratio */ @@ -1073,9 +1078,9 @@ public class GridLayout extends AbstractLayout implements /** * Returns the expand ratio of given column - * + * * @see #setColumnExpandRatio(int, float) - * + * * @param columnIndex * @return the expand ratio, 0.0f by default */ @@ -1086,20 +1091,20 @@ public class GridLayout extends AbstractLayout implements /** * Sets the expand ratio of given row. - * + * * <p> * Expand ratio defines how excess space is distributed among rows. Excess * space means the space left over from components that are not sized * relatively. By default, the excess space is distributed evenly. * </p> - * + * * <p> * Note, that height needs to be defined (fixed or relative, as opposed to * undefined height) for this method to have any effect. * </p> - * + * * @see #setHeight(float, int) - * + * * @param rowIndex * The row index, starting from 0 for the topmost row. * @param ratio @@ -1112,9 +1117,9 @@ public class GridLayout extends AbstractLayout implements /** * Returns the expand ratio of given row. - * + * * @see #setRowExpandRatio(int, float) - * + * * @param rowIndex * The row index, starting from 0 for the topmost row. * @return the expand ratio, 0.0f by default @@ -1126,7 +1131,7 @@ public class GridLayout extends AbstractLayout implements /** * Gets the Component at given index. - * + * * @param x * The column index, starting from 0 for the leftmost column. * @param y @@ -1134,7 +1139,7 @@ public class GridLayout extends AbstractLayout implements * @return Component in given cell or null if empty */ public Component getComponent(int x, int y) { - for (Entry<Connector, ChildComponentData> entry : getState().childData + for (Entry<Connector, ChildComponentData> entry : getState(false).childData .entrySet()) { ChildComponentData childData = entry.getValue(); if (childData.column1 <= x && x <= childData.column2 @@ -1148,14 +1153,14 @@ public class GridLayout extends AbstractLayout implements /** * Returns information about the area where given component is laid in the * GridLayout. - * + * * @param component * the component whose area information is requested. * @return an Area object that contains information how component is laid in * the grid */ public Area getComponentArea(Component component) { - ChildComponentData childComponentData = getState().childData + ChildComponentData childComponentData = getState(false).childData .get(component); if (childComponentData == null) { return null; @@ -1226,7 +1231,7 @@ public class GridLayout extends AbstractLayout implements */ @Override public MarginInfo getMargin() { - return new MarginInfo(getState().marginsBitmask); + return new MarginInfo(getState(false).marginsBitmask); } /* diff --git a/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java index b4685adcea..c73840e6e9 100644 --- a/server/src/com/vaadin/ui/Label.java +++ b/server/src/com/vaadin/ui/Label.java @@ -155,6 +155,11 @@ public class Label extends AbstractComponent implements Property<String>, return (LabelState) super.getState(); } + @Override + protected LabelState getState(boolean markAsDirty) { + return (LabelState) super.getState(markAsDirty); + } + /** * Gets the value of the label. * <p> @@ -168,7 +173,7 @@ public class Label extends AbstractComponent implements Property<String>, public String getValue() { if (getPropertyDataSource() == null) { // Use internal value if we are running without a data source - return getState().text; + return getState(false).text; } return getDataSourceValue(); } @@ -196,7 +201,7 @@ public class Label extends AbstractComponent implements Property<String>, public void setValue(String newStringValue) { if (getPropertyDataSource() == null) { - LabelState state = (LabelState) getState(false); + LabelState state = getState(false); String oldTextValue = state.text; if (!SharedUtil.equals(oldTextValue, newStringValue)) { getState().text = newStringValue; @@ -281,7 +286,7 @@ public class Label extends AbstractComponent implements Property<String>, * @see ContentMode */ public ContentMode getContentMode() { - return getState().contentMode; + return getState(false).contentMode; } /** @@ -412,8 +417,7 @@ public class Label extends AbstractComponent implements Property<String>, private void updateValueFromDataSource() { // Update the internal value from the data source String newConvertedValue = getDataSourceValue(); - if (!SharedUtil.equals(newConvertedValue, - ((LabelState) getState(false)).text)) { + if (!SharedUtil.equals(newConvertedValue, getState(false).text)) { getState().text = newConvertedValue; fireValueChange(); } diff --git a/server/src/com/vaadin/ui/MenuBar.java b/server/src/com/vaadin/ui/MenuBar.java index 17a2f8e391..6b6555c0a2 100644 --- a/server/src/com/vaadin/ui/MenuBar.java +++ b/server/src/com/vaadin/ui/MenuBar.java @@ -57,6 +57,11 @@ public class MenuBar extends AbstractComponent implements LegacyComponent, return (MenuBarState) super.getState(); } + @Override + protected MenuBarState getState(boolean markAsDirty) { + return (MenuBarState) super.getState(markAsDirty); + } + /** Paint (serialise) the component for the client. */ @Override public void paintContent(PaintTarget target) throws PaintException { @@ -396,7 +401,7 @@ public class MenuBar extends AbstractComponent implements LegacyComponent, @Override public int getTabIndex() { - return getState().tabIndex; + return getState(false).tabIndex; } /* diff --git a/server/src/com/vaadin/ui/Panel.java b/server/src/com/vaadin/ui/Panel.java index 34ff6ec112..9b1d8fd5fa 100644 --- a/server/src/com/vaadin/ui/Panel.java +++ b/server/src/com/vaadin/ui/Panel.java @@ -171,7 +171,7 @@ public class Panel extends AbstractSingleComponentContainer implements */ @Override public int getScrollLeft() { - return getState().scrollLeft; + return getState(false).scrollLeft; } /* @@ -181,7 +181,7 @@ public class Panel extends AbstractSingleComponentContainer implements */ @Override public int getScrollTop() { - return getState().scrollTop; + return getState(false).scrollTop; } /* @@ -309,7 +309,7 @@ public class Panel extends AbstractSingleComponentContainer implements */ @Override public int getTabIndex() { - return getState().tabIndex; + return getState(false).tabIndex; } /** @@ -334,4 +334,9 @@ public class Panel extends AbstractSingleComponentContainer implements return (PanelState) super.getState(); } + @Override + protected PanelState getState(boolean markAsDirty) { + return (PanelState) super.getState(markAsDirty); + } + } diff --git a/server/src/com/vaadin/ui/PopupDateField.java b/server/src/com/vaadin/ui/PopupDateField.java index 61aac16a97..f07ac84160 100644 --- a/server/src/com/vaadin/ui/PopupDateField.java +++ b/server/src/com/vaadin/ui/PopupDateField.java @@ -93,6 +93,11 @@ public class PopupDateField extends DateField { return (PopupDateFieldState) super.getState(); } + @Override + protected PopupDateFieldState getState(boolean markAsDirty) { + return (PopupDateFieldState) super.getState(markAsDirty); + } + /** * Checks whether the text field is enabled (default) or not. * @@ -101,7 +106,7 @@ public class PopupDateField extends DateField { * @return <b>true</b> if the text field is enabled, <b>false</b> otherwise. */ public boolean isTextFieldEnabled() { - return getState().textFieldEnabled; + return getState(false).textFieldEnabled; } /** @@ -136,6 +141,6 @@ public class PopupDateField extends DateField { * @return String with the description */ public String getAssistiveText() { - return getState().descriptionForAssistiveDevices; + return getState(false).descriptionForAssistiveDevices; } } diff --git a/server/src/com/vaadin/ui/PopupView.java b/server/src/com/vaadin/ui/PopupView.java index b347576b22..90c60edc6e 100644 --- a/server/src/com/vaadin/ui/PopupView.java +++ b/server/src/com/vaadin/ui/PopupView.java @@ -61,6 +61,11 @@ public class PopupView extends AbstractComponent implements HasComponents { /* Constructors */ + private PopupView() { + registerRpc(rpc); + setHideOnMouseOut(true); + } + /** * A simple way to create a PopupPanel. Note that the minimal representation * may not be dynamically updated, in order to achieve this create your own @@ -94,9 +99,7 @@ public class PopupView extends AbstractComponent implements HasComponents { * the PopupView.Content that contains the information for this */ public PopupView(PopupView.Content content) { - super(); - registerRpc(rpc); - setHideOnMouseOut(true); + this(); setContent(content); } @@ -185,7 +188,7 @@ public class PopupView extends AbstractComponent implements HasComponents { * @return true if the popup is hidden on mouse out, false otherwise */ public boolean isHideOnMouseOut() { - return getState().hideOnMouseOut; + return getState(false).hideOnMouseOut; } /** @@ -234,6 +237,11 @@ public class PopupView extends AbstractComponent implements HasComponents { return (PopupViewState) super.getState(); } + @Override + protected PopupViewState getState(boolean markAsDirty) { + return (PopupViewState) super.getState(markAsDirty); + } + /** * Used to deliver customized content-packages to the PopupView. These are * dynamically loaded when they are redrawn. The user must take care that diff --git a/server/src/com/vaadin/ui/Slider.java b/server/src/com/vaadin/ui/Slider.java index e108c74ba2..ff6c955e47 100644 --- a/server/src/com/vaadin/ui/Slider.java +++ b/server/src/com/vaadin/ui/Slider.java @@ -144,13 +144,18 @@ public class Slider extends AbstractField<Double> { return (SliderState) super.getState(); } + @Override + public SliderState getState(boolean markAsDirty) { + return (SliderState) super.getState(markAsDirty); + } + /** * Gets the maximum slider value * * @return the largest value the slider can have */ public double getMax() { - return getState().maxValue; + return getState(false).maxValue; } /** @@ -173,7 +178,7 @@ public class Slider extends AbstractField<Double> { * @return the smallest value the slider can have */ public double getMin() { - return getState().minValue; + return getState(false).minValue; } /** @@ -197,7 +202,7 @@ public class Slider extends AbstractField<Double> { * {@link SliderOrientation#VERTICAL} */ public SliderOrientation getOrientation() { - return getState().orientation; + return getState(false).orientation; } /** @@ -219,7 +224,7 @@ public class Slider extends AbstractField<Double> { * @return resolution */ public int getResolution() { - return getState().resolution; + return getState(false).resolution; } /** diff --git a/server/src/com/vaadin/ui/TextArea.java b/server/src/com/vaadin/ui/TextArea.java index 56c97f58eb..e38be8ad3c 100644 --- a/server/src/com/vaadin/ui/TextArea.java +++ b/server/src/com/vaadin/ui/TextArea.java @@ -85,6 +85,11 @@ public class TextArea extends AbstractTextField { return (TextAreaState) super.getState(); } + @Override + protected TextAreaState getState(boolean markAsDirty) { + return (TextAreaState) super.getState(markAsDirty); + } + /** * Sets the number of rows in the text area. * @@ -104,7 +109,7 @@ public class TextArea extends AbstractTextField { * @return number of explicitly set rows. */ public int getRows() { - return getState().rows; + return getState(false).rows; } /** @@ -125,7 +130,7 @@ public class TextArea extends AbstractTextField { * <code>false</code> if not. */ public boolean isWordwrap() { - return getState().wordwrap; + return getState(false).wordwrap; } } diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 562b30f81d..a72cbe5c30 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -1581,7 +1581,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements * @return the label of the container */ public String getOverlayContainerLabel() { - return getState().overlayContainerLabel; + return getState(false).overlayContainerLabel; } /** diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java index 149fcd536f..35583c6052 100644 --- a/server/src/com/vaadin/ui/Window.java +++ b/server/src/com/vaadin/ui/Window.java @@ -36,9 +36,9 @@ import com.vaadin.server.PaintTarget; import com.vaadin.shared.Connector; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.window.WindowMode; +import com.vaadin.shared.ui.window.WindowRole; import com.vaadin.shared.ui.window.WindowServerRpc; import com.vaadin.shared.ui.window.WindowState; -import com.vaadin.shared.ui.window.WindowRole; import com.vaadin.util.ReflectTools; /** @@ -254,7 +254,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @since 4.0.0 */ public int getPositionX() { - return getState().positionX; + return getState(false).positionX; } /** @@ -283,7 +283,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @since 4.0.0 */ public int getPositionY() { - return getState().positionY; + return getState(false).positionY; } /** @@ -661,7 +661,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @return true if this window is modal. */ public boolean isModal() { - return getState().modal; + return getState(false).modal; } /** @@ -679,7 +679,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @return true if window is resizable by the end-user, otherwise false. */ public boolean isResizable() { - return getState().resizable; + return getState(false).resizable; } /** @@ -688,7 +688,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * sizes are recalculated immediately. */ public boolean isResizeLazy() { - return getState().resizeLazy; + return getState(false).resizeLazy; } /** @@ -764,7 +764,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * true if the window can be dragged by the user */ public boolean isDraggable() { - return getState().draggable; + return getState(false).draggable; } /** @@ -1034,7 +1034,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @return array of previously set components */ public Component[] getAssistiveDescription() { - Connector[] contentDescription = getState().contentDescription; + Connector[] contentDescription = getState(false).contentDescription; if (contentDescription == null) { return null; } @@ -1068,7 +1068,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @return The accessibility prefix */ public String getAssistivePrefix() { - return getState().assistivePrefix; + return getState(false).assistivePrefix; } /** @@ -1093,7 +1093,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @return The accessibility postfix */ public String getAssistivePostfix() { - return getState().assistivePostfix; + return getState(false).assistivePostfix; } /** @@ -1124,7 +1124,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @return WAI-ARIA role set for the window */ public WindowRole getAssistiveRole() { - return getState().role; + return getState(false).role; } /** @@ -1152,7 +1152,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * focus can leave the window */ public boolean isTabStopEnabled() { - return getState().assistiveTabStop; + return getState(false).assistiveTabStop; } /** @@ -1193,7 +1193,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @return the top message */ public String getTabStopTopAssistiveText() { - return getState().assistiveTabStopTopText; + return getState(false).assistiveTabStopTopText; } /** @@ -1204,6 +1204,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * @return the bottom message */ public String getTabStopBottomAssistiveText() { - return getState().assistiveTabStopBottomText; + return getState(false).assistiveTabStopBottomText; } } diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGradient.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGradient.java index 6147fcdd96..81b178e4f0 100644 --- a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGradient.java +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGradient.java @@ -56,7 +56,7 @@ public class ColorPickerGradient extends AbstractComponent implements }; /** The converter. */ - private final Coordinates2Color converter; + private Coordinates2Color converter; /** The foreground color. */ private Color color; @@ -67,6 +67,14 @@ public class ColorPickerGradient extends AbstractComponent implements /** The y-coordinate. */ private int y = 0; + private ColorPickerGradient() { + registerRpc(rpc); + // width and height must be set here instead of in theme, otherwise + // coordinate calculations fail + getState().width = "220px"; + getState().height = "220px"; + } + /** * Instantiates a new color picker gradient. * @@ -76,12 +84,8 @@ public class ColorPickerGradient extends AbstractComponent implements * the converter */ public ColorPickerGradient(String id, Coordinates2Color converter) { - registerRpc(rpc); + this(); addStyleName(id); - // width and height must be set here instead of in theme, otherwise - // coordinate calculations fail - getState().width = "220px"; - getState().height = "220px"; this.converter = converter; } diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java index e7b412f7eb..b9a8c001ce 100644 --- a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java @@ -143,14 +143,7 @@ public class ColorPickerPopup extends Window implements ClickListener, */ private boolean updatingColors = false; - /** - * Instantiates a new color picker popup. - */ - public ColorPickerPopup(Color initialColor) { - super(); - - selectedColor = initialColor; - + private ColorPickerPopup() { // Set the layout layout = new VerticalLayout(); layout.setSpacing(false); @@ -162,15 +155,21 @@ public class ColorPickerPopup extends Window implements ClickListener, setStyleName(STYLENAME); setResizable(false); setImmediate(true); + // Create the history + history = new ColorPickerHistory(); + history.addColorChangeListener(this); + } + /** + * Instantiates a new color picker popup. + */ + public ColorPickerPopup(Color initialColor) { + this(); + selectedColor = initialColor; initContents(); } private void initContents() { - // Create the history - history = new ColorPickerHistory(); - history.addColorChangeListener(this); - // Create the preview on the rgb tab rgbPreview = new ColorPickerPreview(selectedColor); rgbPreview.setWidth("240px"); diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java index ae00b267ce..21a3630de2 100644 --- a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java @@ -56,24 +56,23 @@ public class ColorPickerPreview extends CssLayout implements ColorSelector, /** The old value. */ private String oldValue; - /** - * Instantiates a new color picker preview. - */ - public ColorPickerPreview(Color color) { + private ColorPickerPreview() { setStyleName("v-colorpicker-preview"); setImmediate(true); - - this.color = color; - field = new TextField(); field.setImmediate(true); field.setSizeFull(); field.setStyleName("v-colorpicker-preview-textfield"); field.setData(this); field.addValueChangeListener(this); - addComponent(field); + } + /** + * Instantiates a new color picker preview. + */ + public ColorPickerPreview(Color color) { + this(); setColor(color); } diff --git a/server/tests/src/com/vaadin/tests/server/component/StateGetDoesNotMarkDirty.java b/server/tests/src/com/vaadin/tests/server/component/StateGetDoesNotMarkDirty.java new file mode 100644 index 0000000000..280d638707 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/StateGetDoesNotMarkDirty.java @@ -0,0 +1,100 @@ +package com.vaadin.tests.server.component; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +import junit.framework.TestCase; + +import org.mockito.Mockito; + +import com.vaadin.tests.VaadinClasses; +import com.vaadin.ui.Component; +import com.vaadin.ui.ConnectorTracker; +import com.vaadin.ui.Label; +import com.vaadin.ui.UI; + +public class StateGetDoesNotMarkDirty extends TestCase { + + private Set<String> excludedMethods = new HashSet<String>(); + + @Override + protected void setUp() throws Exception { + excludedMethods.add(Label.class.getName() + "getDataSourceValue"); + excludedMethods.add("getConnectorId"); + } + + public void testGetDoesntMarkStateDirty() throws Exception { + for (Class<? extends Component> c : VaadinClasses.getComponents()) { + Component newInstance = construct(c); + prepareMockUI(newInstance); + + Set<Method> methods = new HashSet<Method>(); + methods.addAll(Arrays.asList(c.getMethods())); + methods.addAll(Arrays.asList(c.getDeclaredMethods())); + for (Method method : methods) { + try { + if (method.getName().startsWith("is") + || method.getName().startsWith("get")) { + if (method.getName().startsWith("getState")) { + continue; + } + if (method.getParameterTypes().length > 0) { + // usually getters do not have params, if they have + // we still wouldnt know what to put into + continue; + } + if (excludedMethods.contains(c.getName() + + method.getName())) { + // blacklisted method for specific classes + continue; + } + if (excludedMethods.contains(method.getName())) { + // blacklisted method for all classes + continue; + } + // just to make sure we can invoke it + method.setAccessible(true); + method.invoke(newInstance); + } + } catch (Exception e) { + System.err.println("problem with method " + c.getName() + + "# " + method.getName()); + e.printStackTrace(); + throw e; + } + } + } + + } + + private void prepareMockUI(Component newInstance) { + UI ui = Mockito.mock(UI.class); + Mockito.when(ui.getLocale()).thenReturn(Locale.ENGLISH); + ConnectorTracker connectorTracker = Mockito + .mock(ConnectorTracker.class); + Mockito.when(ui.getConnectorTracker()).thenReturn(connectorTracker); + Mockito.doThrow(new RuntimeException("getState(true) called in getter")) + .when(connectorTracker).markDirty(newInstance); + + newInstance.setParent(ui); + } + + private Component construct(Class<? extends Component> c) { + try { + try { + Constructor<? extends Component> declaredConstructor = c + .getDeclaredConstructor(); + declaredConstructor.setAccessible(true); + return declaredConstructor.newInstance(); + } catch (NoSuchMethodException e) { + return c.newInstance(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java index 53317bd581..43d6a55a8b 100644 --- a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java +++ b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java @@ -49,7 +49,7 @@ public class VerifyBrowserVersionTest extends MultiBrowserTest { "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36"); expectedUserAgent .put(Browser.PHANTOMJS.getDesiredCapabilities(), - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.7 Safari/534.34"); + "Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.7 Safari/534.34"); } diff --git a/uitest/src/com/vaadin/tests/components/LongTooltip.html b/uitest/src/com/vaadin/tests/components/LongTooltip.html deleted file mode 100644 index a5055741f1..0000000000 --- a/uitest/src/com/vaadin/tests/components/LongTooltip.html +++ /dev/null @@ -1,324 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<!--Lower-right--> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.LongTooltip?restartApplication</td> - <td></td> -</tr> -<!--Show tooltip, which should be on screen--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VTextField[0]</td> - <td>0,0</td> -</tr> -<!--Wait for tooltip to appear--> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-lower-right-1</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]</td> - <td>55,43</td> -</tr> -<!--Wait for tooltip to disappear. Cannot for some reason use waitForNotVisible--> -<tr> - <td>pause</td> - <td>500</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VTextField[0]</td> - <td>0,0</td> -</tr> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-lower-right-2</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]</td> - <td>55,43</td> -</tr> -<!--Wait for tooltip to disappear. Cannot for some reason use waitForNotVisible--> -<tr> - <td>pause</td> - <td>500</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VTextField[0]</td> - <td>100,20</td> -</tr> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-lower-right-3</td> -</tr> -<!--Upper-right--> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.LongTooltip?restartApplication</td> - <td></td> -</tr> -<!--Show tooltip, which should be on screen--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VTextField[0]</td> - <td>0,0</td> -</tr> -<!--Wait for tooltip to appear--> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-upper-right-1</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]</td> - <td>55,43</td> -</tr> -<!--Wait for tooltip to disappear. Cannot for some reason use waitForNotVisible--> -<tr> - <td>pause</td> - <td>500</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VTextField[0]</td> - <td>0,0</td> -</tr> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-upper-right-2</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]</td> - <td>55,43</td> -</tr> -<!--Wait for tooltip to disappear. Cannot for some reason use waitForNotVisible--> -<tr> - <td>pause</td> - <td>500</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VTextField[0]</td> - <td>100,20</td> -</tr> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-upper-right-3</td> -</tr> -<!--Lower-left--> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.LongTooltip?restartApplication</td> - <td></td> -</tr> -<!--Show tooltip, which should be on screen--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VTextField[0]</td> - <td>0,0</td> -</tr> -<!--Wait for tooltip to appear--> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-lower-left-1</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]</td> - <td>55,43</td> -</tr> -<!--Wait for tooltip to disappear. Cannot for some reason use waitForNotVisible--> -<tr> - <td>pause</td> - <td>500</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VTextField[0]</td> - <td>0,0</td> -</tr> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-lower-left-2</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]</td> - <td>55,43</td> -</tr> -<!--Wait for tooltip to disappear. Cannot for some reason use waitForNotVisible--> -<tr> - <td>pause</td> - <td>500</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VTextField[0]</td> - <td>100,20</td> -</tr> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-lower-left-3</td> -</tr> -<!--Upper-left--> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.LongTooltip?restartApplication</td> - <td></td> -</tr> -<!--Show tooltip, which should be on screen--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VTextField[0]</td> - <td>0,0</td> -</tr> -<!--Wait for tooltip to appear--> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-upper-left-1</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]</td> - <td>55,43</td> -</tr> -<!--Wait for tooltip to disappear. Cannot for some reason use waitForNotVisible--> -<tr> - <td>pause</td> - <td>500</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VTextField[0]</td> - <td>0,0</td> -</tr> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-upper-left-2</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]</td> - <td>55,43</td> -</tr> -<!--Wait for tooltip to disappear. Cannot for some reason use waitForNotVisible--> -<tr> - <td>pause</td> - <td>500</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VTextField[0]</td> - <td>100,20</td> -</tr> -<tr> - <td>waitForVisible</td> - <td>vaadin=runcomvaadintestscomponentsLongTooltip::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-upper-left-3</td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEvents.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEvents.java new file mode 100644 index 0000000000..2025ce2ea7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEvents.java @@ -0,0 +1,103 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.calendar; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Calendar; +import com.vaadin.ui.components.calendar.event.BasicEvent; +import com.vaadin.ui.components.calendar.event.CalendarEvent; +import com.vaadin.ui.components.calendar.event.CalendarEventProvider; + +/** + * + * @author Vaadin Ltd + */ +public class CalendarResizeOverlappingEvents extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + Calendar calendar = new Calendar(new CalendarEventProvider() { + + @Override + public List<CalendarEvent> getEvents(Date startDate, Date endDate) { + DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + DateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd"); + List<CalendarEvent> events = new ArrayList<CalendarEvent>(); + try { + java.util.Calendar today = java.util.Calendar.getInstance(); + + String todayString = dayFormat.format(today.getTime()); + + Date date1 = format.parse(todayString + " 09:00:00"); + Date date2 = format.parse(todayString + " 11:00:00"); + Date date3 = format.parse(todayString + " 12:00:00"); + Date date4 = format.parse(todayString + " 14:00:00"); + Date date5 = format.parse(todayString + " 15:00:00"); + Date date6 = format.parse(todayString + " 17:00:00"); + + CalendarEvent event1 = new BasicEvent("First", "", date1, + date2); + CalendarEvent event2 = new BasicEvent("Second", "", date3, + date4); + CalendarEvent event3 = new BasicEvent("Third", "", date5, + date6); + + events.add(event1); + events.add(event2); + events.add(event3); + } catch (ParseException e) { + } + return events; + } + }); + calendar.setSizeFull(); + setContent(calendar); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Verify the widths of the events are correctly recalculated when these are resized and overlapped"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 13961; + } +} diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEventsTest.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEventsTest.java new file mode 100644 index 0000000000..f664149cce --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEventsTest.java @@ -0,0 +1,153 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.calendar; + +import java.io.IOException; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * + * @author Vaadin Ltd + */ +public class CalendarResizeOverlappingEventsTest extends MultiBrowserTest { + + private int noOverlapWidth; + private int oneOverlapWidth; + private int twoOverlapsWidth; + + private WebElement firstEvent; + private WebElement secondEvent; + private WebElement thirdEvent; + + private WebElement firstEventBottomResize; + private WebElement secondEventBottomResize; + private WebElement thirdEventBottomResize; + + @Test + public void testCalendarResizeOverlappingEvents() + throws InterruptedException, IOException { + + openTestURL(); + initParams(); + doTest(); + } + + private void doTest() { + assertWidths(noOverlapWidth, noOverlapWidth, noOverlapWidth); + + dragAndDrop(firstEventBottomResize, 240); + assertWidths(oneOverlapWidth, oneOverlapWidth, oneOverlapWidth); + + dragAndDrop(secondEventBottomResize, 240); + assertWidths(twoOverlapsWidth, twoOverlapsWidth, twoOverlapsWidth); + + dragAndDrop(secondEventBottomResize, -240); + dragAndDrop(firstEventBottomResize, -240); + assertWidths(noOverlapWidth, noOverlapWidth, noOverlapWidth); + + } + + private void assertWidths(int firstEventExpectedWidth, + int secondEventExpectedWidth, int thirdEventExpectedWidth) { + int widthTolerance = 5; + String errorMessage = "Wrong event width after resizing, expected [%d] (+/-%d), obtained [%d]"; + + int actualWidth = firstEvent.getSize().getWidth(); + int expectedWidth = firstEventExpectedWidth; + Assert.assertTrue(String.format(errorMessage, expectedWidth, + widthTolerance, actualWidth), + isAproximateWidth(actualWidth, expectedWidth, widthTolerance)); + + actualWidth = secondEvent.getSize().getWidth(); + expectedWidth = secondEventExpectedWidth; + Assert.assertTrue(String.format(errorMessage, expectedWidth, + widthTolerance, actualWidth), + isAproximateWidth(actualWidth, expectedWidth, widthTolerance)); + + actualWidth = thirdEvent.getSize().getWidth(); + expectedWidth = thirdEventExpectedWidth; + Assert.assertTrue(String.format(errorMessage, expectedWidth, + widthTolerance, actualWidth), + isAproximateWidth(actualWidth, expectedWidth, widthTolerance)); + } + + private boolean isAproximateWidth(int actualWidth, int expectedWidth, + int tolerance) { + return Math.abs(expectedWidth - actualWidth) <= tolerance; + } + + private void dragAndDrop(WebElement element, int yOffset) { + /* + * Selenium doesn't properly drag and drop items in IE8. It tries to + * start dragging an element from a position above the element itself. + */ + if (BrowserUtil.isIE8(getDesiredCapabilities())) { + Actions action = new Actions(getDriver()); + action.moveToElement(element); + action.moveByOffset(0, 1); + action.clickAndHold(); + action.moveByOffset(0, yOffset); + action.release(); + action.build().perform(); + } else { + Actions action = new Actions(getDriver()); + action.dragAndDropBy(element, 0, yOffset); + action.build().perform(); + } + } + + private void initParams() { + WebElement dateSlot = getDriver().findElement( + By.className("v-datecellslot")); + int dateSlotWidth = dateSlot.getSize().getWidth(); + noOverlapWidth = dateSlotWidth; + oneOverlapWidth = dateSlotWidth / 2; + twoOverlapsWidth = dateSlotWidth / 3; + + Comparator<WebElement> startTimeComparator = new Comparator<WebElement>() { + @Override + public int compare(WebElement e1, WebElement e2) { + int e1Top = e1.getLocation().getY(); + int e2Top = e2.getLocation().getY(); + return e1Top - e2Top; + } + }; + + List<WebElement> eventElements = getDriver().findElements( + By.className("v-calendar-event-content")); + Collections.sort(eventElements, startTimeComparator); + firstEvent = eventElements.get(0); + secondEvent = eventElements.get(1); + thirdEvent = eventElements.get(2); + + List<WebElement> resizeBottomElements = getDriver().findElements( + By.className("v-calendar-event-resizebottom")); + Collections.sort(resizeBottomElements, startTimeComparator); + firstEventBottomResize = resizeBottomElements.get(0); + secondEventBottomResize = resizeBottomElements.get(1); + thirdEventBottomResize = resizeBottomElements.get(2); + } +} diff --git a/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRpcCount.java b/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRpcCount.java new file mode 100644 index 0000000000..bd44e8a074 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRpcCount.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.checkbox; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Label; + +public class CheckBoxRpcCount extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final Label countLabel = new Label("No RPC calls made yet."); + countLabel.setId("count-label"); + addComponent(countLabel); + + CheckBox cb = new CheckBox("Click me to start counting...") { + { + // Register a new RPC that counts the number of invocations. + registerRpc(new CheckBoxServerRpc() { + private int rpcCount = 0; + + @Override + public void setChecked(boolean checked, + MouseEventDetails mouseEventDetails) { + rpcCount++; + countLabel.setValue(rpcCount + " RPC call(s) made."); + } + + }); + } + }; + addComponent(cb); + } + + @Override + protected String getTestDescription() { + return "Test for verifying that no extra RPC calls are made when clicking on CheckBox label."; + } + + @Override + protected Integer getTicketNumber() { + return 8259; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRpcCountTest.java b/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRpcCountTest.java new file mode 100644 index 0000000000..9d6640eb6d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRpcCountTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.checkbox; + +import static org.junit.Assert.assertEquals; + +import com.vaadin.testbench.elements.CheckBoxElement; +import com.vaadin.testbench.elements.LabelElement; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; +import org.openqa.selenium.support.ui.ExpectedCondition; + +public class CheckBoxRpcCountTest extends MultiBrowserTest { + + @Test + public void numberOfRpcCallsIsEqualToClicks() { + openTestURL(); + + CheckBoxElement checkBoxElement = $(CheckBoxElement.class).first(); + WebElement labelElem = checkBoxElement.findElement(By.tagName("label")); + WebElement inputElem = checkBoxElement.findElement(By.tagName("input")); + final WebElement countElem = $(LabelElement.class).id("count-label"); + + // Click on the actual checkbox. + inputElem.click(); + //Have to use waitUntil to make this test more stable. + waitUntilLabelIsUpdated(countElem, "1 RPC call(s) made."); + + // Click on the checkbox label. + labelElem.click(); + waitUntilLabelIsUpdated(countElem, "2 RPC call(s) made."); + + // Again on the label. + labelElem.click(); + waitUntilLabelIsUpdated(countElem, "3 RPC call(s) made."); + } + + private void waitUntilLabelIsUpdated(final WebElement countElem, final String expectedText) { + waitUntil(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver input) { + return countElem.getText().equals(expectedText); + } + }, 5); + } +} diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxInputPrompt.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxInputPrompt.java new file mode 100644 index 0000000000..082aca6989 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxInputPrompt.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.combobox; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.ComboBox; + +public class ComboBoxInputPrompt extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final ComboBox cb1 = new ComboBox("Normal"); + cb1.setInputPrompt("Normal input prompt"); + + final ComboBox cb2 = new ComboBox("Disabled"); + cb2.setEnabled(false); + cb2.setInputPrompt("Disabled input prompt"); + + final ComboBox cb3 = new ComboBox("Read-only"); + cb3.setReadOnly(true); + cb3.setInputPrompt("Read-only input prompt"); + + Button enableButton = new Button("Toggle enabled", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + cb2.setEnabled(!cb2.isEnabled()); + cb3.setReadOnly(!cb3.isReadOnly()); + } + }); + + addComponents(cb1, cb2, cb3, enableButton); + } + + @Override + protected String getTestDescription() { + return "ComboBox should not display the input prompt if disabled or read-only."; + } + + @Override + protected Integer getTicketNumber() { + return 10573; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxInputPromptTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxInputPromptTest.java new file mode 100644 index 0000000000..96151022ff --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxInputPromptTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.combobox; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isEmptyString; +import static org.junit.Assert.assertEquals; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.ComboBoxElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.AbstractTB3Test; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class ComboBoxInputPromptTest extends MultiBrowserTest { + + @Test + public void promptIsHiddenForDisabledAndReadonly() { + openTestURL(); + + ComboBoxElement normalComboBox = getComboBoxWithCaption("Normal"); + ComboBoxElement disabledComboBox = getComboBoxWithCaption("Disabled"); + ComboBoxElement readOnlyComboBox = getComboBoxWithCaption("Read-only"); + + assertThat(getInputPromptValue(normalComboBox), is("Normal input prompt")); + assertThat(getInputPromptValue(disabledComboBox), isEmptyString()); + assertThat(getInputPromptValue(readOnlyComboBox), isEmptyString()); + + toggleDisabledAndReadonly(); + assertThat(getInputPromptValue(disabledComboBox), is("Disabled input prompt")); + assertThat(getInputPromptValue(readOnlyComboBox), is("Read-only input prompt")); + + toggleDisabledAndReadonly(); + assertThat(getInputPromptValue(disabledComboBox), isEmptyString()); + assertThat(getInputPromptValue(readOnlyComboBox), isEmptyString()); + } + + private void toggleDisabledAndReadonly() { + $(ButtonElement.class).first().click(); + } + + private String getInputPromptValue(ComboBoxElement comboBox) { + WebElement input = comboBox.findElement(By.tagName("input")); + + return input.getAttribute("value"); + } + + private ComboBoxElement getComboBoxWithCaption(String caption) { + return $(ComboBoxElement.class).caption(caption).first(); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxScrollingWithArrowsTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxScrollingWithArrowsTest.java index bc03593e3f..fa6f5a3a93 100644 --- a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxScrollingWithArrowsTest.java +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxScrollingWithArrowsTest.java @@ -15,16 +15,19 @@ */ package com.vaadin.tests.components.combobox; -import java.util.List; - -import org.junit.Assert; -import org.junit.Before; +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ComboBoxElement; +import com.vaadin.tests.tb3.MultiBrowserTest; import org.junit.Test; import org.openqa.selenium.Keys; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; -import com.vaadin.testbench.By; -import com.vaadin.tests.tb3.MultiBrowserTest; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; /** * When pressed down key, while positioned on the last item - should show next @@ -32,52 +35,72 @@ import com.vaadin.tests.tb3.MultiBrowserTest; */ public class ComboBoxScrollingWithArrowsTest extends MultiBrowserTest { - @Before - public void openURL() { + private final int PAGESIZE = 10; + + @Override + public void setup() throws Exception { + super.setup(); + openTestURL(); + openPopup(); } - @Test - public void scrollDownArrowKeyTest() throws InterruptedException { - final int ITEMS_PER_PAGE = 10; + private WebElement getDropDown() { // Selenium is used instead of TestBench4, because there is no method to // access the popup of the combobox // The method ComboBoxElement.openPopup() opens the popup, but doesn't // provide any way to access the popup and send keys to it. // Ticket #13756 - WebElement dropDownComboBox = driver.findElement(By + + return driver.findElement(By .className("v-filterselect-input")); - // opens Lookup - dropDownComboBox.sendKeys(Keys.DOWN); + } + + private void openPopup() { + ComboBoxElement cb = $(ComboBoxElement.class).first(); + cb.openPopup(); + } + + @Test + public void scrollDownArrowKeyTest() throws InterruptedException { + WebElement dropDownComboBox = getDropDown(); + // go to the last item and then one more - for (int i = 0; i < ITEMS_PER_PAGE + 1; i++) { + for (int i = 0; i < PAGESIZE + 1; i++) { dropDownComboBox.sendKeys(Keys.DOWN); } - String expected = "item " + ITEMS_PER_PAGE;// item 10 + assertThat(getSelectedItemText(), is("item " + PAGESIZE)); //item 10 + } + + private String getSelectedItemText() { List<WebElement> items = driver.findElements(By .className("gwt-MenuItem-selected")); - String actual = items.get(0).getText(); - Assert.assertEquals(expected, actual); + return items.get(0).getText(); } @Test public void scrollUpArrowKeyTest() throws InterruptedException { - final int ITEMS_PER_PAGE = 10; - WebElement dropDownComboBox = driver.findElement(By - .className("v-filterselect-input")); - // opens Lookup - dropDownComboBox.sendKeys(Keys.DOWN); + WebElement dropDownComboBox = getDropDown(); + // go to the last item and then one more - for (int i = 0; i < ITEMS_PER_PAGE + 1; i++) { + for (int i = 0; i < PAGESIZE + 1; i++) { dropDownComboBox.sendKeys(Keys.DOWN); } + // move to one item up + waitUntilNextPageIsVisible(); dropDownComboBox.sendKeys(Keys.UP); - String expected = "item " + (ITEMS_PER_PAGE - 1);// item 9 - List<WebElement> items = driver.findElements(By - .className("gwt-MenuItem-selected")); - String actual = items.get(0).getText(); - Assert.assertEquals(expected, actual); + + assertThat(getSelectedItemText(), is("item " + (PAGESIZE - 1))); //item 9 + } + + private void waitUntilNextPageIsVisible() { + waitUntil(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver input) { + return getSelectedItemText().equals("item " + PAGESIZE); + } + }, 5); } } diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSetNullWhenNewItemsAllowedTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSetNullWhenNewItemsAllowedTest.java index 54d355ab0a..7951187fa7 100644 --- a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSetNullWhenNewItemsAllowedTest.java +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSetNullWhenNewItemsAllowedTest.java @@ -46,9 +46,11 @@ public class ComboBoxSetNullWhenNewItemsAllowedTest extends MultiBrowserTest { assertEquals("New value", element.getAttribute("value")); if (BrowserUtil.isPhantomJS(getDesiredCapabilities())) { new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); + Thread.sleep(500); } else { element.sendKeys(Keys.RETURN); } + assertEquals("", element.getAttribute("value")); } } diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldReadOnly.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldReadOnly.java index 392dbaf9c6..304c978381 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/DateFieldReadOnly.java +++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldReadOnly.java @@ -3,16 +3,18 @@ package com.vaadin.tests.components.datefield; import java.util.Calendar; import java.util.Locale; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.DateField; -public class DateFieldReadOnly extends TestBase { +public class DateFieldReadOnly extends AbstractTestUI { @Override - protected String getDescription() { + protected String getTestDescription() { return "A read-only DateField should not show the popup button and not be editable."; } @@ -22,7 +24,7 @@ public class DateFieldReadOnly extends TestBase { } @Override - protected void setup() { + protected void setup(VaadinRequest request) { final DateField timeField = new DateField("A read-only datefield"); timeField.setResolution(DateField.RESOLUTION_SEC); timeField.setDateFormat("HH:mm:ss"); @@ -30,6 +32,7 @@ public class DateFieldReadOnly extends TestBase { timeField.setIcon(null); timeField.setWidth("8em"); timeField.addStyleName("timeField"); + timeField.setLocale(new Locale("fi")); // Set date so that testing always has same time Calendar c = Calendar.getInstance(Locale.ENGLISH); diff --git a/uitest/src/com/vaadin/tests/components/datefield/LocaleChange.java b/uitest/src/com/vaadin/tests/components/datefield/LocaleChange.java new file mode 100644 index 0000000000..f69c93419b --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/LocaleChange.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.datefield; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.datefield.Resolution; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.DateField; + +public class LocaleChange extends AbstractTestUI { + + private final Locale locale12hClock = Locale.US; + private final Locale locale24hClock = Locale.FRANCE; + + private final String caption = "Switch to %s hour clock"; + private static final Date dateValue; + static { + try { + dateValue = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss") + .parse("2014-05-22 20:00:00"); + } catch (ParseException e) { + throw new ExceptionInInitializerError("Should never happen."); + } + } + + @Override + protected void setup(VaadinRequest request) { + final DateField df = new DateField(); + df.setLocale(locale24hClock); + df.setResolution(Resolution.SECOND); + df.setValue(dateValue); + + Button button = new Button(String.format(caption, "12")); + button.addClickListener(new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + if (locale12hClock.equals(df.getLocale())) { + df.setLocale(locale24hClock); + event.getButton().setCaption(String.format(caption, "12")); + } else { + df.setLocale(locale12hClock); + event.getButton().setCaption(String.format(caption, "24")); + } + } + }); + + addComponent(df); + addComponent(button); + } + + @Override + protected String getTestDescription() { + return "Testing locale change from one with 24h clock to a 12h clock locale."; + } + + @Override + protected Integer getTicketNumber() { + return 13722; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/datefield/LocaleChangeTest.java b/uitest/src/com/vaadin/tests/components/datefield/LocaleChangeTest.java new file mode 100644 index 0000000000..cf756034a1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/LocaleChangeTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.datefield; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.openqa.selenium.By; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class LocaleChangeTest extends MultiBrowserTest { + + @Test + public void testLocaleChange() { + openTestURL(); + + // Check the initial value and that popup can be opened. + assertEquals("22/05/14 20:00:00", getDateValue()); + toggleDatePopup(); + assertPopupOpen(true); + + // Close the popup and change the locale. + toggleDatePopup(); + assertPopupOpen(false); + driver.findElement(By.className("v-button")).click(); // Locale change. + + // Check that the value has changed and the popup can still be opened + // without problems. + assertEquals("5/22/14 08:00:00 PM", getDateValue()); + toggleDatePopup(); + assertPopupOpen(true); + } + + private void assertPopupOpen(boolean open) { + assertEquals("Date popup was not " + (open ? "open" : "closed") + ".", + (open ? 1 : 0), + driver.findElements(By.className("v-datefield-popup")).size()); + } + + private void toggleDatePopup() { + driver.findElement(By.className("v-datefield-button")).click(); + } + + private String getDateValue() { + return driver.findElement(By.className("v-datefield-textfield")) + .getAttribute("value"); + } +} diff --git a/uitest/src/com/vaadin/tests/components/draganddropwrapper/DragAndDropWrapperTooltips.html b/uitest/src/com/vaadin/tests/components/draganddropwrapper/DragAndDropWrapperTooltips.html deleted file mode 100644 index 3c91c8b24f..0000000000 --- a/uitest/src/com/vaadin/tests/components/draganddropwrapper/DragAndDropWrapperTooltips.html +++ /dev/null @@ -1,53 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.draganddropwrapper.DragAndDropWrapperTooltips?restartApplication</td> - <td></td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsdraganddropwrapperDragAndDropWrapperTooltips::PID_Swrapper3/VLabel[0]</td> - <td>0,0</td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-initial</td> -</tr> -<!--Drag Block 4 between Block 1 and Block 2--> -<tr> - <td>drag</td> - <td>vaadin=runcomvaadintestscomponentsdraganddropwrapperDragAndDropWrapperTooltips::PID_Swrapper4/VLabel[0]</td> - <td>30,41</td> -</tr> -<tr> - <td>drop</td> - <td>vaadin=runcomvaadintestscomponentsdraganddropwrapperDragAndDropWrapperTooltips::PID_Swrapper2</td> - <td>4,42</td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentsdraganddropwrapperDragAndDropWrapperTooltips::PID_Swrapper1/VLabel[0]</td> - <td>0,0</td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>tooltip-after-drag</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/components/form/FormTooltipsTest.java b/uitest/src/com/vaadin/tests/components/form/FormTooltipsTest.java index df18d4082d..cb71fef3ef 100644 --- a/uitest/src/com/vaadin/tests/components/form/FormTooltipsTest.java +++ b/uitest/src/com/vaadin/tests/components/form/FormTooltipsTest.java @@ -33,9 +33,7 @@ public class FormTooltipsTest extends TooltipTest { WebElement fieldElement = $(FormElement.class).first() .$(TextFieldElement.class).first(); checkTooltip(fieldElement, "Fields own tooltip"); - - moveToRoot(); - Thread.sleep(1000); + clearTooltip(); checkTooltipNotPresent(); // first name caption tooltip @@ -43,8 +41,7 @@ public class FormTooltipsTest extends TooltipTest { $(FormElement.class).first().findElement( By.className("v-caption")), "Fields own tooltip"); - moveToRoot(); - Thread.sleep(1000); + clearTooltip(); checkTooltipNotPresent(); // Form should not have a description tooltip diff --git a/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutExpandRatioTest.java b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutExpandRatioTest.java index 7d5ad1fbc4..d4d36bd10f 100644 --- a/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutExpandRatioTest.java +++ b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutExpandRatioTest.java @@ -15,32 +15,30 @@ */ package com.vaadin.tests.components.gridlayout; -import static org.junit.Assert.assertEquals; - -import java.util.List; - +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.GridLayoutElement; +import com.vaadin.tests.tb3.MultiBrowserTest; import org.junit.Test; import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; -import com.vaadin.testbench.elements.ButtonElement; -import com.vaadin.testbench.elements.GridLayoutElement; -import com.vaadin.tests.tb3.MultiBrowserTest; +import java.util.List; + +import static org.junit.Assert.assertEquals; public class GridLayoutExpandRatioTest extends MultiBrowserTest { @Test - public void gridLayoutExpandRatioTest() { + public void cellSizesAreCorrectlyCalculated() { openTestURL(); - GridLayoutElement gridLayout5x5 = $(GridLayoutElement.class).get(0); - GridLayoutElement gridLayout4x4 = $(GridLayoutElement.class).get(1); - ButtonElement hidingButton = $(ButtonElement.class).get(0); - hidingButton.click(); - List<WebElement> slots5x5 = gridLayout5x5.findElements(By - .className("v-gridlayout-slot")); - List<WebElement> slots4x4 = gridLayout4x4.findElements(By - .className("v-gridlayout-slot")); - assertEquals("Different amount of slots", slots5x5.size(), - slots4x4.size()); + + hideMiddleRowAndColumn(); + final List<WebElement> slots4x4 = getSlots(1); + + waitUntilColumnAndRowAreHidden(slots4x4); + final List<WebElement> slots5x5 = getSlots(0); + for (int i = 0; i < slots5x5.size(); i++) { WebElement compared = slots5x5.get(i); WebElement actual = slots4x4.get(i); @@ -50,4 +48,23 @@ public class GridLayoutExpandRatioTest extends MultiBrowserTest { compared.getCssValue("left"), actual.getCssValue("left")); } } + + private void waitUntilColumnAndRowAreHidden(final List<WebElement> slots4x4) { + waitUntil(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver input) { + return getSlots(0).size() == slots4x4.size(); + } + }, 5); + } + + private List<WebElement> getSlots(int index) { + GridLayoutElement layout = $(GridLayoutElement.class).get(index); + + return layout.findElements(By.className("v-gridlayout-slot")); + } + + private void hideMiddleRowAndColumn() { + $(ButtonElement.class).first().click(); + } } diff --git a/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutHideMiddleCellsTest.java b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutHideMiddleCellsTest.java index d0225275f7..a5eb9b6e04 100644 --- a/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutHideMiddleCellsTest.java +++ b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutHideMiddleCellsTest.java @@ -15,43 +15,5 @@ */ package com.vaadin.tests.components.gridlayout; -import static org.junit.Assert.assertEquals; - -import java.util.List; - -import org.junit.Test; -import org.openqa.selenium.By; -import org.openqa.selenium.WebElement; - -import com.vaadin.testbench.elements.ButtonElement; -import com.vaadin.testbench.elements.GridLayoutElement; -import com.vaadin.tests.tb3.MultiBrowserTest; - -public class GridLayoutHideMiddleCellsTest extends MultiBrowserTest { - @Test - public void gridLayoutInvisibleElementsTest() { - openTestURL(); - GridLayoutElement gridLayout5x5 = $(GridLayoutElement.class).get(0); - GridLayoutElement gridLayout4x4 = $(GridLayoutElement.class).get(1); - ButtonElement hidingButton = $(ButtonElement.class).get(0); - hidingButton.click(); - List<WebElement> slots5x5 = gridLayout5x5.findElements(By - .className("v-gridlayout-slot")); - List<WebElement> slots4x4 = gridLayout4x4.findElements(By - .className("v-gridlayout-slot")); - assertEquals("Different amount of slots", slots5x5.size(), - slots4x4.size()); - - for (int i = 0; i < slots5x5.size(); i++) { - assertEquals("Different left coordinate for element " + i, slots5x5 - .get(i).getCssValue("left"), - slots4x4.get(i).getCssValue("left")); - } - for (int i = 0; i < slots5x5.size(); i++) { - assertEquals("Different top coordinate for element " + i, slots5x5 - .get(i).getCssValue("top"), - slots4x4.get(i).getCssValue("top")); - } - } - +public class GridLayoutHideMiddleCellsTest extends GridLayoutExpandRatioTest { } diff --git a/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentFromGridLayoutToInnerLayout.html b/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentFromGridLayoutToInnerLayout.html deleted file mode 100644 index ed6d39f63d..0000000000 --- a/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentFromGridLayoutToInnerLayout.html +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.gridlayout.MoveComponentsFromGridLayoutToInnerLayout?restartApplication</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsgridlayoutMoveComponentsFromGridLayoutToInnerLayout::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsgridlayoutMoveComponentsFromGridLayoutToInnerLayout::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>buttons-with-captions</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentsFromGridLayoutToInnerLayout.java b/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentsFromGridLayoutToInnerLayout.java index 0106f2e218..4f5b29c91f 100644 --- a/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentsFromGridLayoutToInnerLayout.java +++ b/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentsFromGridLayoutToInnerLayout.java @@ -1,20 +1,19 @@ package com.vaadin.tests.components.gridlayout; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button; +import com.vaadin.ui.*; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.ComponentContainer; -import com.vaadin.ui.GridLayout; -import com.vaadin.ui.VerticalLayout; -public class MoveComponentsFromGridLayoutToInnerLayout extends TestBase { +public class MoveComponentsFromGridLayoutToInnerLayout extends AbstractTestUI { protected Button testButton; private GridLayout gl; protected ComponentContainer vl; @Override - protected void setup() { + protected void setup(VaadinRequest request) { gl = new GridLayout(); gl.setWidth("200px"); gl.setHeight("200px"); @@ -31,6 +30,7 @@ public class MoveComponentsFromGridLayoutToInnerLayout extends TestBase { gl.addComponent(testButton); vl = new VerticalLayout(); + vl.addComponent(new Label("I'm inside the inner layout")); gl.addComponent(vl); addComponent(gl); @@ -48,7 +48,7 @@ public class MoveComponentsFromGridLayoutToInnerLayout extends TestBase { } @Override - protected String getDescription() { + protected String getTestDescription() { return "Click the first button to move it from an outer layout to an inner. Then click the second button to repaint the inner layout."; } diff --git a/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentsFromGridLayoutToInnerLayoutTest.java b/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentsFromGridLayoutToInnerLayoutTest.java new file mode 100644 index 0000000000..eb4888ea1a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/gridlayout/MoveComponentsFromGridLayoutToInnerLayoutTest.java @@ -0,0 +1,22 @@ +package com.vaadin.tests.components.gridlayout; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.AbstractTB3Test; +import com.vaadin.tests.tb3.MultiBrowserTest; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class MoveComponentsFromGridLayoutToInnerLayoutTest extends MultiBrowserTest { + + @Test + public void buttonIsMovedInsideInnerLayout() throws IOException { + openTestURL(); + + $(ButtonElement.class).first().click(); + + compareScreen("buttonClicked"); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/menubar/SpaceMenuBarNavigationTest.java b/uitest/src/com/vaadin/tests/components/menubar/SpaceMenuBarNavigationTest.java index 3e0053d0d1..a32a611d9a 100644 --- a/uitest/src/com/vaadin/tests/components/menubar/SpaceMenuBarNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/menubar/SpaceMenuBarNavigationTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -23,10 +23,11 @@ import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.MenuBarElement; import com.vaadin.tests.tb3.MultiBrowserTest; /** - * + * * @since 7.2 * @author Vaadin Ltd */ @@ -36,19 +37,21 @@ public class SpaceMenuBarNavigationTest extends MultiBrowserTest { public void testEnableParentLayout() { openTestURL(); - WebElement menu = driver.findElement(By.className("menu-bar")); + MenuBarElement menu = $(MenuBarElement.class).get(0); + menu.focus(); menu.sendKeys(Keys.ARROW_RIGHT); - menu.sendKeys(Keys.SPACE); + menu.sendKeys(Keys.ENTER); List<WebElement> captions = driver.findElements(By .className("v-menubar-menuitem-caption")); boolean found = false; + for (WebElement caption : captions) { if ("subitem".equals(caption.getText())) { found = true; } } - Assert.assertTrue("Sub menu is not opened on SPACE key", found); + Assert.assertTrue("Sub menu is not opened on ENTER key", found); menu.sendKeys(Keys.SPACE); diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeak.java b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeak.java index 7d347d6180..c715aa383a 100644 --- a/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeak.java +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeak.java @@ -1,13 +1,13 @@ package com.vaadin.tests.components.orderedlayout; import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.ui.Button; import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.CssLayout; -import com.vaadin.ui.Label; +import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Panel; import com.vaadin.ui.TextField; -import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; /** @@ -17,23 +17,32 @@ import com.vaadin.ui.VerticalLayout; * @since 7.1.13 * @author Vaadin Ltd */ -public class CaptionLeak extends UI { - - public static final String USAGE = "Open this UI with ?debug and count" - + " measured non-connector elements after setting leaky and non leaky" - + " content."; +public class CaptionLeak extends AbstractTestUI { + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ @Override - public void init(VaadinRequest req) { - final VerticalLayout root = new VerticalLayout(); - setContent(root); - Label usage = new Label(USAGE); + protected void setup(VaadinRequest request) { + VerticalLayout root = new VerticalLayout(); + root.setSizeFull(); + root.setMargin(false); + root.setSpacing(false); + + HorizontalLayout layout = new HorizontalLayout(); Panel parent = new Panel(); Button setLeakyContent = makeButton("Set leaky content", parent, VerticalLayout.class); Button setNonLeakyContent = makeButton("Set non leaky content", parent, CssLayout.class); - root.addComponents(usage, setLeakyContent, setNonLeakyContent, parent); + layout.addComponent(setLeakyContent); + layout.addComponent(setNonLeakyContent); + root.addComponent(layout); + root.addComponent(parent); + setContent(root); } private Button makeButton(String caption, final Panel parent, @@ -59,4 +68,24 @@ public class CaptionLeak extends UI { return btn; } + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Open this UI with ?debug and count measured non-connector elements after setting leaky and non leaky content."; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return null; + } + } diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java index 0fbd0e5f69..a95ceca22b 100644 --- a/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java @@ -18,6 +18,7 @@ package com.vaadin.tests.components.orderedlayout; import org.junit.Test; import org.openqa.selenium.By; +import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.tests.tb3.MultiBrowserTest; public class CaptionLeakTest extends MultiBrowserTest { @@ -26,43 +27,53 @@ public class CaptionLeakTest extends MultiBrowserTest { public void testCaptionLeak() throws Exception { setDebug(true); openTestURL(); - openDebugLogTab(); + + openLog(); // this should be present // 3 general non-connector elements, none accumulated on click - getDriver() - .findElement( - By.xpath("//span[text() = 'Measured 3 non connector elements']")); + checkConnectorCount(); - getDriver().findElement(By.xpath("//button[@title = 'Clear log']")) - .click(); - getDriver().findElement(By.id("Set leaky content")).click(); + clearLog(); - getDriver() - .findElement( - By.xpath("//span[text() = 'Measured 3 non connector elements']")); + $(ButtonElement.class).caption("Set leaky content").first().click(); + + checkConnectorCount(); // nothing accumulates over clicks - getDriver().findElement(By.xpath("//button[@title = 'Clear log']")) - .click(); - getDriver().findElement(By.id("Set leaky content")).click(); - getDriver() - .findElement( - By.xpath("//span[text() = 'Measured 3 non connector elements']")); + clearLog(); + + $(ButtonElement.class).caption("Set leaky content").first().click(); + checkConnectorCount(); } @Test public void testNoCaptionLeak() throws Exception { setDebug(true); openTestURL(); + + openLog(); + + clearLog(); + $(ButtonElement.class).caption("Set non leaky content").first().click(); + // this should be present + // 3 general non-connector elements, none accumulated on click + checkConnectorCount(); + } + + private void openLog() { openDebugLogTab(); + if (BrowserUtil.isIE8(getDesiredCapabilities())) { + openDebugLogTab(); + } + } + private void clearLog() { getDriver().findElement(By.xpath("//button[@title = 'Clear log']")) .click(); - getDriver().findElement(By.id("Set non leaky content")).click(); + } - // this should be present - // 3 general non-connector elements, none accumulated on click + private void checkConnectorCount() { getDriver() .findElement( By.xpath("//span[text() = 'Measured 3 non connector elements']")); diff --git a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaRelativeHeightResize.java b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaRelativeHeightResize.java new file mode 100644 index 0000000000..870c6cb8cb --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaRelativeHeightResize.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.richtextarea; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.RichTextArea; +import com.vaadin.ui.VerticalLayout; + +public class RichTextAreaRelativeHeightResize extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final VerticalLayout layout = new VerticalLayout(); + layout.setSizeFull(); + layout.setHeight("300px"); + + RichTextArea richTextArea = new RichTextArea(); + richTextArea.setSizeFull(); + layout.addComponent(richTextArea); + + addComponent(layout); + addComponent(new Button("Increase height", new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + layout.setHeight("400px"); + } + })); + + } + + @Override + protected String getTestDescription() { + return "Tests that a RichTextArea with dynamic height " + + "updates its editor elements height on resize"; + } + + @Override + protected Integer getTicketNumber() { + return 11320; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaRelativeHeightResizeTest.java b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaRelativeHeightResizeTest.java new file mode 100644 index 0000000000..5c31ce4dc7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaRelativeHeightResizeTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.richtextarea; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class RichTextAreaRelativeHeightResizeTest extends MultiBrowserTest { + + @Test + public void testCenteredClosingAndPostLayout() { + openTestURL(); + + int originalHeight = driver + .findElement(By.cssSelector(".v-richtextarea")).getSize() + .getHeight(); + int originalEditorHeight = driver + .findElement(By.cssSelector(".v-richtextarea iframe")) + .getSize().getHeight(); + + // Increase the component height + driver.findElement(By.cssSelector(".v-button")).click(); + + int newHeight = driver.findElement(By.cssSelector(".v-richtextarea")) + .getSize().getHeight(); + int newEditorHeight = driver + .findElement(By.cssSelector(".v-richtextarea iframe")) + .getSize().getHeight(); + + // Check that the component height changed and that the editor height + // changed equally as much + Assert.assertTrue("RichTextArea height didn't change", + newHeight != originalHeight); + Assert.assertEquals( + "Editor height change didn't match the Component height change", + newHeight - originalHeight, newEditorHeight + - originalEditorHeight); + } +} diff --git a/uitest/src/com/vaadin/tests/components/slider/SliderTooltip.html b/uitest/src/com/vaadin/tests/components/slider/SliderTooltip.html deleted file mode 100644 index 6014f557e7..0000000000 --- a/uitest/src/com/vaadin/tests/components/slider/SliderTooltip.html +++ /dev/null @@ -1,72 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8888/" /> -<title>SliderTooltip</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">SliderTooltip</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.slider.SliderTest?debug&restartApplication</td> - <td></td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::PID_Smenu#item0</td> - <td>24,2</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::Root/VOverlay[0]/VMenuBar[0]#item1</td> - <td>35,12</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::Root/VOverlay[1]/VMenuBar[0]#item1</td> - <td>74,3</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::Root/VOverlay[2]/VMenuBar[0]#item2</td> - <td>30,6</td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::PID_StestComponent/domChild[2]/domChild[0]</td> - <td>0,0</td> -</tr> -<tr> - <td>waitForElementPresent</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td>This is a semi-long text that might wrap.</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> - <td>40,16</td> -</tr> -<tr> - <td>pause</td> - <td></td> - <td>1000</td> -</tr> -<tr> - <td>assertElementPositionLeft</td> - <td>vaadin=runcomvaadintestscomponentssliderSliderTest::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td> - <td>-5000</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/components/splitpanel/SplitPanelMoveComponent.java b/uitest/src/com/vaadin/tests/components/splitpanel/SplitPanelMoveComponent.java new file mode 100644 index 0000000000..b788b568c2 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/splitpanel/SplitPanelMoveComponent.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2013 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.tests.components.splitpanel; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.HorizontalSplitPanel; + +public class SplitPanelMoveComponent extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final HorizontalSplitPanel split = new HorizontalSplitPanel(); + split.setHeight("200px"); + final Button targetComponent = new Button( + "Button in splitpanel. Click to move to the other side"); + split.setFirstComponent(targetComponent); + + targetComponent.addClickListener(new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + if (split.getFirstComponent() != null) { + split.setFirstComponent(null); + split.setSecondComponent(targetComponent); + } else { + split.setSecondComponent(null); + split.setFirstComponent(targetComponent); + + } + } + + }); + + addComponent(split); + } + + @Override + protected String getTestDescription() { + return "Fail to swap components in HorizontalSplitPanel"; + } + + @Override + protected Integer getTicketNumber() { + return 11920; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/splitpanel/SplitPanelMoveComponentTest.java b/uitest/src/com/vaadin/tests/components/splitpanel/SplitPanelMoveComponentTest.java new file mode 100644 index 0000000000..1bf5212185 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/splitpanel/SplitPanelMoveComponentTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2013 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.tests.components.splitpanel; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class SplitPanelMoveComponentTest extends MultiBrowserTest { + + private static final String BUTTON_TEXT = "Button in splitpanel. Click to move to the other side"; + + @Test + public void moveComponent() { + openTestURL(); + Assert.assertEquals(BUTTON_TEXT, getFirstChild().getText()); + getFirstChild().click(); + Assert.assertEquals(BUTTON_TEXT, getSecondChild().getText()); + getSecondChild().click(); + Assert.assertEquals(BUTTON_TEXT, getFirstChild().getText()); + } + + private WebElement getFirstChild() { + WebElement container = getDriver() + .findElement( + By.xpath("//div[contains(@class,'v-splitpanel-first-container')]")); + return container.findElement(By + .xpath("//div[contains(@class, 'v-button')]")); + } + + private WebElement getSecondChild() { + WebElement container = getDriver() + .findElement( + By.xpath("//div[contains(@class,'v-splitpanel-second-container')]")); + return container.findElement(By + .xpath("//div[contains(@class, 'v-button')]")); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/table/SelectAllConstantViewport.java b/uitest/src/com/vaadin/tests/components/table/SelectAllConstantViewport.java new file mode 100644 index 0000000000..5a406eac48 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/SelectAllConstantViewport.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.CssLayout; +import com.vaadin.ui.Table; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class SelectAllConstantViewport extends AbstractTestUIWithLog { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + + final Table table = new Table(); + table.addContainerProperty("", Integer.class, null); + table.setSizeFull(); + table.setMultiSelect(true); + table.setNullSelectionAllowed(true); + table.setSelectable(true); + + CheckBox selectAllCheckbox = new CheckBox("Select All"); + selectAllCheckbox.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange( + com.vaadin.data.Property.ValueChangeEvent event) { + Object checked = event.getProperty().getValue(); + if (checked instanceof Boolean) { + if (((Boolean) checked).booleanValue()) { + table.setValue(table.getItemIds()); + } else { + table.setValue(null); + } + } + } + }); + + for (int i = 0; i < 200; i++) { + table.addItem(new Object[] { new Integer(i) }, new Integer(i)); + } + + table.setCurrentPageFirstItemIndex(185); + + final CssLayout layout = new CssLayout(); + layout.addComponent(selectAllCheckbox); + layout.addComponent(table); + layout.setSizeFull(); + addComponent(layout); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + + return "The scroll position of a table with many items should remain constant if all items are selected."; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 13341; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/table/SelectAllConstantViewportTest.java b/uitest/src/com/vaadin/tests/components/table/SelectAllConstantViewportTest.java new file mode 100644 index 0000000000..0e7a7c08a4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/SelectAllConstantViewportTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.CheckBoxElement; +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class SelectAllConstantViewportTest extends MultiBrowserTest { + + @Test + public void testViewportUnchanged() throws IOException { + openTestURL(); + + CheckBoxElement checkbox = $(CheckBoxElement.class).first(); + + WebElement row = $(TableElement.class).first().getCell(190, 0); + final WebElement scrollPositionDisplay = getDriver().findElement( + By.className("v-table-scrollposition")); + waitUntilNot(new ExpectedCondition<Boolean>() { + + @Override + public Boolean apply(WebDriver input) { + return scrollPositionDisplay.isDisplayed(); + } + }, 10); + + int rowLocation = row.getLocation().getY(); + + // use click x,y with non-zero offset to actually toggle the checkbox. (#13763) + checkbox.click(5, 5); + int newRowLocation = row.getLocation().getY(); + + assertThat(newRowLocation, is(rowLocation)); + + } +} diff --git a/uitest/src/com/vaadin/tests/components/ui/TooltipConfigurationTest.java b/uitest/src/com/vaadin/tests/components/ui/TooltipConfigurationTest.java deleted file mode 100644 index f3e7554579..0000000000 --- a/uitest/src/com/vaadin/tests/components/ui/TooltipConfigurationTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2000-2013 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.tests.components.ui; - -import java.util.NoSuchElementException; - -import org.junit.Assert; -import org.junit.Test; -import org.openqa.selenium.Keys; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.interactions.Actions; - -import com.vaadin.testbench.By; -import com.vaadin.tests.tb3.MultiBrowserTest; - -public class TooltipConfigurationTest extends MultiBrowserTest { - - private org.openqa.selenium.By tooltipBy = By - .vaadin("Root/VTooltip[0]/FlowPanel[0]/domChild[1]"); - - @Test - public void testTooltipConfiguration() throws Exception { - openTestURL(); - - WebElement uiRoot = getDriver().findElement(By.vaadin("Root")); - WebElement closeTimeout = vaadinElementById("Close timeout"); - WebElement shortTooltip = vaadinElementById("shortTooltip"); - WebElement longTooltip = vaadinElementById("longTooltip"); - WebElement maxWidth = vaadinElementById("Max width"); - - selectAndType(closeTimeout, "0"); - testBenchElement(shortTooltip).showTooltip(); - waitForElementToBePresent(tooltipBy); - Assert.assertEquals("This is a short tooltip", getTooltip().getText()); - - new Actions(getDriver()).moveToElement(uiRoot, 0, 0).click().perform(); - // uiRoot.click(); - checkTooltipNotPresent(); - - selectAndType(closeTimeout, "3000"); - moveMouseToTopLeft(uiRoot); - testBenchElement(shortTooltip).showTooltip(); - waitForElementToBePresent(tooltipBy); - WebElement tooltip2 = getTooltip(); - Assert.assertEquals("This is a short tooltip", tooltip2.getText()); - - uiRoot.click(); - // assert that tooltip is present - getTooltip(); - selectAndType(closeTimeout, "0"); - testBenchElement(longTooltip).showTooltip(); - waitForElementToBePresent(tooltipBy); - Assert.assertEquals(500, getTooltip().getSize().getWidth()); - - uiRoot.click(); - selectAndType(maxWidth, "100"); - moveMouseToTopLeft(uiRoot); - testBenchElement(longTooltip).showTooltip(); - Assert.assertEquals(100, getTooltip().getSize().getWidth()); - } - - private WebElement getTooltip() { - return getDriver().findElement(tooltipBy); - } - - private void checkTooltipNotPresent() { - try { - WebElement tooltip = getTooltip(); - if (!"".equals(tooltip.getText()) - || tooltip.getLocation().getX() > -999) { - Assert.fail("Found tooltip that shouldn't be visible: " - + tooltip.getText() + " at " + tooltip.getLocation()); - } - } catch (NoSuchElementException e) { - Assert.fail("Tooltip element was removed completely, causing extra events to accessibility tools"); - } - } - - private void selectAndType(WebElement element, String value) { - // select and replace text - element.clear(); - // if null representation not set as "", need to move cursor to end and - // remove text "null" - // element.sendKeys("" + Keys.BACK_SPACE + Keys.BACK_SPACE - // + Keys.BACK_SPACE + Keys.BACK_SPACE); - element.sendKeys(value + Keys.ENTER); - } - - private void moveMouseToTopLeft(WebElement element) { - new Actions(getDriver()).moveToElement(element, 0, 0).perform(); - } - -}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/upload/TestFileUploadTest.java b/uitest/src/com/vaadin/tests/components/upload/TestFileUploadTest.java new file mode 100644 index 0000000000..1887427a72 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/upload/TestFileUploadTest.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.upload; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.internal.WrapsElement; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.LocalFileDetector; +import org.openqa.selenium.remote.RemoteWebElement; + +import com.vaadin.testbench.elements.UploadElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TestFileUploadTest extends MultiBrowserTest { + + @Override + public List<DesiredCapabilities> getBrowsersToTest() { + // PhantomJS fails to upload files for unknown reasons + List<DesiredCapabilities> b = super.getBrowsersToTest(); + b.remove(Browser.PHANTOMJS.getDesiredCapabilities()); + return b; + } + + @Test + public void testUploadAnyFile() throws Exception { + openTestURL(); + + File tempFile = createTempFile(); + fillPathToUploadInput(tempFile.getPath()); + + getSubmitButton().click(); + + String expected = String.format( + "1. Upload finished. Name: %s, Size: %s, md5: %s", + tempFile.getName(), getTempFileContents().length(), + md5(getTempFileContents())); + + String actual = getLogRow(0); + Assert.assertEquals("Upload log row does not match expected", expected, + actual); + } + + private String md5(String string) throws NoSuchAlgorithmException { + byte[] digest = MessageDigest.getInstance("MD5").digest( + string.getBytes()); + BigInteger bigInt = new BigInteger(1, digest); + String hashtext = bigInt.toString(16); + return hashtext; + } + + /** + * @return The generated temp file handle + * @throws IOException + */ + private File createTempFile() throws IOException { + File tempFile = File.createTempFile("TestFileUpload", ".txt"); + BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)); + writer.write(getTempFileContents()); + writer.close(); + tempFile.deleteOnExit(); + return tempFile; + } + + private String getTempFileContents() { + return "This is a test file!\nRow 2\nRow3"; + } + + private void fillPathToUploadInput(String tempFileName) throws Exception { + // create a valid path in upload input element. Instead of selecting a + // file by some file browsing dialog, we use the local path directly. + WebElement input = getInput(); + setLocalFileDetector(input); + input.sendKeys(tempFileName); + } + + private WebElement getSubmitButton() { + UploadElement upload = $(UploadElement.class).first(); + WebElement submitButton = upload.findElement(By.className("v-button")); + return submitButton; + } + + private WebElement getInput() { + return getDriver().findElement(By.className("gwt-FileUpload")); + } + + private void setLocalFileDetector(WebElement element) throws Exception { + if (getClass().isAnnotationPresent(RunLocally.class)) { + return; + } + + if (element instanceof WrapsElement) { + element = ((WrapsElement) element).getWrappedElement(); + } + if (element instanceof RemoteWebElement) { + ((RemoteWebElement) element) + .setFileDetector(new LocalFileDetector()); + } else { + throw new IllegalArgumentException( + "Expected argument of type RemoteWebElement, received " + + element.getClass().getName()); + } + } +} diff --git a/uitest/src/com/vaadin/tests/fieldgroup/IntegerRangeValidator.html b/uitest/src/com/vaadin/tests/fieldgroup/IntegerRangeValidator.html deleted file mode 100644 index 48d48ede80..0000000000 --- a/uitest/src/com/vaadin/tests/fieldgroup/IntegerRangeValidator.html +++ /dev/null @@ -1,95 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>IntegerRangeValidator</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">IntegerRangeValidator</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.fieldgroup.BasicPersonForm?restartApplication</td> - <td></td> -</tr> -<!--64123 -> age--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> - <td>64,20</td> -</tr> -<tr> - <td>enterCharacter</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> - <td>64123</td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> - <td></td> -</tr> -<tr> - <td>waitForElementPresent</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::Root/VTooltip[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::Root/VTooltip[0]/FlowPanel[0]/VErrorMessage[0]/HTML[0]</td> - <td>Must be between 0 and 150, 64123 is not</td> -</tr> -<tr> - <td>assertCSSClass</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[5]/domChild[0]/domChild[1]</td> - <td>v-errorindicator</td> -</tr> -<!--Hide tooltip--> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/VVerticalLayout[0]</td> - <td></td> -</tr> -<!--10 -> age--> -<tr> - <td>enterCharacter</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> - <td>10</td> -</tr> -<tr> - <td>assertElementNotPresent</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[5]/domChild[0]/domChild[1]</td> - <td>v-errorindicator</td> -</tr> -<!---1--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> - <td>69,11</td> -</tr> -<tr> - <td>enterCharacter</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> - <td>-1</td> -</tr> -<tr> - <td>assertCSSClass</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[5]/domChild[0]/domChild[1]</td> - <td>v-errorindicator</td> -</tr> -<tr> - <td>showTooltip</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VTextField[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::Root/VTooltip[0]/FlowPanel[0]/VErrorMessage[0]/HTML[0]</td> - <td>Must be between 0 and 150, -1 is not</td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/layouts/GridLayoutMoveComponent.html b/uitest/src/com/vaadin/tests/layouts/GridLayoutMoveComponent.html deleted file mode 100644 index 77a17263f8..0000000000 --- a/uitest/src/com/vaadin/tests/layouts/GridLayoutMoveComponent.html +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.layouts.GridLayoutMoveComponent?restartApplication</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>all-left</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsGridLayoutMoveComponent::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>label-right</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsGridLayoutMoveComponent::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>label-button-right</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsGridLayoutMoveComponent::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>label-button-textfield-right</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/layouts/GridLayoutWidthChange.html b/uitest/src/com/vaadin/tests/layouts/GridLayoutWidthChange.html deleted file mode 100644 index f01a1a7026..0000000000 --- a/uitest/src/com/vaadin/tests/layouts/GridLayoutWidthChange.html +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>GridLayoutWidthChange</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">GridLayoutWidthChange</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.layouts.GridLayoutWidthChange</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsGridLayoutWidthChange::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td></td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/layouts/GridLayoutMoveComponent.java b/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutMoveComponent.java index efd1277653..cd86fbcf3c 100644 --- a/uitest/src/com/vaadin/tests/layouts/GridLayoutMoveComponent.java +++ b/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutMoveComponent.java @@ -1,5 +1,7 @@ -package com.vaadin.tests.layouts; +package com.vaadin.tests.layouts.gridlayout; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; @@ -7,10 +9,10 @@ import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.TextField; -public class GridLayoutMoveComponent extends TestBase { +public class GridLayoutMoveComponent extends AbstractTestUI { @Override - protected void setup() { + protected void setup(VaadinRequest request) { final GridLayout grid = new GridLayout(2, 3); grid.setCaption("Fixed size grid"); grid.setWidth("300px"); @@ -51,13 +53,14 @@ public class GridLayoutMoveComponent extends TestBase { @Override public void buttonClick(ClickEvent event) { grid.removeComponent(tf); + grid.addComponent(new Label("I'm on left"), 0, 2); grid.addComponent(tf, 1, 2); } })); } @Override - protected String getDescription() { + protected String getTestDescription() { return "Click the buttons below the GridLayout to move the components to the right. Should definitely work no matter what."; } diff --git a/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutMoveComponentTest.java b/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutMoveComponentTest.java new file mode 100644 index 0000000000..0fab64989a --- /dev/null +++ b/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutMoveComponentTest.java @@ -0,0 +1,31 @@ +package com.vaadin.tests.layouts.gridlayout; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.MultiBrowserTest; +import org.junit.Test; + +import java.io.IOException; + +public class GridLayoutMoveComponentTest extends MultiBrowserTest { + + @Test + public void componentsShouldMoveRight() throws IOException { + openTestURL(); + + compareScreen("all-left"); + + clickButtonWithCaption("Shift label right"); + compareScreen("label-right"); + + clickButtonWithCaption("Shift button right"); + compareScreen("label-button-right"); + + clickButtonWithCaption("Shift text field right"); + compareScreen("label-button-textfield-right"); + } + + private void clickButtonWithCaption(String caption) { + $(ButtonElement.class).caption(caption).first().click(); + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/layouts/GridLayoutWidthChange.java b/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutWidthChange.java index c0e6b27c7d..96091bdab5 100644 --- a/uitest/src/com/vaadin/tests/layouts/GridLayoutWidthChange.java +++ b/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutWidthChange.java @@ -1,5 +1,7 @@ -package com.vaadin.tests.layouts; +package com.vaadin.tests.layouts.gridlayout; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; @@ -9,7 +11,7 @@ import com.vaadin.ui.NativeButton; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -public class GridLayoutWidthChange extends TestBase { +public class GridLayoutWidthChange extends AbstractTestUI { private GridLayout generateLayout() { VerticalLayout fields1 = new VerticalLayout(); @@ -34,7 +36,7 @@ public class GridLayoutWidthChange extends TestBase { } @Override - protected void setup() { + protected void setup(VaadinRequest request) { final GridLayout layout1 = generateLayout(); final CustomComponent cc = new CustomComponent(layout1); cc.setWidth("500px"); @@ -45,7 +47,7 @@ public class GridLayoutWidthChange extends TestBase { @Override public void buttonClick(ClickEvent event) { - cc.setWidth((cc.getWidth() - 10) + "px"); + cc.setWidth((cc.getWidth() - 100) + "px"); } }); @@ -53,7 +55,7 @@ public class GridLayoutWidthChange extends TestBase { } @Override - protected String getDescription() { + protected String getTestDescription() { return "A 100% wide GridLayout is wrapped inside a CustomComponent. When the width of the CustomComponent is reduced, the size of the GridLayout should be reduced accordingly. The Buttons should stay in place vertically and just move closer to each other horizontally."; } diff --git a/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutWidthChangeTest.java b/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutWidthChangeTest.java new file mode 100644 index 0000000000..52ea5f4f8e --- /dev/null +++ b/uitest/src/com/vaadin/tests/layouts/gridlayout/GridLayoutWidthChangeTest.java @@ -0,0 +1,24 @@ +package com.vaadin.tests.layouts.gridlayout; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.AbstractTB3Test; +import com.vaadin.tests.tb3.MultiBrowserTest; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class GridLayoutWidthChangeTest extends MultiBrowserTest { + + @Test + public void layoutIsReduced() throws IOException { + openTestURL(); + + compareScreen("initial"); + + $(ButtonElement.class).caption("Reduce GridLayout parent width").first().click(); + + compareScreen("buttonMoved"); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java index 8783a4dc42..406f1fe27c 100644 --- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -791,7 +791,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { */ public static DesiredCapabilities phantomJS(int version) { DesiredCapabilities c = DesiredCapabilities.phantomjs(); - c.setPlatform(Platform.XP); + c.setPlatform(Platform.LINUX); c.setVersion("" + version); return c; } diff --git a/uitest/src/com/vaadin/tests/tb3/TooltipTest.java b/uitest/src/com/vaadin/tests/tb3/TooltipTest.java index 86ac8c1f12..86ea44287a 100644 --- a/uitest/src/com/vaadin/tests/tb3/TooltipTest.java +++ b/uitest/src/com/vaadin/tests/tb3/TooltipTest.java @@ -16,11 +16,13 @@ package com.vaadin.tests.tb3; +import java.util.List; import java.util.NoSuchElementException; import org.junit.Assert; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.By; @@ -58,10 +60,20 @@ public abstract class TooltipTest extends MultiBrowserTest { } protected void checkTooltip(String value) throws Exception { + WebElement body = findElement(By.cssSelector("body")); WebElement tooltip = getTooltip(); Assert.assertEquals(value, tooltip.getText()); - Assert.assertTrue("Tooltip should be in viewport", tooltip + Assert.assertTrue("Tooltip overflowed to the left", tooltip .getLocation().getX() >= 0); + Assert.assertTrue("Tooltip overflowed up", + tooltip.getLocation().getY() >= 0); + Assert.assertTrue("Tooltip overflowed to the right", tooltip + .getLocation().getX() + tooltip.getSize().getWidth() < body + .getSize().getWidth()); + Assert.assertTrue("Tooltip overflowed down", tooltip.getLocation() + .getY() + tooltip.getSize().getHeight() < body.getSize() + .getHeight()); + } protected void moveToRoot() { @@ -88,7 +100,18 @@ public abstract class TooltipTest extends MultiBrowserTest { } protected void moveMouseToTopLeft(WebElement element) { - new Actions(getDriver()).moveToElement(element, 0, 0).perform(); + moveMouseTo(element, 0, 0); + } + + protected void moveMouseTo(WebElement element, int offsetX, int offsetY) { + new Actions(getDriver()).moveToElement(element, offsetX, offsetY) + .perform(); } + @Override + public List<DesiredCapabilities> getBrowsersToTest() { + // TODO Once we figure out how to get mouse hovering work with the IE + // webdriver, exclude them from these tests (#13854) + return getBrowsersExcludingIE(); + } } diff --git a/uitest/src/com/vaadin/tests/tooltip/AdjacentElementsWithTooltips.java b/uitest/src/com/vaadin/tests/tooltip/AdjacentElementsWithTooltips.java new file mode 100644 index 0000000000..60167e43b4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/AdjacentElementsWithTooltips.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Component; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.TooltipConfiguration; + +/** + * When moving between adjacent elements, the tooltip replace should obey + * quickOpenDelay + * + * @author Vaadin Ltd + */ +public class AdjacentElementsWithTooltips extends AbstractTestUI { + + private int buttonCount = 0; + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + TooltipConfiguration ttc = super.getTooltipConfiguration(); + ttc.setMaxWidth(350); + ttc.setOpenDelay(200); + ttc.setCloseTimeout(200); + ttc.setQuickOpenDelay(1000); + ttc.setQuickOpenTimeout(1000); + HorizontalLayout layout = new HorizontalLayout(); + layout.addComponent(makeButton("first")); + layout.addComponent(makeButton("second")); + addComponent(layout); + + } + + private Component makeButton(String tooltip) { + Button button = new Button("Button " + buttonCount++); + button.setDescription(tooltip); + return button; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Moving between adjacent elements with tooltips should open quickOpenDelay"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 13998; + } + +} diff --git a/uitest/src/com/vaadin/tests/tooltip/AdjacentElementsWithTooltipsTest.java b/uitest/src/com/vaadin/tests/tooltip/AdjacentElementsWithTooltipsTest.java new file mode 100644 index 0000000000..b9fc788008 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/AdjacentElementsWithTooltipsTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.interactions.HasInputDevices; +import org.openqa.selenium.interactions.Mouse; +import org.openqa.selenium.interactions.internal.Coordinates; +import org.openqa.selenium.internal.Locatable; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Test to see if tooltips obey quickOpenDelay when moving between directly + * adjacent elements. + * + * @author Vaadin Ltd + */ +public class AdjacentElementsWithTooltipsTest extends MultiBrowserTest { + + @Override + public List<DesiredCapabilities> getBrowsersToTest() { + return getBrowsersExcludingIE(); + } + + @Test + public void tooltipsHaveQuickOpenDelay() throws InterruptedException { + openTestURL(); + Coordinates button0Coordinates = getButtonCoordinates("Button 0"); + Coordinates button1Coordinates = getButtonCoordinates("Button 1"); + + Mouse mouse = getMouse(); + mouse.mouseMove(button0Coordinates, 10, 10); + sleep(1000); + assertThat(getTooltipElement().getLocation().x, is(greaterThan(0))); + + mouse.mouseMove(button1Coordinates, 10, 10); + assertThat(getTooltipElement().getLocation().x, is(lessThan(-1000))); + + sleep(1000); + assertThat(getTooltipElement().getLocation().x, + is(greaterThan(button1Coordinates.onPage().x))); + } + + private Coordinates getButtonCoordinates(String caption) { + return getCoordinates(getButton(caption)); + } + + private ButtonElement getButton(String caption) { + return $(ButtonElement.class) + .caption(caption).first(); + } +} diff --git a/uitest/src/com/vaadin/tests/components/button/ButtonTooltips.java b/uitest/src/com/vaadin/tests/tooltip/ButtonTooltips.java index fa639918aa..d212a13058 100644 --- a/uitest/src/com/vaadin/tests/components/button/ButtonTooltips.java +++ b/uitest/src/com/vaadin/tests/tooltip/ButtonTooltips.java @@ -1,4 +1,4 @@ -package com.vaadin.tests.components.button; +package com.vaadin.tests.tooltip; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Alignment; @@ -24,14 +24,8 @@ public class ButtonTooltips extends TestBase { button.setDescription("long descidescidescpription"); Button button2 = new Button("Two"); button2.setDescription("Another"); - Button button3 = new Button("One"); - button3.setDescription("long descidescidescpription"); - Button button4 = new Button("Two"); - button4.setDescription("Another"); vl.addComponent(button); vl.addComponent(button2); - vl.addComponent(button3); - vl.addComponent(button4); vl.setComponentAlignment(button, Alignment.TOP_RIGHT); vl.setComponentAlignment(button2, Alignment.TOP_RIGHT); addComponent(vl); diff --git a/uitest/src/com/vaadin/tests/tooltip/ButtonTooltipsTest.java b/uitest/src/com/vaadin/tests/tooltip/ButtonTooltipsTest.java new file mode 100644 index 0000000000..d64dd900a7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/ButtonTooltipsTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.TooltipTest; + +/** + * Tests that tooltip sizes do not change when moving between adjacent elements + * + * @author Vaadin Ltd + */ +public class ButtonTooltipsTest extends TooltipTest { + + @Test + public void tooltipSizeWhenMovingBetweenElements() throws Exception { + openTestURL(); + + WebElement buttonOne = $(ButtonElement.class).caption("One").first(); + WebElement buttonTwo = $(ButtonElement.class).caption("Two").first(); + + checkTooltip(buttonOne, "long descidescidescpription"); + int originalWidth = getTooltipElement().getSize().getWidth(); + int originalHeight = getTooltipElement().getSize().getHeight(); + + clearTooltip(); + checkTooltip(buttonTwo, "Another"); + moveMouseTo(buttonOne, 5, 5); + sleep(100); + assertThat(getTooltipElement().getSize().getWidth(), is(originalWidth)); + assertThat(getTooltipElement().getSize().getHeight(), + is(originalHeight)); + } +} diff --git a/uitest/src/com/vaadin/tests/components/draganddropwrapper/DragAndDropWrapperTooltips.java b/uitest/src/com/vaadin/tests/tooltip/DragAndDropWrapperTooltips.java index f0010acce8..606a773141 100644 --- a/uitest/src/com/vaadin/tests/components/draganddropwrapper/DragAndDropWrapperTooltips.java +++ b/uitest/src/com/vaadin/tests/tooltip/DragAndDropWrapperTooltips.java @@ -1,4 +1,4 @@ -package com.vaadin.tests.components.draganddropwrapper; +package com.vaadin.tests.tooltip; import java.util.Iterator; @@ -10,7 +10,8 @@ import com.vaadin.event.dd.DropTarget; import com.vaadin.event.dd.TargetDetails; import com.vaadin.event.dd.acceptcriteria.AcceptAll; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; -import com.vaadin.tests.components.TestBase; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.tests.util.TestUtils; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; @@ -18,7 +19,7 @@ import com.vaadin.ui.DragAndDropWrapper; import com.vaadin.ui.Label; import com.vaadin.ui.VerticalLayout; -public class DragAndDropWrapperTooltips extends TestBase { +public class DragAndDropWrapperTooltips extends AbstractTestUI { private final String BASE = ".v-widget.greenblock {vertical-align: middle; float:left; width:60px;height:60px;background: green !important; padding:0; margin:2px;-webkit-transition: width 0.3s ease-in-out;color: white;}"; private final String B2 = ".v-widget.b2 {background-color: red !important;}"; @@ -28,9 +29,8 @@ public class DragAndDropWrapperTooltips extends TestBase { private DragAndDropWrapper dragAndDropWrapper; @Override - protected void setup() { - TestUtils.injectCSS(getMainWindow(), BASE + B4 + B2 + B3 - + HIDEDRAGSOURCE); + protected void setup(VaadinRequest request) { + TestUtils.injectCSS(this, BASE + B4 + B2 + B3 + HIDEDRAGSOURCE); VerticalLayout l = new VerticalLayout(); l.setWidth("400px"); @@ -49,7 +49,7 @@ public class DragAndDropWrapperTooltips extends TestBase { wl.addStyleName("b" + i); cssLayout.addComponent(wl); } - + getTooltipConfiguration().setOpenDelay(300); } int count; @@ -123,7 +123,7 @@ public class DragAndDropWrapperTooltips extends TestBase { }; @Override - protected String getDescription() { + protected String getTestDescription() { return "A tooltip should be shown when hovering the DragAndDropWrapper containing all the draggable layouts"; } diff --git a/uitest/src/com/vaadin/tests/tooltip/DragAndDropWrapperTooltipsTest.java b/uitest/src/com/vaadin/tests/tooltip/DragAndDropWrapperTooltipsTest.java new file mode 100644 index 0000000000..d913c8cc12 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/DragAndDropWrapperTooltipsTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import org.junit.Test; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.elements.LabelElement; +import com.vaadin.tests.tb3.TooltipTest; + +/** + * + * + * @author Vaadin Ltd + */ +public class DragAndDropWrapperTooltipsTest extends TooltipTest { + @Test + public void testDragAndDropTooltips() throws Exception { + openTestURL(); + LabelElement element = $(LabelElement.class).get(4); + LabelElement targetElement = $(LabelElement.class).get(1); + checkTooltip(element, + "Tooltip for the wrapper wrapping all the draggable layouts"); + new Actions(getDriver()).clickAndHold(element) + .moveToElement(targetElement).perform(); + sleep(500); + checkTooltipNotPresent(); + new Actions(getDriver()).release().perform(); + checkTooltip(element, "Drag was performed and tooltip was changed"); + } +} diff --git a/uitest/src/com/vaadin/tests/components/LongTooltip.java b/uitest/src/com/vaadin/tests/tooltip/LongTooltip.java index acb498bcee..0eee9d4976 100644 --- a/uitest/src/com/vaadin/tests/components/LongTooltip.java +++ b/uitest/src/com/vaadin/tests/tooltip/LongTooltip.java @@ -1,11 +1,13 @@ -package com.vaadin.tests.components; +package com.vaadin.tests.tooltip; +import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.LoremIpsum; import com.vaadin.ui.Alignment; import com.vaadin.ui.GridLayout; import com.vaadin.ui.TextField; public class LongTooltip extends TestBase { + private int tooltipCount = 0; @Override public void setup() { @@ -33,7 +35,8 @@ public class LongTooltip extends TestBase { private TextField createField() { final TextField field = new TextField(); - field.setDescription(LoremIpsum.get(1000)); + field.setDescription("Tooltip " + Integer.toString(tooltipCount++) + + ": " + LoremIpsum.get(1000)); return field; } diff --git a/uitest/src/com/vaadin/tests/tooltip/LongTooltipTest.java b/uitest/src/com/vaadin/tests/tooltip/LongTooltipTest.java new file mode 100644 index 0000000000..191ce6ffec --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/LongTooltipTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import java.util.List; + +import org.junit.Test; + +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.TooltipTest; +import com.vaadin.tests.util.LoremIpsum; + +/** + * Test to see if long tooltips behave appropriately + * + * @author Vaadin Ltd + */ +public class LongTooltipTest extends TooltipTest { + + @Test + public void tooltipsDontOverflow() throws Exception { + openTestURL(); + List<TextFieldElement> elements = $(TextFieldElement.class).all(); + checkTooltipNotPresent(); + int i = 0; + for (TextFieldElement element : elements) { + checkTooltip(element, "Tooltip " + Integer.toString(i++) + ": " + + LoremIpsum.get(1000)); + clearTooltip(); + checkTooltipNotPresent(); + } + } + +} diff --git a/uitest/src/com/vaadin/tests/tooltip/SliderTooltip.java b/uitest/src/com/vaadin/tests/tooltip/SliderTooltip.java new file mode 100644 index 0000000000..8cf7232fab --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/SliderTooltip.java @@ -0,0 +1,42 @@ +package com.vaadin.tests.tooltip; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Slider; + +public class SliderTooltip extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + Slider slider = new Slider(); + slider.setDescription("Tooltip"); + addComponent(slider); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Testing that sliders have tooltips."; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 14019; + } + +} diff --git a/uitest/src/com/vaadin/tests/tooltip/SliderTooltipTest.java b/uitest/src/com/vaadin/tests/tooltip/SliderTooltipTest.java new file mode 100644 index 0000000000..743b7c2ab5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/SliderTooltipTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.SliderElement; +import com.vaadin.tests.tb3.TooltipTest; + +/** + * Test that sliders can have tooltips + * + * @author Vaadin Ltd + */ +public class SliderTooltipTest extends TooltipTest { + + @Test + public void sliderHasTooltip() throws Exception { + openTestURL(); + WebElement slider = $(SliderElement.class).first(); + checkTooltipNotPresent(); + checkTooltip(slider, "Tooltip"); + clearTooltip(); + checkTooltipNotPresent(); + } +} diff --git a/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.java b/uitest/src/com/vaadin/tests/tooltip/TooltipConfiguration.java index eeea91b638..f67db4219f 100644 --- a/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.java +++ b/uitest/src/com/vaadin/tests/tooltip/TooltipConfiguration.java @@ -1,4 +1,4 @@ -package com.vaadin.tests.components.ui; +package com.vaadin.tests.tooltip; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; diff --git a/uitest/src/com/vaadin/tests/tooltip/TooltipConfigurationTest.java b/uitest/src/com/vaadin/tests/tooltip/TooltipConfigurationTest.java new file mode 100644 index 0000000000..8f84444400 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/TooltipConfigurationTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2013 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.tests.tooltip; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.TooltipTest; + +public class TooltipConfigurationTest extends TooltipTest { + + @Test + public void testTooltipConfiguration() throws Exception { + openTestURL(); + + WebElement uiRoot = getDriver().findElement(By.vaadin("Root")); + WebElement closeTimeout = vaadinElementById("Close timeout"); + WebElement shortTooltip = vaadinElementById("shortTooltip"); + WebElement longTooltip = vaadinElementById("longTooltip"); + WebElement maxWidth = vaadinElementById("Max width"); + + selectAndType(closeTimeout, "0"); + + checkTooltip(shortTooltip, "This is a short tooltip"); + + moveToRoot(); + + checkTooltipNotPresent(); + + selectAndType(closeTimeout, "3000"); + checkTooltip(shortTooltip, "This is a short tooltip"); + + moveToRoot(); + + // The tooltip should still be there despite being "cleared", as the + // timeout hasn't expired yet. + checkTooltip("This is a short tooltip"); + + // assert that tooltip is present + selectAndType(closeTimeout, "0"); + selectAndType(maxWidth, "100"); + + testBenchElement(longTooltip).showTooltip(); + assertThat(getDriver().findElement(By.className("popupContent")) + .getSize().getWidth(), is(100)); + } + + private void selectAndType(WebElement element, String value) { + // select and replace text + element.clear(); + // if null representation not set as "", need to move cursor to end and + // remove text "null" + element.sendKeys(value + Keys.ENTER); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tooltip/ValidatorCaptionTooltip.java b/uitest/src/com/vaadin/tests/tooltip/ValidatorCaptionTooltip.java new file mode 100644 index 0000000000..20dc514c10 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/ValidatorCaptionTooltip.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import com.vaadin.data.validator.IntegerRangeValidator; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.TextField; + +/** + * + * UI test class for Tooltip with integer range validator. + */ +public class ValidatorCaptionTooltip extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + TextField fieldWithError = new TextField(); + int min = 0; + int max = 100; + String errorMessage = "Valid value is between " + min + " and " + max + + ". {0} is not."; + IntegerRangeValidator validator = new IntegerRangeValidator( + errorMessage, min, max); + fieldWithError.setValue("142"); + + fieldWithError.addValidator(validator); + fieldWithError.setConverter(Integer.class); + fieldWithError.setImmediate(true); + + TextField fieldWithoutError = new TextField(); + fieldWithoutError.addValidator(validator); + fieldWithoutError.setConverter(Integer.class); + fieldWithoutError.setValue("42"); + addComponent(fieldWithError); + addComponent(fieldWithoutError); + } + + @Override + protected String getTestDescription() { + return "Valid value is from 0 to 100.When the value is not valid. An error tooltip should appear"; + } + + @Override + protected Integer getTicketNumber() { + return 14046; + } + +} diff --git a/uitest/src/com/vaadin/tests/tooltip/ValidatorCaptionTooltipTest.java b/uitest/src/com/vaadin/tests/tooltip/ValidatorCaptionTooltipTest.java new file mode 100644 index 0000000000..9603b1df36 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/ValidatorCaptionTooltipTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import org.junit.Test; + +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.TooltipTest; + +/** + * Test to see if validators create error tooltips correctly. + * + * @author Vaadin Ltd + */ +public class ValidatorCaptionTooltipTest extends TooltipTest { + @Test + public void validatorWithError() throws Exception { + openTestURL(); + + TextFieldElement field = $(TextFieldElement.class).get(0); + String fieldValue = field.getAttribute("value"); + String expected = "Valid value is between 0 and 100. " + fieldValue + + " is not."; + checkTooltip(field, expected); + } + + @Test + public void validatorWithoutError() throws Exception { + openTestURL(); + TextFieldElement field = $(TextFieldElement.class).get(1); + checkTooltip(field, null); + } +} |