001    /*
002     * Copyright 2002-2006 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.Image;
020    import java.awt.Toolkit;
021    import java.net.URL;
022    
023    import javax.swing.JFrame;
024    import javax.swing.JOptionPane;
025    
026    import org.apache.commons.logging.Log;
027    import org.apache.commons.logging.LogFactory;
028    import org.springframework.context.MessageSource;
029    import org.springframework.context.NoSuchMessageException;
030    import org.springframework.richclient.components.ShadowBorderFrame;
031    import org.springframework.richclient.util.WindowUtils;
032    
033    /**
034     * An abstract helper implementation of the {@link SplashScreen} interface.
035     * 
036     * <p>
037     * The splash screen produced by this class will be an undecorated, centered
038     * frame containing the component provided by {@link #createContentPane()},
039     * which is the only method that subclasses need to implement.
040     * </p>
041     * 
042     * @author Peter De Bruycker
043     */
044    public abstract class AbstractSplashScreen implements SplashScreen {
045    
046            /**
047             * The message resource key used to look up the splash screen's frame title.
048             */
049            public static final String SPLASH_TITLE_KEY = "splash.title";
050    
051            private JFrame frame;
052    
053            private MessageSource messageSource;
054    
055            private String iconResourcePath;
056    
057            private boolean shadowBorder;
058    
059            protected final Log logger = LogFactory.getLog(getClass());
060    
061            private boolean rootFrame = true;
062    
063            /**
064             * Returns the location of the image to be used as the icon for the splash
065             * screen's frame. The splash screen produced by this class is undecorated,
066             * so the icon will only be visible in the frame's taskbar icon. If the
067             * given path starts with a '/', it is interpreted to be relative to the
068             * root of the runtime classpath. Otherwise it is interpreted to be relative
069             * to the subdirectory of the classpath root that corresponds to the package
070             * of this class.
071             * 
072             * @return The location of the icon resource.
073             */
074            public String getIconResourcePath() {
075                    return iconResourcePath;
076            }
077    
078            /**
079             * Sets the location of the image to be used as the icon for the splash
080             * screen's frame. The splash screen produced by this class is undecorated,
081             * so the icon will only be visible in the frame's taskbar icon. If the
082             * given path starts with a '/', it is interpreted to be relative to the
083             * root of the runtime classpath. Otherwise it is interpreted to be relative
084             * to the subdirectory of the classpath root that corresponds to the package
085             * of this class.
086             * 
087             * @param iconResourcePath The location of the icon resource.
088             */
089            public void setIconResourcePath(String iconResourcePath) {
090                    this.iconResourcePath = iconResourcePath;
091            }
092    
093            /**
094             * Returns the message source used to resolve localized messages.
095             * 
096             * @return The message source, or null.
097             */
098            public MessageSource getMessageSource() {
099                    return messageSource;
100            }
101    
102            /**
103             * Sets the message source used to resolve localized messages.
104             * 
105             * @param messageSource The message source.
106             */
107            public void setMessageSource(MessageSource messageSource) {
108                    this.messageSource = messageSource;
109            }
110    
111            public final void dispose() {
112    
113                    if (frame != null) {
114                            frame.dispose();
115                            frame = null;
116                    }
117    
118            }
119    
120            /**
121             * Creates and displays an undecorated, centered splash screen containing
122             * the component provided by {@link #createContentPane()}. If this instance
123             * has been provided with a {@link MessageSource}, it will be used to
124             * retrieve the splash screen's frame title under the key
125             * {@value #SPLASH_TITLE_KEY}.
126             */
127            public final void splash() {
128                    frame = shadowBorder ? new ShadowBorderFrame() : new JFrame();
129                    if (isRootFrame())
130                            JOptionPane.setRootFrame(frame);
131    
132                    frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
133                    frame.setUndecorated(true);
134    
135                    frame.setTitle(loadFrameTitle());
136                    frame.setIconImage(loadFrameIcon());
137    
138                    Component content = createContentPane();
139                    if (content != null) {
140                            frame.getContentPane().add(content);
141                    }
142                    frame.pack();
143                    WindowUtils.centerOnScreen(frame);
144                    frame.setVisible(true);
145            }
146    
147            /**
148             * Loads the message under the key {@value #SPLASH_TITLE_KEY} if a
149             * {@link MessageSource} has been set on this instance.
150             * 
151             * @return The message resource stored under the key
152             * {@value #SPLASH_TITLE_KEY}, or null if no message source has been set.
153             */
154            private String loadFrameTitle() {
155                    try {
156                            return messageSource == null ? null : messageSource.getMessage(SPLASH_TITLE_KEY, null, null);
157                    }
158                    catch (NoSuchMessageException e) {
159                            return null;
160                    }
161            }
162    
163            private Image loadFrameIcon() {
164                    if (iconResourcePath == null) {
165                            return null;
166                    }
167    
168                    URL url = this.getClass().getResource(iconResourcePath);
169                    if (url == null) {
170                            logger.warn("Unable to locate splash screen in classpath at: " + iconResourcePath);
171                            return null;
172                    }
173                    return Toolkit.getDefaultToolkit().createImage(url);
174            }
175    
176            /**
177             * Returns the component to be displayed in the splash screen's main frame.
178             * If the returned value is null the frame for the splash screen will still
179             * be created but will not have any content
180             * 
181             * @return The content pane component. Can be null.
182             */
183            protected abstract Component createContentPane();
184    
185            /**
186             * Returns whether the splash screen will be rendered with a shadow border.
187             * The shadow border will let the background show through.
188             * 
189             * @return whether to show a shadow border or not
190             */
191            public boolean isShadowBorder() {
192                    return shadowBorder;
193            }
194    
195            /**
196             * Sets whether the splash screen will be rendered with a shadow border. If
197             * <code>true</code> a border will be shown.
198             * 
199             * @param shadowBorder Show the shadow border or not
200             */
201            public void setShadowBorder(boolean shadowBorder) {
202                    this.shadowBorder = shadowBorder;
203            }
204    
205            /**
206             * The frame that is used to display this splashscreen can be used as
207             * rootFrame for other dialogs/windows that need a Frame before the
208             * applicationFrame is created. (eg login).
209             * 
210             * @param rootFrame <code>true</code> if the created frame must be set as
211             * rootFrame. Defaults to <code>true</code>.
212             * @see JOptionPane#setRootFrame(java.awt.Frame)
213             */
214            public void setRootFrame(boolean rootFrame) {
215                    this.rootFrame = rootFrame;
216            }
217    
218            /**
219             * @return <code>true</code> if the created frame must be set as rootFrame.
220             */
221            public boolean isRootFrame() {
222                    return this.rootFrame;
223            }
224    }