From b55ff51e8c254c56bb415432102b878fa053d8f3 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 27 Jun 2012 16:52:09 +0300 Subject: Add @JavaScript and @StyleSheet and remove @LoadScripts (#9044) --- src/com/vaadin/annotations/JavaScript.java | 16 + src/com/vaadin/annotations/LoadScripts.java | 24 -- src/com/vaadin/annotations/StyleSheet.java | 16 + .../terminal/gwt/client/ApplicationConnection.java | 55 +++ .../vaadin/terminal/gwt/client/ResourceLoader.java | 401 +++++++++++++++++++++ .../gwt/server/AbstractCommunicationManager.java | 69 +++- .../terminal/gwt/server/BootstrapHandler.java | 53 +-- .../terminal/gwt/server/CommunicationManager.java | 3 +- .../gwt/server/PortletCommunicationManager.java | 4 +- 9 files changed, 559 insertions(+), 82 deletions(-) create mode 100644 src/com/vaadin/annotations/JavaScript.java delete mode 100644 src/com/vaadin/annotations/LoadScripts.java create mode 100644 src/com/vaadin/annotations/StyleSheet.java create mode 100644 src/com/vaadin/terminal/gwt/client/ResourceLoader.java (limited to 'src/com') diff --git a/src/com/vaadin/annotations/JavaScript.java b/src/com/vaadin/annotations/JavaScript.java new file mode 100644 index 0000000000..8e0bc09958 --- /dev/null +++ b/src/com/vaadin/annotations/JavaScript.java @@ -0,0 +1,16 @@ +/* +@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; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface JavaScript { + 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..40f75511dd --- /dev/null +++ b/src/com/vaadin/annotations/StyleSheet.java @@ -0,0 +1,16 @@ +/* +@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; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface StyleSheet { + public String[] value(); +} diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index f0470c8ee8..3ec4233c59 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -40,6 +40,8 @@ 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 +1069,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); /* @@ -1611,6 +1621,51 @@ public class ApplicationConnection { ApplicationConfiguration.runWhenWidgetsLoaded(c); } + private static void loadStyleDependencies(JsArrayString dependencies) { + // Assuming no reason to interpret in a defined order + ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { + public void onResourceLoad(ResourceLoadEvent event) { + ApplicationConfiguration.endWidgetLoading(); + } + }; + ResourceLoader loader = ResourceLoader.get(); + for (int i = 0; i < dependencies.length(); i++) { + ApplicationConfiguration.startWidgetLoading(); + loader.loadStylesheet(dependencies.get(i), resourceLoadListener); + } + } + + private static 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 onResourceLoad(ResourceLoadEvent event) { + if (dependencies.length() != 0) { + ApplicationConfiguration.startWidgetLoading(); + // Load next in chain (hopefully already preloaded) + event.getResourceLoader().loadScript(dependencies.shift(), + this); + } + // Call start for next before calling end for current + ApplicationConfiguration.endWidgetLoading(); + } + }; + + ResourceLoader loader = ResourceLoader.get(); + + // Start chain by loading first + ApplicationConfiguration.startWidgetLoading(); + loader.loadScript(dependencies.shift(), resourceLoadListener); + + // Preload all remaining + for (int i = 0; i < dependencies.length(); i++) { + loader.loadScript(dependencies.get(i), null); + } + } + // Redirect browser, null reloads current page private static native void redirect(String url) /*-{ 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..7abafbc216 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ResourceLoader.java @@ -0,0 +1,401 @@ +/* +@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.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; + +/** + * 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 { + /** + * Notified this ResourceLoadListener that a resource has been loaded + * + * @see ResourceLoadEvent + * + * @param event + * a resource load event with information about the loaded + * resource + */ + public void onResourceLoad(ResourceLoadEvent event); + } + + private static final ResourceLoader INSTANCE = GWT + .create(ResourceLoader.class); + + private ApplicationConnection connection; + + private final Set loadedResources = new HashSet(); + private final Set preloadedResources = new HashSet(); + + private final Map> loadListeners = new HashMap>(); + private final Map> preloadListeners = new HashMap>(); + + 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 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 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); + if (loadedResources.contains(url)) { + if (resourceLoadListener != null) { + resourceLoadListener.onResourceLoad(new ResourceLoadEvent(this, + url, false)); + } + return; + } + + if (preloadListeners.containsKey(url)) { + preloadResource(url, new ResourceLoadListener() { + public void onResourceLoad(ResourceLoadEvent event) { + loadScript(url, resourceLoadListener); + } + }); + return; + } + + if (addListener(url, resourceLoadListener, loadListeners)) { + ScriptElement scriptTag = Document.get().createScriptElement(); + scriptTag.setSrc(url); + scriptTag.setType("text/javascript"); + addOnloadHandler(scriptTag, url, false); + 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); + if (loadedResources.contains(url) || preloadedResources.contains(url)) { + if (resourceLoadListener != null) { + resourceLoadListener.onResourceLoad(new ResourceLoadEvent(this, + url, !loadedResources.contains(url))); + } + 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, url, true); + + // 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, String url, + boolean preload) + /*-{ + var self = this; + var done = $entry(function() { + element.onloadDone = true; + element.onload = null; + element.onreadystatechange = null; + self.@com.vaadin.terminal.gwt.client.ResourceLoader::onResourceLoad(Ljava/lang/String;Z)(url, preload); + }); + element.onload = function() { + if (!element.onloadDone) { + done(); + } + }; + element.onreadystatechange = function() { + if (("loaded" === element.readyState || "complete" === element.readyState) && !element.onloadDone ) { + done(); + } + }; + }-*/; + + /** + * 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); + if (loadedResources.contains(url)) { + if (resourceLoadListener != null) { + resourceLoadListener.onResourceLoad(new ResourceLoadEvent(this, + url, false)); + } + return; + } + + if (preloadListeners.containsKey(url)) { + preloadResource(url, new ResourceLoadListener() { + public void onResourceLoad(ResourceLoadEvent event) { + loadStylesheet(url, resourceLoadListener); + } + }); + 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 onload events for link elements + // See http://www.phpied.com/when-is-a-stylesheet-really-loaded/ + // TODO Stop checking after some timeout + Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() { + public boolean execute() { + if (isStyleSheetPresent(url)) { + onResourceLoad(url, false); + return false; // Stop repeating + } else { + return true; // Continue repeating + } + } + }, 10); + } else { + addOnloadHandler(linkElement, url, false); + } + + head.appendChild(linkElement); + } + } + + private static native boolean isStyleSheetPresent(String url) + /*-{ + for(var i = 0; i < $doc.styleSheets.length; i++) { + if ($doc.styleSheets[i].href === url) { + return true; + } + } + return false; + }-*/; + + private static boolean addListener(String url, + ResourceLoadListener listener, + Map> listenerMap) { + Collection listeners = listenerMap.get(url); + if (listeners == null) { + listeners = new HashSet(); + listeners.add(listener); + listenerMap.put(url, listeners); + return true; + } else { + listeners.add(listener); + return false; + } + } + + private void onResourceLoad(String resource, boolean preload) { + Collection listeners; + if (preload) { + preloadedResources.add(resource); + listeners = preloadListeners.remove(resource); + } else { + if (preloadListeners.containsKey(resource)) { + // Also fire preload events for potential listeners + onResourceLoad(resource, true); + } + preloadedResources.remove(resource); + loadedResources.add(resource); + listeners = loadListeners.remove(resource); + } + if (listeners != null && !listeners.isEmpty()) { + ResourceLoadEvent event = new ResourceLoadEvent(this, resource, + preload); + for (ResourceLoadListener listener : listeners) { + if (listener != null) { + listener.onResourceLoad(event); + } + } + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 7cad8e3a33..c65b8947d6 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -25,6 +25,7 @@ import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; import java.text.StringCharacterIterator; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; @@ -46,6 +47,8 @@ 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; @@ -497,10 +500,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 +700,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 +769,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 dirtyVisibleConnectors = new ArrayList(); Application application = root.getApplication(); // Paints components @@ -1095,10 +1100,14 @@ public abstract class AbstractCommunicationManager implements Serializable { boolean typeMappingsOpen = false; ClientCache clientCache = getClientCache(root); + List> newConnectorTypes = new ArrayList>(); + for (Class 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 +1151,54 @@ 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>() { + 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 scriptDependencies = new ArrayList(); + List styleDependencies = new ArrayList(); + + for (Class class1 : newConnectorTypes) { + JavaScript jsAnnotation = class1.getAnnotation(JavaScript.class); + if (jsAnnotation != null) { + scriptDependencies.addAll(Arrays.asList(jsAnnotation.value())); + } + + StyleSheet styleAnnotation = class1.getAnnotation(StyleSheet.class); + if (styleAnnotation != null) { + styleDependencies + .addAll(Arrays.asList(styleAnnotation.value())); + } + } + + // 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); @@ -1380,7 +1437,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 +2313,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); 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("" + AbstractApplicationServlet.safeEscapeForHtml(title) + "\n"); - - if (root != null) { - List 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("\n"); - } - } - } - - } - } - - private static List getAnnotationsFor( - Class type, Class annotationType) { - List list = new ArrayList(); - // 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); } -- cgit v1.2.3 From 236fd821354b6906c9100c13f7912738ac19c70a Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 27 Jun 2012 17:08:38 +0300 Subject: Rename widget -> dependency in delayed load handling (#9044) --- .../gwt/client/ApplicationConfiguration.java | 20 ++++++++++---------- .../terminal/gwt/client/ApplicationConnection.java | 12 ++++++------ src/com/vaadin/terminal/gwt/client/WidgetLoader.java | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src/com') 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 callbacks = new LinkedList(); - private static int widgetsLoading; + private static int dependenciesLoading; private static ArrayList runningApplications = new ArrayList(); @@ -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 3ec4233c59..ab9520240c 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1618,19 +1618,19 @@ public class ApplicationConnection { } }; - ApplicationConfiguration.runWhenWidgetsLoaded(c); + ApplicationConfiguration.runWhenDependenciesLoaded(c); } private static void loadStyleDependencies(JsArrayString dependencies) { // Assuming no reason to interpret in a defined order ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { public void onResourceLoad(ResourceLoadEvent event) { - ApplicationConfiguration.endWidgetLoading(); + ApplicationConfiguration.endDependencyLoading(); } }; ResourceLoader loader = ResourceLoader.get(); for (int i = 0; i < dependencies.length(); i++) { - ApplicationConfiguration.startWidgetLoading(); + ApplicationConfiguration.startDependencyLoading(); loader.loadStylesheet(dependencies.get(i), resourceLoadListener); } } @@ -1644,20 +1644,20 @@ public class ApplicationConnection { ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { public void onResourceLoad(ResourceLoadEvent event) { if (dependencies.length() != 0) { - ApplicationConfiguration.startWidgetLoading(); + ApplicationConfiguration.startDependencyLoading(); // Load next in chain (hopefully already preloaded) event.getResourceLoader().loadScript(dependencies.shift(), this); } // Call start for next before calling end for current - ApplicationConfiguration.endWidgetLoading(); + ApplicationConfiguration.endDependencyLoading(); } }; ResourceLoader loader = ResourceLoader.get(); // Start chain by loading first - ApplicationConfiguration.startWidgetLoading(); + ApplicationConfiguration.startDependencyLoading(); loader.loadScript(dependencies.shift(), resourceLoadListener); // Preload all remaining 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(); -- cgit v1.2.3 From 48cc0f3973579ee6c5893b27e484afc3c87692ec Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 27 Jun 2012 17:12:49 +0300 Subject: Javadocs for @StyleSheet and @JavaScript (#9044) --- src/com/vaadin/annotations/JavaScript.java | 16 ++++++++++++++++ src/com/vaadin/annotations/StyleSheet.java | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'src/com') diff --git a/src/com/vaadin/annotations/JavaScript.java b/src/com/vaadin/annotations/JavaScript.java index 8e0bc09958..3abe7467ba 100644 --- a/src/com/vaadin/annotations/JavaScript.java +++ b/src/com/vaadin/annotations/JavaScript.java @@ -9,8 +9,24 @@ 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 + * corresponding client-side connector is initialized. + * + * @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/StyleSheet.java b/src/com/vaadin/annotations/StyleSheet.java index 40f75511dd..7056853ff4 100644 --- a/src/com/vaadin/annotations/StyleSheet.java +++ b/src/com/vaadin/annotations/StyleSheet.java @@ -9,8 +9,24 @@ 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 + * corresponding client-side connector is initialized. + * + * @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(); } -- cgit v1.2.3 From 7e4dd75434647514a4f4745ff82db4c4e78a85e5 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 28 Jun 2012 10:24:17 +0300 Subject: Clean non-component connectors also (#8943) Now prints a warning if cleanup is done in ConnectorTracker. It should always be handled by detach(). --- src/com/vaadin/ui/ConnectorTracker.java | 129 +++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 19 deletions(-) (limited to 'src/com') diff --git a/src/com/vaadin/ui/ConnectorTracker.java b/src/com/vaadin/ui/ConnectorTracker.java index 75a75ad22a..1feac99d65 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. *

* 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 it 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. + *

+ * The state and pending RPC calls for dirty connectors are sent to the + * client in the following request. + *

+ * + * @return A collection of all dirty connectors for this root. This list may + * contain invisible connectors. + */ public Collection getDirtyConnectors() { return dirtyConnectors; } -- cgit v1.2.3 From 23bafe0cf09918bc2c80455de1607be0035ee250 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 28 Jun 2012 10:24:48 +0300 Subject: Updated javadoc --- .../terminal/gwt/client/ui/label/ContentMode.java | 22 ++++++++++------------ src/com/vaadin/ui/Label.java | 12 +++++++----- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'src/com') 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/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, } /** - * Gets the value of the label. Value of the label is the XML contents of - * the label. + * Gets the value of the label. + *

+ * 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. + *

* - * @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, /** * @see java.lang.Object#toString() - * @deprecated use the data source value or {@link #getStringValue()} - * instead + * @deprecated Use {@link #getValue()} instead */ @Deprecated @Override -- cgit v1.2.3 From 04bfffbb7e80d023087ced84e6a20a394d284eac Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 28 Jun 2012 10:42:38 +0300 Subject: Fixed typo (#8943) --- src/com/vaadin/ui/ConnectorTracker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/com') diff --git a/src/com/vaadin/ui/ConnectorTracker.java b/src/com/vaadin/ui/ConnectorTracker.java index 1feac99d65..e3d1bf86db 100644 --- a/src/com/vaadin/ui/ConnectorTracker.java +++ b/src/com/vaadin/ui/ConnectorTracker.java @@ -164,7 +164,7 @@ public class ConnectorTracker implements Serializable { .warning( "cleanConnectorMap unregistered connector " + getConnectorAndParentInfo(connector) - + "). This it should have been done when the connector was detached."); + + "). This should have been done when the connector was detached."); iterator.remove(); } } -- cgit v1.2.3 From 41ba62d05946c7aef3998b95c63dd09c6af75c69 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 28 Jun 2012 11:47:55 +0300 Subject: Add error handling to ResourceLoader (#9044) --- .../terminal/gwt/client/ApplicationConnection.java | 17 +- .../vaadin/terminal/gwt/client/ResourceLoader.java | 206 +++++++++++++++++---- 2 files changed, 182 insertions(+), 41 deletions(-) (limited to 'src/com') diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index ab9520240c..c6320f941b 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1624,9 +1624,16 @@ public class ApplicationConnection { private static void loadStyleDependencies(JsArrayString dependencies) { // Assuming no reason to interpret in a defined order ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { - public void onResourceLoad(ResourceLoadEvent event) { + 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++) { @@ -1642,7 +1649,7 @@ public class ApplicationConnection { // Listener that loads the next when one is completed ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { - public void onResourceLoad(ResourceLoadEvent event) { + public void onLoad(ResourceLoadEvent event) { if (dependencies.length() != 0) { ApplicationConfiguration.startDependencyLoading(); // Load next in chain (hopefully already preloaded) @@ -1652,6 +1659,12 @@ public class ApplicationConnection { // 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(); diff --git a/src/com/vaadin/terminal/gwt/client/ResourceLoader.java b/src/com/vaadin/terminal/gwt/client/ResourceLoader.java index 7abafbc216..8c481e0356 100644 --- a/src/com/vaadin/terminal/gwt/client/ResourceLoader.java +++ b/src/com/vaadin/terminal/gwt/client/ResourceLoader.java @@ -10,6 +10,7 @@ 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; @@ -20,6 +21,7 @@ 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 @@ -97,7 +99,9 @@ public class ResourceLoader { */ public interface ResourceLoadListener { /** - * Notified this ResourceLoadListener that a resource has been loaded + * 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 * @@ -105,7 +109,22 @@ public class ResourceLoader { * a resource load event with information about the loaded * resource */ - public void onResourceLoad(ResourceLoadEvent event); + 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 @@ -176,19 +195,27 @@ public class ResourceLoader { 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.onResourceLoad(new ResourceLoadEvent(this, - url, false)); + resourceLoadListener.onLoad(event); } return; } if (preloadListeners.containsKey(url)) { + // Preload going on, continue when preloaded preloadResource(url, new ResourceLoadListener() { - public void onResourceLoad(ResourceLoadEvent event) { + 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; } @@ -197,7 +224,15 @@ public class ResourceLoader { ScriptElement scriptTag = Document.get().createScriptElement(); scriptTag.setSrc(url); scriptTag.setType("text/javascript"); - addOnloadHandler(scriptTag, url, false); + addOnloadHandler(scriptTag, new ResourceLoadListener() { + public void onLoad(ResourceLoadEvent event) { + fireLoad(event); + } + + public void onError(ResourceLoadEvent event) { + fireError(event); + } + }, event); head.appendChild(scriptTag); } } @@ -229,10 +264,11 @@ public class ResourceLoader { 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.onResourceLoad(new ResourceLoadEvent(this, - url, !loadedResources.contains(url))); + resourceLoadListener.onLoad(event); } return; } @@ -243,7 +279,15 @@ public class ResourceLoader { // AND the resources isn't already being loaded in the normal way Element element = getPreloadElement(url); - addOnloadHandler(element, url, true); + 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); @@ -266,24 +310,24 @@ public class ResourceLoader { } } - private native void addOnloadHandler(Element element, String url, - boolean preload) + private native void addOnloadHandler(Element element, + ResourceLoadListener listener, ResourceLoadEvent event) /*-{ - var self = this; - var done = $entry(function() { - element.onloadDone = true; + element.onload = $entry(function() { element.onload = null; + element.onerror = null; element.onreadystatechange = null; - self.@com.vaadin.terminal.gwt.client.ResourceLoader::onResourceLoad(Ljava/lang/String;Z)(url, preload); + 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.onload = function() { - if (!element.onloadDone) { - done(); - } - }; element.onreadystatechange = function() { - if (("loaded" === element.readyState || "complete" === element.readyState) && !element.onloadDone ) { - done(); + if ("loaded" === element.readyState || "complete" === element.readyState ) { + element.onload(arguments[0]); } }; }-*/; @@ -303,19 +347,27 @@ public class ResourceLoader { 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.onResourceLoad(new ResourceLoadEvent(this, - url, false)); + resourceLoadListener.onLoad(event); } return; } if (preloadListeners.containsKey(url)) { + // Preload going on, continue when preloaded preloadResource(url, new ResourceLoadListener() { - public void onResourceLoad(ResourceLoadEvent event) { + 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; } @@ -327,35 +379,92 @@ public class ResourceLoader { linkElement.setHref(url); if (BrowserInfo.get().isSafari()) { - // Safari doesn't fire onload events for link elements + // Safari doesn't fire any events for link elements // See http://www.phpied.com/when-is-a-stylesheet-really-loaded/ - // TODO Stop checking after some timeout Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() { + private final Duration duration = new Duration(); + public boolean execute() { - if (isStyleSheetPresent(url)) { - onResourceLoad(url, false); + 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, url, false); + 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 boolean isStyleSheetPresent(String url) + private static native int getStyleSheetLength(String url) /*-{ for(var i = 0; i < $doc.styleSheets.length; i++) { if ($doc.styleSheets[i].href === url) { - return true; + 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; + } } } - return false; + // No matching stylesheet found -> not yet loaded + return -1; }-*/; private static boolean addListener(String url, @@ -373,26 +482,45 @@ public class ResourceLoader { } } - private void onResourceLoad(String resource, boolean preload) { + private void fireError(ResourceLoadEvent event) { + String resource = event.getResourceUrl(); + + Collection 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 listeners; - if (preload) { + if (event.isPreload()) { preloadedResources.add(resource); listeners = preloadListeners.remove(resource); } else { if (preloadListeners.containsKey(resource)) { // Also fire preload events for potential listeners - onResourceLoad(resource, true); + fireLoad(new ResourceLoadEvent(this, resource, true)); } preloadedResources.remove(resource); loadedResources.add(resource); listeners = loadListeners.remove(resource); } if (listeners != null && !listeners.isEmpty()) { - ResourceLoadEvent event = new ResourceLoadEvent(this, resource, - preload); for (ResourceLoadListener listener : listeners) { if (listener != null) { - listener.onResourceLoad(event); + listener.onLoad(event); } } } -- cgit v1.2.3 From d9822150a389d97c50d9321752b5054ade336d5b Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 28 Jun 2012 11:52:03 +0300 Subject: Define what initialization corresponds to init method in javadoc (#9044) --- src/com/vaadin/annotations/JavaScript.java | 4 ++-- src/com/vaadin/annotations/StyleSheet.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/com') diff --git a/src/com/vaadin/annotations/JavaScript.java b/src/com/vaadin/annotations/JavaScript.java index 3abe7467ba..065c37b78d 100644 --- a/src/com/vaadin/annotations/JavaScript.java +++ b/src/com/vaadin/annotations/JavaScript.java @@ -13,8 +13,8 @@ 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 - * corresponding client-side connector is initialized. + * 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@ diff --git a/src/com/vaadin/annotations/StyleSheet.java b/src/com/vaadin/annotations/StyleSheet.java index 7056853ff4..f8bf635474 100644 --- a/src/com/vaadin/annotations/StyleSheet.java +++ b/src/com/vaadin/annotations/StyleSheet.java @@ -13,8 +13,8 @@ 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 - * corresponding client-side connector is initialized. + * 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@ -- cgit v1.2.3 From 5e46aa3dd23c194a741c4e7c6c5821b6eb3d7a2d Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 28 Jun 2012 15:55:02 +0300 Subject: Support connector:// and use it for relative dependency urls (#9048) --- .../terminal/gwt/client/ApplicationConnection.java | 17 +-- .../gwt/server/AbstractApplicationServlet.java | 27 ++++- .../gwt/server/AbstractCommunicationManager.java | 115 ++++++++++++++++++++- 3 files changed, 148 insertions(+), 11 deletions(-) (limited to 'src/com') diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index c6320f941b..8484d4abea 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1621,7 +1621,7 @@ public class ApplicationConnection { ApplicationConfiguration.runWhenDependenciesLoaded(c); } - private static void loadStyleDependencies(JsArrayString dependencies) { + private void loadStyleDependencies(JsArrayString dependencies) { // Assuming no reason to interpret in a defined order ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { public void onLoad(ResourceLoadEvent event) { @@ -1637,12 +1637,13 @@ public class ApplicationConnection { }; ResourceLoader loader = ResourceLoader.get(); for (int i = 0; i < dependencies.length(); i++) { + String url = translateVaadinUri(dependencies.get(i)); ApplicationConfiguration.startDependencyLoading(); - loader.loadStylesheet(dependencies.get(i), resourceLoadListener); + loader.loadStylesheet(url, resourceLoadListener); } } - private static void loadScriptDependencies(final JsArrayString dependencies) { + private void loadScriptDependencies(final JsArrayString dependencies) { if (dependencies.length() == 0) { return; } @@ -1651,10 +1652,10 @@ public class ApplicationConnection { 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(dependencies.shift(), - this); + event.getResourceLoader().loadScript(url, this); } // Call start for next before calling end for current ApplicationConfiguration.endDependencyLoading(); @@ -1670,8 +1671,9 @@ public class ApplicationConnection { ResourceLoader loader = ResourceLoader.get(); // Start chain by loading first + String url = translateVaadinUri(dependencies.shift()); ApplicationConfiguration.startDependencyLoading(); - loader.loadScript(dependencies.shift(), resourceLoadListener); + loader.loadScript(url, resourceLoadListener); // Preload all remaining for (int i = 0; i < dependencies.length(); i++) { @@ -2284,6 +2286,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; } 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 c65b8947d6..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; @@ -25,7 +27,6 @@ import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; import java.text.StringCharacterIterator; import java.util.ArrayList; -import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; @@ -43,6 +44,8 @@ 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; @@ -157,6 +160,8 @@ public abstract class AbstractCommunicationManager implements Serializable { private Connector highlightedConnector; + private Map> connectoResourceContexts = new HashMap>(); + /** * TODO New constructor - document me! * @@ -1177,13 +1182,16 @@ public abstract class AbstractCommunicationManager implements Serializable { for (Class class1 : newConnectorTypes) { JavaScript jsAnnotation = class1.getAnnotation(JavaScript.class); if (jsAnnotation != null) { - scriptDependencies.addAll(Arrays.asList(jsAnnotation.value())); + for (String resource : jsAnnotation.value()) { + scriptDependencies.add(registerResource(resource, class1)); + } } StyleSheet styleAnnotation = class1.getAnnotation(StyleSheet.class); if (styleAnnotation != null) { - styleDependencies - .addAll(Arrays.asList(styleAnnotation.value())); + for (String resource : styleAnnotation.value()) { + styleDependencies.add(registerResource(resource, class1)); + } } } @@ -1209,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. @@ -2332,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. -- cgit v1.2.3 From a90ab25c53099b21e81872aeded94bcb0fda9edf Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 28 Jun 2012 10:52:17 +0300 Subject: Formatted all source files --- src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java | 4 ++-- src/com/vaadin/terminal/gwt/client/ui/UnknownComponentConnector.java | 1 - src/com/vaadin/tools/WidgetsetCompiler.java | 3 ++- src/com/vaadin/ui/Component.java | 4 ++-- .../com/vaadin/tests/server/component/table/TableSerialization.java | 3 ++- .../testbench/com/vaadin/tests/application/ThreadLocalInstances.java | 3 +-- tests/testbench/com/vaadin/tests/components/AbstractTestRoot.java | 3 +-- 7 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src/com') 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/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/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/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 { *

* 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. *

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/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(); -- cgit v1.2.3 From 4ef39f3e80f7c208c68038968b8dfd157cc25c93 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 28 Jun 2012 11:20:38 +0300 Subject: AbstractMedia should be abstract (#9053) --- src/com/vaadin/ui/AbstractMedia.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/com') 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() { -- cgit v1.2.3 From 92784107eddb53bd1a5f651775937a3caf2eeae0 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 28 Jun 2012 11:24:05 +0300 Subject: AbstractJavascriptComponent should be abstract (#9054) --- src/com/vaadin/ui/AbstractJavaScriptComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/com') 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); -- cgit v1.2.3 From 18ac8b25501e28cfcfc3271d2c6722a00fa01b98 Mon Sep 17 00:00:00 2001 From: Sami Viitanen Date: Thu, 28 Jun 2012 15:43:11 +0300 Subject: Tooltips are now handled by the connector and not the widget (#8425) --- .../terminal/gwt/client/ApplicationConnection.java | 99 +--------- .../terminal/gwt/client/ComponentConnector.java | 11 ++ .../vaadin/terminal/gwt/client/ConnectorMap.java | 38 ---- .../vaadin/terminal/gwt/client/TooltipInfo.java | 19 ++ src/com/vaadin/terminal/gwt/client/VCaption.java | 27 ++- src/com/vaadin/terminal/gwt/client/VTooltip.java | 214 +++++++++++++++------ .../gwt/client/ui/AbstractComponentConnector.java | 29 ++- .../terminal/gwt/client/ui/button/VButton.java | 5 - .../terminal/gwt/client/ui/checkbox/VCheckBox.java | 4 - .../gwt/client/ui/combobox/VFilterSelect.java | 22 +-- .../gwt/client/ui/datefield/VDateField.java | 11 -- .../ui/draganddropwrapper/VDragAndDropWrapper.java | 12 -- .../terminal/gwt/client/ui/embedded/VEmbedded.java | 2 - .../client/ui/formlayout/FormLayoutConnector.java | 35 ++++ .../gwt/client/ui/formlayout/VFormLayout.java | 21 +- .../terminal/gwt/client/ui/label/VLabel.java | 4 - .../vaadin/terminal/gwt/client/ui/link/VLink.java | 5 - .../gwt/client/ui/listselect/TooltipListBox.java | 41 ---- .../gwt/client/ui/listselect/VListSelect.java | 15 +- .../terminal/gwt/client/ui/menubar/VMenuBar.java | 30 --- .../gwt/client/ui/nativebutton/VNativeButton.java | 6 - .../gwt/client/ui/nativeselect/VNativeSelect.java | 16 +- .../AbstractOrderedLayoutConnector.java | 1 + .../gwt/client/ui/panel/PanelConnector.java | 1 + .../terminal/gwt/client/ui/panel/VPanel.java | 4 - .../gwt/client/ui/popupview/VPopupView.java | 10 - .../terminal/gwt/client/ui/slider/VSlider.java | 6 - .../gwt/client/ui/table/TableConnector.java | 25 +++ .../terminal/gwt/client/ui/table/VScrollTable.java | 70 +++---- .../gwt/client/ui/tabsheet/TabsheetConnector.java | 30 ++- .../terminal/gwt/client/ui/tabsheet/VTabsheet.java | 16 +- .../gwt/client/ui/textfield/VTextField.java | 5 - .../terminal/gwt/client/ui/tree/TreeConnector.java | 47 ++++- .../vaadin/terminal/gwt/client/ui/tree/VTree.java | 21 +- .../terminal/gwt/client/ui/upload/VUpload.java | 11 -- .../terminal/gwt/client/ui/window/VWindow.java | 5 - .../abstractcomponent/AllComponentTooltipTest.java | 50 +++++ .../components/abstractcomponent/TooltipTests.html | 77 ++++++++ .../components/abstractcomponent/TooltipTests.java | 97 ++++++++++ 39 files changed, 649 insertions(+), 493 deletions(-) delete mode 100644 src/com/vaadin/terminal/gwt/client/ui/listselect/TooltipListBox.java create mode 100644 tests/testbench/com/vaadin/tests/components/abstractcomponent/AllComponentTooltipTest.java create mode 100644 tests/testbench/com/vaadin/tests/components/abstractcomponent/TooltipTests.html create mode 100644 tests/testbench/com/vaadin/tests/components/abstractcomponent/TooltipTests.java (limited to 'src/com') diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 8484d4abea..da4dfa08dc 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -35,7 +35,6 @@ 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; @@ -2323,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() { @@ -2400,34 +2350,6 @@ public class ApplicationConnection { return rootConnector; } - /** - * If component has several tooltips in addition to the one provided by - * {@link com.vaadin.ui.AbstractComponent}, component can register them with - * this method. - *

- * Component must also pipe events to - * {@link #handleTooltipEvent(Event, ComponentConnector, Object)} method. - *

- * 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. * @@ -2510,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 @@ -2546,17 +2468,6 @@ public class ApplicationConnection { return false; } - @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), 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,48 +200,10 @@ 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 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}. * 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/ui/AbstractComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java index f0b9d518ca..2f55cc4d16 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java @@ -5,6 +5,7 @@ package com.vaadin.terminal.gwt.client.ui; 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; @@ -37,6 +38,12 @@ public abstract class AbstractComponentConnector extends AbstractConnector public AbstractComponentConnector() { } + @Override + protected void init() { + super.init(); + getConnection().getVTooltip().connectHandlersToWidget(getWidget()); + } + /** * Creates and returns the widget for this VPaintableWidget. This method * should only be called once when initializing the paintable. @@ -99,16 +106,6 @@ public abstract class AbstractComponentConnector extends AbstractConnector 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()); - // Set captions if (delegateCaptionHandling()) { ServerConnector parent = getParent(); @@ -315,4 +312,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/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/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/VEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java index 203e7362f3..5edd31174d 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java +++ b/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java @@ -232,8 +232,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/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 cellToolTips = new HashMap(); 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 tooltipMap = new HashMap(); + 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/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 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 @@ + + + + + + +TooltipTests + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TooltipTests
open/run/com.vaadin.tests.components.abstractcomponent.TooltipTests?restartApplication
showTooltip//div[@id='label']
screenCaptureno_tooltip
mouseClickvaadin=runcomvaadintestscomponentsabstractcomponentTooltipTests::/VVerticalLayout[0]/VVerticalLayout[0]/VHorizontalLayout[0]/VCheckBox[0]/domChild[0]10,7
showTooltip//div[@id='label']
screenCapturepanel_tooltip
mouseClickvaadin=runcomvaadintestscomponentsabstractcomponentTooltipTests::/VVerticalLayout[0]/VVerticalLayout[0]/VHorizontalLayout[0]/VCheckBox[1]/domChild[0]8,6
showTooltip//div[@id='label']
screenCapturelayout_tooltip
mouseClickvaadin=runcomvaadintestscomponentsabstractcomponentTooltipTests::/VVerticalLayout[0]/VVerticalLayout[0]/VHorizontalLayout[0]/VCheckBox[2]/domChild[0]5,5
showTooltip//div[@id='label']
screenCapturelabel_tooltip
+ + 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(""); + } + } + + }; + +} -- cgit v1.2.3 From e9b1233e49b66c97f5237538e8299ad75aa9c88b Mon Sep 17 00:00:00 2001 From: Pekka Hyvönen Date: Thu, 28 Jun 2012 16:42:33 +0300 Subject: Fixed connector so it no longer overwrites all style attributes (#8664) --- .../gwt/client/ui/AbstractComponentConnector.java | 156 +++++-- .../gwt/client/ui/AbstractFieldConnector.java | 21 +- .../ui/datefield/AbstractDateFieldConnector.java | 14 +- .../ui/datefield/PopupDateFieldConnector.java | 34 +- .../gwt/client/ui/embedded/EmbeddedConnector.java | 22 + .../terminal/gwt/client/ui/embedded/VEmbedded.java | 1 + .../components/AddRemoveSetStyleNamesTest.html | 456 +++++++++++++++++++++ .../components/AddRemoveSetStyleNamesTest.java | 81 ++++ 8 files changed, 714 insertions(+), 71 deletions(-) create mode 100644 tests/testbench/com/vaadin/tests/components/AddRemoveSetStyleNamesTest.html create mode 100644 tests/testbench/com/vaadin/tests/components/AddRemoveSetStyleNamesTest.java (limited to 'src/com') diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java index 2f55cc4d16..6105c545f6 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java @@ -3,6 +3,8 @@ */ 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; @@ -22,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,6 +35,12 @@ public abstract class AbstractComponentConnector extends AbstractConnector private String lastKnownWidth = ""; private String lastKnownHeight = ""; + /** + * The style names from getState().getStyles() which are currently applied + * to the widget. + */ + protected List styleNames = new ArrayList(); + /** * Default constructor */ @@ -41,7 +50,11 @@ public abstract class AbstractComponentConnector extends AbstractConnector @Override protected void init() { super.init(); + getConnection().getVTooltip().connectHandlersToWidget(getWidget()); + + // Set v-connector style names for the widget + getWidget().setStyleName("v-connector", true); } /** @@ -103,8 +116,7 @@ public abstract class AbstractComponentConnector extends AbstractConnector super.onStateChanged(stateChangeEvent); // Style names - String styleName = getStyleNames(getWidget().getStylePrimaryName()); - getWidget().setStyleName(styleName); + updateWidgetStyleNames(); // Set captions if (delegateCaptionHandling()) { @@ -127,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(); @@ -210,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()} *

* This method can be overridden to provide additional style names for the - * component + * component, for example see + * {@link AbstractFieldConnector#updateWidgetStyleNames()} *

- * - * @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 newStyles = new ArrayList(); + 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); - } + } - return styleBuf.toString(); + /** + * This is used to add / remove state related style names from the widget. + *

+ * 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()}. + *

+ * + * @param styleName + * the style name to be added or removed + * @param add + * true to add the given style, false + * to remove it + */ + protected void setWidgetStyleName(String styleName, boolean add) { + getWidget().setStyleName(styleName, add); + } + + /** + * This is used to add / remove state related prefixed style names from the + * widget. + *

+ * Override this method if the prefixed style name given here should be + * updated in another widget in addition to the one returned by the + * Connector's {@link #getWidget()}, or if the prefix should be + * different. For example see + * {@link PopupDateFieldConnector#setWidgetStyleNameWithPrefix(String, String, boolean)} + *

+ * + * @param styleName + * the style name to be added or removed + * @param add + * true to add the given style, false + * 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); } /* 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/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/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 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 5edd31174d..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; 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 @@ + + + + + + +AddRemoveSetStyleNamesTest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddRemoveSetStyleNamesTest
openrun/com.vaadin.tests.components.AddRemoveSetStyleNamesTest?restartApplication
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style1
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style1
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style2
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style2
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style2
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style2
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style2
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style2
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style2
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style2
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style2
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style2
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style2
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style2
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]thestyle
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-thestyle
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-thestyle
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]thestyle
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]thestyle
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-thestyle
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-thestyle
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]thestyle
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]thestyle
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-thestyle
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style1
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-thestyle
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]thestyle
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-thestyle
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]thestyle
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-thestyle
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]thestyle
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]v-datefield-thestyle
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]thestyle
mouseClickvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::/VVerticalLayout[0]/VVerticalLayout[0]/VPopupCalendar[0]#popupButton
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-style1
assertCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]style1
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]v-datefield-popup-thestyle
assertNotCSSClassvaadin=runcomvaadintestscomponentsAddRemoveSetStyleNamesTest::Root/VOverlay[0]thestyle
+ + 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 -- cgit v1.2.3