All Downloads are FREE. Search and download functionalities are using the official Maven repository.

acm.program.CommandLineProgram Maven / Gradle / Ivy

Go to download

This the original Stanford Karel for Java, packaged for Maven. ACM Library is included. See also https://cs.stanford.edu/people/eroberts/karel-the-robot-learns-java.pdf

The newest version!
/*
 * @(#)CommandLineProgram.java   1.99.1 08/12/08
 */

// ************************************************************************
// * Copyright (c) 2008 by the Association for Computing Machinery        *
// *                                                                      *
// * The Java Task Force seeks to impose few restrictions on the use of   *
// * these packages so that users have as much freedom as possible to     *
// * use this software in constructive ways and can make the benefits of  *
// * that work available to others.  In view of the legal complexities    *
// * of software development, however, it is essential for the ACM to     *
// * maintain its copyright to guard against attempts by others to        *
// * claim ownership rights.  The full text of the JTF Software License   *
// * is available at the following URL:                                   *
// *                                                                      *
// *          http://www.acm.org/jtf/jtf-software-license.pdf             *
// *                                                                      *
// ************************************************************************

// REVISION HISTORY
//
// Class introduced in V1.1

package acm.program;

import acm.io.*;
import acm.util.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import javax.swing.*;

/**
 * This class simulates the functionality of a ConsoleProgram
 * in an environment that lacks a graphics context. As of JDK 1.4, it is
 * illegal even to instantiate an applet in a non-graphics environment
 * (called "headless" in the Java terminology), which means that the program
 * can no longer extend Applet or JApplet.  This
 * class creates a stripped-down program class that duplicates the operation
 * of a ConsoleProgram using the standard I/O streams.
 */
public class CommandLineProgram
  implements IOModel, Runnable, MouseListener, MouseMotionListener,
             KeyListener, ActionListener {

/** Constant specifying the north edge of the container */
	public static final String NORTH = BorderLayout.NORTH;

/** Constant specifying the south edge of the container */
	public static final String SOUTH = BorderLayout.SOUTH;

/** Constant specifying the east edge of the container */
	public static final String EAST = BorderLayout.EAST;

/** Constant specifying the west edge of the container */
	public static final String WEST = BorderLayout.WEST;

/** Constant specifying the center of the container */
	public static final String CENTER = BorderLayout.CENTER;

/* Default constructor: CommandLineProgram */
/**
 * This code initializes the program data structures.
 */
	protected CommandLineProgram() {
		parameterTable = null;
		finalizers = new ArrayList();
		myTitle = getClass().getName();
		myTitle = myTitle.substring(myTitle.lastIndexOf(".") + 1);
		setConsole(createConsole());
	}

/* Static method: checkIfHeadless(className) */
/**
 * Checks to see if the program is running in a headless environment and, if so,
 * runs it in that form.  If the environment is indeed headless, this call never
 * returns.
 *
 * Example: CommandLineProgram.checkIfHeadless(className);
 * @param className The name of the main class
 */
	public static void checkIfHeadless(String className) {
		if (!JTFTools.testDebugOption("headless")) {
			try {
				Class graphicsEnvironmentClass = Class.forName("java.awt.GraphicsEnvironment");
				Method isHeadless = graphicsEnvironmentClass.getMethod("isHeadless", new Class[0]);
				if (!Boolean.TRUE.equals(isHeadless.invoke(null, new Object[0]))) return;
			} catch (Exception ex) {
				return;
			}
		}
		try {
			ClassLoader loader = new CommandLineProgramLoader(className);
			Class mainClass = loader.loadClass(className);
			CommandLineProgram program = (CommandLineProgram) mainClass.newInstance();
			program.init();
			program.run();
			program.exit();
		} catch (Exception ex) {
			throw new ErrorException(ex);
		}
	}

/* Method: run() */
/**
 * Contains the code to be executed for each specific program subclass.  If
 * you are defining your own program, you need to override the definition of
 * run so that it contains the code for your application.
 */
	public void run() {
		/* Empty */
	}

/* Method: init() */
/**
 * The init method is called at startup time before the run method is
 * called.  Subclasses can override this method to perform any
 * initialization code that would ordinarily be included in an applet
 * init method.  This method is used only for certain styles
 * of application development that have their roots in the applet world;
 * other styles will not ordinarily use or override this method.
 *
 * Example: program.init();
 */
	public void init() {
		/* Empty */
	}

/* Method: print(value) */
/**
 * Displays the argument value on the console, leaving the cursor at the end of
 * the output.  The print method is overloaded so that
 * value can be of any type.
 *
 * Example: program.print(value);
 * @param value The value to be displayed
 */
	public void print(String value) {
		getOutputModel().print(value);
	}

/**
 * Makes sure that print can display a boolean.
 *
 */
	public final void print(boolean x) {
		print("" + x);
	}

/**
 * Makes sure that print can display a char.
 *
 */
	public final void print(char x) {
		print("" + x);
	}

/**
 * Makes sure that print can display a double.
 *
 */
	public final void print(double x) {
		print("" + x);
	}

/**
 * Makes sure that print can display a float.
 *
 */
	public final void print(float x) {
		print("" + x);
	}

/**
 * Makes sure that print can display an int.
 *
 */
	public final void print(int x) {
		print("" + x);
	}

/**
 * Makes sure that print can display a long.
 *
 */
	public final void print(long x) {
		print("" + x);
	}

/**
 * Makes sure that print can display an Object.
 *
 */
	public final void print(Object x) {
		print("" + x);
	}

/* Method: println() */
/**
 * Advances the console cursor to the beginning of the next line.
 *
 * Example: program.println();
 */
	public void println() {
		getOutputModel().println();
	}

/* Method: println(value) */
/**
 * Displays the argument value on the console and then advances the cursor
 * to the beginning of the next line.  The println method is
 * overloaded so that value can be of any type.
 *
 * Example: program.println(value);
 * @param value The value to be displayed
 */
	public void println(String value) {
		getOutputModel().println(value);
	}

/**
 * Makes sure that println can display a boolean.
 *
 */
	public final void println(boolean x) {
		println("" + x);
	}

/**
 * Makes sure that println can display a char.
 *
 */
	public final void println(char x) {
		println("" + x);
	}

/**
 * Makes sure that println can display a double.
 *
 */
	public final void println(double x) {
		println("" + x);
	}

/**
 * Makes sure that println can display a float.
 *
 */
	public final void println(float x) {
		println("" + x);
	}

/**
 * Makes sure that println can display an int.
 *
 */
	public final void println(int x) {
		println("" + x);
	}

/**
 * Makes sure that println can display a long.
 *
 */
	public final void println(long x) {
		println("" + x);
	}

/**
 * Makes sure that println can display an Object.
 *
 */
	public final void println(Object x) {
		println("" + x);
	}

/* Method: showErrorMessage(msg) */
/**
 * Displays the error message in the standard output model.
 *
 * Example: showErrorMessage(msg);
 * @param msg The error msg to be displayed
 */
	public void showErrorMessage(String msg) {
		getOutputModel().showErrorMessage(msg);
	}

/* Method: readLine() */
/**
 * Reads and returns a line of input from the console.  The end-of-line
 * characters that terminate the input are not included in the returned
 * string.
 *
 * Example: String str = program.readLine();
 * @return The next line of input as a String
 */
	public final String readLine() {
		return readLine(null);
	}

/* Method: readLine(prompt) */
/**
 * Prompts the user for a line of input.  The end-of-line characters
 * that terminate the input are not included in the returned string.
 *
 * Example: String str = program.readLine(prompt);
 * @param prompt The prompt string to display to the user
 * @return The next line of input as a String
 */
	public String readLine(String prompt) {
		return getInputModel().readLine(prompt);
	}

/* Method: readInt() */
/**
 * Reads and returns an integer value from the user.  If the user types
 * a value that is not a legal integer, the method ordinarily offers the
 * user a chance to reenter the data, although this behavior can be
 * changed using the
 * setExceptionOnError method.
 *
 * Example: int n = program.readInt();
 * @return The value of the input interpreted as a decimal integer
 */
	public final int readInt() {
		return readInt(null, Integer.MIN_VALUE, Integer.MAX_VALUE);
	}

/* Method: readInt(low, high) */
/**
 * Reads and returns an integer value from the user, which is constrained to
 * be within the specified inclusive range.  If the user types a value
 * that is not a legal integer, the method ordinarily offers the user a chance
 * to reenter the data, although this behavior can be changed using the
 * setExceptionOnError method.
 *
 * Example: int n = program.readInt(low, high);
 * @param low The lowest value in the permitted range
 * @param high The highest value in the permitted range
 * @return The value of the input interpreted as a decimal integer
 */
	public final int readInt(int low, int high) {
		return readInt(null, low, high);
	}

/* Method: readInt(prompt) */
/**
 * Prompts the user to enter an integer, which is then returned as the value
 * of this method.  If the user types a value that is not a legal integer,
 * the method ordinarily offers the user a chance to reenter the data,
 * although this behavior can be changed using the
 * setExceptionOnError method.
 *
 * Example: int n = program.readInt(prompt);
 * @param prompt The prompt string to display to the user
 * @return The value of the input interpreted as a decimal integer
 */
	public final int readInt(String prompt) {
		return readInt(prompt, Integer.MIN_VALUE, Integer.MAX_VALUE);
	}

/* Method: readInt(prompt, low, high) */
/**
 * Prompts the user to enter an integer, which is then returned as the value
 * of this method.  The value must be within the inclusive range between
 * low and high.  If the user types a value that
 * is not a legal integer or is outside the specified range, the method
 * ordinarily offers the user a chance to reenter the data,
 * although this behavior can be changed using the
 * setExceptionOnError method.
 *
 * Example: int n = console.readInt(prompt, low, high);
 * @param prompt The prompt string to display to the user
 * @param low The lowest value in the permitted range
 * @param high The highest value in the permitted range
 * @return The value of the input interpreted as a decimal integer
 */
	public int readInt(String prompt, int low, int high) {
		return getInputModel().readInt(prompt, low, high);
	}

/* Method: readDouble() */
/**
 * Reads and returns a double-precision value from the user.  If the user
 * types a value that is not a legal number, the method ordinarily offers
 * the user a chance to reenter the data, although this behavior can be
 * changed using the
 * setExceptionOnError method.
 *
 * Example: double d = program.readDouble();
 * @return The value of the input interpreted as a double
 */
	public final double readDouble() {
		return readDouble(null, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
	}

/* Method: readDouble(low, high) */
/**
 * Reads and returns a double-precision value from the user, which is
 * constrained to be within the specified inclusive range.  If the user
 * types a value that is not a legal number, the method ordinarily offers
 * the user a chance to reenter the data, although this behavior can be
 * changed using the
 * setExceptionOnError method.
 *
 * Example: double d = program.readDouble(low, high);
 * @param low The lowest value in the permitted range
 * @param high The highest value in the permitted range
 * @return The value of the input interpreted as a double
 */
	public final double readDouble(double low, double high) {
		return readDouble(null, low, high);
	}

/* Method: readDouble(prompt) */
/**
 * Prompts the user to enter an double-precision number, which is then
 * returned as the value of this method.  If the user types a value that
 * is not a legal number, the method ordinarily offers the user a chance to
 * reenter the data,  although this behavior can be changed using the
 * setExceptionOnError method.
 *
 * Example: double d = program.readDouble(prompt);
 * @param prompt The prompt string to display to the user
 * @return The value of the input interpreted as a double
 */
	public final double readDouble(String prompt) {
		return readDouble(prompt, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
	}

/* Method: readDouble(prompt, low, high) */
/**
 * Prompts the user to enter an double-precision number, which is then returned
 * as the value of this method.  The value must be within the inclusive range
 * between low and high.  If the user types a value
 * that is not a legal number, the method ordinarily offers the user a chance
 * to reenter the data,  although this behavior can be changed using the
 * setExceptionOnError method.
 *
 * Example: d = program.readDouble(prompt, low, high);
 * @param prompt The prompt string to display to the user
 * @param low The lowest value in the permitted range
 * @param high The highest value in the permitted range
 * @return The value of the input interpreted as a double
 */
	public double readDouble(String prompt, double low, double high) {
		return getInputModel().readDouble(prompt, low, high);
	}

/* Method: readBoolean() */
/**
 * Reads and returns a boolean value (true or false).
 * The input must match one of these strings, ignoring case.  If the user
 * types a value that is not one of these possibilities, the method ordinarily
 * offers the user a chance to reenter the data, although this behavior
 * can be changed using the
 * setExceptionOnError method.
 *
 * Example: boolean flag = program.readBoolean();
 * @return The value of the input interpreted as a boolean value
 */
	public final boolean readBoolean() {
		return readBoolean(null);
	}

/* Method: readBoolean(prompt) */
/**
 * Prompts the user to enter a boolean value, which is returned as
 * the value of this method.  If the user types a value that is not a
 * legal boolean value, the method ordinarily offers the user a chance
 * to reenter the data, although this behavior can be changed using the
 * setExceptionOnError method.
 *
 * Example: boolean flag = program.readBoolean(prompt);
 * @param prompt The prompt string to display to the user
 * @return The value of the input interpreted as a boolean value
 */
	public final boolean readBoolean(String prompt) {
		return readBoolean(prompt, "true", "false");
	}

/* Method: readBoolean(prompt, trueLabel, falseLabel) */
/**
 * Prompts the user to enter a boolean value, which is matched against the
 * labels provided.  If the user enters a value that is not one of the two
 * choices, readBoolean ordinarily offers the user a chance
 * to reenter the data, although this behavior can be changed using the
 * setExceptionOnError method.
 *
 * Example: boolean flag = program.readBoolean(prompt);
 * @param prompt The prompt string to display to the user
 * @param trueLabel The string used to indicate true
 * @param falseLabel The string used to indicate false
 * @return The value of the input interpreted as a boolean value
 */
	public boolean readBoolean(String prompt, String trueLabel, String falseLabel) {
		return getInputModel().readBoolean(prompt, trueLabel, falseLabel);
	}

/* Method: isAppletMode() */
/**
 * Returns true if this program is running as an applet in a browser.
 *
 * Example: if (isAppletMode()) . . .
 * @return true if this program is running as an applet, false otherwise
 *
 */
	public boolean isAppletMode() {
		return false;
	}

/* Method: setConsole(console) */
/**
 * Sets the console associated with this program.
 *
 * Example: program.setConsole(console);
 * @param console The IOConsole object used for this program
 */
	public void setConsole(IOConsole console) {
		myConsole = console;
	}

/* Method: getConsole() */
/**
 * Returns the console associated with this program.
 *
 * Example: IOConsole console = program.getConsole();
 * @return The IOConsole object used for this program
 */
	public IOConsole getConsole() {
		return myConsole;
	}

/* Method: getDialog() */
/**
 * Returns the dialog used for user interaction.
 *
 * Example: IODialog dialog = program.getDialog();
 * @return The IODialog object used for this program
 */
	public IODialog getDialog() {
		return null;
	}

/* Method: getInputModel() */
/**
 * Returns the IOModel used for program input, which will
 * typically be either the default IOConsole or IODialog object.
 *
 * Example: IOModel io = program.getInputModel();
 * @return The IOModel used for program input
 */
	public IOModel getInputModel() {
		return getConsole();
	}

/* Method: getOutputModel() */
/**
 * Returns the IOModel used for program output, which will
 * typically be either the default IOConsole or IODialog object.
 *
 * Example: IOModel io = program.getOutputModel();
 * @return The IOModel used for program output
 */
	public IOModel getOutputModel() {
		return getConsole();
	}

/* Method: getReader() */
/**
 * Returns a BufferedReader whose input comes from the console.
 *
 * Example: BufferedReader rd = getReader();
 * @return A Reader for use with this console
 */
	public BufferedReader getReader() {
		return getConsole().getReader();
	}

/* Method: getWriter() */
/**
 * Returns a PrintWriter whose output is directed to the console.
 *
 * Example: PrintWriter wr = getWriter();
 * @return A PrintWriter for use with this console
 */
	public PrintWriter getWriter() {
		return getConsole().getWriter();
	}

/* Method: getRegionPanel(region) */
/**
 * Gets the JPanel for the specified region.
 *
 * Example: JPanel panel = getRegionPanel(region);
 * @param region The region of the window (NORTH, SOUTH,
 *               EAST, WEST, or CENTER)
 * @return The JPanel for that subregion
 *
 */
	public JPanel getRegionPanel(String region) {
		if (region != region) /* Avoid unused parameter warning */;
		throw new ErrorException("No graphics environment");
	}

/* Method: add(comp, region, constraints) */
/**
 * Adds the component to the specified border region with the indicated
 * constraints object.
 *
 * Example: add(comp, region, constraints);
 * @param comp The component to be added
 * @param region The region of the window (NORTH, SOUTH,
 *               EAST, WEST, or CENTER)
 * @param constraints The constraints object
 *
 */
	public void add(Component comp, String region, Object constraints) {
		if (comp != comp) /* Avoid unused parameter warning */;
		if (region != region) /* Avoid unused parameter warning */;
		if (constraints != constraints) /* Avoid unused parameter warning */;
		throw new ErrorException("No graphics environment");
	}

/* Method: addActionListeners() */
/**
 * Adds the program as an ActionListener to every button in
 * the structure that does not have a listener already.
 *
 * Example: addActionListeners();
 */
	public void addActionListeners() {
		throw new ErrorException("No graphics environment");
	}

/* Method: addActionListeners(listener) */
/**
 * Adds the specified listener to every button in
 * the structure that does not have a listener already.
 *
 * Example: addActionListeners(listener);
 * @param listener The ActionListener to be added
 */
	public void addActionListeners(ActionListener listener) {
		if (listener != listener) /* Avoid unused parameter warning */;
		throw new ErrorException("No graphics environment");
	}

/* Method: setTitle(title) */
/**
 * Sets the title of this program.  The title appears in the title bar
 * when the program is running as an application.
 *
 * Example: setTitle(title);
 * @param title The title for this program
 */
	public void setTitle(String title) {
		myTitle = title;
	}

/* Method: getTitle() */
/**
 * Gets the title of this program.
 *
 * Example: String title = getTitle();
 * @return The title in use for this program
 */
	public String getTitle() {
		return myTitle;
	}

/* Method: start(args) */
/**
 * Starts the program using the specified argument list.
 *
 * Example: program.start(args);
 * @param args An array of strings passed to the program
 */
	public void start(String[] args) {
		if (parameterTable == null && args != null) {
			parameterTable = createParameterTable(args);
		}
		init();
		run();
	}

/* Method: exit() */
/**
 * Exits from the program.  Subclasses should override this method if they need
 * to perform any actions before shutting down the program, such as asking the
 * user to save any unsaved files.  Any clients that do override this method
 * should call super.exit() at the end of their processing.
 *
 * Example: program.exit();
 */
	public void exit() {
		int nFinalizers = finalizers.size();
		for (int i = 0; i < nFinalizers; i++) {
			Object obj = finalizers.get(i);
			try {
				Class c = obj.getClass();
				Method exit = c.getMethod("exit", new Class[0]);
				exit.invoke(obj, new Object[0]);
			} catch (Exception ex) {
				throw new ErrorException(ex);
			}
		}
	}

/* Method: addExitHook(obj) */
/**
 * Requests that the program call the exit method in the
 * specified object before exiting.
 *
 * Example: program.addExitHook(obj);
 * @param obj finalizer
 */
	public void addExitHook(Object obj) {
		finalizers.add(obj);
	}

/**********************************************************************/
/* Listener methods                                                   */
/**********************************************************************/

/* Method: mouseClicked (implements MouseListener) */
/**
 * Called when the mouse is clicked.  A call to mouseClicked
 * is always preceded by both a mousePressed and a
 * mouseReleased event for the same source.
 *
 * @param e event
 */
	public void mouseClicked(MouseEvent e) { }

/* Method: mousePressed (implements MouseListener) */
/**
 * Called when the mouse button is pressed.
 *
 * @param e event
 */
	public void mousePressed(MouseEvent e) { }

/* Method: mouseReleased (implements MouseListener) */
/**
 * Called when the mouse button is released.
 *
 * @param e event
 */
	public void mouseReleased(MouseEvent e) { }

/* Method: mouseEntered (implements MouseListener) */
/**
 * Called when the mouse enters the source (which may be
 * either a component or a GObject).
 *
 * @param e event
 */
	public void mouseEntered(MouseEvent e) { }

/* Method: mouseExited (implements MouseListener) */
/**
 * Called when the mouse exits the source (which may be
 * either a component or a GObject).
 *
 * @param e event
 */
	public void mouseExited(MouseEvent e) { }

/* Method: mouseMoved (implements MouseMotionListener) */
/**
 * Called when the mouse is moved.
 *
 * @param e event
 */
	public void mouseMoved(MouseEvent e) { }

/* Method: mouseDragged (implements MouseMotionListener) */
/**
 * Called when the mouse is dragged with the button down.  Java
 * makes several guarantees about dragging.  First, a
 * mouseDragged call is always preceded by a
 * mousePressed call for the same source.  If the
 * mouse is pressed elsewhere and then enters a source with
 * the button down, no drag event occurs.  Moreover, once the
 * mouse button goes down in a particular source, only that
 * source will receive mouse events until the button goes up.
 * Those events, moreover, are reported even in the mouse
 * travels outside the domain of the object.
 *
 * @param e event
 */
	public void mouseDragged(MouseEvent e) { }

/* Method: keyTyped (implements KeyListener) */
/**
 * Called when a key is typed (i.e., pressed and released).
 *
 * @param e event
 */
	public void keyTyped(KeyEvent e) { }

/* Method: keyPressed (implements KeyListener) */
/**
 * Called when a key is pressed.
 *
 * @param e event
 */
	public void keyPressed(KeyEvent e) { }

/* Method: keyReleased (implements KeyListener) */
/**
 * Called when a key is released.
 *
 * @param e event
 */
	public void keyReleased(KeyEvent e) { }

/* Method: actionPerformed (implements ActionListener) */
/**
 * Called when a component (typically a button) is activated.
 *
 * @param e event
 */
	public void actionPerformed(ActionEvent e) { }

/* Factory method: createConsole() */
/**
 * Creates the console used by the ConsoleProgram.  Subclasses can
 * override this method to create their own console types.
 *
 * Example: IOConsole console = program.createConsole();
 * @return The console to be used by the program
 */
	protected IOConsole createConsole() {
		return IOConsole.SYSTEM_CONSOLE;
	}

/* Factory method: createDialogIO() */
/**
 * Creates the dialog used for interaction (primarily by the DialogProgram
 * class).  Subclasses can override this method to create their own dialog types.
 *
 * Example: IODialog dialog = program.createDialogIO();
 * @return The dialog to be used by the program
 */
	protected IODialog createDialogIO() {
		throw new ErrorException("No graphics environment");
	}

/**********************************************************************/
/* Overrides of existing methods                                      */
/**********************************************************************/

/* Overridden method: getPreferredSize() */
/**
 * Returns the preferred size of the content pane.
 *
 * Example: Dimension size = getPreferredSize();
 * @return The preferred size of the content pane
 *
 */
	public Dimension getPreferredSize() {
		return new Dimension(0, 0);
	}

/* Overridden method: getWidth() */
/**
 * Returns the width of the central region.
 *
 * Example: int width = getWidth();
 * @return The width of the central region
 *
 */
	public int getWidth() {
		return 0;
	}

/* Overridden method: getHeight() */
/**
 * Returns the height of the central region.
 *
 * Example: int height = getHeight();
 * @return The height of the central region
 *
 */
	public int getHeight() {
		return 0;
	}

/* Overridden method: getParameter(name) */
/**
 * Returns the parameter associated with name.
 *
 * Example: String value = getParameter(name);
 * @param name The name of the parameter
 * @return The value associated with the parameter, or null if none
 *
 */
	public String getParameter(String name) {
		String value = null;
		if (parameterTable != null) {
			value = parameterTable.get(name.toLowerCase());
		}
		return value;
	}

/* Overridden method: setLayout(layout) */
/**
 * Sets the layout manager for the central region of the content pane.
 *
 * Example: setLayout(layout);
 * @param layout The layout manager to use
 *
 */
	public void setLayout(LayoutManager layout) {
		if (layout != layout) /* Avoid unused parameter warning */;
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: getLayout() */
/**
 * Gets the layout manager for the central region of the content pane.
 *
 * Example: LayoutManager layout = setLayout();
 * @return The active layout manager
 *
 */
	public LayoutManager getLayout() {
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: setBackground(color) */
/**
 * Sets the background for the central region of the content pane.
 *
 * Example: setBackground(color);
 * @param color The new background color
 *
 */
	public void setBackground(Color color) {
		if (color != color) /* Avoid unused parameter warning */;
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: addImpl(comp, constraints, index) */
/**
 * Adds the specified component to the content pane using the specified constraints and index.
 *
 * @param comp just a dummy param to keep the impl
 * @param constraints just a dummy param to keep the impl
 * @param index just a dummy param to keep the impl
 */
	protected void addImpl(Component comp, Object constraints, int index) {
		if (comp != comp) /* Avoid unused parameter warning */;
		if (constraints != constraints) /* Avoid unused parameter warning */;
		if (index != index) /* Avoid unused parameter warning */;
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: remove(index) */
/**
 * Removes the component at the specified index from the central region.
 *
 * Example: remove(index);
 * @param index The index position of the component to remove
 *
 */
	public void remove(int index) {
		if (index != index) /* Avoid unused parameter warning */;
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: remove(comp) */
/**
 * Removes the specified component from the central region.
 *
 * Example: remove(comp);
 * @param comp The component to remove
 *
 */
	public void remove(Component comp) {
		if (comp != comp) /* Avoid unused parameter warning */;
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: removeAll() */
/**
 * Removes all components from the central region.
 *
 * Example: removeAll();
 *
 */
	public void removeAll() {
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: validate() */
/**
 * Forwards validate to the content pane.
 *
 * Example: validate();
 *
 */
	public void validate() {
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: repaint() */
/**
 * Forwards repaint to the content pane.
 *
 * Example: repaint();
 *
 */
	public void repaint() {
		throw new ErrorException("No graphics environment");
	}

/* Overridden method: destroy() */
/**
 * Called when the program has been told to destroy itself.
 *
 * Example: program.destroy();
 *
 */
	public void destroy() {
		/* Empty */
	}

/* Static method: main(args) */
/**
 * Every application must either contain a "Main-Class" entry in its
 * manifest file or include a main method that looks like this, where
 * MyClass is the name of the program class:
 *
 * 

 


 *      public static void main(String[] args) {
 *         new MyClass().start();
 *      }
 * 
* *

 

If the program needs the command line arguments, the args * array can be passed to the start method and then retrieved * using the getArgumentArray method. * * @param args An array of string arguments */ public static void main(String[] args) { HashMap ht = createParameterTable(args); JTFTools.setDebugOptions(ht.get("debug")); String className = ht.get("code"); if (className == null) { className = JTFTools.getMainClass(); } Class mainClass = null; CommandLineProgram program = null; if (className != null) { if (className.endsWith(".class")) { className = className.substring(0, className.length() - 6); } className = className.replace('/', '.'); try { mainClass = Class.forName(className); } catch (ClassNotFoundException ex) { /* Empty */ } } if (mainClass != null) { try { Object obj = mainClass.newInstance(); if (obj instanceof CommandLineProgram) { program = (CommandLineProgram) obj; } else { throw new ErrorException("Main class does not specify a program"); } } catch (IllegalAccessException ex) { /* Empty */ } catch (InstantiationException ex) { /* Empty */ } } if (program == null) throw new ErrorException("Cannot determine the main class."); program.setParameterTable(ht); program.start(null); } /**********************************************************************/ /* Menu handling methods */ /**********************************************************************/ /* Method: menuAction(cmd) */ /** * Called whenever an action event is detected in the menu bar. Most of * these actions are simply passed on to the appropriate console. * * @param cmd command */ public void menuAction(String cmd) { if (cmd != cmd) /* Avoid unused parameter warning */; throw new ErrorException("No graphics environment"); } /* Protected method: setMacMenuBarFlag(flag) */ /** * Sets a flag indicating whether applications running on the Macintosh * should use standard Mac menus. The default is true. * Setting this value to false means that Mac programs * use the same in-window JMenuBar approach used on other * platforms. * * Example: setMacMenuBarFlag(flag); * @param flag true to use Mac menu style; false otherwise */ protected void setMacMenuBarFlag(boolean flag) { if (flag != flag) /* Avoid unused parameter warning */; throw new ErrorException("No graphics environment"); } /* Protected method: getMacMenuBarFlag() */ /** * Retrieves the setting of the Mac menu bar flag. * * Example: boolean flag = getMacMenuBarFlag(); * @return true if Mac menu style is supported; false otherwise */ protected boolean getMacMenuBarFlag() { throw new ErrorException("No graphics environment"); } /**********************************************************************/ /* Protected methods */ /**********************************************************************/ /* Protected method: getBorder(side) */ /** * Returns the component installed as a border on the specified side, which must * be one of the constants from BorderLayout (NORTH, * SOUTH, EAST, WEST). * * Example: getBorder(side, comp); * @param side The side (NORTH, SOUTH, EAST, * or WEST) * @return The component used as a border on the specified side * */ protected Component getBorder(String side) { if (side != side) /* Avoid unused parameter warning */; throw new ErrorException("No graphics environment"); } /* Protected method: getArgumentArray() */ /** * Retrieves the array of arguments passed in from the command line, or * null if no arguments are available. * * Example: String[] args = getArgumentArray(); * @return The array of command-line arguments * */ protected String[] getArgumentArray() { if (parameterTable == null) return null; StringTokenizer tokenizer = new StringTokenizer(parameterTable.get("ARGS"), "\t", false); String[] args = new String[tokenizer.countTokens()]; for (int i = 0; tokenizer.hasMoreTokens(); i++) { args[i] = tokenizer.nextToken(); } return args; } /* Protected method: isStarted() */ /** * Checks to see whether this program has started, usually by checking to see * whether some pane exists. Subclasses can override this method to ensure * that their structures are visible before proceeding. * * @return actually not * */ protected boolean isStarted() { throw new ErrorException("No graphics environment"); } /* Protected method: startHook() */ /** * Performs class-specific initialization for the program just before * it starts. * */ protected void startHook() { /* Empty */ } /* Protected method: endHook() */ /** * Performs class-specific cleanup for the program just after * it finishes. * */ protected void endHook() { /* Empty */ } /* Protected method: setAppletStub(stub) */ /** * Sets the applet stub for this program in a way that makes it possible for * clients to retrieve it. * * Example: setAppletStub(stub); * @param stub The applet stub */ protected void setAppletStub(AppletStub stub) { appletStub = stub; } /* Protected method: getAppletStub() */ /** * Retrieves the applet stub. * * Example: AppletStub stub = getAppletStub(); * @return The applet stub */ protected AppletStub getAppletStub() { return appletStub; } /* Protected method: setParameterTable(ht) */ /** * Sets the parameter table for this program. * * Example: setParameterTable(ht); * @param ht The parameter table */ protected void setParameterTable(HashMap ht) { parameterTable = ht; } /* Protected method: getParameterTable() */ /** * Retrieves the parameter table. * * Example: ParameterTable ht = getParameterTable(); * @return The parameter table */ protected HashMap getParameterTable() { return parameterTable; } /* Protected static method: createParameterTable(args) */ /** * Creates a hash table containing the parameters specified in the * argument list. Parameters are taken to be any argument that matches * the template * *

 

name=value * * All other arguments are collected as a tab-separated string and placed * in an entry under the key "ARGS". All named parameters * are converted to lower case to preserve the case-insensitive semantics * of getParameter. * * Example: HashMap ht = createParameterTable(args); * @param args The array of strings passed to the application * @return A HashMap containing the parameter bindings */ protected static HashMap createParameterTable(String[] args) { if (args == null) return null; HashMap ht = new HashMap(); String newArgs = ""; for (int i = 0; i < args.length; i++) { String arg = args[i]; int equals = arg.indexOf('='); if (equals > 0) { String name = arg.substring(0, equals).toLowerCase(); String value = arg.substring(equals + 1); ht.put(name, value); } else { if (newArgs.length() > 0) newArgs += '\t'; newArgs += arg; } } ht.put("ARGS", newArgs); return ht; } /* Private instance variables */ private HashMap parameterTable; private ArrayList finalizers; private AppletStub appletStub; private String myTitle; private IOConsole myConsole; } class CommandLineProgramLoader extends ClassLoader { public CommandLineProgramLoader(String name) { targetName = name; try { Class classLoader = Class.forName("java.lang.ClassLoader"); Method getSystemClassLoader = classLoader.getMethod("getSystemClassLoader", new Class[0]); realLoader = (ClassLoader) getSystemClassLoader.invoke(null, new Object[0]); } catch (Exception ex) { throw new ErrorException(ex); } } public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { if (name.equals(targetName)) { InputStream in = getResourceAsStream(name + ".class"); superclassOffset = findSuperclassOffset(in); in = getResourceAsStream(name + ".class"); byte[] code = patchClassData(in); return defineClass(name, code, 0, code.length); } else { return realLoader.loadClass(name); } } public InputStream getResourceAsStream(String name) { return realLoader.getResourceAsStream(name); } public java.net.URL getResource(String name) { return realLoader.getResource(name); } private byte[] patchClassData(InputStream in) { try { ByteArrayOutputStream out = new ByteArrayOutputStream(); JTFTools.copyBytes(in, out, 8); int nConstants = in.read() << 8 | in.read(); out.write(nConstants >> 8); out.write(nConstants & 0xFF); for (int index = 1; index < nConstants; index++) { int type = in.read(); out.write(type); if (JTFTools.testDebugOption("constants")) { System.out.println(index + ": " + getConstantTypeName(type)); } switch (type) { case CONSTANT_Integer: JTFTools.copyBytes(in, out, 4); break; case CONSTANT_Float: JTFTools.copyBytes(in, out, 4); break; case CONSTANT_Long: JTFTools.copyBytes(in, out, 8); index++; break; case CONSTANT_Double: JTFTools.copyBytes(in, out, 8); index++; break; case CONSTANT_Class: JTFTools.copyBytes(in, out, 2); break; case CONSTANT_String: JTFTools.copyBytes(in, out, 2); break; case CONSTANT_Fieldref: JTFTools.copyBytes(in, out, 4); break; case CONSTANT_Methodref: JTFTools.copyBytes(in, out, 4); break; case CONSTANT_InterfaceMethodref: JTFTools.copyBytes(in, out, 4); break; case CONSTANT_NameAndType: JTFTools.copyBytes(in, out, 4); break; case CONSTANT_Utf8: if (index == superclassOffset) { int nChars = in.read() << 8 | in.read(); in.skip(nChars); String superclass = "acm/program/CommandLineProgram"; nChars = superclass.length(); out.write(nChars >> 8); out.write(nChars & 0xFF); for (int j = 0; j < nChars; j++) { out.write((byte) superclass.charAt(j)); } } else { int nChars = in.read() << 8 | in.read(); out.write(nChars >> 8); out.write(nChars & 0xFF); JTFTools.copyBytes(in, out, nChars); } break; } } while (true) { int ch = in.read(); if (ch == -1) break; out.write(ch); } return out.toByteArray(); } catch (IOException ex) { throw new ErrorException(ex); } } private int findSuperclassOffset(InputStream in) { classTable = new HashMap(); try { in.skip(8); int nConstants = in.read() << 8 | in.read(); nConstants += 2; for (int i = 1; i < nConstants - 2; i++) { int type = in.read(); switch (type) { case CONSTANT_Integer: in.skip(4); break; case CONSTANT_Float: in.skip(4); break; case CONSTANT_Long: in.skip(8); i++; break; case CONSTANT_Double: in.skip(8); i++; break; case CONSTANT_String: in.skip(2); break; case CONSTANT_Fieldref: in.skip(4); break; case CONSTANT_Methodref: in.skip(4); break; case CONSTANT_InterfaceMethodref: in.skip(4); break; case CONSTANT_NameAndType: in.skip(4); break; case CONSTANT_Class: int offset = in.read() << 8 | in.read(); classTable.put(new Integer(i), new Integer(offset)); break; case CONSTANT_Utf8: int nChars = in.read() << 8 | in.read(); in.skip(nChars); break; } } in.skip(4); return classTable.get(new Integer(in.read() << 8 | in.read())).intValue(); } catch (IOException ex) { throw new ErrorException(ex); } } private static String getConstantTypeName(int id) { switch (id) { case CONSTANT_Utf8: return "Utf8"; case CONSTANT_Integer: return "Integer"; case CONSTANT_Float: return "Float"; case CONSTANT_Long: return "Long"; case CONSTANT_Double: return "Double"; case CONSTANT_Class: return "Class"; case CONSTANT_String: return "String"; case CONSTANT_Fieldref: return "Fieldref"; case CONSTANT_Methodref: return "Methodref"; case CONSTANT_InterfaceMethodref: return "InterfaceMethodref"; case CONSTANT_NameAndType: return "NameAndType"; default: return "Type[" + id + "]"; } } private static final int CONSTANT_Utf8 = 1; private static final int CONSTANT_Integer = 3; private static final int CONSTANT_Float = 4; private static final int CONSTANT_Long = 5; private static final int CONSTANT_Double = 6; private static final int CONSTANT_Class = 7; private static final int CONSTANT_String = 8; private static final int CONSTANT_Fieldref = 9; private static final int CONSTANT_Methodref = 10; private static final int CONSTANT_InterfaceMethodref = 11; private static final int CONSTANT_NameAndType = 12; private HashMap classTable; private ClassLoader realLoader; private String targetName; private int superclassOffset; }