// AppletLoader - An error-handling applet container with optional frame // Copyright (C) 2001 Jon A. Maxwell (JAM) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import java.util.*; import java.applet.*; import java.awt.*; import java.awt.event.*; /** * This applet will try to load another applet class (using the * same classloader) and run it in within this applet. If the * applet does not load correctly because of an incorrect Java * version or other error, an appropriate error message is * displayed instead of the normal applet gray box.
* * The applet also adds a title and an expand button that moves * the applet into a Frame, allowing it to be resized.
*
* The following applet parameters are used:
* Loader_AppletClassName - the applet to load
* Loader_AppletName - the title string.
* * @author Jon A. Maxwell (JAM) */ public class AppletLoader extends Applet implements AppletStub, MouseListener, WindowListener { // todo: the methods delegating to the contained applet might // also catch link and class not found errors since linking can // happen at any point depending on the applet run. /** applet loaded correctly */ boolean appletLoaded = false; /** whether loaded applet has been initialized */ boolean appletInitialized = false; /** message to print if applet could not load */ String notLoadedMessage = null; // set in init() on error /** the loaded applet */ Applet applet = null; /** applet classname to load */ String appletName = null; /** image that expands applet into a frame */ Image expandImage = null; /** whether in the browser (docket) or in a frame */ boolean docked = false; /** frame when undocked */ Frame frame = null; /** size of title area */ final int titleHeight = 24; /** applet "empty" color */ Color emptyColor = new Color(240, 240, 240); /** * Initialize the AppletLoader. */ public void init() { System.out.println("AppletLoader - Jon A. Maxwell (JAM) - http://www.acm.vt.edu/~jmaxwell"); //this.setBackground(Color.white); // not needed because we paint the whole area } public void start() { // comment out initLoadedApplet to have the background // cleared before attempting to load the other applet // (minimizes gray box time for larger applets). Applet // will be loaded in the paint method, which could cause // unwanted side-effects. if (!appletInitialized) initLoadedApplet(); else if (appletLoaded) { applet.start(); if (!docked) frame.show(); } } /** * Load, init, and start the contained applet. The * AppletLoader must have been started before calling this * method. Calling this method more than once is safe and * performs no additional operations. */ public void initLoadedApplet() { if (appletInitialized) return; appletInitialized = true; // do first to prevent retry on error // get properties String appletClassName = getParameter("Loader_AppletClassName"); appletName = getParameter("Loader_AppletName"); if (appletName == null) appletName=appletClassName; // load and start Applet try { applet = (Applet) Class.forName(appletClassName).newInstance(); applet.setStub(this); // cleverly avoid using another class setDocked(true); // some applets must be displayed before init called // both start and init can also throw link / class not found errors applet.init(); applet.start(); appletLoaded = true; } catch (Throwable t) { setErrorMessage(t); } // load images try { expandImage = Toolkit.getDefaultToolkit().getImage( getClass().getClassLoader().getResource("resources/Frame.gif")); } catch (Exception ex) { // Netscape 4 won't read images out of the jar file properly // so just ignore and then don't paint the image. } this.addMouseListener(this); } /** * Docks the applet inside of the browser or places it in a * frame. * * @param docked dock applet if true, place in frame if false */ void setDocked(boolean dock) { // short circuit if (docked == dock) return; docked = dock; if (dock) { if (frame != null) { frame.hide(); frame.remove(applet); } this.add(applet); // custom layout } else { if (frame == null) { frame = new Frame(appletName); frame.setLayout(new BorderLayout()); frame.addWindowListener(this); // should correct for titleHeight, but Frame size includes // it's own title size which is unknowable in early JREs // and they cancel each other out to some degree. frame.setSize( getSize() ); } this.remove(applet); frame.add(applet, BorderLayout.CENTER); frame.show(); } validate(); repaint(); } /** * Layout the contained applet. */ public void doLayout() { if (docked) applet.setBounds(0, titleHeight, getSize().width, getSize().height-titleHeight); } /** * Set the error message based on a throwable type. */ void setErrorMessage(Throwable t) { t.printStackTrace(); notLoadedMessage = "Could not load applet.\n"; if (t instanceof ExceptionInInitializerError) notLoadedMessage += "Applet did not initialize properly."; else if (t instanceof UnsatisfiedLinkError || t instanceof LinkageError || t instanceof ClassNotFoundException) notLoadedMessage += "Incompatible Java version."; // remove signs of applet appletLoaded = false; if (applet != null) removeAll(); if (frame != null) frame.hide(); } /** * Prevent potential flash of background clearing. */ public void update(Graphics g) { // super clears the background paint(g); } /** * Paint the applet name and expand icon or if there was an * error loading the applet, paint the applet name and error * message. */ public void paint(Graphics g) { super.paint(g); g = g.create(); // clear background Dimension size = getSize(); // jdk1.1 doesn't have Component.getWidth, Component.getHeight methods g.setColor(Color.white); g.fillRect(0, 0, size.width, titleHeight); g.setColor(emptyColor); g.fillRect(0, titleHeight, size.width, size.height); // applet may be initialized in paint to reduce the gray box // time (make sure background is cleared by this point or // there's no advantage to doing it here). initLoadedApplet(); // if not already initialized // draw title Font font = new Font("SansSerif", Font.BOLD, 14); // Dialog, Serif FontMetrics fm = g.getFontMetrics(font); int baseline = titleHeight/2 + fm.getAscent()/2; g.setFont(font); g.setColor(Color.black); g.drawString(appletName, 0, baseline); // draw expand image if (expandImage != null && appletLoaded && docked) { // this may paint partially on-screen if the image is // partially loaded but should be unnoticable g.drawImage(expandImage, // no Component.getWidth() in jdk1.1: getSize().width - 1 - expandImage.getWidth(this), titleHeight/2 - expandImage.getHeight(this)/2, Color.white, this); } // error message if (!appletLoaded) paintErrorMessage(g); g.dispose(); } protected void paintErrorMessage(Graphics g) { Dimension size = getSize(); // jdk1.1 doesn't have Component.getWidth, Component.getHeight methods // red-X points int xPoints[] = { 8, 6, 3, 3, 11, 3, 3, 6, 8, 16, 24, 26, 29, 29, 21, 29, 29, 26, 24, 16 }; int yPoints[] = {28, 28, 25, 23, 15, 7, 5, 2, 2, 10, 2, 2, 5, 7, 15, 23, 25, 28, 28, 20 }; // scaled polygon to 1/3 of shortest dimension float scale = Math.min( (size.width/3f) / 29, ((size.height-titleHeight)/3f) / 28 ); for (int i=0; i < xPoints.length; i++) { xPoints[i] = (int)(xPoints[i] * scale); yPoints[i] = (int)(yPoints[i] * scale); } int centerX = size.width/2; int centerY = (size.height-titleHeight)/2 + titleHeight; // translate red-X Polygon xGon = new Polygon(xPoints, yPoints, xPoints.length); Rectangle bounds = xGon.getBounds(); xGon.translate( centerX - bounds.width/2 - bounds.x, centerY - bounds.height/2 - bounds.y); // draw red-X g.setColor(Color.red); g.fillPolygon(xGon); int fontSize = // also try (int)(*2.75) instead of *3 Math.min(24, Math.max(8, 3*size.width/notLoadedMessage.length()) ); Font font = new Font("SansSerif", Font.BOLD, fontSize); // Dialog, Serif FontMetrics fm = g.getFontMetrics(font); // split error message on newline, draw lines of text centered g.setFont(font); int fontY = centerY + bounds.height/2 + fm.getHeight(); StringTokenizer st = new StringTokenizer(notLoadedMessage, "\n"); while (st.hasMoreTokens()) { String text = st.nextToken(); char cbuf[] = new char[text.length()]; text.getChars(0, cbuf.length, cbuf, 0); int errWidth = fm.charsWidth(cbuf, 0, cbuf.length); g.drawString(text, centerX - errWidth/2, fontY); fontY += fm.getHeight(); } } // Mouse listener methods public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseClicked(MouseEvent e) { // click in rough area of icon if docked, any area if free if (appletLoaded && (!docked || e.getX() > getSize().width-30)) setDocked(!docked); } // Window listener methods public void windowActivated(WindowEvent e) {} public void windowClosed(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowOpened(WindowEvent e) {} public void windowClosing(WindowEvent e) { setDocked(true); } /** * Implements the appletResize method of AppletStub; other * methods are automatically implemented by the applet itself * because they have the same name as Applet methods. */ public void appletResize(int width, int height) { resize(width, height); } // The following methods delegate applet methods to the loaded // applet. public void stop() { if (appletLoaded) { applet.stop(); if (!docked) frame.hide(); } } public void destroy() { if (appletLoaded) applet.destroy(); } /* Requires javax public AccessibleContext getAccessibleContext() { if (appletLoaded) applet.getAccessibleContext(); } */ public String getAppletInfo() { String ad = " (AppletLoader by Jon A. Maxwell (JAM) - www.acm.vt.edu/~jmaxwell)"; if (appletLoaded) return "" + applet.getAppletInfo() + ad; return ad; } public String[][] getParameterInfo() { // probably should also add in appletloader parameters if (appletLoaded) return applet.getParameterInfo(); return null; } }