001 /*
002 * Created on Jul 10, 2008
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 *
014 * Copyright @2008-2010 the original author or authors.
015 */
016 package org.fest.swing.applet;
017
018 import static java.awt.BorderLayout.CENTER;
019 import static java.awt.BorderLayout.SOUTH;
020 import static javax.swing.BorderFactory.*;
021 import static javax.swing.SwingUtilities.invokeLater;
022 import static javax.swing.SwingUtilities.isEventDispatchThread;
023 import static javax.swing.border.BevelBorder.LOWERED;
024 import static org.fest.swing.edt.GuiActionRunner.execute;
025 import static org.fest.util.Strings.concat;
026
027 import java.applet.Applet;
028 import java.applet.AppletStub;
029 import java.awt.BorderLayout;
030 import java.awt.Dimension;
031 import java.util.Map;
032
033 import javax.swing.JFrame;
034 import javax.swing.JLabel;
035
036 import org.fest.swing.annotation.RunsInCurrentThread;
037 import org.fest.swing.annotation.RunsInEDT;
038 import org.fest.swing.edt.GuiQuery;
039
040 /**
041 * Understands a window that displays an <code>{@link Applet}</code>.
042 * <p>
043 * Typical usage:
044 * <pre>
045 * AppletViewer viewer = AppletViewer.newViewer(new MyApplet());
046 *
047 * // test the applet, viewer can be wrapped with a FrameFixture.
048 * FrameFixture viewerFixture = new FrameFixture(viewer);
049 *
050 * viewer.unloadApplet() // stops and destroys the applet
051 * viewerFixture.cleanUp();
052 * </pre>
053 * <p>
054 * <b>Note:</b> In version 1.2, due to bug <a href="http://jira.codehaus.org/browse/FEST-219" target="_blank">FEST-219</a>
055 * constructors in this class have been replaced with the static factory methods <code>newViewer</code>. It was not
056 * possible to just deprecate them. To ensure correct behavior of the applet viewer, they had to be made unaccessible to
057 * client code.
058 * </p>
059 * </p>
060 *
061 * @author Alex Ruiz
062 * @author Yvonne Wang
063 */
064 public class AppletViewer extends JFrame implements StatusDisplay {
065
066 private static final long serialVersionUID = 1L;
067
068 private static final String APPLET_VIEWER_TITLE = "Applet Viewer: ";
069 private static final String APPLET_LOADED_MESSAGE = "Applet loaded";
070 private static final Dimension DEFAULT_SIZE = new Dimension(100, 100);
071
072 private final JLabel statusLabel = new JLabel();
073
074 private final Applet applet;
075 private transient AppletStub stub;
076 private boolean loaded;
077
078 /**
079 * Creates a new </code>{@link AppletViewer}</code>. This factory method creates new instances of
080 * <code>{@link BasicAppletStub}</code> and <code>{@link BasicAppletContext}</code>.
081 * <p>
082 * <b>Note:</b> This method is executed in the event dispatch thread (EDT.)
083 * </p>
084 * @param applet the applet to view.
085 * @return the created <code>AppletViewer</code>.
086 * @throws NullPointerException if <code>applet</code> is <code>null</code>.
087 * @since 1.2
088 */
089 @RunsInEDT
090 public static AppletViewer newViewer(Applet applet) {
091 AppletViewer viewer = createInEDT(applet);
092 viewer.appletStub(new BasicAppletStub(viewer, new BasicAppletContext(viewer)));
093 return viewer;
094 }
095
096 /**
097 * Creates a new </code>{@link AppletViewer}</code>. This factory method creates new instances of
098 * <code>{@link BasicAppletStub}</code> and <code>{@link BasicAppletContext}</code>.
099 * <p>
100 * <b>Note:</b> This method is executed in the event dispatch thread (EDT.)
101 * </p>
102 * @param applet the applet to view.
103 * @param parameters the parameters included in an applet HTML tag.
104 * @return the created <code>AppletViewer</code>.
105 * @throws NullPointerException if <code>applet</code> is <code>null</code>.
106 * @throws NullPointerException if <code>parameters</code> is <code>null</code>.
107 * @since 1.2
108 */
109 @RunsInEDT
110 public static AppletViewer newViewer(Applet applet, Map<String, String> parameters) {
111 AppletViewer viewer = createInEDT(applet);
112 viewer.appletStub(new BasicAppletStub(viewer, new BasicAppletContext(viewer), parameters));
113 return viewer;
114 }
115
116
117 /**
118 * Creates a new </code>{@link AppletViewer}</code>.
119 * <p>
120 * <b>Note:</b> This method is executed in the event dispatch thread (EDT.)
121 * </p>
122 * @param applet the applet to view.
123 * @param stub the applet's stub.
124 * @return the created <code>AppletViewer</code>.
125 * @throws NullPointerException if <code>applet</code> is <code>null</code>.
126 * @throws NullPointerException if <code>stub</code> is <code>null</code>.
127 * @since 1.2
128 */
129 @RunsInEDT
130 public static AppletViewer newViewer(Applet applet, AppletStub stub) {
131 AppletViewer viewer = createInEDT(applet);
132 viewer.appletStub(stub);
133 return viewer;
134 }
135
136 @RunsInEDT
137 private static AppletViewer createInEDT(final Applet applet) {
138 return execute(new GuiQuery<AppletViewer>() {
139 protected AppletViewer executeInEDT() {
140 return new AppletViewer(applet);
141 }
142 });
143 }
144
145 private AppletViewer(Applet applet) {
146 if (applet == null) throw new NullPointerException("The applet to load should not be null");
147 this.applet = applet;
148 setUpFrame();
149 addContent();
150 }
151
152 private void setUpFrame() {
153 setTitle(concat(APPLET_VIEWER_TITLE, applet.getClass().getName()));
154 setSize(DEFAULT_SIZE);
155 setLayout(new BorderLayout());
156 }
157
158 private void addContent() {
159 add(applet, CENTER);
160 statusLabel.setBorder(createCompoundBorder(createBevelBorder(LOWERED), createEmptyBorder(2, 5, 2, 5)));
161 statusLabel.setName("status");
162 add(statusLabel, SOUTH);
163 }
164
165 private void appletStub(AppletStub newAppletStub) {
166 if (newAppletStub == null) throw new NullPointerException("The AppletStub should not be null");
167 stub = newAppletStub;
168 applet.setStub(stub);
169 setUpApplet();
170 }
171
172 private void setUpApplet() {
173 loadApplet();
174 showStatus(APPLET_LOADED_MESSAGE);
175 }
176
177 /**
178 * Initializes and starts the applet in this viewer.
179 */
180 public void reloadApplet() {
181 if (loaded) unloadApplet();
182 loadApplet();
183 }
184
185 private void loadApplet() {
186 applet.init();
187 applet.start();
188 loaded = true;
189 }
190
191 /**
192 * Stops and destroys the applet loaded in this viewer. This method should be called before closing or disposing this
193 * viewer.
194 */
195 public void unloadApplet() {
196 applet.stop();
197 applet.destroy();
198 loaded = false;
199 }
200
201 /**
202 * Indicates whether the applet in this viewer is loaded or not.
203 * @return <code>true</code> if this applet is loaded, <code>false</code> otherwise.
204 */
205 public boolean appletLoaded() { return loaded; }
206
207 /**
208 * Displays the given status message. This method is executed in the event dispatch thread (EDT.)
209 * @param status the status to display.
210 */
211 @RunsInEDT
212 public void showStatus(final String status) {
213 if (isEventDispatchThread()) {
214 setStatus(status);
215 return;
216 }
217 invokeLater(new Runnable() {
218 public void run() {
219 setStatus(status);
220 }
221 });
222 }
223
224 @RunsInCurrentThread
225 private void setStatus(String status) {
226 statusLabel.setText(status);
227 }
228
229 /**
230 * Returns the applet displayed in this viewer.
231 * @return the applet displayed in this viewer.
232 */
233 public Applet applet() {
234 return applet;
235 }
236
237 /**
238 * Returns the <code>{@link AppletStub}</code> in this viewer.
239 * @return the <code>AppletStub</code> in this viewer.
240 */
241 public AppletStub stub() {
242 return stub;
243 }
244 }