/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package gwt.g2d.client.graphics;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.resources.client.ClientBundle;
import gwt.g2d.resources.client.ExternalImageResource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* <p>
* Provides a mechanism for deferred execution of a callback
* method once all specified Images are loaded.
* <p>
* This class may be deprecated in future release. Considers using
* {@link ClientBundle} with {@link ExternalImageResource} instead.
* <p>
* (This is a slightly modified by hao1300@gmail.com from the GWT-incubator's
* ImageLoader to provide a more flexible loading scheme.)
*/
public class ImageLoader {
/**
* Interface to allow anonymous instantiation of a CallBack
* Object with method that gets invoked when all the images
* are loaded.
*/
public interface CallBack {
void onImagesLoaded(ImageElement[] imageElements);
}
/**
* Static internal collection of ImageLoader instances.
* ImageLoader is not instantiable externally.
*/
private static Set<ImageLoader> imageLoaders = new HashSet<ImageLoader>();
/**
* Takes in an url String corresponding to the image needed to be loaded.
* The onImagesLoaded() method in the specified CallBack
* object is invoked with an array of ImageElements corresponding to
* the where the first element of the array is the image requested.
*
* @param url Array of urls for the images that need to be loaded
* @param cb CallBack object
*/
public static void loadImages(String url, CallBack cb) {
ImageLoader il = new ImageLoader();
il.finalize(cb);
ImageLoader.imageLoaders.add(il);
il.totalImages = 1;
ImageElement imageElement = il.prepareImage();
il.images.add(imageElement);
imageElement.setSrc(url);
}
/**
* Takes in an array of url Strings corresponding to the images needed to
* be loaded. The onImagesLoaded() method in the specified CallBack
* object is invoked with an array of ImageElements corresponding to
* the original input array of url Strings once all the images report
* an onload event.
*
* @param urls Array of urls for the images that need to be loaded
* @param cb CallBack object
*/
public static void loadImages(String[] urls, CallBack cb) {
loadImages(Arrays.asList(urls), cb);
}
/**
* Takes in a list of url Strings corresponding to the images needed to
* be loaded. The onImagesLoaded() method in the specified CallBack
* object is invoked with a list of ImageElements corresponding to
* the original input list of url Strings once all the images report
* an onload event.
*
* @param urls List of urls for the images that need to be loaded
* @param cb CallBack object
*/
public static void loadImages(List<String> urls, CallBack cb) {
ImageLoader il = new ImageLoader();
il.finalize(cb);
ImageLoader.imageLoaders.add(il);
il.totalImages = urls.size();
for (String url : urls) {
ImageElement imageElement = il.prepareImage();
il.images.add(imageElement);
imageElement.setSrc(url);
}
}
private CallBack callBack = null;
private List<ImageElement> images = new ArrayList<ImageElement>();
private int loadedImages = 0;
private int totalImages = 0;
private ImageLoader() {
}
/**
* Invokes the onImagesLoaded method in the CallBack if all the
* images are loaded AND we have a CallBack specified.
*
* Called from the JSNI onload event handler.
*/
@SuppressWarnings("unused")
private void dispatchIfComplete() {
if (callBack != null && isAllLoaded()) {
callBack.onImagesLoaded(images.toArray(new ImageElement[0]));
// remove the image loader
ImageLoader.imageLoaders.remove(this);
}
}
/**
* Sets the callback object for the ImageLoader.
* Once this is set, we may invoke the callback once all images that
* need to be loaded report in from their onload event handlers.
*
* @param cb
*/
private void finalize(CallBack cb) {
this.callBack = cb;
}
@SuppressWarnings("unused")
private void incrementLoadedImages() {
this.loadedImages++;
}
private boolean isAllLoaded() {
return (loadedImages == totalImages);
}
/**
* Returns a handle to an img object. Ties back to the ImageLoader instance
*/
private native ImageElement prepareImage() /*-{
// if( callback specified )
// do nothing
var img = new Image();
var __this = this;
img.onload = function() {
if(!img.__isLoaded) {
// __isLoaded should be set for the first time here.
// if for some reason img fires a second onload event
// we do not want to execute the following again (hence the guard)
img.__isLoaded = true;
__this.@gwt.g2d.client.graphics.ImageLoader::incrementLoadedImages()();
img.onload = null;
// we call this function each time onload fires
// It will see if we are ready to invoke the callback
__this.@gwt.g2d.client.graphics.ImageLoader::dispatchIfComplete()();
} else {
// we invoke the callback since we are already loaded
__this.@gwt.g2d.client.graphics.ImageLoader::dispatchIfComplete()();
}
}
return img;
}-*/;
}