001    /*
002     * Copyright 2002-2007 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.springframework.richclient.application.splash;
017    
018    import java.awt.Component;
019    import java.awt.Dimension;
020    import java.awt.Graphics;
021    import java.awt.Image;
022    import java.awt.MediaTracker;
023    import java.awt.Toolkit;
024    import java.io.IOException;
025    import java.net.URL;
026    
027    import javax.swing.JPanel;
028    
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    import org.springframework.core.io.Resource;
032    import org.springframework.util.Assert;
033    
034    /**
035     * A lightweight splash-screen for display when a GUI application is being
036     * initialized.
037     * <p>
038     * The splash screen renders an image in a Frame. It minimizes class loading so
039     * it is displayed immediately once the application is started.
040     * 
041     * @author Keith Donald
042     * @author Jan Hoskens
043     */
044    public class SimpleSplashScreen extends AbstractSplashScreen {
045            private Image image;
046    
047            private Resource imageResourcePath;
048    
049            private static final Log logger = LogFactory.getLog(SimpleSplashScreen.class);
050    
051            /**
052             * Creates a new uninitialized {@code SimpleSplashScreen}.
053             */
054            public SimpleSplashScreen() {
055                    // do nothing
056            }
057    
058            /**
059             * Creates a new {@code SimpleSplashScreen} that will display the image at
060             * the specified location.
061             * 
062             * @param imageResourcePath The location of the image file to be displayed
063             * by this splash screen.
064             * 
065             * @see #setImageResourcePath(String)
066             */
067            public SimpleSplashScreen(Resource imageResourcePath) {
068                    setImageResourcePath(imageResourcePath);
069            }
070    
071            /**
072             * Creates a new {@code SimpleSplashScreen} that will display the given
073             * image.
074             * 
075             * @param image the image to splash.
076             * 
077             * @throws IllegalArgumentException if {@code image} is null.
078             */
079            public SimpleSplashScreen(Image image) {
080                    Assert.notNull(image, "The splash screen image is required");
081                    this.image = image;
082            }
083    
084            /**
085             * Sets the location of the image to be displayed by this splash screen. If
086             * the given path starts with a '/', it is interpreted to be relative to the
087             * root of the runtime classpath. Otherwise it is interpreted to be relative
088             * to the subdirectory of the classpath root that corresponds to the package
089             * of this class.
090             * 
091             * @param path The path to the splash screen image.
092             */
093            public void setImageResourcePath(Resource path) {
094                    Assert.notNull(path, "The splash screen image resource path is required");
095                    this.imageResourcePath = path;
096            }
097    
098            /**
099             * Load image from path.
100             * 
101             * @param path Path to image.
102             * @return Image
103             * @throws IOException
104             * 
105             * @throws NullPointerException if {@code path} is null.
106             */
107            private Image loadImage(Resource path) throws IOException {
108                    URL url = path.getURL();
109                    if (url == null) {
110                            logger.warn("Unable to locate splash screen in classpath at: " + path);
111                            return null;
112                    }
113                    return Toolkit.getDefaultToolkit().createImage(url);
114            }
115    
116            protected Image getImage() {
117                    if (image == null && imageResourcePath != null) {
118                            try {
119                                    image = loadImage(imageResourcePath);
120                            }
121                            catch (IOException e) {
122                                    logger.error("Unable to load image from resource " + imageResourcePath, e);
123                            }
124                    }
125                    return image;
126            }
127    
128            /**
129             * Simple Canvas that paints an image.
130             */
131            public class ImageCanvas extends JPanel {
132                    private static final long serialVersionUID = -5096223464173393949L;
133    
134                    private Image image;
135    
136                    /**
137                     * Creates a new {@code ImageCanvas} with the specified image. The size
138                     * of the canvas will be set to the size of the image.
139                     * 
140                     * @param image The image to be displayed by the canvas.
141                     * 
142                     * @throws NullPointerException if {@code image} is null.
143                     */
144                    public ImageCanvas(Image image) {
145                            this.image = image;
146    
147                            loadImage();
148    
149                            Dimension size = new Dimension(image.getWidth(null), image.getHeight(null));
150    
151                            setSize(size);
152                            setPreferredSize(size);
153                            setMinimumSize(size);
154                    }
155    
156                    private void loadImage() {
157                            MediaTracker mediaTracker = new MediaTracker(this);
158                            mediaTracker.addImage(image, 0);
159                            try {
160                                    mediaTracker.waitForID(0);
161                            }
162                            catch (InterruptedException e) {
163                                    logger.warn("Interrupted while waiting for splash image to load.", e);
164                            }
165                    }
166    
167                    public void paintComponent(Graphics g) {
168                            g.clearRect(0, 0, getWidth(), getHeight());
169                            g.drawImage(image, 0, 0, this);
170                    }
171            }
172    
173            /**
174             * Returns a component that displays an image in a canvas.
175             */
176            protected Component createContentPane() {
177                    Image image = getImage();
178                    if (image != null) {
179                            return new ImageCanvas(image);
180                    }
181                    return null;
182            }
183    }