0001: /*
0002: * @(#)AppletViewer.java 1.135 06/10/10
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027:
0028: package sun.applet;
0029:
0030: import java.util.*;
0031: import java.io.*;
0032: import java.awt.*;
0033: import java.awt.event.*;
0034: import java.applet.*;
0035: import java.net.URL;
0036: import java.net.MalformedURLException;
0037: import java.net.SocketPermission;
0038: import sun.misc.Ref;
0039: import java.security.AccessController;
0040: import java.security.PrivilegedAction;
0041: import java.lang.reflect.InvocationTargetException;
0042: import java.lang.reflect.Method;
0043:
0044: /**
0045: * A frame to show the applet tag in.
0046: */
0047: class TextFrame extends Frame {
0048: /**
0049: * Create the tag frame.
0050: */
0051: TextFrame(int x, int y, String title, String text) {
0052: setTitle(title);
0053: TextArea txt = new TextArea(20, 60);
0054: txt.setText(text);
0055: txt.setEditable(false);
0056: add("Center", txt);
0057: Panel p = new Panel();
0058: add("South", p);
0059: Button b = new Button(amh.getMessage("button.dismiss",
0060: "Dismiss"));
0061: p.add(b);
0062: class ActionEventListener implements ActionListener {
0063: public void actionPerformed(ActionEvent evt) {
0064: dispose();
0065: }
0066: }
0067: b.addActionListener(new ActionEventListener());
0068: pack();
0069: move(x, y);
0070: setVisible(true);
0071: WindowListener windowEventListener = new WindowAdapter() {
0072: public void windowClosing(WindowEvent evt) {
0073: dispose();
0074: }
0075: };
0076: addWindowListener(windowEventListener);
0077: }
0078:
0079: private static AppletMessageHandler amh = new AppletMessageHandler(
0080: "textframe");
0081: }
0082:
0083: /**
0084: * Lets us construct one using unix-style one shot behaviors
0085: */
0086:
0087: class StdAppletViewerFactory implements AppletViewerFactory {
0088: public AppletViewer createAppletViewer(int x, int y, URL doc,
0089: Hashtable atts) {
0090: return new AppletViewer(x, y, doc, atts, System.out, this );
0091: }
0092:
0093: public MenuBar getBaseMenuBar() {
0094: return new MenuBar();
0095: }
0096:
0097: public boolean isStandalone() {
0098: return true;
0099: }
0100: }
0101:
0102: /**
0103: * The applet viewer makes it possible to run a Java applet without using a browser.
0104: * For details on the syntax that <B>appletviewer</B> supports, see
0105: * <a href="../../../docs/tooldocs/appletviewertags.html">AppletViewer Tags</a>.
0106: * (The document named appletviewertags.html in the JDK's docs/tooldocs directory,
0107: * once the JDK docs have been installed.)
0108: */
0109: public class AppletViewer extends Frame implements AppletContext {
0110: /**
0111: * Some constants...
0112: */
0113: private static String defaultSaveFile = "Applet.ser";
0114: /**
0115: * The panel in which the applet is being displayed.
0116: */
0117: AppletViewerPanel panel;
0118: /**
0119: * The status line.
0120: */
0121: Label label;
0122: /**
0123: * output status messages to this stream
0124: */
0125:
0126: PrintStream statusMsgStream;
0127: /**
0128: * For cloning
0129: */
0130: AppletViewerFactory factory;
0131:
0132: private final class UserActionListener implements ActionListener {
0133: public void actionPerformed(ActionEvent evt) {
0134: processUserAction(evt);
0135: }
0136: }
0137:
0138: /**
0139: * Create the applet viewer
0140: */
0141: public AppletViewer(int x, int y, URL doc, Hashtable atts,
0142: PrintStream statusMsgStream, AppletViewerFactory factory) {
0143: this .factory = factory;
0144: this .statusMsgStream = statusMsgStream;
0145: setTitle(amh.getMessage("tool.title", atts.get("code")));
0146: MenuBar mb = factory.getBaseMenuBar();
0147: Menu m = new Menu(amh.getMessage("menu.applet"));
0148: addMenuItem(m, "menuitem.restart");
0149: addMenuItem(m, "menuitem.reload");
0150: addMenuItem(m, "menuitem.stop");
0151: addMenuItem(m, "menuitem.save");
0152: addMenuItem(m, "menuitem.start");
0153: addMenuItem(m, "menuitem.clone");
0154: m.add(new MenuItem("-"));
0155: addMenuItem(m, "menuitem.tag");
0156: addMenuItem(m, "menuitem.info");
0157: addMenuItem(m, "menuitem.edit").disable();
0158: addMenuItem(m, "menuitem.encoding");
0159: m.add(new MenuItem("-"));
0160: //addMenuItem(m, "menuitem.print");
0161: //m.add(new MenuItem("-"));
0162: addMenuItem(m, "menuitem.props");
0163: m.add(new MenuItem("-"));
0164: addMenuItem(m, "menuitem.close");
0165: if (factory.isStandalone()) {
0166: addMenuItem(m, "menuitem.quit");
0167: }
0168: mb.add(m);
0169: setMenuBar(mb);
0170: add("Center", panel = new AppletViewerPanel(doc, atts));
0171: add("South", label = new Label(amh.getMessage("label.hello")));
0172: panel.init();
0173: appletPanels.addElement(panel);
0174: pack();
0175: move(x, y);
0176: setVisible(true);
0177: WindowListener windowEventListener = new WindowAdapter() {
0178: public void windowClosing(WindowEvent evt) {
0179: appletClose();
0180: }
0181:
0182: public void windowIconified(WindowEvent evt) {
0183: appletStop();
0184: }
0185:
0186: public void windowDeiconified(WindowEvent evt) {
0187: appletStart();
0188: }
0189: };
0190: class AppletEventListener implements AppletListener {
0191: public void appletStateChanged(AppletEvent evt) {
0192: switch (evt.getID()) {
0193: case AppletPanel.APPLET_RESIZE: {
0194: AppletPanel src = (AppletPanel) evt.getSource();
0195: if (src != null) {
0196: setSize(getPreferredSize());
0197: validate();
0198: }
0199: }
0200: }
0201: }
0202: }
0203: ;
0204: addWindowListener(windowEventListener);
0205: panel.addAppletListener(new AppletEventListener());
0206: // Start the applet
0207: showStatus(amh.getMessage("status.start"));
0208: initEventQueue();
0209: }
0210:
0211: // NOTE: probably should be "private"
0212: public MenuItem addMenuItem(Menu m, String s) {
0213: MenuItem mItem = new MenuItem(amh.getMessage(s));
0214: mItem.addActionListener(new UserActionListener());
0215: return m.add(mItem);
0216: }
0217:
0218: /**
0219: * Send the initial set of events to the appletviewer event queue.
0220: * On start-up the current behaviour is to load the applet and call
0221: * Applet.init() and Applet.start().
0222: */
0223: private void initEventQueue() {
0224: // appletviewer.send.event is an undocumented and unsupported system
0225: // property which is used exclusively for testing purposes.
0226: String eventList = System
0227: .getProperty("appletviewer.send.event");
0228: if (eventList == null) {
0229: // Add the standard events onto the event queue.
0230: panel.sendEvent(AppletPanel.APPLET_LOAD);
0231: panel.sendEvent(AppletPanel.APPLET_INIT);
0232: panel.sendEvent(AppletPanel.APPLET_START);
0233: } else {
0234: // We're testing AppletViewer. Force the specified set of events
0235: // onto the event queue, wait for the events to be processed, and
0236: // exit.
0237:
0238: // The list of events that will be executed is provided as a
0239: // ","-separated list. No error-checking will be done on the list.
0240: String[] events = splitSeparator(",", eventList);
0241: for (int i = 0; i < events.length; i++) {
0242: System.out.println("Adding event to queue: "
0243: + events[i]);
0244: if (events[i].equals("dispose"))
0245: panel.sendEvent(AppletPanel.APPLET_DISPOSE);
0246: else if (events[i].equals("load"))
0247: panel.sendEvent(AppletPanel.APPLET_LOAD);
0248: else if (events[i].equals("init"))
0249: panel.sendEvent(AppletPanel.APPLET_INIT);
0250: else if (events[i].equals("start"))
0251: panel.sendEvent(AppletPanel.APPLET_START);
0252: else if (events[i].equals("stop"))
0253: panel.sendEvent(AppletPanel.APPLET_STOP);
0254: else if (events[i].equals("destroy"))
0255: panel.sendEvent(AppletPanel.APPLET_DESTROY);
0256: else if (events[i].equals("quit"))
0257: panel.sendEvent(AppletPanel.APPLET_QUIT);
0258: else if (events[i].equals("error"))
0259: panel.sendEvent(AppletPanel.APPLET_ERROR);
0260: else
0261: // non-fatal error if we get an unrecognized event
0262: System.out.println("Unrecognized event name: "
0263: + events[i]);
0264: }
0265: while (!panel.emptyEventQueue())
0266: ;
0267: appletSystemExit();
0268: }
0269: }
0270:
0271: /**
0272: * Split a string based on the presence of a specified separator. Returns
0273: * an array of arbitrary length. The end of each element in the array is
0274: * indicated by the separator of the end of the string. If there is a
0275: * separator immediately before the end of the string, the final element
0276: * will be empty. None of the strings will contain the separator. Useful
0277: * when separating strings such as "foo/bar/bas" using separator "/".
0278: *
0279: * @param sep The separator.
0280: * @param s The string to split.
0281: * @return An array of strings. Each string in the array is determined
0282: * by the location of the provided sep in the original string,
0283: * s. Whitespace not stripped.
0284: */
0285: private String[] splitSeparator(String sep, String s) {
0286: Vector v = new Vector();
0287: int tokenStart = 0;
0288: int tokenEnd = 0;
0289: while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) {
0290: v.addElement(s.substring(tokenStart, tokenEnd));
0291: tokenStart = tokenEnd + 1;
0292: }
0293: // Add the final element.
0294: v.addElement(s.substring(tokenStart));
0295: String[] retVal = new String[v.size()];
0296: v.copyInto(retVal);
0297: return retVal;
0298: }
0299:
0300: /*
0301: * Methods for java.applet.AppletContext
0302: */
0303:
0304: private static Map audioClips = new HashMap();
0305:
0306: /**
0307: * Get an audio clip.
0308: */
0309: public AudioClip getAudioClip(URL url) {
0310: checkConnect(url);
0311: synchronized (audioClips) {
0312: AudioClip clip = (AudioClip) audioClips.get(url);
0313: if (clip == null) {
0314: audioClips.put(url, clip = new AppletAudioClip(url));
0315: }
0316: return clip;
0317: }
0318: }
0319:
0320: private static Map imageRefs = new HashMap();
0321:
0322: /**
0323: * Get an image.
0324: */
0325: public Image getImage(URL url) {
0326: return getCachedImage(url);
0327: }
0328:
0329: static Image getCachedImage(URL url) {
0330: // System.getSecurityManager().checkConnection(url.getHost(), url.getPort());
0331: return (Image) getCachedImageRef(url).get();
0332: }
0333:
0334: /**
0335: * Get an image ref.
0336: */
0337: static Ref getCachedImageRef(URL url) {
0338: synchronized (imageRefs) {
0339: AppletImageRef ref = (AppletImageRef) imageRefs.get(url);
0340: if (ref == null) {
0341: ref = new AppletImageRef(url);
0342: imageRefs.put(url, ref);
0343: }
0344: return ref;
0345: }
0346: }
0347:
0348: /**
0349: * Flush the image cache.
0350: */
0351: static void flushImageCache() {
0352: imageRefs.clear();
0353: }
0354:
0355: static Vector appletPanels = new Vector();
0356:
0357: /**
0358: * Get an applet by name.
0359: */
0360: public Applet getApplet(String name) {
0361: AppletSecurity security = (AppletSecurity) System
0362: .getSecurityManager();
0363: name = name.toLowerCase();
0364: SocketPermission panelSp = new SocketPermission(panel
0365: .getCodeBase().getHost(), "connect");
0366: for (Enumeration e = appletPanels.elements(); e
0367: .hasMoreElements();) {
0368: AppletPanel p = (AppletPanel) e.nextElement();
0369: String param = p.getParameter("name");
0370: if (param != null) {
0371: param = param.toLowerCase();
0372: }
0373: if (name.equals(param)
0374: && p.getDocumentBase().equals(
0375: panel.getDocumentBase())) {
0376: SocketPermission sp = new SocketPermission(p
0377: .getCodeBase().getHost(), "connect");
0378: if (panelSp.implies(sp)) {
0379: return p.applet;
0380: }
0381: }
0382: }
0383: return null;
0384: }
0385:
0386: /**
0387: * Return an enumeration of all the accessible
0388: * applets on this page.
0389: */
0390: public Enumeration getApplets() {
0391: AppletSecurity security = (AppletSecurity) System
0392: .getSecurityManager();
0393: Vector v = new Vector();
0394: SocketPermission panelSp = new SocketPermission(panel
0395: .getCodeBase().getHost(), "connect");
0396: for (Enumeration e = appletPanels.elements(); e
0397: .hasMoreElements();) {
0398: AppletPanel p = (AppletPanel) e.nextElement();
0399: if (p.getDocumentBase().equals(panel.getDocumentBase())) {
0400: SocketPermission sp = new SocketPermission(p
0401: .getCodeBase().getHost(), "connect");
0402: if (panelSp.implies(sp)) {
0403: v.addElement(p.applet);
0404: }
0405: }
0406: }
0407: return v.elements();
0408: }
0409:
0410: /**
0411: * Ignore.
0412: */
0413: public void showDocument(URL url) {
0414: }
0415:
0416: /**
0417: * Ignore.
0418: */
0419: public void showDocument(URL url, String target) {
0420: }
0421:
0422: /**
0423: * Show status.
0424: */
0425: public void showStatus(String status) {
0426: label.setText(status);
0427: }
0428:
0429: /**
0430: * System parameters.
0431: */
0432: static Hashtable systemParam = new Hashtable();
0433: static {
0434: systemParam.put("codebase", "codebase");
0435: systemParam.put("code", "code");
0436: systemParam.put("alt", "alt");
0437: systemParam.put("width", "width");
0438: systemParam.put("height", "height");
0439: systemParam.put("align", "align");
0440: systemParam.put("vspace", "vspace");
0441: systemParam.put("hspace", "hspace");
0442: }
0443:
0444: /**
0445: * Print the HTML tag.
0446: */
0447: public static void printTag(PrintStream out, Hashtable atts) {
0448: out.print("<applet");
0449: String v = (String) atts.get("codebase");
0450: if (v != null) {
0451: out.print(" codebase=\"" + v + "\"");
0452: }
0453: v = (String) atts.get("code");
0454: if (v == null) {
0455: v = "applet.class";
0456: }
0457: out.print(" code=\"" + v + "\"");
0458: v = (String) atts.get("width");
0459: if (v == null) {
0460: v = "150";
0461: }
0462: out.print(" width=" + v);
0463: v = (String) atts.get("height");
0464: if (v == null) {
0465: v = "100";
0466: }
0467: out.print(" height=" + v);
0468: v = (String) atts.get("name");
0469: if (v != null) {
0470: out.print(" name=\"" + v + "\"");
0471: }
0472: out.println(">");
0473: // A very slow sorting algorithm
0474: int len = atts.size();
0475: String params[] = new String[len];
0476: len = 0;
0477: for (Enumeration e = atts.keys(); e.hasMoreElements();) {
0478: String param = (String) e.nextElement();
0479: int i = 0;
0480: for (; i < len; i++) {
0481: if (params[i].compareTo(param) >= 0) {
0482: break;
0483: }
0484: }
0485: System.arraycopy(params, i, params, i + 1, len - i);
0486: params[i] = param;
0487: len++;
0488: }
0489: for (int i = 0; i < len; i++) {
0490: String param = params[i];
0491: if (systemParam.get(param) == null) {
0492: out.println("<param name=" + param + " value=\""
0493: + atts.get(param) + "\">");
0494: }
0495: }
0496: out.println("</applet>");
0497: }
0498:
0499: /**
0500: * Make sure the atrributes are uptodate.
0501: */
0502: public void updateAtts() {
0503: Dimension d = panel.getSize();
0504: Insets in = panel.getInsets();
0505: panel.atts.put("width", new Integer(d.width
0506: - (in.left + in.right)).toString());
0507: panel.atts.put("height", new Integer(d.height
0508: - (in.top + in.bottom)).toString());
0509: }
0510:
0511: /**
0512: * Restart the applet.
0513: */
0514: void appletRestart() {
0515: panel.sendEvent(AppletPanel.APPLET_STOP);
0516: panel.sendEvent(AppletPanel.APPLET_DESTROY);
0517: panel.sendEvent(AppletPanel.APPLET_INIT);
0518: panel.sendEvent(AppletPanel.APPLET_START);
0519: }
0520:
0521: /**
0522: * Reload the applet.
0523: */
0524: void appletReload() {
0525: panel.sendEvent(AppletPanel.APPLET_STOP);
0526: panel.sendEvent(AppletPanel.APPLET_DESTROY);
0527: panel.sendEvent(AppletPanel.APPLET_DISPOSE);
0528: AppletPanel.flushClassLoader(panel.baseURL);
0529: /*
0530: * Make sure we don't have two threads running through the event queue
0531: * at the same time.
0532: */
0533: try {
0534: panel.joinAppletThread();
0535: panel.release();
0536: } catch (InterruptedException e) {
0537: return; // abort the reload
0538: }
0539: panel.createAppletThread();
0540: panel.sendEvent(AppletPanel.APPLET_LOAD);
0541: panel.sendEvent(AppletPanel.APPLET_INIT);
0542: panel.sendEvent(AppletPanel.APPLET_START);
0543: }
0544:
0545: /**
0546: * Save the applet to a well known file (for now) as a serialized object
0547: */
0548: void appletSave() {
0549: AccessController.doPrivileged(new PrivilegedAction() {
0550: public Object run() {
0551: // TODO: this privileged block should be made smaller
0552: // by initializing a private static variable with "user.dir"
0553:
0554: // Applet needs to be stopped for serialization to succeed.
0555: // Since panel.sendEvent only queues the event, there is a
0556: // chance that the event will not be processed before
0557: // serialization begins. However, by sending the event before
0558: // FileDialog is created, enough time is given such that this
0559: // situation is unlikely to ever occur.
0560:
0561: panel.sendEvent(AppletPanel.APPLET_STOP);
0562: FileDialog fd = new FileDialog(AppletViewer.this , amh
0563: .getMessage("appletsave.filedialogtitle"),
0564: FileDialog.SAVE);
0565: // needed for a bug under Solaris...
0566: fd.setDirectory(System.getProperty("user.dir"));
0567: fd.setFile(defaultSaveFile);
0568: fd.show();
0569: String fname = fd.getFile();
0570: if (fname == null) {
0571: // Restart applet if Save is cancelled.
0572: panel.sendEvent(AppletPanel.APPLET_START);
0573: return null; // cancelled
0574: }
0575: String dname = fd.getDirectory();
0576: File file = new File(dname, fname);
0577: try {
0578: OutputStream s = new FileOutputStream(file);
0579: ObjectOutputStream os = new ObjectOutputStream(s);
0580: showStatus(amh.getMessage("appletsave.err1",
0581: panel.applet.toString(), file.toString()));
0582: os.writeObject(panel.applet);
0583: } catch (IOException ex) {
0584: System.err.println(amh.getMessage(
0585: "appletsave.err2", ex));
0586: } finally {
0587: panel.sendEvent(AppletPanel.APPLET_START);
0588: }
0589: return null;
0590: }
0591: });
0592: }
0593:
0594: /**
0595: * Clone the viewer and the applet.
0596: */
0597: void appletClone() {
0598: Point p = location();
0599: updateAtts();
0600: factory.createAppletViewer(p.x + XDELTA, p.y + YDELTA,
0601: panel.documentURL, (Hashtable) panel.atts.clone());
0602: }
0603:
0604: /**
0605: * Show the applet tag.
0606: */
0607: void appletTag() {
0608: ByteArrayOutputStream out = new ByteArrayOutputStream();
0609: updateAtts();
0610: printTag(new PrintStream(out), panel.atts);
0611: showStatus(amh.getMessage("applettag"));
0612: Point p = location();
0613: new TextFrame(p.x + XDELTA, p.y + YDELTA, amh
0614: .getMessage("applettag.textframe"), out.toString());
0615: }
0616:
0617: /**
0618: * Show the applet info.
0619: */
0620: void appletInfo() {
0621: String str = panel.applet.getAppletInfo();
0622: if (str == null) {
0623: str = amh.getMessage("appletinfo.applet");
0624: }
0625: str += "\n\n";
0626: String atts[][] = panel.applet.getParameterInfo();
0627: if (atts != null) {
0628: for (int i = 0; i < atts.length; i++) {
0629: str += atts[i][0] + " -- " + atts[i][1] + " -- "
0630: + atts[i][2] + "\n";
0631: }
0632: } else {
0633: str += amh.getMessage("appletinfo.param");
0634: }
0635: Point p = location();
0636: new TextFrame(p.x + XDELTA, p.y + YDELTA, amh
0637: .getMessage("appletinfo.textframe"), str);
0638: }
0639:
0640: /**
0641: * Show character encoding type
0642: */
0643: void appletCharacterEncoding() {
0644: showStatus(amh.getMessage("appletencoding", encoding));
0645: }
0646:
0647: /**
0648: * Edit the applet.
0649: */
0650: void appletEdit() {
0651: }
0652:
0653: /**
0654: * Print the applet.
0655: */
0656:
0657: /* void appletPrint() {
0658: PrintJob pj = Toolkit.getDefaultToolkit().getPrintJob(
0659: this, amh.getMessage("appletprint.printjob"), (Properties)null);
0660:
0661:
0662: if (pj != null) {
0663: Dimension pageDim = pj.getPageDimension();
0664: int pageRes = pj.getPageResolution();
0665: boolean lastFirst = pj.lastPageFirst();
0666:
0667: Graphics g = pj.getGraphics();
0668: if (g != null) {
0669: panel.applet.printAll(g);
0670: g.dispose();
0671: } else {
0672: statusMsgStream.println(amh.getMessage("appletprint.fail"));
0673: }
0674: statusMsgStream.println(amh.getMessage("appletprint.finish"));
0675: pj.end();
0676:
0677: } else {
0678: statusMsgStream.println(amh.getMessage("appletprint.cancel"));
0679: }
0680: }
0681: */
0682:
0683: /**
0684: * Properties.
0685: */
0686: static AppletProps props;
0687:
0688: public static synchronized void networkProperties() {
0689: if (props == null) {
0690: props = new AppletProps();
0691: }
0692: props.addNotify();
0693: props.setVisible(true);
0694: }
0695:
0696: /**
0697: * Start the applet.
0698: */
0699: void appletStart() {
0700: panel.sendEvent(AppletPanel.APPLET_START);
0701: }
0702:
0703: /**
0704: * Stop the applet.
0705: */
0706: void appletStop() {
0707: panel.sendEvent(AppletPanel.APPLET_STOP);
0708: }
0709:
0710: /**
0711: * Shutdown a viewer.
0712: * Stop, Destroy, Dispose and Quit a viewer
0713: */
0714: private void appletShutdown(AppletPanel p) {
0715: p.sendEvent(AppletPanel.APPLET_STOP);
0716: p.sendEvent(AppletPanel.APPLET_DESTROY);
0717: p.sendEvent(AppletPanel.APPLET_DISPOSE);
0718: p.sendEvent(AppletPanel.APPLET_QUIT);
0719: }
0720:
0721: /**
0722: * Close this viewer.
0723: * Stop, Destroy, Dispose and Quit an AppletView, then
0724: * reclaim resources and exit the program if this is
0725: * the last applet.
0726: */
0727: void appletClose() {
0728: appletShutdown(panel);
0729: appletPanels.removeElement(panel);
0730: dispose();
0731: if (countApplets() == 0) {
0732: appletSystemExit();
0733: }
0734: }
0735:
0736: /**
0737: * Exit the program.
0738: * Exit from the program (if not stand alone) - do no clean-up
0739: */
0740: private void appletSystemExit() {
0741: if (factory.isStandalone())
0742: System.exit(0);
0743: }
0744:
0745: /**
0746: * Quit all viewers.
0747: * Shutdown all viewers properly then
0748: * exit from the program (if not stand alone)
0749: */
0750: protected void appletQuit() {
0751: for (Enumeration e = appletPanels.elements(); e
0752: .hasMoreElements();) {
0753: AppletPanel p = (AppletPanel) e.nextElement();
0754: appletShutdown(p);
0755: }
0756: appletSystemExit();
0757: }
0758:
0759: /**
0760: * Handle events.
0761: */
0762: public void processUserAction(ActionEvent evt) {
0763: String label = ((MenuItem) evt.getSource()).getLabel();
0764: if (amh.getMessage("menuitem.restart").equals(label)) {
0765: appletRestart();
0766: return;
0767: }
0768: if (amh.getMessage("menuitem.reload").equals(label)) {
0769: appletReload();
0770: return;
0771: }
0772: if (amh.getMessage("menuitem.clone").equals(label)) {
0773: appletClone();
0774: return;
0775: }
0776: if (amh.getMessage("menuitem.stop").equals(label)) {
0777: appletStop();
0778: return;
0779: }
0780: if (amh.getMessage("menuitem.save").equals(label)) {
0781: appletSave();
0782: return;
0783: }
0784: if (amh.getMessage("menuitem.start").equals(label)) {
0785: appletStart();
0786: return;
0787: }
0788: if (amh.getMessage("menuitem.tag").equals(label)) {
0789: appletTag();
0790: return;
0791: }
0792: if (amh.getMessage("menuitem.info").equals(label)) {
0793: appletInfo();
0794: return;
0795: }
0796: if (amh.getMessage("menuitem.encoding").equals(label)) {
0797: appletCharacterEncoding();
0798: return;
0799: }
0800: if (amh.getMessage("menuitem.edit").equals(label)) {
0801: appletEdit();
0802: return;
0803: }
0804: /* if (amh.getMessage("menuitem.print").equals(label)) {
0805: appletPrint();
0806: return;
0807: }
0808: */
0809:
0810: if (amh.getMessage("menuitem.props").equals(label)) {
0811: networkProperties();
0812: return;
0813: }
0814: if (amh.getMessage("menuitem.close").equals(label)) {
0815: appletClose();
0816: return;
0817: }
0818: if (factory.isStandalone()
0819: && amh.getMessage("menuitem.quit").equals(label)) {
0820: appletQuit();
0821: return;
0822: }
0823: //statusMsgStream.println("evt = " + evt);
0824: }
0825:
0826: /**
0827: * How many applets are running?
0828: */
0829:
0830: public static int countApplets() {
0831: return appletPanels.size();
0832: }
0833:
0834: /**
0835: * The current character.
0836: */
0837: static int c;
0838:
0839: /**
0840: * Scan spaces.
0841: */
0842: public static void skipSpace(Reader in) throws IOException {
0843: while ((c >= 0)
0844: && ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) {
0845: c = in.read();
0846: }
0847: }
0848:
0849: /**
0850: * Scan identifier
0851: */
0852: public static String scanIdentifier(Reader in) throws IOException {
0853: StringBuffer buf = new StringBuffer();
0854: while (true) {
0855: if (((c >= 'a') && (c <= 'z'))
0856: || ((c >= 'A') && (c <= 'Z'))
0857: || ((c >= '0') && (c <= '9')) || (c == '_')) {
0858: buf.append((char) c);
0859: c = in.read();
0860: } else {
0861: return buf.toString();
0862: }
0863: }
0864: }
0865:
0866: /**
0867: * Scan tag
0868: */
0869: public static Hashtable scanTag(Reader in) throws IOException {
0870: Hashtable atts = new Hashtable();
0871: skipSpace(in);
0872: while (c >= 0 && c != '>') {
0873: String att = scanIdentifier(in);
0874: String val = "";
0875: skipSpace(in);
0876: if (c == '=') {
0877: int quote = -1;
0878: c = in.read();
0879: skipSpace(in);
0880: if ((c == '\'') || (c == '\"')) {
0881: quote = c;
0882: c = in.read();
0883: }
0884: StringBuffer buf = new StringBuffer();
0885: while ((c > 0)
0886: && (((quote < 0) && (c != ' ') && (c != '\t')
0887: && (c != '\n') && (c != '\r') && (c != '>')) || ((quote >= 0) && (c != quote)))) {
0888: buf.append((char) c);
0889: c = in.read();
0890: }
0891: if (c == quote) {
0892: c = in.read();
0893: }
0894: skipSpace(in);
0895: val = buf.toString();
0896: }
0897: //statusMsgStream.println("PUT " + att + " = '" + val + "'");
0898: if (!val.equals("")) {
0899: atts.put(att.toLowerCase(), val);
0900: }
0901: while (true) {
0902: if ((c == '>') || (c < 0) || ((c >= 'a') && (c <= 'z'))
0903: || ((c >= 'A') && (c <= 'Z'))
0904: || ((c >= '0') && (c <= '9')) || (c == '_'))
0905: break;
0906: c = in.read();
0907: }
0908: //skipSpace(in);
0909: }
0910: return atts;
0911: }
0912:
0913: /* values used for placement of AppletViewer's frames */
0914: private static int x = 0;
0915: private static int y = 0;
0916: private static final int XDELTA = 30;
0917: private static final int YDELTA = XDELTA;
0918: static String encoding = null;
0919:
0920: static private Reader makeReader(InputStream is) {
0921: if (encoding != null) {
0922: try {
0923: return new BufferedReader(new InputStreamReader(is,
0924: encoding));
0925: } catch (IOException x) {
0926: }
0927: }
0928: InputStreamReader r = new InputStreamReader(is);
0929: encoding = r.getEncoding();
0930: return new BufferedReader(r);
0931: }
0932:
0933: /**
0934: * Scan an html file for <applet> tags
0935: */
0936: public static void parse(URL url, String enc) throws IOException {
0937: encoding = enc;
0938: parse(url, System.out, new StdAppletViewerFactory());
0939: }
0940:
0941: public static void parse(URL url) throws IOException {
0942: parse(url, System.out, new StdAppletViewerFactory());
0943: }
0944:
0945: public static void parse(URL url, PrintStream statusMsgStream,
0946: AppletViewerFactory factory) throws IOException {
0947: // <OBJECT> <EMBED> tag flags
0948: boolean isAppletTag = false;
0949: boolean isObjectTag = false;
0950: boolean isEmbedTag = false;
0951: // warning messages
0952: String requiresNameWarning = amh
0953: .getMessage("parse.warning.requiresname");
0954: String paramOutsideWarning = amh
0955: .getMessage("parse.warning.paramoutside");
0956: String appletRequiresCodeWarning = amh
0957: .getMessage("parse.warning.applet.requirescode");
0958: String appletRequiresHeightWarning = amh
0959: .getMessage("parse.warning.applet.requiresheight");
0960: String appletRequiresWidthWarning = amh
0961: .getMessage("parse.warning.applet.requireswidth");
0962: String objectRequiresCodeWarning = amh
0963: .getMessage("parse.warning.object.requirescode");
0964: String objectRequiresHeightWarning = amh
0965: .getMessage("parse.warning.object.requiresheight");
0966: String objectRequiresWidthWarning = amh
0967: .getMessage("parse.warning.object.requireswidth");
0968: String embedRequiresCodeWarning = amh
0969: .getMessage("parse.warning.embed.requirescode");
0970: String embedRequiresHeightWarning = amh
0971: .getMessage("parse.warning.embed.requiresheight");
0972: String embedRequiresWidthWarning = amh
0973: .getMessage("parse.warning.embed.requireswidth");
0974: String appNotLongerSupportedWarning = amh
0975: .getMessage("parse.warning.appnotLongersupported");
0976: java.net.URLConnection conn = url.openConnection();
0977: Reader in = makeReader(conn.getInputStream());
0978: /* The original URL may have been redirected - this
0979: * sets it to whatever URL/codebase we ended up getting
0980: */
0981: url = conn.getURL();
0982: int ydisp = 1;
0983: Hashtable atts = null;
0984: while (true) {
0985: c = in.read();
0986: if (c == -1)
0987: break;
0988: if (c == '<') {
0989: c = in.read();
0990: if (c == '/') {
0991: c = in.read();
0992: String nm = scanIdentifier(in);
0993: if (nm.equalsIgnoreCase("applet")
0994: || nm.equalsIgnoreCase("object")
0995: || nm.equalsIgnoreCase("embed")) {
0996: // We can't test for a code tag until </OBJECT>
0997: // because it is a parameter, not an attribute.
0998: if (isObjectTag) {
0999: if (atts.get("code") == null
1000: && atts.get("object") == null) {
1001: statusMsgStream
1002: .println(objectRequiresCodeWarning);
1003: atts = null;
1004: }
1005: }
1006: if (atts != null) {
1007: // NOTE: In general this code just simply
1008: // shouldn't be part of parsing.
1009: factory.createAppletViewer(x, y, url, atts);
1010: x += XDELTA;
1011: y += YDELTA;
1012: // make sure we don't go too far!
1013: Dimension d = Toolkit.getDefaultToolkit()
1014: .getScreenSize();
1015: if ((x > d.width - 300)
1016: || (y > d.height - 300)) {
1017: x = 0;
1018: y = 2 * ydisp * YDELTA;
1019: ydisp++;
1020: }
1021: }
1022: atts = null;
1023: isAppletTag = false;
1024: isObjectTag = false;
1025: isEmbedTag = false;
1026: }
1027: } else {
1028: String nm = scanIdentifier(in);
1029: if (nm.equalsIgnoreCase("param")) {
1030: Hashtable t = scanTag(in);
1031: String att = (String) t.get("name");
1032: if (att == null) {
1033: statusMsgStream
1034: .println(requiresNameWarning);
1035: } else {
1036: String val = (String) t.get("value");
1037: if (val == null) {
1038: statusMsgStream
1039: .println(requiresNameWarning);
1040: } else if (atts != null) {
1041: atts.put(att.toLowerCase(), val);
1042: } else {
1043: statusMsgStream
1044: .println(paramOutsideWarning);
1045: }
1046: }
1047: } else if (nm.equalsIgnoreCase("applet")) {
1048: isAppletTag = true;
1049: atts = scanTag(in);
1050: if (atts.get("code") == null
1051: && atts.get("object") == null) {
1052: statusMsgStream
1053: .println(appletRequiresCodeWarning);
1054: atts = null;
1055: } else if (atts.get("width") == null) {
1056: statusMsgStream
1057: .println(appletRequiresWidthWarning);
1058: atts = null;
1059: } else if (atts.get("height") == null) {
1060: statusMsgStream
1061: .println(appletRequiresHeightWarning);
1062: atts = null;
1063: }
1064: } else if (nm.equalsIgnoreCase("object")) {
1065: isObjectTag = true;
1066: atts = scanTag(in);
1067: // The <OBJECT> attribute codebase isn't what
1068: // we want. If its defined, remove it.
1069: if (atts.get("codebase") != null) {
1070: atts.remove("codebase");
1071: }
1072: if (atts.get("width") == null) {
1073: statusMsgStream
1074: .println(objectRequiresWidthWarning);
1075: atts = null;
1076: } else if (atts.get("height") == null) {
1077: statusMsgStream
1078: .println(objectRequiresHeightWarning);
1079: atts = null;
1080: }
1081: } else if (nm.equalsIgnoreCase("embed")) {
1082: isEmbedTag = true;
1083: atts = scanTag(in);
1084: if (atts.get("code") == null
1085: && atts.get("object") == null) {
1086: statusMsgStream
1087: .println(embedRequiresCodeWarning);
1088: atts = null;
1089: } else if (atts.get("width") == null) {
1090: statusMsgStream
1091: .println(embedRequiresWidthWarning);
1092: atts = null;
1093: } else if (atts.get("height") == null) {
1094: statusMsgStream
1095: .println(embedRequiresHeightWarning);
1096: atts = null;
1097: }
1098: } else if (nm.equalsIgnoreCase("app")) {
1099: statusMsgStream
1100: .println(appNotLongerSupportedWarning);
1101: Hashtable atts2 = scanTag(in);
1102: nm = (String) atts2.get("class");
1103: if (nm != null) {
1104: atts2.remove("class");
1105: atts2.put("code", nm + ".class");
1106: }
1107: nm = (String) atts2.get("src");
1108: if (nm != null) {
1109: atts2.remove("src");
1110: atts2.put("codebase", nm);
1111: }
1112: if (atts2.get("width") == null) {
1113: atts2.put("width", "100");
1114: }
1115: if (atts2.get("height") == null) {
1116: atts2.put("height", "100");
1117: }
1118: printTag(statusMsgStream, atts2);
1119: statusMsgStream.println();
1120: }
1121: }
1122: }
1123: }
1124: in.close();
1125: }
1126:
1127: /**
1128: * Old main entry point.
1129: *
1130: * @deprecated
1131: */
1132: public static void main(String argv[]) {
1133: // re-route everything to the new main entry point
1134: Main.main(argv);
1135: }
1136:
1137: private static AppletMessageHandler amh = new AppletMessageHandler(
1138: "appletviewer");
1139:
1140: private static void checkConnect(URL url) {
1141: SecurityManager security = System.getSecurityManager();
1142: if (security != null) {
1143: try {
1144: java.security.Permission perm = url.openConnection()
1145: .getPermission();
1146: if (perm != null)
1147: security.checkPermission(perm);
1148: else
1149: security.checkConnect(url.getHost(), url.getPort());
1150: } catch (java.io.IOException ioe) {
1151: security.checkConnect(url.getHost(), url.getPort());
1152: }
1153: }
1154: }
1155: }
|