diff options
43 files changed, 1335 insertions, 167 deletions
diff --git a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java index 91950f5d4f..9159fa358b 100644 --- a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java +++ b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java @@ -294,7 +294,8 @@ public class ContainerHierarchicalWrapper implements Container.Hierarchical, return ((Container.Hierarchical) container).hasChildren(itemId); } - return children.get(itemId) != null; + LinkedList<Object> list = children.get(itemId); + return (list != null && !list.isEmpty()); } /* diff --git a/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java b/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java index 8562bc70ec..0d29e9a327 100644 --- a/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java +++ b/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java @@ -6,6 +6,9 @@ */ package com.vaadin.event.dd.acceptcriteria; +import java.util.logging.Level; +import java.util.logging.Logger; + import com.vaadin.event.TransferableImpl; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.terminal.PaintException; @@ -22,27 +25,39 @@ import com.vaadin.ui.Component; @SuppressWarnings("serial") @ClientCriterion(VDragSourceIs.class) public class SourceIs extends ClientSideCriterion { + private static final Logger logger = Logger.getLogger(SourceIs.class + .getName()); - private Component[] component; + private Component[] components; public SourceIs(Component... component) { - this.component = component; + components = component; } @Override public void paintContent(PaintTarget target) throws PaintException { super.paintContent(target); - target.addAttribute("c", component.length); - for (int i = 0; i < component.length; i++) { - target.addAttribute("component" + i, component[i]); + int paintedComponents = 0; + for (int i = 0; i < components.length; i++) { + Component c = components[i]; + if (c.getApplication() != null) { + target.addAttribute("component" + paintedComponents++, c); + } else { + logger.log( + Level.WARNING, + "SourceIs component {0} at index {1} is not attached to the component hierachy and will thus be ignored", + new Object[] { c.getClass().getName(), + Integer.valueOf(i) }); + } } + target.addAttribute("c", paintedComponents); } public boolean accept(DragAndDropEvent dragEvent) { if (dragEvent.getTransferable() instanceof TransferableImpl) { Component sourceComponent = ((TransferableImpl) dragEvent .getTransferable()).getSourceComponent(); - for (Component c : component) { + for (Component c : components) { if (c == sourceComponent) { return true; } diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index be6d578112..739c232a72 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -272,7 +272,7 @@ public class ApplicationConnection { ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::lastProcessingTime, ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::totalProcessingTime ]; - pd = pd.concat(ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::testBenchServerStatus); + pd = pd.concat(ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::serverTimingInfo); return pd; }); @@ -698,7 +698,7 @@ public class ApplicationConnection { * servicing the session so far. These values are always one request behind, * since they cannot be measured before the request is finished. */ - private ValueMap testBenchServerStatus; + private ValueMap serverTimingInfo; static final int MAX_CSS_WAITS = 100; @@ -1037,10 +1037,10 @@ public class ApplicationConnection { handleUIDLDuration.logDuration( " * Handling type mappings from server completed", 10); /* - * Hook for TestBench to get details about server status + * Hook for e.g. TestBench to get details about server peformance */ - if (json.containsKey("tbss")) { - testBenchServerStatus = json.getValueMap("tbss"); + if (json.containsKey("timings")) { + serverTimingInfo = json.getValueMap("timings"); } Command c = new Command() { diff --git a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java index ef1dc481b1..064f175301 100644 --- a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java +++ b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java @@ -28,6 +28,8 @@ public class BrowserInfo { private static final String OS_WINDOWS = "win"; private static final String OS_LINUX = "lin"; private static final String OS_MACOSX = "mac"; + private static final String OS_ANDROID = "android"; + private static final String OS_IOS = "ios"; private static BrowserInfo instance; @@ -167,13 +169,18 @@ public class BrowserInfo { if (osClass != null) { cssClass = cssClass + " " + prefix + osClass; } + } return cssClass; } private String getOperatingSystemClass() { - if (browserDetails.isWindows()) { + if (browserDetails.isAndroid()) { + return OS_ANDROID; + } else if (browserDetails.isIOS()) { + return OS_IOS; + } else if (browserDetails.isWindows()) { return OS_WINDOWS; } else if (browserDetails.isLinux()) { return OS_LINUX; @@ -312,4 +319,59 @@ public class BrowserInfo { && Util.getNativeScrollbarSize() > 0; } + /** + * Checks if the browser is run on iOS + * + * @return true if the browser is run on iOS, false otherwise + */ + public boolean isIOS() { + return browserDetails.isIOS(); + } + + /** + * Checks if the browser is run on Android + * + * @return true if the browser is run on Android, false otherwise + */ + public boolean isAndroid() { + return browserDetails.isAndroid(); + } + + /** + * Checks if the browser is capable of handling scrolling natively or if a + * touch scroll helper is needed for scrolling. + * + * @return true if browser needs a touch scroll helper, false if the browser + * can handle scrolling natively + */ + public boolean requiresTouchScrollDelegate() { + if (!isTouchDevice()) { + return false; + } + + if (isAndroid() && isWebkit() && getWebkitVersion() < 534) { + return true; + } + // if (isIOS() && isWebkit() && getWebkitVersion() < ???) { + // return true; + // } + + return false; + } + + /** + * Tests if this is an Android devices with a broken scrollTop + * implementation + * + * @return true if scrollTop cannot be trusted on this device, false + * otherwise + */ + public boolean isAndroidWithBrokenScrollTop() { + return isAndroid() + && (getOperatingSystemMajorVersion() == 3 || getOperatingSystemMajorVersion() == 4); + } + + private int getOperatingSystemMajorVersion() { + return browserDetails.getOperatingSystemMajorVersion(); + } } diff --git a/src/com/vaadin/terminal/gwt/client/CSSRule.java b/src/com/vaadin/terminal/gwt/client/CSSRule.java index 4d9196c8d6..c36b0611e8 100644 --- a/src/com/vaadin/terminal/gwt/client/CSSRule.java +++ b/src/com/vaadin/terminal/gwt/client/CSSRule.java @@ -33,6 +33,7 @@ public class CSSRule { for(var i = 0; i < sheets.length; i++) { var sheet = sheets[i]; if(sheet.href && sheet.href.indexOf("VAADIN/themes")>-1) { + // $entry not needed as function is not exported this.@com.vaadin.terminal.gwt.client.CSSRule::rules = @com.vaadin.terminal.gwt.client.CSSRule::searchForRule(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Z)(sheet, selector, deep); return; } @@ -58,6 +59,7 @@ public class CSSRule { // IE handles imported sheet differently if(deep && sheet.imports && sheet.imports.length > 0) { for(var i=0; i < sheet.imports.length; i++) { + // $entry not needed as function is not exported var imports = @com.vaadin.terminal.gwt.client.CSSRule::searchForRule(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Z)(sheet.imports[i], selector, deep); allMatches.concat(imports); } @@ -83,6 +85,7 @@ public class CSSRule { } } else if(deep && r.type == 3) { // Search @import stylesheet + // $entry not needed as function is not exported var imports = @com.vaadin.terminal.gwt.client.CSSRule::searchForRule(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Z)(r.styleSheet, selector, deep); allMatches = allMatches.concat(imports); } @@ -102,6 +105,7 @@ public class CSSRule { /*-{ var j = this.@com.vaadin.terminal.gwt.client.CSSRule::rules.length; for(var i=0; i<j; i++) { + // $entry not needed as function is not exported var value = this.@com.vaadin.terminal.gwt.client.CSSRule::rules[i].style[propertyName]; if(value) return value; diff --git a/src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java b/src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java index 3405d838a7..dfbcf9d38b 100644 --- a/src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java +++ b/src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java @@ -62,6 +62,7 @@ final class ComponentDetailMap extends JavaScriptObject { private final native void fillWithValues(Collection<ComponentDetail> list) /*-{ for(var key in this) { + // $entry not needed as function is not exported list.@java.util.Collection::add(Ljava/lang/Object;)(this[key]); } }-*/; diff --git a/src/com/vaadin/terminal/gwt/client/ComputedStyle.java b/src/com/vaadin/terminal/gwt/client/ComputedStyle.java index bedb217c63..29b02b4dde 100644 --- a/src/com/vaadin/terminal/gwt/client/ComputedStyle.java +++ b/src/com/vaadin/terminal/gwt/client/ComputedStyle.java @@ -179,6 +179,7 @@ public class ComputedStyle { if (isNaN(number)) return null; else + // $entry not needed as function is not exported return @java.lang.Integer::valueOf(I)(number); }-*/; diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java index bfe63caefd..c392a0ba9c 100644 --- a/src/com/vaadin/terminal/gwt/client/Util.java +++ b/src/com/vaadin/terminal/gwt/client/Util.java @@ -978,6 +978,19 @@ public class Util { */ final Element target = getElementFromPoint(touch.getClientX(), touch.getClientY()); + + /* + * Fixes infocusable form fields in Safari of iOS 5.x and some Android + * browsers. + */ + Widget targetWidget = findWidget(target, null); + if (targetWidget instanceof com.google.gwt.user.client.ui.Focusable) { + final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) targetWidget; + toBeFocusedWidget.setFocus(true); + } else if (targetWidget instanceof Focusable) { + ((Focusable) targetWidget).focus(); + } + Scheduler.get().scheduleDeferred(new ScheduledCommand() { public void execute() { try { diff --git a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java index 89e106f063..6e0417149c 100644 --- a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java +++ b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java @@ -31,14 +31,19 @@ public class VBrowserDetails implements Serializable { private boolean isOpera = false; private boolean isIE = false; - private boolean isWindows = false; - private boolean isMacOSX = false; - private boolean isLinux = false; + private OperatingSystem os = OperatingSystem.UNKNOWN; + + public enum OperatingSystem { + UNKNOWN, WINDOWS, MACOSX, LINUX, IOS, ANDROID; + } private float browserEngineVersion = -1; private int browserMajorVersion = -1; private int browserMinorVersion = -1; + private int osMajorVersion = -1; + private int osMinorVersion = -1; + /** * Create an instance based on the given user agent. * @@ -122,14 +127,80 @@ public class VBrowserDetails implements Serializable { // Operating system if (userAgent.contains("windows ")) { - isWindows = true; + os = OperatingSystem.WINDOWS; } else if (userAgent.contains("linux")) { - isLinux = true; + if (userAgent.contains("android")) { + os = OperatingSystem.ANDROID; + parseAndroidVersion(userAgent); + } else { + os = OperatingSystem.LINUX; + + } } else if (userAgent.contains("macintosh") || userAgent.contains("mac osx") || userAgent.contains("mac os x")) { - isMacOSX = true; + if (userAgent.contains("ipad") || userAgent.contains("ipod") + || userAgent.contains("iphone")) { + os = OperatingSystem.IOS; + parseIOSVersion(userAgent); + } else { + os = OperatingSystem.MACOSX; + } + } + } + + private void parseAndroidVersion(String userAgent) { + // Android 5.1; + if (!userAgent.contains("android")) { + return; + } + + String osVersionString = safeSubstring(userAgent, + userAgent.indexOf("android ") + "android ".length(), + userAgent.length()); + osVersionString = safeSubstring(osVersionString, 0, + osVersionString.indexOf(";")); + String[] parts = osVersionString.split("\\."); + parseOsVersion(parts); + } + + private void parseIOSVersion(String userAgent) { + // OS 5_1 like Mac OS X + if (!userAgent.contains("os ") || !userAgent.contains(" like mac")) { + return; + } + + String osVersionString = safeSubstring(userAgent, + userAgent.indexOf("os ") + 3, userAgent.indexOf(" like mac")); + String[] parts = osVersionString.split("_"); + parseOsVersion(parts); + } + + private void parseOsVersion(String[] parts) { + osMajorVersion = -1; + osMinorVersion = -1; + + if (parts.length >= 1) { + try { + osMajorVersion = Integer.parseInt(parts[0]); + } catch (Exception e) { + } + } + if (parts.length >= 2) { + try { + osMinorVersion = Integer.parseInt(parts[1]); + } catch (Exception e) { + } + // Some Androids report version numbers as "2.1-update1" + if (osMinorVersion == -1 && parts[1].contains("-")) { + try { + osMinorVersion = Integer.parseInt(parts[1].substring(0, + parts[1].indexOf('-'))); + } catch (Exception ee) { + } + } } + } private void parseVersionString(String versionString) { @@ -306,7 +377,7 @@ public class VBrowserDetails implements Serializable { * @return true if run on Windows, false otherwise */ public boolean isWindows() { - return isWindows; + return os == OperatingSystem.WINDOWS; } /** @@ -315,7 +386,7 @@ public class VBrowserDetails implements Serializable { * @return true if run on Mac OSX, false otherwise */ public boolean isMacOSX() { - return isMacOSX; + return os == OperatingSystem.MACOSX; } /** @@ -324,7 +395,45 @@ public class VBrowserDetails implements Serializable { * @return true if run on Linux, false otherwise */ public boolean isLinux() { - return isLinux; + return os == OperatingSystem.LINUX; + } + + /** + * Tests if the browser is run on Android. + * + * @return true if run on Android, false otherwise + */ + public boolean isAndroid() { + return os == OperatingSystem.ANDROID; + } + + /** + * Tests if the browser is run in iOS. + * + * @return true if run in iOS, false otherwise + */ + public boolean isIOS() { + return os == OperatingSystem.IOS; + } + + /** + * Returns the major version of the operating system. Currently only + * supported for mobile devices (iOS/Android) + * + * @return The major version or -1 if unknown + */ + public int getOperatingSystemMajorVersion() { + return osMajorVersion; + } + + /** + * Returns the minor version of the operating system. Currently only + * supported for mobile devices (iOS/Android) + * + * @return The minor version or -1 if unknown + */ + public int getOperatingSystemMinorVersion() { + return osMinorVersion; } /** diff --git a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java index 533d6a78ae..62697c4d98 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java @@ -153,7 +153,7 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements * the new vertical scroll position, in pixels */ public void setScrollPosition(int position) { - if (isAndroidWithBrokenScrollTop()) { + if (BrowserInfo.get().isAndroidWithBrokenScrollTop()) { ArrayList<com.google.gwt.dom.client.Element> elements = TouchScrollDelegate .getElements(getElement()); for (com.google.gwt.dom.client.Element el : elements) { @@ -167,11 +167,6 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements } } - private boolean isAndroidWithBrokenScrollTop() { - return BrowserInfo.getBrowserString().contains("Android 3") - || BrowserInfo.getBrowserString().contains("Android 4"); - } - public void onScroll(ScrollEvent event) { Scheduler.get().scheduleDeferred(new ScheduledCommand() { public void execute() { diff --git a/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java b/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java index d4b59ed23a..8b2248aff6 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java +++ b/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java @@ -83,9 +83,8 @@ public class TouchScrollDelegate implements NativePreviewHandler { private static TouchScrollDelegate activeScrollDelegate; - private static final boolean androidWithBrokenScrollTop = BrowserInfo - .getBrowserString().contains("Android 3") - || BrowserInfo.getBrowserString().contains("Android 4"); + private static final boolean androidWithBrokenScrollTop = BrowserInfo.get() + .isAndroidWithBrokenScrollTop(); public TouchScrollDelegate(Element... elements) { scrollableElements = elements; diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java index 62a5e8ac8b..a555ecd392 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java @@ -57,7 +57,11 @@ public class ButtonConnector extends AbstractComponentConnector implements blurHandlerRegistration = EventHelper.updateBlurHandler(this, blurHandlerRegistration); // Set text - getWidget().setText(getState().getCaption()); + if (getState().isHtmlContentAllowed()) { + getWidget().setHtml(getState().getCaption()); + } else { + getWidget().setText(getState().getCaption()); + } // handle error if (null != getState().getErrorMessage()) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java index f26cdae0c6..fdc053b3ae 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java +++ b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java @@ -17,6 +17,10 @@ import com.vaadin.ui.Button; public class ButtonState extends ComponentState { private boolean disableOnClick = false; private int clickShortcutKeyCode = 0; + /** + * If caption should be rendered in HTML + */ + private boolean htmlContentAllowed = false; /** * Checks whether the button should be disabled on the client side on next @@ -62,4 +66,30 @@ public class ButtonState extends ComponentState { this.clickShortcutKeyCode = clickShortcutKeyCode; } + /** + * Set whether the caption text is rendered as HTML or not. You might need + * to retheme button to allow higher content than the original text style. + * + * If set to true, the captions are passed to the browser as html and the + * developer is responsible for ensuring no harmful html is used. If set to + * false, the content is passed to the browser as plain text. + * + * @param htmlContentAllowed + * <code>true</code> if caption is rendered as HTML, + * <code>false</code> otherwise + */ + public void setHtmlContentAllowed(boolean htmlContentAllowed) { + this.htmlContentAllowed = htmlContentAllowed; + } + + /** + * Return HTML rendering setting. + * + * @return <code>true</code> if the caption text is to be rendered as HTML, + * <code>false</code> otherwise + */ + public boolean isHtmlContentAllowed() { + return htmlContentAllowed; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java index f7d73d3b5e..e5e7dbba8b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java +++ b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java @@ -98,6 +98,10 @@ public class VButton extends FocusWidget implements ClickHandler { captionElement.setInnerText(text); } + public void setHtml(String html) { + captionElement.setInnerHTML(html); + } + @SuppressWarnings("deprecation") @Override /* diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java index 21e0e0820d..84b3c678eb 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java @@ -45,6 +45,13 @@ public class VDateFieldCalendar extends VDateField { */ @SuppressWarnings("deprecation") protected void updateValueFromPanel() { + + // If field is invisible at the beginning, client can still be null when + // this function is called. + if (getClient() == null) { + return; + } + Date date2 = calendarPanel.getDate(); Date currentDate = getCurrentDate(); if (currentDate == null || date2.getTime() != currentDate.getTime()) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java index 801c405826..84d3b73285 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java @@ -58,7 +58,11 @@ public class NativeButtonConnector extends AbstractComponentConnector implements blurHandlerRegistration); // Set text - getWidget().setText(getState().getCaption()); + if (getState().isHtmlContentAllowed()) { + getWidget().setHTML(getState().getCaption()); + } else { + getWidget().setText(getState().getCaption()); + } // handle error if (null != getState().getErrorMessage()) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java index d0b8f73eb1..01ac4fab6a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java +++ b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java @@ -65,6 +65,11 @@ public class VNativeButton extends Button implements ClickHandler { } @Override + public void setHTML(String html) { + captionElement.setInnerHTML(html); + } + + @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); diff --git a/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java index eb97160f52..0d222044ba 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java +++ b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java @@ -160,6 +160,13 @@ public class VNotification extends VOverlay { } super.show(); setPosition(position); + /** + * Android 4 fails to render notifications correctly without a little + * nudge (#8551) + */ + if (BrowserInfo.get().isAndroid()) { + Util.setStyleTemporarily(getElement(), "display", "none"); + } } @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java index 13fc55d7ea..12a69d5556 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java +++ b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java @@ -306,6 +306,7 @@ public class VRoot extends SimplePanel implements ResizeHandler, /*-{ var j; for(j in $wnd.vaadin.vaadinConfigurations) { + // $entry not needed as function is not exported list.@java.util.Collection::add(Ljava/lang/Object;)(j); } }-*/; diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java index 58d6a18592..77698805de 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java @@ -509,6 +509,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet protected void handleRequest(PortletRequest request, PortletResponse response) throws PortletException, IOException { + RequestTimer requestTimer = new RequestTimer(); + requestTimer.start(); + AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper( this); @@ -530,9 +533,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet WrappedPortletResponse wrappedResponse = new WrappedPortletResponse( response, getDeploymentConfiguration()); - RequestTimer requestTimer = RequestTimer.get(wrappedRequest); - requestTimer.start(wrappedRequest); - RequestType requestType = getRequestType(request); if (requestType == RequestType.UNKNOWN) { @@ -721,10 +721,11 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet } finally { Root.setCurrentRoot(null); Application.setCurrentApplication(null); - } - requestTimer.stop(); - RequestTimer.set(wrappedRequest, requestTimer); + requestTimer + .stop((AbstractWebApplicationContext) application + .getContext()); + } } } } diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index 799271b979..6ab2748332 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -400,12 +400,12 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements private void service(WrappedHttpServletRequest request, WrappedHttpServletResponse response) throws ServletException, IOException { + RequestTimer requestTimer = new RequestTimer(); + requestTimer.start(); + AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( this); - RequestTimer requestTimer = RequestTimer.get(request); - requestTimer.start(request); - RequestType requestType = getRequestType(request); if (!ensureCookiesEnabled(requestType, request, response)) { return; @@ -540,10 +540,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } finally { Root.setCurrentRoot(null); Application.setCurrentApplication(null); - } - requestTimer.stop(); - RequestTimer.set(request, requestTimer); + requestTimer + .stop((AbstractWebApplicationContext) application + .getContext()); + } } } diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index b780f66a23..c57e7d8bc1 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -1097,19 +1097,18 @@ public abstract class AbstractCommunicationManager implements Serializable { dragAndDropService.printJSONResponse(outWriter); } - writePerformanceDataForTestBench(request, outWriter); + writePerformanceData(outWriter); } /** - * Adds the performance timing data used by TestBench 3 to the UIDL + * Adds the performance timing data (used by TestBench 3) to the UIDL * response. */ - private void writePerformanceDataForTestBench(final WrappedRequest request, - final PrintWriter outWriter) { - Long totalTime = (Long) request.getAttribute("TOTAL"); - Long lastRequestTime = (Long) request.getAttribute("LASTREQUEST"); - outWriter.write(String.format(", \"tbss\":[%d, %d]", totalTime, - lastRequestTime)); + private void writePerformanceData(final PrintWriter outWriter) { + AbstractWebApplicationContext ctx = (AbstractWebApplicationContext) application + .getContext(); + outWriter.write(String.format(", \"timings\":[%d, %d]", + ctx.getTotalSessionTime(), ctx.getLastRequestTime())); } private void legacyPaint(PaintTarget paintTarget, diff --git a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java b/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java index c8335a8607..c0ae0afc26 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java @@ -44,6 +44,10 @@ public abstract class AbstractWebApplicationContext implements protected HashMap<Application, AbstractCommunicationManager> applicationToAjaxAppMgrMap = new HashMap<Application, AbstractCommunicationManager>(); + private long totalSessionTime = 0; + + private long lastRequestTime = -1; + public void addTransactionListener(TransactionListener listener) { if (listener != null) { listeners.add(listener); @@ -222,4 +226,30 @@ public abstract class AbstractWebApplicationContext implements return relativeUri.substring(index + 1, next); } + /** + * @return The total time spent servicing requests in this session. + */ + public long getTotalSessionTime() { + return totalSessionTime; + } + + /** + * Sets the time spent servicing the last request in the session and updates + * the total time spent servicing requests in this session. + * + * @param time + * the time spent in the last request. + */ + public void setLastRequestTime(long time) { + lastRequestTime = time; + totalSessionTime += time; + } + + /** + * @return the time spent servicing the last request in this session. + */ + public long getLastRequestTime() { + return lastRequestTime; + } + }
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/RequestTimer.java b/src/com/vaadin/terminal/gwt/server/RequestTimer.java index d47f444bef..6c0edec466 100644 --- a/src/com/vaadin/terminal/gwt/server/RequestTimer.java +++ b/src/com/vaadin/terminal/gwt/server/RequestTimer.java @@ -4,7 +4,7 @@ package com.vaadin.terminal.gwt.server; -import com.vaadin.terminal.WrappedRequest; +import java.io.Serializable; /** * Times the handling of requests and stores the information as an attribute in @@ -14,67 +14,30 @@ import com.vaadin.terminal.WrappedRequest; * * @author Jonatan Kronqvist / Vaadin Ltd */ -public class RequestTimer { - public static final String SESSION_ATTR_ID = "REQUESTTIMER"; - +public class RequestTimer implements Serializable { private long requestStartTime = 0; - private long totalSessionTime = 0; - private long lastRequestTime = -1; /** * Starts the timing of a request. This should be called before any * processing of the request. - * - * @param request - * the request. */ - public void start(WrappedRequest request) { + public void start() { requestStartTime = System.nanoTime(); - request.setAttribute("TOTAL", totalSessionTime); - request.setAttribute("LASTREQUEST", lastRequestTime); } /** * Stops the timing of a request. This should be called when all processing * of a request has finished. + * + * @param context */ - public void stop() { + public void stop(AbstractWebApplicationContext context) { // Measure and store the total handling time. This data can be // used in TestBench 3 tests. long time = (System.nanoTime() - requestStartTime) / 1000000; - lastRequestTime = time; - totalSessionTime += time; - } - - /** - * Returns a valid request timer for the specified request. Timers are - * session bound. - * - * @param request - * the request for which to get a valid timer. - * @return a valid timer. - */ - public static RequestTimer get(WrappedRequest request) { - RequestTimer timer = (RequestTimer) request - .getSessionAttribute(SESSION_ATTR_ID); - if (timer == null) { - timer = new RequestTimer(); - } - return timer; - } - /** - * Associates the specified request timer with the specified request. Since - * {@link #get(RequestWrapper)} will, at one point or another, return a new - * instance, this method should be called to keep the request <-> timer - * association updated. - * - * @param request - * the request for which to set the timer. - * @param requestTimer - * the timer. - */ - public static void set(WrappedRequest request, RequestTimer requestTimer) { - request.setSessionAttribute(RequestTimer.SESSION_ATTR_ID, requestTimer); + // The timings must be stored in the context, since a new + // RequestTimer is created for every request. + context.setLastRequestTime(time); } } diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java index f5e45ef3ef..876fe593e2 100644 --- a/src/com/vaadin/ui/Button.java +++ b/src/com/vaadin/ui/Button.java @@ -489,4 +489,33 @@ public class Button extends AbstractComponent implements return (ButtonState) super.getState(); } + /** + * Set whether the caption text is rendered as HTML or not. You might need + * to retheme button to allow higher content than the original text style. + * + * If set to true, the captions are passed to the browser as html and the + * developer is responsible for ensuring no harmful html is used. If set to + * false, the content is passed to the browser as plain text. + * + * @param htmlContentAllowed + * <code>true</code> if caption is rendered as HTML, + * <code>false</code> otherwise + */ + public void setHtmlContentAllowed(boolean htmlContentAllowed) { + if (getState().isHtmlContentAllowed() != htmlContentAllowed) { + getState().setHtmlContentAllowed(htmlContentAllowed); + requestRepaint(); + } + } + + /** + * Return HTML rendering setting + * + * @return <code>true</code> if the caption text is to be rendered as HTML, + * <code>false</code> otherwise + */ + public boolean isHtmlContentAllowed() { + return getState().isHtmlContentAllowed(); + } + } diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java index 2fffedd9d6..ba4c6529c5 100644 --- a/src/com/vaadin/ui/Table.java +++ b/src/com/vaadin/ui/Table.java @@ -1930,7 +1930,7 @@ public class Table extends AbstractSelect implements Action.Container, if (index < firstIndexNotInCache && index >= pageBufferFirstIndex && pageBuffer[CELL_GENERATED_ROW][indexInOldBuffer] == null - && pageBuffer[CELL_ITEMID][indexInOldBuffer] == id) { + && id.equals(pageBuffer[CELL_ITEMID][indexInOldBuffer])) { // we already have data in our cache, // recycle it instead of fetching it via // getValue/getPropertyValue diff --git a/tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java b/tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java index f661b6cf15..fedce98ecf 100644 --- a/tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java +++ b/tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java @@ -2,8 +2,6 @@ package com.vaadin.terminal.gwt.client; import junit.framework.TestCase; -import com.vaadin.terminal.gwt.client.VBrowserDetails; - public class TestVBrowserDetailsUserAgentParser extends TestCase { private static final String FIREFOX30_WINDOWS = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6"; @@ -37,6 +35,15 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { private static final String SAFARI3_WINDOWS = "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.29"; private static final String SAFARI4_MAC = "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; en-us) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7"; + private static final String IPHONE_IOS_5_1 = "Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B179 Safari/7534.48.3"; + private static final String IPHONE_IOS_4_0 = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7"; + private static final String IPAD_IOS_4_3_1 = "Mozilla/5.0 (iPad; U; CPU OS 4_3_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8G4 Safari/6533.18.5"; + + private static final String ANDROID_HTC_2_1 = "Mozilla/5.0 (Linux; U; Android 2.1-update1; en-us; ADR6300 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17"; + private static final String ANDROID_GOOGLE_NEXUS_2_2 = "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"; + private static final String ANDROID_MOTOROLA_3_0 = "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13"; + private static final String ANDROID_GALAXY_NEXUS_4_0_4_CHROME = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; + public void testSafari3() { VBrowserDetails bd = new VBrowserDetails(SAFARI3_WINDOWS); assertWebKit(bd); @@ -57,6 +64,86 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { assertMacOSX(bd); } + public void testIPhoneIOS5() { + VBrowserDetails bd = new VBrowserDetails(IPHONE_IOS_5_1); + assertWebKit(bd); + assertSafari(bd); + assertBrowserMajorVersion(bd, 5); + assertBrowserMinorVersion(bd, 1); + assertEngineVersion(bd, 534f); + assertIOS(bd, 5, 1); + } + + public void testIPhoneIOS4() { + VBrowserDetails bd = new VBrowserDetails(IPHONE_IOS_4_0); + assertWebKit(bd); + assertSafari(bd); + assertBrowserMajorVersion(bd, 4); + assertBrowserMinorVersion(bd, 0); + assertEngineVersion(bd, 532f); + assertIOS(bd, 4, 0); + } + + public void testIPadIOS4() { + VBrowserDetails bd = new VBrowserDetails(IPAD_IOS_4_3_1); + assertWebKit(bd); + assertSafari(bd); + assertBrowserMajorVersion(bd, 5); + assertBrowserMinorVersion(bd, 0); + assertEngineVersion(bd, 533f); + assertIOS(bd, 4, 3); + } + + public void testAndroid21() { + VBrowserDetails bd = new VBrowserDetails(ANDROID_HTC_2_1); + assertWebKit(bd); + assertSafari(bd); + assertBrowserMajorVersion(bd, 4); + assertBrowserMinorVersion(bd, 0); + assertEngineVersion(bd, 530f); + assertAndroid(bd, 2, 1); + + } + + public void testAndroid22() { + VBrowserDetails bd = new VBrowserDetails(ANDROID_GOOGLE_NEXUS_2_2); + assertWebKit(bd); + assertSafari(bd); + assertBrowserMajorVersion(bd, 4); + assertBrowserMinorVersion(bd, 0); + assertEngineVersion(bd, 533f); + assertAndroid(bd, 2, 2); + } + + public void testAndroid30() { + VBrowserDetails bd = new VBrowserDetails(ANDROID_MOTOROLA_3_0); + assertWebKit(bd); + assertSafari(bd); + assertBrowserMajorVersion(bd, 4); + assertBrowserMinorVersion(bd, 0); + assertEngineVersion(bd, 534f); + assertAndroid(bd, 3, 0); + } + + public void testAndroid40Chrome() { + VBrowserDetails bd = new VBrowserDetails( + ANDROID_GALAXY_NEXUS_4_0_4_CHROME); + assertWebKit(bd); + assertChrome(bd); + assertBrowserMajorVersion(bd, 18); + assertBrowserMinorVersion(bd, 0); + assertEngineVersion(bd, 535f); + assertAndroid(bd, 4, 0); + } + + private void assertOSMajorVersion(VBrowserDetails bd, int i) { + assertEquals(i, bd.getOperatingSystemMajorVersion()); + } + + private void assertOSMinorVersion(VBrowserDetails bd, int i) { + assertEquals(i, bd.getOperatingSystemMinorVersion()); + } + public void testChrome3() { VBrowserDetails bd = new VBrowserDetails(CHROME3_MAC); assertWebKit(bd); @@ -352,18 +439,47 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { assertFalse(browserDetails.isLinux()); assertFalse(browserDetails.isWindows()); assertTrue(browserDetails.isMacOSX()); + assertFalse(browserDetails.isAndroid()); + } + + private void assertAndroid(VBrowserDetails browserDetails, + int majorVersion, int minorVersion) { + assertFalse(browserDetails.isLinux()); + assertFalse(browserDetails.isWindows()); + assertFalse(browserDetails.isMacOSX()); + assertFalse(browserDetails.isIOS()); + assertTrue(browserDetails.isAndroid()); + + assertOSMajorVersion(browserDetails, majorVersion); + assertOSMinorVersion(browserDetails, minorVersion); + } + + private void assertIOS(VBrowserDetails browserDetails, int majorVersion, + int minorVersion) { + assertFalse(browserDetails.isLinux()); + assertFalse(browserDetails.isWindows()); + assertFalse(browserDetails.isMacOSX()); + assertTrue(browserDetails.isIOS()); + assertFalse(browserDetails.isAndroid()); + + assertOSMajorVersion(browserDetails, majorVersion); + assertOSMinorVersion(browserDetails, minorVersion); } private void assertWindows(VBrowserDetails browserDetails) { assertFalse(browserDetails.isLinux()); assertTrue(browserDetails.isWindows()); assertFalse(browserDetails.isMacOSX()); + assertFalse(browserDetails.isIOS()); + assertFalse(browserDetails.isAndroid()); } private void assertLinux(VBrowserDetails browserDetails) { assertTrue(browserDetails.isLinux()); assertFalse(browserDetails.isWindows()); assertFalse(browserDetails.isMacOSX()); + assertFalse(browserDetails.isIOS()); + assertFalse(browserDetails.isAndroid()); } } diff --git a/tests/server-side/com/vaadin/tests/server/SourceFileChecker.java b/tests/server-side/com/vaadin/tests/server/SourceFileChecker.java index 453aab5af8..9906990165 100644 --- a/tests/server-side/com/vaadin/tests/server/SourceFileChecker.java +++ b/tests/server-side/com/vaadin/tests/server/SourceFileChecker.java @@ -5,6 +5,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.util.HashSet; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import junit.framework.Assert; import junit.framework.TestCase; @@ -81,6 +83,17 @@ public class SourceFileChecker extends TestCase { } } + public void testGwtFilesUsingEntry() { + Set<String> ignore = new HashSet<String>(alwaysIgnore); + ignore.add(externalJavaFiles); + validateFiles( + SRC_DIR, + new GwtEntryChecker(), + ignore, + "The following files might export javscript callbacks without $entry:\n{0}", + ".java"); + } + public interface FileValidator { void validateFile(File f) throws Exception; } @@ -171,4 +184,33 @@ public class SourceFileChecker extends TestCase { } } } + + class GwtEntryChecker extends FileContentsValidator { + // Matches e.g. + // @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::escapeHtml( + private final Matcher matcher = Pattern.compile("@[\\w.]+::\\w+\\(") + .matcher(""); + + @Override + protected void validateContents(File f, String contents) + throws Exception { + matcher.reset(contents); + while (matcher.find()) { + int start = matcher.start(); + + // Search backwards to find index of native block start + int nativeBlockStart = contents.lastIndexOf("/*-{", start); + + // Get contents between block start and our match + String beforeMatchInBlock = contents.substring( + nativeBlockStart, start); + + // Fail if there's no $entry + if (!beforeMatchInBlock.contains("$entry")) { + throw new IllegalArgumentException(); + } + } + } + + } } diff --git a/tests/server-side/com/vaadin/tests/server/component/tree/TestHasChildren.java b/tests/server-side/com/vaadin/tests/server/component/tree/TestHasChildren.java new file mode 100644 index 0000000000..66535d3ffb --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/tree/TestHasChildren.java @@ -0,0 +1,25 @@ +package com.vaadin.tests.server.component.tree; + +import junit.framework.TestCase; + +import com.vaadin.ui.Tree; + +public class TestHasChildren extends TestCase { + + private Tree tree; + + @Override + protected void setUp() { + tree = new Tree(); + tree.addItem("parent"); + tree.addItem("child"); + tree.setChildrenAllowed("parent", true); + tree.setParent("child", "parent"); + } + + public void testRemoveChildren() { + assertTrue(tree.hasChildren("parent")); + tree.removeItem("child"); + assertFalse(tree.hasChildren("parent")); + } +} diff --git a/tests/test.xml b/tests/test.xml index 28459c37e9..67e48ee137 100644 --- a/tests/test.xml +++ b/tests/test.xml @@ -11,7 +11,7 @@ <!-- Configuration --> <!-- ================================================================== --> <!-- Browsers to use for testing --> - <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox11,winxp-safari5,winxp-googlechrome18,winxp-opera11" /> + <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox12,winxp-safari5,winxp-googlechrome18,winxp-opera11" /> <property name="browsers-linux" value="linux-firefox3,linux-opera10,linux-googlechrome8" /> <property name="browsers-mac" value="osx-firefox3,osx-opera10,osx-googlechrome8,osx-safari4,osx-safari5" /> diff --git a/tests/testbench/com/vaadin/tests/components/TouchScrollables.java b/tests/testbench/com/vaadin/tests/components/TouchScrollables.java index 636bddead8..053691e738 100644 --- a/tests/testbench/com/vaadin/tests/components/TouchScrollables.java +++ b/tests/testbench/com/vaadin/tests/components/TouchScrollables.java @@ -15,27 +15,102 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation; import com.vaadin.tests.util.Person; import com.vaadin.tests.util.PersonContainer; import com.vaadin.tests.util.TestUtils; -import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails; +import com.vaadin.ui.Accordion; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; -import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; +import com.vaadin.ui.Layout; import com.vaadin.ui.Panel; +import com.vaadin.ui.TabSheet; import com.vaadin.ui.Table; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.Window; public class TouchScrollables extends TestBase { java.util.Random r = new java.util.Random(1); - private HorizontalLayout testSelector; + private TabSheet testSelector = new TabSheet(); @Override public void setup() { - testSelector = new HorizontalLayout(); getLayout().addComponent(testSelector); + testSelector.setHeight("500px"); + addTest(getPanelTest()); + addTest(getSimpleTableTest()); + addTest(getDDSortableTableTest()); + addTest(getTabSheetTest()); + addTest(getSplitPanelTest()); + addTest(getAccordionTest()); + addTest(getSubWindowTest()); + + TestUtils + .injectCSS( + getLayout().getRoot(), + "body * {-webkit-user-select: none;} .v-table-row-drag-middle .v-table-cell-content {" + + " background-color: inherit ; border-bottom: 1px solid cyan;" + + "}" + + ".v-table-row-drag-middle .v-table-cell-wrapper {" + + " margin-bottom: -1px;" + "}" + "" + + ); + } + + private Component getPanelTest() { + Layout cssLayout = new CssLayout(); + cssLayout.setCaption("Panel"); + + final Panel p = new Panel(); + p.setHeight("400px"); + Label l50 = null; + for (int i = 0; i < 100; i++) { + Label c = new Label("Label" + i); + p.addComponent(c); + if (i == 50) { + l50 = c; + } + } + + final Label l = l50; + Button button = new Button("Scroll to label 50", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + getLayout().getRoot().scrollIntoView(l); + } + }); + cssLayout.addComponent(button); + button = new Button("Scroll to 100px", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + p.setScrollTop(100); + } + }); + cssLayout.addComponent(button); + cssLayout.addComponent(p); + return cssLayout; + } + + private Component getTabSheetTest() { + TabSheet ts = new TabSheet(); + ts.setCaption("Tabsheet"); + ts.setHeight("100%"); + ts.addTab(getBigComponent(), "Tab 1"); + ts.addTab(getBigComponent(), "Tab 2"); + return ts; + } + + private Component getSplitPanelTest() { + HorizontalSplitPanel sp = new HorizontalSplitPanel(); + sp.setCaption("Splitpanel"); + sp.addComponent(getBigComponent()); + sp.addComponent(getBigComponent()); + return sp; + } + + private Component getSimpleTableTest() { CssLayout cssLayout = new CssLayout(); final Table table = new Table(); @@ -68,57 +143,33 @@ public class TouchScrollables extends TestBase { } cssLayout.addComponent(table); cssLayout.setCaption("Table"); + return cssLayout; + } - addTest(cssLayout); - - cssLayout = new CssLayout(); - cssLayout.setCaption("Panel"); - - final Panel p = new Panel(); - p.setHeight("400px"); - p.setCaption("Panel"); - Label l50 = null; - for (int i = 0; i < 100; i++) { - Label c = new Label("Label" + i); - p.addComponent(c); - if (i == 50) { - l50 = c; - } - } + private Component getAccordionTest() { + Accordion a = new Accordion(); + a.setCaption("Accordion"); + a.setHeight("100%"); + a.addTab(getBigComponent(), "Tab 1"); + a.addTab(getBigComponent(), "Tab 2"); + a.addTab(getBigComponent(), "Tab 3"); + return a; + } - final Label l = l50; - button = new Button("Scroll to label 50", new Button.ClickListener() { + private Component getSubWindowTest() { + Button b = new Button("Open subwindow", new Button.ClickListener() { public void buttonClick(ClickEvent event) { - getLayout().getRoot().scrollIntoView(l); + Window w = new Window("Subwindow"); + w.center(); + w.setHeight("200px"); + w.addComponent(getBigComponent()); + getMainWindow().addWindow(w); } }); - cssLayout.addComponent(button); - button = new Button("Scroll to 100px", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - p.setScrollTop(100); - } - }); - cssLayout.addComponent(button); - cssLayout.addComponent(p); - - addTest(cssLayout); - - TestUtils - .injectCSS( - getLayout().getRoot(), - "body * {-webkit-user-select: none;} .v-table-row-drag-middle .v-table-cell-content {" - + " background-color: inherit ; border-bottom: 1px solid cyan;" - + "}" - + ".v-table-row-drag-middle .v-table-cell-wrapper {" - + " margin-bottom: -1px;" + "}" + "" - - ); - - addDDSortableTable(); - + return b; } - private void addDDSortableTable() { + private Component getDDSortableTableTest() { final Table table; table = new Table(); table.setCaption("DD sortable table with context menus"); @@ -219,7 +270,7 @@ public class TouchScrollables extends TestBase { } }); - addTest(table); + return table; } private void populateTable(Table table) { @@ -238,21 +289,17 @@ public class TouchScrollables extends TestBase { } - private Component testComponent; - - private void addTest(final AbstractComponent t) { - Button button = new Button(t.getCaption()); - testSelector.addComponent(button); - button.addListener(new Button.ClickListener() { + private void addTest(final Component t) { + testSelector.addComponent(t); + } - public void buttonClick(ClickEvent event) { - if (testComponent != null) { - getLayout().removeComponent(testComponent); - } - testComponent = t; - getLayout().addComponent(t); - } - }); + private Component getBigComponent() { + Layout l = new VerticalLayout(); + for (int i = 0; i < 100; i++) { + Label c = new Label("Label" + i); + l.addComponent(c); + } + return l; } @Override diff --git a/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.html b/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.html new file mode 100644 index 0000000000..2d58d0e2e1 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.html @@ -0,0 +1,47 @@ +<?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>ButtonHtml</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">ButtonHtml</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.button.ButtonHtml?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>initial</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsbuttonButtonHtml::/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>after_1_click</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsbuttonButtonHtml::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>after_2_clicks</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.java b/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.java new file mode 100644 index 0000000000..253de5b43c --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.java @@ -0,0 +1,39 @@ +package com.vaadin.tests.components.button; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; + +public class ButtonHtml extends TestBase { + + @Override + protected void setup() { + Button b = new Button("<b>Plain text button</b>"); + addComponent(b); + + b = new Button( + "<span style=\"color: red; font-weight: bold;\">HTML</span> button"); + b.setHtmlContentAllowed(true); + addComponent(b); + + final Button swapButton = new Button("<i>Swap button<i>"); + swapButton.addListener(new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + swapButton.setHtmlContentAllowed(!swapButton + .isHtmlContentAllowed()); + } + }); + addComponent(swapButton); + } + + @Override + protected String getDescription() { + return "Verify that Button HTML rendering works"; + } + + @Override + protected Integer getTicketNumber() { + return 8663; + } +} diff --git a/tests/testbench/com/vaadin/tests/components/combobox/GridLayoutComboBoxZoomOut.java b/tests/testbench/com/vaadin/tests/components/combobox/GridLayoutComboBoxZoomOut.java new file mode 100644 index 0000000000..37b0fe21a1 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/combobox/GridLayoutComboBoxZoomOut.java @@ -0,0 +1,62 @@ +package com.vaadin.tests.components.combobox; + +import com.vaadin.tests.components.AbstractTestCase; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Layout; +import com.vaadin.ui.Root; +import com.vaadin.ui.Select; + +@SuppressWarnings("serial") +public class GridLayoutComboBoxZoomOut extends AbstractTestCase { + + @Override + public void init() { + Root.LegacyWindow mainWindow = new Root.LegacyWindow( + "Gridlayoutbug Application"); + setMainWindow(mainWindow); + + Label description = new Label( + "Open this application in Chrome, zoom out (cmd + \"-\") and " + + "open the ComboBox for weird behaviour."); + mainWindow.addComponent(description); + + Layout formLayout = new GridLayout(2, 1); + // formLayout.setWidth("100%"); + formLayout.setWidth("1000px"); + + Select countryField = new ComboBox(); + countryField.addItem("Finland"); + countryField.addItem("Sweden"); + countryField.addItem("Canada"); + countryField.addItem("USA"); + countryField.setCaption("Country"); + countryField.setWidth("100%"); + formLayout.addComponent(countryField); + + Select statusField = new ComboBox(); + statusField.addItem("Available"); + statusField.addItem("On vacation"); + statusField.addItem("Busy"); + statusField.addItem("Left the building"); + statusField.setCaption("Status"); + statusField.setWidth("100%"); + formLayout.addComponent(statusField); + + mainWindow.addComponent(formLayout); + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java index de08477dd3..b8c5be57bf 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java @@ -25,6 +25,10 @@ public class InlineDateFields extends ComponentTestCase<InlineDateField> { @Override protected void initializeComponents() { + InlineDateField hidden = new InlineDateField(); + hidden.setVisible(false); // Used to break rest of layout #8693 + addComponent(hidden); + Locale locale = LOCALES[0]; InlineDateField pd = createInlineDateField("Undefined width", "-1", diff --git a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldsHiddenOnStart.html b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldsHiddenOnStart.html new file mode 100644 index 0000000000..6b79ef419b --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldsHiddenOnStart.html @@ -0,0 +1,26 @@ +<?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.datefield.InlineDateFields?restartApplication</td> + <td></td> +</tr> +<tr> + <td>assertElementPresent</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFields::PID_SLocale-en_US-undefined-wide/VCalendarPanel[0]#header</td> + <td></td> +</tr> +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.html b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.html new file mode 100644 index 0000000000..8a1b21c35d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.html @@ -0,0 +1,47 @@ +<?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>NativeButtonHtml</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">NativeButtonHtml</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.nativebutton.NativeButtonHtml?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>initial</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonHtml::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VNativeButton[0]</td> + <td>116,9</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>after_1_click</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonHtml::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VNativeButton[0]</td> + <td>74,10</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>after_2_clicks</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.java b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.java new file mode 100644 index 0000000000..011439f810 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.java @@ -0,0 +1,41 @@ +package com.vaadin.tests.components.nativebutton; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.NativeButton; + +public class NativeButtonHtml extends TestBase { + + @Override + protected void setup() { + NativeButton b = new NativeButton("<b>Plain text button</b>"); + addComponent(b); + + b = new NativeButton( + "<span style=\"color: red; font-weight: bold;\">HTML</span> button"); + b.setHtmlContentAllowed(true); + addComponent(b); + + final NativeButton swapButton = new NativeButton("<i>Swap button<i>"); + swapButton.addListener(new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + swapButton.setHtmlContentAllowed(!swapButton + .isHtmlContentAllowed()); + } + }); + addComponent(swapButton); + } + + @Override + protected String getDescription() { + return "Verify that NativeButton HTML rendering works"; + } + + @Override + protected Integer getTicketNumber() { + // 8663 was for normal button (see ButtonHtml test) + return null; + } +} diff --git a/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.html b/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.html new file mode 100644 index 0000000000..5364b1cd1e --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.html @@ -0,0 +1,97 @@ +<?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://arturwin.office.itmill.com:9999/" /> +<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.table.TableWithContainerRequiringEqualsForItemId?debug&restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[0]</td> + <td>523,81</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::PID_SLog_row_0</td> + <td>1. Button Button999 clicked</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[14]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::PID_SLog_row_0</td> + <td>2. Button Button985 clicked</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]</td> + <td>19,7</td> +</tr> +<tr> + <td>contextmenu</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>0</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::PID_SLog_row_0</td> + <td>3. Button Button0 clicked</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]</td> + <td>8,15</td> +</tr> +<tr> + <td>contextmenu</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>999</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::PID_SLog_row_0</td> + <td>4. Button Button999 clicked</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.java b/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.java new file mode 100644 index 0000000000..1b0335b673 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.java @@ -0,0 +1,128 @@ +package com.vaadin.tests.components.table; + +import java.util.Date; + +import com.vaadin.data.util.BeanContainer; +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Component; +import com.vaadin.ui.Table; +import com.vaadin.ui.themes.Reindeer; + +public class TableWithContainerRequiringEqualsForItemId extends TestBase { + + private MyEntityContainer container = new MyEntityContainer(); + private Log log = new Log(10); + + public static class MyEntityContainer extends BeanContainer<Long, MyEntity> { + + public MyEntityContainer() { + super(MyEntity.class); + setBeanIdResolver(new BeanIdResolver<Long, TableWithContainerRequiringEqualsForItemId.MyEntity>() { + + public Long getIdForBean(MyEntity bean) { + // Return a new instance every time to ensure Table can + // handle it + return new Long(bean.getId()); + } + }); + + } + + @Override + public Long getIdByIndex(int index) { + // Explicitly get the id using the resolver to make sure the + // instance does not stay the same + BeanItem<MyEntity> beanItem = getItem(super.getIdByIndex(index)); + return getBeanIdResolver().getIdForBean(beanItem.getBean()); + }; + + } + + @Override + protected void setup() { + Table t = new Table("Table with 1000 item"); + t.addGeneratedColumn("Actions", new Table.ColumnGenerator() { + public Component generateCell(final Table source, + final Object itemId, final Object columnId) { + Button tripFolderLink = new Button("Button" + itemId); + tripFolderLink.addListener(new Button.ClickListener() { + public void buttonClick(final ClickEvent event) { + log.log("Button " + event.getButton().getCaption() + + " clicked"); + } + }); + tripFolderLink.setStyleName(Reindeer.BUTTON_SMALL); + return tripFolderLink; + } + }); + + for (int i = 0; i < 1000; i++) { + MyEntity myEntity = new MyEntity(i + "st"); + myEntity.setCreated(new Date(new Date().getTime() - 24 * 60 * 60 + * 1000L)); + myEntity.setId(i); + container.addBean(myEntity); + // entityProvider.addEntity(myEntity); + } + + t.setContainerDataSource(container); + t.setVisibleColumns(new String[] { "id", "created", "name", "Actions" }); + + addComponent(t); + addComponent(log); + + t.sort(new Object[] { "id" }, new boolean[] { false }); + + } + + @Override + protected String getDescription() { + return "Test that verifies that Table works correctly with containers which do not return the same instance of the itemId object but instead requires an itemId.equals(otherItemId) check"; + } + + @Override + protected Integer getTicketNumber() { + return 8712; + } + + public static class MyEntity { + + private long id; + + private String name; + + private Date created; + + public MyEntity() { + } + + public MyEntity(String string) { + name = string; + } + + public String getName() { + return name; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + } + +} diff --git a/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.html b/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.html new file mode 100644 index 0000000000..fd45e7284d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.html @@ -0,0 +1,71 @@ +<?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>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.dd.NotPaintedAcceptSource?restartApplication</td> + <td></td> +</tr> +<!--Drag value 0 to target--> +<tr> + <td>drag</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>50,9</td> +</tr> +<tr> + <td>drop</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>124,20</td> +</tr> +<!--Assert drag was successful--> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>Source 1 value 0</td> +</tr> +<!--Swap source and verify it was properly painted--> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>Source 2</td> +</tr> +<!--Drag value 0 from source 2 and verify--> +<tr> + <td>drag</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>19,8</td> +</tr> +<tr> + <td>drop</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>139,18</td> +</tr> +<tr> + <td>contextmenu</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td> + <td>Source 2 value 0</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.java b/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.java new file mode 100644 index 0000000000..74774f09ab --- /dev/null +++ b/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.java @@ -0,0 +1,91 @@ +package com.vaadin.tests.dd; + +import com.vaadin.data.Item; +import com.vaadin.event.dd.DragAndDropEvent; +import com.vaadin.event.dd.DropHandler; +import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; +import com.vaadin.event.dd.acceptcriteria.SourceIs; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Table; +import com.vaadin.ui.Table.TableDragMode; +import com.vaadin.ui.Table.TableTransferable; + +public class NotPaintedAcceptSource extends TestBase { + + @Override + protected void setup() { + final Table source1 = createTable("Source 1"); + final Table source2 = createTable("Source 2"); + final Table target = createTable("Target"); + + source1.setDragMode(TableDragMode.ROW); + source2.setDragMode(TableDragMode.ROW); + + target.setDropHandler(new DropHandler() { + public AcceptCriterion getAcceptCriterion() { + return new SourceIs(source1, source2); + } + + public void drop(DragAndDropEvent event) { + TableTransferable transferable = (TableTransferable) event + .getTransferable(); + Item item = transferable.getSourceComponent().getItem( + transferable.getItemId()); + Object value = item.getItemProperty("value").getValue(); + AbstractSelectTargetDetails targetDetails = (AbstractSelectTargetDetails) event + .getTargetDetails(); + Object targetItemId = targetDetails.getItemIdOver(); + Object addItemAfter = target.addItemAfter(targetItemId); + target.getItem(addItemAfter).getItemProperty("value") + .setValue(value); + transferable.getSourceComponent().removeItem( + transferable.getItemId()); + } + }); + + final HorizontalLayout horizontalLayout = new HorizontalLayout(); + horizontalLayout.setSpacing(true); + horizontalLayout.addComponent(source1); + horizontalLayout.addComponent(target); + + addComponent(horizontalLayout); + + addComponent(new Button("Swap sources", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + if (source1.getParent() != null) { + horizontalLayout.replaceComponent(source1, source2); + } else { + horizontalLayout.replaceComponent(source2, source1); + } + target.requestRepaint(); + } + })); + + } + + private Table createTable(String caption) { + Table table = new Table(caption); + table.addContainerProperty("value", String.class, ""); + for (int i = 0; i < 10; i++) { + table.addItem(new Object[] { caption + " value " + i }, + Integer.valueOf(i)); + } + table.setWidth("300px"); + return table; + } + + @Override + protected String getDescription() { + return "Including a component in an accept criterion when the actual component is not included in a layout and thus not painted should still allow painting the component properly when it is added to a layout."; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(8730); + } + +} diff --git a/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html b/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html index 4bc409b881..8408aba9fd 100644 --- a/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html +++ b/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html @@ -13,7 +13,7 @@ </thead><tbody> <tr> <td>open</td> - <td>/run/com.vaadin.tests.layouts.layouttester.LayoutTesterApplication</td> + <td>/run/com.vaadin.tests.layouts.layouttester.LayoutTesterApplication?restartApplication</td> <td></td> </tr> <tr> |