Revision: 7093 Author: jlaba...@google.com Date: Fri Nov 20 16:14:24 2009 Log: tr...@7092 was merged into this branch Fired onload events for images that are cached. svn merge --ignore-ancestry -c 7092 https://google-web-toolkit.googlecode.com/svn/trunk .
Patch by: jlabanca http://code.google.com/p/google-web-toolkit/source/detail?r=7093 Modified: /releases/2.0/branch-info.txt /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java /releases/2.0/user/src/com/google/gwt/user/client/ui/Image.java /releases/2.0/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java /releases/2.0/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java /releases/2.0/user/test/com/google/gwt/resources/client/ImageResourceTest.java /releases/2.0/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java /releases/2.0/user/test/com/google/gwt/user/client/ui/ImageTest.java /releases/2.0/user/test/com/google/gwt/user/client/ui/TreeItemTest.java /releases/2.0/user/test/com/google/gwt/user/client/ui/TreeTest.java ======================================= --- /releases/2.0/branch-info.txt Fri Nov 20 15:48:57 2009 +++ /releases/2.0/branch-info.txt Fri Nov 20 16:14:24 2009 @@ -950,3 +950,7 @@ Tweaks to get restart server up and running. svn merge --ignore-ancestry -c 7089 https://google-web-toolkit.googlecode.com/svn/trunk . +tr...@7092 was merged into this branch + Fired onload events for images that are cached. + svn merge --ignore-ancestry -c 7092 https://google-web-toolkit.googlecode.com/svn/trunk . + ======================================= --- /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java Tue Jul 21 07:10:53 2009 +++ /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java Fri Nov 20 16:14:24 2009 @@ -59,7 +59,7 @@ elem.onscroll = (bits & 0x04000) ? @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null; elem.onload = (bits & 0x08000) ? - @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null; + @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent : null; elem.onerror = (bits & 0x10000) ? @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null; elem.onmousewheel = (bits & 0x20000) ? ======================================= --- /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java Fri Oct 16 14:48:33 2009 +++ /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java Fri Nov 20 16:14:24 2009 @@ -38,6 +38,9 @@ @SuppressWarnings("unused") private static JavaScriptObject dispatchEvent; + @SuppressWarnings("unused") + private static JavaScriptObject dispatchUnhandledEvent; + @Override public Element eventGetFromElement(Event evt) { if (evt.getType().equals("mouseover")) { @@ -165,6 +168,11 @@ return true; }); + @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent = $entry(function(evt) { + this.__gwtLastUnhandledEvent = evt.type; + @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent.call(this, evt); + }); + @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent = $entry(function(evt) { var listener, curElem = this; while (curElem && !(listener = curElem.__listener)) { @@ -231,7 +239,7 @@ if (chMask & 0x04000) elem.onscroll = (bits & 0x04000) ? @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null; if (chMask & 0x08000) elem.onload = (bits & 0x08000) ? - @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null; + @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent : null; if (chMask & 0x10000) elem.onerror = (bits & 0x10000) ? @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null; if (chMask & 0x20000) elem.onmousewheel = (bits & 0x20000) ? ======================================= --- /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java Mon Nov 2 12:44:54 2009 +++ /releases/2.0/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java Fri Nov 20 16:14:24 2009 @@ -31,6 +31,9 @@ @SuppressWarnings("unused") private static JavaScriptObject dispatchDblClickEvent; + @SuppressWarnings("unused") + private static JavaScriptObject dispatchUnhandledEvent; + /** * Let every GWT app on the page preview the current event. If any app cancels * the event, the event will be canceled for all apps. @@ -151,6 +154,11 @@ } }); + @com.google.gwt.user.client.impl.DOMImplTrident::dispatchUnhandledEvent = $entry(function() { + this.__gwtLastUnhandledEvent = $wnd.event.type; + @com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent.call(this); + }); + // We need to create these delegate functions to fix up the 'this' context. // Normally, 'this' is the firing element, but this is only true for // 'onclick = ...' event handlers, not for handlers setup via attachEvent(). @@ -243,7 +251,7 @@ if (chMask & 0x04000) elem.onscroll = (bits & 0x04000) ? @com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent : null; if (chMask & 0x08000) elem.onload = (bits & 0x08000) ? - @com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent : null; + @com.google.gwt.user.client.impl.DOMImplTrident::dispatchUnhandledEvent : null; if (chMask & 0x10000) elem.onerror = (bits & 0x10000) ? @com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent : null; if (chMask & 0x20000) elem.onmousewheel = (bits & 0x20000) ? ======================================= --- /releases/2.0/user/src/com/google/gwt/user/client/ui/Image.java Thu Oct 8 12:27:08 2009 +++ /releases/2.0/user/src/com/google/gwt/user/client/ui/Image.java Fri Nov 20 16:14:24 2009 @@ -1,12 +1,12 @@ /* * Copyright 2008 Google Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -19,6 +19,7 @@ import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.ImageElement; +import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ErrorEvent; @@ -43,6 +44,8 @@ import com.google.gwt.event.dom.client.MouseWheelHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.impl.ClippedImageImpl; @@ -57,16 +60,20 @@ * image is constructed, and how it is transformed after construction. Methods * will operate differently depending on the mode that the image is in. These * differences are detailed in the documentation for each method. - * + * * <p> * If an image transitions between clipped mode and unclipped mode, any * {...@link Element}-specific attributes added by the user (including style * attributes, style names, and style modifiers), except for event listeners, * will be lost. * </p> - * - * <h3>CSS Style Rules</h3> <ul class="css"> <li>.gwt-Image { }</li> </ul> - * + * + * <h3>CSS Style Rules</h3> + * <dl> + * <dt>.gwt-Image</dt> + * </dd>The outer element</dd> + * </dl> + * * Tranformations between clipped and unclipped state will result in a loss of * any style names that were set/added; the only style names that are preserved * are those that are mentioned in the static CSS style rules. Due to @@ -75,7 +82,7 @@ * expected when an image is in clipped mode. These limitations can usually be * easily worked around by encapsulating the image in a container widget that * can itself be styled. - * + * * <p> * <h3>Example</h3> * {...@example com.google.gwt.examples.ImageExample} @@ -86,6 +93,12 @@ HasLoadHandlers, HasErrorHandlers, SourcesClickEvents, HasClickHandlers, HasAllMouseHandlers, SourcesMouseEvents { + /** + * The attribute that is set when an image fires a native load or error event + * before it is attached. + */ + private static final String UNHANDLED_EVENT_ATTR = "__gwtLastUnhandledEvent"; + /** * Implementation of behaviors associated with the clipped state of an image. */ @@ -117,6 +130,11 @@ public int getHeight(Image image) { return height; } + + @Override + public ImageElement getImageElement(Image image) { + return impl.getImgElement(image).cast(); + } @Override public int getOriginLeft() { @@ -140,7 +158,10 @@ @Override public void setUrl(Image image, String url) { - image.changeState(new UnclippedState(image, url)); + image.changeState(new UnclippedState(image)); + // Need to make sure we change the state before an onload event can fire, + // or handlers will be fired while we are in the old state. + image.setUrl(url); } @Override @@ -156,7 +177,7 @@ this.height = height; impl.adjust(image.getElement(), url, left, top, width, height); - impl.fireSyntheticLoadEvent(image); + fireSyntheticLoadEvent(image); } } @@ -177,7 +198,7 @@ this.height = height; impl.adjust(image.getElement(), url, left, top, width, height); - impl.fireSyntheticLoadEvent(image); + fireSyntheticLoadEvent(image); } } @@ -196,6 +217,8 @@ public abstract int getHeight(Image image); + public abstract ImageElement getImageElement(Image image); + public abstract int getOriginLeft(); public abstract int getOriginTop(); @@ -204,6 +227,16 @@ public abstract int getWidth(Image image); + public void onLoad(Image image) { + // If an onload event fired while the image wasn't attached, we need to + // synthesize one now. + String unhandledEvent = getImageElement(image).getPropertyString( + UNHANDLED_EVENT_ATTR); + if ("load".equals(unhandledEvent)) { + fireSyntheticLoadEvent(image); + } + } + public abstract void setUrl(Image image, String url); public abstract void setUrlAndVisibleRect(Image image, String url, @@ -211,6 +244,27 @@ public abstract void setVisibleRect(Image image, int left, int top, int width, int height); + + /** + * We need to synthesize a load event in case the image loads synchronously, + * before our handlers can be attached. + * + * @param image the image on which to dispatch the event + */ + protected void fireSyntheticLoadEvent(final Image image) { + /* + * We use a deferred command here to simulate the native version of the + * event as closely as possible. In the native event case, it is unlikely + * that a second load event would occur while you are in the load event + * handler. + */ + DeferredCommand.addCommand(new Command() { + public void execute() { + NativeEvent evt = Document.get().createLoadEvent(); + getImageElement(image).dispatchEvent(evt); + } + }); + } // This method is used only by unit tests. protected abstract String getStateName(); @@ -248,7 +302,12 @@ @Override public int getHeight(Image image) { - return image.getImageElement().getHeight(); + return getImageElement(image).getHeight(); + } + + @Override + public ImageElement getImageElement(Image image) { + return image.getElement().cast(); } @Override @@ -263,17 +322,18 @@ @Override public String getUrl(Image image) { - return image.getImageElement().getSrc(); + return getImageElement(image).getSrc(); } @Override public int getWidth(Image image) { - return image.getImageElement().getWidth(); + return getImageElement(image).getWidth(); } @Override public void setUrl(Image image, String url) { - image.getImageElement().setSrc(url); + image.clearUnhandledEvent(); + getImageElement(image).setSrc(url); } @Override @@ -305,7 +365,7 @@ /** * Causes the browser to pre-fetch the image at a given URL. - * + * * @param url the URL of the image to be prefetched */ public static void prefetch(String url) { @@ -316,11 +376,11 @@ /** * Creates a Image widget that wraps an existing <img> element. - * + * * This element must already be attached to the document. If the element is * removed from the document, you must call * {...@link RootPanel#detachNow(Widget)}. - * + * * @param element the element to be wrapped */ public static Image wrap(Element element) { @@ -349,18 +409,18 @@ /** * Creates an image whose size and content are defined by an ImageResource. - * + * * @param resource the ImageResource to be displayed */ public Image(ImageResource resource) { - this(resource.getURL(), resource.getLeft(), - resource.getTop(), resource.getWidth(), resource.getHeight()); + this(resource.getURL(), resource.getLeft(), resource.getTop(), + resource.getWidth(), resource.getHeight()); } /** * Creates an image with a specified URL. The load event will be fired once * the image at the given URL has been retrieved by the browser. - * + * * @param url the URL of the image to be displayed */ public Image(String url) { @@ -377,7 +437,7 @@ * the width and height are specified explicitly by the user, this behavior * will not cause problems with retrieving the width and height of a clipped * image in a load event handler. - * + * * @param url the URL of the image to be displayed * @param left the horizontal co-ordinate of the upper-left vertex of the * visibility rectangle @@ -394,7 +454,7 @@ /** * This constructor may be used by subclasses to explicitly use an existing * element. This element must be an <img> element. - * + * * @param element the element to be used */ protected Image(Element element) { @@ -436,9 +496,9 @@ } /** - * @deprecated Use {...@link #addMouseOverHandler} {...@link - * #addMouseMoveHandler}, {...@link #addMouseDownHandler}, {...@link - * #addMouseUpHandler} and {...@link #addMouseOutHandler} instead + * @deprecated Use {...@link #addMouseOverHandler} {...@link #addMouseMoveHandler}, + * {...@link #addMouseDownHandler}, {...@link #addMouseUpHandler} and + * {...@link #addMouseOutHandler} instead */ @Deprecated public void addMouseListener(MouseListener listener) { @@ -477,7 +537,7 @@ * Gets the height of the image. When the image is in the unclipped state, the * height of the image is not known until the image has been loaded (i.e. load * event has been fired for the image). - * + * * @return the height of the image, or 0 if the height is unknown */ public int getHeight() { @@ -489,7 +549,7 @@ * visibility rectangle. If the image is in the unclipped state, then the * visibility rectangle is assumed to be the rectangle which encompasses the * entire image, which has an upper-left vertex of (0,0). - * + * * @return the horizontal co-ordinate of the upper-left vertex of the image's * visibility rectangle */ @@ -502,7 +562,7 @@ * visibility rectangle. If the image is in the unclipped state, then the * visibility rectangle is assumed to be the rectangle which encompasses the * entire image, which has an upper-left vertex of (0,0). - * + * * @return the vertical co-ordinate of the upper-left vertex of the image's * visibility rectangle */ @@ -514,7 +574,7 @@ * Gets the URL of the image. The URL that is returned is not necessarily the * URL that was passed in by the user. It may have been transformed to an * absolute URL. - * + * * @return the image URL */ public String getUrl() { @@ -525,16 +585,27 @@ * Gets the width of the image. When the image is in the unclipped state, the * width of the image is not known until the image has been loaded (i.e. load * event has been fired for the image). - * + * * @return the width of the image, or 0 if the width is unknown */ public int getWidth() { return state.getWidth(this); } + + @Override + public void onBrowserEvent(Event event) { + // We have to clear the unhandled event before firing handlers because the + // handlers could trigger onLoad, which would refire the event. + if (event.getTypeInt() == Event.ONLOAD) { + clearUnhandledEvent(); + } + + super.onBrowserEvent(event); + } /** - * @deprecated Use the {...@link HandlerRegistration#removeHandler} method on - * the object returned by {...@link #addClickHandler} instead + * @deprecated Use the {...@link HandlerRegistration#removeHandler} method on the + * object returned by {...@link #addClickHandler} instead */ @Deprecated public void removeClickListener(ClickListener listener) { @@ -542,8 +613,8 @@ } /** - * @deprecated Use the {...@link HandlerRegistration#removeHandler} - * method on the object returned by an add*Handler method instead + * @deprecated Use the {...@link HandlerRegistration#removeHandler} method on the + * object returned by an add*Handler method instead */ @Deprecated public void removeLoadListener(LoadListener listener) { @@ -551,8 +622,8 @@ } /** - * @deprecated Use the {...@link HandlerRegistration#removeHandler} - * method on the object returned by an add*Handler method instead + * @deprecated Use the {...@link HandlerRegistration#removeHandler} method on the + * object returned by an add*Handler method instead */ @Deprecated public void removeMouseListener(MouseListener listener) { @@ -560,9 +631,8 @@ } /** - * @deprecated Use the {...@link HandlerRegistration#removeHandler} - * method on the object returned by {...@link #addMouseWheelHandler} - * instead + * @deprecated Use the {...@link HandlerRegistration#removeHandler} method on the + * object returned by {...@link #addMouseWheelHandler} instead */ @Deprecated public void removeMouseWheelListener(MouseWheelListener listener) { @@ -576,7 +646,7 @@ * image's current url or current visibility rectangle co-ordinates. If the * image is currently in the unclipped state, a call to this method will cause * a transition to the clipped state. - * + * * @param resource the ImageResource to display */ public void setResource(ImageResource resource) { @@ -589,7 +659,7 @@ * state, a call to this method will cause a transition of the image to the * unclipped state. Regardless of whether or not the image is in the clipped * or unclipped state, a load event will be fired. - * + * * @param url the image URL */ public void setUrl(String url) { @@ -603,7 +673,7 @@ * visibility rectangle co-ordinates. If the image is currently in the * unclipped state, a call to this method will cause a transition to the * clipped state. - * + * * @param url the image URL * @param left the horizontal coordinate of the upper-left vertex of the * visibility rectangle @@ -626,7 +696,7 @@ * is in the unclipped state, a call to this method will cause a transition of * the image to the clipped state. This transition will cause a load event to * fire. - * + * * @param left the horizontal coordinate of the upper-left vertex of the * visibility rectangle * @param top the vertical coordinate of the upper-left vertex of the @@ -637,12 +707,26 @@ public void setVisibleRect(int left, int top, int width, int height) { state.setVisibleRect(this, left, top, width, height); } + + @Override + protected void onLoad() { + super.onLoad(); + + // Issue 863: the state may need to fire a synthetic event if the native + // onload event fired while the image was detached. + state.onLoad(this); + } private void changeState(State newState) { state = newState; } - private ImageElement getImageElement() { - return getElement().cast(); + /** + * Clear the unhandled event. + */ + private void clearUnhandledEvent() { + if (state != null) { + state.getImageElement(this).setPropertyString(UNHANDLED_EVENT_ATTR, ""); + } } } ======================================= --- /releases/2.0/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java Fri Feb 6 13:06:24 2009 +++ /releases/2.0/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java Fri Nov 20 16:14:24 2009 @@ -1,12 +1,12 @@ /* * Copyright 2008 Google Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -18,22 +18,19 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.NativeEvent; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.ui.Image; /** * Uses a combination of a clear image and a background image to clip all except * a desired portion of an underlying image. - * + * * Do not use this class - it is used for implementation only, and its methods * may change in the future. */ public class ClippedImageImpl { public void adjust(Element img, String url, int left, int top, int width, - int height) { + int height) { String style = "url(" + url + ") no-repeat " + (-left + "px ") + (-top + "px"); img.getStyle().setProperty("background", style); @@ -42,7 +39,7 @@ } public Element createStructure(String url, int left, int top, int width, - int height) { + int height) { Element tmp = Document.get().createSpanElement(); tmp.setInnerHTML(getHTML(url, left, top, width, height)); return tmp.getFirstChildElement(); @@ -53,31 +50,15 @@ + "px; background: url(" + url + ") no-repeat " + (-left + "px ") + (-top + "px"); - String clippedImgHtml = "<img src='" + GWT.getModuleBaseURL() + - "clear.cache.gif' style='" + style + "' border='0'>"; + String clippedImgHtml = "<img " + + "onload='this.__gwtLastUnhandledEvent=\"load\";' src='" + + GWT.getModuleBaseURL() + "clear.cache.gif' style='" + style + + "' border='0'>"; return clippedImgHtml; } - public void fireSyntheticLoadEvent(final Image image) { - /* - * We need to synthesize a load event, because the native events that are - * fired would correspond to the loading of clear.cache.gif, which is - * incorrect. A native event would not even fire in Internet Explorer, - * because the root element is a wrapper element around the <img> element. - * Since we are synthesizing a load event, we do not need to sink the - * onload event. - * - * We use a deferred command here to simulate the native version of the - * load event as closely as possible. In the native event case, it is - * unlikely that a second load event would occur while you are in the load - * event handler. - */ - DeferredCommand.addCommand(new Command() { - public void execute() { - NativeEvent evt = Document.get().createLoadEvent(); - image.getElement().dispatchEvent(evt); - } - }); + public Element getImgElement(Image image) { + return image.getElement(); } } ======================================= --- /releases/2.0/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java Tue Nov 10 14:44:37 2009 +++ /releases/2.0/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java Fri Nov 20 16:14:24 2009 @@ -16,11 +16,7 @@ package com.google.gwt.user.client.ui.impl; import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.NativeEvent; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Image; @@ -112,25 +108,6 @@ Event.sinkEvents(img, Event.ONLOAD); return clipper; } - - public void fireSyntheticLoadEvent(final Image image) { - if (!isIE6) { - super.fireSyntheticLoadEvent(image); - return; - } - - // This is the same as the superclass' implementation, except that it - // explicitly checks for the 'clipper' element, and dispatches the event - // on the img (you can't dispatch events on the clipper). - DeferredCommand.addCommand(new Command() { - public void execute() { - NativeEvent evt = Document.get().createLoadEvent(); - Element clipper = image.getElement(); - Element img = clipper.getFirstChildElement(); - img.dispatchEvent(evt); - } - }); - } @Override public String getHTML(String url, int left, int top, int width, int height) { @@ -158,7 +135,7 @@ */ String clippedImgHtml = "<gwt:clipper style=\"" + clipperStyle - + "\"><img src='" + + "\"><img onload='this.__gwtLastUnhandledEvent=\"load\";' src='" + moduleBaseUrlProtocol + "' onerror='if(window.__gwt_transparentImgHandler)window.__gwt_transparentImgHandler(this);else this.src=\"" + GWT.getModuleBaseURL() + "clear.cache.gif\"' style=\"" + imgStyle + "\" width=" + (left + width) + " height=" + (top + height) @@ -166,4 +143,12 @@ return clippedImgHtml; } -} + + @Override + public Element getImgElement(Image image) { + if (!isIE6) { + return super.getImgElement(image); + } + return image.getElement().getFirstChildElement(); + } +} ======================================= --- /releases/2.0/user/test/com/google/gwt/resources/client/ImageResourceTest.java Wed Sep 30 16:46:38 2009 +++ /releases/2.0/user/test/com/google/gwt/resources/client/ImageResourceTest.java Fri Nov 20 16:14:24 2009 @@ -92,13 +92,7 @@ assertFalse(a.getURL().equals(r.i16x16().getURL())); } - /** - * Issue 863: Image.onload event does not fire on Internet Explorer when image - * is in cache. - * - * TODO(jlabanca): Reenable this test after fixing the issue. - */ - public void disabledTestDedup() { + public void testDedup() { Resources r = GWT.create(Resources.class); ImageResource a = r.i64x64(); ======================================= --- /releases/2.0/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java Mon Nov 16 11:27:22 2009 +++ /releases/2.0/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java Fri Nov 20 16:14:24 2009 @@ -41,6 +41,7 @@ /** * Functional test of UiBinder. */ +...@donotrunwith({Platform.HtmlUnit}) public class UiBinderTest extends GWTTestCase { private WidgetBasedUi widgetUi; private DomBasedUi domUi; ======================================= --- /releases/2.0/user/test/com/google/gwt/user/client/ui/ImageTest.java Mon Nov 2 12:50:41 2009 +++ /releases/2.0/user/test/com/google/gwt/user/client/ui/ImageTest.java Fri Nov 20 16:14:24 2009 @@ -1,12 +1,12 @@ /* * Copyright 2008 Google Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -27,12 +27,13 @@ import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.user.client.Timer; /** * Tests for the Image widget. Images in both clipped mode and unclipped mode * are tested, along with the transitions between the two modes. */ -...@suppresswarnings("deprecation") +...@donotrunwith({Platform.HtmlUnit}) public class ImageTest extends GWTTestCase { interface Bundle extends ClientBundle { ImageResource prettyPiccy(); @@ -49,6 +50,24 @@ fail("The image " + image.getUrl() + " failed to load."); } } + + private abstract static class TestLoadHandler implements LoadHandler { + private boolean finished = false; + + /** + * Mark the test as finished. + */ + public void finish() { + finished = true; + } + + /** + * @return true if the test has finished + */ + public boolean isFinished() { + return finished; + } + } @Deprecated private abstract static class TestLoadListener implements LoadListener { @@ -82,7 +101,7 @@ * Helper method that allows us to 'peek' at the private <code>state</code> * field in the Image object, and call the <code>state.getStateName()</code> * method. - * + * * @param image The image instance * @return "unclipped" if image is in the unclipped state, or "clipped" if the * image is in the clipped state @@ -95,26 +114,25 @@ private int firedError; private int firedLoad; + + @Override + public String getModuleName() { + return "com.google.gwt.user.UserTest"; + } /** * Tests the transition from the clipped state to the unclipped state. - * - * Disabled because of issue #863 & #864. It fails intermittently in linux - * hosted mode tests. */ - public void disabledTestChangeClippedImageToUnclipped() { + public void testChangeClippedImageToUnclipped() { final Image image = new Image("counting-forwards.png", 12, 13, 8, 8); assertEquals("clipped", getCurrentImageStateName(image)); delayTestFinish(5000); - image.addLoadListener(new LoadListener() { + image.addErrorHandler(new TestErrorHandler(image)); + image.addLoadHandler(new LoadHandler() { private int onLoadEventCount = 0; - public void onError(Widget sender) { - fail("The image " + ((Image) sender).getUrl() + " failed to load."); - } - - public void onLoad(Widget sender) { + public void onLoad(LoadEvent event) { ++onLoadEventCount; if (onLoadEventCount == 1) { // Set the url after the first image loads image.setUrl("counting-forwards.png"); @@ -134,22 +152,17 @@ /** * Tests the transition from the unclipped state to the clipped state. - * - * Disabled because of issue #863. */ - public void disabledTestChangeImageToClipped() { + public void testChangeImageToClipped() { final Image image = new Image("counting-forwards.png"); assertEquals("unclipped", getCurrentImageStateName(image)); delayTestFinish(5000); - image.addLoadListener(new LoadListener() { + image.addErrorHandler(new TestErrorHandler(image)); + image.addLoadHandler(new LoadHandler() { private int onLoadEventCount = 0; - public void onError(Widget sender) { - fail("The image " + ((Image) sender).getUrl() + " failed to load."); - } - - public void onLoad(Widget sender) { + public void onLoad(LoadEvent event) { if (getCurrentImageStateName(image).equals("unclipped")) { image.setVisibleRect(12, 13, 8, 8); } @@ -170,21 +183,16 @@ /** * Tests the creation of an image in unclipped mode. - * - * Disabled because of issue #863 & #864. */ - public void disabledTestCreateImage() { + public void testCreateImage() { final Image image = new Image("counting-forwards.png"); delayTestFinish(5000); - image.addLoadListener(new LoadListener() { + image.addErrorHandler(new TestErrorHandler(image)); + image.addLoadHandler(new LoadHandler() { private int onLoadEventCount = 0; - public void onError(Widget sender) { - fail("The image " + ((Image) sender).getUrl() + " failed to load."); - } - - public void onLoad(Widget sender) { + public void onLoad(LoadEvent event) { if (++onLoadEventCount == 1) { assertEquals(32, image.getWidth()); assertEquals(32, image.getHeight()); @@ -198,26 +206,42 @@ assertEquals(0, image.getOriginTop()); assertEquals("unclipped", getCurrentImageStateName(image)); } + + /** + * Tests the creation of an image that does not exist. + */ + public void testCreateImageWithError() { + final Image image = new Image("imageDoesNotExist.png"); + + delayTestFinish(5000); + image.addErrorHandler(new ErrorHandler() { + public void onError(ErrorEvent event) { + finishTest(); + } + }); + image.addLoadHandler(new LoadHandler() { + public void onLoad(LoadEvent event) { + fail("The image " + image.getUrl() + " should have failed to load."); + } + }); + + RootPanel.get().add(image); + } /** * Tests the firing of onload events when * {...@link com.google.gwt.user.client.ui.Image#setUrl(String)} is called on an * unclipped image. - * - * Disabled because of issue #863 */ - public void disabledTestSetUrlAndLoadEventsOnUnclippedImage() { + public void testSetUrlAndLoadEventsOnUnclippedImage() { final Image image = new Image(); delayTestFinish(5000); - image.addLoadListener(new LoadListener() { + image.addErrorHandler(new TestErrorHandler(image)); + image.addLoadHandler(new LoadHandler() { private int onLoadEventCount = 0; - public void onError(Widget sender) { - fail("The image " + ((Image) sender).getUrl() + " failed to load."); - } - - public void onLoad(Widget sender) { + public void onLoad(LoadEvent event) { if (++onLoadEventCount == 2) { finishTest(); } else { @@ -232,23 +256,19 @@ /** * Tests the behavior of - * <code>setUrlAndVisibleRect(String, int, int, int, int)</code> method on - * an unclipped image, which causes a state transition to the clipped state. - * - * Disabled because of issue #863. + * <code>setUrlAndVisibleRect(String, int, int, int, int)</code> method on an + * unclipped image, which causes a state transition to the clipped state. */ - public void disabledTestSetUrlAndVisibleRectOnUnclippedImage() { + public void testSetUrlAndVisibleRectOnUnclippedImage() { final Image image = new Image("counting-backwards.png"); + assertEquals("unclipped", getCurrentImageStateName(image)); delayTestFinish(5000); - image.addLoadListener(new LoadListener() { + image.addErrorHandler(new TestErrorHandler(image)); + image.addLoadHandler(new LoadHandler() { private int onLoadEventCount = 0; - public void onError(Widget sender) { - fail("The image " + ((Image) sender).getUrl() + " failed to load."); - } - - public void onLoad(Widget sender) { + public void onLoad(LoadEvent event) { if (getCurrentImageStateName(image).equals("unclipped")) { image.setUrlAndVisibleRect("counting-forwards.png", 0, 16, 16, 16); } @@ -265,19 +285,13 @@ }); RootPanel.get().add(image); - assertEquals("unclipped", getCurrentImageStateName(image)); - } - - @Override - public String getModuleName() { - return "com.google.gwt.user.UserTest"; } /** * Tests the creation of an image in clipped mode. */ - @DoNotRunWith({Platform.HtmlUnit}) - public void disabledTestCreateClippedImage() { + @SuppressWarnings("deprecation") + public void testCreateClippedImage() { final Image image = new Image("counting-forwards.png", 16, 16, 16, 16); delayTestFinish(5000); @@ -343,6 +357,83 @@ assertEquals(1, firedError); } + /** + * Verify that detaching and reattaching an image in a handler does not fire a + * second onload event. + */ + public void testNoEventOnReattachInHandler() { + final Image image = new Image("counting-forwards.png"); + + delayTestFinish(5000); + image.addErrorHandler(new TestErrorHandler(image)); + image.addLoadHandler(new LoadHandler() { + private int onLoadEventCount = 0; + + public void onLoad(LoadEvent event) { + if (++onLoadEventCount == 1) { + RootPanel.get().remove(image); + RootPanel.get().add(image); + // The extra onLoad would will fire synchronously before finishTest(). + finishTest(); + } else { + fail("onLoad fired on reattach."); + } + } + }); + + RootPanel.get().add(image); + } + + public void testOneEventOnly() { + final Image image = new Image("counting-forwards.png"); + + final TestLoadHandler loadHandler = new TestLoadHandler() { + public void onLoad(LoadEvent event) { + if (isFinished()) { + fail("LoadHandler fired multiple times."); + } + finish(); + } + }; + delayTestFinish(6000); + new Timer() { + @Override + public void run() { + assertTrue(loadHandler.isFinished()); + finishTest(); + } + }.schedule(5000); + image.addErrorHandler(new TestErrorHandler(image)); + image.addLoadHandler(loadHandler); + + RootPanel.get().add(image); + } + + public void testOneEventOnlyClippedImage() { + final Image image = new Image("counting-forwards.png", 12, 13, 8, 8); + + final TestLoadHandler loadHandler = new TestLoadHandler() { + public void onLoad(LoadEvent event) { + if (isFinished()) { + fail("LoadHandler fired multiple times."); + } + finish(); + } + }; + delayTestFinish(6000); + new Timer() { + @Override + public void run() { + assertTrue(loadHandler.isFinished()); + finishTest(); + } + }.schedule(5000); + image.addErrorHandler(new TestErrorHandler(image)); + image.addLoadHandler(loadHandler); + + RootPanel.get().add(image); + } + public void testResourceConstructor() { Bundle b = GWT.create(Bundle.class); Image image = new Image(b.prettyPiccy()); @@ -361,8 +452,8 @@ * {...@link com.google.gwt.user.client.ui.Image#setUrlAndVisibleRect(String,int,int,int,int)} * on a clipped image. */ - @DoNotRunWith({Platform.HtmlUnit}) - public void disabledTestSetUrlAndVisibleRectOnClippedImage() { + @SuppressWarnings("deprecation") + public void testSetUrlAndVisibleRectOnClippedImage() { final Image image = new Image("counting-backwards.png", 12, 12, 12, 12); delayTestFinish(5000); @@ -412,8 +503,8 @@ * {...@link com.google.gwt.user.client.ui.Image#setVisibleRect(int,int,int,int)} * on a clipped image. */ - @DoNotRunWith({Platform.HtmlUnit}) - public void disabledTestSetVisibleRectAndLoadEventsOnClippedImage() { + @SuppressWarnings("deprecation") + public void testSetVisibleRectAndLoadEventsOnClippedImage() { final Image image = new Image("counting-backwards.png", 16, 16, 16, 16); delayTestFinish(5000); ======================================= --- /releases/2.0/user/test/com/google/gwt/user/client/ui/TreeItemTest.java Wed Sep 23 10:15:52 2009 +++ /releases/2.0/user/test/com/google/gwt/user/client/ui/TreeItemTest.java Fri Nov 20 16:14:24 2009 @@ -15,6 +15,8 @@ */ package com.google.gwt.user.client.ui; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; /** @@ -39,6 +41,7 @@ assertEquals("Test", widget.getText()); } + @DoNotRunWith({Platform.HtmlUnit}) public void testSetWidgetNullWithError() { // Create a widget that will throw an exception onUnload. BadWidget badWidget = new BadWidget(); ======================================= --- /releases/2.0/user/test/com/google/gwt/user/client/ui/TreeTest.java Wed Oct 28 19:23:32 2009 +++ /releases/2.0/user/test/com/google/gwt/user/client/ui/TreeTest.java Fri Nov 20 16:14:24 2009 @@ -15,6 +15,8 @@ */ package com.google.gwt.user.client.ui; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; @@ -37,6 +39,7 @@ return "com.google.gwt.user.DebugTest"; } + @DoNotRunWith({Platform.HtmlUnit}) public void testAttachDetachOrder() { HasWidgetsTester.testAll(new Tree(), new Adder(), true); } -- http://groups.google.com/group/Google-Web-Toolkit-Contributors