1 /*
2  * $RCSfile: MainFrame.java,v $
3  *
4  * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistribution of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  *
13  * - Redistribution in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  *
18  * Neither the name of Sun Microsystems, Inc. or the names of
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * This software is provided "AS IS," without a warranty of any
23  * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
24  * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
26  * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
27  * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
28  * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
29  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
30  * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
31  * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
32  * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
33  * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGES.
35  *
36  * You acknowledge that this software is not designed, licensed or
37  * intended for use in the design, construction, operation or
38  * maintenance of any nuclear facility.
39  *
40  * $Revision: 1.4 $
41  * $Date: 2007/02/09 17:20:10 $
42  * $State: Exp $
43  */
44 
45 // MainFrame - run an Applet as an application
46 //
47 // Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights reserved.
48 //
49 // Redistribution and use in source and binary forms, with or without
50 // modification, are permitted provided that the following conditions
51 // are met:
52 // 1. Redistributions of source code must retain the above copyright
53 //    notice, this list of conditions and the following disclaimer.
54 // 2. Redistributions in binary form must reproduce the above copyright
55 //    notice, this list of conditions and the following disclaimer in the
56 //    documentation and/or other materials provided with the distribution.
57 //
58 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
59 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
62 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 // SUCH DAMAGE.
69 //
70 // Visit the ACME Labs Java page for up-to-date versions of this and other
71 // fine Java utilities: http://www.acme.com/java/
72 
73 // ---------------------------------------------------------------------
74 
75 package com.sun.j3d.utils.applet;
76 
77 import java.applet.*;
78 import java.awt.*;
79 import java.awt.event.*;
80 import java.awt.image.*;
81 import java.net.*;
82 import java.io.*;
83 import java.util.*;
84 
85 /// Run an Applet as an application.
86 // <P>
87 // Using this class you can add a trivial main program to any Applet
88 // and run it directly, as well as from a browser or the appletviewer.
89 // And unlike some versions of this concept, MainFrame implements both
90 // images and sound.
91 // <P>
92 // Sample main program:
93 // <BLOCKQUOTE><PRE>
94 // public static void main( String[] args )
95 //     {
96 //     new Acme.MainFrame( new ThisApplet(), args, 400, 400 );
97 //     }
98 // </PRE></BLOCKQUOTE>
99 // The only methods you need to know about are the constructors.
100 // <P>
101 // You can specify Applet parameters on the command line, as name=value.
102 // For instance, the equivalent of:
103 // <BLOCKQUOTE><PRE>
104 // &lt;PARAM NAME="pause" VALUE="200"&gt;
105 // </PRE></BLOCKQUOTE>
106 // would just be:
107 // <BLOCKQUOTE><PRE>
108 // pause=200
109 // </PRE></BLOCKQUOTE>
110 // You can also specify three special parameters:
111 // <BLOCKQUOTE><PRE>
112 // width=N          Width of the Applet.
113 // height=N         Height of the Applet.
114 // barebones=true   Leave off the menu bar and status area.
115 // </PRE></BLOCKQUOTE>
116 // <P>
117 // <A HREF="/resources/classes/Acme/MainFrame.java">Fetch the software.</A><BR>
118 // <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
119 
120 public class MainFrame extends Frame implements
121                    Runnable, AppletStub, AppletContext
122 {
123 
124     private String[] args = null;
125     private static int instances = 0;
126     private String name;
127     private boolean barebones = true;
128     private Applet applet;
129     private Label label = null;
130     private Dimension appletSize;
131 
132     private static final String PARAM_PROP_PREFIX = "parameter.";
133 
134     /// Constructor with everything specified.
MainFrame(Applet applet, String[] args, int width, int height)135     public MainFrame(Applet applet, String[] args,
136 		     int width, int height) {
137 	build(applet, args, width, height);
138     }
139 
140     /// Constructor with no default width/height.
MainFrame(Applet applet, String[] args )141     public MainFrame(Applet applet, String[] args ) {
142 	build(applet, args, -1, -1);
143     }
144 
145     /// Constructor with no arg parsing.
MainFrame(Applet applet, int width, int height)146     public MainFrame(Applet applet, int width, int height) {
147 	build( applet, null, width, height );
148     }
149 
150     // Internal constructor routine.
build( Applet applet, String[] args, int width, int height)151     private void build(	Applet applet, String[] args,
152 			int width, int height) {
153 	++instances;
154 	this.applet = applet;
155 	this.args = args;
156 	applet.setStub( this );
157 	name = applet.getClass().getName();
158 	setTitle( name );
159 
160 	// Set up properties.
161 	Properties props = System.getProperties();
162 	props.put( "browser", "Acme.MainFrame" );
163 	props.put( "browser.version", "11jul96" );
164 	props.put( "browser.vendor", "Acme Laboratories" );
165 	props.put( "browser.vendor.url", "http://www.acme.com/" );
166 
167 	// Turn args into parameters by way of the properties list.
168 	if ( args != null )
169 	    parseArgs( args, props );
170 
171 	// If width and height are specified in the parameters, override
172 	// the compiled-in values.
173 	String widthStr = getParameter( "width" );
174 	if ( widthStr != null ) {
175 	    width = Integer.parseInt( widthStr );
176 	}
177 
178 	String heightStr = getParameter( "height" );
179 	if ( heightStr != null ) {
180 	    height = Integer.parseInt( heightStr );
181 	}
182 
183 	// Were width and height specified somewhere?
184 	if ((width == -1) || (height == -1)) {
185 	    System.err.println( "Width and height must be specified." );
186 	    return;
187 	}
188 
189 	// Do we want to run bare-bones?
190 	String bonesStr = getParameter( "barebones" );
191 	if ((bonesStr != null) && bonesStr.equals( "true" )) {
192 	    barebones = true;
193 	}
194 
195 	// Lay out components.
196 	setLayout( new BorderLayout() );
197 	add( "Center", applet );
198 
199 	// Set up size.
200 	pack();
201 	validate();
202 	appletSize = applet.getSize();
203 	applet.setSize( width, height );
204 	setVisible(true);
205 
206 
207 	/*
208 	  Added WindowListener inner class to detect close events.
209 	*/
210 	SecurityManager sm = System.getSecurityManager();
211 	boolean doExit = true;
212 
213 	if (sm != null) {
214 	    try {
215 		sm.checkExit(0);
216 	    } catch (SecurityException e) {
217 		doExit = false;
218 	    }
219 	}
220 
221 	final boolean _doExit = doExit;
222 
223 	addWindowListener(new WindowAdapter() {
224             public void windowClosing(WindowEvent winEvent) {
225 		if (MainFrame.this.applet != null) {
226 		    MainFrame.this.applet.destroy();
227 		}
228 		Window w = winEvent.getWindow();
229 		w.hide();
230 		try {
231 		    w.dispose();
232 		} catch (IllegalStateException e) {}
233 
234 		if (_doExit) {
235 		    System.exit(0);
236 		}
237 	    }
238 	});
239 
240 	// Start a separate thread to call the applet's init() and start()
241 	// methods, in case they take a long time.
242 	(new Thread( this )).start();
243     }
244 
245     // Turn command-line arguments into Applet parameters, by way of the
246     // properties list.
parseArgs( String[] args, Properties props)247     private static void parseArgs( String[] args, Properties props) {
248 	String arg;
249 
250 	for (int i = 0; i < args.length; ++i) {
251 	    arg = args[i];
252 	    int ind = arg.indexOf( '=' );
253 	    if ( ind == -1 ) {
254 		props.put(PARAM_PROP_PREFIX + arg.toLowerCase(), "" );
255 	    } else {
256 		props.put(PARAM_PROP_PREFIX + arg.substring( 0, ind ).toLowerCase(),
257 			  arg.substring( ind + 1 ) );
258 	    }
259 	}
260     }
261 
262     // Methods from Runnable.
263 
264     /// Separate thread to call the applet's init() and start() methods.
run()265     public void run() {
266 	showStatus( name + " initializing..." );
267 	applet.init();
268 	validate();
269 	showStatus( name + " starting..." );
270 	applet.start();
271 	validate();
272 	showStatus( name + " running..." );
273     }
274 
275 
276     // Methods from AppletStub.
isActive()277     public boolean isActive() {
278 	return true;
279     }
280 
getDocumentBase()281     public URL getDocumentBase() {
282 	// Returns the current directory.
283 	String dir = System.getProperty( "user.dir" );
284 	String urlDir = dir.replace( File.separatorChar, '/' );
285 	try {
286 	    return new URL( "file:" + urlDir + "/");
287 	} catch ( MalformedURLException e ) {
288 	    return null;
289 	}
290     }
291 
getCodeBase()292     public URL getCodeBase() {
293 	// Hack: loop through each item in CLASSPATH, checking if
294 	// the appropriately named .class file exists there.  But
295 	// this doesn't account for .zip files.
296 	String path = System.getProperty( "java.class.path" );
297 	Enumeration st = new StringTokenizer( path, ":" );
298 	while ( st.hasMoreElements() ) {
299 	    String dir = (String) st.nextElement();
300 	    String filename = dir + File.separatorChar + name + ".class";
301 	    File file = new File( filename );
302 	    if (file.exists()) {
303 		String urlDir = dir.replace( File.separatorChar, '/' );
304 		try {
305 		    return new URL( "file:" + urlDir + "/" );
306 		} catch (MalformedURLException e) {
307 		    return null;
308 		}
309 	    }
310 	}
311 	return null;
312     }
313 
getParameter(String name)314     public String getParameter(String name) {
315 	// Return a parameter via the munged names in the properties list.
316 	return System.getProperty( PARAM_PROP_PREFIX + name.toLowerCase() );
317     }
318 
appletResize(int width, int height)319     public void appletResize(int width, int height) {
320 	// Change the frame's size by the same amount that the applet's
321 	// size is changing.
322 	Dimension frameSize = getSize();
323 	frameSize.width += width - appletSize.width;
324 	frameSize.height += height - appletSize.height;
325 	setSize( frameSize );
326 	appletSize = applet.getSize();
327     }
328 
getAppletContext()329     public AppletContext getAppletContext() {
330 	return this;
331     }
332 
333 
334     // Methods from AppletContext.
getAudioClip( URL url )335     public AudioClip getAudioClip( URL url ) {
336 	// This is an internal undocumented routine.  However, it
337 	// also provides needed functionality not otherwise available.
338 	// I suspect that in a future release, JavaSoft will add an
339 	// audio content handler which encapsulates this, and then
340 	// we can just do a getContent just like for images.
341 	return new sun.applet.AppletAudioClip( url );
342     }
343 
getImage( URL url )344     public Image getImage( URL url ) {
345 	Toolkit tk = Toolkit.getDefaultToolkit();
346 	try {
347 	    ImageProducer prod = (ImageProducer) url.getContent();
348 	    return tk.createImage( prod );
349 	} catch ( IOException e ) {
350 	    return null;
351 	}
352     }
353 
getApplet(String name)354     public Applet getApplet(String name) {
355 	// Returns this Applet or nothing.
356 	if (name.equals( this.name )) {
357 	    return applet;
358 	}
359 	return null;
360     }
361 
getApplets()362     public Enumeration getApplets() {
363 	// Just yields this applet.
364 	Vector v = new Vector();
365 	v.addElement( applet );
366 	return v.elements();
367     }
368 
showDocument( URL url )369     public void showDocument( URL url )	{
370 	// Ignore.
371     }
372 
showDocument( URL url, String target )373     public void showDocument( URL url, String target ) {
374 	// Ignore.
375     }
376 
showStatus( String status )377     public void showStatus( String status ) {
378 	if (label != null) {
379 	    label.setText(status);
380 	}
381     }
382 
setStream( String key, java.io.InputStream stream )383     public void setStream( String key, java.io.InputStream stream ) {
384 	throw new RuntimeException("Not Implemented");
385 	// TODO implement setStream method
386     }
387 
getStream( String key )388     public java.io.InputStream getStream( String key ) {
389 	throw new RuntimeException("Not Implemented");
390 	// TODO implement getStream method
391     }
392 
getStreamKeys()393     public java.util.Iterator getStreamKeys() {
394      		throw new RuntimeException("Not Implemented");
395  	// TODO implement getStreamKeys method
396     }
397 }
398