diff options
72 files changed, 2392 insertions, 718 deletions
diff --git a/build/build.xml b/build/build.xml index 436170edc2..800de09db2 100644 --- a/build/build.xml +++ b/build/build.xml @@ -394,10 +394,6 @@ </fileset> </copy> - <!-- Unify mix usage of mac/Linux/Win characters --> - <echo>Unifying mix usage of Mac/Linux/Win linefeeds for java/html/css/xml files.</echo> - <fixcrlf srcdir="${result-path}/src" eol="crlf" tablength="4" tab="asis" includes="**/*.java **/*.html **/*.css **/*.xml" /> - <!-- Add other files such as images, these are not filtered or processed by fixcrlf task --> <echo>Copying non java/html/css/xml files such as images.</echo> <copy todir="${result-src-core}"> diff --git a/src/com/vaadin/annotations/JavaScript.java b/src/com/vaadin/annotations/JavaScript.java new file mode 100644 index 0000000000..065c37b78d --- /dev/null +++ b/src/com/vaadin/annotations/JavaScript.java @@ -0,0 +1,32 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.terminal.gwt.server.ClientConnector; + +/** + * If this annotation is present on a {@link ClientConnector} class, the + * framework ensures the referenced JavaScript files are loaded before the init + * method for the corresponding client-side connector is invoked. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface JavaScript { + /** + * JavaScript files to load before initializing the client-side connector. + * + * @return an array of JavaScript file urls + */ + public String[] value(); +} diff --git a/src/com/vaadin/annotations/LoadScripts.java b/src/com/vaadin/annotations/LoadScripts.java deleted file mode 100644 index 84ac2d2fb7..0000000000 --- a/src/com/vaadin/annotations/LoadScripts.java +++ /dev/null @@ -1,24 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Temporary hack used for ensuring external javascript libraries are included. - * To add a javascript, add this annotation to your Root class. - * - * @deprecated Will be removed in favor of a more robust solution before version - * 7.0.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Deprecated -public @interface LoadScripts { - public String[] value(); - -} diff --git a/src/com/vaadin/annotations/StyleSheet.java b/src/com/vaadin/annotations/StyleSheet.java new file mode 100644 index 0000000000..f8bf635474 --- /dev/null +++ b/src/com/vaadin/annotations/StyleSheet.java @@ -0,0 +1,32 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.terminal.gwt.server.ClientConnector; + +/** + * If this annotation is present on a {@link ClientConnector} class, the + * framework ensures the referenced style sheets are loaded before the init + * method for the corresponding client-side connector is invoked. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface StyleSheet { + /** + * Style sheets to load before initializing the client-side connector. + * + * @return an array of style sheet urls + */ + public String[] value(); +} diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java index 960b0a8b0e..540841a6ae 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java @@ -218,7 +218,7 @@ public class ApplicationConfiguration implements EntryPoint { static// TODO consider to make this hashmap per application LinkedList<Command> callbacks = new LinkedList<Command>(); - private static int widgetsLoading; + private static int dependenciesLoading; private static ArrayList<ApplicationConnection> runningApplications = new ArrayList<ApplicationConnection>(); @@ -454,26 +454,26 @@ public class ApplicationConfiguration implements EntryPoint { * * @param c */ - static void runWhenWidgetsLoaded(Command c) { - if (widgetsLoading == 0) { + static void runWhenDependenciesLoaded(Command c) { + if (dependenciesLoading == 0) { c.execute(); } else { callbacks.add(c); } } - static void startWidgetLoading() { - widgetsLoading++; + static void startDependencyLoading() { + dependenciesLoading++; } - static void endWidgetLoading() { - widgetsLoading--; - if (widgetsLoading == 0 && !callbacks.isEmpty()) { + static void endDependencyLoading() { + dependenciesLoading--; + if (dependenciesLoading == 0 && !callbacks.isEmpty()) { for (Command cmd : callbacks) { cmd.execute(); } callbacks.clear(); - } else if (widgetsLoading == 0 && deferredWidgetLoader != null) { + } else if (dependenciesLoading == 0 && deferredWidgetLoader != null) { deferredWidgetLoader.trigger(); } @@ -534,7 +534,7 @@ public class ApplicationConfiguration implements EntryPoint { } private boolean isBusy() { - if (widgetsLoading > 0) { + if (dependenciesLoading > 0) { communicationFree = 0; return true; } diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index f0470c8ee8..da4dfa08dc 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -35,11 +35,12 @@ import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage; +import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadEvent; +import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadListener; import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper; import com.vaadin.terminal.gwt.client.communication.JsonDecoder; import com.vaadin.terminal.gwt.client.communication.JsonEncoder; @@ -1067,6 +1068,14 @@ public class ApplicationConnection { json.getValueMap("typeMappings"), widgetSet); } + VConsole.log("Handling resource dependencies"); + if (json.containsKey("scriptDependencies")) { + loadScriptDependencies(json.getJSStringArray("scriptDependencies")); + } + if (json.containsKey("styleDependencies")) { + loadStyleDependencies(json.getJSStringArray("styleDependencies")); + } + handleUIDLDuration.logDuration( " * Handling type mappings from server completed", 10); /* @@ -1608,7 +1617,67 @@ public class ApplicationConnection { } }; - ApplicationConfiguration.runWhenWidgetsLoaded(c); + ApplicationConfiguration.runWhenDependenciesLoaded(c); + } + + private void loadStyleDependencies(JsArrayString dependencies) { + // Assuming no reason to interpret in a defined order + ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { + public void onLoad(ResourceLoadEvent event) { + ApplicationConfiguration.endDependencyLoading(); + } + + public void onError(ResourceLoadEvent event) { + VConsole.error(event.getResourceUrl() + + " could not be loaded, or the load detection failed because the stylesheet is empty."); + // The show must go on + onLoad(event); + } + }; + ResourceLoader loader = ResourceLoader.get(); + for (int i = 0; i < dependencies.length(); i++) { + String url = translateVaadinUri(dependencies.get(i)); + ApplicationConfiguration.startDependencyLoading(); + loader.loadStylesheet(url, resourceLoadListener); + } + } + + private void loadScriptDependencies(final JsArrayString dependencies) { + if (dependencies.length() == 0) { + return; + } + + // Listener that loads the next when one is completed + ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { + public void onLoad(ResourceLoadEvent event) { + if (dependencies.length() != 0) { + String url = translateVaadinUri(dependencies.shift()); + ApplicationConfiguration.startDependencyLoading(); + // Load next in chain (hopefully already preloaded) + event.getResourceLoader().loadScript(url, this); + } + // Call start for next before calling end for current + ApplicationConfiguration.endDependencyLoading(); + } + + public void onError(ResourceLoadEvent event) { + VConsole.error(event.getResourceUrl() + " could not be loaded."); + // The show must go on + onLoad(event); + } + }; + + ResourceLoader loader = ResourceLoader.get(); + + // Start chain by loading first + String url = translateVaadinUri(dependencies.shift()); + ApplicationConfiguration.startDependencyLoading(); + loader.loadScript(url, resourceLoadListener); + + // Preload all remaining + for (int i = 0; i < dependencies.length(); i++) { + loader.loadScript(dependencies.get(i), null); + } } // Redirect browser, null reloads current page @@ -2216,6 +2285,9 @@ public class ApplicationConnection { } if (uidlUri.startsWith("app://")) { uidlUri = getAppUri() + uidlUri.substring(6); + } else if (uidlUri.startsWith("connector://")) { + uidlUri = getAppUri() + "APP/CONNECTOR/" + + uidlUri.substring("connector://".length()); } return uidlUri; } @@ -2250,57 +2322,8 @@ public class ApplicationConnection { /* Extended title handling */ - /** - * Data showed in tooltips are stored centrilized as it may be needed in - * varios place: caption, layouts, and in owner components themselves. - * - * Updating TooltipInfo is done in updateComponent method. - * - */ - public TooltipInfo getTooltipTitleInfo(ComponentConnector titleOwner, - Object key) { - if (null == titleOwner) { - return null; - } - return connectorMap.getTooltipInfo(titleOwner, key); - } - private final VTooltip tooltip = new VTooltip(this); - /** - * Component may want to delegate Tooltip handling to client. Layouts add - * Tooltip (description, errors) to caption, but some components may want - * them to appear one other elements too. - * - * Events wanted by this handler are same as in Tooltip.TOOLTIP_EVENTS - * - * @param event - * @param owner - */ - public void handleTooltipEvent(Event event, ComponentConnector owner) { - tooltip.handleTooltipEvent(event, owner, null); - - } - - /** - * Component may want to delegate Tooltip handling to client. Layouts add - * Tooltip (description, errors) to caption, but some components may want - * them to appear one other elements too. - * - * Events wanted by this handler are same as in Tooltip.TOOLTIP_EVENTS - * - * @param event - * @param owner - * @param key - * the key for tooltip if this is "additional" tooltip, null for - * components "main tooltip" - */ - public void handleTooltipEvent(Event event, ComponentConnector owner, - Object key) { - tooltip.handleTooltipEvent(event, owner, key); - - } - private ConnectorMap connectorMap = GWT.create(ConnectorMap.class); protected String getUidlSecurityKey() { @@ -2328,34 +2351,6 @@ public class ApplicationConnection { } /** - * If component has several tooltips in addition to the one provided by - * {@link com.vaadin.ui.AbstractComponent}, component can register them with - * this method. - * <p> - * Component must also pipe events to - * {@link #handleTooltipEvent(Event, ComponentConnector, Object)} method. - * <p> - * This method can also be used to deregister tooltips by using null as - * tooltip - * - * @param paintable - * Paintable "owning" this tooltip - * @param key - * key assosiated with given tooltip. Can be any object. For - * example a related dom element. Same key must be given for - * {@link #handleTooltipEvent(Event, ComponentConnector, Object)} - * method. - * - * @param tooltip - * the TooltipInfo object containing details shown in tooltip, - * null if deregistering tooltip - */ - public void registerTooltip(ComponentConnector paintable, Object key, - TooltipInfo tooltip) { - connectorMap.registerTooltip(paintable, key, tooltip); - } - - /** * Gets the {@link ApplicationConfiguration} for the current application. * * @see ApplicationConfiguration @@ -2437,15 +2432,15 @@ public class ApplicationConnection { // connectorMap.unregisterConnector(p); } + /** + * Get VTooltip instance related to application connection + * + * @return VTooltip instance + */ public VTooltip getVTooltip() { return tooltip; } - @Deprecated - public void handleTooltipEvent(Event event, Widget owner, Object key) { - handleTooltipEvent(event, getConnectorMap().getConnector(owner), key); - } - /** * Method provided for backwards compatibility. Duties previously done by * this method is now handled by the state change event handler in @@ -2474,17 +2469,6 @@ public class ApplicationConnection { } @Deprecated - public void handleTooltipEvent(Event event, Widget owner) { - handleTooltipEvent(event, getConnectorMap().getConnector(owner)); - - } - - @Deprecated - public void registerTooltip(Widget owner, Object key, TooltipInfo info) { - registerTooltip(getConnectorMap().getConnector(owner), key, info); - } - - @Deprecated public boolean hasEventListeners(Widget widget, String eventIdentifier) { return hasEventListeners(getConnectorMap().getConnector(widget), eventIdentifier); diff --git a/src/com/vaadin/terminal/gwt/client/ComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ComponentConnector.java index 4e6a690a3c..95e9a4cf78 100644 --- a/src/com/vaadin/terminal/gwt/client/ComponentConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ComponentConnector.java @@ -4,6 +4,7 @@ package com.vaadin.terminal.gwt.client; +import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.ui.Widget; /** @@ -104,4 +105,14 @@ public interface ComponentConnector extends ServerConnector { */ public void setWidgetEnabled(boolean widgetEnabled); + /** + * Gets the tooltip info for the given element. + * + * @param element + * The element to lookup a tooltip for + * @return The tooltip for the element or null if no tooltip is defined for + * this element. + */ + public TooltipInfo getTooltipInfo(Element element); + } diff --git a/src/com/vaadin/terminal/gwt/client/ConnectorMap.java b/src/com/vaadin/terminal/gwt/client/ConnectorMap.java index efb50b5e00..8bc4a4aacf 100644 --- a/src/com/vaadin/terminal/gwt/client/ConnectorMap.java +++ b/src/com/vaadin/terminal/gwt/client/ConnectorMap.java @@ -200,49 +200,11 @@ public class ConnectorMap { return idToConnector.size(); } - /** - * FIXME: Should be moved to VAbstractPaintableWidget - * - * @param paintable - * @return - */ - @Deprecated - public TooltipInfo getTooltipInfo(ComponentConnector paintable, Object key) { - ComponentDetail componentDetail = getComponentDetail(paintable); - if (componentDetail == null) { - return null; - } - return componentDetail.getTooltipInfo(key); - } - - @Deprecated - public TooltipInfo getWidgetTooltipInfo(Widget widget, Object key) { - ComponentConnector connector = getConnector(widget); - if (connector == null) { - return null; - } - return getTooltipInfo(connector, key); - } - public Collection<? extends ServerConnector> getConnectors() { return Collections.unmodifiableCollection(idToConnector.values()); } /** - * FIXME: Should not be here - * - * @param componentConnector - * @return - */ - @Deprecated - public void registerTooltip(ComponentConnector componentConnector, - Object key, TooltipInfo tooltip) { - getComponentDetail(componentConnector).putAdditionalTooltip(key, - tooltip); - - } - - /** * Tests if the widget is the root widget of a {@link ComponentConnector}. * * @param widget diff --git a/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java b/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java index bd62a759cb..f3a3aa3e83 100644 --- a/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java +++ b/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java @@ -238,8 +238,8 @@ public class JavaScriptConnectorHelper { return connector; } - return ConnectorMap.get(connector.getConnection()) - .getConnector(connectorId); + return ConnectorMap.get(connector.getConnection()).getConnector( + connectorId); } private void fireRpc(String iface, String method, diff --git a/src/com/vaadin/terminal/gwt/client/ResourceLoader.java b/src/com/vaadin/terminal/gwt/client/ResourceLoader.java new file mode 100644 index 0000000000..8c481e0356 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ResourceLoader.java @@ -0,0 +1,529 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.google.gwt.core.client.Duration; +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.RepeatingCommand; +import com.google.gwt.dom.client.AnchorElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.LinkElement; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.dom.client.ObjectElement; +import com.google.gwt.dom.client.ScriptElement; +import com.google.gwt.user.client.Timer; + +/** + * ResourceLoader lets you dynamically include external scripts and styles on + * the page and lets you know when the resource has been loaded. + * + * You can also preload resources, allowing them to get cached by the browser + * without being evaluated. This enables downloading multiple resources at once + * while still controlling in which order e.g. scripts are executed. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + */ +public class ResourceLoader { + /** + * Event fired when a resource has been loaded. + */ + public static class ResourceLoadEvent { + private ResourceLoader loader; + private String resourceUrl; + private final boolean preload; + + /** + * Creates a new event. + * + * @param loader + * the resource loader that has loaded the resource + * @param resourceUrl + * the url of the loaded resource + * @param preload + * true if the resource has only been preloaded, false if + * it's fully loaded + */ + public ResourceLoadEvent(ResourceLoader loader, String resourceUrl, + boolean preload) { + this.loader = loader; + this.resourceUrl = resourceUrl; + this.preload = preload; + } + + /** + * Gets the resource loader that has fired this event + * + * @return the resource loader + */ + public ResourceLoader getResourceLoader() { + return loader; + } + + /** + * Gets the absolute url of the loaded resource. + * + * @return the absolute url of the loaded resource + */ + public String getResourceUrl() { + return resourceUrl; + } + + /** + * Returns true if the resource has been preloaded, false if it's fully + * loaded + * + * @see ResourceLoader#preloadResource(String, ResourceLoadListener) + * + * @return true if the resource has been preloaded, false if it's fully + * loaded + */ + public boolean isPreload() { + return preload; + } + } + + /** + * Event listener that gets notified when a resource has been loaded + */ + public interface ResourceLoadListener { + /** + * Notifies this ResourceLoadListener that a resource has been loaded. + * Some browsers do not support any way of detecting load errors. In + * these cases, onLoad will be called regardless of the status. + * + * @see ResourceLoadEvent + * + * @param event + * a resource load event with information about the loaded + * resource + */ + public void onLoad(ResourceLoadEvent event); + + /** + * Notifies this ResourceLoadListener that a resource could not be + * loaded, e.g. because the file could not be found or because the + * server did not respond. Some browsers do not support any way of + * detecting load errors. In these cases, onLoad will be called + * regardless of the status. + * + * @see ResourceLoadEvent + * + * @param event + * a resource load event with information about the resource + * that could not be loaded. + */ + public void onError(ResourceLoadEvent event); + } + + private static final ResourceLoader INSTANCE = GWT + .create(ResourceLoader.class); + + private ApplicationConnection connection; + + private final Set<String> loadedResources = new HashSet<String>(); + private final Set<String> preloadedResources = new HashSet<String>(); + + private final Map<String, Collection<ResourceLoadListener>> loadListeners = new HashMap<String, Collection<ResourceLoadListener>>(); + private final Map<String, Collection<ResourceLoadListener>> preloadListeners = new HashMap<String, Collection<ResourceLoadListener>>(); + + private final Element head; + + /** + * Creates a new resource loader. You should generally not create you own + * resource loader, but instead use {@link ResourceLoader#get()} to get an + * instance. + */ + protected ResourceLoader() { + Document document = Document.get(); + head = document.getElementsByTagName("head").getItem(0); + + // detect already loaded scripts and stylesheets + NodeList<Element> scripts = document.getElementsByTagName("script"); + for (int i = 0; i < scripts.getLength(); i++) { + ScriptElement element = ScriptElement.as(scripts.getItem(i)); + String src = element.getSrc(); + if (src != null && src.length() != 0) { + loadedResources.add(src); + } + } + + NodeList<Element> links = document.getElementsByTagName("link"); + for (int i = 0; i < links.getLength(); i++) { + LinkElement linkElement = LinkElement.as(links.getItem(i)); + String rel = linkElement.getRel(); + String href = linkElement.getHref(); + if ("stylesheet".equalsIgnoreCase(rel) && href != null + && href.length() != 0) { + loadedResources.add(href); + } + } + } + + /** + * Returns the default ResourceLoader + * + * @return the default ResourceLoader + */ + public static ResourceLoader get() { + return INSTANCE; + } + + /** + * Load a script and notify a listener when the script is loaded. Calling + * this method when the script is currently loading or already loaded + * doesn't cause the script to be loaded again, but the listener will still + * be notified when appropriate. + * + * + * @param scriptUrl + * the url of the script to load + * @param resourceLoadListener + * the listener that will get notified when the script is loaded + */ + public void loadScript(final String scriptUrl, + final ResourceLoadListener resourceLoadListener) { + final String url = getAbsoluteUrl(scriptUrl); + ResourceLoadEvent event = new ResourceLoadEvent(this, url, false); + if (loadedResources.contains(url)) { + if (resourceLoadListener != null) { + resourceLoadListener.onLoad(event); + } + return; + } + + if (preloadListeners.containsKey(url)) { + // Preload going on, continue when preloaded + preloadResource(url, new ResourceLoadListener() { + public void onLoad(ResourceLoadEvent event) { + loadScript(url, resourceLoadListener); + } + + public void onError(ResourceLoadEvent event) { + // Preload failed -> signal error to own listener + if (resourceLoadListener != null) { + resourceLoadListener.onError(event); + } + } + }); + return; + } + + if (addListener(url, resourceLoadListener, loadListeners)) { + ScriptElement scriptTag = Document.get().createScriptElement(); + scriptTag.setSrc(url); + scriptTag.setType("text/javascript"); + addOnloadHandler(scriptTag, new ResourceLoadListener() { + public void onLoad(ResourceLoadEvent event) { + fireLoad(event); + } + + public void onError(ResourceLoadEvent event) { + fireError(event); + } + }, event); + head.appendChild(scriptTag); + } + } + + private static String getAbsoluteUrl(String url) { + AnchorElement a = Document.get().createAnchorElement(); + a.setHref(url); + return a.getHref(); + } + + /** + * Download a resource and notify a listener when the resource is loaded + * without attempting to interpret the resource. When a resource has been + * preloaded, it will be present in the browser's cache (provided the HTTP + * headers allow caching), making a subsequent load operation complete + * without having to wait for the resource to be downloaded again. + * + * Calling this method when the resource is currently loading, currently + * preloading, already preloaded or already loaded doesn't cause the + * resource to be preloaded again, but the listener will still be notified + * when appropriate. + * + * @param url + * the url of the resource to preload + * @param resourceLoadListener + * the listener that will get notified when the resource is + * preloaded + */ + public void preloadResource(String url, + ResourceLoadListener resourceLoadListener) { + url = getAbsoluteUrl(url); + ResourceLoadEvent event = new ResourceLoadEvent(this, url, true); + if (loadedResources.contains(url) || preloadedResources.contains(url)) { + // Already loaded or preloaded -> just fire listener + if (resourceLoadListener != null) { + resourceLoadListener.onLoad(event); + } + return; + } + + if (addListener(url, resourceLoadListener, preloadListeners) + && !loadListeners.containsKey(url)) { + // Inject loader element if this is the first time this is preloaded + // AND the resources isn't already being loaded in the normal way + + Element element = getPreloadElement(url); + addOnloadHandler(element, new ResourceLoadListener() { + public void onLoad(ResourceLoadEvent event) { + fireLoad(event); + } + + public void onError(ResourceLoadEvent event) { + fireError(event); + } + }, event); + + // TODO Remove object when loaded (without causing spinner in FF) + Document.get().getBody().appendChild(element); + } + } + + private static Element getPreloadElement(String url) { + if (BrowserInfo.get().isIE()) { + ScriptElement element = Document.get().createScriptElement(); + element.setSrc(url); + element.setType("text/cache"); + return element; + } else { + ObjectElement element = Document.get().createObjectElement(); + element.setData(url); + element.setType("text/plain"); + element.setHeight("0px"); + element.setWidth("0px"); + return element; + } + } + + private native void addOnloadHandler(Element element, + ResourceLoadListener listener, ResourceLoadEvent event) + /*-{ + element.onload = $entry(function() { + element.onload = null; + element.onerror = null; + element.onreadystatechange = null; + listener.@com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadListener::onLoad(Lcom/vaadin/terminal/gwt/client/ResourceLoader$ResourceLoadEvent;)(event); + }); + element.onerror = $entry(function() { + element.onload = null; + element.onerror = null; + element.onreadystatechange = null; + listener.@com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadListener::onError(Lcom/vaadin/terminal/gwt/client/ResourceLoader$ResourceLoadEvent;)(event); + }); + element.onreadystatechange = function() { + if ("loaded" === element.readyState || "complete" === element.readyState ) { + element.onload(arguments[0]); + } + }; + }-*/; + + /** + * Load a stylesheet and notify a listener when the stylesheet is loaded. + * Calling this method when the stylesheet is currently loading or already + * loaded doesn't cause the stylesheet to be loaded again, but the listener + * will still be notified when appropriate. + * + * @param stylesheetUrl + * the url of the stylesheet to load + * @param resourceLoadListener + * the listener that will get notified when the stylesheet is + * loaded + */ + public void loadStylesheet(final String stylesheetUrl, + final ResourceLoadListener resourceLoadListener) { + final String url = getAbsoluteUrl(stylesheetUrl); + final ResourceLoadEvent event = new ResourceLoadEvent(this, url, false); + if (loadedResources.contains(url)) { + if (resourceLoadListener != null) { + resourceLoadListener.onLoad(event); + } + return; + } + + if (preloadListeners.containsKey(url)) { + // Preload going on, continue when preloaded + preloadResource(url, new ResourceLoadListener() { + public void onLoad(ResourceLoadEvent event) { + loadStylesheet(url, resourceLoadListener); + } + + public void onError(ResourceLoadEvent event) { + // Preload failed -> signal error to own listener + if (resourceLoadListener != null) { + resourceLoadListener.onError(event); + } + } + }); + return; + } + + if (addListener(url, resourceLoadListener, loadListeners)) { + LinkElement linkElement = Document.get().createLinkElement(); + linkElement.setRel("stylesheet"); + linkElement.setType("text/css"); + linkElement.setHref(url); + + if (BrowserInfo.get().isSafari()) { + // Safari doesn't fire any events for link elements + // See http://www.phpied.com/when-is-a-stylesheet-really-loaded/ + Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() { + private final Duration duration = new Duration(); + + public boolean execute() { + int styleSheetLength = getStyleSheetLength(url); + if (getStyleSheetLength(url) > 0) { + fireLoad(event); + return false; // Stop repeating + } else if (styleSheetLength == 0) { + // "Loaded" empty sheet -> most likely 404 error + fireError(event); + return true; + } else if (duration.elapsedMillis() > 60 * 1000) { + fireError(event); + return false; + } else { + return true; // Continue repeating + } + } + }, 10); + } else { + addOnloadHandler(linkElement, new ResourceLoadListener() { + public void onLoad(ResourceLoadEvent event) { + // Chrome && IE fires load for errors, must check + // stylesheet data + if (BrowserInfo.get().isChrome() + || BrowserInfo.get().isIE()) { + int styleSheetLength = getStyleSheetLength(url); + // Error if there's an empty stylesheet + if (styleSheetLength == 0) { + fireError(event); + return; + } + } + fireLoad(event); + } + + public void onError(ResourceLoadEvent event) { + fireError(event); + } + }, event); + if (BrowserInfo.get().isOpera()) { + // Opera onerror never fired, assume error if no onload in x + // seconds + new Timer() { + @Override + public void run() { + if (!loadedResources.contains(url)) { + fireError(event); + } + } + }.schedule(5 * 1000); + } + } + + head.appendChild(linkElement); + } + } + + private static native int getStyleSheetLength(String url) + /*-{ + for(var i = 0; i < $doc.styleSheets.length; i++) { + if ($doc.styleSheets[i].href === url) { + var sheet = $doc.styleSheets[i]; + try { + var rules = sheet.cssRules + if (rules === undefined) { + rules = sheet.rules; + } + + if (rules === null) { + // Style sheet loaded, but can't access length because of XSS -> assume there's something there + return 1; + } + + // Return length so we can distinguish 0 (probably 404 error) from normal case. + return rules.length; + } catch (err) { + return 1; + } + } + } + // No matching stylesheet found -> not yet loaded + return -1; + }-*/; + + private static boolean addListener(String url, + ResourceLoadListener listener, + Map<String, Collection<ResourceLoadListener>> listenerMap) { + Collection<ResourceLoadListener> listeners = listenerMap.get(url); + if (listeners == null) { + listeners = new HashSet<ResourceLoader.ResourceLoadListener>(); + listeners.add(listener); + listenerMap.put(url, listeners); + return true; + } else { + listeners.add(listener); + return false; + } + } + + private void fireError(ResourceLoadEvent event) { + String resource = event.getResourceUrl(); + + Collection<ResourceLoadListener> listeners; + if (event.isPreload()) { + // Also fire error for load listeners + fireError(new ResourceLoadEvent(this, resource, false)); + listeners = preloadListeners.remove(resource); + } else { + listeners = loadListeners.remove(resource); + } + if (listeners != null && !listeners.isEmpty()) { + for (ResourceLoadListener listener : listeners) { + if (listener != null) { + listener.onError(event); + } + } + } + } + + private void fireLoad(ResourceLoadEvent event) { + String resource = event.getResourceUrl(); + Collection<ResourceLoadListener> listeners; + if (event.isPreload()) { + preloadedResources.add(resource); + listeners = preloadListeners.remove(resource); + } else { + if (preloadListeners.containsKey(resource)) { + // Also fire preload events for potential listeners + fireLoad(new ResourceLoadEvent(this, resource, true)); + } + preloadedResources.remove(resource); + loadedResources.add(resource); + listeners = loadListeners.remove(resource); + } + if (listeners != null && !listeners.isEmpty()) { + for (ResourceLoadListener listener : listeners) { + if (listener != null) { + listener.onLoad(event); + } + } + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/TooltipInfo.java b/src/com/vaadin/terminal/gwt/client/TooltipInfo.java index fb33a56c56..1ad1ea43cd 100644 --- a/src/com/vaadin/terminal/gwt/client/TooltipInfo.java +++ b/src/com/vaadin/terminal/gwt/client/TooltipInfo.java @@ -16,6 +16,11 @@ public class TooltipInfo { setTitle(tooltip); } + public TooltipInfo(String tooltip, String errorMessage) { + setTitle(tooltip); + setErrorMessage(errorMessage); + } + public String getTitle() { return title; } @@ -32,4 +37,18 @@ public class TooltipInfo { errorMessageHtml = errorMessage; } + /** + * Checks is a message has been defined for the tooltip. + * + * @return true if title or error message is present, false if both are + * empty + */ + public boolean hasMessage() { + return (title != null && !title.isEmpty()) + || (errorMessageHtml != null && errorMessageHtml.isEmpty()); + } + + public boolean equals(TooltipInfo other) { + return (other != null && other.title == title && other.errorMessageHtml == errorMessageHtml); + } } diff --git a/src/com/vaadin/terminal/gwt/client/VCaption.java b/src/com/vaadin/terminal/gwt/client/VCaption.java index 6f3fcf2c3a..2f7ba87870 100644 --- a/src/com/vaadin/terminal/gwt/client/VCaption.java +++ b/src/com/vaadin/terminal/gwt/client/VCaption.java @@ -35,6 +35,8 @@ public class VCaption extends HTML { ICON, CAPTION, REQUIRED, ERROR } + private TooltipInfo tooltipInfo = null; + /** * Creates a caption that is not linked to a {@link ComponentConnector}. * @@ -74,8 +76,6 @@ public class VCaption extends HTML { } setStyleName(CLASSNAME); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } /** @@ -345,9 +345,6 @@ public class VCaption extends HTML { public void onBrowserEvent(Event event) { super.onBrowserEvent(event); final Element target = DOM.eventGetTarget(event); - if (client != null && owner != null && target != getElement()) { - client.handleTooltipEvent(event, owner); - } if (DOM.eventGetType(event) == Event.ONLOAD && icon.getElement() == target) { @@ -555,6 +552,26 @@ public class VCaption extends HTML { } } + /** + * Sets the tooltip that should be shown for the caption + * + * @param tooltipInfo + * The tooltip that should be shown or null if no tooltip should + * be shown + */ + public void setTooltipInfo(TooltipInfo tooltipInfo) { + this.tooltipInfo = tooltipInfo; + } + + /** + * Returns the tooltip that should be shown for the caption + * + * @return The tooltip to show or null if no tooltip should be shown + */ + public TooltipInfo getTooltipInfo() { + return tooltipInfo; + } + protected Element getTextElement() { return captionText; } diff --git a/src/com/vaadin/terminal/gwt/client/VTooltip.java b/src/com/vaadin/terminal/gwt/client/VTooltip.java index 70f4a0de0a..7fd3a3238b 100644 --- a/src/com/vaadin/terminal/gwt/client/VTooltip.java +++ b/src/com/vaadin/terminal/gwt/client/VTooltip.java @@ -3,12 +3,19 @@ */ package com.vaadin.terminal.gwt.client; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.dom.client.MouseMoveEvent; +import com.google.gwt.event.dom.client.MouseMoveHandler; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ui.VOverlay; /** @@ -27,15 +34,12 @@ public class VTooltip extends VOverlay { private static final int QUICK_OPEN_DELAY = 100; VErrorMessage em = new VErrorMessage(); Element description = DOM.createDiv(); - private ComponentConnector tooltipOwner; private boolean closing = false; private boolean opening = false; private ApplicationConnection ac; // Open next tooltip faster. Disabled after 2 sec of showTooltip-silence. private boolean justClosed = false; - // If this is "additional" tooltip, this field contains the key for it - private Object tooltipKey; public VTooltip(ApplicationConnection client) { super(false, false, true); @@ -115,51 +119,30 @@ public class VTooltip extends VOverlay { } } - public void showTooltip(ComponentConnector owner, Event event, Object key) { - if (closing && tooltipOwner == owner && tooltipKey == key) { - // return to same tooltip, cancel closing - closeTimer.cancel(); - closing = false; - justClosedTimer.cancel(); - justClosed = false; - return; - } + private void showTooltip() { - if (closing) { + // Close current tooltip + if (isShowing()) { closeNow(); } - updatePosition(event); - - if (opening) { - showTimer.cancel(); - } - tooltipOwner = owner; - tooltipKey = key; - // Schedule timer for showing the tooltip according to if it was // recently closed or not. - if (justClosed) { - showTimer.schedule(QUICK_OPEN_DELAY); - } else { - showTimer.schedule(OPEN_DELAY); - } + int timeout = justClosed ? QUICK_OPEN_DELAY : OPEN_DELAY; + showTimer.schedule(timeout); opening = true; } private void closeNow() { - if (closing) { - hide(); - tooltipOwner = null; - setWidth(""); - closing = false; - } + hide(); + setWidth(""); + closing = false; } private Timer showTimer = new Timer() { @Override public void run() { - TooltipInfo info = ac.getTooltipTitleInfo(tooltipOwner, tooltipKey); + TooltipInfo info = tooltipEventHandler.getTooltipInfo(); if (null != info) { show(info); } @@ -187,7 +170,6 @@ public class VTooltip extends VOverlay { if (opening) { showTimer.cancel(); opening = false; - tooltipOwner = null; } if (!isAttached()) { return; @@ -209,24 +191,6 @@ public class VTooltip extends VOverlay { public void updatePosition(Event event) { tooltipEventMouseX = DOM.eventGetClientX(event); tooltipEventMouseY = DOM.eventGetClientY(event); - - } - - public void handleTooltipEvent(Event event, ComponentConnector owner, - Object key) { - final int type = DOM.eventGetType(event); - if ((VTooltip.TOOLTIP_EVENTS & type) == type) { - if (type == Event.ONMOUSEOVER) { - showTooltip(owner, event, key); - } else if (type == Event.ONMOUSEMOVE) { - updatePosition(event); - } else { - hideTooltip(); - } - } else { - // non-tooltip event, hide tooltip - hideTooltip(); - } } @Override @@ -235,17 +199,149 @@ public class VTooltip extends VOverlay { // cancel closing event if tooltip is mouseovered; the user might want // to scroll of cut&paste - switch (type) { - case Event.ONMOUSEOVER: + if (type == Event.ONMOUSEOVER) { + // Cancel closing so tooltip stays open and user can copy paste the + // tooltip closeTimer.cancel(); closing = false; - break; - case Event.ONMOUSEOUT: + } + } + + /** + * Replace current open tooltip with new content + */ + public void replaceCurrentTooltip() { + if (closing) { + closeTimer.cancel(); + closeNow(); + } + + TooltipInfo info = tooltipEventHandler.getTooltipInfo(); + if (null != info) { + show(info); + } + opening = false; + } + + private class TooltipEventHandler implements MouseMoveHandler, + ClickHandler, KeyDownHandler { + + /** + * Current element hovered + */ + private com.google.gwt.dom.client.Element currentElement = null; + + /** + * Current tooltip active + */ + private TooltipInfo currentTooltipInfo = null; + + /** + * Get current active tooltip information + * + * @return Current active tooltip information or null + */ + public TooltipInfo getTooltipInfo() { + return currentTooltipInfo; + } + + /** + * Locate connector and it's tooltip for given element + * + * @param element + * Element used in search + * @return true if connector and tooltip found + */ + private boolean resolveConnector(Element element) { + + ComponentConnector connector = Util.getConnectorForElement(ac, ac + .getRootConnector().getWidget(), element); + + // Try to find first connector with proper tooltip info + TooltipInfo info = null; + while (connector != null) { + + info = connector.getTooltipInfo(element); + + if (info != null && info.hasMessage()) { + break; + } + + if (!(connector.getParent() instanceof ComponentConnector)) { + connector = null; + info = null; + break; + } + connector = (ComponentConnector) connector.getParent(); + } + + if (connector != null && info != null) { + currentTooltipInfo = info; + return true; + } + + return false; + } + + /** + * Handle hide event + * + * @param event + * Event causing hide + */ + private void handleHideEvent() { hideTooltip(); - break; - default: - // NOP + currentTooltipInfo = null; + } + + public void onMouseMove(MouseMoveEvent mme) { + Event event = Event.as(mme.getNativeEvent()); + com.google.gwt.dom.client.Element element = Element.as(event + .getEventTarget()); + + // We can ignore move event if it's handled by move or over already + if (currentElement == element) { + return; + } + currentElement = element; + + boolean connectorAndTooltipFound = resolveConnector((com.google.gwt.user.client.Element) element); + if (!connectorAndTooltipFound) { + if (isShowing()) { + handleHideEvent(); + } else { + currentTooltipInfo = null; + } + } else { + updatePosition(event); + if (isShowing()) { + replaceCurrentTooltip(); + } else { + showTooltip(); + } + } + } + + public void onClick(ClickEvent event) { + handleHideEvent(); + } + + public void onKeyDown(KeyDownEvent event) { + handleHideEvent(); } } + private final TooltipEventHandler tooltipEventHandler = new TooltipEventHandler(); + + /** + * Connects DOM handlers to widget that are needed for tooltip presentation. + * + * @param widget + * Widget which DOM handlers are connected + */ + public void connectHandlersToWidget(Widget widget) { + widget.addDomHandler(tooltipEventHandler, MouseMoveEvent.getType()); + widget.addDomHandler(tooltipEventHandler, ClickEvent.getType()); + widget.addDomHandler(tooltipEventHandler, KeyDownEvent.getType()); + } } diff --git a/src/com/vaadin/terminal/gwt/client/WidgetLoader.java b/src/com/vaadin/terminal/gwt/client/WidgetLoader.java index 16e99716a0..491e569411 100644 --- a/src/com/vaadin/terminal/gwt/client/WidgetLoader.java +++ b/src/com/vaadin/terminal/gwt/client/WidgetLoader.java @@ -9,12 +9,12 @@ import com.google.gwt.core.client.RunAsyncCallback; abstract class WidgetLoader implements RunAsyncCallback { public void onFailure(Throwable reason) { - ApplicationConfiguration.endWidgetLoading(); + ApplicationConfiguration.endDependencyLoading(); } public void onSuccess() { addInstantiator(); - ApplicationConfiguration.endWidgetLoading(); + ApplicationConfiguration.endDependencyLoading(); } abstract void addInstantiator(); diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java index f0b9d518ca..6105c545f6 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java @@ -3,8 +3,11 @@ */ package com.vaadin.terminal.gwt.client.ui; +import java.util.ArrayList; +import java.util.List; import java.util.Set; +import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.ui.Focusable; import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; @@ -21,6 +24,7 @@ import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.datefield.PopupDateFieldConnector; import com.vaadin.terminal.gwt.client.ui.root.RootConnector; public abstract class AbstractComponentConnector extends AbstractConnector @@ -32,11 +36,27 @@ public abstract class AbstractComponentConnector extends AbstractConnector private String lastKnownHeight = ""; /** + * The style names from getState().getStyles() which are currently applied + * to the widget. + */ + protected List<String> styleNames = new ArrayList<String>(); + + /** * Default constructor */ public AbstractComponentConnector() { } + @Override + protected void init() { + super.init(); + + getConnection().getVTooltip().connectHandlersToWidget(getWidget()); + + // Set v-connector style names for the widget + getWidget().setStyleName("v-connector", true); + } + /** * Creates and returns the widget for this VPaintableWidget. This method * should only be called once when initializing the paintable. @@ -96,18 +116,7 @@ public abstract class AbstractComponentConnector extends AbstractConnector super.onStateChanged(stateChangeEvent); // Style names - String styleName = getStyleNames(getWidget().getStylePrimaryName()); - getWidget().setStyleName(styleName); - - // Update tooltip - TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(this, null); - if (getState().hasDescription()) { - tooltipInfo.setTitle(getState().getDescription()); - } else { - tooltipInfo.setTitle(null); - } - // add error info to tooltip if present - tooltipInfo.setErrorMessage(getState().getErrorMessage()); + updateWidgetStyleNames(); // Set captions if (delegateCaptionHandling()) { @@ -130,12 +139,14 @@ public abstract class AbstractComponentConnector extends AbstractConnector } public void setWidgetEnabled(boolean widgetEnabled) { + // add or remove v-disabled style name from the widget + setWidgetStyleName(ApplicationConnection.DISABLED_CLASSNAME, + !widgetEnabled); + if (getWidget() instanceof HasEnabled) { // set widget specific enabled state ((HasEnabled) getWidget()).setEnabled(widgetEnabled); - // add or remove v-disabled style name from the widget - getWidget().setStyleName(ApplicationConnection.DISABLED_CLASSNAME, - !widgetEnabled); + // make sure the caption has or has not v-disabled style if (delegateCaptionHandling()) { ServerConnector parent = getParent(); @@ -213,58 +224,112 @@ public abstract class AbstractComponentConnector extends AbstractConnector } /** - * Generates the style name for the widget based on the given primary style - * name and the shared state. + * Updates the user defined, read-only and error style names for the widget + * based the shared state. User defined style names are prefixed with the + * primary style name of the widget returned by {@link #getWidget()} * <p> * This method can be overridden to provide additional style names for the - * component + * component, for example see + * {@link AbstractFieldConnector#updateWidgetStyleNames()} * </p> - * - * @param primaryStyleName - * The primary style name to use when generating the final style - * names - * @return The style names, settable using - * {@link Widget#setStyleName(String)} */ - protected String getStyleNames(String primaryStyleName) { + protected void updateWidgetStyleNames() { ComponentState state = getState(); - StringBuilder styleBuf = new StringBuilder(); - styleBuf.append(primaryStyleName); - styleBuf.append(" v-connector"); + String primaryStyleName = getWidget().getStylePrimaryName(); - // Uses connector methods to enable connectors to take hierarchy or - // multiple state variables into account - if (!isEnabled()) { - styleBuf.append(" "); - styleBuf.append(ApplicationConnection.DISABLED_CLASSNAME); - } - if (isReadOnly()) { - styleBuf.append(" "); - styleBuf.append("v-readonly"); - } + // should be in AbstractFieldConnector ? + // add / remove read-only style name + setWidgetStyleName("v-readonly", isReadOnly()); + + // add / remove error style name + setWidgetStyleNameWithPrefix(primaryStyleName, + ApplicationConnection.ERROR_CLASSNAME_EXT, + null != state.getErrorMessage()); - // add additional styles as css classes, prefixed with component default - // stylename + // add additional user defined style names as class names, prefixed with + // component default class name. remove nonexistent style names. if (state.hasStyles()) { - for (String style : state.getStyles()) { - styleBuf.append(" "); - styleBuf.append(primaryStyleName); - styleBuf.append("-"); - styleBuf.append(style); - styleBuf.append(" "); - styleBuf.append(style); + // add new style names + List<String> newStyles = new ArrayList<String>(); + newStyles.addAll(state.getStyles()); + newStyles.removeAll(styleNames); + for (String newStyle : newStyles) { + setWidgetStyleName(newStyle, true); + setWidgetStyleNameWithPrefix(primaryStyleName + "-", newStyle, + true); + } + // remove nonexistent style names + styleNames.removeAll(state.getStyles()); + for (String oldStyle : styleNames) { + setWidgetStyleName(oldStyle, false); + setWidgetStyleNameWithPrefix(primaryStyleName + "-", oldStyle, + false); } + styleNames.clear(); + styleNames.addAll(state.getStyles()); + } else { + // remove all old style names + for (String oldStyle : styleNames) { + setWidgetStyleName(oldStyle, false); + setWidgetStyleNameWithPrefix(primaryStyleName + "-", oldStyle, + false); + } + styleNames.clear(); } - // add error classname to components w/ error - if (null != state.getErrorMessage()) { - styleBuf.append(" "); - styleBuf.append(primaryStyleName); - styleBuf.append(ApplicationConnection.ERROR_CLASSNAME_EXT); - } + } + + /** + * This is used to add / remove state related style names from the widget. + * <p> + * Override this method for example if the style name given here should be + * updated in another widget in addition to the one returned by the + * {@link #getWidget()}. + * </p> + * + * @param styleName + * the style name to be added or removed + * @param add + * <code>true</code> to add the given style, <code>false</code> + * to remove it + */ + protected void setWidgetStyleName(String styleName, boolean add) { + getWidget().setStyleName(styleName, add); + } - return styleBuf.toString(); + /** + * This is used to add / remove state related prefixed style names from the + * widget. + * <p> + * Override this method if the prefixed style name given here should be + * updated in another widget in addition to the one returned by the + * <code>Connector</code>'s {@link #getWidget()}, or if the prefix should be + * different. For example see + * {@link PopupDateFieldConnector#setWidgetStyleNameWithPrefix(String, String, boolean)} + * </p> + * + * @param styleName + * the style name to be added or removed + * @param add + * <code>true</code> to add the given style, <code>false</code> + * to remove it + * @deprecated This will be removed once styles are no longer added with + * prefixes. + */ + @Deprecated + protected void setWidgetStyleNameWithPrefix(String prefix, + String styleName, boolean add) { + if (!styleName.startsWith("-")) { + if (!prefix.endsWith("-")) { + prefix += "-"; + } + } else { + if (prefix.endsWith("-")) { + styleName.replaceFirst("-", ""); + } + } + getWidget().setStyleName(prefix + styleName, add); } /* @@ -315,4 +380,16 @@ public abstract class AbstractComponentConnector extends AbstractConnector + ") has been unregistered. Widget was removed."); } } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ComponentConnector#getTooltipInfo(com. + * google.gwt.dom.client.Element) + */ + public TooltipInfo getTooltipInfo(Element element) { + return new TooltipInfo(getState().getDescription(), getState() + .getErrorMessage()); + } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractFieldConnector.java index 4be0f02c2a..5bff88c774 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/AbstractFieldConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractFieldConnector.java @@ -35,20 +35,15 @@ public abstract class AbstractFieldConnector extends AbstractComponentConnector } @Override - protected String getStyleNames(String primaryStyleName) { - String styleNames = super.getStyleNames(primaryStyleName); + protected void updateWidgetStyleNames() { + super.updateWidgetStyleNames(); - if (isModified()) { - // add modified classname to Fields - styleNames += " " + ApplicationConnection.MODIFIED_CLASSNAME; - } + // add / remove modified style name to Fields + setWidgetStyleName(ApplicationConnection.MODIFIED_CLASSNAME, + isModified()); - if (isRequired()) { - // add required classname to Fields - styleNames += " " + primaryStyleName - + ApplicationConnection.REQUIRED_CLASSNAME_EXT; - } - - return styleNames; + // add / remove error style name to Fields + setWidgetStyleNameWithPrefix(getWidget().getStylePrimaryName(), + ApplicationConnection.REQUIRED_CLASSNAME_EXT, isRequired()); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/UnknownComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/UnknownComponentConnector.java index 0cccec6481..83ac97458e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/UnknownComponentConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/UnknownComponentConnector.java @@ -4,7 +4,6 @@ package com.vaadin.terminal.gwt.client.ui; - public class UnknownComponentConnector extends AbstractComponentConnector { @Override 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 0cd8bc54f4..bb3d8e2985 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java +++ b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java @@ -18,7 +18,6 @@ import com.google.gwt.user.client.ui.FocusWidget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Icon; public class VButton extends FocusWidget implements ClickHandler { @@ -90,7 +89,6 @@ public class VButton extends FocusWidget implements ClickHandler { setTabIndex(0); sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS | Event.KEYEVENTS); - sinkEvents(VTooltip.TOOLTIP_EVENTS); setStyleName(CLASSNAME); @@ -128,9 +126,6 @@ public class VButton extends FocusWidget implements ClickHandler { * -onload event handler added (for icon handling) */ public void onBrowserEvent(Event event) { - if (client != null) { - client.handleTooltipEvent(event, this); - } if (DOM.eventGetType(event) == Event.ONLOAD) { Util.notifyParentOfSizeChange(this, true); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/checkbox/VCheckBox.java b/src/com/vaadin/terminal/gwt/client/ui/checkbox/VCheckBox.java index fd90796ea5..a6eec2de8a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/checkbox/VCheckBox.java +++ b/src/com/vaadin/terminal/gwt/client/ui/checkbox/VCheckBox.java @@ -31,7 +31,6 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements public VCheckBox() { setStyleName(CLASSNAME); - sinkEvents(VTooltip.TOOLTIP_EVENTS); Element el = DOM.getFirstChild(getElement()); while (el != null) { DOM.sinkEvents(el, @@ -53,9 +52,6 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements if (event.getTypeInt() == Event.ONLOAD) { Util.notifyParentOfSizeChange(this, true); } - if (client != null) { - client.handleTooltipEvent(event, this); - } } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java b/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java index 8c5d521445..9831001024 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java @@ -54,7 +54,6 @@ import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Field; import com.vaadin.terminal.gwt.client.ui.SubPartAware; import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; @@ -824,21 +823,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * The text box where the filter is written */ protected final TextBox tb = new TextBox() { - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.user.client.ui.TextBoxBase#onBrowserEvent(com.google - * .gwt.user.client.Event) - */ - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, VFilterSelect.this); - } - } // Overridden to avoid selecting text when text input is disabled @Override @@ -869,9 +853,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, VFilterSelect.this); - } /* * Prevent the keyboard focus from leaving the textfield by @@ -972,8 +953,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, } }); - tb.sinkEvents(VTooltip.TOOLTIP_EVENTS); - popupOpener.sinkEvents(VTooltip.TOOLTIP_EVENTS | Event.ONMOUSEDOWN); + popupOpener.sinkEvents(Event.ONMOUSEDOWN); panel.add(tb); panel.add(popupOpener); initWidget(panel); diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/AbstractDateFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/AbstractDateFieldConnector.java index b55f480bac..72555214fa 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/datefield/AbstractDateFieldConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/AbstractDateFieldConnector.java @@ -63,15 +63,17 @@ public class AbstractDateFieldConnector extends AbstractFieldConnector newResolution = VDateField.RESOLUTION_YEAR; } + // Remove old stylename that indicates current resolution + setWidgetStyleNameWithPrefix(VDateField.CLASSNAME, + VDateField.resolutionToString(getWidget().currentResolution), + false); + getWidget().currentResolution = newResolution; // Add stylename that indicates current resolution - getWidget() - .addStyleName( - VDateField.CLASSNAME - + "-" - + VDateField - .resolutionToString(getWidget().currentResolution)); + setWidgetStyleNameWithPrefix(VDateField.CLASSNAME, + VDateField.resolutionToString(getWidget().currentResolution), + true); final int year = uidl.getIntVariable("year"); final int month = (getWidget().currentResolution >= VDateField.RESOLUTION_MONTH) ? uidl diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/PopupDateFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/PopupDateFieldConnector.java index e169d83b48..dfe0b327ac 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/datefield/PopupDateFieldConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/PopupDateFieldConnector.java @@ -35,14 +35,6 @@ public class PopupDateFieldConnector extends TextualDateConnector { super.updateFromUIDL(uidl, client); - String popupStyleNames = getStyleNames(VPopupCalendar.POPUP_PRIMARY_STYLE_NAME); - popupStyleNames += " " - + VDateField.CLASSNAME - + "-" - + VPopupCalendar - .resolutionToString(getWidget().currentResolution); - getWidget().popup.setStyleName(popupStyleNames); - getWidget().calendar.setDateTimeService(getWidget() .getDateTimeService()); getWidget().calendar.setShowISOWeekNumbers(getWidget() @@ -114,4 +106,30 @@ public class PopupDateFieldConnector extends TextualDateConnector { public VPopupCalendar getWidget() { return (VPopupCalendar) super.getWidget(); } + + @Override + protected void setWidgetStyleName(String styleName, boolean add) { + super.setWidgetStyleName(styleName, add); + + // update the style change to popup calendar widget + getWidget().popup.setStyleName(styleName, add); + } + + @Override + protected void setWidgetStyleNameWithPrefix(String prefix, + String styleName, boolean add) { + super.setWidgetStyleNameWithPrefix(prefix, styleName, add); + + // update the style change to popup calendar widget with the correct + // prefix + if (!styleName.startsWith("-")) { + getWidget().popup.setStyleName( + VPopupCalendar.POPUP_PRIMARY_STYLE_NAME + "-" + styleName, + add); + } else { + getWidget().popup.setStyleName( + VPopupCalendar.POPUP_PRIMARY_STYLE_NAME + styleName, add); + } + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateField.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateField.java index d169b1b47e..614c4febdd 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateField.java @@ -6,11 +6,9 @@ package com.vaadin.terminal.gwt.client.ui.datefield; import java.util.Date; -import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.FlowPanel; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Field; public class VDateField extends FlowPanel implements Field { @@ -66,15 +64,6 @@ public class VDateField extends FlowPanel implements Field { public VDateField() { setStyleName(CLASSNAME); dts = new DateTimeService(); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, this); - } } /* diff --git a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java index 4c36e92bbb..b1fffc8355 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java +++ b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java @@ -29,7 +29,6 @@ import com.vaadin.terminal.gwt.client.LayoutManager; import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ValueMap; import com.vaadin.terminal.gwt.client.ui.customcomponent.VCustomComponent; import com.vaadin.terminal.gwt.client.ui.dd.DDUtil; @@ -64,7 +63,6 @@ public class VDragAndDropWrapper extends VCustomComponent implements public VDragAndDropWrapper() { super(); - sinkEvents(VTooltip.TOOLTIP_EVENTS); hookHtml5Events(getElement()); setStyleName(CLASSNAME); @@ -92,16 +90,6 @@ public class VDragAndDropWrapper extends VCustomComponent implements sinkEvents(Event.TOUCHEVENTS); } - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - - if (hasTooltip && client != null) { - // Override child tooltips if the wrapper has a tooltip defined - client.handleTooltipEvent(event, this); - } - } - /** * Starts a drag and drop operation from mousedown or touchstart event if * required conditions are met. diff --git a/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java index af3ad67db4..fe3549e7f2 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java @@ -54,6 +54,16 @@ public class EmbeddedConnector extends AbstractComponentConnector implements clickEventHandler.handleEventHandlerRegistration(); if (uidl.hasAttribute("type")) { + // remove old style name related to type + if (getWidget().type != null) { + getWidget().removeStyleName( + VEmbedded.CLASSNAME + "-" + getWidget().type); + } + // remove old style name related to mime type + if (getWidget().mimetype != null) { + getWidget().removeStyleName( + VEmbedded.CLASSNAME + "-" + getWidget().mimetype); + } getWidget().type = uidl.getStringAttribute("type"); if (getWidget().type.equals("image")) { getWidget().addStyleName(VEmbedded.CLASSNAME + "-image"); @@ -118,13 +128,25 @@ public class EmbeddedConnector extends AbstractComponentConnector implements VConsole.log("Unknown Embedded type '" + getWidget().type + "'"); } } else if (uidl.hasAttribute("mimetype")) { + // remove old style name related to type + if (getWidget().type != null) { + getWidget().removeStyleName( + VEmbedded.CLASSNAME + "-" + getWidget().type); + } + // remove old style name related to mime type + if (getWidget().mimetype != null) { + getWidget().removeStyleName( + VEmbedded.CLASSNAME + "-" + getWidget().mimetype); + } final String mime = uidl.getStringAttribute("mimetype"); if (mime.equals("application/x-shockwave-flash")) { + getWidget().mimetype = "flash"; // Handle embedding of Flash getWidget().addStyleName(VEmbedded.CLASSNAME + "-flash"); getWidget().setHTML(getWidget().createFlashEmbed(uidl)); } else if (mime.equals("image/svg+xml")) { + getWidget().mimetype = "svg"; getWidget().addStyleName(VEmbedded.CLASSNAME + "-svg"); String data; Map<String, String> parameters = VEmbedded.getParameters(uidl); diff --git a/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java index 203e7362f3..1d2a5a156a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java +++ b/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java @@ -26,6 +26,7 @@ public class VEmbedded extends HTML { protected Element browserElement; protected String type; + protected String mimetype; protected ApplicationConnection client; @@ -232,8 +233,6 @@ public class VEmbedded extends HTML { VConsole.log("Embeddable onload"); Util.notifyParentOfSizeChange(this, true); } - - client.handleTooltipEvent(event, this); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/formlayout/FormLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/formlayout/FormLayoutConnector.java index ca21947a6c..c08651ded1 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/formlayout/FormLayoutConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/formlayout/FormLayoutConnector.java @@ -3,9 +3,12 @@ */ package com.vaadin.terminal.gwt.client.ui.formlayout; +import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.TooltipInfo; +import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; import com.vaadin.terminal.gwt.client.ui.AbstractLayoutConnector; @@ -96,4 +99,36 @@ public class FormLayoutConnector extends AbstractLayoutConnector { return (VFormLayout) super.getWidget(); } + @Override + public TooltipInfo getTooltipInfo(Element element) { + TooltipInfo info = null; + + if (element != getWidget().getElement()) { + Object node = Util.findWidget( + (com.google.gwt.user.client.Element) element, + VFormLayout.Caption.class); + + if (node != null) { + VFormLayout.Caption caption = (VFormLayout.Caption) node; + info = caption.getOwner().getTooltipInfo(element); + } else { + + node = Util.findWidget( + (com.google.gwt.user.client.Element) element, + VFormLayout.ErrorFlag.class); + + if (node != null) { + VFormLayout.ErrorFlag flag = (VFormLayout.ErrorFlag) node; + info = flag.getOwner().getTooltipInfo(element); + } + } + } + + if (info == null) { + info = super.getTooltipInfo(element); + } + + return info; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/formlayout/VFormLayout.java b/src/com/vaadin/terminal/gwt/client/ui/formlayout/VFormLayout.java index 8a859c409c..1a161c529d 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/formlayout/VFormLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/formlayout/VFormLayout.java @@ -12,7 +12,6 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.SimplePanel; @@ -215,8 +214,6 @@ public class VFormLayout extends SimplePanel { public Caption(ComponentConnector component) { super(); owner = component; - - sinkEvents(VTooltip.TOOLTIP_EVENTS); } private void setStyles(String[] styles) { @@ -324,12 +321,6 @@ public class VFormLayout extends SimplePanel { public ComponentConnector getOwner() { return owner; } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - owner.getConnection().handleTooltipEvent(event, owner); - } } class ErrorFlag extends HTML { @@ -345,6 +336,10 @@ public class VFormLayout extends SimplePanel { this.owner = owner; } + public ComponentConnector getOwner() { + return owner; + } + public void updateError(String errorMessage, boolean hideErrors) { boolean showError = null != errorMessage; if (hideErrors) { @@ -366,13 +361,5 @@ public class VFormLayout extends SimplePanel { } } - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (owner != null) { - owner.getConnection().handleTooltipEvent(event, owner); - } - } - } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/label/ContentMode.java b/src/com/vaadin/terminal/gwt/client/ui/label/ContentMode.java index 4892c7e6bd..5e621681c3 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/label/ContentMode.java +++ b/src/com/vaadin/terminal/gwt/client/ui/label/ContentMode.java @@ -10,38 +10,36 @@ package com.vaadin.terminal.gwt.client.ui.label; */ public enum ContentMode { /** - * Content mode, where the label contains only plain text. The getValue() - * result is coded to XML when painting. + * Content mode, where the label contains only plain text. */ TEXT, /** - * Content mode, where the label contains preformatted text. + * Content mode, where the label contains pre formatted text. In this mode + * newlines are preserved when rendered on the screen. */ PREFORMATTED, /** - * Content mode, where the label contains XHTML. + * Content mode, where the label contains XHTML. Care should be taken to + * ensure */ XHTML, /** * Content mode, where the label contains well-formed or well-balanced XML. - * Each of the root elements must have their default namespace specified. + * This is handled in the same way as {@link #XHTML}. * - * @deprecated Use {@link #XHTML} + * @deprecated Use {@link #XHTML} instead */ @Deprecated XML, /** - * Content mode, where the label contains RAW output. Output is not required - * to comply to with XML. In Web Adapter output is inserted inside the - * resulting HTML document as-is. This is useful for some specific purposes - * where possibly broken HTML content needs to be shown, but in most cases - * XHTML mode should be preferred. + * Legacy content mode, where the label contains RAW output. This is handled + * in exactly the same way as {@link #XHTML}. * - * @deprecated Use {@link #XHTML}, {@link #TEXT} or {@link #PREFORMATTED}. + * @deprecated Use {@link #XHTML} instead */ @Deprecated RAW; diff --git a/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java b/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java index f47b8437b7..f0c170c6b0 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java @@ -28,7 +28,6 @@ public class VLabel extends HTML { public VLabel(String text) { super(text); setStyleName(CLASSNAME); - sinkEvents(VTooltip.TOOLTIP_EVENTS); } @Override @@ -39,9 +38,6 @@ public class VLabel extends HTML { event.stopPropagation(); return; } - if (connection != null) { - connection.handleTooltipEvent(event, this); - } } @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/link/VLink.java b/src/com/vaadin/terminal/gwt/client/ui/link/VLink.java index 68fe5d9292..bef7943e3f 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/link/VLink.java +++ b/src/com/vaadin/terminal/gwt/client/ui/link/VLink.java @@ -13,7 +13,6 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.HTML; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Icon; public class VLink extends HTML implements ClickHandler { @@ -51,7 +50,6 @@ public class VLink extends HTML implements ClickHandler { getElement().appendChild(anchor); anchor.appendChild(captionElement); addClickHandler(this); - sinkEvents(VTooltip.TOOLTIP_EVENTS); setStyleName(CLASSNAME); } @@ -101,9 +99,6 @@ public class VLink extends HTML implements ClickHandler { if (event.getTypeInt() == Event.ONLOAD) { Util.notifyParentOfSizeChange(this, true); } - if (client != null) { - client.handleTooltipEvent(event, this); - } if (target == captionElement || target == anchor || (icon != null && target == icon.getElement())) { super.onBrowserEvent(event); diff --git a/src/com/vaadin/terminal/gwt/client/ui/listselect/TooltipListBox.java b/src/com/vaadin/terminal/gwt/client/ui/listselect/TooltipListBox.java deleted file mode 100644 index abecd844da..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/listselect/TooltipListBox.java +++ /dev/null @@ -1,41 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui.listselect; - -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.ListBox; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.VTooltip; - -/** - * Extended ListBox to listen tooltip events and forward them to generic - * handler. - */ -public class TooltipListBox extends ListBox { - private ApplicationConnection client; - private Widget widget; - - public TooltipListBox(boolean isMultiselect) { - super(isMultiselect); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - public void setClient(ApplicationConnection client) { - this.client = client; - } - - public void setSelect(Widget widget) { - this.widget = widget; - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, widget); - } - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/listselect/VListSelect.java b/src/com/vaadin/terminal/gwt/client/ui/listselect/VListSelect.java index e338897841..1b1c2c44e3 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/listselect/VListSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/listselect/VListSelect.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.Iterator; import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.user.client.ui.ListBox; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.ui.optiongroup.VOptionGroupBase; @@ -17,23 +18,25 @@ public class VListSelect extends VOptionGroupBase { private static final int VISIBLE_COUNT = 10; - protected TooltipListBox select; + protected ListBox select; private int lastSelectedIndex = -1; public VListSelect() { - super(new TooltipListBox(true), CLASSNAME); - select = (TooltipListBox) optionsContainer; - select.setSelect(this); + super(new ListBox(true), CLASSNAME); + select = getOptionsContainer(); select.addChangeHandler(this); select.addClickHandler(this); select.setStyleName(CLASSNAME + "-select"); select.setVisibleItemCount(VISIBLE_COUNT); } + protected ListBox getOptionsContainer() { + return (ListBox) optionsContainer; + } + @Override protected void buildOptions(UIDL uidl) { - select.setClient(client); select.setMultipleSelect(isMultiselect()); select.setEnabled(!isDisabled() && !isReadonly()); select.clear(); @@ -99,7 +102,7 @@ public class VListSelect extends VOptionGroupBase { @Override protected void setTabIndex(int tabIndex) { - ((TooltipListBox) optionsContainer).setTabIndex(tabIndex); + getOptionsContainer().setTabIndex(tabIndex); } public void focus() { diff --git a/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java index e48483cb02..821fa5032c 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java @@ -33,10 +33,8 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.LayoutManager; -import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Icon; import com.vaadin.terminal.gwt.client.ui.SimpleFocusablePanel; import com.vaadin.terminal.gwt.client.ui.SubPartAware; @@ -140,8 +138,6 @@ public class VMenuBar extends SimpleFocusablePanel implements sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONLOAD); - - sinkEvents(VTooltip.TOOLTIP_EVENTS); } @Override @@ -340,15 +336,6 @@ public class VMenuBar extends SimpleFocusablePanel implements } } - // Handle tooltips - if (targetItem == null && client != null) { - // Handle root menubar tooltips - client.handleTooltipEvent(e, this); - } else if (targetItem != null) { - // Handle item tooltips - targetItem.onBrowserEvent(e); - } - if (targetItem != null) { switch (DOM.eventGetType(e)) { @@ -761,7 +748,6 @@ public class VMenuBar extends SimpleFocusablePanel implements setSelected(false); setStyleName(CLASSNAME + "-menuitem"); - sinkEvents(VTooltip.TOOLTIP_EVENTS); } public void setSelected(boolean selected) { @@ -917,22 +903,6 @@ public class VMenuBar extends SimpleFocusablePanel implements addStyleDependentName(itemStyle); } - if (uidl.hasAttribute(ATTRIBUTE_ITEM_DESCRIPTION)) { - String description = uidl - .getStringAttribute(ATTRIBUTE_ITEM_DESCRIPTION); - TooltipInfo info = new TooltipInfo(description); - - VMenuBar root = findRootMenu(); - client.registerTooltip(root, this, info); - } - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, findRootMenu(), this); - } } private VMenuBar findRootMenu() { 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 dd6e741126..e5a2e1253c 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java +++ b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java @@ -15,7 +15,6 @@ import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.MouseEventDetails; import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Icon; import com.vaadin.terminal.gwt.client.ui.button.ButtonServerRpc; @@ -54,7 +53,6 @@ public class VNativeButton extends Button implements ClickHandler { addClickHandler(this); - sinkEvents(VTooltip.TOOLTIP_EVENTS); sinkEvents(Event.ONMOUSEDOWN); sinkEvents(Event.ONMOUSEUP); } @@ -87,10 +85,6 @@ public class VNativeButton extends Button implements ClickHandler { } clickPending = false; } - - if (client != null) { - client.handleTooltipEvent(event, this); - } } @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativeselect/VNativeSelect.java b/src/com/vaadin/terminal/gwt/client/ui/nativeselect/VNativeSelect.java index 54f5e9aff5..cab23b1bc2 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/nativeselect/VNativeSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/nativeselect/VNativeSelect.java @@ -8,32 +8,34 @@ import java.util.ArrayList; import java.util.Iterator; import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.user.client.ui.ListBox; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.ui.Field; -import com.vaadin.terminal.gwt.client.ui.listselect.TooltipListBox; import com.vaadin.terminal.gwt.client.ui.optiongroup.VOptionGroupBase; public class VNativeSelect extends VOptionGroupBase implements Field { public static final String CLASSNAME = "v-select"; - protected TooltipListBox select; + protected ListBox select; private boolean firstValueIsTemporaryNullItem = false; public VNativeSelect() { - super(new TooltipListBox(false), CLASSNAME); - select = (TooltipListBox) optionsContainer; - select.setSelect(this); + super(new ListBox(false), CLASSNAME); + select = getOptionsContainer(); select.setVisibleItemCount(1); select.addChangeHandler(this); select.setStyleName(CLASSNAME + "-select"); } + protected ListBox getOptionsContainer() { + return (ListBox) optionsContainer; + } + @Override protected void buildOptions(UIDL uidl) { - select.setClient(client); select.setEnabled(!isDisabled() && !isReadonly()); select.clear(); firstValueIsTemporaryNullItem = false; @@ -103,7 +105,7 @@ public class VNativeSelect extends VOptionGroupBase implements Field { @Override protected void setTabIndex(int tabIndex) { - ((TooltipListBox) optionsContainer).setTabIndex(tabIndex); + getOptionsContainer().setTabIndex(tabIndex); } public void focus() { diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index 9a89553fd2..7c748df29d 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -48,6 +48,7 @@ public abstract class AbstractOrderedLayoutConnector extends @Override public void init() { + super.init(); rpc = RpcProxy.create(AbstractOrderedLayoutServerRpc.class, this); getLayoutManager().registerDependency(this, getWidget().spacingMeasureElement); diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java index d9096526f3..ea7ffda9db 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java @@ -46,6 +46,7 @@ public class PanelConnector extends AbstractComponentContainerConnector @Override public void init() { + super.init(); rpc = RpcProxy.create(PanelServerRpc.class, this); VPanel panel = getWidget(); LayoutManager layoutManager = getLayoutManager(); diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java index 6a06367acd..d56a82c46b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java @@ -167,10 +167,6 @@ public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner, client.updateVariable(id, "scrollTop", scrollTop, false); client.updateVariable(id, "scrollLeft", scrollLeft, false); } - } else if (captionNode.isOrHasChild(target)) { - if (client != null) { - client.handleTooltipEvent(event, this); - } } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java b/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java index da48975726..c8a0222ee2 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java +++ b/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java @@ -26,7 +26,6 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.VCaptionWrapper; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.VOverlay; import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea; @@ -73,7 +72,6 @@ public class VPopupView extends HTML { }); popup.setAnimationEnabled(true); - sinkEvents(VTooltip.TOOLTIP_EVENTS); } /** @@ -337,12 +335,4 @@ public class VPopupView extends HTML { }// class CustomPopup - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, this); - } - } - }// class VPopupView diff --git a/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java b/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java index 5c7ee7a784..e5282dc45e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java +++ b/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java @@ -18,7 +18,6 @@ import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.ContainerResizedListener; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Field; import com.vaadin.terminal.gwt.client.ui.SimpleFocusablePanel; import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; @@ -114,8 +113,6 @@ public class VSlider extends SimpleFocusablePanel implements Field, feedbackPopup.addStyleName(CLASSNAME + "-feedback"); feedbackPopup.setWidget(feedback); - - sinkEvents(VTooltip.TOOLTIP_EVENTS); } void setFeedbackValue(double value) { @@ -291,9 +288,6 @@ public class VSlider extends SimpleFocusablePanel implements Field, event.preventDefault(); // avoid simulated events event.stopPropagation(); } - if (client != null) { - client.handleTooltipEvent(event, this); - } } private void processMouseWheelEvent(final Event event) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java b/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java index ada0f2424f..ab867ea045 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java @@ -7,6 +7,7 @@ import java.util.Iterator; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.ui.Widget; @@ -17,6 +18,7 @@ import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.DirectionalManagedLayout; import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.ServerConnector; +import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; @@ -328,4 +330,27 @@ public class TableConnector extends AbstractComponentContainerConnector } } + @Override + public TooltipInfo getTooltipInfo(Element element) { + + TooltipInfo info = null; + + if (element != getWidget().getElement()) { + Object node = Util.findWidget( + (com.google.gwt.user.client.Element) element, + VScrollTableRow.class); + + if (node != null) { + VScrollTableRow row = (VScrollTableRow) node; + info = row.getTooltip(element); + } + } + + if (info == null) { + info = super.getTooltipInfo(element); + } + + return info; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java index c4a57f5c8b..b5f10e68ec 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java @@ -11,6 +11,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; import com.google.gwt.core.client.JavaScriptObject; @@ -4194,14 +4195,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private void unlinkRowAtActualIndex(int index) { final VScrollTableRow toBeRemoved = (VScrollTableRow) renderedRows .get(index); - // Unregister row tooltip - client.registerTooltip(VScrollTable.this, toBeRemoved.getElement(), - null); - for (int i = 0; i < toBeRemoved.getElement().getChildCount(); i++) { - // Unregister cell tooltips - Element td = toBeRemoved.getElement().getChild(i).cast(); - client.registerTooltip(VScrollTable.this, td, null); - } tBodyElement.removeChild(toBeRemoved.getElement()); orphan(toBeRemoved); renderedRows.remove(index); @@ -4423,6 +4416,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private Timer dragTouchTimeout; private int touchStartY; private int touchStartX; + private TooltipInfo tooltipInfo = null; + private Map<TableCellElement, TooltipInfo> cellToolTips = new HashMap<TableCellElement, TooltipInfo>(); private boolean isDragging = false; private VScrollTableRow(int rowKey) { @@ -4450,11 +4445,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets, String rowDescription = uidl.getStringAttribute("rowdescr"); if (rowDescription != null && !rowDescription.equals("")) { - TooltipInfo info = new TooltipInfo(rowDescription); - client.registerTooltip(VScrollTable.this, rowElement, info); + tooltipInfo = new TooltipInfo(rowDescription); } else { - // Remove possibly previously set tooltip - client.registerTooltip(VScrollTable.this, rowElement, null); + tooltipInfo = null; } tHead.getColumnAlignments(); @@ -4480,6 +4473,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } + public TooltipInfo getTooltipInfo() { + return tooltipInfo; + } + /** * Add a dummy row, used for measurements if Table is empty. */ @@ -4665,10 +4662,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (description != null && !description.equals("")) { TooltipInfo info = new TooltipInfo(description); - client.registerTooltip(VScrollTable.this, td, info); + cellToolTips.put(td, info); } else { - // Remove possibly previously set tooltip - client.registerTooltip(VScrollTable.this, td, null); + cellToolTips.remove(td); } td.appendChild(container); @@ -4776,39 +4772,22 @@ public class VScrollTable extends FlowPanel implements HasWidgets, return true; } - private void handleTooltips(final Event event, Element target) { + public TooltipInfo getTooltip( + com.google.gwt.dom.client.Element target) { + + TooltipInfo info = null; + if (target.hasTagName("TD")) { - // Table cell (td) - Element container = target.getFirstChildElement().cast(); - Element widget = container.getFirstChildElement().cast(); - - boolean containsWidget = false; - for (Widget w : childWidgets) { - if (widget == w.getElement()) { - containsWidget = true; - break; - } - } - if (!containsWidget) { - // Only text nodes has tooltips - if (ConnectorMap.get(client).getWidgetTooltipInfo( - VScrollTable.this, target) != null) { - // Cell has description, use it - client.handleTooltipEvent(event, VScrollTable.this, - target); - } else { - // Cell might have row description, use row - // description - client.handleTooltipEvent(event, VScrollTable.this, - target.getParentElement()); - } - } + TableCellElement td = (TableCellElement) target.cast(); + info = cellToolTips.get(td); + } - } else { - // Table row (tr) - client.handleTooltipEvent(event, VScrollTable.this, target); + if (info == null) { + info = tooltipInfo; } + + return info; } /** @@ -4953,9 +4932,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } boolean targetCellOrRowFound = targetTdOrTr != null; - if (targetCellOrRowFound) { - handleTooltips(event, targetTdOrTr); - } switch (type) { case Event.ONDBLCLICK: diff --git a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetConnector.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetConnector.java index 08d4679dc5..51a7801f91 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetConnector.java @@ -3,12 +3,13 @@ */ package com.vaadin.terminal.gwt.client.ui.tabsheet; -import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.ui.Connect; import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; import com.vaadin.terminal.gwt.client.ui.layout.MayScrollChildren; @@ -97,4 +98,29 @@ public class TabsheetConnector extends TabsheetBaseConnector implements } + @Override + public TooltipInfo getTooltipInfo(Element element) { + + TooltipInfo info = null; + + // Find a tooltip for the tab, if the element is a tab + if (element != getWidget().getElement()) { + Object node = Util.findWidget( + (com.google.gwt.user.client.Element) element, + VTabsheet.TabCaption.class); + + if (node != null) { + VTabsheet.TabCaption caption = (VTabsheet.TabCaption) node; + info = caption.getTooltipInfo(); + } + } + + // If not tab tooltip was found, use the default + if (info == null) { + info = super.getTooltipInfo(element); + } + + return info; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java index aba5a41f9a..24ea3b2d38 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java @@ -233,7 +233,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } } - private static class TabCaption extends VCaption { + public static class TabCaption extends VCaption { private boolean closable = false; private Element closeButton; @@ -248,16 +248,11 @@ public class VTabsheet extends VTabsheetBase implements Focusable, public boolean updateCaption(UIDL uidl) { if (uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION)) { - TooltipInfo tooltipInfo = new TooltipInfo(); - tooltipInfo - .setTitle(uidl - .getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION)); - tooltipInfo - .setErrorMessage(uidl - .getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ERROR_MESSAGE)); - client.registerTooltip(getTabsheet(), getElement(), tooltipInfo); + setTooltipInfo(new TooltipInfo( + uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION), + uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ERROR_MESSAGE))); } else { - client.registerTooltip(getTabsheet(), getElement(), null); + setTooltipInfo(null); } // TODO need to call this instead of super because the caption does @@ -292,7 +287,6 @@ public class VTabsheet extends VTabsheetBase implements Focusable, if (event.getTypeInt() == Event.ONLOAD) { getTabsheet().tabSizeMightHaveChanged(getTab()); } - client.handleTooltipEvent(event, getTabsheet(), getElement()); } public Tab getTab() { diff --git a/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java index aeae165f60..bd55c26a24 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java @@ -22,7 +22,6 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.EventId; import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Field; /** @@ -88,7 +87,6 @@ public class VTextField extends TextBoxBase implements Field, ChangeHandler, } addFocusHandler(this); addBlurHandler(this); - sinkEvents(VTooltip.TOOLTIP_EVENTS); } /* @@ -107,9 +105,6 @@ public class VTextField extends TextBoxBase implements Field, ChangeHandler, @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, this); - } if (listenTextChangeEvents && (event.getTypeInt() & TEXTCHANGE_EVENTS) == event diff --git a/src/com/vaadin/terminal/gwt/client/ui/tree/TreeConnector.java b/src/com/vaadin/terminal/gwt/client/ui/tree/TreeConnector.java index e4afa32143..3f96a61bf3 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/tree/TreeConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/tree/TreeConnector.java @@ -3,14 +3,18 @@ */ package com.vaadin.terminal.gwt.client.ui.tree; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; +import com.google.gwt.dom.client.Element; import com.vaadin.terminal.gwt.client.AbstractFieldState; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; import com.vaadin.terminal.gwt.client.ui.Connect; import com.vaadin.terminal.gwt.client.ui.tree.VTree.TreeNode; @@ -27,6 +31,8 @@ public class TreeConnector extends AbstractComponentConnector implements public static final String ATTRIBUTE_ACTION_CAPTION = "caption"; public static final String ATTRIBUTE_ACTION_ICON = ATTRIBUTE_NODE_ICON; + protected final Map<TreeNode, TooltipInfo> tooltipMap = new HashMap<TreeNode, TooltipInfo>(); + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { if (!isRealUpdate(uidl)) { return; @@ -62,6 +68,8 @@ public class TreeConnector extends AbstractComponentConnector implements getWidget().body.clear(); // clear out any references to nodes that no longer are attached getWidget().clearNodeToKeyMap(); + tooltipMap.clear(); + TreeNode childTree = null; UIDL childUidl = null; for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) { @@ -74,6 +82,7 @@ public class TreeConnector extends AbstractComponentConnector implements continue; } childTree = getWidget().new TreeNode(); + getConnection().getVTooltip().connectHandlersToWidget(childTree); updateNodeFromUIDL(childTree, childUidl); getWidget().body.add(childTree); childTree.addStyleDependentName("root"); @@ -193,13 +202,8 @@ public class TreeConnector extends AbstractComponentConnector implements } String description = uidl.getStringAttribute("descr"); - if (description != null && getConnection() != null) { - // Set tooltip - TooltipInfo info = new TooltipInfo(description); - getConnection().registerTooltip(this, nodeKey, info); - } else { - // Remove possible previous tooltip - getConnection().registerTooltip(this, nodeKey, null); + if (description != null) { + tooltipMap.put(treeNode, new TooltipInfo(description)); } if (uidl.getBooleanAttribute("expanded") && !treeNode.getState()) { @@ -228,6 +232,7 @@ public class TreeConnector extends AbstractComponentConnector implements continue; } final TreeNode childTree = getWidget().new TreeNode(); + getConnection().getVTooltip().connectHandlersToWidget(childTree); updateNodeFromUIDL(childTree, childUidl); containerNode.childNodeContainer.add(childTree); if (!i.hasNext()) { @@ -250,4 +255,32 @@ public class TreeConnector extends AbstractComponentConnector implements return (AbstractFieldState) super.getState(); } + @Override + public TooltipInfo getTooltipInfo(Element element) { + + TooltipInfo info = null; + + // Try to find a tooltip for a node + if (element != getWidget().getElement()) { + Object node = Util.findWidget( + (com.google.gwt.user.client.Element) element, + TreeNode.class); + + if (node != null) { + TreeNode tnode = (TreeNode) node; + if (tnode.isCaptionElement(element)) { + info = tooltipMap.get(tnode); + } + } + } + + // If no tooltip found for the node or if the target was not a node, use + // the default tooltip + if (info == null) { + info = super.getTooltipInfo(element); + } + + return info; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/tree/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/tree/VTree.java index 6f19cba957..7462160bad 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/tree/VTree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/tree/VTree.java @@ -45,7 +45,6 @@ import com.vaadin.terminal.gwt.client.MouseEventDetails; import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.Action; import com.vaadin.terminal.gwt.client.ui.ActionOwner; import com.vaadin.terminal.gwt.client.ui.FocusElementPanel; @@ -656,12 +655,7 @@ public class VTree extends FocusElementPanel implements VHasDropHandler, return; } - if (target == nodeCaptionSpan) { - client.handleTooltipEvent(event, VTree.this, key); - } - - final boolean inCaption = target == nodeCaptionSpan - || (icon != null && target == icon.getElement()); + final boolean inCaption = isCaptionElement(target); if (inCaption && client .hasEventListeners(VTree.this, ITEM_CLICK_EVENT_ID) @@ -751,6 +745,18 @@ public class VTree extends FocusElementPanel implements VHasDropHandler, } } + /** + * Checks if the given element is the caption or the icon. + * + * @param target + * The element to check + * @return true if the element is the caption or the icon + */ + public boolean isCaptionElement(com.google.gwt.dom.client.Element target) { + return (target == nodeCaptionSpan || (icon != null && target == icon + .getElement())); + } + private void fireClick(final Event evt) { /* * Ensure we have focus in tree before sending variables. Otherwise @@ -825,7 +831,6 @@ public class VTree extends FocusElementPanel implements VHasDropHandler, + "-caption"); Element wrapper = DOM.createDiv(); nodeCaptionSpan = DOM.createSpan(); - DOM.sinkEvents(nodeCaptionSpan, VTooltip.TOOLTIP_EVENTS); DOM.appendChild(getElement(), nodeCaptionDiv); DOM.appendChild(nodeCaptionDiv, wrapper); DOM.appendChild(wrapper, nodeCaptionSpan); diff --git a/src/com/vaadin/terminal/gwt/client/ui/upload/VUpload.java b/src/com/vaadin/terminal/gwt/client/ui/upload/VUpload.java index 4fe53fb89c..ac475ce5a5 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/upload/VUpload.java +++ b/src/com/vaadin/terminal/gwt/client/ui/upload/VUpload.java @@ -24,7 +24,6 @@ import com.google.gwt.user.client.ui.SimplePanel; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ui.button.VButton; /** @@ -128,16 +127,6 @@ public class VUpload extends SimplePanel { panel.add(submitButton); setStyleName(CLASSNAME); - - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - @Override - public void onBrowserEvent(Event event) { - if ((event.getTypeInt() & VTooltip.TOOLTIP_EVENTS) > 0) { - client.handleTooltipEvent(event, this); - } - super.onBrowserEvent(event); } private static native void setEncoding(Element form, String encoding) diff --git a/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java index 8fd84a9ea6..3946a026c6 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java +++ b/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java @@ -552,11 +552,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, final Element target = DOM.eventGetTarget(event); - if (client != null && header.isOrHasChild(target)) { - // Handle window caption tooltips - client.handleTooltipEvent(event, this); - } - if (resizing || resizeBox == target) { onResizeEvent(event); bubble = false; diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index f7e46a7ca9..6930961497 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -136,6 +136,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/"; + static final String CONNECTOR_RESOURCE_PREFIX = "/APP/CONNECTOR/"; + /** * Called by the servlet container to indicate to a servlet that the servlet * is being placed into service. @@ -396,6 +398,19 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements CommunicationManager applicationManager = webApplicationContext .getApplicationManager(application, this); + if (requestType == RequestType.CONNECTOR_RESOURCE) { + String pathInfo = getRequestPathInfo(request); + String resourceName = pathInfo + .substring(CONNECTOR_RESOURCE_PREFIX.length()); + + final String mimetype = getServletContext().getMimeType( + resourceName); + + applicationManager.serveConnectorResource(resourceName, + request, response, mimetype); + return; + } + /* Update browser information from the request */ webApplicationContext.getBrowser().updateRequestDetails(request); @@ -1250,12 +1265,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } protected enum RequestType { - FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE; + FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE, CONNECTOR_RESOURCE; } protected RequestType getRequestType(HttpServletRequest request) { if (isFileUploadRequest(request)) { return RequestType.FILE_UPLOAD; + } else if (isConnectorResourceRequest(request)) { + return RequestType.CONNECTOR_RESOURCE; } else if (isBrowserDetailsRequest(request)) { return RequestType.BROWSER_DETAILS; } else if (isUIDLRequest(request)) { @@ -1276,6 +1293,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements && request.getParameter("browserDetails") != null; } + private boolean isConnectorResourceRequest(HttpServletRequest request) { + String path = getRequestPathInfo(request); + if (path != null && path.startsWith(CONNECTOR_RESOURCE_PREFIX)) { + return true; + } + return false; + } + private boolean isApplicationRequest(HttpServletRequest request) { String path = getRequestPathInfo(request); if (path != null && path.startsWith("/APP/")) { diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 7cad8e3a33..4ee300edac 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -18,6 +18,8 @@ import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.net.URI; +import java.net.URISyntaxException; import java.security.GeneralSecurityException; import java.text.CharacterIterator; import java.text.DateFormat; @@ -42,10 +44,14 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import javax.servlet.http.HttpServletResponse; + import com.vaadin.Application; import com.vaadin.Application.SystemMessages; import com.vaadin.RootRequiresMoreInformationException; import com.vaadin.Version; +import com.vaadin.annotations.JavaScript; +import com.vaadin.annotations.StyleSheet; import com.vaadin.external.json.JSONArray; import com.vaadin.external.json.JSONException; import com.vaadin.external.json.JSONObject; @@ -154,6 +160,8 @@ public abstract class AbstractCommunicationManager implements Serializable { private Connector highlightedConnector; + private Map<String, Class<?>> connectoResourceContexts = new HashMap<String, Class<?>>(); + /** * TODO New constructor - document me! * @@ -497,10 +505,11 @@ public abstract class AbstractCommunicationManager implements Serializable { * found * @throws IOException * @throws InvalidUIDLSecurityKeyException + * @throws JSONException */ public void handleUidlRequest(WrappedRequest request, WrappedResponse response, Callback callback, Root root) - throws IOException, InvalidUIDLSecurityKeyException { + throws IOException, InvalidUIDLSecurityKeyException, JSONException { checkWidgetsetVersion(request); requestThemeName = request.getParameter("theme"); @@ -696,11 +705,12 @@ public abstract class AbstractCommunicationManager implements Serializable { * @param analyzeLayouts * @throws PaintException * @throws IOException + * @throws JSONException */ private void paintAfterVariableChanges(WrappedRequest request, WrappedResponse response, Callback callback, boolean repaintAll, final PrintWriter outWriter, Root root, boolean analyzeLayouts) - throws PaintException, IOException { + throws PaintException, IOException, JSONException { // Removes application if it has stopped during variable changes if (!application.isRunning()) { @@ -764,7 +774,7 @@ public abstract class AbstractCommunicationManager implements Serializable { @SuppressWarnings("unchecked") public void writeUidlResponse(WrappedRequest request, boolean repaintAll, final PrintWriter outWriter, Root root, boolean analyzeLayouts) - throws PaintException { + throws PaintException, JSONException { ArrayList<ClientConnector> dirtyVisibleConnectors = new ArrayList<ClientConnector>(); Application application = root.getApplication(); // Paints components @@ -1095,10 +1105,14 @@ public abstract class AbstractCommunicationManager implements Serializable { boolean typeMappingsOpen = false; ClientCache clientCache = getClientCache(root); + List<Class<? extends ClientConnector>> newConnectorTypes = new ArrayList<Class<? extends ClientConnector>>(); + for (Class<? extends ClientConnector> class1 : usedClientConnectors) { if (clientCache.cache(class1)) { // client does not know the mapping key for this type, send // mapping to client + newConnectorTypes.add(class1); + if (!typeMappingsOpen) { typeMappingsOpen = true; outWriter.print(", \"typeMappings\" : { "); @@ -1142,6 +1156,57 @@ public abstract class AbstractCommunicationManager implements Serializable { } } + /* + * Ensure super classes come before sub classes to get script dependency + * order right. Sub class @JavaScript might assume that @JavaScript + * defined by super class is already loaded. + */ + Collections.sort(newConnectorTypes, new Comparator<Class<?>>() { + public int compare(Class<?> o1, Class<?> o2) { + // TODO optimize using Class.isAssignableFrom? + return hierarchyDepth(o1) - hierarchyDepth(o2); + } + + private int hierarchyDepth(Class<?> type) { + if (type == Object.class) { + return 0; + } else { + return hierarchyDepth(type.getSuperclass()) + 1; + } + } + }); + + List<String> scriptDependencies = new ArrayList<String>(); + List<String> styleDependencies = new ArrayList<String>(); + + for (Class<? extends ClientConnector> class1 : newConnectorTypes) { + JavaScript jsAnnotation = class1.getAnnotation(JavaScript.class); + if (jsAnnotation != null) { + for (String resource : jsAnnotation.value()) { + scriptDependencies.add(registerResource(resource, class1)); + } + } + + StyleSheet styleAnnotation = class1.getAnnotation(StyleSheet.class); + if (styleAnnotation != null) { + for (String resource : styleAnnotation.value()) { + styleDependencies.add(registerResource(resource, class1)); + } + } + } + + // Include script dependencies in output if there are any + if (!scriptDependencies.isEmpty()) { + outWriter.print(", \"scriptDependencies\": " + + new JSONArray(scriptDependencies).toString()); + } + + // Include style dependencies in output if there are any + if (!styleDependencies.isEmpty()) { + outWriter.print(", \"styleDependencies\": " + + new JSONArray(styleDependencies).toString()); + } + // add any pending locale definitions requested by the client printLocaleDeclarations(outWriter); @@ -1152,6 +1217,51 @@ public abstract class AbstractCommunicationManager implements Serializable { writePerformanceData(outWriter); } + private String registerResource(String resource, Class<?> context) { + try { + URI uri = new URI(resource); + String protocol = uri.getScheme(); + + if ("connector".equals(protocol)) { + return registerContextResource(uri, context); + } + + if (protocol != null || uri.getHost() != null) { + return resource; + } + + String path = uri.getPath(); + if (path.startsWith("/")) { + return resource; + } + + // Default if just simple relative url + return registerContextResource(uri, context); + } catch (URISyntaxException e) { + getLogger().log(Level.WARNING, + "Could not parse resource url " + resource, e); + return resource; + } + } + + private String registerContextResource(URI uri, Class<?> context) { + String path = uri.getPath(); + synchronized (connectoResourceContexts) { + // Connector resource + if (connectoResourceContexts.containsKey(path)) { + Class<?> oldContext = connectoResourceContexts.get(path); + getLogger().warning( + "Resource " + path + " defined by both " + context + + " and " + oldContext + ". Resource from " + + oldContext + " will be used."); + } else { + connectoResourceContexts.put(path, context); + } + } + + return "connector://" + path; + } + /** * Adds the performance timing data (used by TestBench 3) to the UIDL * response. @@ -1380,7 +1490,7 @@ public abstract class AbstractCommunicationManager implements Serializable { private boolean handleVariables(WrappedRequest request, WrappedResponse response, Callback callback, Application application2, Root root) throws IOException, - InvalidUIDLSecurityKeyException { + InvalidUIDLSecurityKeyException, JSONException { boolean success = true; String changes = getRequestPayload(request); @@ -2256,9 +2366,11 @@ public abstract class AbstractCommunicationManager implements Serializable { * @return a string with the initial UIDL message * @throws PaintException * if an exception occurs while painting + * @throws JSONException + * if an exception occurs while encoding output */ protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException { + throws PaintException, JSONException { // TODO maybe unify writeUidlResponse()? StringWriter sWriter = new StringWriter(); PrintWriter pWriter = new PrintWriter(sWriter); @@ -2273,6 +2385,60 @@ public abstract class AbstractCommunicationManager implements Serializable { return initialUIDL; } + public void serveConnectorResource(String resourceName, + WrappedRequest request, WrappedResponse response, String mimetype) + throws IOException { + if (resourceName.startsWith("/")) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); + return; + } + + Class<?> context; + synchronized (connectoResourceContexts) { + context = connectoResourceContexts.get(resourceName); + } + + if (context == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); + return; + } + + InputStream in = context.getResourceAsStream(resourceName); + if (in == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); + return; + } + OutputStream out = null; + try { + if (mimetype != null) { + response.setContentType(mimetype); + } + + out = response.getOutputStream(); + + final byte[] buffer = new byte[Constants.DEFAULT_BUFFER_SIZE]; + + int bytesRead = 0; + while ((bytesRead = in.read(buffer)) > 0) { + out.write(buffer, 0, bytesRead); + } + out.flush(); + } finally { + try { + in.close(); + } catch (Exception e) { + // Do nothing + } + if (out != null) { + try { + out.close(); + } catch (Exception e) { + // Do nothing + } + } + } + } + /** * Stream that extracts content from another stream until the boundary * string is encountered. diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java index 69f033c8cd..d32fa325f4 100644 --- a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java +++ b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java @@ -9,10 +9,6 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Serializable; import java.io.Writer; -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; @@ -20,7 +16,6 @@ import javax.servlet.http.HttpServletResponse; import com.vaadin.Application; import com.vaadin.RootRequiresMoreInformationException; import com.vaadin.Version; -import com.vaadin.annotations.LoadScripts; import com.vaadin.external.json.JSONException; import com.vaadin.external.json.JSONObject; import com.vaadin.terminal.DeploymentConfiguration; @@ -490,50 +485,6 @@ public abstract class BootstrapHandler implements RequestHandler { page.write("<title>" + AbstractApplicationServlet.safeEscapeForHtml(title) + "</title>\n"); - - if (root != null) { - List<LoadScripts> loadScriptsAnnotations = getAnnotationsFor( - root.getClass(), LoadScripts.class); - Collections.reverse(loadScriptsAnnotations); - // Begin from the end as a class might requests scripts that depend - // on script loaded by a super class - for (int i = loadScriptsAnnotations.size() - 1; i >= 0; i--) { - LoadScripts loadScripts = loadScriptsAnnotations.get(i); - String[] value = loadScripts.value(); - if (value != null) { - for (String script : value) { - page.write("<script type='text/javascript' src='"); - page.write(script); - page.write("'></script>\n"); - } - } - } - - } - } - - private static <T extends Annotation> List<T> getAnnotationsFor( - Class<?> type, Class<T> annotationType) { - List<T> list = new ArrayList<T>(); - // Find from the class hierarchy - Class<?> currentType = type; - while (currentType != Object.class) { - T annotation = currentType.getAnnotation(annotationType); - if (annotation != null) { - list.add(annotation); - } - currentType = currentType.getSuperclass(); - } - - // Find from an implemented interface - for (Class<?> iface : type.getInterfaces()) { - T annotation = iface.getAnnotation(annotationType); - if (annotation != null) { - list.add(annotation); - } - } - - return list; } /** @@ -645,8 +596,10 @@ public abstract class BootstrapHandler implements RequestHandler { * @return a string with the initial UIDL message * @throws PaintException * if an exception occurs while painting the components + * @throws JSONException + * if an exception occurs while formatting the output */ protected abstract String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException; + throws PaintException, JSONException; } diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java index cc2981dc45..2d2888e034 100644 --- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java @@ -15,6 +15,7 @@ import java.util.UUID; import javax.servlet.ServletContext; import com.vaadin.Application; +import com.vaadin.external.json.JSONException; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.StreamVariable; import com.vaadin.terminal.WrappedRequest; @@ -245,7 +246,7 @@ public class CommunicationManager extends AbstractCommunicationManager { @Override protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException { + throws PaintException, JSONException { return CommunicationManager.this.getInitialUIDL(request, root); } }; diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java index d3fbf4d988..7398315ee2 100644 --- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java @@ -104,7 +104,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { @Override public void handleUidlRequest(WrappedRequest request, WrappedResponse response, Callback callback, Root root) - throws IOException, InvalidUIDLSecurityKeyException { + throws IOException, InvalidUIDLSecurityKeyException, JSONException { setCurrentMimeReponse(response); super.handleUidlRequest(request, response, callback, root); currentMimeResponse = null; @@ -253,7 +253,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { @Override protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException { + throws PaintException, JSONException { return PortletCommunicationManager.this.getInitialUIDL(request, root); } diff --git a/src/com/vaadin/tools/WidgetsetCompiler.java b/src/com/vaadin/tools/WidgetsetCompiler.java index 407f0e2387..987fd8f734 100644 --- a/src/com/vaadin/tools/WidgetsetCompiler.java +++ b/src/com/vaadin/tools/WidgetsetCompiler.java @@ -31,7 +31,8 @@ import com.vaadin.terminal.gwt.widgetsetutils.WidgetSetBuilder; * included in the classpath, as well as the gwt-dev-[platform].jar and other * relevant JARs. * - * @deprecated with Java 6, can use com.google.gwt.dev.Compiler directly (also in Eclipse plug-in etc.) + * @deprecated with Java 6, can use com.google.gwt.dev.Compiler directly (also + * in Eclipse plug-in etc.) */ @Deprecated public class WidgetsetCompiler { diff --git a/src/com/vaadin/ui/AbstractJavaScriptComponent.java b/src/com/vaadin/ui/AbstractJavaScriptComponent.java index 95c45f55f9..0d7f60186a 100644 --- a/src/com/vaadin/ui/AbstractJavaScriptComponent.java +++ b/src/com/vaadin/ui/AbstractJavaScriptComponent.java @@ -110,7 +110,7 @@ import com.vaadin.terminal.gwt.client.ui.JavaScriptWidget; * @version @VERSION@ * @since 7.0.0 */ -public class AbstractJavaScriptComponent extends AbstractComponent { +public abstract class AbstractJavaScriptComponent extends AbstractComponent { private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper( this); diff --git a/src/com/vaadin/ui/AbstractMedia.java b/src/com/vaadin/ui/AbstractMedia.java index 760d9878ca..eafc6c4ed9 100644 --- a/src/com/vaadin/ui/AbstractMedia.java +++ b/src/com/vaadin/ui/AbstractMedia.java @@ -18,7 +18,7 @@ import com.vaadin.terminal.gwt.server.ResourceReference; * * @author Vaadin Ltd */ -public class AbstractMedia extends AbstractComponent { +public abstract class AbstractMedia extends AbstractComponent { @Override public AbstractMediaState getState() { diff --git a/src/com/vaadin/ui/Component.java b/src/com/vaadin/ui/Component.java index 81e0319880..5d05f9d0f2 100644 --- a/src/com/vaadin/ui/Component.java +++ b/src/com/vaadin/ui/Component.java @@ -520,8 +520,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable { * <p> * Getting a null value is often a problem in constructors of regular * components and in the initializers of custom composite components. A - * standard workaround is to use {@link Application#getCurrent()} - * to retrieve the application instance that the current request relates to. + * standard workaround is to use {@link Application#getCurrent()} to + * retrieve the application instance that the current request relates to. * Another way is to move the problematic initialization to * {@link #attach()}, as described in the documentation of the method. * </p> diff --git a/src/com/vaadin/ui/ConnectorTracker.java b/src/com/vaadin/ui/ConnectorTracker.java index 75a75ad22a..e3d1bf86db 100644 --- a/src/com/vaadin/ui/ConnectorTracker.java +++ b/src/com/vaadin/ui/ConnectorTracker.java @@ -17,7 +17,7 @@ import com.vaadin.terminal.gwt.client.ServerConnector; import com.vaadin.terminal.gwt.server.ClientConnector; /** - * A class which takes care of book keeping of {@link ClientConnector}s for one + * A class which takes care of book keeping of {@link ClientConnector}s for a * Root. * <p> * Provides {@link #getConnector(String)} which can be used to lookup a @@ -53,6 +53,14 @@ public class ConnectorTracker implements Serializable { return Logger.getLogger(ConnectorTracker.class.getName()); } + /** + * Creates a new ConnectorTracker for the given root. A tracker is always + * attached to a root and the root cannot be changed during the lifetime of + * a {@link ConnectorTracker}. + * + * @param root + * The root to attach to. Cannot be null. + */ public ConnectorTracker(Root root) { this.root = root; } @@ -144,61 +152,134 @@ public class ConnectorTracker implements Serializable { while (iterator.hasNext()) { String connectorId = iterator.next(); ClientConnector connector = connectorIdToConnector.get(connectorId); - if (connector instanceof Component) { - Component component = (Component) connector; - if (component.getRoot() != root) { - // If component is no longer part of this application, - // remove it from the map. If it is re-attached to the - // application at some point it will be re-added through - // registerConnector(connector) - iterator.remove(); - } + if (getRootForConnector(connector) != root) { + // If connector is no longer part of this root, + // remove it from the map. If it is re-attached to the + // application at some point it will be re-added through + // registerConnector(connector) + + // This code should never be called as cleanup should take place + // in detach() + getLogger() + .warning( + "cleanConnectorMap unregistered connector " + + getConnectorAndParentInfo(connector) + + "). This should have been done when the connector was detached."); + iterator.remove(); } } } + /** + * Finds the root that the connector is attached to. + * + * @param connector + * The connector to lookup + * @return The root the connector is attached to or null if it is not + * attached to any root. + */ + private Root getRootForConnector(ClientConnector connector) { + if (connector == null) { + return null; + } + if (connector instanceof Component) { + return ((Component) connector).getRoot(); + } + + return getRootForConnector(connector.getParent()); + } + + /** + * Mark the connector as dirty. + * + * @see #getDirtyConnectors() + * + * @param connector + * The connector that should be marked clean. + */ public void markDirty(ClientConnector connector) { if (getLogger().isLoggable(Level.FINE)) { if (!dirtyConnectors.contains(connector)) { - getLogger() - .fine(getDebugInfo(connector) + " " + "is now dirty"); + getLogger().fine( + getConnectorAndParentInfo(connector) + " " + + "is now dirty"); } } dirtyConnectors.add(connector); } + /** + * Mark the connector as clean. + * + * @param connector + * The connector that should be marked clean. + */ public void markClean(ClientConnector connector) { if (getLogger().isLoggable(Level.FINE)) { if (dirtyConnectors.contains(connector)) { getLogger().fine( - getDebugInfo(connector) + " " + "is no longer dirty"); + getConnectorAndParentInfo(connector) + " " + + "is no longer dirty"); } } dirtyConnectors.remove(connector); } - private String getDebugInfo(ClientConnector connector) { - String message = getObjectString(connector); + /** + * Returns {@link #getConnectorString(ClientConnector)} for the connector + * and its parent (if it has a parent). + * + * @param connector + * The connector + * @return A string describing the connector and its parent + */ + private String getConnectorAndParentInfo(ClientConnector connector) { + String message = getConnectorString(connector); if (connector.getParent() != null) { - message += " (parent: " + getObjectString(connector.getParent()) + message += " (parent: " + getConnectorString(connector.getParent()) + ")"; } return message; } - private String getObjectString(Object connector) { - return connector.getClass().getName() + "@" - + Integer.toHexString(connector.hashCode()); + /** + * Returns a string with the connector name and id. Useful mostly for + * debugging and logging. + * + * @param connector + * The connector + * @return A string that describes the connector + */ + private String getConnectorString(ClientConnector connector) { + if (connector == null) { + return "(null)"; + } + + String connectorId; + try { + connectorId = connector.getConnectorId(); + } catch (RuntimeException e) { + // This happens if the connector is not attached to the application. + // SHOULD not happen in this case but theoretically can. + connectorId = "@" + Integer.toHexString(connector.hashCode()); + } + return connector.getClass().getName() + "(" + connectorId + ")"; } + /** + * Mark all connectors in this root as dirty. + */ public void markAllConnectorsDirty() { markConnectorsDirtyRecursively(root); getLogger().fine("All connectors are now dirty"); } + /** + * Mark all connectors in this root as clean. + */ public void markAllConnectorsClean() { dirtyConnectors.clear(); getLogger().fine("All connectors are now clean"); @@ -222,6 +303,16 @@ public class ConnectorTracker implements Serializable { } } + /** + * Returns a collection of all connectors which have been marked as dirty. + * <p> + * The state and pending RPC calls for dirty connectors are sent to the + * client in the following request. + * </p> + * + * @return A collection of all dirty connectors for this root. This list may + * contain invisible connectors. + */ public Collection<ClientConnector> getDirtyConnectors() { return dirtyConnectors; } diff --git a/src/com/vaadin/ui/Label.java b/src/com/vaadin/ui/Label.java index e1c64605d7..e98da384cf 100644 --- a/src/com/vaadin/ui/Label.java +++ b/src/com/vaadin/ui/Label.java @@ -142,10 +142,13 @@ public class Label extends AbstractComponent implements Property<String>, } /** - * Gets the value of the label. Value of the label is the XML contents of - * the label. + * Gets the value of the label. + * <p> + * The value of the label is the text that is shown to the end user. + * Depending on the {@link ContentMode} it is plain text or markup. + * </p> * - * @return the Value of the label. + * @return the value of the label. */ public String getValue() { if (getPropertyDataSource() == null) { @@ -180,8 +183,7 @@ public class Label extends AbstractComponent implements Property<String>, /** * @see java.lang.Object#toString() - * @deprecated use the data source value or {@link #getStringValue()} - * instead + * @deprecated Use {@link #getValue()} instead */ @Deprecated @Override diff --git a/tests/server-side/com/vaadin/tests/server/component/table/TableSerialization.java b/tests/server-side/com/vaadin/tests/server/component/table/TableSerialization.java index 44dcd60fa5..ee6349093c 100644 --- a/tests/server-side/com/vaadin/tests/server/component/table/TableSerialization.java +++ b/tests/server-side/com/vaadin/tests/server/component/table/TableSerialization.java @@ -12,8 +12,9 @@ public class TableSerialization extends TestCase { Table t = new Table(); byte[] ser = SerializationUtils.serialize(t); Table t2 = (Table) SerializationUtils.deserialize(ser); - + } + public void testSerializationWithRowHeaders() { Table t = new Table(); t.setRowHeaderMode(Table.ROW_HEADER_MODE_EXPLICIT); diff --git a/tests/server-side/com/vaadin/tests/server/navigator/UriFragmentManagerTest.java b/tests/server-side/com/vaadin/tests/server/navigator/UriFragmentManagerTest.java index 65294b2913..37c9a7ecd5 100644 --- a/tests/server-side/com/vaadin/tests/server/navigator/UriFragmentManagerTest.java +++ b/tests/server-side/com/vaadin/tests/server/navigator/UriFragmentManagerTest.java @@ -22,7 +22,7 @@ public class UriFragmentManagerTest extends TestCase { // prepare mock EasyMock.expect(page.getFragment()).andReturn(""); - page.setFragment("test"); + page.setFragment("test", false); EasyMock.expect(page.getFragment()).andReturn("test"); EasyMock.replay(page); diff --git a/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.java b/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.java index fd65adf209..eeb866138b 100644 --- a/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.java +++ b/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.java @@ -92,8 +92,7 @@ public class ThreadLocalInstances extends AbstractTestApplication { } private void reportCurrentStatus(String phase) { - reportStatus(phase, Application.getCurrent(), - Root.getCurrent()); + reportStatus(phase, Application.getCurrent(), Root.getCurrent()); } private void reportStatus(String phase, Application application, Root root) { diff --git a/tests/testbench/com/vaadin/tests/components/AbstractTestRoot.java b/tests/testbench/com/vaadin/tests/components/AbstractTestRoot.java index 875d2b1df8..4355b66e5e 100644 --- a/tests/testbench/com/vaadin/tests/components/AbstractTestRoot.java +++ b/tests/testbench/com/vaadin/tests/components/AbstractTestRoot.java @@ -57,8 +57,7 @@ public abstract class AbstractTestRoot extends Root { protected abstract Integer getTicketNumber(); protected WebBrowser getBrowser() { - ApplicationContext context = Application.getCurrent() - .getContext(); + ApplicationContext context = Application.getCurrent().getContext(); if (context instanceof AbstractWebApplicationContext) { AbstractWebApplicationContext webContext = (AbstractWebApplicationContext) context; return webContext.getBrowser(); diff --git a/tests/testbench/com/vaadin/tests/components/AddRemoveSetStyleNamesTest.html b/tests/testbench/com/vaadin/tests/components/AddRemoveSetStyleNamesTest.html new file mode 100644 index 0000000000..a09a1e06e5 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/AddRemoveSetStyleNamesTest.html @@ -0,0 +1,456 @@ +<?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>AddRemoveSetStyleNamesTest</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">AddRemoveSetStyleNamesTest</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>run/com.vaadin.tests.components.AddRemoveSetStyleNamesTest?restartApplication</td>
+ <td></td>
+</tr>
+<!--add style 1. assert style1-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style1</td>
+</tr>
+<!--add style 2. assert style1, style2-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style2</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style2</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style2</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style2</td>
+</tr>
+<!--remove style 1. assertNot style1. assert style2-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style2</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style2</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style2</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style2</td>
+</tr>
+<!--remove style 2. assertNot style1, style2-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style2</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style2</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style2</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style2</td>
+</tr>
+<!--add style1. set thestyle. assertNot style1. assert thestyle.-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>thestyle</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-thestyle</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-thestyle</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>thestyle</td>
+</tr>
+<!--remove thestyle. assertNot thestyle-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>thestyle</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-thestyle</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-thestyle</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>thestyle</td>
+</tr>
+<!--set thestyle. add style1. assert thestyle, style1-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>thestyle</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-thestyle</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-thestyle</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>thestyle</td>
+</tr>
+<!--remove style 1. assertNot style1. assert thestyle-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-thestyle</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>thestyle</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-thestyle</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>thestyle</td>
+</tr>
+<!--add style 1. remove thestyle. assertNot style1, thestyle-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>v-datefield-thestyle</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]</td>
+ <td>thestyle</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-style1</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>style1</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>v-datefield-popup-thestyle</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]</td>
+ <td>thestyle</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/AddRemoveSetStyleNamesTest.java b/tests/testbench/com/vaadin/tests/components/AddRemoveSetStyleNamesTest.java new file mode 100644 index 0000000000..21cf9e45a6 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/AddRemoveSetStyleNamesTest.java @@ -0,0 +1,81 @@ +package com.vaadin.tests.components;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.PopupDateField;
+
+public class AddRemoveSetStyleNamesTest extends TestBase {
+
+ private String style1 = "style1";
+ private String style2 = "style2";
+ private String thestyle = "thestyle";
+
+ private PopupDateField popupDateField;
+ private Button button1;
+ private Button button2;
+ private Button button3;
+
+ private Button.ClickListener listener;
+
+ @Override
+ protected void setup() {
+ popupDateField = new PopupDateField("PopupDateField");
+ popupDateField.setRequired(true);
+ popupDateField.setRequiredError("abcd");
+ addComponent(popupDateField);
+
+ listener = new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ String style = (String) event.getButton().getData();
+ setComponentsStyle(style, !popupDateField.getStyleName()
+ .contains(style), event.getButton());
+ }
+ };
+
+ button1 = new Button("Add style1", listener);
+ button1.setData(style1);
+ addComponent(button1);
+
+ button2 = new Button("Add style2", listener);
+ button2.setData(style2);
+ addComponent(button2);
+
+ button3 = new Button("Set thestyle", new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ if (popupDateField.getStyleName().contains(thestyle)) {
+ popupDateField.removeStyleName(thestyle);
+ button3.setCaption("Set thestyle");
+ } else {
+ popupDateField.setStyleName(thestyle);
+ button1.setCaption("Add style1");
+ button2.setCaption("Add style2");
+ button3.setCaption("Remove thestyle");
+ }
+ }
+ });
+ addComponent(button3);
+ }
+
+ private void setComponentsStyle(String style, boolean add, Button button) {
+ if (add) {
+ popupDateField.addStyleName(style);
+ button.setCaption("Remove " + style);
+ } else {
+ popupDateField.removeStyleName(style);
+ button.setCaption("Add " + style);
+ }
+ }
+
+ @Override
+ protected String getDescription() {
+ return "If a widget has set multiple css class names, AbtractComponentConnector.getStyleNames() removes all but first one of them. This is not acceptable, because we should be able to create connector for any existing GWT component and thus we do not know it it depends on multiple css class names.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 8664;
+ }
+
+}
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/abstractcomponent/AllComponentTooltipTest.java b/tests/testbench/com/vaadin/tests/components/abstractcomponent/AllComponentTooltipTest.java new file mode 100644 index 0000000000..17cc4270fb --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractcomponent/AllComponentTooltipTest.java @@ -0,0 +1,50 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.tests.components.abstractcomponent; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.VaadinClasses; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.Component; +import com.vaadin.ui.GridLayout; + +public class AllComponentTooltipTest extends AbstractTestRoot { + + @Override + protected void setup(WrappedRequest request) { + setContent(new GridLayout(5, 5)); + for (Class<? extends Component> cls : VaadinClasses.getComponents()) { + try { + AbstractComponent c = (AbstractComponent) cls.newInstance(); + if (c instanceof LegacyWindow) { + continue; + } + + c.setDebugId(cls.getName()); + c.setCaption(cls.getName()); + c.setDescription(cls.getName()); + c.setWidth("100px"); + c.setHeight("100px"); + getContent().addComponent(c); + System.out.println("Added " + cls.getName()); + } catch (Exception e) { + System.err.println("Could not instatiate " + cls.getName()); + } + } + } + + @Override + protected String getTestDescription() { + // 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/abstractcomponent/TooltipTests.html b/tests/testbench/com/vaadin/tests/components/abstractcomponent/TooltipTests.html new file mode 100644 index 0000000000..a1d4fc9b35 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractcomponent/TooltipTests.html @@ -0,0 +1,77 @@ +<?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>TooltipTests</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">TooltipTests</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.abstractcomponent.TooltipTests?restartApplication</td> + <td></td> +</tr> +<tr> + <td>showTooltip</td> + <td>//div[@id='label']</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>no_tooltip</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsabstractcomponentTooltipTests::/VVerticalLayout[0]/VVerticalLayout[0]/VHorizontalLayout[0]/VCheckBox[0]/domChild[0]</td> + <td>10,7</td> +</tr> +<tr> + <td>showTooltip</td> + <td>//div[@id='label']</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>panel_tooltip</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsabstractcomponentTooltipTests::/VVerticalLayout[0]/VVerticalLayout[0]/VHorizontalLayout[0]/VCheckBox[1]/domChild[0]</td> + <td>8,6</td> +</tr> +<tr> + <td>showTooltip</td> + <td>//div[@id='label']</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>layout_tooltip</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsabstractcomponentTooltipTests::/VVerticalLayout[0]/VVerticalLayout[0]/VHorizontalLayout[0]/VCheckBox[2]/domChild[0]</td> + <td>5,5</td> +</tr> +<tr> + <td>showTooltip</td> + <td>//div[@id='label']</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>label_tooltip</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/abstractcomponent/TooltipTests.java b/tests/testbench/com/vaadin/tests/components/abstractcomponent/TooltipTests.java new file mode 100644 index 0000000000..c009e1d7bc --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractcomponent/TooltipTests.java @@ -0,0 +1,97 @@ +package com.vaadin.tests.components.abstractcomponent; + +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Panel; +import com.vaadin.ui.VerticalLayout; + +public class TooltipTests extends TestBase { + + private Panel panel; + private VerticalLayout layout; + private Label label; + + @Override + protected String getDescription() { + return "Generic tooltip handling tests"; + } + + @Override + protected Integer getTicketNumber() { + return 8425; + } + + @Override + protected void setup() { + HorizontalLayout topLayout = new HorizontalLayout(); + addComponent(topLayout); + CheckBox panelCbox = new CheckBox("Panel"); + panelCbox.addListener(panelListener); + topLayout.addComponent(panelCbox); + CheckBox layoutCbox = new CheckBox("Layout"); + layoutCbox.addListener(layoutListener); + topLayout.addComponent(layoutCbox); + CheckBox labelCbox = new CheckBox("Label"); + topLayout.addComponent(labelCbox); + labelCbox.addListener(labelListener); + + panel = new Panel(); + panel.setCaption("Panel caption"); + panel.setDebugId("panel"); + addComponent(panel); + + layout = new VerticalLayout(); + layout.setDebugId("layout"); + layout.setMargin(true); + layout.setSpacing(true); + panel.setContent(layout); + + label = new Label("Hover me!"); + label.setDebugId("label"); + layout.addComponent(label); + } + + private final Property.ValueChangeListener panelListener = new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean value = (Boolean) (event.getProperty().getValue()); + if (value) { + panel.setDescription("I'm panel!"); + } else { + panel.setDescription(""); + } + } + + }; + + private final Property.ValueChangeListener layoutListener = new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean value = (Boolean) (event.getProperty().getValue()); + if (value) { + layout.setDescription("I'm layout!"); + } else { + layout.setDescription(""); + } + } + + }; + + private final Property.ValueChangeListener labelListener = new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean value = (Boolean) (event.getProperty().getValue()); + if (value) { + label.setDescription("I'm label!"); + } else { + label.setDescription(""); + } + } + + }; + +} diff --git a/tests/testbench/com/vaadin/tests/components/javascriptcomponent/BasicJavaScriptComponent.java b/tests/testbench/com/vaadin/tests/components/javascriptcomponent/BasicJavaScriptComponent.java index 5f2f945c8b..15c5f6b642 100644 --- a/tests/testbench/com/vaadin/tests/components/javascriptcomponent/BasicJavaScriptComponent.java +++ b/tests/testbench/com/vaadin/tests/components/javascriptcomponent/BasicJavaScriptComponent.java @@ -6,7 +6,7 @@ package com.vaadin.tests.components.javascriptcomponent; import java.util.Arrays; import java.util.List; -import com.vaadin.annotations.LoadScripts; +import com.vaadin.annotations.JavaScript; import com.vaadin.external.json.JSONArray; import com.vaadin.external.json.JSONException; import com.vaadin.terminal.WrappedRequest; @@ -17,7 +17,6 @@ import com.vaadin.ui.AbstractJavaScriptComponent; import com.vaadin.ui.JavaScriptCallback; import com.vaadin.ui.Notification; -@LoadScripts({ "/statictestfiles/jsconnector.js" }) public class BasicJavaScriptComponent extends AbstractTestRoot { public interface ExampleClickRpc extends ServerRpc { @@ -36,6 +35,7 @@ public class BasicJavaScriptComponent extends AbstractTestRoot { } } + @JavaScript("/statictestfiles/jsconnector.js") public static class ExampleWidget extends AbstractJavaScriptComponent { public ExampleWidget() { registerRpc(new ExampleClickRpc() { diff --git a/tests/testbench/com/vaadin/tests/extensions/SimpleJavaScriptExtensionTest.java b/tests/testbench/com/vaadin/tests/extensions/SimpleJavaScriptExtensionTest.java index bbfe3f0f46..72168c08df 100644 --- a/tests/testbench/com/vaadin/tests/extensions/SimpleJavaScriptExtensionTest.java +++ b/tests/testbench/com/vaadin/tests/extensions/SimpleJavaScriptExtensionTest.java @@ -4,7 +4,8 @@ package com.vaadin.tests.extensions; -import com.vaadin.annotations.LoadScripts; +import com.vaadin.annotations.JavaScript; +import com.vaadin.annotations.StyleSheet; import com.vaadin.external.json.JSONArray; import com.vaadin.external.json.JSONException; import com.vaadin.terminal.AbstractJavaScriptExtension; @@ -18,7 +19,6 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.JavaScriptCallback; import com.vaadin.ui.Notification; -@LoadScripts({ "/statictestfiles/jsextension.js" }) public class SimpleJavaScriptExtensionTest extends AbstractTestRoot { public static class SimpleJavaScriptExtensionState extends @@ -44,6 +44,8 @@ public class SimpleJavaScriptExtensionTest extends AbstractTestRoot { public void greet(String message); } + @JavaScript("/statictestfiles/jsextension.js") + @StyleSheet("/VAADIN/external1.css") public static class SimpleJavascriptExtension extends AbstractJavaScriptExtension { |